Skip to content

Commit 3d127e2

Browse files
committed
Auto merge of rust-lang#94123 - bjorn3:cg_ssa_singleton_builder, r=tmiasko
Partially move cg_ssa towards using a single builder Not all codegen backends can handle hopping between blocks well. For example Cranelift requires blocks to be terminated before switching to building a new block. Rust-gpu requires a `RefCell` to allow hopping between blocks and cg_gcc currently has a buggy implementation of hopping between blocks. This PR reduces the amount of cases where cg_ssa switches between blocks before they are finished and mostly fixes the block hopping in cg_gcc. (~~only `scalar_to_backend` doesn't handle it correctly yet in cg_gcc~~ fixed that one.) `@antoyo` please review the cg_gcc changes.
2 parents 7ccfe2f + 96cf799 commit 3d127e2

File tree

6 files changed

+158
-150
lines changed

6 files changed

+158
-150
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

+19-16
Original file line numberDiff line numberDiff line change
@@ -390,11 +390,6 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
390390
bx
391391
}
392392

393-
fn build_sibling_block(&mut self, name: &str) -> Self {
394-
let block = self.append_sibling_block(name);
395-
Self::build(self.cx, block)
396-
}
397-
398393
fn llbb(&self) -> Block<'gcc> {
399394
self.block.expect("block")
400395
}
@@ -409,6 +404,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
409404
func.new_block(name)
410405
}
411406

407+
fn switch_to_block(&mut self, block: Self::BasicBlock) {
408+
*self.cx.current_block.borrow_mut() = Some(block);
409+
self.block = Some(block);
410+
}
411+
412412
fn ret_void(&mut self) {
413413
self.llbb().end_with_void_return(None)
414414
}
@@ -880,28 +880,31 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
880880
let start = dest.project_index(&mut self, zero).llval;
881881
let end = dest.project_index(&mut self, count).llval;
882882

883-
let mut header_bx = self.build_sibling_block("repeat_loop_header");
884-
let mut body_bx = self.build_sibling_block("repeat_loop_body");
885-
let next_bx = self.build_sibling_block("repeat_loop_next");
883+
let header_bb = self.append_sibling_block("repeat_loop_header");
884+
let body_bb = self.append_sibling_block("repeat_loop_body");
885+
let next_bb = self.append_sibling_block("repeat_loop_next");
886886

887887
let ptr_type = start.get_type();
888888
let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var");
889889
let current_val = current.to_rvalue();
890890
self.assign(current, start);
891891

892-
self.br(header_bx.llbb());
892+
self.br(header_bb);
893893

894-
let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end);
895-
header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
894+
self.switch_to_block(header_bb);
895+
let keep_going = self.icmp(IntPredicate::IntNE, current_val, end);
896+
self.cond_br(keep_going, body_bb, next_bb);
896897

898+
self.switch_to_block(body_bb);
897899
let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
898-
cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
900+
cg_elem.val.store(&mut self, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
899901

900-
let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]);
901-
body_bx.llbb().add_assignment(None, current, next);
902-
body_bx.br(header_bx.llbb());
902+
let next = self.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]);
903+
self.llbb().add_assignment(None, current, next);
904+
self.br(header_bb);
903905

904-
next_bx
906+
self.switch_to_block(next_bb);
907+
self
905908
}
906909

907910
fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) {

compiler/rustc_codegen_llvm/src/builder.rs

+13-11
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
166166
Self::append_block(self.cx, self.llfn(), name)
167167
}
168168

169-
fn build_sibling_block(&mut self, name: &str) -> Self {
170-
let llbb = self.append_sibling_block(name);
171-
Self::build(self.cx, llbb)
169+
fn switch_to_block(&mut self, llbb: Self::BasicBlock) {
170+
*self = Self::build(self.cx, llbb)
172171
}
173172

174173
fn ret_void(&mut self) {
@@ -544,16 +543,19 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
544543
let start = dest.project_index(&mut self, zero).llval;
545544
let end = dest.project_index(&mut self, count).llval;
546545

547-
let mut header_bx = self.build_sibling_block("repeat_loop_header");
548-
let mut body_bx = self.build_sibling_block("repeat_loop_body");
549-
let next_bx = self.build_sibling_block("repeat_loop_next");
546+
let header_bb = self.append_sibling_block("repeat_loop_header");
547+
let body_bb = self.append_sibling_block("repeat_loop_body");
548+
let next_bb = self.append_sibling_block("repeat_loop_next");
550549

551-
self.br(header_bx.llbb());
550+
self.br(header_bb);
551+
552+
let mut header_bx = Self::build(self.cx, header_bb);
552553
let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
553554

554555
let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
555-
header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
556+
header_bx.cond_br(keep_going, body_bb, next_bb);
556557

558+
let mut body_bx = Self::build(self.cx, body_bb);
557559
let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
558560
cg_elem
559561
.val
@@ -564,10 +566,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
564566
current,
565567
&[self.const_usize(1)],
566568
);
567-
body_bx.br(header_bx.llbb());
568-
header_bx.add_incoming_to_phi(current, next, body_bx.llbb());
569+
body_bx.br(header_bb);
570+
header_bx.add_incoming_to_phi(current, next, body_bb);
569571

570-
next_bx
572+
Self::build(self.cx, next_bb)
571573
}
572574

