Skip to content

Commit

Permalink
rustc_codegen_ssa: turn builders "unpositioned" after emitting a term…
Browse files Browse the repository at this point in the history
…inator.
  • Loading branch information
eddyb committed Apr 30, 2021
1 parent ce953ec commit 78e2ac0
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 233 deletions.
69 changes: 40 additions & 29 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,58 +161,63 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {

fn set_span(&mut self, _span: Span) {}

fn ret_void(&mut self) {
fn ret_void(self) -> Self::Unpositioned {
unsafe {
llvm::LLVMBuildRetVoid(self.llbuilder);
}
self.into_unpositioned()
}

fn ret(&mut self, v: &'ll Value) {
fn ret(self, v: &'ll Value) -> Self::Unpositioned {
unsafe {
llvm::LLVMBuildRet(self.llbuilder, v);
}
self.into_unpositioned()
}

fn br(&mut self, dest: &'ll BasicBlock) {
fn br(self, dest: &'ll BasicBlock) -> Self::Unpositioned {
unsafe {
llvm::LLVMBuildBr(self.llbuilder, dest);
}
self.into_unpositioned()
}

fn cond_br(
&mut self,
self,
cond: &'ll Value,
then_llbb: &'ll BasicBlock,
else_llbb: &'ll BasicBlock,
) {
) -> Self::Unpositioned {
unsafe {
llvm::LLVMBuildCondBr(self.llbuilder, cond, then_llbb, else_llbb);
}
self.into_unpositioned()
}

fn switch(
&mut self,
self,
v: &'ll Value,
else_llbb: &'ll BasicBlock,
cases: impl ExactSizeIterator<Item = (u128, &'ll BasicBlock)>,
) {
) -> Self::Unpositioned {
let switch =
unsafe { llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) };
for (on_val, dest) in cases {
let on_val = self.const_uint_big(self.val_ty(v), on_val);
unsafe { llvm::LLVMAddCase(switch, on_val, dest) }
}
self.into_unpositioned()
}

fn invoke(
&mut self,
mut self,
llfn: &'ll Value,
args: &[&'ll Value],
then: &'ll BasicBlock,
catch: &'ll BasicBlock,
funclet: Option<&Funclet<'ll>>,
fn_abi_for_attrs: Option<&FnAbi<'tcx, Ty<'tcx>>>,
) -> &'ll Value {
) -> (Self::Unpositioned, &'ll Value) {
debug!("invoke {:?} with args ({:?})", llfn, args);

let args = self.check_call("invoke", llfn, args);
Expand All @@ -232,15 +237,16 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
)
};
if let Some(fn_abi) = fn_abi_for_attrs {
fn_abi.apply_attrs_callsite(self, invoke);
fn_abi.apply_attrs_callsite(&mut self, invoke);
}
invoke
(self.into_unpositioned(), invoke)
}

fn unreachable(&mut self) {
fn unreachable(self) -> Self::Unpositioned {
unsafe {
llvm::LLVMBuildUnreachable(self.llbuilder);
}
self.into_unpositioned()
}

builder_methods_for_value_instructions! {
Expand Down Expand Up @@ -530,29 +536,33 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
count: u64,
dest: PlaceRef<'tcx, &'ll Value>,
) -> Self {
let zero = self.const_usize(0);
let count = self.const_usize(count);
let start = dest.project_index(&mut self, zero).llval;
let end = dest.project_index(&mut self, count).llval;
let cx = self.cx;
let original_llbb = self.llbb();

let start = dest.project_index(&mut self, cx.const_usize(0)).llval;
let end = dest.project_index(&mut self, cx.const_usize(count)).llval;

let mut header_bx = self.build_sibling_block("repeat_loop_header");
let header_llbb = header_bx.llbb();
let mut body_bx = self.build_sibling_block("repeat_loop_body");
let body_llbb = body_bx.llbb();
let next_bx = self.build_sibling_block("repeat_loop_next");

let current_llty = cx.val_ty(start);
self.br(header_bx.llbb());
let current = header_bx.phi(self.val_ty(start), &[start], &[self.llbb()]);
let current = header_bx.phi(current_llty, &[start], &[original_llbb]);

let keep_going = header_bx.icmp(IntPredicate::IntNE, current, end);
header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());

let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
let align = dest.align.restrict_for_offset(dest.layout.field(cx, 0).size);
cg_elem
.val
.store(&mut body_bx, PlaceRef::new_sized_aligned(current, cg_elem.layout, align));

let next = body_bx.inbounds_gep(current, &[self.const_usize(1)]);
body_bx.br(header_bx.llbb());
Self::add_incoming_to_phi(current, &[next], &[body_bx.llbb()]);
let next = body_bx.inbounds_gep(current, &[cx.const_usize(1)]);
body_bx.br(header_llbb);
Self::add_incoming_to_phi(current, &[next], &[body_llbb]);

next_bx
}
Expand Down Expand Up @@ -958,8 +968,9 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn resume(&mut self, exn: &'ll Value) -> &'ll Value {
unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) }
fn resume(self, exn: &'ll Value) -> (Self::Unpositioned, &'ll Value) {
let resume = unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) };
(self.into_unpositioned(), resume)
}

fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> {
Expand All @@ -977,13 +988,13 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}

fn cleanup_ret(
&mut self,
self,
funclet: &Funclet<'ll>,
unwind: Option<&'ll BasicBlock>,
) -> &'ll Value {
) -> (Self::Unpositioned, &'ll Value) {
let ret =
unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) };
ret.expect("LLVM does not have support for cleanupret")
(self.into_unpositioned(), ret.expect("LLVM does not have support for cleanupret"))
}

fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> {
Expand All @@ -1001,11 +1012,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}

fn catch_switch(
&mut self,
self,
parent: Option<&'ll Value>,
unwind: Option<&'ll BasicBlock>,
handlers: &[&'ll BasicBlock],
) -> &'ll Value {
) -> (Self::Unpositioned, &'ll Value) {
let name = cstr!("catchswitch");
let ret = unsafe {
llvm::LLVMRustBuildCatchSwitch(
Expand All @@ -1022,7 +1033,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
llvm::LLVMRustAddHandler(catch_switch, handler);
}
}
catch_switch
(self.into_unpositioned(), catch_switch)
}

fn set_personality_fn(&mut self, personality: &'ll Value) {
Expand Down
80 changes: 43 additions & 37 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,15 @@ fn codegen_msvc_try(
dest: &'ll Value,
) {
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
let cx = bx.cx;

bx.set_personality_fn(bx.eh_personality());

let mut normal = bx.build_sibling_block("normal");
let mut catchswitch = bx.build_sibling_block("catchswitch");
let normal = bx.build_sibling_block("normal");
let 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 caught = bx.build_sibling_block("caught");

let try_func = llvm::get_param(bx.llfn(), 0);
let data = llvm::get_param(bx.llfn(), 1);
Expand Down Expand Up @@ -476,9 +478,9 @@ fn codegen_msvc_try(
let slot = bx.alloca(bx.type_i8p(), ptr_align);
bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None, None);

normal.ret(bx.const_i32(0));
normal.ret(cx.const_i32(0));

let cs =
let (_, cs) =
catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]);

// We can't use the TypeDescriptor defined in libpanic_unwind because it
Expand All @@ -495,14 +497,14 @@ fn codegen_msvc_try(
//
// When modifying, make sure that the type_name string exactly matches
// the one used in src/libpanic_unwind/seh.rs.
let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
let type_name = bx.const_bytes(b"rust_panic\0");
let type_info_vtable = cx.declare_global("??_7type_info@@6B@", cx.type_i8p());
let type_name = cx.const_bytes(b"rust_panic\0");
let type_info =
bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
cx.const_struct(&[type_info_vtable, cx.const_null(cx.type_i8p()), type_name], false);
let tydesc = cx.declare_global("__rust_panic_type_info", cx.val_ty(type_info));
unsafe {
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
llvm::SetUniqueComdat(bx.llmod, tydesc);
llvm::SetUniqueComdat(cx.llmod, tydesc);
llvm::LLVMSetInitializer(tydesc, type_info);
}

Expand All @@ -512,20 +514,20 @@ fn codegen_msvc_try(
// since our exception object effectively contains a Box.
//
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
let flags = bx.const_i32(8);
let flags = cx.const_i32(8);
let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]);
let ptr = catchpad_rust.load(slot, ptr_align);
catchpad_rust.call(catch_func, &[data, ptr], Some(&funclet), None);
catchpad_rust.catch_ret(&funclet, caught.llbb());

// The flag value of 64 indicates a "catch-all".
let flags = bx.const_i32(64);
let null = bx.const_null(bx.type_i8p());
let flags = cx.const_i32(64);
let null = cx.const_null(cx.type_i8p());
let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]);
catchpad_foreign.call(catch_func, &[data, null], Some(&funclet), None);
catchpad_foreign.catch_ret(&funclet, caught.llbb());

caught.ret(bx.const_i32(1));
caught.ret(cx.const_i32(1));
});

// Note that no invoke is used here because by definition this function
Expand Down Expand Up @@ -553,7 +555,9 @@ fn codegen_gnu_try(
catch_func: &'ll Value,
dest: &'ll Value,
) {
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
let llfn = get_rust_try_fn(bx, &mut |bx| {
let cx = bx.cx;

// Codegens the shims described above:
//
// bx:
Expand All @@ -566,28 +570,28 @@ fn codegen_gnu_try(
// (%ptr, _) = landingpad
// call %catch_func(%data, %ptr)
// ret 1
let mut then = bx.build_sibling_block("then");
let then = bx.build_sibling_block("then");
let mut catch = bx.build_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);
bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None, None);
then.ret(bx.const_i32(0));
then.ret(cx.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.
// rust_try ignores the selector.
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 tydesc = bx.const_null(bx.type_i8p());
let lpad_ty = cx.type_struct(&[cx.type_i8p(), cx.type_i32()], false);
let vals = catch.landing_pad(lpad_ty, cx.eh_personality(), 1);
let tydesc = cx.const_null(cx.type_i8p());
catch.add_clause(vals, tydesc);
let ptr = catch.extract_value(vals, 0);
catch.call(catch_func, &[data, ptr], None, None);
catch.ret(bx.const_i32(1));
catch.ret(cx.const_i32(1));
});

// Note that no invoke is used here because by definition this function
Expand All @@ -607,7 +611,9 @@ fn codegen_emcc_try(
catch_func: &'ll Value,
dest: &'ll Value,
) {
let llfn = get_rust_try_fn(bx, &mut |mut bx| {
let llfn = get_rust_try_fn(bx, &mut |bx| {
let cx = bx.cx;

// Codegens the shims described above:
//
// bx:
Expand All @@ -625,48 +631,48 @@ fn codegen_emcc_try(
// %catch_data[1] = %is_rust_panic
// call %catch_func(%data, %catch_data)
// ret 1
let mut then = bx.build_sibling_block("then");
let then = bx.build_sibling_block("then");
let mut catch = bx.build_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);
bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None, None);
then.ret(bx.const_i32(0));
then.ret(cx.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.
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);
let tydesc = cx.eh_catch_typeinfo();
let lpad_ty = cx.type_struct(&[cx.type_i8p(), cx.type_i32()], false);
let vals = catch.landing_pad(lpad_ty, cx.eh_personality(), 2);
catch.add_clause(vals, tydesc);
catch.add_clause(vals, bx.const_null(bx.type_i8p()));
catch.add_clause(vals, cx.const_null(cx.type_i8p()));
let ptr = catch.extract_value(vals, 0);
let selector = catch.extract_value(vals, 1);

// Check if the typeid we got is the one for a Rust panic.
let llvm_eh_typeid_for = bx.get_intrinsic("llvm.eh.typeid.for");
let llvm_eh_typeid_for = cx.get_intrinsic("llvm.eh.typeid.for");
let rust_typeid = catch.call(llvm_eh_typeid_for, &[tydesc], None, None);
let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid);
let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool());
let is_rust_panic = catch.zext(is_rust_panic, cx.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 ptr_align = cx.tcx.data_layout.pointer_align.abi;
let i8_align = cx.tcx.data_layout.i8_align.abi;
let catch_data =
catch.alloca(bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false), ptr_align);
let catch_data_0 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
catch.alloca(cx.type_struct(&[cx.type_i8p(), cx.type_bool()], false), ptr_align);
let catch_data_0 = catch.inbounds_gep(catch_data, &[cx.const_usize(0), cx.const_usize(0)]);
catch.store(ptr, catch_data_0, ptr_align);
let catch_data_1 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
let catch_data_1 = catch.inbounds_gep(catch_data, &[cx.const_usize(0), cx.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 = catch.bitcast(catch_data, cx.type_i8p());

catch.call(catch_func, &[data, catch_data], None, None);
catch.ret(bx.const_i32(1));
catch.ret(cx.const_i32(1));
});

// Note that no invoke is used here because by definition this function
Expand Down
Loading

0 comments on commit 78e2ac0

Please sign in to comment.