forked from OSchip/llvm-project
[AArch64] Fix verifier error when outlining indirect calls
The MachineOutliner for AArch64 transforms indirect calls into indirect tail calls, replacing the call with the TCRETURNri pseudo-instruction. This pseudo lowers to a BR, but has the isCall and isReturn flags set. The problem is that TCRETURNri takes a tcGPR64 as the register argument, to prevent indiret tail-calls from using caller-saved registers. The indirect calls transformed by the outliner could use caller-saved registers. This is fine, because the outliner ensures that the register is available at all call sites. However, this causes a verifier failure when the register is not in tcGPR64. The fix is to add a new pseudo-instruction like TCRETURNri, but which accepts any GPR. Differential revision: https://reviews.llvm.org/D52829 llvm-svn: 343959
This commit is contained in:
parent
5af6c1496a
commit
9ecdac8ee0
|
@ -590,7 +590,8 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
// Tail calls use pseudo instructions so they have the proper code-gen
|
// Tail calls use pseudo instructions so they have the proper code-gen
|
||||||
// attributes (isCall, isReturn, etc.). We lower them to the real
|
// attributes (isCall, isReturn, etc.). We lower them to the real
|
||||||
// instruction here.
|
// instruction here.
|
||||||
case AArch64::TCRETURNri: {
|
case AArch64::TCRETURNri:
|
||||||
|
case AArch64::TCRETURNriALL: {
|
||||||
MCInst TmpInst;
|
MCInst TmpInst;
|
||||||
TmpInst.setOpcode(AArch64::BR);
|
TmpInst.setOpcode(AArch64::BR);
|
||||||
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
|
TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg()));
|
||||||
|
|
|
@ -5461,7 +5461,7 @@ void AArch64InstrInfo::buildOutlinedFrame(
|
||||||
TailOpcode = AArch64::TCRETURNdi;
|
TailOpcode = AArch64::TCRETURNdi;
|
||||||
} else {
|
} else {
|
||||||
assert(Call->getOpcode() == AArch64::BLR);
|
assert(Call->getOpcode() == AArch64::BLR);
|
||||||
TailOpcode = AArch64::TCRETURNri;
|
TailOpcode = AArch64::TCRETURNriALL;
|
||||||
}
|
}
|
||||||
MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
|
MachineInstr *TC = BuildMI(MF, DebugLoc(), get(TailOpcode))
|
||||||
.add(Call->getOperand(0))
|
.add(Call->getOperand(0))
|
||||||
|
|
|
@ -6635,6 +6635,12 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in {
|
||||||
Sched<[WriteBrReg]>;
|
Sched<[WriteBrReg]>;
|
||||||
def TCRETURNri : Pseudo<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff), []>,
|
def TCRETURNri : Pseudo<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff), []>,
|
||||||
Sched<[WriteBrReg]>;
|
Sched<[WriteBrReg]>;
|
||||||
|
// Indirect tail-call with any register allowed, used by MachineOutliner when
|
||||||
|
// this is proven safe.
|
||||||
|
// FIXME: If we have to add any more hacks like this, we should instead relax
|
||||||
|
// some verifier checks for outlined functions.
|
||||||
|
def TCRETURNriALL : Pseudo<(outs), (ins GPR64:$dst, i32imm:$FPDiff), []>,
|
||||||
|
Sched<[WriteBrReg]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
def : Pat<(AArch64tcret tcGPR64:$dst, (i32 timm:$FPDiff)),
|
def : Pat<(AArch64tcret tcGPR64:$dst, (i32 timm:$FPDiff)),
|
||||||
|
|
|
@ -12,7 +12,7 @@ define i32 @a() {
|
||||||
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
||||||
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
; CHECK-NEXT: .cfi_offset w30, -16
|
; CHECK-NEXT: .cfi_offset w30, -16
|
||||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
; CHECK-NEXT: bl [[OUTLINED_DIRECT:OUTLINED_FUNCTION_[0-9]+]]
|
||||||
; CHECK-NEXT: add w0, w0, #8 // =8
|
; CHECK-NEXT: add w0, w0, #8 // =8
|
||||||
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
|
@ -28,7 +28,7 @@ define i32 @b() {
|
||||||
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
||||||
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
; CHECK-NEXT: .cfi_offset w30, -16
|
; CHECK-NEXT: .cfi_offset w30, -16
|
||||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
; CHECK-NEXT: bl [[OUTLINED_DIRECT]]
|
||||||
; CHECK-NEXT: add w0, w0, #88 // =88
|
; CHECK-NEXT: add w0, w0, #88 // =88
|
||||||
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
|
@ -38,7 +38,48 @@ entry:
|
||||||
ret i32 %cx
|
ret i32 %cx
|
||||||
}
|
}
|
||||||
|
|
||||||
; CHECK-LABEL: OUTLINED_FUNCTION_0:
|
define hidden i32 @c(i32 (i32, i32, i32, i32)* %fptr) {
|
||||||
|
; CHECK-LABEL: c:
|
||||||
|
; CHECK: // %bb.0: // %entry
|
||||||
|
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
||||||
|
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
; CHECK-NEXT: .cfi_offset w30, -16
|
||||||
|
; CHECK-NEXT: bl [[OUTLINED_INDIRECT:OUTLINED_FUNCTION_[0-9]+]]
|
||||||
|
; CHECK-NEXT: add w0, w0, #8 // =8
|
||||||
|
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
entry:
|
||||||
|
%call = tail call i32 %fptr(i32 1, i32 2, i32 3, i32 4)
|
||||||
|
%add = add nsw i32 %call, 8
|
||||||
|
ret i32 %add
|
||||||
|
}
|
||||||
|
|
||||||
|
define hidden i32 @d(i32 (i32, i32, i32, i32)* %fptr) {
|
||||||
|
; CHECK-LABEL: d:
|
||||||
|
; CHECK: // %bb.0: // %entry
|
||||||
|
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
|
||||||
|
; CHECK-NEXT: .cfi_def_cfa_offset 16
|
||||||
|
; CHECK-NEXT: .cfi_offset w30, -16
|
||||||
|
; CHECK-NEXT: bl [[OUTLINED_INDIRECT]]
|
||||||
|
; CHECK-NEXT: add w0, w0, #88 // =88
|
||||||
|
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
entry:
|
||||||
|
%call = tail call i32 %fptr(i32 1, i32 2, i32 3, i32 4)
|
||||||
|
%add = add nsw i32 %call, 88
|
||||||
|
ret i32 %add
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK: [[OUTLINED_INDIRECT]]:
|
||||||
|
; CHECK: // %bb.0:
|
||||||
|
; CHECK-NEXT: mov x8, x0
|
||||||
|
; CHECK-NEXT: orr w0, wzr, #0x1
|
||||||
|
; CHECK-NEXT: orr w1, wzr, #0x2
|
||||||
|
; CHECK-NEXT: orr w2, wzr, #0x3
|
||||||
|
; CHECK-NEXT: orr w3, wzr, #0x4
|
||||||
|
; CHECK-NEXT: br x8
|
||||||
|
|
||||||
|
; CHECK: [[OUTLINED_DIRECT]]:
|
||||||
; CHECK: // %bb.0:
|
; CHECK: // %bb.0:
|
||||||
; CHECK-NEXT: orr w0, wzr, #0x1
|
; CHECK-NEXT: orr w0, wzr, #0x1
|
||||||
; CHECK-NEXT: orr w1, wzr, #0x2
|
; CHECK-NEXT: orr w1, wzr, #0x2
|
||||||
|
|
Loading…
Reference in New Issue