573575
fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {

compiler/rustc_codegen_llvm/src/intrinsic.rs

+58-54
Original file line numberDiff line numberDiff line change
@@ -452,11 +452,11 @@ fn codegen_msvc_try<'ll>(
452452
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
453453
bx.set_personality_fn(bx.eh_personality());
454454

455-
let mut normal = bx.build_sibling_block("normal");
456-
let mut catchswitch = bx.build_sibling_block("catchswitch");
457-
let mut catchpad_rust = bx.build_sibling_block("catchpad_rust");
458-
let mut catchpad_foreign = bx.build_sibling_block("catchpad_foreign");
459-
let mut caught = bx.build_sibling_block("caught");
455+
let normal = bx.append_sibling_block("normal");
456+
let catchswitch = bx.append_sibling_block("catchswitch");
457+
let catchpad_rust = bx.append_sibling_block("catchpad_rust");
458+
let catchpad_foreign = bx.append_sibling_block("catchpad_foreign");
459+
let caught = bx.append_sibling_block("caught");
460460

461461
let try_func = llvm::get_param(bx.llfn(), 0);
462462
let data = llvm::get_param(bx.llfn(), 1);
@@ -520,12 +520,13 @@ fn codegen_msvc_try<'ll>(
520520
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
521521
let slot = bx.alloca(bx.type_i8p(), ptr_align);
522522
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
523-
bx.invoke(try_func_ty, try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
523+
bx.invoke(try_func_ty, try_func, &[data], normal, catchswitch, None);
524524

525-
normal.ret(bx.const_i32(0));
525+
bx.switch_to_block(normal);
526+
bx.ret(bx.const_i32(0));
526527

527-
let cs =
528-
catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]);
528+
bx.switch_to_block(catchswitch);
529+
let cs = bx.catch_switch(None, None, &[catchpad_rust, catchpad_foreign]);
529530

530531
// We can't use the TypeDescriptor defined in libpanic_unwind because it
531532
// might be in another DLL and the SEH encoding only supports specifying
@@ -558,21 +559,24 @@ fn codegen_msvc_try<'ll>(
558559
// since our exception object effectively contains a Box.
559560
//
560561
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
562+
bx.switch_to_block(catchpad_rust);
561563
let flags = bx.const_i32(8);
562-
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
563-
let ptr = catchpad_rust.load(bx.type_i8p(), slot, ptr_align);
564+
let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
565+
let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
564566
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
565-
catchpad_rust.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
566-
catchpad_rust.catch_ret(&funclet, caught.llbb());
567+
bx.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
568+
bx.catch_ret(&funclet, caught);
567569

568570
// The flag value of 64 indicates a "catch-all".
571+
bx.switch_to_block(catchpad_foreign);
569572
let flags = bx.const_i32(64);
570573
let null = bx.const_null(bx.type_i8p());
571-
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
572-
catchpad_foreign.call(catch_ty, catch_func, &[data, null], Some(&funclet));
573-
catchpad_foreign.catch_ret(&funclet, caught.llbb());
574+
let funclet = bx.catch_pad(cs, &[null, flags, null]);
575+
bx.call(catch_ty, catch_func, &[data, null], Some(&funclet));
576+
bx.catch_ret(&funclet, caught);
574577

575-
caught.ret(bx.const_i32(1));
578+
bx.switch_to_block(caught);
579+
bx.ret(bx.const_i32(1));
576580
});
577581

578582
// Note that no invoke is used here because by definition this function
@@ -613,30 +617,33 @@ fn codegen_gnu_try<'ll>(
613617
// (%ptr, _) = landingpad
614618
// call %catch_func(%data, %ptr)
615619
// ret 1
616-
let mut then = bx.build_sibling_block("then");
617-
let mut catch = bx.build_sibling_block("catch");
620+
let then = bx.append_sibling_block("then");
621+
let catch = bx.append_sibling_block("catch");
618622

619623
let try_func = llvm::get_param(bx.llfn(), 0);
620624
let data = llvm::get_param(bx.llfn(), 1);
621625
let catch_func = llvm::get_param(bx.llfn(), 2);
622626
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
623-
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
624-
then.ret(bx.const_i32(0));
627+
bx.invoke(try_func_ty, try_func, &[data], then, catch, None);
628+
629+
bx.switch_to_block(then);
630+
bx.ret(bx.const_i32(0));
625631

