void X86RetpolineThunks::populateThunk(MachineFunction &MF, unsigned Reg) { // Set MF properties. We never use vregs... MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); // Grab the entry MBB and erase any other blocks. O0 codegen appears to // generate two bbs for the entry block. MachineBasicBlock *Entry = &MF.front(); Entry->clear(); while (MF.size() > 1) MF.erase(std::next(MF.begin())); MachineBasicBlock *CaptureSpec = MF.CreateMachineBasicBlock(Entry->getBasicBlock()); MachineBasicBlock *CallTarget = MF.CreateMachineBasicBlock(Entry->getBasicBlock()); MCSymbol *TargetSym = MF.getContext().createTempSymbol(); MF.push_back(CaptureSpec); MF.push_back(CallTarget); const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; const unsigned RetOpc = Is64Bit ? X86::RETQ : X86::RETL; Entry->addLiveIn(Reg); BuildMI(Entry, DebugLoc(), TII->get(CallOpc)).addSym(TargetSym); // The MIR verifier thinks that the CALL in the entry block will fall through // to CaptureSpec, so mark it as the successor. Technically, CaptureTarget is // the successor, but the MIR verifier doesn't know how to cope with that. Entry->addSuccessor(CaptureSpec); // In the capture loop for speculation, we want to stop the processor from // speculating as fast as possible. On Intel processors, the PAUSE instruction // will block speculation without consuming any execution resources. On AMD // processors, the PAUSE instruction is (essentially) a nop, so we also use an // LFENCE instruction which they have advised will stop speculation as well // with minimal resource utilization. We still end the capture with a jump to // form an infinite loop to fully guarantee that no matter what implementation // of the x86 ISA, speculating this code path never escapes. BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::PAUSE)); BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::LFENCE)); BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::JMP_1)).addMBB(CaptureSpec); CaptureSpec->setHasAddressTaken(); CaptureSpec->addSuccessor(CaptureSpec); CallTarget->addLiveIn(Reg); CallTarget->setHasAddressTaken(); CallTarget->setAlignment(4); insertRegReturnAddrClobber(*CallTarget, Reg); CallTarget->back().setPreInstrSymbol(MF, TargetSym); BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc)); }
void PatmosSPMark::removeUncalledSPFunctions(const Module &M) { for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-maybe")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); if (!PMFI->isSinglePath()) { DEBUG(dbgs() << " Remove function: " << F->getName() << "\n"); // delete all MBBs while (MF->begin() != MF->end()) { MF->begin()->eraseFromParent(); } // insert a new single MBB with a single return instruction MachineBasicBlock *EmptyMBB = MF->CreateMachineBasicBlock(); MF->push_back(EmptyMBB); DebugLoc DL; AddDefaultPred(BuildMI(*EmptyMBB, EmptyMBB->end(), DL, TM.getInstrInfo()->get(Patmos::RET))); NumSPCleared++; // bump STATISTIC }; } } }
/// Insert LOOP and BLOCK markers at appropriate places. static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI, const WebAssemblyInstrInfo &TII) { for (auto &MBB : MF) { // Place the LOOP for loops. if (MachineLoop *Loop = MLI.getLoopFor(&MBB)) if (Loop->getHeader() == &MBB) { // The operand of a LOOP is the first block after the loop. If the loop // is the bottom of the function, insert a dummy block at the end. MachineBasicBlock *Bottom = Loop->getBottomBlock(); auto Iter = next(MachineFunction::iterator(Bottom)); if (Iter == MF.end()) { MF.push_back(MF.CreateMachineBasicBlock()); Iter = next(MachineFunction::iterator(Bottom)); } BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP)) .addMBB(&*Iter); } // Check for forward branches and switches that need BLOCKS placed. for (auto &Term : MBB.terminators()) for (auto &MO : Term.operands()) if (MO.isMBB()) PlaceBlockMarkers(MBB, *MO.getMBB(), MF, MLI, TII); } }
/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). static void PlaceLoopMarker(MachineBasicBlock &MBB, MachineFunction &MF, SmallVectorImpl<MachineBasicBlock *> &ScopeTops, const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) { MachineLoop *Loop = MLI.getLoopFor(&MBB); if (!Loop || Loop->getHeader() != &MBB) return; // The operand of a LOOP is the first block after the loop. If the loop is the // bottom of the function, insert a dummy block at the end. MachineBasicBlock *Bottom = LoopBottom(Loop); auto Iter = next(MachineFunction::iterator(Bottom)); if (Iter == MF.end()) { MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); // Give it a fake predecessor so that AsmPrinter prints its label. Label->addSuccessor(Label); MF.push_back(Label); Iter = next(MachineFunction::iterator(Bottom)); } MachineBasicBlock *AfterLoop = &*Iter; BuildMI(MBB, MBB.begin(), DebugLoc(), TII.get(WebAssembly::LOOP)) .addMBB(AfterLoop); // Emit a special no-op telling the asm printer that we need a label to close // the loop scope, even though the destination is only reachable by // fallthrough. if (!Bottom->back().isBarrier()) BuildMI(*Bottom, Bottom->end(), DebugLoc(), TII.get(WebAssembly::LOOP_END)); assert((!ScopeTops[AfterLoop->getNumber()] || ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && "With RPO we should visit the outer-most loop for a block first."); if (!ScopeTops[AfterLoop->getNumber()]) ScopeTops[AfterLoop->getNumber()] = &MBB; }
bool VPreRegAllocSched::runOnMachineFunction(MachineFunction &MF) { TII = MF.getTarget().getInstrInfo(); MRI = &MF.getRegInfo(); FInfo = MF.getInfo<VFInfo>(); AA = &getAnalysis<AliasAnalysis>(); MLI = &getAnalysis<MachineLoopInfo>(); MDT= &getAnalysis<MachineDominatorTree>(); LI = &getAnalysis<LoopInfo>(); SE = &getAnalysis<ScalarEvolution>(); // Create a place holder for the virtual exit for the scheduling graph. MachineBasicBlock *VirtualExit = MF.CreateMachineBasicBlock(); MF.push_back(VirtualExit); VSchedGraph G(getAnalysis<DetialLatencyInfo>(), EnableDangling, false, 1); buildGlobalSchedulingGraph(G, &MF.front(), VirtualExit); schedule(G); DEBUG(G.viewCPGraph()); DEBUG(G.viewDPGraph()); // Erase the virtual exit block. VirtualExit->eraseFromParent(); MF.RenumberBlocks(&MF.back()); unsigned TotalCycles = G.emitSchedule(); FInfo->setTotalSlots(TotalCycles); cleanUpSchedule(); return true; }
void X86RetpolineThunks::populateThunk(MachineFunction &MF, Optional<unsigned> Reg) { // Set MF properties. We never use vregs... MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); MachineBasicBlock *Entry = &MF.front(); Entry->clear(); MachineBasicBlock *CaptureSpec = MF.CreateMachineBasicBlock(Entry->getBasicBlock()); MachineBasicBlock *CallTarget = MF.CreateMachineBasicBlock(Entry->getBasicBlock()); MF.push_back(CaptureSpec); MF.push_back(CallTarget); const unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; const unsigned RetOpc = Is64Bit ? X86::RETQ : X86::RETL; BuildMI(Entry, DebugLoc(), TII->get(CallOpc)).addMBB(CallTarget); Entry->addSuccessor(CallTarget); Entry->addSuccessor(CaptureSpec); CallTarget->setHasAddressTaken(); // In the capture loop for speculation, we want to stop the processor from // speculating as fast as possible. On Intel processors, the PAUSE instruction // will block speculation without consuming any execution resources. On AMD // processors, the PAUSE instruction is (essentially) a nop, so we also use an // LFENCE instruction which they have advised will stop speculation as well // with minimal resource utilization. We still end the capture with a jump to // form an infinite loop to fully guarantee that no matter what implementation // of the x86 ISA, speculating this code path never escapes. BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::PAUSE)); BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::LFENCE)); BuildMI(CaptureSpec, DebugLoc(), TII->get(X86::JMP_1)).addMBB(CaptureSpec); CaptureSpec->setHasAddressTaken(); CaptureSpec->addSuccessor(CaptureSpec); CallTarget->setAlignment(4); insertRegReturnAddrClobber(*CallTarget, *Reg); BuildMI(CallTarget, DebugLoc(), TII->get(RetOpc)); }
/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). static void PlaceLoopMarker( MachineBasicBlock &MBB, MachineFunction &MF, SmallVectorImpl<MachineBasicBlock *> &ScopeTops, DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops, const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) { MachineLoop *Loop = MLI.getLoopFor(&MBB); if (!Loop || Loop->getHeader() != &MBB) return; // The operand of a LOOP is the first block after the loop. If the loop is the // bottom of the function, insert a dummy block at the end. MachineBasicBlock *Bottom = LoopBottom(Loop); auto Iter = next(MachineFunction::iterator(Bottom)); if (Iter == MF.end()) { MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); // Give it a fake predecessor so that AsmPrinter prints its label. Label->addSuccessor(Label); MF.push_back(Label); Iter = next(MachineFunction::iterator(Bottom)); } MachineBasicBlock *AfterLoop = &*Iter; // Mark the beginning of the loop (after the end of any existing loop that // ends here). auto InsertPos = MBB.begin(); while (InsertPos != MBB.end() && InsertPos->getOpcode() == WebAssembly::END_LOOP) ++InsertPos; BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP)); // Mark the end of the loop. MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(), TII.get(WebAssembly::END_LOOP)); LoopTops[End] = &MBB; assert((!ScopeTops[AfterLoop->getNumber()] || ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && "With block sorting the outermost loop for a block should be first."); if (!ScopeTops[AfterLoop->getNumber()]) ScopeTops[AfterLoop->getNumber()] = &MBB; }
bool ShadowCallStack::runOnMachineFunction(MachineFunction &Fn) { if (!Fn.getFunction().hasFnAttribute(Attribute::ShadowCallStack) || Fn.getFunction().hasFnAttribute(Attribute::Naked)) return false; if (Fn.empty() || !Fn.getRegInfo().tracksLiveness()) return false; // FIXME: Skip functions that have r10 or r11 live on entry (r10 can be live // on entry for parameters with the nest attribute.) if (Fn.front().isLiveIn(X86::R10) || Fn.front().isLiveIn(X86::R11)) return false; // FIXME: Skip functions with conditional and r10 tail calls for now. bool HasReturn = false; for (auto &MBB : Fn) { if (MBB.empty()) continue; const MachineInstr &MI = MBB.instr_back(); if (MI.isReturn()) HasReturn = true; if (MI.isReturn() && MI.isCall()) { if (MI.findRegisterUseOperand(X86::EFLAGS)) return false; // This should only be possible on Windows 64 (see GR64_TC versus // GR64_TCW64.) if (MI.findRegisterUseOperand(X86::R10) || MI.hasRegisterImplicitUseOperand(X86::R10)) return false; } } if (!HasReturn) return false; // For leaf functions: // 1. Do not instrument very short functions where it would not improve that // function's security. // 2. Detect if there is an unused caller-saved register we can reserve to // hold the return address instead of writing/reading it from the shadow // call stack. MCPhysReg LeafFuncRegister = X86::NoRegister; if (!Fn.getFrameInfo().adjustsStack()) { size_t InstructionCount = 0; std::bitset<X86::NUM_TARGET_REGS> UsedRegs; for (auto &MBB : Fn) { for (auto &LiveIn : MBB.liveins()) UsedRegs.set(LiveIn.PhysReg); for (auto &MI : MBB) { if (!MI.isDebugValue() && !MI.isCFIInstruction() && !MI.isLabel()) InstructionCount++; for (auto &Op : MI.operands()) if (Op.isReg() && Op.isDef()) UsedRegs.set(Op.getReg()); } } if (InstructionCount <= SkipLeafInstructions) return false; std::bitset<X86::NUM_TARGET_REGS> CalleeSavedRegs; const MCPhysReg *CSRegs = Fn.getRegInfo().getCalleeSavedRegs(); for (size_t i = 0; CSRegs[i]; i++) CalleeSavedRegs.set(CSRegs[i]); const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo(); for (auto &Reg : X86::GR64_NOSPRegClass.getRegisters()) { // FIXME: Optimization opportunity: spill/restore a callee-saved register // if a caller-saved register is unavailable. if (CalleeSavedRegs.test(Reg)) continue; bool Used = false; for (MCSubRegIterator SR(Reg, TRI, true); SR.isValid(); ++SR) if ((Used = UsedRegs.test(*SR))) break; if (!Used) { LeafFuncRegister = Reg; break; } } } const bool LeafFuncOptimization = LeafFuncRegister != X86::NoRegister; if (LeafFuncOptimization) // Mark the leaf function register live-in for all MBBs except the entry MBB for (auto I = ++Fn.begin(), E = Fn.end(); I != E; ++I) I->addLiveIn(LeafFuncRegister); MachineBasicBlock &MBB = Fn.front(); const MachineBasicBlock *NonEmpty = MBB.empty() ? MBB.getFallThrough() : &MBB; const DebugLoc &DL = NonEmpty->front().getDebugLoc(); const TargetInstrInfo *TII = Fn.getSubtarget().getInstrInfo(); if (LeafFuncOptimization) addPrologLeaf(Fn, TII, MBB, DL, LeafFuncRegister); else addProlog(Fn, TII, MBB, DL); MachineBasicBlock *Trap = nullptr; for (auto &MBB : Fn) { if (MBB.empty()) continue; MachineInstr &MI = MBB.instr_back(); if (MI.isReturn()) { if (!Trap) { Trap = Fn.CreateMachineBasicBlock(); BuildMI(Trap, MI.getDebugLoc(), TII->get(X86::TRAP)); Fn.push_back(Trap); } if (LeafFuncOptimization) addEpilogLeaf(TII, MBB, MI, *Trap, LeafFuncRegister); else if (MI.findRegisterUseOperand(X86::R11)) addEpilogOnlyR10(TII, MBB, MI, *Trap); else addEpilog(TII, MBB, MI, *Trap); } } return true; }
bool PatmosSPMark::runOnMachineModule(const Module &M) { DEBUG( dbgs() << "[Single-Path] Mark functions reachable from single-path roots\n"); MMI = &getAnalysis<MachineModuleInfo>(); assert(MMI); Worklist W; // initialize the worklist with machine functions that have either // sp-root or sp-reachable function attribute for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-root") || F->hasFnAttribute("sp-reachable")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); PMFI->setSinglePath(); NumSPTotal++; // bump STATISTIC W.push_back(MF); } } // process worklist while (!W.empty()) { MachineFunction *MF = W.front(); W.pop_front(); scanAndRewriteCalls(MF, W); } // clear all cloned machine functions that are not marked as single-path // by now for(Module::const_iterator F(M.begin()), FE(M.end()); F != FE; ++F) { if (F->hasFnAttribute("sp-maybe")) { // get the machine-level function MachineFunction *MF = MMI->getMachineFunction(F); assert( MF ); PatmosMachineFunctionInfo *PMFI = MF->getInfo<PatmosMachineFunctionInfo>(); if (!PMFI->isSinglePath()) { // delete all MBBs while (MF->begin() != MF->end()) { MF->begin()->eraseFromParent(); } // insert a new single MBB with a single return instruction MachineBasicBlock *EmptyMBB = MF->CreateMachineBasicBlock(); MF->push_back(EmptyMBB); DebugLoc DL; AddDefaultPred(BuildMI(*EmptyMBB, EmptyMBB->end(), DL, TM.getInstrInfo()->get(Patmos::RET))); NumSPCleared++; // bump STATISTIC }; } } return true; }