Index: include/llvm/CodeGen/CommandFlags.h =================================================================== --- include/llvm/CodeGen/CommandFlags.h +++ include/llvm/CodeGen/CommandFlags.h @@ -186,7 +186,7 @@ cl::opt NOPInsertion("nop-insertion", - cl::desc("Randomly add NOPs."), + cl::desc("Randomly add noop instructions to create fine-grained diversity."), cl::init(false)); cl::opt StopAfter("stop-after", @@ -243,8 +243,8 @@ Options.StackAlignmentOverride = OverrideStackAlignment; Options.TrapFuncName = TrapFuncName; Options.PositionIndependentExecutable = EnablePIE; - Options.UseInitArray = UseInitArray; Options.NOPInsertion = NOPInsertion; + Options.UseInitArray = UseInitArray; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Index: include/llvm/CodeGen/NOPInsertion.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/NOPInsertion.h @@ -0,0 +1,35 @@ +//===-- NOPInsertion.h - NOP Insertion -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass adds fine-grained diversity by displacing code using randomly +// placed (optionally target supplied) NOP instructions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_NOPINSERTION_H +#define LLVM_CODEGEN_NOPINSERTION_H + +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { + +class NOPInsertion : public MachineFunctionPass { +public: + static char ID; + + NOPInsertion(); + + bool runOnMachineFunction(MachineFunction &MF); + + void getAnalysisUsage(AnalysisUsage &AU) const override; +}; + +} + +#endif // LLVM_CODEGEN_NOPINSERTION_H Index: include/llvm/CodeGen/Passes.h =================================================================== --- include/llvm/CodeGen/Passes.h +++ include/llvm/CodeGen/Passes.h @@ -588,6 +588,10 @@ /// the intrinsic for later emission to the StackMap. extern char &StackMapLivenessID; + /// NOPInsertion - This pass adds fine-grained diversity by displacing code + /// using randomly placed (optionally target supplied) NOP instructions. + extern char &NOPInsertionID; + /// createJumpInstrTables - This pass creates jump-instruction tables. ModulePass *createJumpInstrTablesPass(); } // End llvm namespace Index: include/llvm/IR/Module.h =================================================================== --- include/llvm/IR/Module.h +++ include/llvm/IR/Module.h @@ -254,6 +254,17 @@ /// @returns a string containing the module-scope inline assembly blocks. const std::string &getModuleInlineAsm() const { return GlobalScopeAsm; } + /// Get a RandomNumberGenerator salted for use with this module. The + /// RNG can be seeded via -rng-seed= and is salted with the + /// ModuleID and the provided pass salt. The returned RNG should not + /// be shared across threads or passes. + /// + /// A unique RNG per pass ensures a reproducible random stream even + /// when other randomness consuming passes are added or removed. In + /// addition, the random stream will be reproducible across LLVM + /// versions when the pass does not change. + RandomNumberGenerator *createRNG(const Pass* P) const; + /// @} /// @name Module Level Mutators /// @{ Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -199,6 +199,7 @@ void initializeMergeFunctionsPass(PassRegistry&); void initializeModuleDebugInfoPrinterPass(PassRegistry&); void initializeNoAAPass(PassRegistry&); +void initializeNOPInsertionPass(PassRegistry&); void initializeObjCARCAliasAnalysisPass(PassRegistry&); void initializeObjCARCAPElimPass(PassRegistry&); void initializeObjCARCExpandPass(PassRegistry&); Index: include/llvm/Support/RandomNumberGenerator.h =================================================================== --- include/llvm/Support/RandomNumberGenerator.h +++ include/llvm/Support/RandomNumberGenerator.h @@ -17,7 +17,6 @@ #define LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_ #include "llvm/ADT/StringRef.h" -#include "llvm/IR/Module.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" // Needed for uint64_t on Windows. #include @@ -25,26 +24,26 @@ namespace llvm { /// A random number generator. -/// Instances of this class should not be shared across threads. +/// +/// Instances of this class should not be shared across threads. The +/// seed should be set by passing the -rng-seed= option. Use +/// Module::createRNG to create a new RNG instance for use with that +/// module. class RandomNumberGenerator { public: - /// Seeds and salts the underlying RNG engine. The seed can be set - /// on the command line via -rng-seed=. - /// - /// The RNG is salted with the Module ID of M and a salt (usually - /// the pass name) provided by the client pass. Each pass which - /// needs randomness should instantiate its own pass, using a unique - /// seed. This ensures a reproducible random stream even when other - /// randomness consuming passes are added or removed. - RandomNumberGenerator(const Module &M, StringRef PassSalt); - /// Returns a random number in the range [0, Max). uint_fast64_t operator()(); private: + /// Seeds and salts the underlying RNG engine. + /// + /// This constructor should not be used directly. Instead use + /// Module::createRNG to create a new RNG salted with the Module ID. + RandomNumberGenerator(StringRef Salt); + // 64-bit Mersenne Twister by Matsumoto and Nishimura, 2000 // http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine - // This RNG should be deterministicly portable across C++11 + // This RNG is deterministically portable across C++11 // implementations. std::mt19937_64 Generator; @@ -53,6 +52,8 @@ LLVM_DELETED_FUNCTION; RandomNumberGenerator & operator=(const RandomNumberGenerator &other) LLVM_DELETED_FUNCTION; + + friend class Module; }; } Index: include/llvm/Target/TargetInstrInfo.h =================================================================== --- include/llvm/Target/TargetInstrInfo.h +++ include/llvm/Target/TargetInstrInfo.h @@ -30,6 +30,7 @@ class MCInst; class MCSchedModel; class MCSymbolRefExpr; +class RandomNumberGenerator; class SDNode; class ScheduleHazardRecognizer; class SelectionDAG; @@ -676,6 +677,15 @@ virtual void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const; + /// insertNoop - Insert a type of noop into the instruction stream at the + /// specified point to introduce fine-grained diversity. A target may randomly + /// choose from a pool of valid noops using the provided RNG. + virtual void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + RandomNumberGenerator *RNG) const { + insertNoop(MBB, MI); + } + /// getNoopForMachoTarget - Return the noop instruction to use for a noop. virtual void getNoopForMachoTarget(MCInst &NopInst) const { Index: include/llvm/Target/TargetOptions.h =================================================================== --- include/llvm/Target/TargetOptions.h +++ include/llvm/Target/TargetOptions.h @@ -165,7 +165,7 @@ /// if the relocation model is anything other than PIC. unsigned PositionIndependentExecutable : 1; - /// Attempt to insert NOPs + /// Randomly insert noop instructions to create fine-grained diversity unsigned NOPInsertion : 1; /// UseInitArray - Use .init_array instead of .ctors for static Index: lib/CodeGen/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -69,6 +69,7 @@ MachineSink.cpp MachineTraceMetrics.cpp MachineVerifier.cpp + NOPInsertion.cpp OcamlGC.cpp OptimizePHIs.cpp PHIElimination.cpp Index: lib/CodeGen/CodeGen.cpp =================================================================== --- lib/CodeGen/CodeGen.cpp +++ lib/CodeGen/CodeGen.cpp @@ -73,6 +73,7 @@ initializeLowerIntrinsicsPass(Registry); initializeMachineFunctionPrinterPassPass(Registry); initializeStackMapLivenessPass(Registry); + initializeNOPInsertionPass(Registry); } void LLVMInitializeCodeGen(LLVMPassRegistryRef R) { Index: lib/CodeGen/NOPInsertion.cpp =================================================================== --- /dev/null +++ lib/CodeGen/NOPInsertion.cpp @@ -0,0 +1,101 @@ +//===- NOPInsertion.cpp - NOP Insertion -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass adds fine-grained diversity by displacing code using randomly +// placed (optionally target supplied) NOP instructions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/NOPInsertion.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Target/TargetInstrInfo.h" +using namespace llvm; + +#define DEBUG_TYPE "nop-insertion" + +static cl::opt +NOPInsertionPercentage( + "nop-insertion-percentage", + cl::desc("Percentage of instructions that have NOPs prepended"), + cl::init(50)); + +static cl::opt +MaxNOPsPerInstruction( + "max-nops-per-instruction", + llvm::cl::desc("Maximum number of NOPs per instruction"), + llvm::cl::init(1)); + + +STATISTIC(InsertedNOPs, + "Total number of noop type instructions inserted for diversity"); + +char NOPInsertion::ID = 0; +char &llvm::NOPInsertionID = NOPInsertion::ID; +INITIALIZE_PASS(NOPInsertion, "nop-insertion", + "NOP Insertion for fine-grained code randomization", false, + false) + +NOPInsertion::NOPInsertion() : MachineFunctionPass(ID) { + initializeNOPInsertionPass(*PassRegistry::getPassRegistry()); + + // clamp percentage to 100 + if (NOPInsertionPercentage > 100) + NOPInsertionPercentage = 100; +} + +void NOPInsertion::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool NOPInsertion::runOnMachineFunction(MachineFunction &Fn) { + const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + + RandomNumberGenerator *RNG = Fn.getFunction()->getParent()->createRNG(this); + for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { + MachineBasicBlock::iterator FirstTerm = BB->getFirstTerminator(); + // Insert NOPs before instruction. + for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { + MachineBasicBlock::iterator NextI = std::next(I); + if (I->isPseudo()) { + I = NextI; + continue; + } + + // Insert random number of NOP-like instructions. + for (unsigned i = 0; i < MaxNOPsPerInstruction; i++) { + unsigned Roll = (*RNG)() % 100; // FIXME: not uniform + if (Roll >= NOPInsertionPercentage) + continue; + + TII->insertNoop(*BB, I, RNG); + + ++InsertedNOPs; + } + + // Do not insert NOPs between terminators. + if (I == FirstTerm) + break; + + I = NextI; + } + } + return true; +} + Index: lib/CodeGen/Passes.cpp =================================================================== --- lib/CodeGen/Passes.cpp +++ lib/CodeGen/Passes.cpp @@ -554,6 +554,9 @@ addPass(createGCInfoPrinter(dbgs())); } + if (TM->Options.NOPInsertion) + addPass(&NOPInsertionID); + // Basic block placement. if (getOptLevel() != CodeGenOpt::None) addBlockPlacement(); Index: lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp =================================================================== --- lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -27,7 +27,6 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" @@ -105,17 +104,6 @@ "sched-avg-ipc", cl::Hidden, cl::init(1), cl::desc("Average inst/cycle whan no target itinerary exists.")); -static cl::opt RandomizeSchedule( - "sched-randomize", - cl::desc("Enable randomization of scheduling"), - cl::init(false)); - -static cl::opt SchedRandPercentage( - "sched-randomize-percentage", - cl::desc("Percentage of instructions where schedule is randomized"), - cl::init(50)); - - namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGRRList - The actual register reduction list scheduler @@ -1771,17 +1759,6 @@ class RegReductionPriorityQueue : public RegReductionPQBase { SF Picker; - RandomNumberGenerator *RNG; - - SUnit *popRandom(std::vector &Q) { - size_t randIndex = (*RNG)() % Q.size(); // FIXME: not uniform - SUnit *V = Q[randIndex]; - if (randIndex < Q.size() - 1) - std::swap(Q[randIndex], Q.back()); - Q.pop_back(); - return V; - } - public: RegReductionPriorityQueue(MachineFunction &mf, bool tracksrp, @@ -1791,10 +1768,7 @@ const TargetLowering *tli) : RegReductionPQBase(mf, SF::HasReadyFilter, tracksrp, srcorder, tii, tri, tli), - Picker(this), RNG(nullptr) { - if (RandomizeSchedule) - RNG = new RandomNumberGenerator(*MF.getFunction()->getParent(), "RegReductionPriorityQueue"); - } + Picker(this) {} bool isBottomUp() const override { return SF::IsBottomUp; } @@ -1805,17 +1779,7 @@ SUnit *pop() override { if (Queue.empty()) return nullptr; - SUnit *V; - if (RandomizeSchedule) { - unsigned int Roll = (*RNG)() % 100; // FIXME: not uniform - if (Roll < SchedRandPercentage) { - V = popRandom(Queue); - } else { - V = popFromQueue(Queue, Picker, scheduleDAG); - } - } else { - V = popFromQueue(Queue, Picker, scheduleDAG); - } + SUnit *V = popFromQueue(Queue, Picker, scheduleDAG); V->NodeQueueId = 0; return V; } Index: lib/IR/Module.cpp =================================================================== --- lib/IR/Module.cpp +++ lib/IR/Module.cpp @@ -24,6 +24,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LeakDetector.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" #include #include @@ -62,6 +63,25 @@ delete static_cast *>(NamedMDSymTab); } +RandomNumberGenerator *Module::createRNG(const Pass* P) const { + SmallString<32> Salt(P->getPassName()); + + // This RNG is guaranteed to produce the same random stream only + // when the Module ID and thus the input filename is the same. This + // might be problematic if the input filename extension changes + // (e.g. from .c to .bc or .ll). + // + // We could store this salt in NamedMetadata, but this would make + // the parameter non-const. This would unfortunately make this + // interface unusable by any Machine passes, since they only have a + // const reference to their IR Module. Alternatively we can always + // store salt metadata from the Module constructor. + Salt += sys::path::filename(getModuleIdentifier()); + + return new RandomNumberGenerator(Salt); +} + + /// getNamedValue - Return the first global value in the module with /// the specified name, of arbitrary type. This method returns null /// if a global with the specified name is not found. Index: lib/Support/RandomNumberGenerator.cpp =================================================================== --- lib/Support/RandomNumberGenerator.cpp +++ lib/Support/RandomNumberGenerator.cpp @@ -16,7 +16,6 @@ #define DEBUG_TYPE "rng" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" using namespace llvm; @@ -29,37 +28,23 @@ Seed("rng-seed", cl::value_desc("seed"), cl::desc("Seed for the random number generator"), cl::init(0)); -RandomNumberGenerator::RandomNumberGenerator(const Module &M, StringRef PassSalt) { +RandomNumberGenerator::RandomNumberGenerator(StringRef Salt) { DEBUG( if (Seed == 0) dbgs() << "Warning! Using unseeded random number generator.\n" ); - // This RNG is guaranteed to produce the same random stream only - // when the Module ID and thus the input filename is the same. This - // might be problematic if the input filename extension changes - // (e.g. from .c to .bc or .ll). - // - // We could store this salt in NamedMetadata, but this would make - // the parameter non-const. This would unfortunately make this - // interface unusable by any Machine passes, since they only have a - // const reference to their IR Module. Alternatively we can always - // store salt metadata from the Module constructor. - StringRef ModuleSalt = sys::path::filename(M.getModuleIdentifier()); - // Combine seed and salts using std::seed_seq. - // Data: Seed-low, Seed-high, ModuleSalt, PassSalt + // Data: Seed-low, Seed-high, Salt // Note: std::seed_seq can only store 32-bit values, even though we - // are using a 64-bit RNG. This isn't a problem since the Mersenn - // twister constructor copies these correctly into its initial state + // are using a 64-bit RNG. This isn't a problem since the Mersenne + // twister constructor copies these correctly into its initial state. std::vector Data; - Data.reserve(2 + ModuleSalt.size() + PassSalt.size()); + Data.reserve(2 + Salt.size()); Data.push_back(Seed); Data.push_back(Seed >> 32); - std::vector::iterator I = Data.end(); - I = std::copy(ModuleSalt.begin(), ModuleSalt.end(), I); - I = std::copy(PassSalt.begin(), PassSalt.end(), I); + std::copy(Salt.begin(), Salt.end(), Data.end()); std::seed_seq SeedSeq(Data.begin(), Data.end()); Generator.seed(SeedSeq); Index: lib/Target/X86/CMakeLists.txt =================================================================== --- lib/Target/X86/CMakeLists.txt +++ lib/Target/X86/CMakeLists.txt @@ -13,7 +13,6 @@ add_public_tablegen_target(X86CommonTableGen) set(sources - NOPInsertion.cpp X86AsmPrinter.cpp X86AtomicExpandPass.cpp X86CodeEmitter.cpp Index: lib/Target/X86/NOPInsertion.cpp =================================================================== --- lib/Target/X86/NOPInsertion.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//===- NOPInsertion.cpp - Insert NOPs between instructions ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains the NOPInsertion pass. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "nop-insertion" -#include "X86InstrBuilder.h" -#include "X86InstrInfo.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/RandomNumberGenerator.h" -#include "llvm/Target/TargetInstrInfo.h" - -using namespace llvm; - -static cl::opt -NOPInsertionPercentage( - "nop-insertion-percentage", - cl::desc("Percentage of instructions that have NOPs prepended"), - cl::init(50)); - -static cl::opt -MaxNOPsPerInstruction( - "max-nops-per-instruction", - llvm::cl::desc("Maximum number of NOPs per instruction"), - llvm::cl::init(1)); - - -STATISTIC(InsertedNOPs, - "Total number of noop type instructions inserted for diversity"); - -namespace { -class NOPInsertionPass : public MachineFunctionPass { - - static char ID; - - bool is64Bit; - -public: - NOPInsertionPass(bool is64Bit_) : - MachineFunctionPass(ID), is64Bit(is64Bit_) { - } - - virtual bool runOnMachineFunction(MachineFunction &MF); - - virtual const char *getPassName() const { - return "NOP insertion pass"; - } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - MachineFunctionPass::getAnalysisUsage(AU); - } -}; -} - -char NOPInsertionPass::ID = 0; - -enum { NOP, - MOV_EBP, MOV_ESP, - LEA_ESI, LEA_EDI, - MAX_NOPS }; - -static const unsigned nopRegs[MAX_NOPS][2] = { - { 0, 0 }, - { X86::EBP, X86::RBP }, - { X86::ESP, X86::RSP }, - { X86::ESI, X86::RSI }, - { X86::EDI, X86::RDI }, -}; - -bool NOPInsertionPass::runOnMachineFunction(MachineFunction &Fn) { - const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); - - RandomNumberGenerator RNG(*Fn.getFunction()->getParent(), "NOPInsertion"); - for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { - MachineBasicBlock::iterator FirstTerm = BB->getFirstTerminator(); - // Insert NOPs before instruction. - for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { - MachineBasicBlock::iterator NextI = std::next(I); - if (I->isPseudo()) { - I = NextI; - continue; - } - // Insert random number of NOP-like instructions. - for (unsigned i = 0; i < MaxNOPsPerInstruction; i++) { - unsigned Roll = RNG() % 100; // FIXME: not uniform - if (Roll >= NOPInsertionPercentage) - continue; - - unsigned NOPCode = RNG() % MAX_NOPS; // FIXME: not uniform - - MachineInstr *NewMI = NULL; - unsigned reg = nopRegs[NOPCode][is64Bit]; - switch (NOPCode) { - case NOP: - NewMI = BuildMI(*BB, I, I->getDebugLoc(), TII->get(X86::NOOP)); - break; - case MOV_EBP: - case MOV_ESP: { - unsigned opc = is64Bit ? X86::MOV64rr : X86::MOV32rr; - NewMI = BuildMI(*BB, I, I->getDebugLoc(), TII->get(opc), reg) - .addReg(reg); - break; - } - - case LEA_ESI: - case LEA_EDI: { - unsigned opc = is64Bit ? X86::LEA64r : X86::LEA32r; - NewMI = addRegOffset(BuildMI(*BB, I, I->getDebugLoc(), - TII->get(opc), reg), - reg, false, 0); - break; - } - } - - if (NewMI != NULL) - ++InsertedNOPs; - } - // Do not insert NOPs between terminators. - if (I == FirstTerm) - break; - - I = NextI; - } - } - return true; -} - -namespace llvm { - FunctionPass *createNOPInsertionPass(bool is64Bit) { - return new NOPInsertionPass(is64Bit); - } -} Index: lib/Target/X86/X86.h =================================================================== --- lib/Target/X86/X86.h +++ lib/Target/X86/X86.h @@ -54,10 +54,6 @@ /// AVX and SSE. FunctionPass *createX86IssueVZeroUpperPass(); -/// createNOPInsertionPass - This pass adds NOPs at random between -/// instructions. -FunctionPass *createNOPInsertionPass(bool is64Bit); - /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code /// to the specified MCE object. FunctionPass *createX86JITCodeEmitterPass(X86TargetMachine &TM, Index: lib/Target/X86/X86InstrInfo.h =================================================================== --- lib/Target/X86/X86InstrInfo.h +++ lib/Target/X86/X86InstrInfo.h @@ -360,6 +360,13 @@ bool shouldScheduleAdjacent(MachineInstr* First, MachineInstr *Second) const override; + void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const override; + + void insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + RandomNumberGenerator *RNG) const override; + void getNoopForMachoTarget(MCInst &NopInst) const override; bool Index: lib/Target/X86/X86InstrInfo.cpp =================================================================== --- lib/Target/X86/X86InstrInfo.cpp +++ lib/Target/X86/X86InstrInfo.cpp @@ -34,6 +34,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Target/TargetOptions.h" #include @@ -5293,6 +5294,56 @@ MI->setDesc(get(table[Domain-1])); } +/// insertNoop - Insert a noop into the instruction stream at the specified +/// point. +void X86InstrInfo::insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI) const { + DebugLoc DL; + BuildMI(MBB, MI, DL, get(X86::NOOP)); +} + +/// insertNoop - Insert a randomly chosen type of noop into the instruction +/// stream at the specified point to introduce fine-grained diversity. +void X86InstrInfo::insertNoop(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + RandomNumberGenerator *RNG) const { + enum { NOP, + MOV_BP, MOV_SP, + LEA_SI, LEA_DI, + MAX_NOPS }; + + static const unsigned NopRegs[MAX_NOPS][2] = { + { 0, 0 }, + { X86::EBP, X86::RBP }, + { X86::ESP, X86::RSP }, + { X86::ESI, X86::RSI }, + { X86::EDI, X86::RDI }, + }; + + unsigned Type = (*RNG)() % MAX_NOPS; + + DebugLoc DL; + bool is64Bit = Subtarget.is64Bit(); + unsigned Reg = NopRegs[Type][is64Bit]; + + switch (Type) { + case NOP: + BuildMI(MBB, MI, DL, get(X86::NOOP)); + break; + case MOV_BP: + case MOV_SP: + copyPhysReg(MBB, MI, DL, Reg, Reg, false); + break; + case LEA_SI: + case LEA_DI: { + unsigned opc = is64Bit ? X86::LEA64r : X86::LEA32r; + addRegOffset(BuildMI(MBB, MI, DL, get(opc), Reg), + Reg, false, 0); + break; + } + } +} + /// getNoopForMachoTarget - Return the noop instruction to use for a noop. void X86InstrInfo::getNoopForMachoTarget(MCInst &NopInst) const { NopInst.setOpcode(X86::NOOP); Index: lib/Target/X86/X86TargetMachine.cpp =================================================================== --- lib/Target/X86/X86TargetMachine.cpp +++ lib/Target/X86/X86TargetMachine.cpp @@ -175,11 +175,6 @@ ShouldPrint = true; } - if (TM->Options.NOPInsertion) { - addPass(createNOPInsertionPass(getX86Subtarget().is64Bit())); - ShouldPrint = true; - } - return ShouldPrint; } Index: test/CodeGen/X86/nop-insert-percentage.ll =================================================================== --- test/CodeGen/X86/nop-insert-percentage.ll +++ test/CodeGen/X86/nop-insert-percentage.ll @@ -1,8 +1,8 @@ -; RUN: llc < %s -rng-seed=5 -nop-insertion -nop-insertion-percentage=10 \ +; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -nop-insertion -nop-insertion-percentage=10 \ ; RUN: | FileCheck %s --check-prefix=PERCENT10 -; RUN: llc < %s -rng-seed=5 -nop-insertion -nop-insertion-percentage=50 \ +; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -nop-insertion -nop-insertion-percentage=50 \ ; RUN: | FileCheck %s --check-prefix=PERCENT50 -; RUN: llc < %s -rng-seed=5 -nop-insertion -nop-insertion-percentage=100 \ +; RUN: llc < %s -mtriple=x86_64-linux -rng-seed=5 -nop-insertion -nop-insertion-percentage=100 \ ; RUN: | FileCheck %s --check-prefix=PERCENT100 ; This test case tests NOP insertion at varying percentage levels. @@ -26,22 +26,22 @@ ; PERCENT10: leaq (%rsi), %rsi ; PERCENT50: movq %rbp, %rbp +; PERCENT50: nop ; PERCENT50: leaq (%rsi), %rsi -; PERCENT50: movq %rbp, %rbp ; PERCENT50: leaq (%rdi), %rdi +; PERCENT50: movq %rbp, %rbp ; PERCENT50: movq %rsp, %rsp -; PERCENT50: leaq (%rsi), %rsi -; PERCENT50: leaq (%rdi), %rdi ; PERCENT100: leaq (%rdi), %rdi -; PERCENT100: movq %rbp, %rbp -; PERCENT100: leaq (%rsi), %rsi -; PERCENT100: movq %rbp, %rbp ; PERCENT100: leaq (%rdi), %rdi ; PERCENT100: movq %rsp, %rsp +; PERCENT100: movq %rsp, %rsp +; PERCENT100: leaq (%rdi), %rdi ; PERCENT100: leaq (%rsi), %rsi +; PERCENT100: leaq (%rdi), %rdi +; PERCENT100: movq %rbp, %rbp +; PERCENT100: movq %rsp, %rsp ; PERCENT100: leaq (%rsi), %rsi ; PERCENT100: nop ; PERCENT100: leaq (%rsi), %rsi -; PERCENT100: movq %rsp, %rsp -; PERCENT100: movq %rbp, %rbp + Index: test/CodeGen/X86/nop-insert.ll =================================================================== --- test/CodeGen/X86/nop-insert.ll +++ test/CodeGen/X86/nop-insert.ll @@ -1,40 +1,31 @@ -; RUN: llc < %s -nop-insertion | FileCheck %s -; RUN: llc < %s -nop-insertion -salt-data="test" -rng-seed=1 | FileCheck %s --check-prefix=SEED1 -; RUN: llc < %s -nop-insertion -salt-data="test" -rng-seed=25 | FileCheck %s --check-prefix=SEED2 -; RUN: llc < %s -nop-insertion -salt-data="test" -rng-seed=1534 | FileCheck %s --check-prefix=SEED3 -; RUN: llc < %s -nop-insertion -salt-data="different entropy" -rng-seed=1 | FileCheck %s --check-prefix=SALT +; RUN: llc < %s -mtriple=x86_64-linux -nop-insertion | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-linux -nop-insertion -rng-seed=1 | FileCheck %s --check-prefix=SEED1 +; RUN: llc < %s -mtriple=x86_64-linux -nop-insertion -rng-seed=25 | FileCheck %s --check-prefix=SEED2 +; RUN: llc < %s -mtriple=x86_64-linux -nop-insertion -rng-seed=1534 | FileCheck %s --check-prefix=SEED3 ; This test case checks that NOPs are inserted, and that the RNG seed ; affects both the placement (position of imull) and choice of these NOPs. -; CHECK: movq %rsp, %rsp ; CHECK: imull -; CHECK: movq %rbp, %rbp -; CHECK-NOT: leaq +; CHECK: leaq (%rsi), %rsi +; CHECK: retq ; CHECK-NOT: nop ; SEED1: imull -; SEED1: leaq (%rsi), %rsi -; SEED1-NOT: movq +; SEED1: movq %rbp, %rbp +; SEED1: retq ; SEED1-NOT: nop -; SEED2: movq %rbp, %rbp +; SEED2: movq %rsp, %rsp ; SEED2: imull -; SEED2: movq %rbp, %rbp -; SEED2-NOT: leaq -; SEED2-NOT: nop +; SEED2: leaq (%rsi), %rsi +; SEED2: nop +; SEED2: retq ; SEED3: movq %rsp, %rsp ; SEED3: imull -; SEED3: movq %rsp, %rsp -; SEED3-NOT: leaq -; SEED3-NOT: nop - -; SALT: imull -; SALT: nop -; SALT: nop -; SALT-NOT: leaq -; SALT-NOT: movq +; SEED3: nop +; SEED3: retq define i32 @test1(i32 %x, i32 %y, i32 %z) { entry: Index: test/CodeGen/X86/sched-rnd-test.ll =================================================================== --- test/CodeGen/X86/sched-rnd-test.ll +++ /dev/null @@ -1,36 +0,0 @@ -; RUN: llc < %s -rng-seed=1 -sched-randomize -sched-randomize-percentage=100 | FileCheck %s --check-prefix=SEED1 -; RUN: llc < %s -rng-seed=5 -sched-randomize -sched-randomize-percentage=100 | FileCheck %s --check-prefix=SEED2 -; RUN: llc < %s -rng-seed=5 -sched-randomize -sched-randomize-percentage=50 | FileCheck %s --check-prefix=PERCENTAGE - -; This test case checks that the schedule randomization is changing -; scheduling decisions, that different seeds result in different -; schedules, and that the percentage alters the amount of -; randomization - -define i32 @test(i32 %x, i32 %y, i32 %z) { -entry: - %a = add i32 %x, %y - %b = add i32 %x, %z - %c = add i32 %y, %z - %d = mul i32 %a, %b - %e = mul i32 %d, %c - ret i32 %e -} - -; SEED1: leal (%rdi,%rsi), %eax -; SEED1-NEXT: addl %edx, %esi -; SEED1-NEXT: addl %edx, %edi -; SEED1-NEXT: imull %edi, %eax -; SEED1-NEXT: imull %esi, %eax - -; SEED2: leal (%rdi,%rsi), %eax -; SEED2-NEXT: addl %edx, %edi -; SEED2-NEXT: imull %edi, %eax -; SEED2-NEXT: addl %edx, %esi -; SEED2-NEXT: imull %esi, %eax - -; PERCENTAGE: leal (%rdi,%rsi), %eax -; PERCENTAGE: addl %edx, %esi -; PERCENTAGE: addl %edx, %edi -; PERCENTAGE: imull %edi, %eax -; PERCENTAGE: imull %esi, %eax