626632
// Type indicator for the exception being thrown.
627633
//
628634
// The first value in this tuple is a pointer to the exception object
629635
// being thrown. The second value is a "selector" indicating which of
630636
// the landing pad clauses the exception's type had been matched to.
631637
// rust_try ignores the selector.
638+
bx.switch_to_block(catch);
632639
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
633-
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1);
640+
let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
634641
let tydesc = bx.const_null(bx.type_i8p());
635-
catch.add_clause(vals, tydesc);
636-
let ptr = catch.extract_value(vals, 0);
642+
bx.add_clause(vals, tydesc);
643+
let ptr = bx.extract_value(vals, 0);
637644
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
638-
catch.call(catch_ty, catch_func, &[data, ptr], None);
639-
catch.ret(bx.const_i32(1));
645+
bx.call(catch_ty, catch_func, &[data, ptr], None);
646+
bx.ret(bx.const_i32(1));
640647
});
641648

642649
// Note that no invoke is used here because by definition this function
@@ -674,57 +681,54 @@ fn codegen_emcc_try<'ll>(
674681
// %catch_data[1] = %is_rust_panic
675682
// call %catch_func(%data, %catch_data)
676683
// ret 1
677-
let mut then = bx.build_sibling_block("then");
678-
let mut catch = bx.build_sibling_block("catch");
684+
let then = bx.append_sibling_block("then");
685+
let catch = bx.append_sibling_block("catch");
679686

680687
let try_func = llvm::get_param(bx.llfn(), 0);
681688
let data = llvm::get_param(bx.llfn(), 1);
682689
let catch_func = llvm::get_param(bx.llfn(), 2);
683690
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
684-
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
685-
then.ret(bx.const_i32(0));
691+
bx.invoke(try_func_ty, try_func, &[data], then, catch, None);
692+
693+
bx.switch_to_block(then);
694+
bx.ret(bx.const_i32(0));
686695

687696
// Type indicator for the exception being thrown.
688697
//
689698
// The first value in this tuple is a pointer to the exception object
690699
// being thrown. The second value is a "selector" indicating which of
691700
// the landing pad clauses the exception's type had been matched to.
701+
bx.switch_to_block(catch);
692702
let tydesc = bx.eh_catch_typeinfo();
693703
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
694-
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 2);
695-
catch.add_clause(vals, tydesc);
696-
catch.add_clause(vals, bx.const_null(bx.type_i8p()));
697-
let ptr = catch.extract_value(vals, 0);
698-
let selector = catch.extract_value(vals, 1);
704+
let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2);
705+
bx.add_clause(vals, tydesc);
706+
bx.add_clause(vals, bx.const_null(bx.type_i8p()));
707+
let ptr = bx.extract_value(vals, 0);
708+
let selector = bx.extract_value(vals, 1);
699709

700710
// Check if the typeid we got is the one for a Rust panic.
701-
let rust_typeid = catch.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
702-
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
703-
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
711+
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
712+
let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
713+
let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
704714

705715
// We need to pass two values to catch_func (ptr and is_rust_panic), so
706716
// create an alloca and pass a pointer to that.
707717
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
708718
let i8_align = bx.tcx().data_layout.i8_align.abi;
709719
let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
710-
let catch_data = catch.alloca(catch_data_type, ptr_align);
711-
let catch_data_0 = catch.inbounds_gep(
712-
catch_data_type,
713-
catch_data,
714-
&[bx.const_usize(0), bx.const_usize(0)],
715-
);
716-
catch.store(ptr, catch_data_0, ptr_align);
717-
let catch_data_1 = catch.inbounds_gep(
718-
catch_data_type,
719-
catch_data,
720-
&[bx.const_usize(0), bx.const_usize(1)],
721-
);
722-
catch.store(is_rust_panic, catch_data_1, i8_align);
723-
let catch_data = catch.bitcast(catch_data, bx.type_i8p());
720+
let catch_data = bx.alloca(catch_data_type, ptr_align);
721+
let catch_data_0 =
722+
bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
723+
bx.store(ptr, catch_data_0, ptr_align);
724+
let catch_data_1 =
725+
bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
726+
bx.store(is_rust_panic, catch_data_1, i8_align);
727+
let catch_data = bx.bitcast(catch_data, bx.type_i8p());
724728

725729
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
726-
catch.call(catch_ty, catch_func, &[data, catch_data], None);
727-
catch.ret(bx.const_i32(1));
730+
bx.call(catch_ty, catch_func, &[data, catch_data], None);
731+
bx.ret(bx.const_i32(1));
728732
});
729733

730734
// Note that no invoke is used here because by definition this function

0 commit comments

Comments
 (0)