[llvm] add CallBrPrepare pass to pipelines

Capstone of
https://discourse.llvm.org/t/rfc-syncing-asm-goto-with-outputs-with-gcc/65453/8

Clang changes are still necessary to enable the use of outputs along
indirect edges of asm goto statements.

Link: https://github.com/llvm/llvm-project/issues/53562

Reviewed By: void

Differential Revision: https://reviews.llvm.org/D140180
This commit is contained in:
Nick Desaulniers
2023-02-16 17:48:14 -08:00
parent 5cc1016a57
commit a3a84c9e25
18 changed files with 85 additions and 37 deletions

View File

@@ -8540,6 +8540,14 @@ function, with the possibility of control flow transfer to either the
This instruction should only be used to implement the "goto" feature of gcc
style inline assembly. Any other usage is an error in the IR verifier.
Note that in order to support outputs along indirect edges, LLVM may need to
split critical edges, which may require synthesizing a replacement block for
the ``indirect labels``. Therefore, the address of a label as seen by another
``callbr`` instruction, or for a :ref:`blockaddress <blockaddress>` constant,
may not be equal to the address provided for the same block to this
instruction's ``indirect labels`` operand. The assembly code may only transfer
control to addresses provided via this instruction's ``indirect labels``.
Arguments:
""""""""""

View File

@@ -714,7 +714,7 @@ template <typename Derived>
void CodeGenPassBuilder<Derived>::addISelPrepare(AddIRPass &addPass) const {
derived().addPreISel(addPass);
// addPass(CallBrPrepare()); // TODO(ndesaulniers): impl pass
addPass(CallBrPrepare());
// Add both the safe stack and the stack protection passes: each of them will
// only protect functions that have corresponding attributes.
addPass(SafeStackPass());

View File

@@ -627,8 +627,11 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) {
// it is an entry block or landing pad.
for (const auto &LI : MBB->liveins()) {
if (isAllocatable(LI.PhysReg) && !MBB->isEHPad() &&
MBB->getIterator() != MBB->getParent()->begin()) {
report("MBB has allocatable live-in, but isn't entry or landing-pad.", MBB);
MBB->getIterator() != MBB->getParent()->begin() &&
!MBB->isInlineAsmBrIndirectTarget()) {
report("MBB has allocatable live-in, but isn't entry, landing-pad, or "
"inlineasm-br-indirect-target.",
MBB);
report_context(LI.PhysReg);
}
}

View File

@@ -978,7 +978,7 @@ void TargetPassConfig::addISelPrepare() {
if (requiresCodeGenSCCOrder())
addPass(new DummyCGSCCPass);
// addPass(createCallBrPass()); // TODO(ndesaulniers): impl pass
addPass(createCallBrPass());
// Add both the safe stack and the stack protection passes: each of them will
// only protect functions that have corresponding attributes.

View File

@@ -31,6 +31,7 @@
; CHECK-NEXT: AArch64 Stack Tagging
; CHECK-NEXT: SME ABI Pass
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -100,6 +100,7 @@
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Merge internal globals
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -93,6 +93,7 @@
; GCN-O0-NEXT: Loop-Closed SSA Form Pass
; GCN-O0-NEXT: DummyCGSCCPass
; GCN-O0-NEXT: FunctionPass Manager
; GCN-O0-NEXT: Prepare callbr
; GCN-O0-NEXT: Safe Stack instrumentation pass
; GCN-O0-NEXT: Insert stack protectors
; GCN-O0-NEXT: Dominator Tree Construction
@@ -285,6 +286,7 @@
; GCN-O1-NEXT: Loop-Closed SSA Form Pass
; GCN-O1-NEXT: DummyCGSCCPass
; GCN-O1-NEXT: FunctionPass Manager
; GCN-O1-NEXT: Prepare callbr
; GCN-O1-NEXT: Safe Stack instrumentation pass
; GCN-O1-NEXT: Insert stack protectors
; GCN-O1-NEXT: Dominator Tree Construction
@@ -581,6 +583,7 @@
; GCN-O1-OPTS-NEXT: Loop-Closed SSA Form Pass
; GCN-O1-OPTS-NEXT: DummyCGSCCPass
; GCN-O1-OPTS-NEXT: FunctionPass Manager
; GCN-O1-OPTS-NEXT: Prepare callbr
; GCN-O1-OPTS-NEXT: Safe Stack instrumentation pass
; GCN-O1-OPTS-NEXT: Insert stack protectors
; GCN-O1-OPTS-NEXT: Dominator Tree Construction
@@ -886,6 +889,7 @@
; GCN-O2-NEXT: Analysis if a function is memory bound
; GCN-O2-NEXT: DummyCGSCCPass
; GCN-O2-NEXT: FunctionPass Manager
; GCN-O2-NEXT: Prepare callbr
; GCN-O2-NEXT: Safe Stack instrumentation pass
; GCN-O2-NEXT: Insert stack protectors
; GCN-O2-NEXT: Dominator Tree Construction
@@ -1203,6 +1207,7 @@
; GCN-O3-NEXT: Analysis if a function is memory bound
; GCN-O3-NEXT: DummyCGSCCPass
; GCN-O3-NEXT: FunctionPass Manager
; GCN-O3-NEXT: Prepare callbr
; GCN-O3-NEXT: Safe Stack instrumentation pass
; GCN-O3-NEXT: Insert stack protectors
; GCN-O3-NEXT: Dominator Tree Construction

View File

@@ -65,6 +65,7 @@
; CHECK-NEXT: Transform predicated vector loops to use MVE tail predication
; CHECK-NEXT: A No-Op Barrier Pass
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -31,6 +31,7 @@
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -70,6 +70,7 @@
; CHECK-NEXT: CodeGen Prepare
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -30,6 +30,7 @@
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -80,6 +80,7 @@
; CHECK-NEXT: Lazy Block Frequency Analysis
; CHECK-NEXT: Optimization Remark Emitter
; CHECK-NEXT: Hardware Loop Insertion
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -31,6 +31,7 @@
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -66,6 +66,7 @@
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: A No-Op Barrier Pass
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -32,6 +32,7 @@
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Expand indirectbr instructions
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier

View File

@@ -22,7 +22,7 @@
; Check the first INLINEASM_BR target block is predecessed by the block with
; the first INLINEASM_BR.
; CHECK: bb.4 (%ir-block.11, machine-block-address-taken, inlineasm-br-indirect-target):
; CHECK: bb.4 (%ir-block.12, machine-block-address-taken, inlineasm-br-indirect-target):
; CHECK-NEXT: predecessors: %bb.0
@.str = private unnamed_addr constant [26 x i8] c"inline asm#1 returned %d\0A\00", align 1

View File

@@ -38,36 +38,46 @@ define i32 @test2(i32 %out1, i32 %out2) nounwind {
; CHECK-NEXT: pushl %esi
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %edi
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %esi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmpl %edi, %esi
; CHECK-NEXT: jge .LBB1_2
; CHECK-NEXT: jge .LBB1_3
; CHECK-NEXT: # %bb.1: # %if.then
; CHECK-NEXT: #APP
; CHECK-NEXT: testl %esi, %esi
; CHECK-NEXT: testl %edi, %esi
; CHECK-NEXT: jne .LBB1_4
; CHECK-NEXT: jne .LBB1_2
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: jmp .LBB1_3
; CHECK-NEXT: .LBB1_2: # %if.else
; CHECK-NEXT: jmp .LBB1_4
; CHECK-NEXT: .LBB1_2: # Block address taken
; CHECK-NEXT: # %if.then.label_true_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: jmp .LBB1_8
; CHECK-NEXT: .LBB1_3: # %if.else
; CHECK-NEXT: #APP
; CHECK-NEXT: testl %esi, %edi
; CHECK-NEXT: testl %esi, %edi
; CHECK-NEXT: jne .LBB1_5
; CHECK-NEXT: jne .LBB1_9
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: .LBB1_3:
; CHECK-NEXT: .LBB1_4:
; CHECK-NEXT: movl %esi, %eax
; CHECK-NEXT: addl %edi, %eax
; CHECK-NEXT: .LBB1_5: # Block address taken
; CHECK-NEXT: # %return
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB1_5: # %return
; CHECK-NEXT: popl %esi
; CHECK-NEXT: popl %edi
; CHECK-NEXT: retl
; CHECK-NEXT: .LBB1_4: # Block address taken
; CHECK-NEXT: # %label_true
; CHECK-NEXT: .LBB1_7: # Block address taken
; CHECK-NEXT: # %if.else.label_true_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB1_8: # %label_true
; CHECK-NEXT: movl $-2, %eax
; CHECK-NEXT: jmp .LBB1_5
; CHECK-NEXT: .LBB1_9: # Block address taken
; CHECK-NEXT: # %if.else.return_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB1_6: # Block address taken
; CHECK-NEXT: # %if.then.return_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: jmp .LBB1_5
entry:
%cmp = icmp slt i32 %out1, %out2
br i1 %cmp, label %if.then, label %if.else
@@ -109,23 +119,25 @@ define i32 @test3(i1 %cmp) nounwind {
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: # %bb.2:
; CHECK-NEXT: movl %edi, %eax
; CHECK-NEXT: jmp .LBB2_5
; CHECK-NEXT: jmp .LBB2_4
; CHECK-NEXT: .LBB2_3: # %false
; CHECK-NEXT: #APP
; CHECK-NEXT: .short %eax
; CHECK-NEXT: .short %edx
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: # %bb.4:
; CHECK-NEXT: movl %edx, %eax
; CHECK-NEXT: .LBB2_5: # %asm.fallthrough
; CHECK-NEXT: .LBB2_4: # %asm.fallthrough
; CHECK-NEXT: popl %esi
; CHECK-NEXT: popl %edi
; CHECK-NEXT: retl
; CHECK-NEXT: .LBB2_5: # Block address taken
; CHECK-NEXT: # %true.indirect_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB2_6: # Block address taken
; CHECK-NEXT: # %indirect
; CHECK-NEXT: # %false.indirect_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: movl $42, %eax
; CHECK-NEXT: jmp .LBB2_5
; CHECK-NEXT: jmp .LBB2_4
entry:
br i1 %cmp, label %true, label %false
@@ -148,31 +160,37 @@ indirect:
define i32 @test4(i32 %out1, i32 %out2) {
; CHECK-LABEL: test4:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %ecx
; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax
; CHECK-NEXT: #APP
; CHECK-NEXT: testl %ecx, %ecx
; CHECK-NEXT: testl %edx, %ecx
; CHECK-NEXT: testl %eax, %eax
; CHECK-NEXT: testl %ecx, %eax
; CHECK-NEXT: jne .LBB3_3
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: # %bb.1: # %asm.fallthrough
; CHECK-NEXT: #APP
; CHECK-NEXT: testl %ecx, %edx
; CHECK-NEXT: testl %ecx, %edx
; CHECK-NEXT: jne .LBB3_4
; CHECK-NEXT: testl %eax, %ecx
; CHECK-NEXT: testl %eax, %ecx
; CHECK-NEXT: jne .LBB3_5
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: # %bb.2: # %asm.fallthrough2
; CHECK-NEXT: addl %edx, %ecx
; CHECK-NEXT: movl %ecx, %eax
; CHECK-NEXT: .LBB3_4: # Block address taken
; CHECK-NEXT: # %return
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: addl %ecx, %eax
; CHECK-NEXT: retl
; CHECK-NEXT: .LBB3_4: # Block address taken
; CHECK-NEXT: # %entry.return_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB3_5: # Block address taken
; CHECK-NEXT: # %asm.fallthrough.return_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: retl
; CHECK-NEXT: .LBB3_6: # Block address taken
; CHECK-NEXT: # %asm.fallthrough.label_true_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: .LBB3_3: # Block address taken
; CHECK-NEXT: # %label_true
; CHECK-NEXT: # %entry.label_true_crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: movl $-2, %eax
; CHECK-NEXT: jmp .LBB3_4
; CHECK-NEXT: retl
entry:
%0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,!i,!i"(i32 %out1)
to label %asm.fallthrough [label %label_true, label %return]
@@ -206,7 +224,10 @@ define dso_local void @test5() {
; CHECK: # %bb.0:
; CHECK-NEXT: #APP
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: .LBB4_1: # Block address taken
; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: retl
; CHECK-NEXT: .LBB4_2: # Block address taken
; CHECK-NEXT: # %._crit_edge
; CHECK-NEXT: # Label of block must be emitted
; CHECK-NEXT: retl
%1 = call i32 @llvm.read_register.i32(metadata !3)

View File

@@ -72,6 +72,7 @@
; CHECK-NEXT: CodeGen Prepare
; CHECK-NEXT: Dominator Tree Construction
; CHECK-NEXT: Exception handling preparation
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier