| # In certain cases CodeGenPrepare folds a return instruction into |
| # the return block's predecessor blocks and subsequently deletes the return block. |
| # The purpose of this is to enable tail call optimization in the predecessor blocks. |
| # Removal of the return block also removes fake use instructions that were present |
| # in the return block, potentially causing debug information to be lost. |
| # |
| # The fix is to clone any fake use instructions that are not dominated by definitions |
| # in the return block itself into the predecessor blocks. This test enures that we do so. |
| # |
| # Generated from the following source with |
| # clang -fextend-variable-liveness -S -emit-llvm -O2 -mllvm -stop-before=codegenprepare -o test.mir test.c |
| # |
| # extern int f0(); |
| # extern int f1(); |
| # |
| # int foo(int i) { |
| # int temp = i; |
| # if (temp == 0) |
| # temp = f0(); |
| # else |
| # temp = f1(); |
| # return temp; |
| # } |
| # |
| # RUN: llc -run-pass=codegenprepare -mtriple=x86_64-unknown-linux -o - %s | FileCheck %s |
| # |
| # CHECK: define{{.*}}foo |
| # CHECK: if.then: |
| # CHECK-NEXT: call{{.*}}fake.use(i32 %i) |
| # CHECK-NEXT: tail call i32{{.*}}@f0 |
| # CHECK-NEXT: ret |
| # CHECK: if.else: |
| # CHECK-NEXT: call{{.*}}fake.use(i32 %i) |
| # CHECK-NEXT: tail call i32{{.*}}@f1 |
| # CHECK-NEXT: ret |
| |
| --- | |
| define hidden i32 @foo(i32 %i) local_unnamed_addr optdebug { |
| entry: |
| %cmp = icmp eq i32 %i, 0 |
| br i1 %cmp, label %if.then, label %if.else |
| |
| if.then: |
| %call = tail call i32 (...) @f0() |
| br label %if.end |
| |
| if.else: |
| %call1 = tail call i32 (...) @f1() |
| br label %if.end |
| |
| if.end: |
| %temp.0 = phi i32 [ %call, %if.then ], [ %call1, %if.else ] |
| notail call void (...) @llvm.fake.use(i32 %temp.0) |
| notail call void (...) @llvm.fake.use(i32 %i) |
| ret i32 %temp.0 |
| } |
| declare i32 @f0(...) local_unnamed_addr |
| declare i32 @f1(...) local_unnamed_addr |
| |
| ... |
| --- |
| name: foo |
| alignment: 16 |
| exposesReturnsTwice: false |
| legalized: false |
| regBankSelected: false |
| selected: false |
| failedISel: false |
| tracksRegLiveness: true |
| hasWinCFI: false |
| registers: [] |
| liveins: [] |
| frameInfo: |
| isFrameAddressTaken: false |
| isReturnAddressTaken: false |
| hasStackMap: false |
| hasPatchPoint: false |
| stackSize: 0 |
| offsetAdjustment: 0 |
| maxAlignment: 1 |
| adjustsStack: false |
| hasCalls: false |
| stackProtector: '' |
| maxCallFrameSize: 4294967295 |
| cvBytesOfCalleeSavedRegisters: 0 |
| hasOpaqueSPAdjustment: false |
| hasVAStart: false |
| hasMustTailInVarArgFunc: false |
| localFrameSize: 0 |
| savePoint: '' |
| restorePoint: '' |
| fixedStack: [] |
| stack: [] |
| callSites: [] |
| constants: [] |
| machineFunctionInfo: {} |
| body: | |
| |
| ... |