diff options
-rw-r--r-- | lib/CodeGen/VirtRegMap.cpp | 42 | ||||
-rw-r--r-- | test/CodeGen/ARM/noreturn.ll | 38 |
2 files changed, 77 insertions, 3 deletions
diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index cd012d2..0a08608 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -28,6 +28,7 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/IR/Function.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" @@ -264,15 +265,32 @@ void VirtRegRewriter::rewrite() { SmallVector<unsigned, 8> SuperDeads; SmallVector<unsigned, 8> SuperDefs; SmallVector<unsigned, 8> SuperKills; + SmallPtrSet<const MachineInstr *, 4> NoReturnInsts; for (MachineFunction::iterator MBBI = MF->begin(), MBBE = MF->end(); MBBI != MBBE; ++MBBI) { DEBUG(MBBI->print(dbgs(), Indexes)); + bool IsExitBB = MBBI->succ_empty(); for (MachineBasicBlock::instr_iterator MII = MBBI->instr_begin(), MIE = MBBI->instr_end(); MII != MIE;) { MachineInstr *MI = MII; ++MII; + // Check if this instruction is a call to a noreturn function. + // If so, all the definitions set by this instruction can be ignored. + if (IsExitBB && MI->isCall()) + for (MachineInstr::mop_iterator MOI = MI->operands_begin(), + MOE = MI->operands_end(); MOI != MOE; ++MOI) { + MachineOperand &MO = *MOI; + if (!MO.isGlobal()) + continue; + const Function *Func = dyn_cast<Function>(MO.getGlobal()); + if (!Func || !Func->hasFnAttribute(Attribute::NoReturn)) + continue; + NoReturnInsts.insert(MI); + break; + } + for (MachineInstr::mop_iterator MOI = MI->operands_begin(), MOE = MI->operands_end(); MOI != MOE; ++MOI) { MachineOperand &MO = *MOI; @@ -353,7 +371,25 @@ void VirtRegRewriter::rewrite() { } // Tell MRI about physical registers in use. - for (unsigned Reg = 1, RegE = TRI->getNumRegs(); Reg != RegE; ++Reg) - if (!MRI->reg_nodbg_empty(Reg)) - MRI->setPhysRegUsed(Reg); + if (NoReturnInsts.empty()) { + for (unsigned Reg = 1, RegE = TRI->getNumRegs(); Reg != RegE; ++Reg) + if (!MRI->reg_nodbg_empty(Reg)) + MRI->setPhysRegUsed(Reg); + } else { + for (unsigned Reg = 1, RegE = TRI->getNumRegs(); Reg != RegE; ++Reg) { + if (MRI->reg_nodbg_empty(Reg)) + continue; + // Check if this register has a use that will impact the rest of the + // code. Uses in debug and noreturn instructions do not impact the + // generated code. + for (MachineRegisterInfo::reg_nodbg_iterator It = + MRI->reg_nodbg_begin(Reg), + EndIt = MRI->reg_nodbg_end(); It != EndIt; ++It) { + if (!NoReturnInsts.count(&(*It))) { + MRI->setPhysRegUsed(Reg); + break; + } + } + } + } } diff --git a/test/CodeGen/ARM/noreturn.ll b/test/CodeGen/ARM/noreturn.ll new file mode 100644 index 0000000..3a5c39e --- /dev/null +++ b/test/CodeGen/ARM/noreturn.ll @@ -0,0 +1,38 @@ +; RUN: llc -O3 -o - %s | FileCheck %s +; Test case from PR16882. +target triple = "thumbv7s-apple-ios" + +; Function Attrs: noreturn +define i32 @test1() #0 { +; CHECK-LABEL: @test1 +; CHECK-NOT: push +entry: + tail call void @overflow() #0 + unreachable +} + +; Function Attrs: noreturn +declare void @overflow() #0 + +define i32 @test2(i32 %x, i32 %y) { +; CHECK-LABEL: @test2 +; CHECK-NOT: push +; CHECK-NOT: pop +entry: + %conv = sext i32 %x to i64 + %conv1 = sext i32 %y to i64 + %mul = mul nsw i64 %conv1, %conv + %conv2 = trunc i64 %mul to i32 + %conv3 = sext i32 %conv2 to i64 + %cmp = icmp eq i64 %mul, %conv3 + br i1 %cmp, label %if.end, label %if.then + +if.then: ; preds = %entry + tail call void @overflow() #0 + unreachable + +if.end: ; preds = %entry + ret i32 %conv2 +} + +attributes #0 = { noreturn } |