AArch64: avoid branches with explicit offsets at lowering stage.

In discussions with @bnjbvr, it came up that generating `OneWayCondBr`s
with explicit, hardcoded PC-offsets as part of lowered instruction
sequences is actually unsafe, because the register allocator *might*
insert a spill or reload into the middle of our sequence. We were
careful about this in some cases but somehow missed that it was a
general restriction. Conceptually, all inter-instruction references
should be via labels at the VCode level; explicit offsets are only ever
known at emission time, and resolved by the `MachBuffer`.

To allow for conditional trap checks without modifying the CFG (as seen
by regalloc) during lowering, this PR instead adds a `TrapIf`
pseudo-instruction that conditionally skips a single embedded trap
instruction. It lowers to the same `condbr label ; trap ; label: ...`
sequence, but without the hardcoded branch-target offset in the lowering
code.
This commit is contained in:
Chris Fallin
2020-07-01 16:28:41 -07:00
parent f2dd1535d5
commit b7ecad1d74
11 changed files with 267 additions and 312 deletions

View File

@@ -2505,149 +2505,148 @@ fn test_aarch64_binemit() {
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Zero(xreg(8)),
},
"080200B4",
"cbz x8, 64",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::NotZero(xreg(8)),
},
"080200B5",
"cbnz x8, 64",
"480000B40000A0D4",
"cbz x8, 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Eq),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Zero(xreg(8)),
},
"00020054",
"b.eq 64",
"480000B50000A0D4",
"cbnz x8, 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ne),
},
"01020054",
"b.ne 64",
"400000540000A0D4",
"b.eq 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Hs),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Eq),
},
"02020054",
"b.hs 64",
"410000540000A0D4",
"b.ne 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Lo),
},
"03020054",
"b.lo 64",
"420000540000A0D4",
"b.hs 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Mi),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Hs),
},
"04020054",
"b.mi 64",
"430000540000A0D4",
"b.lo 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Pl),
},
"05020054",
"b.pl 64",
"440000540000A0D4",
"b.mi 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Vs),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Mi),
},
"06020054",
"b.vs 64",
"450000540000A0D4",
"b.pl 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Vc),
},
"07020054",
"b.vc 64",
"460000540000A0D4",
"b.vs 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Hi),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Vs),
},
"08020054",
"b.hi 64",
"470000540000A0D4",
"b.vc 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ls),
},
"09020054",
"b.ls 64",
"480000540000A0D4",
"b.hi 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Ge),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Hi),
},
"0A020054",
"b.ge 64",
"490000540000A0D4",
"b.ls 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Lt),
},
"0B020054",
"b.lt 64",
"4A0000540000A0D4",
"b.ge 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Gt),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Ge),
},
"0C020054",
"b.gt 64",
"4B0000540000A0D4",
"b.lt 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Le),
},
"0D020054",
"b.le 64",
"4C0000540000A0D4",
"b.gt 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
kind: CondBrKind::Cond(Cond::Al),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Gt),
},
"0E020054",
"b.al 64",
"4D0000540000A0D4",
"b.le 8 ; udf",
));
insns.push((
Inst::OneWayCondBr {
target: BranchTarget::ResolvedOffset(64),
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Nv),
},
"0F020054",
"b.nv 64",
"4E0000540000A0D4",
"b.al 8 ; udf",
));
insns.push((
Inst::TrapIf {
trap_info: (SourceLoc::default(), TrapCode::Interrupt),
kind: CondBrKind::Cond(Cond::Al),
},
"4F0000540000A0D4",
"b.nv 8 ; udf",
));
insns.push((