Auto merge of #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.
This commit is contained in:
commit
3d127e2040
6 changed files with 158 additions and 150 deletions
|
@ -166,9 +166,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
Self::append_block(self.cx, self.llfn(), name)
|
||||
}
|
||||
|
||||
fn build_sibling_block(&mut self, name: &str) -> Self {
|
||||
let llbb = self.append_sibling_block(name);
|
||||
Self::build(self.cx, llbb)
|
||||
fn switch_to_block(&mut self, llbb: Self::BasicBlock) {
|
||||
*self = Self::build(self.cx, llbb)
|
||||
}
|
||||
|
||||
fn ret_void(&mut self) {
|
||||
|
@ -544,16 +543,19 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
let start = dest.project_index(&mut self, zero).llval;
|
||||
let end = dest.project_index(&mut self, count).llval;
|
||||
|
||||
let mut header_bx = self.build_sibling_block("repeat_loop_header");
|
||||
let mut body_bx = self.build_sibling_block("repeat_loop_body");
|
||||
let next_bx = self.build_sibling_block("repeat_loop_next");
|
||||
let header_bb = self.append_sibling_block("repeat_loop_header");
|
||||
let body_bb = self.append_sibling_block("repeat_loop_body");
|
||||
let next_bb = self.append_sibling_block("repeat_loop_next");
|
||||
|
||||
self.br(header_bx.llbb());
|
||||
self.br(header_bb);
|
||||
|
||||
let mut header_bx = Self::build(self.cx, header_bb);
|
||||
let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
|
||||
|
||||
let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
|
||||
header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
|
||||
header_bx.cond_br(keep_going, body_bb, next_bb);
|
||||
|
||||
let mut body_bx = Self::build(self.cx, body_bb);
|
||||
let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
|
||||
cg_elem
|
||||
.val
|
||||
|
@ -564,10 +566,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
current,
|
||||
&[self.const_usize(1)],
|
||||
);
|
||||
body_bx.br(header_bx.llbb());
|
||||
header_bx.add_incoming_to_phi(current, next, body_bx.llbb());
|
||||
body_bx.br(header_bb);
|
||||
header_bx.add_incoming_to_phi(current, next, body_bb);
|
||||
|
||||
next_bx
|
||||
Self::build(self.cx, next_bb)
|
||||
}
|
||||
|
||||
fn range_metadata(&mut self, load: &'ll Value, range: WrappingRange) {
|
||||
|
|
|
@ -452,11 +452,11 @@ fn codegen_msvc_try<'ll>(
|
|||
let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
|
||||
bx.set_personality_fn(bx.eh_personality());
|
||||
|
||||
let mut normal = bx.build_sibling_block("normal");
|
||||
let mut catchswitch = bx.build_sibling_block("catchswitch");
|
||||
let mut catchpad_rust = bx.build_sibling_block("catchpad_rust");
|
||||
let mut catchpad_foreign = bx.build_sibling_block("catchpad_foreign");
|
||||
let mut caught = bx.build_sibling_block("caught");
|
||||
let normal = bx.append_sibling_block("normal");
|
||||
let catchswitch = bx.append_sibling_block("catchswitch");
|
||||
let catchpad_rust = bx.append_sibling_block("catchpad_rust");
|
||||
let catchpad_foreign = bx.append_sibling_block("catchpad_foreign");
|
||||
let caught = bx.append_sibling_block("caught");
|
||||
|
||||
let try_func = llvm::get_param(bx.llfn(), 0);
|
||||
let data = llvm::get_param(bx.llfn(), 1);
|
||||
|
@ -520,12 +520,13 @@ fn codegen_msvc_try<'ll>(
|
|||
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||
let slot = bx.alloca(bx.type_i8p(), ptr_align);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
|
||||
bx.invoke(try_func_ty, try_func, &[data], normal, catchswitch, None);
|
||||
|
||||
normal.ret(bx.const_i32(0));
|
||||
bx.switch_to_block(normal);
|
||||
bx.ret(bx.const_i32(0));
|
||||
|
||||
let cs =
|
||||
catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]);
|
||||
bx.switch_to_block(catchswitch);
|
||||
let cs = bx.catch_switch(None, None, &[catchpad_rust, catchpad_foreign]);
|
||||
|
||||
// We can't use the TypeDescriptor defined in libpanic_unwind because it
|
||||
// might be in another DLL and the SEH encoding only supports specifying
|
||||
|
@ -558,21 +559,24 @@ fn codegen_msvc_try<'ll>(
|
|||
// since our exception object effectively contains a Box.
|
||||
//
|
||||
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
|
||||
bx.switch_to_block(catchpad_rust);
|
||||
let flags = bx.const_i32(8);
|
||||
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
|
||||
let ptr = catchpad_rust.load(bx.type_i8p(), slot, ptr_align);
|
||||
let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
|
||||
let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
catchpad_rust.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
|
||||
catchpad_rust.catch_ret(&funclet, caught.llbb());
|
||||
bx.call(catch_ty, catch_func, &[data, ptr], Some(&funclet));
|
||||
bx.catch_ret(&funclet, caught);
|
||||
|
||||
// The flag value of 64 indicates a "catch-all".
|
||||
bx.switch_to_block(catchpad_foreign);
|
||||
let flags = bx.const_i32(64);
|
||||
let null = bx.const_null(bx.type_i8p());
|
||||
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
|
||||
catchpad_foreign.call(catch_ty, catch_func, &[data, null], Some(&funclet));
|
||||
catchpad_foreign.catch_ret(&funclet, caught.llbb());
|
||||
let funclet = bx.catch_pad(cs, &[null, flags, null]);
|
||||
bx.call(catch_ty, catch_func, &[data, null], Some(&funclet));
|
||||
bx.catch_ret(&funclet, caught);
|
||||
|
||||
caught.ret(bx.const_i32(1));
|
||||
bx.switch_to_block(caught);
|
||||
bx.ret(bx.const_i32(1));
|
||||
});
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
|
@ -613,15 +617,17 @@ fn codegen_gnu_try<'ll>(
|
|||
// (%ptr, _) = landingpad
|
||||
// call %catch_func(%data, %ptr)
|
||||
// ret 1
|
||||
let mut then = bx.build_sibling_block("then");
|
||||
let mut catch = bx.build_sibling_block("catch");
|
||||
let then = bx.append_sibling_block("then");
|
||||
let catch = bx.append_sibling_block("catch");
|
||||
|
||||
let try_func = llvm::get_param(bx.llfn(), 0);
|
||||
let data = llvm::get_param(bx.llfn(), 1);
|
||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
|
||||
then.ret(bx.const_i32(0));
|
||||
bx.invoke(try_func_ty, try_func, &[data], then, catch, None);
|
||||
|
||||
bx.switch_to_block(then);
|
||||
bx.ret(bx.const_i32(0));
|
||||
|
||||
// Type indicator for the exception being thrown.
|
||||
//
|
||||
|
@ -629,14 +635,15 @@ fn codegen_gnu_try<'ll>(
|
|||
// being thrown. The second value is a "selector" indicating which of
|
||||
// the landing pad clauses the exception's type had been matched to.
|
||||
// rust_try ignores the selector.
|
||||
bx.switch_to_block(catch);
|
||||
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
|
||||
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1);
|
||||
let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
|
||||
let tydesc = bx.const_null(bx.type_i8p());
|
||||
catch.add_clause(vals, tydesc);
|
||||
let ptr = catch.extract_value(vals, 0);
|
||||
bx.add_clause(vals, tydesc);
|
||||
let ptr = bx.extract_value(vals, 0);
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
catch.call(catch_ty, catch_func, &[data, ptr], None);
|
||||
catch.ret(bx.const_i32(1));
|
||||
bx.call(catch_ty, catch_func, &[data, ptr], None);
|
||||
bx.ret(bx.const_i32(1));
|
||||
});
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
|
@ -674,57 +681,54 @@ fn codegen_emcc_try<'ll>(
|
|||
// %catch_data[1] = %is_rust_panic
|
||||
// call %catch_func(%data, %catch_data)
|
||||
// ret 1
|
||||
let mut then = bx.build_sibling_block("then");
|
||||
let mut catch = bx.build_sibling_block("catch");
|
||||
let then = bx.append_sibling_block("then");
|
||||
let catch = bx.append_sibling_block("catch");
|
||||
|
||||
let try_func = llvm::get_param(bx.llfn(), 0);
|
||||
let data = llvm::get_param(bx.llfn(), 1);
|
||||
let catch_func = llvm::get_param(bx.llfn(), 2);
|
||||
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
|
||||
bx.invoke(try_func_ty, try_func, &[data], then.llbb(), catch.llbb(), None);
|
||||
then.ret(bx.const_i32(0));
|
||||
bx.invoke(try_func_ty, try_func, &[data], then, catch, None);
|
||||
|
||||
bx.switch_to_block(then);
|
||||
bx.ret(bx.const_i32(0));
|
||||
|
||||
// Type indicator for the exception being thrown.
|
||||
//
|
||||
// The first value in this tuple is a pointer to the exception object
|
||||
// being thrown. The second value is a "selector" indicating which of
|
||||
// the landing pad clauses the exception's type had been matched to.
|
||||
bx.switch_to_block(catch);
|
||||
let tydesc = bx.eh_catch_typeinfo();
|
||||
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
|
||||
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 2);
|
||||
catch.add_clause(vals, tydesc);
|
||||
catch.add_clause(vals, bx.const_null(bx.type_i8p()));
|
||||
let ptr = catch.extract_value(vals, 0);
|
||||
let selector = catch.extract_value(vals, 1);
|
||||
let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2);
|
||||
bx.add_clause(vals, tydesc);
|
||||
bx.add_clause(vals, bx.const_null(bx.type_i8p()));
|
||||
let ptr = bx.extract_value(vals, 0);
|
||||
let selector = bx.extract_value(vals, 1);
|
||||
|
||||
// Check if the typeid we got is the one for a Rust panic.
|
||||
let rust_typeid = catch.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
|
||||
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
||||
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
|
||||
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
|
||||
let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
||||
let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
|
||||
|
||||
// We need to pass two values to catch_func (ptr and is_rust_panic), so
|
||||
// create an alloca and pass a pointer to that.
|
||||
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
||||
let i8_align = bx.tcx().data_layout.i8_align.abi;
|
||||
let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
|
||||
let catch_data = catch.alloca(catch_data_type, ptr_align);
|
||||
let catch_data_0 = catch.inbounds_gep(
|
||||
catch_data_type,
|
||||
catch_data,
|
||||
&[bx.const_usize(0), bx.const_usize(0)],
|
||||
);
|
||||
catch.store(ptr, catch_data_0, ptr_align);
|
||||
let catch_data_1 = catch.inbounds_gep(
|
||||
catch_data_type,
|
||||
catch_data,
|
||||
&[bx.const_usize(0), bx.const_usize(1)],
|
||||
);
|
||||
catch.store(is_rust_panic, catch_data_1, i8_align);
|
||||
let catch_data = catch.bitcast(catch_data, bx.type_i8p());
|
||||
let catch_data = bx.alloca(catch_data_type, ptr_align);
|
||||
let catch_data_0 =
|
||||
bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
|
||||
bx.store(ptr, catch_data_0, ptr_align);
|
||||
let catch_data_1 =
|
||||
bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
|
||||
bx.store(is_rust_panic, catch_data_1, i8_align);
|
||||
let catch_data = bx.bitcast(catch_data, bx.type_i8p());
|
||||
|
||||
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
|
||||
catch.call(catch_ty, catch_func, &[data, catch_data], None);
|
||||
catch.ret(bx.const_i32(1));
|
||||
bx.call(catch_ty, catch_func, &[data, catch_data], None);
|
||||
bx.ret(bx.const_i32(1));
|
||||
});
|
||||
|
||||
// Note that no invoke is used here because by definition this function
|
||||
|
|
|
@ -102,10 +102,10 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
|
|||
let va_list_ty = va_list_layout.llvm_type(bx);
|
||||
let layout = bx.cx.layout_of(target_ty);
|
||||
|
||||
let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
|
||||
let mut in_reg = bx.build_sibling_block("va_arg.in_reg");
|
||||
let mut on_stack = bx.build_sibling_block("va_arg.on_stack");
|
||||
let mut end = bx.build_sibling_block("va_arg.end");
|
||||
let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
|
||||
let in_reg = bx.append_sibling_block("va_arg.in_reg");
|
||||
let on_stack = bx.append_sibling_block("va_arg.on_stack");
|
||||
let end = bx.append_sibling_block("va_arg.end");
|
||||
let zero = bx.const_i32(0);
|
||||
let offset_align = Align::from_bytes(4).unwrap();
|
||||
|
||||
|
@ -125,53 +125,53 @@ fn emit_aapcs_va_arg<'ll, 'tcx>(
|
|||
// if the offset >= 0 then the value will be on the stack
|
||||
let mut reg_off_v = bx.load(bx.type_i32(), reg_off, offset_align);
|
||||
let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
|
||||
bx.cond_br(use_stack, on_stack.llbb(), maybe_reg.llbb());
|
||||
bx.cond_br(use_stack, on_stack, maybe_reg);
|
||||
|
||||
// The value at this point might be in a register, but there is a chance that
|
||||
// it could be on the stack so we have to update the offset and then check
|
||||
// the offset again.
|
||||
|
||||
bx.switch_to_block(maybe_reg);
|
||||
if gr_type && layout.align.abi.bytes() > 8 {
|
||||
reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15));
|
||||
reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16));
|
||||
reg_off_v = bx.add(reg_off_v, bx.const_i32(15));
|
||||
reg_off_v = bx.and(reg_off_v, bx.const_i32(-16));
|
||||
}
|
||||
let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32));
|
||||
let new_reg_off_v = bx.add(reg_off_v, bx.const_i32(slot_size as i32));
|
||||
|
||||
maybe_reg.store(new_reg_off_v, reg_off, offset_align);
|
||||
bx.store(new_reg_off_v, reg_off, offset_align);
|
||||
|
||||
// Check to see if we have overflowed the registers as a result of this.
|
||||
// If we have then we need to use the stack for this value
|
||||
let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
|
||||
maybe_reg.cond_br(use_stack, on_stack.llbb(), in_reg.llbb());
|
||||
let use_stack = bx.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
|
||||
bx.cond_br(use_stack, on_stack, in_reg);
|
||||
|
||||
bx.switch_to_block(in_reg);
|
||||
let top_type = bx.type_i8p();
|
||||
let top = in_reg.struct_gep(va_list_ty, va_list_addr, reg_top_index);
|
||||
let top = in_reg.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
|
||||
let top = bx.struct_gep(va_list_ty, va_list_addr, reg_top_index);
|
||||
let top = bx.load(top_type, top, bx.tcx().data_layout.pointer_align.abi);
|
||||
|
||||
// reg_value = *(@top + reg_off_v);
|
||||
let mut reg_addr = in_reg.gep(bx.type_i8(), top, &[reg_off_v]);
|
||||
let mut reg_addr = bx.gep(bx.type_i8(), top, &[reg_off_v]);
|
||||
if bx.tcx().sess.target.endian == Endian::Big && layout.size.bytes() != slot_size {
|
||||
// On big-endian systems the value is right-aligned in its slot.
|
||||
let offset = bx.const_i32((slot_size - layout.size.bytes()) as i32);
|
||||
reg_addr = in_reg.gep(bx.type_i8(), reg_addr, &[offset]);
|
||||
reg_addr = bx.gep(bx.type_i8(), reg_addr, &[offset]);
|
||||
}
|
||||
let reg_type = layout.llvm_type(bx);
|
||||
let reg_addr = in_reg.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
|
||||
let reg_value = in_reg.load(reg_type, reg_addr, layout.align.abi);
|
||||
in_reg.br(end.llbb());
|
||||
let reg_addr = bx.bitcast(reg_addr, bx.cx.type_ptr_to(reg_type));
|
||||
let reg_value = bx.load(reg_type, reg_addr, layout.align.abi);
|
||||
bx.br(end);
|
||||
|
||||
// On Stack block
|
||||
bx.switch_to_block(on_stack);
|
||||
let stack_value =
|
||||
emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
|
||||
on_stack.br(end.llbb());
|
||||
emit_ptr_va_arg(bx, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
|
||||
bx.br(end);
|
||||
|
||||
let val = end.phi(
|
||||
layout.immediate_llvm_type(bx),
|
||||
&[reg_value, stack_value],
|
||||
&[in_reg.llbb(), on_stack.llbb()],
|
||||
);
|
||||
bx.switch_to_block(end);
|
||||
let val =
|
||||
bx.phi(layout.immediate_llvm_type(bx), &[reg_value, stack_value], &[in_reg, on_stack]);
|
||||
|
||||
*bx = end;
|
||||
val
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue