| # RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -no-stack-coloring=false -run-pass stack-coloring -o - %s | |
| # RUN: llc -mtriple=x86_64-unknown-linux-gnu -mcpu=corei7 -no-stack-coloring=false -passes stack-coloring -o - %s | |
| # Test to insure that the liveness analysis in the StackColoring | |
| # pass gracefully handles statically unreachable blocks. See PR 37310. | |
| # This MIR testcase was created by compiling the following test, first | |
| # with "clang -emit-llvm -S" and then "llc -stop-before stack-coloring", | |
| # and finally editing the resulting MIR by hand to introduce a statically | |
| # unreachable BB (to wit: rename all bb.3 to bb.4, rename bb.2 to bb.3, | |
| # then add bb.2 with unconditional jump to bb.4). | |
| # Original C code: | |
| # extern int inita(int *); | |
| # void foo(int x) { | |
| # if (x != 3) { | |
| # int q[128]; | |
| # inita(&q[0]); | |
| # return; | |
| # } | |
| # int r[128]; | |
| # inita(&r[x]); | |
| # } | |
| --- | | |
| define void @foo(i32 %x) { | |
| entry: | |
| %q = alloca [128 x i32], align 16 | |
| %r = alloca [128 x i32], align 16 | |
| %cmp = icmp eq i32 %x, 3 | |
| br i1 %cmp, label %if.end, label %if.then | |
| if.then: ; preds = %entry | |
| %0 = bitcast ptr %q to ptr | |
| call void @llvm.lifetime.start.p0(i64 512, ptr nonnull %0) | |
| %arrayidx2 = bitcast ptr %q to ptr | |
| %call = call i32 @inita(ptr nonnull %arrayidx2) | |
| call void @llvm.lifetime.end.p0(i64 512, ptr nonnull %0) | |
| br label %return | |
| unreachable: | |
| br label %return | |
| if.end: ; preds = %entry | |
| %1 = bitcast ptr %r to ptr | |
| call void @llvm.lifetime.start.p0(i64 512, ptr nonnull %1) | |
| %arrayidx1 = getelementptr inbounds [128 x i32], ptr %r, i64 0, i64 3 | |
| %call2 = call i32 @inita(ptr nonnull %arrayidx1) | |
| call void @llvm.lifetime.end.p0(i64 512, ptr nonnull %1) | |
| br label %return | |
| return: ; preds = %if.end, %if.then | |
| ret void | |
| } | |
| declare void @llvm.lifetime.start.p0(i64, ptr nocapture) | |
| declare i32 @inita(ptr) | |
| declare void @llvm.lifetime.end.p0(i64, ptr nocapture) | |
| declare void @llvm.stackprotector(ptr, ptr) | |
| ... | |
| --- | |
| name: foo | |
| alignment: 16 | |
| exposesReturnsTwice: false | |
| legalized: false | |
| regBankSelected: false | |
| selected: false | |
| failedISel: false | |
| tracksRegLiveness: true | |
| registers: | |
| - { id: 0, class: gr32, preferred-register: '' } | |
| - { id: 1, class: gr32, preferred-register: '' } | |
| - { id: 2, class: gr64, preferred-register: '' } | |
| - { id: 3, class: gr32, preferred-register: '' } | |
| - { id: 4, class: gr64, preferred-register: '' } | |
| - { id: 5, class: gr32, preferred-register: '' } | |
| liveins: | |
| - { reg: '$edi' } | |
| frameInfo: | |
| isFrameAddressTaken: false | |
| isReturnAddressTaken: false | |
| hasStackMap: false | |
| hasPatchPoint: false | |
| stackSize: 0 | |
| offsetAdjustment: 0 | |
| maxAlignment: 16 | |
| adjustsStack: false | |
| hasCalls: true | |
| stackProtector: '' | |
| maxCallFrameSize: 4294967295 | |
| hasOpaqueSPAdjustment: false | |
| hasVAStart: false | |
| hasMustTailInVarArgFunc: false | |
| localFrameSize: 0 | |
| savePoint: [] | |
| restorePoint: [] | |
| fixedStack: | |
| stack: | |
| - { id: 0, name: q, type: default, offset: 0, size: 512, alignment: 16, | |
| stack-id: default, callee-saved-register: '', callee-saved-restored: true, | |
| debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } | |
| - { id: 1, name: r, type: default, offset: 0, size: 512, alignment: 16, | |
| stack-id: default, callee-saved-register: '', callee-saved-restored: true, | |
| debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } | |
| constants: | |
| body: | | |
| bb.0.entry: | |
| successors: %bb.3(0x40000000), %bb.1(0x40000000) | |
| liveins: $edi | |
| %0:gr32 = COPY $edi | |
| %1:gr32 = SUB32ri8 %0, 3, implicit-def $eflags | |
| JCC_1 %bb.3, 4, implicit $eflags | |
| JMP_1 %bb.1 | |
| bb.1.if.then: | |
| successors: %bb.4(0x80000000) | |
| LIFETIME_START %stack.0.q | |
| ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | |
| %2:gr64 = LEA64r %stack.0.q, 1, $noreg, 0, $noreg | |
| $rdi = COPY %2 | |
| CALL64pcrel32 @inita, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax | |
| ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | |
| %3:gr32 = COPY $eax | |
| LIFETIME_END %stack.0.q | |
| JMP_1 %bb.4 | |
| bb.2.unreachable: | |
| successors: %bb.4(0x80000000) | |
| JMP_1 %bb.4 | |
| bb.3.if.end: | |
| successors: %bb.4(0x80000000) | |
| LIFETIME_START %stack.1.r | |
| %4:gr64 = LEA64r %stack.1.r, 1, $noreg, 12, $noreg | |
| ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | |
| $rdi = COPY %4 | |
| CALL64pcrel32 @inita, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp, implicit-def $eax | |
| ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp | |
| %5:gr32 = COPY $eax | |
| LIFETIME_END %stack.1.r | |
| bb.4.return: | |
| RET 0 | |
| ... |