diff --git a/llvm/lib/Target/SBF/SBFMIPeephole.cpp b/llvm/lib/Target/SBF/SBFMIPeephole.cpp index 13caaf29f8b522..49c58ab18c062d 100644 --- a/llvm/lib/Target/SBF/SBFMIPeephole.cpp +++ b/llvm/lib/Target/SBF/SBFMIPeephole.cpp @@ -131,6 +131,8 @@ struct SBFMIPreEmitPeephole : public MachineFunctionPass { static char ID; MachineFunction *MF; const TargetRegisterInfo *TRI; + const SBFInstrInfo *TII; + const SBFSubtarget *SubTarget; SBFMIPreEmitPeephole() : MachineFunctionPass(ID) { initializeSBFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); @@ -141,6 +143,7 @@ struct SBFMIPreEmitPeephole : public MachineFunctionPass { void initialize(MachineFunction &MFParm); bool eliminateRedundantMov(); + bool addReturn(); public: @@ -151,17 +154,60 @@ struct SBFMIPreEmitPeephole : public MachineFunctionPass { initialize(MF); - return eliminateRedundantMov(); + bool PeepholeExecuted = false; + if (SubTarget->getHasStaticSyscalls()) + PeepholeExecuted |= addReturn(); + + PeepholeExecuted |= eliminateRedundantMov(); + + return PeepholeExecuted; } }; // Initialize class variables. void SBFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { MF = &MFParm; - TRI = MF->getSubtarget().getRegisterInfo(); + SubTarget = &MF->getSubtarget(); + TRI = SubTarget->getRegisterInfo(); + TII = SubTarget->getInstrInfo(); LLVM_DEBUG(dbgs() << "*** SBF PreEmit peephole pass ***\n\n"); } +bool SBFMIPreEmitPeephole::addReturn() { + bool Added = false; + + // In SBFv3, every function must either end with either a JA or a RETURN + // instruction. When we call a function that will never return the control + // flow (e.g. when the callee aborts execution), the caller last instruction + // will be a CALL, failing validation. + // + // Although we can change ISelLowering and manually add the return for an + // LLVM-IR unreachable instruction, LLVM codegen uses the target machine's + // return instruction to determine whether a function needs an epilogue, + // increasing code size more, even when we know the call won't transfer + // control back to the caller. + // + // In that case, we can analyze every function before emitting machine code + // and include a useless return instruction. + + for (MachineBasicBlock &MBB: *MF) { + if (!MBB.succ_empty() || MBB.empty()) + continue; + + MachineInstr &MI = MBB.back(); + unsigned Opcode = MI.getOpcode(); + if (Opcode == SBF::JAL || + Opcode == SBF::JALX || + Opcode == SBF::JALX_v2 || + Opcode == SBF::SYSCALL_v3) { + BuildMI(&MBB, MI.getDebugLoc(), TII->get(SBF::RETURN_v3)); + Added = true; + } + } + + return Added; +} + bool SBFMIPreEmitPeephole::eliminateRedundantMov() { MachineInstr* ToErase = nullptr; bool Eliminated = false; diff --git a/llvm/test/CodeGen/SBF/unreachable_return.ll b/llvm/test/CodeGen/SBF/unreachable_return.ll new file mode 100644 index 00000000000000..db1ac3f1c10279 --- /dev/null +++ b/llvm/test/CodeGen/SBF/unreachable_return.ll @@ -0,0 +1,17 @@ +; RUN: llc -O2 -march=sbf -mcpu=v3 < %s | FileCheck %s + +declare void @dummy_func(i8, ptr, ptr, ptr, ptr, ptr, ptr) + +define internal fastcc void @test_func(ptr %0, ptr %1, ptr %args, ptr %2) { +start: +; CHECK: add64 r10, -64 + %right = alloca [8 x i8], align 8 + %left = alloca [8 x i8], align 8 + store ptr %0, ptr %left, align 8 + store ptr %1, ptr %right, align 8 + call void @dummy_func(i8 0, ptr %left, ptr %left, ptr %right, ptr %right, ptr %args, ptr %2) + unreachable +; CHECK: call dummy_func +; CHECK-NOT: add64 r10, 64 +; CHECK: return +} \ No newline at end of file