Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cranelift/codegen/src/inst_predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub fn has_memory_fence_semantics(op: Opcode) -> bool {
| Opcode::AtomicStore
| Opcode::Fence
| Opcode::Debugtrap => true,
Opcode::Call | Opcode::CallIndirect => true,
Opcode::Call | Opcode::CallIndirect | Opcode::TryCall | Opcode::TryCallIndirect => true,
op if op.can_trap() => true,
_ => false,
}
Expand Down
6 changes: 6 additions & 0 deletions cranelift/codegen/src/ir/exception_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ impl ExceptionTableData {
pub fn signature(&self) -> SigRef {
self.sig
}

/// Clears all entries in this exception table, but leaves the function signature.
pub fn clear(&mut self) {
self.tags.clear();
self.targets.clear();
}
}

/// A wrapper for the context required to display a
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/aarch64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1127,7 +1127,7 @@ impl ABIMachineSpec for AArch64MachineDeps {
fn get_regs_clobbered_by_call(call_conv: isa::CallConv, is_exception: bool) -> PRegSet {
match call_conv {
isa::CallConv::Winch => WINCH_CLOBBERS,
_ if is_exception => ALL_CLOBBERS,
isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
_ => DEFAULT_AAPCS_CLOBBERS,
}
}
Expand Down
4 changes: 2 additions & 2 deletions cranelift/codegen/src/isa/call_conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,15 @@ impl CallConv {
/// Does this calling convention support exceptions?
pub fn supports_exceptions(&self) -> bool {
match self {
CallConv::Tail => true,
CallConv::Tail | CallConv::SystemV => true,
_ => false,
}
}

/// What types do the exception payload value(s) have?
pub fn exception_payload_types(&self, pointer_ty: Type) -> &[Type] {
match self {
CallConv::Tail => match pointer_ty {
CallConv::Tail | CallConv::SystemV => match pointer_ty {
types::I32 => &[types::I32, types::I32],
types::I64 => &[types::I64, types::I64],
_ => unreachable!(),
Expand Down
9 changes: 4 additions & 5 deletions cranelift/codegen/src/isa/riscv64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,13 +639,12 @@ impl ABIMachineSpec for Riscv64MachineDeps {
}

fn get_regs_clobbered_by_call(
_call_conv_of_callee: isa::CallConv,
call_conv_of_callee: isa::CallConv,
is_exception: bool,
) -> PRegSet {
if is_exception {
ALL_CLOBBERS
} else {
DEFAULT_CLOBBERS
match call_conv_of_callee {
isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
_ => DEFAULT_CLOBBERS,
}
}

Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/s390x/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ impl ABIMachineSpec for S390xMachineDeps {
is_exception: bool,
) -> PRegSet {
match call_conv_of_callee {
_ if is_exception => ALL_CLOBBERS,
isa::CallConv::Tail if is_exception => ALL_CLOBBERS,
isa::CallConv::Tail => TAIL_CLOBBERS,
_ => SYSV_CLOBBERS,
}
Expand Down
2 changes: 1 addition & 1 deletion cranelift/codegen/src/isa/x64/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ impl ABIMachineSpec for X64ABIMachineSpec {
match call_conv_of_callee {
CallConv::Winch => ALL_CLOBBERS,
CallConv::WindowsFastcall => WINDOWS_CLOBBERS,
_ if is_exception => ALL_CLOBBERS,
CallConv::Tail if is_exception => ALL_CLOBBERS,
_ => SYSV_CLOBBERS,
}
}
Expand Down
19 changes: 17 additions & 2 deletions cranelift/codegen/src/unreachable_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@ pub fn eliminate_unreachable_code(
let _tt = timing::unreachable_code();
let mut pos = FuncCursor::new(func);
let mut used_tables = EntitySet::with_capacity(pos.func.stencil.dfg.jump_tables.len());
let mut used_exception_tables =
EntitySet::with_capacity(pos.func.stencil.dfg.exception_tables.len());
while let Some(block) = pos.next_block() {
if domtree.is_reachable(block) {
let inst = pos.func.layout.last_inst(block).unwrap();
if let ir::InstructionData::BranchTable { table, .. } = pos.func.dfg.insts[inst] {
used_tables.insert(table);
match pos.func.dfg.insts[inst] {
ir::InstructionData::BranchTable { table, .. } => {
used_tables.insert(table);
}
ir::InstructionData::TryCall { exception, .. }
| ir::InstructionData::TryCallIndirect { exception, .. } => {
used_exception_tables.insert(exception);
}
_ => (),
}
continue;
}
Expand Down Expand Up @@ -55,4 +64,10 @@ pub fn eliminate_unreachable_code(
jt_data.clear();
}
}

for (exception, exception_data) in func.stencil.dfg.exception_tables.iter_mut() {
if !used_exception_tables.contains(exception) {
exception_data.clear();
}
}
}
57 changes: 23 additions & 34 deletions cranelift/codegen/src/verifier/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,23 +1464,6 @@ impl<'a> Verifier<'a> {
Ok(())
}

fn pointer_type_or_error(&self, inst: Inst, errors: &mut VerifierErrors) -> Result<Type, ()> {
// Ensure we have an ISA so we know what the pointer size is.
if let Some(isa) = self.isa {
Ok(isa.pointer_type())
} else {
errors
.fatal((
inst,
self.context(inst),
format!("need an ISA to validate correct pointer type"),
))
// Will always return an `Err`, but the `Ok` type
// doesn't match, so map it.
.map(|_| Type::default())
}
}

fn typecheck_block_call(
&self,
inst: Inst,
Expand All @@ -1504,7 +1487,9 @@ impl<'a> Verifier<'a> {
));
}
for (arg, param) in args.zip(block_params.iter()) {
let arg_ty = self.block_call_arg_ty(arg, inst, target_type, errors)?;
let Some(arg_ty) = self.block_call_arg_ty(arg, inst, target_type, errors)? else {
continue;
};
let param_ty = self.func.dfg.value_type(*param);
if arg_ty != param_ty {
errors.nonfatal((
Expand All @@ -1523,9 +1508,9 @@ impl<'a> Verifier<'a> {
inst: Inst,
target_type: BlockCallTargetType,
errors: &mut VerifierErrors,
) -> Result<Type, ()> {
) -> Result<Option<Type>, ()> {
match arg {
BlockArg::Value(v) => Ok(self.func.dfg.value_type(v)),
BlockArg::Value(v) => Ok(Some(self.func.dfg.value_type(v))),
BlockArg::TryCallRet(_) | BlockArg::TryCallExn(_) => {
// Get the invoked signature.
let et = match self.func.dfg.insts[inst].exception_table() {
Expand All @@ -1548,7 +1533,7 @@ impl<'a> Verifier<'a> {
(BlockArg::TryCallRet(i), BlockCallTargetType::ExNormalRet)
if (i as usize) < sig.returns.len() =>
{
Ok(sig.returns[i as usize].value_type)
Ok(Some(sig.returns[i as usize].value_type))
}
(BlockArg::TryCallRet(_), BlockCallTargetType::ExNormalRet) => {
errors.fatal((
Expand All @@ -1567,20 +1552,24 @@ impl<'a> Verifier<'a> {
unreachable!()
}
(BlockArg::TryCallExn(i), BlockCallTargetType::Exception) => {
match sig
.call_conv
.exception_payload_types(self.pointer_type_or_error(inst, errors)?)
.get(i as usize)
{
Some(ty) => Ok(*ty),
None => {
errors.fatal((
inst,
self.context(inst),
format!("out-of-bounds `exnN` block argument"),
))?;
unreachable!()
if let Some(isa) = self.isa {
match sig
.call_conv
.exception_payload_types(isa.pointer_type())
.get(i as usize)
{
Some(ty) => Ok(Some(*ty)),
None => {
errors.fatal((
inst,
self.context(inst),
format!("out-of-bounds `exnN` block argument"),
))?;
unreachable!()
}
}
} else {
Ok(None)
}
}
(BlockArg::TryCallExn(_), _) => {
Expand Down
25 changes: 25 additions & 0 deletions cranelift/filetests/filetests/egraph/try_call-mem-clobber.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
; Regression test for the alias analysis not considering try_call to be a memory fence

test optimize
set opt_level=speed_and_size
target x86_64

function u0:0(i64 sret, i64) system_v {
ss0 = explicit_slot 8
sig0 = (i64) system_v
fn0 = u0:1 sig0

block0(v0: i64, v1: i64):
v20 = stack_addr.i64 ss0
; check: v20 = stack_addr.i64 ss0
store v1, v20 ; store v1 to ss0
try_call fn0(v20), sig0, block1, []

block1:
v21 = stack_addr.i64 ss0
v2 = load.i64 v21; load v2 from ss0 after the fn0 call potentially changed it
; check: v2 = load.i64 v20
store v2, v0 ; v2 used to be incorrectly replaced by v1 in the egraph pass
; nextln: store v2, v0
return
}
6 changes: 3 additions & 3 deletions cranelift/filetests/filetests/verifier/exceptions.clif
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,12 @@ function %f4(i32) -> i32 {

;; Non-supported calling convention.
function %f5(i32) -> i32 {
sig0 = (i32) -> f32 system_v
fn0 = %g(i32) -> f32 system_v
sig0 = (i32) -> f32 windows_fastcall
fn0 = %g(i32) -> f32 windows_fastcall

block0(v1: i32):
v2 = f64const 0x1.0
try_call fn0(v1), sig0, block1(ret0, v2), [ tag1: block2(), default: block3(v2) ] ; error: calling convention `system_v` of callee does not support exceptions
try_call fn0(v1), sig0, block1(ret0, v2), [ tag1: block2(), default: block3(v2) ] ; error: calling convention `windows_fastcall` of callee does not support exceptions

block1(v3: f32, v4: f64):
v5 = iconst.i32 1
Expand Down
Loading
Loading