diff options
author | Pascal Stumpf <pascal@cvs.openbsd.org> | 2016-09-03 22:47:03 +0000 |
---|---|---|
committer | Pascal Stumpf <pascal@cvs.openbsd.org> | 2016-09-03 22:47:03 +0000 |
commit | c596f2c8274a8ab05a1e5fe0a58385c8df2ee5af (patch) | |
tree | 6cef10c394eb179397f257ad93cabd305ad0ccb1 /gnu/llvm | |
parent | 75d5280649f1c48f0877d595fa40e60842a24cbe (diff) |
Use the space freed up by sparc and zaurus to import LLVM.
ok hackroom@
Diffstat (limited to 'gnu/llvm')
65 files changed, 3354 insertions, 6486 deletions
diff --git a/gnu/llvm/include/llvm/CodeGen/CommandFlags.h b/gnu/llvm/include/llvm/CodeGen/CommandFlags.h index 0d898827efc..0d37dc00422 100644 --- a/gnu/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/gnu/llvm/include/llvm/CodeGen/CommandFlags.h @@ -27,6 +27,7 @@ #include "llvm/Support/Host.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRecip.h" #include <string> using namespace llvm; @@ -45,28 +46,20 @@ MAttrs("mattr", cl::desc("Target specific attributes (-mattr=help for details)"), cl::value_desc("a1,+a2,-a3,...")); -cl::opt<Reloc::Model> RelocModel( - "relocation-model", cl::desc("Choose relocation model"), - cl::values( - clEnumValN(Reloc::Static, "static", "Non-relocatable code"), - clEnumValN(Reloc::PIC_, "pic", - "Fully relocatable, position independent code"), - clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", - "Relocatable external references, non-relocatable code"), - clEnumValN(Reloc::ROPI, "ropi", - "Code and read-only data relocatable, accessed PC-relative"), - clEnumValN(Reloc::RWPI, "rwpi", - "Read-write data relocatable, accessed relative to static base"), - clEnumValN(Reloc::ROPI_RWPI, "ropi-rwpi", - "Combination of ropi and rwpi"))); - -static inline Optional<Reloc::Model> getRelocModel() { - if (RelocModel.getNumOccurrences()) { - Reloc::Model R = RelocModel; - return R; - } - return None; -} +cl::opt<Reloc::Model> +RelocModel("relocation-model", + cl::desc("Choose relocation model"), + cl::init(Reloc::Default), + cl::values( + clEnumValN(Reloc::Default, "default", + "Target default relocation model"), + clEnumValN(Reloc::Static, "static", + "Non-relocatable code"), + clEnumValN(Reloc::PIC_, "pic", + "Fully relocatable, position independent code"), + clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic", + "Relocatable external references, non-relocatable code"), + clEnumValEnd)); cl::opt<ThreadModel::Model> TMModel("thread-model", @@ -75,7 +68,8 @@ TMModel("thread-model", cl::values(clEnumValN(ThreadModel::POSIX, "posix", "POSIX thread model"), clEnumValN(ThreadModel::Single, "single", - "Single thread model"))); + "Single thread model"), + clEnumValEnd)); cl::opt<llvm::CodeModel::Model> CMModel("code-model", @@ -90,22 +84,8 @@ CMModel("code-model", clEnumValN(CodeModel::Medium, "medium", "Medium code model"), clEnumValN(CodeModel::Large, "large", - "Large code model"))); - -cl::opt<llvm::ExceptionHandling> -ExceptionModel("exception-model", - cl::desc("exception model"), - cl::init(ExceptionHandling::None), - cl::values(clEnumValN(ExceptionHandling::None, "default", - "default exception handling model"), - clEnumValN(ExceptionHandling::DwarfCFI, "dwarf", - "DWARF-like CFI based exception handling"), - clEnumValN(ExceptionHandling::SjLj, "sjlj", - "SjLj exception handling"), - clEnumValN(ExceptionHandling::ARM, "arm", - "ARM EHABI exceptions"), - clEnumValN(ExceptionHandling::WinEH, "wineh", - "Windows exception model"))); + "Large code model"), + clEnumValEnd)); cl::opt<TargetMachine::CodeGenFileType> FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), @@ -116,7 +96,13 @@ FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile), clEnumValN(TargetMachine::CGFT_ObjectFile, "obj", "Emit a native object ('.o') file"), clEnumValN(TargetMachine::CGFT_Null, "null", - "Emit nothing, for performance testing"))); + "Emit nothing, for performance testing"), + clEnumValEnd)); + +cl::opt<bool> +EnableFPMAD("enable-fp-mad", + cl::desc("Enable less precise MAD instructions to be generated"), + cl::init(false)); cl::opt<bool> DisableFPElim("disable-fp-elim", @@ -139,31 +125,6 @@ EnableNoNaNsFPMath("enable-no-nans-fp-math", cl::init(false)); cl::opt<bool> -EnableNoSignedZerosFPMath("enable-no-signed-zeros-fp-math", - cl::desc("Enable FP math optimizations that assume " - "the sign of 0 is insignificant"), - cl::init(false)); - -cl::opt<bool> -EnableNoTrappingFPMath("enable-no-trapping-fp-math", - cl::desc("Enable setting the FP exceptions build " - "attribute not to use exceptions"), - cl::init(false)); - -cl::opt<llvm::FPDenormal::DenormalMode> -DenormalMode("denormal-fp-math", - cl::desc("Select which denormal numbers the code is permitted to require"), - cl::init(FPDenormal::IEEE), - cl::values( - clEnumValN(FPDenormal::IEEE, "ieee", - "IEEE 754 denormal numbers"), - clEnumValN(FPDenormal::PreserveSign, "preserve-sign", - "the sign of a flushed-to-zero number is preserved " - "in the sign of 0"), - clEnumValN(FPDenormal::PositiveZero, "positive-zero", - "denormals are flushed to positive zero"))); - -cl::opt<bool> EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", cl::Hidden, cl::desc("Force codegen to assume rounding mode can change dynamically"), @@ -179,7 +140,8 @@ FloatABIForCalls("float-abi", clEnumValN(FloatABI::Soft, "soft", "Soft float ABI (implied by -soft-float)"), clEnumValN(FloatABI::Hard, "hard", - "Hard float ABI (uses FP registers)"))); + "Hard float ABI (uses FP registers)"), + clEnumValEnd)); cl::opt<llvm::FPOpFusion::FPOpFusionMode> FuseFPOps("fp-contract", @@ -191,7 +153,14 @@ FuseFPOps("fp-contract", clEnumValN(FPOpFusion::Standard, "on", "Only fuse 'blessed' FP ops."), clEnumValN(FPOpFusion::Strict, "off", - "Only fuse FP ops when the result won't be affected."))); + "Only fuse FP ops when the result won't be affected."), + clEnumValEnd)); + +cl::list<std::string> +ReciprocalOps("recip", + cl::CommaSeparated, + cl::desc("Choose reciprocal operation types and parameters."), + cl::value_desc("all,none,default,divf,!vec-sqrtd,vec-divd:0,sqrt:9...")); cl::opt<bool> DontPlaceZerosInBSS("nozero-initialized-in-bss", @@ -208,11 +177,6 @@ DisableTailCalls("disable-tail-calls", cl::desc("Never emit tail calls"), cl::init(false)); -cl::opt<bool> -StackSymbolOrdering("stack-symbol-ordering", - cl::desc("Order local stack symbols."), - cl::init(true)); - cl::opt<unsigned> OverrideStackAlignment("stack-alignment", cl::desc("Override default stack alignment"), @@ -229,14 +193,27 @@ TrapFuncName("trap-func", cl::Hidden, cl::init("")); cl::opt<bool> +EnablePIE("enable-pie", + cl::desc("Assume the creation of a position independent executable."), + cl::init(false)); + +cl::opt<bool> UseCtors("use-ctors", cl::desc("Use .ctors instead of .init_array."), cl::init(false)); -cl::opt<bool> RelaxELFRelocations( - "relax-elf-relocations", - cl::desc("Emit GOTPCRELX/REX_GOTPCRELX instead of GOTPCREL on x86-64 ELF"), - cl::init(false)); +cl::opt<std::string> StopAfter("stop-after", + cl::desc("Stop compilation after a specific pass"), + cl::value_desc("pass-name"), + cl::init("")); +cl::opt<std::string> StartAfter("start-after", + cl::desc("Resume compilation after a specific pass"), + cl::value_desc("pass-name"), + cl::init("")); + +cl::opt<std::string> + RunPass("run-pass", cl::desc("Run compiler only for one specific pass"), + cl::value_desc("pass-name"), cl::init("")); cl::opt<bool> DataSections("data-sections", cl::desc("Emit data into separate sections"), @@ -255,6 +232,21 @@ cl::opt<bool> UniqueSectionNames("unique-section-names", cl::desc("Give unique names to every section"), cl::init(true)); +cl::opt<llvm::JumpTable::JumpTableType> +JTableType("jump-table-type", + cl::desc("Choose the type of Jump-Instruction Table for jumptable."), + cl::init(JumpTable::Single), + cl::values( + clEnumValN(JumpTable::Single, "single", + "Create a single table for all jumptable functions"), + clEnumValN(JumpTable::Arity, "arity", + "Create one table per number of parameters."), + clEnumValN(JumpTable::Simplified, "simplified", + "Create one table per simplified function type."), + clEnumValN(JumpTable::Full, "full", + "Create one table per unique function type."), + clEnumValEnd)); + cl::opt<llvm::EABI> EABIVersion( "meabi", cl::desc("Set EABI type (default depends on triple):"), cl::init(EABI::Default), @@ -262,7 +254,7 @@ cl::opt<llvm::EABI> EABIVersion( "Triple default EABI version"), clEnumValN(EABI::EABI4, "4", "EABI version 4"), clEnumValN(EABI::EABI5, "5", "EABI version 5"), - clEnumValN(EABI::GNU, "gnu", "EABI GNU"))); + clEnumValN(EABI::GNU, "gnu", "EABI GNU"), clEnumValEnd)); cl::opt<DebuggerKind> DebuggerTuningOpt("debugger-tune", @@ -272,19 +264,19 @@ DebuggerTuningOpt("debugger-tune", clEnumValN(DebuggerKind::GDB, "gdb", "gdb"), clEnumValN(DebuggerKind::LLDB, "lldb", "lldb"), clEnumValN(DebuggerKind::SCE, "sce", - "SCE targets (e.g. PS4)"))); + "SCE targets (e.g. PS4)"), + clEnumValEnd)); // Common utility function tightly tied to the options listed here. Initializes // a TargetOptions object with CodeGen flags and returns it. static inline TargetOptions InitTargetOptionsFromCodeGenFlags() { TargetOptions Options; + Options.LessPreciseFPMADOption = EnableFPMAD; Options.AllowFPOpFusion = FuseFPOps; + Options.Reciprocals = TargetRecip(ReciprocalOps); Options.UnsafeFPMath = EnableUnsafeFPMath; Options.NoInfsFPMath = EnableNoInfsFPMath; Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.NoSignedZerosFPMath = EnableNoSignedZerosFPMath; - Options.NoTrappingFPMath = EnableNoTrappingFPMath; - Options.FPDenormalMode = DenormalMode; Options.HonorSignDependentRoundingFPMathOption = EnableHonorSignDependentRoundingFPMath; if (FloatABIForCalls != FloatABI::Default) @@ -292,16 +284,15 @@ static inline TargetOptions InitTargetOptionsFromCodeGenFlags() { Options.NoZerosInBSS = DontPlaceZerosInBSS; Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; Options.StackAlignmentOverride = OverrideStackAlignment; - Options.StackSymbolOrdering = StackSymbolOrdering; + Options.PositionIndependentExecutable = EnablePIE; Options.UseInitArray = !UseCtors; - Options.RelaxELFRelocations = RelaxELFRelocations; Options.DataSections = DataSections; Options.FunctionSections = FunctionSections; Options.UniqueSectionNames = UniqueSectionNames; Options.EmulatedTLS = EmulatedTLS; - Options.ExceptionModel = ExceptionModel; Options.MCOptions = InitMCTargetOptionsFromFlags(); + Options.JTType = JTableType; Options.ThreadModel = TMModel; Options.EABIVersion = EABIVersion; @@ -346,21 +337,29 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features, Module &M) { for (auto &F : M) { auto &Ctx = F.getContext(); - AttributeList Attrs = F.getAttributes(); - AttrBuilder NewAttrs; + AttributeSet Attrs = F.getAttributes(), NewAttrs; if (!CPU.empty()) - NewAttrs.addAttribute("target-cpu", CPU); + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "target-cpu", CPU); + if (!Features.empty()) - NewAttrs.addAttribute("target-features", Features); + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "target-features", Features); + if (DisableFPElim.getNumOccurrences() > 0) - NewAttrs.addAttribute("no-frame-pointer-elim", - DisableFPElim ? "true" : "false"); + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "no-frame-pointer-elim", + DisableFPElim ? "true" : "false"); + if (DisableTailCalls.getNumOccurrences() > 0) - NewAttrs.addAttribute("disable-tail-calls", - toStringRef(DisableTailCalls)); + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "disable-tail-calls", + toStringRef(DisableTailCalls)); + if (StackRealign) - NewAttrs.addAttribute("stackrealign"); + NewAttrs = NewAttrs.addAttribute(Ctx, AttributeSet::FunctionIndex, + "stackrealign"); if (TrapFuncName.getNumOccurrences() > 0) for (auto &B : F) @@ -369,13 +368,12 @@ static inline void setFunctionAttributes(StringRef CPU, StringRef Features, if (const auto *F = Call->getCalledFunction()) if (F->getIntrinsicID() == Intrinsic::debugtrap || F->getIntrinsicID() == Intrinsic::trap) - Call->addAttribute( - llvm::AttributeList::FunctionIndex, - Attribute::get(Ctx, "trap-func-name", TrapFuncName)); + Call->addAttribute(llvm::AttributeSet::FunctionIndex, + "trap-func-name", TrapFuncName); // Let NewAttrs override Attrs. - F.setAttributes( - Attrs.addAttributes(Ctx, AttributeList::FunctionIndex, NewAttrs)); + NewAttrs = Attrs.addAttributes(Ctx, AttributeSet::FunctionIndex, NewAttrs); + F.setAttributes(NewAttrs); } } diff --git a/gnu/llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h b/gnu/llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h index 820e8836248..87421e2f83b 100644 --- a/gnu/llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/gnu/llvm/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -1,4 +1,4 @@ -//===- LiveIntervalAnalysis.h - Live Interval Analysis ----------*- C++ -*-===// +//===-- LiveIntervalAnalysis.h - Live Interval Analysis ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,20 +7,19 @@ // //===----------------------------------------------------------------------===// // -/// \file This file implements the LiveInterval analysis pass. Given some -/// numbering of each the machine instructions (in this implemention depth-first -/// order) an interval [i, j) is said to be a live interval for register v if -/// there is no instruction with number j' > j such that v is live at j' and -/// there is no instruction with number i' < i such that v is live at i'. In -/// this implementation intervals can have holes, i.e. an interval might look -/// like [1,20), [50,65), [1000,1001). +// This file implements the LiveInterval analysis pass. Given some numbering of +// each the machine instructions (in this implemention depth-first order) an +// interval [i, j) is said to be a live interval for register v if there is no +// instruction with number j' > j such that v is live at j' and there is no +// instruction with number i' < i such that v is live at i'. In this +// implementation intervals can have holes, i.e. an interval might look like +// [1,20), [50,65), [1000,1001). // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_LIVEINTERVALANALYSIS_H #define LLVM_CODEGEN_LIVEINTERVALANALYSIS_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -28,29 +27,28 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/SlotIndexes.h" -#include "llvm/MC/LaneBitmask.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetRegisterInfo.h" -#include <cassert> -#include <cstdint> -#include <utility> +#include <cmath> +#include <iterator> namespace llvm { extern cl::opt<bool> UseSegmentSetForPhysRegs; -class BitVector; -class LiveRangeCalc; -class MachineBlockFrequencyInfo; -class MachineDominatorTree; -class MachineFunction; -class MachineInstr; -class MachineRegisterInfo; -class raw_ostream; -class TargetInstrInfo; -class VirtRegMap; + class BitVector; + class BlockFrequency; + class LiveRangeCalc; + class LiveVariables; + class MachineDominatorTree; + class MachineLoopInfo; + class TargetRegisterInfo; + class MachineRegisterInfo; + class TargetInstrInfo; + class TargetRegisterClass; + class VirtRegMap; + class MachineBlockFrequencyInfo; class LiveIntervals : public MachineFunctionPass { MachineFunction* MF; @@ -59,21 +57,24 @@ class VirtRegMap; const TargetInstrInfo* TII; AliasAnalysis *AA; SlotIndexes* Indexes; - MachineDominatorTree *DomTree = nullptr; - LiveRangeCalc *LRCalc = nullptr; + MachineDominatorTree *DomTree; + LiveRangeCalc *LRCalc; /// Special pool allocator for VNInfo's (LiveInterval val#). + /// VNInfo::Allocator VNInfoAllocator; /// Live interval pointers for all the virtual registers. IndexedMap<LiveInterval*, VirtReg2IndexFunctor> VirtRegIntervals; - /// Sorted list of instructions with register mask operands. Always use the - /// 'r' slot, RegMasks are normal clobbers, not early clobbers. + /// RegMaskSlots - Sorted list of instructions with register mask operands. + /// Always use the 'r' slot, RegMasks are normal clobbers, not early + /// clobbers. SmallVector<SlotIndex, 8> RegMaskSlots; - /// This vector is parallel to RegMaskSlots, it holds a pointer to the - /// corresponding register mask. This pointer can be recomputed as: + /// RegMaskBits - This vector is parallel to RegMaskSlots, it holds a + /// pointer to the corresponding register mask. This pointer can be + /// recomputed as: /// /// MI = Indexes->getInstructionFromIndex(RegMaskSlot[N]); /// unsigned OpNum = findRegMaskOperand(MI); @@ -97,15 +98,14 @@ class VirtRegMap; SmallVector<LiveRange*, 0> RegUnitRanges; public: - static char ID; - + static char ID; // Pass identification, replacement for typeid LiveIntervals(); ~LiveIntervals() override; - /// Calculate the spill weight to assign to a single instruction. + // Calculate the spill weight to assign to a single instruction. static float getSpillWeight(bool isDef, bool isUse, const MachineBlockFrequencyInfo *MBFI, - const MachineInstr &Instr); + const MachineInstr *Instr); LiveInterval &getInterval(unsigned Reg) { if (hasInterval(Reg)) @@ -122,7 +122,7 @@ class VirtRegMap; return VirtRegIntervals.inBounds(Reg) && VirtRegIntervals[Reg]; } - /// Interval creation. + // Interval creation. LiveInterval &createEmptyInterval(unsigned Reg) { assert(!hasInterval(Reg) && "Interval already exists!"); VirtRegIntervals.grow(Reg); @@ -136,7 +136,7 @@ class VirtRegMap; return LI; } - /// Interval removal. + // Interval removal. void removeInterval(unsigned Reg) { delete VirtRegIntervals[Reg]; VirtRegIntervals[Reg] = nullptr; @@ -145,7 +145,7 @@ class VirtRegMap; /// Given a register and an instruction, adds a live segment from that /// instruction to the end of its MBB. LiveInterval::Segment addSegmentToEndOfBlock(unsigned reg, - MachineInstr &startInst); + MachineInstr* startInst); /// After removing some uses of a register, shrink its live range to just /// the remaining uses. This method does not compute reaching defs for new @@ -164,26 +164,18 @@ class VirtRegMap; /// LiveInterval::removeEmptySubranges() afterwards. void shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg); - /// Extend the live range \p LR to reach all points in \p Indices. The - /// points in the \p Indices array must be jointly dominated by the union - /// of the existing defs in \p LR and points in \p Undefs. - /// - /// PHI-defs are added as needed to maintain SSA form. + /// extendToIndices - Extend the live range of LI to reach all points in + /// Indices. The points in the Indices array must be jointly dominated by + /// existing defs in LI. PHI-defs are added as needed to maintain SSA form. /// - /// If a SlotIndex in \p Indices is the end index of a basic block, \p LR - /// will be extended to be live out of the basic block. - /// If a SlotIndex in \p Indices is jointy dominated only by points in - /// \p Undefs, the live range will not be extended to that point. + /// If a SlotIndex in Indices is the end index of a basic block, LI will be + /// extended to be live out of the basic block. /// /// See also LiveRangeCalc::extend(). - void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices, - ArrayRef<SlotIndex> Undefs); + void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices); - void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices) { - extendToIndices(LR, Indices, /*Undefs=*/{}); - } - /// If \p LR has a live value at \p Kill, prune its live range by removing + /// If @p LR has a live value at @p Kill, prune its live range by removing /// any liveness reachable from Kill. Add live range end points to /// EndPoints such that extendToIndices(LI, EndPoints) will reconstruct the /// value's live range. @@ -193,16 +185,6 @@ class VirtRegMap; void pruneValue(LiveRange &LR, SlotIndex Kill, SmallVectorImpl<SlotIndex> *EndPoints); - /// This function should not be used. Its intend is to tell you that - /// you are doing something wrong if you call pruveValue directly on a - /// LiveInterval. Indeed, you are supposed to call pruneValue on the main - /// LiveRange and all the LiveRange of the subranges if any. - LLVM_ATTRIBUTE_UNUSED void pruneValue(LiveInterval &, SlotIndex, - SmallVectorImpl<SlotIndex> *) { - llvm_unreachable( - "Use pruneValue on the main LiveRange and on each subrange"); - } - SlotIndexes *getSlotIndexes() const { return Indexes; } @@ -211,15 +193,15 @@ class VirtRegMap; return AA; } - /// Returns true if the specified machine instr has been removed or was - /// never entered in the map. - bool isNotInMIMap(const MachineInstr &Instr) const { + /// isNotInMIMap - returns true if the specified machine instr has been + /// removed or was never entered in the map. + bool isNotInMIMap(const MachineInstr* Instr) const { return !Indexes->hasIndex(Instr); } /// Returns the base index of the given instruction. - SlotIndex getInstructionIndex(const MachineInstr &Instr) const { - return Indexes->getInstructionIndex(Instr); + SlotIndex getInstructionIndex(const MachineInstr *instr) const { + return Indexes->getInstructionIndex(instr); } /// Returns the instruction associated with the given index. @@ -258,22 +240,22 @@ class VirtRegMap; RegMaskBlocks.push_back(std::make_pair(RegMaskSlots.size(), 0)); } - SlotIndex InsertMachineInstrInMaps(MachineInstr &MI) { + SlotIndex InsertMachineInstrInMaps(MachineInstr *MI) { return Indexes->insertMachineInstrInMaps(MI); } void InsertMachineInstrRangeInMaps(MachineBasicBlock::iterator B, MachineBasicBlock::iterator E) { for (MachineBasicBlock::iterator I = B; I != E; ++I) - Indexes->insertMachineInstrInMaps(*I); + Indexes->insertMachineInstrInMaps(I); } - void RemoveMachineInstrFromMaps(MachineInstr &MI) { + void RemoveMachineInstrFromMaps(MachineInstr *MI) { Indexes->removeMachineInstrFromMaps(MI); } - SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI) { - return Indexes->replaceMachineInstrInMaps(MI, NewMI); + void ReplaceMachineInstrInMaps(MachineInstr *MI, MachineInstr *NewMI) { + Indexes->replaceMachineInstrInMaps(MI, NewMI); } VNInfo::Allocator& getVNInfoAllocator() { return VNInfoAllocator; } @@ -281,44 +263,48 @@ class VirtRegMap; void getAnalysisUsage(AnalysisUsage &AU) const override; void releaseMemory() override; - /// Pass entry point; Calculates LiveIntervals. + /// runOnMachineFunction - pass entry point bool runOnMachineFunction(MachineFunction&) override; - /// Implement the dump method. + /// print - Implement the dump method. void print(raw_ostream &O, const Module* = nullptr) const override; - /// If LI is confined to a single basic block, return a pointer to that - /// block. If LI is live in to or out of any block, return NULL. + /// intervalIsInOneMBB - If LI is confined to a single basic block, return + /// a pointer to that block. If LI is live in to or out of any block, + /// return NULL. MachineBasicBlock *intervalIsInOneMBB(const LiveInterval &LI) const; /// Returns true if VNI is killed by any PHI-def values in LI. /// This may conservatively return true to avoid expensive computations. bool hasPHIKill(const LiveInterval &LI, const VNInfo *VNI) const; - /// Add kill flags to any instruction that kills a virtual register. + /// addKillFlags - Add kill flags to any instruction that kills a virtual + /// register. void addKillFlags(const VirtRegMap*); - /// Call this method to notify LiveIntervals that instruction \p MI has been - /// moved within a basic block. This will update the live intervals for all - /// operands of \p MI. Moves between basic blocks are not supported. + /// handleMove - call this method to notify LiveIntervals that + /// instruction 'mi' has been moved within a basic block. This will update + /// the live intervals for all operands of mi. Moves between basic blocks + /// are not supported. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. - void handleMove(MachineInstr &MI, bool UpdateFlags = false); + void handleMove(MachineInstr* MI, bool UpdateFlags = false); - /// Update intervals for operands of \p MI so that they begin/end on the - /// SlotIndex for \p BundleStart. + /// moveIntoBundle - Update intervals for operands of MI so that they + /// begin/end on the SlotIndex for BundleStart. /// /// \param UpdateFlags Update live intervals for nonallocatable physregs. /// /// Requires MI and BundleStart to have SlotIndexes, and assumes /// existing liveness is accurate. BundleStart should be the first /// instruction in the Bundle. - void handleMoveIntoBundle(MachineInstr &MI, MachineInstr &BundleStart, + void handleMoveIntoBundle(MachineInstr* MI, MachineInstr* BundleStart, bool UpdateFlags = false); - /// Update live intervals for instructions in a range of iterators. It is - /// intended for use after target hooks that may insert or remove - /// instructions, and is only efficient for a small number of instructions. + /// repairIntervalsInRange - Update live intervals for instructions in a + /// range of iterators. It is intended for use after target hooks that may + /// insert or remove instructions, and is only efficient for a small number + /// of instructions. /// /// OrigRegs is a vector of registers that were originally used by the /// instructions in the range between the two iterators. @@ -341,33 +327,34 @@ class VirtRegMap; // LiveIntervalAnalysis maintains a sorted list of instructions with // register mask operands. - /// Returns a sorted array of slot indices of all instructions with - /// register mask operands. + /// getRegMaskSlots - Returns a sorted array of slot indices of all + /// instructions with register mask operands. ArrayRef<SlotIndex> getRegMaskSlots() const { return RegMaskSlots; } - /// Returns a sorted array of slot indices of all instructions with register - /// mask operands in the basic block numbered \p MBBNum. + /// getRegMaskSlotsInBlock - Returns a sorted array of slot indices of all + /// instructions with register mask operands in the basic block numbered + /// MBBNum. ArrayRef<SlotIndex> getRegMaskSlotsInBlock(unsigned MBBNum) const { std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum]; return getRegMaskSlots().slice(P.first, P.second); } - /// Returns an array of register mask pointers corresponding to - /// getRegMaskSlots(). + /// getRegMaskBits() - Returns an array of register mask pointers + /// corresponding to getRegMaskSlots(). ArrayRef<const uint32_t*> getRegMaskBits() const { return RegMaskBits; } - /// Returns an array of mask pointers corresponding to - /// getRegMaskSlotsInBlock(MBBNum). + /// getRegMaskBitsInBlock - Returns an array of mask pointers corresponding + /// to getRegMaskSlotsInBlock(MBBNum). ArrayRef<const uint32_t*> getRegMaskBitsInBlock(unsigned MBBNum) const { std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum]; return getRegMaskBits().slice(P.first, P.second); } - /// Test if \p LI is live across any register mask instructions, and - /// compute a bit mask of physical registers that are not clobbered by any - /// of them. + /// checkRegMaskInterference - Test if LI is live across any register mask + /// instructions, and compute a bit mask of physical registers that are not + /// clobbered by any of them. /// - /// Returns false if \p LI doesn't cross any register mask instructions. In + /// Returns false if LI doesn't cross any register mask instructions. In /// that case, the bit vector is not filled in. bool checkRegMaskInterference(LiveInterval &LI, BitVector &UsableRegs); @@ -383,8 +370,8 @@ class VirtRegMap; // track liveness per register unit to handle aliasing registers more // efficiently. - /// Return the live range for register unit \p Unit. It will be computed if - /// it doesn't exist. + /// getRegUnit - Return the live range for Unit. + /// It will be computed if it doesn't exist. LiveRange &getRegUnit(unsigned Unit) { LiveRange *LR = RegUnitRanges[Unit]; if (!LR) { @@ -396,8 +383,8 @@ class VirtRegMap; return *LR; } - /// Return the live range for register unit \p Unit if it has already been - /// computed, or nullptr if it hasn't been computed yet. + /// getCachedRegUnit - Return the live range for Unit if it has already + /// been computed, or NULL if it hasn't been computed yet. LiveRange *getCachedRegUnit(unsigned Unit) { return RegUnitRanges[Unit]; } @@ -406,31 +393,19 @@ class VirtRegMap; return RegUnitRanges[Unit]; } - /// Remove computed live range for register unit \p Unit. Subsequent uses - /// should rely on on-demand recomputation. - void removeRegUnit(unsigned Unit) { - delete RegUnitRanges[Unit]; - RegUnitRanges[Unit] = nullptr; - } - /// Remove value numbers and related live segments starting at position - /// \p Pos that are part of any liverange of physical register \p Reg or one + /// @p Pos that are part of any liverange of physical register @p Reg or one /// of its subregisters. void removePhysRegDefAt(unsigned Reg, SlotIndex Pos); - /// Remove value number and related live segments of \p LI and its subranges - /// that start at position \p Pos. + /// Remove value number and related live segments of @p LI and its subranges + /// that start at position @p Pos. void removeVRegDefAt(LiveInterval &LI, SlotIndex Pos); /// Split separate components in LiveInterval \p LI into separate intervals. void splitSeparateComponents(LiveInterval &LI, SmallVectorImpl<LiveInterval*> &SplitLIs); - /// For live interval \p LI with correct SubRanges construct matching - /// information for the main live range. Expects the main live range to not - /// have any segments or value numbers. - void constructMainRangeFromSubranges(LiveInterval &LI); - private: /// Compute live intervals for all virtual registers. void computeVirtRegs(); @@ -438,10 +413,10 @@ class VirtRegMap; /// Compute RegMaskSlots and RegMaskBits. void computeRegMasks(); - /// Walk the values in \p LI and check for dead values: + /// Walk the values in @p LI and check for dead values: /// - Dead PHIDef values are marked as unused. /// - Dead operands are marked as such. - /// - Completely dead machine instructions are added to the \p dead vector + /// - Completely dead machine instructions are added to the @p dead vector /// if it is not nullptr. /// Returns true if any PHI value numbers have been removed which may /// have separated the interval into multiple connected components. @@ -459,18 +434,16 @@ class VirtRegMap; /// Helper function for repairIntervalsInRange(), walks backwards and - /// creates/modifies live segments in \p LR to match the operands found. - /// Only full operands or operands with subregisters matching \p LaneMask + /// creates/modifies live segments in @p LR to match the operands found. + /// Only full operands or operands with subregisters matching @p LaneMask /// are considered. void repairOldRegInRange(MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, const SlotIndex endIdx, LiveRange &LR, - unsigned Reg, - LaneBitmask LaneMask = LaneBitmask::getAll()); + unsigned Reg, LaneBitmask LaneMask = ~0u); class HMEditor; }; +} // End llvm namespace -} // end namespace llvm - -#endif // LLVM_CODEGEN_LIVEINTERVALANALYSIS_H +#endif diff --git a/gnu/llvm/include/llvm/CodeGen/LiveStackAnalysis.h b/gnu/llvm/include/llvm/CodeGen/LiveStackAnalysis.h index c90ae7b184f..3ffbe3d775b 100644 --- a/gnu/llvm/include/llvm/CodeGen/LiveStackAnalysis.h +++ b/gnu/llvm/include/llvm/CodeGen/LiveStackAnalysis.h @@ -1,4 +1,4 @@ -//===- LiveStackAnalysis.h - Live Stack Slot Analysis -----------*- C++ -*-===// +//===-- LiveStackAnalysis.h - Live Stack Slot Analysis ----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,16 +18,13 @@ #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Pass.h" -#include <cassert> +#include "llvm/Support/Allocator.h" +#include "llvm/Target/TargetRegisterInfo.h" #include <map> #include <unordered_map> namespace llvm { -class TargetRegisterClass; -class TargetRegisterInfo; - class LiveStacks : public MachineFunctionPass { const TargetRegisterInfo *TRI; @@ -36,7 +33,8 @@ class LiveStacks : public MachineFunctionPass { VNInfo::Allocator VNInfoAllocator; /// S2IMap - Stack slot indices to live interval mapping. - using SS2IntervalMap = std::unordered_map<int, LiveInterval>; + /// + typedef std::unordered_map<int, LiveInterval> SS2IntervalMap; SS2IntervalMap S2IMap; /// S2RCMap - Stack slot indices to register class mapping. @@ -44,14 +42,12 @@ class LiveStacks : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid - LiveStacks() : MachineFunctionPass(ID) { initializeLiveStacksPass(*PassRegistry::getPassRegistry()); } - using iterator = SS2IntervalMap::iterator; - using const_iterator = SS2IntervalMap::const_iterator; - + typedef SS2IntervalMap::iterator iterator; + typedef SS2IntervalMap::const_iterator const_iterator; const_iterator begin() const { return S2IMap.begin(); } const_iterator end() const { return S2IMap.end(); } iterator begin() { return S2IMap.begin(); } @@ -97,7 +93,6 @@ public: /// print - Implement the dump method. void print(raw_ostream &O, const Module * = nullptr) const override; }; +} -} // end namespace llvm - -#endif // LLVM_CODEGEN_LIVESTACK_ANALYSIS_H +#endif /* LLVM_CODEGEN_LIVESTACK_ANALYSIS_H */ diff --git a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h index 5a6507ee7f5..1f48cf70666 100644 --- a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeRecordBuilder.h @@ -10,10 +10,9 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPERECORDBUILDER_H -#include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" @@ -40,34 +39,14 @@ public: void writeEncodedInteger(int64_t Value); void writeEncodedSignedInteger(int64_t Value); void writeEncodedUnsignedInteger(uint64_t Value); + void writeNullTerminatedString(const char *Value); void writeNullTerminatedString(StringRef Value); - void writeGuid(StringRef Guid); - void writeBytes(StringRef Value) { Stream << Value; } llvm::StringRef str(); uint64_t size() const { return Stream.tell(); } - TypeRecordKind kind() const { return Kind; } - - /// Returns the number of bytes remaining before this record is larger than - /// the maximum record length. Accounts for the extra two byte size field in - /// the header. - size_t maxBytesRemaining() const { return MaxRecordLength - size() - 2; } - - void truncate(uint64_t Size) { - // This works because raw_svector_ostream is not buffered. - assert(Size < Buffer.size()); - Buffer.resize(Size); - } - - void reset(TypeRecordKind K) { - Buffer.clear(); - Kind = K; - writeTypeRecordKind(K); - } private: - TypeRecordKind Kind; llvm::SmallVector<char, 256> Buffer; llvm::raw_svector_ostream Stream; llvm::support::endian::Writer<llvm::support::endianness::little> Writer; diff --git a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h index 1069dcd4533..2c950e8af79 100644 --- a/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h +++ b/gnu/llvm/include/llvm/DebugInfo/CodeView/TypeTableBuilder.h @@ -10,128 +10,51 @@ #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H -#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/Error.h" -#include <algorithm> -#include <cassert> -#include <cstdint> -#include <type_traits> +#include "llvm/Support/Compiler.h" namespace llvm { namespace codeview { +class FieldListRecordBuilder; +class MethodListRecordBuilder; +class TypeRecordBuilder; + class TypeTableBuilder { private: - TypeIndex handleError(Error EC) const { - assert(false && "Couldn't write Type!"); - consumeError(std::move(EC)); - return TypeIndex(); - } - - BumpPtrAllocator &Allocator; - TypeSerializer Serializer; - -public: - explicit TypeTableBuilder(BumpPtrAllocator &Allocator, - bool WriteUnique = true) - : Allocator(Allocator), Serializer(Allocator, WriteUnique) {} TypeTableBuilder(const TypeTableBuilder &) = delete; TypeTableBuilder &operator=(const TypeTableBuilder &) = delete; - bool empty() const { return Serializer.records().empty(); } - - BumpPtrAllocator &getAllocator() const { return Allocator; } - - template <typename T> TypeIndex writeKnownType(T &Record) { - static_assert(!std::is_same<T, FieldListRecord>::value, - "Can't serialize FieldList!"); - - CVType Type; - Type.Type = static_cast<TypeLeafKind>(Record.getKind()); - if (auto EC = Serializer.visitTypeBegin(Type)) - return handleError(std::move(EC)); - if (auto EC = Serializer.visitKnownRecord(Type, Record)) - return handleError(std::move(EC)); - - auto ExpectedIndex = Serializer.visitTypeEndGetIndex(Type); - if (!ExpectedIndex) - return handleError(ExpectedIndex.takeError()); - - return *ExpectedIndex; - } - - TypeIndex writeSerializedRecord(ArrayRef<uint8_t> Record) { - return Serializer.insertRecordBytes(Record); - } - - TypeIndex writeSerializedRecord(const RemappedType &Record) { - return Serializer.insertRecord(Record); - } - - template <typename TFunc> void ForEachRecord(TFunc Func) { - uint32_t Index = TypeIndex::FirstNonSimpleIndex; - - for (auto Record : Serializer.records()) { - Func(TypeIndex(Index), Record); - ++Index; - } - } - - ArrayRef<ArrayRef<uint8_t>> records() const { return Serializer.records(); } -}; - -class FieldListRecordBuilder { - TypeTableBuilder &TypeTable; - BumpPtrAllocator Allocator; - TypeSerializer TempSerializer; - CVType Type; +protected: + TypeTableBuilder(); public: - explicit FieldListRecordBuilder(TypeTableBuilder &TypeTable) - : TypeTable(TypeTable), TempSerializer(Allocator, false) { - Type.Type = TypeLeafKind::LF_FIELDLIST; - } - - void begin() { - TempSerializer.reset(); - - if (auto EC = TempSerializer.visitTypeBegin(Type)) - consumeError(std::move(EC)); - } + virtual ~TypeTableBuilder(); - template <typename T> void writeMemberType(T &Record) { - CVMemberRecord CVMR; - CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind()); - if (auto EC = TempSerializer.visitMemberBegin(CVMR)) - consumeError(std::move(EC)); - if (auto EC = TempSerializer.visitKnownMember(CVMR, Record)) - consumeError(std::move(EC)); - if (auto EC = TempSerializer.visitMemberEnd(CVMR)) - consumeError(std::move(EC)); - } - - TypeIndex end(bool Write) { - TypeIndex Index; - if (auto EC = TempSerializer.visitTypeEnd(Type)) { - consumeError(std::move(EC)); - return TypeIndex(); - } - - if (Write) { - for (auto Record : TempSerializer.records()) - Index = TypeTable.writeSerializedRecord(Record); - } +public: + TypeIndex writeModifier(const ModifierRecord &Record); + TypeIndex writeProcedure(const ProcedureRecord &Record); + TypeIndex writeMemberFunction(const MemberFunctionRecord &Record); + TypeIndex writeArgumentList(const ArgumentListRecord &Record); + TypeIndex writeRecord(TypeRecordBuilder &builder); + TypeIndex writePointer(const PointerRecord &Record); + TypeIndex writePointerToMember(const PointerToMemberRecord &Record); + TypeIndex writeArray(const ArrayRecord &Record); + TypeIndex writeAggregate(const AggregateRecord &Record); + TypeIndex writeEnum(const EnumRecord &Record); + TypeIndex writeBitField(const BitFieldRecord &Record); + TypeIndex writeVirtualTableShape(const VirtualTableShapeRecord &Record); + + TypeIndex writeFieldList(FieldListRecordBuilder &FieldList); + TypeIndex writeMethodList(MethodListRecordBuilder &MethodList); - return Index; - } +private: + virtual TypeIndex writeRecord(llvm::StringRef record) = 0; }; +} +} -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_TYPETABLEBUILDER_H +#endif diff --git a/gnu/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/gnu/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h index 96179be3b8b..5180208d33b 100644 --- a/gnu/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/gnu/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -26,7 +26,8 @@ cl::opt<MCTargetOptions::AsmInstrumentation> AsmInstrumentation( cl::values(clEnumValN(MCTargetOptions::AsmInstrumentationNone, "none", "no instrumentation at all"), clEnumValN(MCTargetOptions::AsmInstrumentationAddress, "address", - "instrument instructions with memory arguments"))); + "instrument instructions with memory arguments"), + clEnumValEnd)); cl::opt<bool> RelaxAll("mc-relax-all", cl::desc("When used with filetype=obj, " @@ -38,8 +39,6 @@ cl::opt<bool> IncrementalLinkerCompatible( "When used with filetype=obj, " "emit an object file which can be used with an incremental linker")); -cl::opt<bool> PIECopyRelocations("pie-copy-relocations", cl::desc("PIE Copy Relocations")); - cl::opt<int> DwarfVersion("dwarf-version", cl::desc("Dwarf version"), cl::init(0)); @@ -53,9 +52,6 @@ cl::opt<bool> FatalWarnings("fatal-warnings", cl::opt<bool> NoWarn("no-warn", cl::desc("Suppress all warnings")); cl::alias NoWarnW("W", cl::desc("Alias for --no-warn"), cl::aliasopt(NoWarn)); -cl::opt<bool> NoDeprecatedWarn("no-deprecated-warn", - cl::desc("Suppress all deprecated warnings")); - cl::opt<std::string> ABIName("target-abi", cl::Hidden, cl::desc("The name of the ABI to be targeted from the backend."), @@ -67,13 +63,11 @@ static inline MCTargetOptions InitMCTargetOptionsFromFlags() { (AsmInstrumentation == MCTargetOptions::AsmInstrumentationAddress); Options.MCRelaxAll = RelaxAll; Options.MCIncrementalLinkerCompatible = IncrementalLinkerCompatible; - Options.MCPIECopyRelocations = PIECopyRelocations; Options.DwarfVersion = DwarfVersion; Options.ShowMCInst = ShowMCInst; Options.ABIName = ABIName; Options.MCFatalWarnings = FatalWarnings; Options.MCNoWarn = NoWarn; - Options.MCNoDeprecatedWarn = NoDeprecatedWarn; return Options; } diff --git a/gnu/llvm/include/llvm/Support/GCOV.h b/gnu/llvm/include/llvm/Support/GCOV.h index 02016e7dbd6..544434f036a 100644 --- a/gnu/llvm/include/llvm/Support/GCOV.h +++ b/gnu/llvm/include/llvm/Support/GCOV.h @@ -1,4 +1,4 @@ -//===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===// +//===- GCOV.h - LLVM coverage tool ----------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -19,17 +19,9 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <memory> -#include <string> -#include <utility> namespace llvm { @@ -38,7 +30,6 @@ class GCOVBlock; class FileInfo; namespace GCOV { - enum GCOVVersion { V402, V404, V704 }; /// \brief A struct for passing gcov options between functions. @@ -56,14 +47,13 @@ struct Options { bool LongFileNames; bool NoOutput; }; - -} // end namespace GCOV +} // end GCOV namespace /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific /// read operations. class GCOVBuffer { public: - GCOVBuffer(MemoryBuffer *B) : Buffer(B) {} + GCOVBuffer(MemoryBuffer *B) : Buffer(B), Cursor(0) {} /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer. bool readGCNOFormat() { @@ -234,48 +224,47 @@ public: private: MemoryBuffer *Buffer; - uint64_t Cursor = 0; + uint64_t Cursor; }; /// GCOVFile - Collects coverage information for one pair of coverage file /// (.gcno and .gcda). class GCOVFile { public: - GCOVFile() = default; - + GCOVFile() + : GCNOInitialized(false), Checksum(0), Functions(), RunCount(0), + ProgramCount(0) {} bool readGCNO(GCOVBuffer &Buffer); bool readGCDA(GCOVBuffer &Buffer); uint32_t getChecksum() const { return Checksum; } - void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: - bool GCNOInitialized = false; + bool GCNOInitialized; GCOV::GCOVVersion Version; - uint32_t Checksum = 0; + uint32_t Checksum; SmallVector<std::unique_ptr<GCOVFunction>, 16> Functions; - uint32_t RunCount = 0; - uint32_t ProgramCount = 0; + uint32_t RunCount; + uint32_t ProgramCount; }; /// GCOVEdge - Collects edge information. struct GCOVEdge { - GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D) {} + GCOVEdge(GCOVBlock &S, GCOVBlock &D) : Src(S), Dst(D), Count(0) {} GCOVBlock &Src; GCOVBlock &Dst; - uint64_t Count = 0; + uint64_t Count; }; /// GCOVFunction - Collects function information. class GCOVFunction { public: - using BlockIterator = pointee_iterator<SmallVectorImpl< - std::unique_ptr<GCOVBlock>>::const_iterator>; - - GCOVFunction(GCOVFile &P) : Parent(P) {} + typedef pointee_iterator<SmallVectorImpl< + std::unique_ptr<GCOVBlock>>::const_iterator> BlockIterator; + GCOVFunction(GCOVFile &P) : Parent(P), Ident(0), LineNumber(0) {} bool readGCNO(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); bool readGCDA(GCOVBuffer &Buffer, GCOV::GCOVVersion Version); StringRef getName() const { return Name; } @@ -290,15 +279,14 @@ public: return make_range(block_begin(), block_end()); } - void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: GCOVFile &Parent; - uint32_t Ident = 0; + uint32_t Ident; uint32_t Checksum; - uint32_t LineNumber = 0; + uint32_t LineNumber; StringRef Name; StringRef Filename; SmallVector<std::unique_ptr<GCOVBlock>, 16> Blocks; @@ -308,10 +296,10 @@ private: /// GCOVBlock - Collects block information. class GCOVBlock { struct EdgeWeight { - EdgeWeight(GCOVBlock *D) : Dst(D) {} + EdgeWeight(GCOVBlock *D) : Dst(D), Count(0) {} GCOVBlock *Dst; - uint64_t Count = 0; + uint64_t Count; }; struct SortDstEdgesFunctor { @@ -321,11 +309,12 @@ class GCOVBlock { }; public: - using EdgeIterator = SmallVectorImpl<GCOVEdge *>::const_iterator; + typedef SmallVectorImpl<GCOVEdge *>::const_iterator EdgeIterator; - GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {} + GCOVBlock(GCOVFunction &P, uint32_t N) + : Parent(P), Number(N), Counter(0), DstEdgesAreSorted(true), SrcEdges(), + DstEdges(), Lines() {} ~GCOVBlock(); - const GCOVFunction &getParent() const { return Parent; } void addLine(uint32_t N) { Lines.push_back(N); } uint32_t getLastLine() const { return Lines.back(); } @@ -336,7 +325,6 @@ public: assert(&Edge->Dst == this); // up to caller to ensure edge is valid SrcEdges.push_back(Edge); } - void addDstEdge(GCOVEdge *Edge) { assert(&Edge->Src == this); // up to caller to ensure edge is valid // Check if adding this edge causes list to become unsorted. @@ -344,7 +332,6 @@ public: DstEdgesAreSorted = false; DstEdges.push_back(Edge); } - size_t getNumSrcEdges() const { return SrcEdges.size(); } size_t getNumDstEdges() const { return DstEdges.size(); } void sortDstEdges(); @@ -361,15 +348,14 @@ public: return make_range(dst_begin(), dst_end()); } - void print(raw_ostream &OS) const; void dump() const; void collectLineCounts(FileInfo &FI); private: GCOVFunction &Parent; uint32_t Number; - uint64_t Counter = 0; - bool DstEdgesAreSorted = true; + uint64_t Counter; + bool DstEdgesAreSorted; SmallVector<GCOVEdge *, 16> SrcEdges; SmallVector<GCOVEdge *, 16> DstEdges; SmallVector<uint32_t, 16> Lines; @@ -381,48 +367,48 @@ class FileInfo { // Therefore this typedef allows LineData.Functions to store multiple // functions // per instance. This is rare, however, so optimize for the common case. - using FunctionVector = SmallVector<const GCOVFunction *, 1>; - using FunctionLines = DenseMap<uint32_t, FunctionVector>; - using BlockVector = SmallVector<const GCOVBlock *, 4>; - using BlockLines = DenseMap<uint32_t, BlockVector>; + typedef SmallVector<const GCOVFunction *, 1> FunctionVector; + typedef DenseMap<uint32_t, FunctionVector> FunctionLines; + typedef SmallVector<const GCOVBlock *, 4> BlockVector; + typedef DenseMap<uint32_t, BlockVector> BlockLines; struct LineData { - LineData() = default; - + LineData() : LastLine(0) {} BlockLines Blocks; FunctionLines Functions; - uint32_t LastLine = 0; + uint32_t LastLine; }; struct GCOVCoverage { - GCOVCoverage(StringRef Name) : Name(Name) {} + GCOVCoverage(StringRef Name) + : Name(Name), LogicalLines(0), LinesExec(0), Branches(0), + BranchesExec(0), BranchesTaken(0) {} StringRef Name; - uint32_t LogicalLines = 0; - uint32_t LinesExec = 0; + uint32_t LogicalLines; + uint32_t LinesExec; - uint32_t Branches = 0; - uint32_t BranchesExec = 0; - uint32_t BranchesTaken = 0; + uint32_t Branches; + uint32_t BranchesExec; + uint32_t BranchesTaken; }; public: - FileInfo(const GCOV::Options &Options) : Options(Options) {} + FileInfo(const GCOV::Options &Options) + : Options(Options), LineInfo(), RunCount(0), ProgramCount(0) {} void addBlockLine(StringRef Filename, uint32_t Line, const GCOVBlock *Block) { if (Line > LineInfo[Filename].LastLine) LineInfo[Filename].LastLine = Line; LineInfo[Filename].Blocks[Line - 1].push_back(Block); } - void addFunctionLine(StringRef Filename, uint32_t Line, const GCOVFunction *Function) { if (Line > LineInfo[Filename].LastLine) LineInfo[Filename].LastLine = Line; LineInfo[Filename].Functions[Line - 1].push_back(Function); } - void setRunCount(uint32_t Runs) { RunCount = Runs; } void setProgramCount(uint32_t Programs) { ProgramCount = Programs; } void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile, @@ -445,16 +431,15 @@ private: const GCOV::Options &Options; StringMap<LineData> LineInfo; - uint32_t RunCount = 0; - uint32_t ProgramCount = 0; + uint32_t RunCount; + uint32_t ProgramCount; - using FileCoverageList = SmallVector<std::pair<std::string, GCOVCoverage>, 4>; - using FuncCoverageMap = MapVector<const GCOVFunction *, GCOVCoverage>; + typedef SmallVector<std::pair<std::string, GCOVCoverage>, 4> FileCoverageList; + typedef MapVector<const GCOVFunction *, GCOVCoverage> FuncCoverageMap; FileCoverageList FileCoverages; FuncCoverageMap FuncCoverages; }; +} -} // end namespace llvm - -#endif // LLVM_SUPPORT_GCOV_H +#endif diff --git a/gnu/llvm/include/llvm/Target/CostTable.h b/gnu/llvm/include/llvm/Target/CostTable.h index b7d9240a91f..2499f5c3189 100644 --- a/gnu/llvm/include/llvm/Target/CostTable.h +++ b/gnu/llvm/include/llvm/Target/CostTable.h @@ -16,7 +16,6 @@ #define LLVM_TARGET_COSTTABLE_H_ #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineValueType.h" namespace llvm { @@ -31,9 +30,9 @@ struct CostTblEntry { /// Find in cost table, TypeTy must be comparable to CompareTy by == inline const CostTblEntry *CostTableLookup(ArrayRef<CostTblEntry> Tbl, int ISD, MVT Ty) { - auto I = find_if(Tbl, [=](const CostTblEntry &Entry) { - return ISD == Entry.ISD && Ty == Entry.Type; - }); + auto I = std::find_if(Tbl.begin(), Tbl.end(), + [=](const CostTblEntry &Entry) { + return ISD == Entry.ISD && Ty == Entry.Type; }); if (I != Tbl.end()) return I; @@ -54,9 +53,11 @@ struct TypeConversionCostTblEntry { inline const TypeConversionCostTblEntry * ConvertCostTableLookup(ArrayRef<TypeConversionCostTblEntry> Tbl, int ISD, MVT Dst, MVT Src) { - auto I = find_if(Tbl, [=](const TypeConversionCostTblEntry &Entry) { - return ISD == Entry.ISD && Src == Entry.Src && Dst == Entry.Dst; - }); + auto I = std::find_if(Tbl.begin(), Tbl.end(), + [=](const TypeConversionCostTblEntry &Entry) { + return ISD == Entry.ISD && Src == Entry.Src && + Dst == Entry.Dst; + }); if (I != Tbl.end()) return I; diff --git a/gnu/llvm/include/llvm/Target/TargetCallingConv.h b/gnu/llvm/include/llvm/Target/TargetCallingConv.h index 4f750b8a289..0c6c1f1468c 100644 --- a/gnu/llvm/include/llvm/Target/TargetCallingConv.h +++ b/gnu/llvm/include/llvm/Target/TargetCallingConv.h @@ -14,120 +14,118 @@ #ifndef LLVM_TARGET_TARGETCALLINGCONV_H #define LLVM_TARGET_TARGETCALLINGCONV_H -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" -#include <cassert> -#include <climits> -#include <cstdint> +#include <string> +#include <limits.h> namespace llvm { -namespace ISD { +namespace ISD { struct ArgFlagsTy { private: - unsigned IsZExt : 1; ///< Zero extended - unsigned IsSExt : 1; ///< Sign extended - unsigned IsInReg : 1; ///< Passed in register - unsigned IsSRet : 1; ///< Hidden struct-ret ptr - unsigned IsByVal : 1; ///< Struct passed by value - unsigned IsNest : 1; ///< Nested fn static chain - unsigned IsReturned : 1; ///< Always returned - unsigned IsSplit : 1; - unsigned IsInAlloca : 1; ///< Passed with inalloca - unsigned IsSplitEnd : 1; ///< Last part of a split - unsigned IsSwiftSelf : 1; ///< Swift self parameter - unsigned IsSwiftError : 1; ///< Swift error parameter - unsigned IsHva : 1; ///< HVA field for - unsigned IsHvaStart : 1; ///< HVA structure start - unsigned IsSecArgPass : 1; ///< Second argument - unsigned ByValAlign : 4; ///< Log 2 of byval alignment - unsigned OrigAlign : 5; ///< Log 2 of original alignment - unsigned IsInConsecutiveRegsLast : 1; - unsigned IsInConsecutiveRegs : 1; - unsigned IsCopyElisionCandidate : 1; ///< Argument copy elision candidate - - unsigned ByValSize; ///< Byval struct size - + static const uint64_t NoFlagSet = 0ULL; + static const uint64_t ZExt = 1ULL<<0; ///< Zero extended + static const uint64_t ZExtOffs = 0; + static const uint64_t SExt = 1ULL<<1; ///< Sign extended + static const uint64_t SExtOffs = 1; + static const uint64_t InReg = 1ULL<<2; ///< Passed in register + static const uint64_t InRegOffs = 2; + static const uint64_t SRet = 1ULL<<3; ///< Hidden struct-ret ptr + static const uint64_t SRetOffs = 3; + static const uint64_t ByVal = 1ULL<<4; ///< Struct passed by value + static const uint64_t ByValOffs = 4; + static const uint64_t Nest = 1ULL<<5; ///< Nested fn static chain + static const uint64_t NestOffs = 5; + static const uint64_t Returned = 1ULL<<6; ///< Always returned + static const uint64_t ReturnedOffs = 6; + static const uint64_t ByValAlign = 0xFULL<<7; ///< Struct alignment + static const uint64_t ByValAlignOffs = 7; + static const uint64_t Split = 1ULL<<11; + static const uint64_t SplitOffs = 11; + static const uint64_t InAlloca = 1ULL<<12; ///< Passed with inalloca + static const uint64_t InAllocaOffs = 12; + static const uint64_t SplitEnd = 1ULL<<13; ///< Last part of a split + static const uint64_t SplitEndOffs = 13; + static const uint64_t OrigAlign = 0x1FULL<<27; + static const uint64_t OrigAlignOffs = 27; + static const uint64_t ByValSize = 0x3fffffffULL<<32; ///< Struct size + static const uint64_t ByValSizeOffs = 32; + static const uint64_t InConsecutiveRegsLast = 0x1ULL<<62; ///< Struct size + static const uint64_t InConsecutiveRegsLastOffs = 62; + static const uint64_t InConsecutiveRegs = 0x1ULL<<63; ///< Struct size + static const uint64_t InConsecutiveRegsOffs = 63; + + static const uint64_t One = 1ULL; ///< 1 of this type, for shifts + + uint64_t Flags; public: - ArgFlagsTy() - : IsZExt(0), IsSExt(0), IsInReg(0), IsSRet(0), IsByVal(0), IsNest(0), - IsReturned(0), IsSplit(0), IsInAlloca(0), IsSplitEnd(0), - IsSwiftSelf(0), IsSwiftError(0), IsHva(0), IsHvaStart(0), - IsSecArgPass(0), ByValAlign(0), OrigAlign(0), - IsInConsecutiveRegsLast(0), IsInConsecutiveRegs(0), - IsCopyElisionCandidate(0), ByValSize(0) { - static_assert(sizeof(*this) == 2 * sizeof(unsigned), "flags are too big"); - } - - bool isZExt() const { return IsZExt; } - void setZExt() { IsZExt = 1; } - - bool isSExt() const { return IsSExt; } - void setSExt() { IsSExt = 1; } - - bool isInReg() const { return IsInReg; } - void setInReg() { IsInReg = 1; } - - bool isSRet() const { return IsSRet; } - void setSRet() { IsSRet = 1; } - - bool isByVal() const { return IsByVal; } - void setByVal() { IsByVal = 1; } + ArgFlagsTy() : Flags(0) { } - bool isInAlloca() const { return IsInAlloca; } - void setInAlloca() { IsInAlloca = 1; } + bool isZExt() const { return Flags & ZExt; } + void setZExt() { Flags |= One << ZExtOffs; } - bool isSwiftSelf() const { return IsSwiftSelf; } - void setSwiftSelf() { IsSwiftSelf = 1; } + bool isSExt() const { return Flags & SExt; } + void setSExt() { Flags |= One << SExtOffs; } - bool isSwiftError() const { return IsSwiftError; } - void setSwiftError() { IsSwiftError = 1; } + bool isInReg() const { return Flags & InReg; } + void setInReg() { Flags |= One << InRegOffs; } - bool isHva() const { return IsHva; } - void setHva() { IsHva = 1; } + bool isSRet() const { return Flags & SRet; } + void setSRet() { Flags |= One << SRetOffs; } - bool isHvaStart() const { return IsHvaStart; } - void setHvaStart() { IsHvaStart = 1; } + bool isByVal() const { return Flags & ByVal; } + void setByVal() { Flags |= One << ByValOffs; } - bool isSecArgPass() const { return IsSecArgPass; } - void setSecArgPass() { IsSecArgPass = 1; } + bool isInAlloca() const { return Flags & InAlloca; } + void setInAlloca() { Flags |= One << InAllocaOffs; } - bool isNest() const { return IsNest; } - void setNest() { IsNest = 1; } + bool isNest() const { return Flags & Nest; } + void setNest() { Flags |= One << NestOffs; } - bool isReturned() const { return IsReturned; } - void setReturned() { IsReturned = 1; } + bool isReturned() const { return Flags & Returned; } + void setReturned() { Flags |= One << ReturnedOffs; } - bool isInConsecutiveRegs() const { return IsInConsecutiveRegs; } - void setInConsecutiveRegs() { IsInConsecutiveRegs = 1; } + bool isInConsecutiveRegs() const { return Flags & InConsecutiveRegs; } + void setInConsecutiveRegs() { Flags |= One << InConsecutiveRegsOffs; } - bool isInConsecutiveRegsLast() const { return IsInConsecutiveRegsLast; } - void setInConsecutiveRegsLast() { IsInConsecutiveRegsLast = 1; } + bool isInConsecutiveRegsLast() const { return Flags & InConsecutiveRegsLast; } + void setInConsecutiveRegsLast() { Flags |= One << InConsecutiveRegsLastOffs; } - bool isSplit() const { return IsSplit; } - void setSplit() { IsSplit = 1; } + unsigned getByValAlign() const { + return (unsigned) + ((One << ((Flags & ByValAlign) >> ByValAlignOffs)) / 2); + } + void setByValAlign(unsigned A) { + Flags = (Flags & ~ByValAlign) | + (uint64_t(Log2_32(A) + 1) << ByValAlignOffs); + } - bool isSplitEnd() const { return IsSplitEnd; } - void setSplitEnd() { IsSplitEnd = 1; } + bool isSplit() const { return Flags & Split; } + void setSplit() { Flags |= One << SplitOffs; } - bool isCopyElisionCandidate() const { return IsCopyElisionCandidate; } - void setCopyElisionCandidate() { IsCopyElisionCandidate = 1; } + bool isSplitEnd() const { return Flags & SplitEnd; } + void setSplitEnd() { Flags |= One << SplitEndOffs; } - unsigned getByValAlign() const { return (1U << ByValAlign) / 2; } - void setByValAlign(unsigned A) { - ByValAlign = Log2_32(A) + 1; - assert(getByValAlign() == A && "bitfield overflow"); + unsigned getOrigAlign() const { + return (unsigned) + ((One << ((Flags & OrigAlign) >> OrigAlignOffs)) / 2); } - - unsigned getOrigAlign() const { return (1U << OrigAlign) / 2; } void setOrigAlign(unsigned A) { - OrigAlign = Log2_32(A) + 1; - assert(getOrigAlign() == A && "bitfield overflow"); + Flags = (Flags & ~OrigAlign) | + (uint64_t(Log2_32(A) + 1) << OrigAlignOffs); } - unsigned getByValSize() const { return ByValSize; } - void setByValSize(unsigned S) { ByValSize = S; } + unsigned getByValSize() const { + return (unsigned)((Flags & ByValSize) >> ByValSizeOffs); + } + void setByValSize(unsigned S) { + Flags = (Flags & ~ByValSize) | (uint64_t(S) << ByValSizeOffs); + } + + /// getRawBits - Represent the flags as a bunch of bits. + uint64_t getRawBits() const { return Flags; } }; /// InputArg - This struct carries flags and type information about a @@ -136,9 +134,9 @@ namespace ISD { /// struct InputArg { ArgFlagsTy Flags; - MVT VT = MVT::Other; + MVT VT; EVT ArgVT; - bool Used = false; + bool Used; /// Index original Function's argument. unsigned OrigArgIndex; @@ -150,7 +148,7 @@ namespace ISD { /// registers, we got 4 InputArgs with PartOffsets 0, 4, 8 and 12. unsigned PartOffset; - InputArg() = default; + InputArg() : VT(MVT::Other), Used(false) {} InputArg(ArgFlagsTy flags, EVT vt, EVT argvt, bool used, unsigned origIdx, unsigned partOffs) : Flags(flags), Used(used), OrigArgIndex(origIdx), PartOffset(partOffs) { @@ -178,7 +176,7 @@ namespace ISD { EVT ArgVT; /// IsFixed - Is this a "fixed" value, ie not passed through a vararg "...". - bool IsFixed = false; + bool IsFixed; /// Index original Function's argument. unsigned OrigArgIndex; @@ -188,7 +186,7 @@ namespace ISD { /// registers, we got 4 OutputArgs with PartOffsets 0, 4, 8 and 12. unsigned PartOffset; - OutputArg() = default; + OutputArg() : IsFixed(false) {} OutputArg(ArgFlagsTy flags, EVT vt, EVT argvt, bool isfixed, unsigned origIdx, unsigned partOffs) : Flags(flags), IsFixed(isfixed), OrigArgIndex(origIdx), @@ -197,8 +195,8 @@ namespace ISD { ArgVT = argvt; } }; +} -} // end namespace ISD -} // end namespace llvm +} // end llvm namespace -#endif // LLVM_TARGET_TARGETCALLINGCONV_H +#endif diff --git a/gnu/llvm/include/llvm/Target/TargetFrameLowering.h b/gnu/llvm/include/llvm/Target/TargetFrameLowering.h index 4576f8c7582..cadd07d71f1 100644 --- a/gnu/llvm/include/llvm/Target/TargetFrameLowering.h +++ b/gnu/llvm/include/llvm/Target/TargetFrameLowering.h @@ -75,9 +75,9 @@ public: /// int alignSPAdjust(int SPAdj) const { if (SPAdj < 0) { - SPAdj = -alignTo(-SPAdj, StackAlignment); + SPAdj = -RoundUpToAlignment(-SPAdj, StackAlignment); } else { - SPAdj = alignTo(SPAdj, StackAlignment); + SPAdj = RoundUpToAlignment(SPAdj, StackAlignment); } return SPAdj; } @@ -151,13 +151,6 @@ public: return false; } - /// Returns true if the stack slot holes in the fixed and callee-save stack - /// area should be used when allocating other stack locations to reduce stack - /// size. - virtual bool enableStackSlotScavenging(const MachineFunction &MF) const { - return false; - } - /// emitProlog/emitEpilog - These methods insert prolog and epilog code into /// the function. virtual void emitPrologue(MachineFunction &MF, @@ -179,6 +172,12 @@ public: virtual void adjustForHiPEPrologue(MachineFunction &MF, MachineBasicBlock &PrologueMBB) const {} + /// Adjust the prologue to add an allocation at a fixed offset from the frame + /// pointer. + virtual void + adjustForFrameAllocatePrologue(MachineFunction &MF, + MachineBasicBlock &PrologueMBB) const {} + /// spillCalleeSavedRegisters - Issues instruction(s) to spill all callee /// saved registers and returns true if it isn't possible / profitable to do /// so by issuing a series of store instructions via @@ -240,17 +239,15 @@ public: virtual int getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const; - /// Same as \c getFrameIndexReference, except that the stack pointer (as - /// opposed to the frame pointer) will be the preferred value for \p - /// FrameReg. This is generally used for emitting statepoint or EH tables that - /// use offsets from RSP. If \p IgnoreSPUpdates is true, the returned - /// offset is only guaranteed to be valid with respect to the value of SP at - /// the end of the prologue. - virtual int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI, - unsigned &FrameReg, - bool IgnoreSPUpdates) const { - // Always safe to dispatch to getFrameIndexReference. - return getFrameIndexReference(MF, FI, FrameReg); + /// Same as above, except that the 'base register' will always be RSP, not + /// RBP on x86. This is generally used for emitting statepoint or EH tables + /// that use offsets from RSP. + /// TODO: This should really be a parameterizable choice. + virtual int getFrameIndexReferenceFromSP(const MachineFunction &MF, int FI, + unsigned &FrameReg) const { + // default to calling normal version, we override this on x86 only + llvm_unreachable("unimplemented for non-x86"); + return 0; } /// This method determines which of the registers reported by @@ -276,13 +273,14 @@ public: report_fatal_error("WinEH not implemented for this target"); } - /// This method is called during prolog/epilog code insertion to eliminate - /// call frame setup and destroy pseudo instructions (but only if the Target - /// is using them). It is responsible for eliminating these instructions, - /// replacing them with concrete instructions. This method need only be - /// implemented if using call frame setup/destroy pseudo instructions. - /// Returns an iterator pointing to the instruction after the replaced one. - virtual MachineBasicBlock::iterator + /// eliminateCallFramePseudoInstr - This method is called during prolog/epilog + /// code insertion to eliminate call frame setup and destroy pseudo + /// instructions (but only if the Target is using them). It is responsible + /// for eliminating these instructions, replacing them with concrete + /// instructions. This method need only be implemented if using call frame + /// setup/destroy pseudo instructions. + /// + virtual void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { @@ -290,18 +288,6 @@ public: "target!"); } - - /// Order the symbols in the local stack frame. - /// The list of objects that we want to order is in \p objectsToAllocate as - /// indices into the MachineFrameInfo. The array can be reordered in any way - /// upon return. The contents of the array, however, may not be modified (i.e. - /// only their order may be changed). - /// By default, just maintain the original order. - virtual void - orderFrameObjects(const MachineFunction &MF, - SmallVectorImpl<int> &objectsToAllocate) const { - } - /// Check whether or not the given \p MBB can be used as a prologue /// for the target. /// The prologue will be inserted first in this basic block. @@ -325,20 +311,6 @@ public: virtual bool canUseAsEpilogue(const MachineBasicBlock &MBB) const { return true; } - - /// Check if given function is safe for not having callee saved registers. - /// This is used when interprocedural register allocation is enabled. - static bool isSafeForNoCSROpt(const Function *F) { - if (!F->hasLocalLinkage() || F->hasAddressTaken() || - !F->hasFnAttribute(Attribute::NoRecurse)) - return false; - // Function should not be optimized as tail call. - for (const User *U : F->users()) - if (auto CS = ImmutableCallSite(U)) - if (CS.isTailCall()) - return false; - return true; - } }; } // End llvm namespace diff --git a/gnu/llvm/include/llvm/Target/TargetInstrInfo.h b/gnu/llvm/include/llvm/Target/TargetInstrInfo.h index 1843a2eed9b..0cebcf1c6b5 100644 --- a/gnu/llvm/include/llvm/Target/TargetInstrInfo.h +++ b/gnu/llvm/include/llvm/Target/TargetInstrInfo.h @@ -1,4 +1,4 @@ -//===- llvm/Target/TargetInstrInfo.h - Instruction Info ---------*- C++ -*-===// +//===-- llvm/Target/TargetInstrInfo.h - Instruction Info --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,63 +14,52 @@ #ifndef LLVM_TARGET_TARGETINSTRINFO_H #define LLVM_TARGET_TARGETINSTRINFO_H -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/None.h" -#include "llvm/CodeGen/LiveIntervalAnalysis.h" -#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/MachineCombinerPattern.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineLoopInfo.h" -#include "llvm/CodeGen/MachineOperand.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/BranchProbability.h" -#include "llvm/Support/ErrorHandling.h" -#include <cassert> -#include <cstddef> -#include <cstdint> -#include <utility> -#include <vector> +#include "llvm/Target/TargetRegisterInfo.h" namespace llvm { -class DFAPacketizer; class InstrItineraryData; class LiveVariables; +class MCAsmInfo; class MachineMemOperand; class MachineRegisterInfo; -class MCAsmInfo; +class MDNode; class MCInst; struct MCSchedModel; -class Module; -class ScheduleDAG; -class ScheduleHazardRecognizer; +class MCSymbolRefExpr; class SDNode; +class ScheduleHazardRecognizer; class SelectionDAG; -class RegScavenger; +class ScheduleDAG; class TargetRegisterClass; class TargetRegisterInfo; -class TargetSchedModel; class TargetSubtargetInfo; +class TargetSchedModel; +class DFAPacketizer; template<class T> class SmallVectorImpl; + //--------------------------------------------------------------------------- /// /// TargetInstrInfo - Interface to description of machine instruction set /// class TargetInstrInfo : public MCInstrInfo { + TargetInstrInfo(const TargetInstrInfo &) = delete; + void operator=(const TargetInstrInfo &) = delete; public: TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, - unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u) + unsigned CatchRetOpcode = ~0u) : CallFrameSetupOpcode(CFSetupOpcode), CallFrameDestroyOpcode(CFDestroyOpcode), - CatchRetOpcode(CatchRetOpcode), - ReturnOpcode(ReturnOpcode) {} - TargetInstrInfo(const TargetInstrInfo &) = delete; - TargetInstrInfo &operator=(const TargetInstrInfo &) = delete; + CatchRetOpcode(CatchRetOpcode) {} + virtual ~TargetInstrInfo(); static bool isGenericOpcode(unsigned Opc) { @@ -89,10 +78,10 @@ public: /// This means the only allowed uses are constants and unallocatable physical /// registers so that the instructions result is independent of the place /// in the function. - bool isTriviallyReMaterializable(const MachineInstr &MI, + bool isTriviallyReMaterializable(const MachineInstr *MI, AliasAnalysis *AA = nullptr) const { - return MI.getOpcode() == TargetOpcode::IMPLICIT_DEF || - (MI.getDesc().isRematerializable() && + return MI->getOpcode() == TargetOpcode::IMPLICIT_DEF || + (MI->getDesc().isRematerializable() && (isReallyTriviallyReMaterializable(MI, AA) || isReallyTriviallyReMaterializableGeneric(MI, AA))); } @@ -105,7 +94,7 @@ protected: /// than producing a value, or if it requres any address registers that are /// not always available. /// Requirements must be check as stated in isTriviallyReMaterializable() . - virtual bool isReallyTriviallyReMaterializable(const MachineInstr &MI, + virtual bool isReallyTriviallyReMaterializable(const MachineInstr *MI, AliasAnalysis *AA) const { return false; } @@ -125,7 +114,8 @@ protected: /// Do not call this method for a non-commutable instruction. /// Even though the instruction is commutable, the method may still /// fail to commute the operands, null pointer is returned in such cases. - virtual MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI, + virtual MachineInstr *commuteInstructionImpl(MachineInstr *MI, + bool NewMI, unsigned OpIdx1, unsigned OpIdx2) const; @@ -149,7 +139,7 @@ private: /// set and the target hook isReallyTriviallyReMaterializable returns false, /// this function does target-independent tests to determine if the /// instruction is really trivially rematerializable. - bool isReallyTriviallyReMaterializableGeneric(const MachineInstr &MI, + bool isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI, AliasAnalysis *AA) const; public: @@ -161,50 +151,13 @@ public: unsigned getCallFrameSetupOpcode() const { return CallFrameSetupOpcode; } unsigned getCallFrameDestroyOpcode() const { return CallFrameDestroyOpcode; } - /// Returns true if the argument is a frame pseudo instruction. - bool isFrameInstr(const MachineInstr &I) const { - return I.getOpcode() == getCallFrameSetupOpcode() || - I.getOpcode() == getCallFrameDestroyOpcode(); - } - - /// Returns true if the argument is a frame setup pseudo instruction. - bool isFrameSetup(const MachineInstr &I) const { - return I.getOpcode() == getCallFrameSetupOpcode(); - } - - /// Returns size of the frame associated with the given frame instruction. - /// For frame setup instruction this is frame that is set up space set up - /// after the instruction. For frame destroy instruction this is the frame - /// freed by the caller. - /// Note, in some cases a call frame (or a part of it) may be prepared prior - /// to the frame setup instruction. It occurs in the calls that involve - /// inalloca arguments. This function reports only the size of the frame part - /// that is set up between the frame setup and destroy pseudo instructions. - int64_t getFrameSize(const MachineInstr &I) const { - assert(isFrameInstr(I) && "Not a frame instruction"); - assert(I.getOperand(0).getImm() >= 0); - return I.getOperand(0).getImm(); - } - - /// Returns the total frame size, which is made up of the space set up inside - /// the pair of frame start-stop instructions and the space that is set up - /// prior to the pair. - int64_t getFrameTotalSize(const MachineInstr &I) const { - if (isFrameSetup(I)) { - assert(I.getOperand(1).getImm() >= 0 && "Frame size must not be negative"); - return getFrameSize(I) + I.getOperand(1).getImm(); - } - return getFrameSize(I); - } - unsigned getCatchReturnOpcode() const { return CatchRetOpcode; } - unsigned getReturnOpcode() const { return ReturnOpcode; } /// Returns the actual stack pointer adjustment made by an instruction /// as part of a call sequence. By default, only call frame setup/destroy /// instructions adjust the stack, but targets may want to override this /// to enable more fine-grained adjustment, or adjust by a different value. - virtual int getSPAdjust(const MachineInstr &MI) const; + virtual int getSPAdjust(const MachineInstr *MI) const; /// Return true if the instruction is a "coalescable" extension instruction. /// That is, it's like a copy where it's legal for the source to overlap the @@ -222,14 +175,14 @@ public: /// the destination along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than loading from the stack slot. - virtual unsigned isLoadFromStackSlot(const MachineInstr &MI, + virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { return 0; } /// Check for post-frame ptr elimination stack locations as well. /// This uses a heuristic so it isn't reliable for correctness. - virtual unsigned isLoadFromStackSlotPostFE(const MachineInstr &MI, + virtual unsigned isLoadFromStackSlotPostFE(const MachineInstr *MI, int &FrameIndex) const { return 0; } @@ -240,7 +193,7 @@ public: /// If not, return false. Unlike isLoadFromStackSlot, this returns true for /// any instructions that loads from the stack. This is just a hint, as some /// cases may be missed. - virtual bool hasLoadFromStackSlot(const MachineInstr &MI, + virtual bool hasLoadFromStackSlot(const MachineInstr *MI, const MachineMemOperand *&MMO, int &FrameIndex) const; @@ -249,14 +202,14 @@ public: /// the source reg along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than storing to the stack slot. - virtual unsigned isStoreToStackSlot(const MachineInstr &MI, + virtual unsigned isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const { return 0; } /// Check for post-frame ptr elimination stack locations as well. /// This uses a heuristic, so it isn't reliable for correctness. - virtual unsigned isStoreToStackSlotPostFE(const MachineInstr &MI, + virtual unsigned isStoreToStackSlotPostFE(const MachineInstr *MI, int &FrameIndex) const { return 0; } @@ -267,14 +220,14 @@ public: /// If not, return false. Unlike isStoreToStackSlot, /// this returns true for any instructions that stores to the /// stack. This is just a hint, as some cases may be missed. - virtual bool hasStoreToStackSlot(const MachineInstr &MI, + virtual bool hasStoreToStackSlot(const MachineInstr *MI, const MachineMemOperand *&MMO, int &FrameIndex) const; /// Return true if the specified machine instruction /// is a copy of one stack slot to another and has no other effect. /// Provide the identity of the two frame indices. - virtual bool isStackSlotCopy(const MachineInstr &MI, int &DestFrameIndex, + virtual bool isStackSlotCopy(const MachineInstr *MI, int &DestFrameIndex, int &SrcFrameIndex) const { return false; } @@ -296,27 +249,12 @@ public: unsigned &Size, unsigned &Offset, const MachineFunction &MF) const; - /// Returns the size in bytes of the specified MachineInstr, or ~0U - /// when this function is not implemented by a target. - virtual unsigned getInstSizeInBytes(const MachineInstr &MI) const { - return ~0U; - } - /// Return true if the instruction is as cheap as a move instruction. /// /// Targets for different archs need to override this, and different /// micro-architectures can also be finely tuned inside. - virtual bool isAsCheapAsAMove(const MachineInstr &MI) const { - return MI.isAsCheapAsAMove(); - } - - /// Return true if the instruction should be sunk by MachineSink. - /// - /// MachineSink determines on its own whether the instruction is safe to sink; - /// this gives the target a hook to override the default behavior with regards - /// to which instructions should be sunk. - virtual bool shouldSink(const MachineInstr &MI) const { - return true; + virtual bool isAsCheapAsAMove(const MachineInstr *MI) const { + return MI->isAsCheapAsAMove(); } /// Re-issue the specified 'original' instruction at the @@ -325,8 +263,9 @@ public: /// DestReg:SubIdx. Any existing subreg index is preserved or composed with /// SubIdx. virtual void reMaterialize(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, unsigned DestReg, - unsigned SubIdx, const MachineInstr &Orig, + MachineBasicBlock::iterator MI, + unsigned DestReg, unsigned SubIdx, + const MachineInstr *Orig, const TargetRegisterInfo &TRI) const; /// Create a duplicate of the Orig instruction in MF. This is like @@ -334,7 +273,7 @@ public: /// that are required to be unique. /// /// The instruction must be duplicable as indicated by isNotDuplicable(). - virtual MachineInstr *duplicate(MachineInstr &Orig, + virtual MachineInstr *duplicate(MachineInstr *Orig, MachineFunction &MF) const; /// This method must be implemented by targets that @@ -347,9 +286,9 @@ public: /// This method returns a null pointer if the transformation cannot be /// performed, otherwise it returns the last new instruction. /// - virtual MachineInstr *convertToThreeAddress(MachineFunction::iterator &MFI, - MachineInstr &MI, - LiveVariables *LV) const { + virtual MachineInstr * + convertToThreeAddress(MachineFunction::iterator &MFI, + MachineBasicBlock::iterator &MBBI, LiveVariables *LV) const { return nullptr; } @@ -376,7 +315,8 @@ public: /// Even though the instruction is commutable, the method may still /// fail to commute the operands, null pointer is returned in such cases. MachineInstr * - commuteInstruction(MachineInstr &MI, bool NewMI = false, + commuteInstruction(MachineInstr *MI, + bool NewMI = false, unsigned OpIdx1 = CommuteAnyOperandIndex, unsigned OpIdx2 = CommuteAnyOperandIndex) const; @@ -397,7 +337,7 @@ public: /// findCommutedOpIndices(MI, Op1, Op2); /// can be interpreted as a query asking to find an operand that would be /// commutable with the operand#1. - virtual bool findCommutedOpIndices(MachineInstr &MI, unsigned &SrcOpIdx1, + virtual bool findCommutedOpIndices(MachineInstr *MI, unsigned &SrcOpIdx1, unsigned &SrcOpIdx2) const; /// A pair composed of a register and a sub-register index. @@ -405,17 +345,14 @@ public: struct RegSubRegPair { unsigned Reg; unsigned SubReg; - RegSubRegPair(unsigned Reg = 0, unsigned SubReg = 0) : Reg(Reg), SubReg(SubReg) {} }; - /// A pair composed of a pair of a register and a sub-register index, /// and another sub-register index. /// Used to give some type checking when modeling Reg:SubReg1, SubReg2. struct RegSubRegPairAndIdx : RegSubRegPair { unsigned SubIdx; - RegSubRegPairAndIdx(unsigned Reg = 0, unsigned SubReg = 0, unsigned SubIdx = 0) : RegSubRegPair(Reg, SubReg), SubIdx(SubIdx) {} @@ -481,40 +418,16 @@ public: RegSubRegPair &BaseReg, RegSubRegPairAndIdx &InsertedReg) const; + /// Return true if two machine instructions would produce identical values. /// By default, this is only true when the two instructions /// are deemed identical except for defs. If this function is called when the /// IR is still in SSA form, the caller can pass the MachineRegisterInfo for /// aggressive checks. - virtual bool produceSameValue(const MachineInstr &MI0, - const MachineInstr &MI1, + virtual bool produceSameValue(const MachineInstr *MI0, + const MachineInstr *MI1, const MachineRegisterInfo *MRI = nullptr) const; - /// \returns true if a branch from an instruction with opcode \p BranchOpc - /// bytes is capable of jumping to a position \p BrOffset bytes away. - virtual bool isBranchOffsetInRange(unsigned BranchOpc, - int64_t BrOffset) const { - llvm_unreachable("target did not implement"); - } - - /// \returns The block that branch instruction \p MI jumps to. - virtual MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const { - llvm_unreachable("target did not implement"); - } - - /// Insert an unconditional indirect branch at the end of \p MBB to \p - /// NewDestBB. \p BrOffset indicates the offset of \p NewDestBB relative to - /// the offset of the position to insert the new branch. - /// - /// \returns The number of bytes added to the block. - virtual unsigned insertIndirectBranch(MachineBasicBlock &MBB, - MachineBasicBlock &NewDestBB, - const DebugLoc &DL, - int64_t BrOffset = 0, - RegScavenger *RS = nullptr) const { - llvm_unreachable("target did not implement"); - } - /// Analyze the branching code at the end of MBB, returning /// true if it cannot be understood (e.g. it's a switch dispatch or isn't /// implemented for a target). Upon success, this returns false and returns @@ -534,15 +447,13 @@ public: /// condition. These operands can be passed to other TargetInstrInfo /// methods to create new branches. /// - /// Note that removeBranch and insertBranch must be implemented to support + /// Note that RemoveBranch and InsertBranch must be implemented to support /// cases where this method returns success. /// /// If AllowModify is true, then this routine is allowed to modify the basic /// block (e.g. delete instructions after the unconditional branch). /// - /// The CFG information in MBB.Predecessors and MBB.Successors must be valid - /// before calling this function. - virtual bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, bool AllowModify = false) const { @@ -562,19 +473,23 @@ public: PRED_INVALID // Sentinel value }; - ComparePredicate Predicate = PRED_INVALID; - MachineOperand LHS = MachineOperand::CreateImm(0); - MachineOperand RHS = MachineOperand::CreateImm(0); - MachineBasicBlock *TrueDest = nullptr; - MachineBasicBlock *FalseDest = nullptr; - MachineInstr *ConditionDef = nullptr; + ComparePredicate Predicate; + MachineOperand LHS; + MachineOperand RHS; + MachineBasicBlock *TrueDest; + MachineBasicBlock *FalseDest; + MachineInstr *ConditionDef; /// SingleUseCondition is true if ConditionDef is dead except for the /// branch(es) at the end of the basic block. /// - bool SingleUseCondition = false; + bool SingleUseCondition; - explicit MachineBranchPredicate() = default; + explicit MachineBranchPredicate() + : Predicate(PRED_INVALID), LHS(MachineOperand::CreateImm(0)), + RHS(MachineOperand::CreateImm(0)), TrueDest(nullptr), + FalseDest(nullptr), ConditionDef(nullptr), SingleUseCondition(false) { + } }; /// Analyze the branching code at the end of MBB and parse it into the @@ -584,7 +499,7 @@ public: /// If AllowModify is true, then this routine is allowed to modify the basic /// block (e.g. delete instructions after the unconditional branch). /// - virtual bool analyzeBranchPredicate(MachineBasicBlock &MBB, + virtual bool AnalyzeBranchPredicate(MachineBasicBlock &MBB, MachineBranchPredicate &MBP, bool AllowModify = false) const { return true; @@ -593,60 +508,25 @@ public: /// Remove the branching code at the end of the specific MBB. /// This is only invoked in cases where AnalyzeBranch returns success. It /// returns the number of instructions that were removed. - /// If \p BytesRemoved is non-null, report the change in code size from the - /// removed instructions. - virtual unsigned removeBranch(MachineBasicBlock &MBB, - int *BytesRemoved = nullptr) const { - llvm_unreachable("Target didn't implement TargetInstrInfo::removeBranch!"); + virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const { + llvm_unreachable("Target didn't implement TargetInstrInfo::RemoveBranch!"); } - /// Insert branch code into the end of the specified MachineBasicBlock. The - /// operands to this method are the same as those returned by AnalyzeBranch. - /// This is only invoked in cases where AnalyzeBranch returns success. It - /// returns the number of instructions inserted. If \p BytesAdded is non-null, - /// report the change in code size from the added instructions. + /// Insert branch code into the end of the specified MachineBasicBlock. + /// The operands to this method are the same as those + /// returned by AnalyzeBranch. This is only invoked in cases where + /// AnalyzeBranch returns success. It returns the number of instructions + /// inserted. /// /// It is also invoked by tail merging to add unconditional branches in /// cases where AnalyzeBranch doesn't apply because there was no original /// branch to analyze. At least this much must be implemented, else tail /// merging needs to be disabled. - /// - /// The CFG information in MBB.Predecessors and MBB.Successors must be valid - /// before calling this function. - virtual unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, - const DebugLoc &DL, - int *BytesAdded = nullptr) const { - llvm_unreachable("Target didn't implement TargetInstrInfo::insertBranch!"); - } - - unsigned insertUnconditionalBranch(MachineBasicBlock &MBB, - MachineBasicBlock *DestBB, - const DebugLoc &DL, - int *BytesAdded = nullptr) const { - return insertBranch(MBB, DestBB, nullptr, - ArrayRef<MachineOperand>(), DL, BytesAdded); - } - - /// Analyze the loop code, return true if it cannot be understoo. Upon - /// success, this function returns false and returns information about the - /// induction variable and compare instruction used at the end. - virtual bool analyzeLoop(MachineLoop &L, MachineInstr *&IndVarInst, - MachineInstr *&CmpInst) const { - return true; - } - - /// Generate code to reduce the loop iteration by one and check if the loop is - /// finished. Return the value/register of the the new loop count. We need - /// this function when peeling off one or more iterations of a loop. This - /// function assumes the nth iteration is peeled first. - virtual unsigned reduceLoopCount(MachineBasicBlock &MBB, - MachineInstr *IndVar, MachineInstr &Cmp, - SmallVectorImpl<MachineOperand> &Cond, - SmallVectorImpl<MachineInstr *> &PrevInsts, - unsigned Iter, unsigned MaxIter) const { - llvm_unreachable("Target didn't implement ReduceLoopCount"); + DebugLoc DL) const { + llvm_unreachable("Target didn't implement TargetInstrInfo::InsertBranch!"); } /// Delete the instruction OldInst and everything after it, replacing it with @@ -654,6 +534,40 @@ public: virtual void ReplaceTailWithBranchTo(MachineBasicBlock::iterator Tail, MachineBasicBlock *NewDest) const; + /// Get an instruction that performs an unconditional branch to the given + /// symbol. + virtual void + getUnconditionalBranch(MCInst &MI, + const MCSymbolRefExpr *BranchTarget) const { + llvm_unreachable("Target didn't implement " + "TargetInstrInfo::getUnconditionalBranch!"); + } + + /// Get a machine trap instruction. + virtual void getTrap(MCInst &MI) const { + llvm_unreachable("Target didn't implement TargetInstrInfo::getTrap!"); + } + + /// Get a number of bytes that suffices to hold + /// either the instruction returned by getUnconditionalBranch or the + /// instruction returned by getTrap. This only makes sense because + /// getUnconditionalBranch returns a single, specific instruction. This + /// information is needed by the jumptable construction code, since it must + /// decide how many bytes to use for a jumptable entry so it can generate the + /// right mask. + /// + /// Note that if the jumptable instruction requires alignment, then that + /// alignment should be factored into this required bound so that the + /// resulting bound gives the right alignment for the instruction. + virtual unsigned getJumpInstrTableEntryBound() const { + // This method gets called by LLVMTargetMachine always, so it can't fail + // just because there happens to be no implementation for this target. + // Any code that tries to use a jumptable annotation without defining + // getUnconditionalBranch on the appropriate Target will fail anyway, and + // the value returned here won't matter in that case. + return 0; + } + /// Return true if it's legal to split the given basic /// block at the specified instruction (i.e. instruction would be the start /// of a new basic block). @@ -758,7 +672,7 @@ public: /// @param TrueReg Virtual register to copy when Cond is true. /// @param FalseReg Virtual register to copy when Cons is false. virtual void insertSelect(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, const DebugLoc &DL, + MachineBasicBlock::iterator I, DebugLoc DL, unsigned DstReg, ArrayRef<MachineOperand> Cond, unsigned TrueReg, unsigned FalseReg) const { llvm_unreachable("Target didn't implement TargetInstrInfo::insertSelect!"); @@ -782,11 +696,11 @@ public: /// @param FalseOp Operand number of the value selected when Cond is false. /// @param Optimizable Returned as true if MI is optimizable. /// @returns False on success. - virtual bool analyzeSelect(const MachineInstr &MI, + virtual bool analyzeSelect(const MachineInstr *MI, SmallVectorImpl<MachineOperand> &Cond, unsigned &TrueOp, unsigned &FalseOp, bool &Optimizable) const { - assert(MI.getDesc().isSelect() && "MI must be a select instruction"); + assert(MI && MI->getDesc().isSelect() && "MI must be a select instruction"); return true; } @@ -805,7 +719,7 @@ public: /// MI. Has to be updated with any newly created MI or deleted ones. /// @param PreferFalse Try to optimize FalseOp instead of TrueOp. /// @returns Optimized instruction or NULL. - virtual MachineInstr *optimizeSelect(MachineInstr &MI, + virtual MachineInstr *optimizeSelect(MachineInstr *MI, SmallPtrSetImpl<MachineInstr *> &NewMIs, bool PreferFalse = false) const { // This function must be implemented if Optimizable is ever set. @@ -821,7 +735,7 @@ public: /// careful implementation when multiple copy instructions are required for /// large registers. See for example the ARM target. virtual void copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, const DebugLoc &DL, + MachineBasicBlock::iterator MI, DebugLoc DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const { llvm_unreachable("Target didn't implement TargetInstrInfo::copyPhysReg!"); @@ -858,21 +772,9 @@ public: /// into real instructions. The target can edit MI in place, or it can insert /// new instructions and erase MI. The function should return true if /// anything was changed. - virtual bool expandPostRAPseudo(MachineInstr &MI) const { return false; } - - /// Check whether the target can fold a load that feeds a subreg operand - /// (or a subreg operand that feeds a store). - /// For example, X86 may want to return true if it can fold - /// movl (%esp), %eax - /// subb, %al, ... - /// Into: - /// subb (%esp), ... - /// - /// Ideally, we'd like the target implementation of foldMemoryOperand() to - /// reject subregs - but since this behavior used to be enforced in the - /// target-independent code, moving this responsibility to the targets - /// has the potential of causing nasty silent breakage in out-of-tree targets. - virtual bool isSubregFoldable() const { return false; } + virtual bool expandPostRAPseudo(MachineBasicBlock::iterator MI) const { + return false; + } /// Attempt to fold a load or store of the specified stack /// slot into the specified machine instruction for the specified operand(s). @@ -880,15 +782,14 @@ public: /// operand folded, otherwise NULL is returned. /// The new instruction is inserted before MI, and the client is responsible /// for removing the old instruction. - MachineInstr *foldMemoryOperand(MachineInstr &MI, ArrayRef<unsigned> Ops, - int FrameIndex, - LiveIntervals *LIS = nullptr) const; + MachineInstr *foldMemoryOperand(MachineBasicBlock::iterator MI, + ArrayRef<unsigned> Ops, int FrameIndex) const; /// Same as the previous version except it allows folding of any load and /// store from / to any address, not just from a specific stack slot. - MachineInstr *foldMemoryOperand(MachineInstr &MI, ArrayRef<unsigned> Ops, - MachineInstr &LoadMI, - LiveIntervals *LIS = nullptr) const; + MachineInstr *foldMemoryOperand(MachineBasicBlock::iterator MI, + ArrayRef<unsigned> Ops, + MachineInstr *LoadMI) const; /// Return true when there is potentially a faster code sequence /// for an instruction chain ending in \p Root. All potential patterns are @@ -901,11 +802,6 @@ public: MachineInstr &Root, SmallVectorImpl<MachineCombinerPattern> &Patterns) const; - /// Return true when a code sequence can improve throughput. It - /// should be called only for instructions in loops. - /// \param Pattern - combiner pattern - virtual bool isThroughputPattern(MachineCombinerPattern Pattern) const; - /// Return true if the input \P Inst is part of a chain of dependent ops /// that are suitable for reassociation, otherwise return false. /// If the instruction's operands must be commuted to have a previous @@ -954,7 +850,8 @@ public: virtual void setSpecialOperandAttr(MachineInstr &OldMI1, MachineInstr &OldMI2, MachineInstr &NewMI1, MachineInstr &NewMI2) const { - } + return; + }; /// Return true when a target supports MachineCombiner. virtual bool useMachineCombiner() const { return false; } @@ -965,11 +862,9 @@ protected: /// take care of adding a MachineMemOperand to the newly created instruction. /// The instruction and any auxiliary instructions necessary will be inserted /// at InsertPt. - virtual MachineInstr * - foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI, - ArrayRef<unsigned> Ops, - MachineBasicBlock::iterator InsertPt, int FrameIndex, - LiveIntervals *LIS = nullptr) const { + virtual MachineInstr *foldMemoryOperandImpl( + MachineFunction &MF, MachineInstr *MI, ArrayRef<unsigned> Ops, + MachineBasicBlock::iterator InsertPt, int FrameIndex) const { return nullptr; } @@ -979,9 +874,8 @@ protected: /// The instruction and any auxiliary instructions necessary will be inserted /// at InsertPt. virtual MachineInstr *foldMemoryOperandImpl( - MachineFunction &MF, MachineInstr &MI, ArrayRef<unsigned> Ops, - MachineBasicBlock::iterator InsertPt, MachineInstr &LoadMI, - LiveIntervals *LIS = nullptr) const { + MachineFunction &MF, MachineInstr *MI, ArrayRef<unsigned> Ops, + MachineBasicBlock::iterator InsertPt, MachineInstr *LoadMI) const { return nullptr; } @@ -1032,10 +926,9 @@ public: /// unfoldMemoryOperand - Separate a single instruction which folded a load or /// a store or a load and a store into two or more instruction. If this is /// possible, returns true as well as the new instructions by reference. - virtual bool - unfoldMemoryOperand(MachineFunction &MF, MachineInstr &MI, unsigned Reg, - bool UnfoldLoad, bool UnfoldStore, - SmallVectorImpl<MachineInstr *> &NewMIs) const { + virtual bool unfoldMemoryOperand(MachineFunction &MF, MachineInstr *MI, + unsigned Reg, bool UnfoldLoad, bool UnfoldStore, + SmallVectorImpl<MachineInstr*> &NewMIs) const{ return false; } @@ -1081,42 +974,31 @@ public: /// Get the base register and byte offset of an instruction that reads/writes /// memory. - virtual bool getMemOpBaseRegImmOfs(MachineInstr &MemOp, unsigned &BaseReg, - int64_t &Offset, + virtual bool getMemOpBaseRegImmOfs(MachineInstr *MemOp, unsigned &BaseReg, + unsigned &Offset, const TargetRegisterInfo *TRI) const { return false; } - /// Return true if the instruction contains a base register and offset. If - /// true, the function also sets the operand position in the instruction - /// for the base register and offset. - virtual bool getBaseAndOffsetPosition(const MachineInstr &MI, - unsigned &BasePos, - unsigned &OffsetPos) const { - return false; - } + virtual bool enableClusterLoads() const { return false; } - /// If the instruction is an increment of a constant value, return the amount. - virtual bool getIncrementValue(const MachineInstr &MI, int &Value) const { + virtual bool shouldClusterLoads(MachineInstr *FirstLdSt, + MachineInstr *SecondLdSt, + unsigned NumLoads) const { return false; } - /// Returns true if the two given memory operations should be scheduled - /// adjacent. Note that you have to add: - /// DAG->addMutation(createLoadClusterDAGMutation(DAG->TII, DAG->TRI)); - /// or - /// DAG->addMutation(createStoreClusterDAGMutation(DAG->TII, DAG->TRI)); - /// to TargetPassConfig::createMachineScheduler() to have an effect. - virtual bool shouldClusterMemOps(MachineInstr &FirstLdSt, - MachineInstr &SecondLdSt, - unsigned NumLoads) const { - llvm_unreachable("target did not implement shouldClusterMemOps()"); + /// Can this target fuse the given instructions if they are scheduled + /// adjacent. + virtual bool shouldScheduleAdjacent(MachineInstr* First, + MachineInstr *Second) const { + return false; } /// Reverses the branch condition of the specified condition list, /// returning false on success and true if it cannot be reversed. virtual - bool reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { + bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const { return true; } @@ -1124,46 +1006,25 @@ public: virtual void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const; + /// Return the noop instruction to use for a noop. - virtual void getNoop(MCInst &NopInst) const; + virtual void getNoopForMachoTarget(MCInst &NopInst) const; - /// Return true for post-incremented instructions. - virtual bool isPostIncrement(const MachineInstr &MI) const { - return false; - } /// Returns true if the instruction is already predicated. - virtual bool isPredicated(const MachineInstr &MI) const { + virtual bool isPredicated(const MachineInstr *MI) const { return false; } /// Returns true if the instruction is a /// terminator instruction that has not been predicated. - virtual bool isUnpredicatedTerminator(const MachineInstr &MI) const; - - /// Returns true if MI is an unconditional tail call. - virtual bool isUnconditionalTailCall(const MachineInstr &MI) const { - return false; - } - - /// Returns true if the tail call can be made conditional on BranchCond. - virtual bool - canMakeTailCallConditional(SmallVectorImpl<MachineOperand> &Cond, - const MachineInstr &TailCall) const { - return false; - } - - /// Replace the conditional branch in MBB with a conditional tail call. - virtual void replaceBranchWithTailCall(MachineBasicBlock &MBB, - SmallVectorImpl<MachineOperand> &Cond, - const MachineInstr &TailCall) const { - llvm_unreachable("Target didn't implement replaceBranchWithTailCall!"); - } + virtual bool isUnpredicatedTerminator(const MachineInstr *MI) const; /// Convert the instruction into a predicated instruction. /// It returns true if the operation was successful. - virtual bool PredicateInstruction(MachineInstr &MI, - ArrayRef<MachineOperand> Pred) const; + virtual + bool PredicateInstruction(MachineInstr *MI, + ArrayRef<MachineOperand> Pred) const; /// Returns true if the first specified predicate /// subsumes the second, e.g. GE subsumes GT. @@ -1176,7 +1037,7 @@ public: /// If the specified instruction defines any predicate /// or condition code register(s) used for predication, returns true as well /// as the definition predicate(s) by reference. - virtual bool DefinesPredicate(MachineInstr &MI, + virtual bool DefinesPredicate(MachineInstr *MI, std::vector<MachineOperand> &Pred) const { return false; } @@ -1184,8 +1045,8 @@ public: /// Return true if the specified instruction can be predicated. /// By default, this returns true for every instruction with a /// PredicateOperand. - virtual bool isPredicable(const MachineInstr &MI) const { - return MI.getDesc().isPredicable(); + virtual bool isPredicable(MachineInstr *MI) const { + return MI->getDesc().isPredicable(); } /// Return true if it's safe to move a machine @@ -1196,7 +1057,7 @@ public: /// Test if the given instruction should be considered a scheduling boundary. /// This primarily includes labels and terminators. - virtual bool isSchedulingBoundary(const MachineInstr &MI, + virtual bool isSchedulingBoundary(const MachineInstr *MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const; @@ -1223,13 +1084,6 @@ public: CreateTargetPostRAHazardRecognizer(const InstrItineraryData*, const ScheduleDAG *DAG) const; - /// Allocate and return a hazard recognizer to use for by non-scheduling - /// passes. - virtual ScheduleHazardRecognizer* - CreateTargetPostRAHazardRecognizer(const MachineFunction &MF) const { - return nullptr; - } - /// Provide a global flag for disabling the PreRA hazard recognizer that /// targets may choose to honor. bool usePreRAHazardRecognizer() const; @@ -1238,20 +1092,22 @@ public: /// in SrcReg and SrcReg2 if having two register operands, and the value it /// compares against in CmpValue. Return true if the comparison instruction /// can be analyzed. - virtual bool analyzeCompare(const MachineInstr &MI, unsigned &SrcReg, - unsigned &SrcReg2, int &Mask, int &Value) const { + virtual bool analyzeCompare(const MachineInstr *MI, + unsigned &SrcReg, unsigned &SrcReg2, + int &Mask, int &Value) const { return false; } /// See if the comparison instruction can be converted /// into something more efficient. E.g., on ARM most instructions can set the /// flags register, obviating the need for a separate CMP. - virtual bool optimizeCompareInstr(MachineInstr &CmpInstr, unsigned SrcReg, - unsigned SrcReg2, int Mask, int Value, + virtual bool optimizeCompareInstr(MachineInstr *CmpInstr, + unsigned SrcReg, unsigned SrcReg2, + int Mask, int Value, const MachineRegisterInfo *MRI) const { return false; } - virtual bool optimizeCondBranch(MachineInstr &MI) const { return false; } + virtual bool optimizeCondBranch(MachineInstr *MI) const { return false; } /// Try to remove the load by folding it to a register operand at the use. /// We fold the load instructions if and only if the @@ -1260,10 +1116,10 @@ public: /// defined by the load we are trying to fold. DefMI returns the machine /// instruction that defines FoldAsLoadDefReg, and the function returns /// the machine instruction generated due to folding. - virtual MachineInstr *optimizeLoadInstr(MachineInstr &MI, - const MachineRegisterInfo *MRI, - unsigned &FoldAsLoadDefReg, - MachineInstr *&DefMI) const { + virtual MachineInstr* optimizeLoadInstr(MachineInstr *MI, + const MachineRegisterInfo *MRI, + unsigned &FoldAsLoadDefReg, + MachineInstr *&DefMI) const { return nullptr; } @@ -1273,7 +1129,7 @@ public: /// then the caller may assume that DefMI has been erased from its parent /// block. The caller may assume that it will not be erased by this /// function otherwise. - virtual bool FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, + virtual bool FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, unsigned Reg, MachineRegisterInfo *MRI) const { return false; } @@ -1283,7 +1139,7 @@ public: /// IssueWidth is the number of microops that can be dispatched each /// cycle. An instruction with zero microops takes no dispatch resources. virtual unsigned getNumMicroOps(const InstrItineraryData *ItinData, - const MachineInstr &MI) const; + const MachineInstr *MI) const; /// Return true for pseudo instructions that don't consume any /// machine resources in their current form. These are common cases that the @@ -1306,28 +1162,35 @@ public: /// by a target. Use computeOperandLatency to get the best estimate of /// latency. virtual int getOperandLatency(const InstrItineraryData *ItinData, - const MachineInstr &DefMI, unsigned DefIdx, - const MachineInstr &UseMI, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const; + /// Compute and return the latency of the given data + /// dependent def and use when the operand indices are already known. + unsigned computeOperandLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) + const; + /// Compute the instruction latency of a given instruction. /// If the instruction has higher cost when predicated, it's returned via /// PredCost. virtual unsigned getInstrLatency(const InstrItineraryData *ItinData, - const MachineInstr &MI, + const MachineInstr *MI, unsigned *PredCost = nullptr) const; - virtual unsigned getPredicationCost(const MachineInstr &MI) const; + virtual unsigned getPredicationCost(const MachineInstr *MI) const; virtual int getInstrLatency(const InstrItineraryData *ItinData, SDNode *Node) const; - /// Return the default expected latency for a def based on its opcode. + /// Return the default expected latency for a def based on it's opcode. unsigned defaultDefLatency(const MCSchedModel &SchedModel, - const MachineInstr &DefMI) const; + const MachineInstr *DefMI) const; int computeDefOperandLatency(const InstrItineraryData *ItinData, - const MachineInstr &DefMI) const; + const MachineInstr *DefMI) const; /// Return true if this opcode has high latency to its result. virtual bool isHighLatencyDef(int opc) const { return false; } @@ -1337,23 +1200,23 @@ public: /// it 'high'. This is used by optimization passes such as machine LICM to /// determine whether it makes sense to hoist an instruction out even in a /// high register pressure situation. - virtual bool hasHighOperandLatency(const TargetSchedModel &SchedModel, - const MachineRegisterInfo *MRI, - const MachineInstr &DefMI, unsigned DefIdx, - const MachineInstr &UseMI, - unsigned UseIdx) const { + virtual + bool hasHighOperandLatency(const TargetSchedModel &SchedModel, + const MachineRegisterInfo *MRI, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const { return false; } /// Compute operand latency of a def of 'Reg'. Return true /// if the target considered it 'low'. - virtual bool hasLowDefLatency(const TargetSchedModel &SchedModel, - const MachineInstr &DefMI, - unsigned DefIdx) const; + virtual + bool hasLowDefLatency(const TargetSchedModel &SchedModel, + const MachineInstr *DefMI, unsigned DefIdx) const; /// Perform target-specific instruction verification. - virtual bool verifyInstruction(const MachineInstr &MI, - StringRef &ErrInfo) const { + virtual + bool verifyInstruction(const MachineInstr *MI, StringRef &ErrInfo) const { return true; } @@ -1377,7 +1240,7 @@ public: /// execution domain. /// virtual std::pair<uint16_t, uint16_t> - getExecutionDomain(const MachineInstr &MI) const { + getExecutionDomain(const MachineInstr *MI) const { return std::make_pair(0, 0); } @@ -1385,7 +1248,8 @@ public: /// /// The bit (1 << Domain) must be set in the mask returned from /// getExecutionDomain(MI). - virtual void setExecutionDomain(MachineInstr &MI, unsigned Domain) const {} + virtual void setExecutionDomain(MachineInstr *MI, unsigned Domain) const {} + /// Returns the preferred minimum clearance /// before an instruction with an unwanted partial register update. @@ -1427,7 +1291,7 @@ public: /// allows the target to insert a dependency breaking instruction. /// virtual unsigned - getPartialRegUpdateClearance(const MachineInstr &MI, unsigned OpNum, + getPartialRegUpdateClearance(const MachineInstr *MI, unsigned OpNum, const TargetRegisterInfo *TRI) const { // The default implementation returns 0 for no partial register dependency. return 0; @@ -1447,7 +1311,7 @@ public: /// This hook works similarly to getPartialRegUpdateClearance, except that it /// does not take an operand index. Instead sets \p OpNum to the index of the /// unused register. - virtual unsigned getUndefRegClearance(const MachineInstr &MI, unsigned &OpNum, + virtual unsigned getUndefRegClearance(const MachineInstr *MI, unsigned &OpNum, const TargetRegisterInfo *TRI) const { // The default implementation returns 0 for no undef register dependency. return 0; @@ -1470,8 +1334,9 @@ public: /// An <imp-kill> operand should be added to MI if an instruction was /// inserted. This ties the instructions together in the post-ra scheduler. /// - virtual void breakPartialRegDependency(MachineInstr &MI, unsigned OpNum, - const TargetRegisterInfo *TRI) const {} + virtual void + breakPartialRegDependency(MachineBasicBlock::iterator MI, unsigned OpNum, + const TargetRegisterInfo *TRI) const {} /// Create machine specific model for scheduling. virtual DFAPacketizer * @@ -1479,23 +1344,16 @@ public: return nullptr; } - /// Sometimes, it is possible for the target - /// to tell, even without aliasing information, that two MIs access different - /// memory addresses. This function returns true if two MIs access different - /// memory addresses and false otherwise. - /// - /// Assumes any physical registers used to compute addresses have the same - /// value for both instructions. (This is the most useful assumption for - /// post-RA scheduling.) - /// - /// See also MachineInstr::mayAlias, which is implemented on top of this - /// function. + // Sometimes, it is possible for the target + // to tell, even without aliasing information, that two MIs access different + // memory addresses. This function returns true if two MIs access different + // memory addresses and false otherwise. virtual bool - areMemAccessesTriviallyDisjoint(MachineInstr &MIa, MachineInstr &MIb, + areMemAccessesTriviallyDisjoint(MachineInstr *MIa, MachineInstr *MIb, AliasAnalysis *AA = nullptr) const { - assert((MIa.mayLoad() || MIa.mayStore()) && + assert(MIa && (MIa->mayLoad() || MIa->mayStore()) && "MIa must load from or modify a memory location"); - assert((MIb.mayLoad() || MIb.mayStore()) && + assert(MIb && (MIb->mayLoad() || MIb->mayStore()) && "MIb must load from or modify a memory location"); return false; } @@ -1545,110 +1403,24 @@ public: return None; } - /// Return an array that contains the MMO target flag values and their - /// names. - /// - /// MIR Serialization is able to serialize only the MMO target flags that are - /// defined by this method. - virtual ArrayRef<std::pair<MachineMemOperand::Flags, const char *>> - getSerializableMachineMemOperandTargetFlags() const { - return None; - } - - /// Determines whether \p Inst is a tail call instruction. Override this - /// method on targets that do not properly set MCID::Return and MCID::Call on - /// tail call instructions." - virtual bool isTailCall(const MachineInstr &Inst) const { - return Inst.isReturn() && Inst.isCall(); - } - - /// True if the instruction is bound to the top of its basic block and no - /// other instructions shall be inserted before it. This can be implemented - /// to prevent register allocator to insert spills before such instructions. - virtual bool isBasicBlockPrologue(const MachineInstr &MI) const { - return false; - } - - /// \brief Return how many instructions would be saved by outlining a - /// sequence containing \p SequenceSize instructions that appears - /// \p Occurrences times in a module. - virtual unsigned getOutliningBenefit(size_t SequenceSize, size_t Occurrences, - bool CanBeTailCall) const { - llvm_unreachable( - "Target didn't implement TargetInstrInfo::getOutliningBenefit!"); - } - - /// Represents how an instruction should be mapped by the outliner. - /// \p Legal instructions are those which are safe to outline. - /// \p Illegal instructions are those which cannot be outlined. - /// \p Invisible instructions are instructions which can be outlined, but - /// shouldn't actually impact the outlining result. - enum MachineOutlinerInstrType {Legal, Illegal, Invisible}; - - /// Returns how or if \p MI should be outlined. - virtual MachineOutlinerInstrType getOutliningType(MachineInstr &MI) const { - llvm_unreachable( - "Target didn't implement TargetInstrInfo::getOutliningType!"); - } - - /// Insert a custom epilogue for outlined functions. - /// This may be empty, in which case no epilogue or return statement will be - /// emitted. - virtual void insertOutlinerEpilogue(MachineBasicBlock &MBB, - MachineFunction &MF, - bool IsTailCall) const { - llvm_unreachable( - "Target didn't implement TargetInstrInfo::insertOutlinerEpilogue!"); - } - - /// Insert a call to an outlined function into the program. - /// Returns an iterator to the spot where we inserted the call. This must be - /// implemented by the target. - virtual MachineBasicBlock::iterator - insertOutlinedCall(Module &M, MachineBasicBlock &MBB, - MachineBasicBlock::iterator &It, MachineFunction &MF, - bool IsTailCall) const { - llvm_unreachable( - "Target didn't implement TargetInstrInfo::insertOutlinedCall!"); - } - - /// Insert a custom prologue for outlined functions. - /// This may be empty, in which case no prologue will be emitted. - virtual void insertOutlinerPrologue(MachineBasicBlock &MBB, - MachineFunction &MF, - bool IsTailCall) const { - llvm_unreachable( - "Target didn't implement TargetInstrInfo::insertOutlinerPrologue!"); - } - - /// Return true if the function can safely be outlined from. - /// By default, this means that the function has no red zone. - virtual bool isFunctionSafeToOutlineFrom(MachineFunction &MF) const { - llvm_unreachable("Target didn't implement " - "TargetInstrInfo::isFunctionSafeToOutlineFrom!"); - } - private: unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode; unsigned CatchRetOpcode; - unsigned ReturnOpcode; }; /// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair. template<> struct DenseMapInfo<TargetInstrInfo::RegSubRegPair> { - using RegInfo = DenseMapInfo<unsigned>; + typedef DenseMapInfo<unsigned> RegInfo; static inline TargetInstrInfo::RegSubRegPair getEmptyKey() { return TargetInstrInfo::RegSubRegPair(RegInfo::getEmptyKey(), RegInfo::getEmptyKey()); } - static inline TargetInstrInfo::RegSubRegPair getTombstoneKey() { return TargetInstrInfo::RegSubRegPair(RegInfo::getTombstoneKey(), RegInfo::getTombstoneKey()); } - /// \brief Reuse getHashValue implementation from /// std::pair<unsigned, unsigned>. static unsigned getHashValue(const TargetInstrInfo::RegSubRegPair &Val) { @@ -1656,7 +1428,6 @@ struct DenseMapInfo<TargetInstrInfo::RegSubRegPair> { std::make_pair(Val.Reg, Val.SubReg); return DenseMapInfo<std::pair<unsigned, unsigned>>::getHashValue(PairVal); } - static bool isEqual(const TargetInstrInfo::RegSubRegPair &LHS, const TargetInstrInfo::RegSubRegPair &RHS) { return RegInfo::isEqual(LHS.Reg, RHS.Reg) && @@ -1664,6 +1435,6 @@ struct DenseMapInfo<TargetInstrInfo::RegSubRegPair> { } }; -} // end namespace llvm +} // End llvm namespace -#endif // LLVM_TARGET_TARGETINSTRINFO_H +#endif diff --git a/gnu/llvm/include/llvm/Target/TargetLowering.h b/gnu/llvm/include/llvm/Target/TargetLowering.h index 23711d636c9..304da4f8751 100644 --- a/gnu/llvm/include/llvm/Target/TargetLowering.h +++ b/gnu/llvm/include/llvm/Target/TargetLowering.h @@ -1,4 +1,4 @@ -//===- llvm/Target/TargetLowering.h - Target Lowering Info ------*- C++ -*-===// +//===-- llvm/Target/TargetLowering.h - Target Lowering Info -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,88 +23,63 @@ #ifndef LLVM_TARGET_TARGETLOWERING_H #define LLVM_TARGET_TARGETLOWERING_H -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/DAGCombine.h" -#include "llvm/CodeGen/ISDOpcodes.h" -#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/RuntimeLibcalls.h" -#include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" -#include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" -#include "llvm/IR/Type.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/AtomicOrdering.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetCallingConv.h" #include "llvm/Target/TargetMachine.h" -#include <algorithm> -#include <cassert> #include <climits> -#include <cstdint> -#include <iterator> #include <map> -#include <string> -#include <utility> #include <vector> namespace llvm { - -class BranchProbability; -class CCState; -class CCValAssign; -class Constant; -class FastISel; -class FunctionLoweringInfo; -class GlobalValue; -class IntrinsicInst; -struct KnownBits; -class LLVMContext; -class MachineBasicBlock; -class MachineFunction; -class MachineInstr; -class MachineJumpTableInfo; -class MachineLoop; -class MachineRegisterInfo; -class MCContext; -class MCExpr; -class Module; -class TargetRegisterClass; -class TargetLibraryInfo; -class TargetRegisterInfo; -class Value; - -namespace Sched { - - enum Preference { - None, // No preference - Source, // Follow source order. - RegPressure, // Scheduling for lowest register pressure. - Hybrid, // Scheduling for both latency and register pressure. - ILP, // Scheduling for ILP in low register pressure mode. - VLIW // Scheduling for VLIW targets. - }; - -} // end namespace Sched + class CallInst; + class CCState; + class FastISel; + class FunctionLoweringInfo; + class ImmutableCallSite; + class IntrinsicInst; + class MachineBasicBlock; + class MachineFunction; + class MachineInstr; + class MachineJumpTableInfo; + class MachineLoop; + class Mangler; + class MCContext; + class MCExpr; + class MCSymbol; + template<typename T> class SmallVectorImpl; + class DataLayout; + class TargetRegisterClass; + class TargetLibraryInfo; + class TargetLoweringObjectFile; + class Value; + + namespace Sched { + enum Preference { + None, // No preference + Source, // Follow source order. + RegPressure, // Scheduling for lowest register pressure. + Hybrid, // Scheduling for both latency and register pressure. + ILP, // Scheduling for ILP in low register pressure mode. + VLIW // Scheduling for VLIW targets. + }; + } /// This base class for TargetLowering contains the SelectionDAG-independent /// parts that can be used from the rest of CodeGen. class TargetLoweringBase { + TargetLoweringBase(const TargetLoweringBase&) = delete; + void operator=(const TargetLoweringBase&) = delete; + public: /// This enum indicates whether operations are valid for a target, and if not, /// what action should be used to make them valid. @@ -133,7 +108,7 @@ public: /// LegalizeKind holds the legalization kind that needs to happen to EVT /// in order to type-legalize it. - using LegalizeKind = std::pair<LegalizeTypeAction, EVT>; + typedef std::pair<LegalizeTypeAction, EVT> LegalizeKind; /// Enum that describes how the target represents true/false values. enum BooleanContent { @@ -164,42 +139,6 @@ public: CmpXChg, // Expand the instruction into cmpxchg; used by at least X86. }; - /// Enum that specifies when a multiplication should be expanded. - enum class MulExpansionKind { - Always, // Always expand the instruction. - OnlyLegalOrCustom, // Only expand when the resulting instructions are legal - // or custom. - }; - - class ArgListEntry { - public: - Value *Val = nullptr; - SDValue Node = SDValue(); - Type *Ty = nullptr; - bool IsSExt : 1; - bool IsZExt : 1; - bool IsInReg : 1; - bool IsSRet : 1; - bool IsNest : 1; - bool IsByVal : 1; - bool IsInAlloca : 1; - bool IsReturned : 1; - bool IsSwiftSelf : 1; - bool IsSwiftError : 1; - uint16_t Alignment = 0; - - ArgListEntry() - : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), - IsNest(false), IsByVal(false), IsInAlloca(false), IsReturned(false), - IsSwiftSelf(false), IsSwiftError(false) {} - - void setAttributes(ImmutableCallSite *CS, unsigned ArgIdx); - }; - using ArgListTy = std::vector<ArgListEntry>; - - virtual void markLibCallAttributes(MachineFunction *MF, unsigned CC, - ArgListTy &Args) const {}; - static ISD::NodeType getExtendForContent(BooleanContent Content) { switch (Content) { case UndefinedBooleanContent: @@ -217,9 +156,7 @@ public: /// NOTE: The TargetMachine owns TLOF. explicit TargetLoweringBase(const TargetMachine &TM); - TargetLoweringBase(const TargetLoweringBase &) = delete; - TargetLoweringBase &operator=(const TargetLoweringBase &) = delete; - virtual ~TargetLoweringBase() = default; + virtual ~TargetLoweringBase() {} protected: /// \brief Initialize all of the actions to default values. @@ -237,18 +174,6 @@ public: return MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); } - /// Return the type for frame index, which is determined by - /// the alloca address space specified through the data layout. - MVT getFrameIndexTy(const DataLayout &DL) const { - return getPointerTy(DL, DL.getAllocaAddrSpace()); - } - - /// Return the type for operands of fence. - /// TODO: Let fence operands be of i32 type and remove this. - virtual MVT getFenceOperandTy(const DataLayout &DL) const { - return getPointerTy(DL); - } - /// EVT is not used in-tree, but is used by out-of-tree target. /// A documentation for this function would be nice... virtual MVT getScalarShiftAmountTy(const DataLayout &, EVT) const; @@ -262,6 +187,9 @@ public: return getPointerTy(DL); } + /// Return true if the select operation is expensive for this target. + bool isSelectExpensive() const { return SelectIsExpensive; } + virtual bool isSelectSupported(SelectSupportKind /*kind*/) const { return true; } @@ -303,49 +231,14 @@ public: /// several shifts, adds, and multiplies for this target. /// The definition of "cheaper" may depend on whether we're optimizing /// for speed or for size. - virtual bool isIntDivCheap(EVT VT, AttributeList Attr) const { return false; } - - /// Return true if the target can handle a standalone remainder operation. - virtual bool hasStandaloneRem(EVT VT) const { - return true; - } - - /// Return true if SQRT(X) shouldn't be replaced with X*RSQRT(X). - virtual bool isFsqrtCheap(SDValue X, SelectionDAG &DAG) const { - // Default behavior is to replace SQRT(X) with X*RSQRT(X). + virtual bool isIntDivCheap(EVT VT, AttributeSet Attr) const { return false; } - /// Reciprocal estimate status values used by the functions below. - enum ReciprocalEstimate : int { - Unspecified = -1, - Disabled = 0, - Enabled = 1 - }; - - /// Return a ReciprocalEstimate enum value for a square root of the given type - /// based on the function's attributes. If the operation is not overridden by - /// the function's attributes, "Unspecified" is returned and target defaults - /// are expected to be used for instruction selection. - int getRecipEstimateSqrtEnabled(EVT VT, MachineFunction &MF) const; - - /// Return a ReciprocalEstimate enum value for a division of the given type - /// based on the function's attributes. If the operation is not overridden by - /// the function's attributes, "Unspecified" is returned and target defaults - /// are expected to be used for instruction selection. - int getRecipEstimateDivEnabled(EVT VT, MachineFunction &MF) const; - - /// Return the refinement step count for a square root of the given type based - /// on the function's attributes. If the operation is not overridden by - /// the function's attributes, "Unspecified" is returned and target defaults - /// are expected to be used for instruction selection. - int getSqrtRefinementSteps(EVT VT, MachineFunction &MF) const; - - /// Return the refinement step count for a division of the given type based - /// on the function's attributes. If the operation is not overridden by - /// the function's attributes, "Unspecified" is returned and target defaults - /// are expected to be used for instruction selection. - int getDivRefinementSteps(EVT VT, MachineFunction &MF) const; + /// Return true if sqrt(x) is as cheap or cheaper than 1 / rsqrt(x) + bool isFsqrtCheap() const { + return FsqrtIsCheap; + } /// Returns true if target has indicated at least one type should be bypassed. bool isSlowDivBypassed() const { return !BypassSlowDivWidths.empty(); } @@ -366,41 +259,18 @@ public: return PredictableSelectIsExpensive; } - /// If a branch or a select condition is skewed in one direction by more than - /// this factor, it is very likely to be predicted correctly. - virtual BranchProbability getPredictableBranchThreshold() const; - - /// Return true if the following transform is beneficial: + /// isLoadBitCastBeneficial() - Return true if the following transform + /// is beneficial. /// fold (conv (load x)) -> (load (conv*)x) /// On architectures that don't natively support some vector loads /// efficiently, casting the load to a smaller vector of larger types and /// loading is more efficient, however, this can be undone by optimizations in /// dag combiner. - virtual bool isLoadBitCastBeneficial(EVT LoadVT, - EVT BitcastVT) const { - // Don't do if we could do an indexed load on the original type, but not on - // the new one. - if (!LoadVT.isSimple() || !BitcastVT.isSimple()) - return true; - - MVT LoadMVT = LoadVT.getSimpleVT(); - - // Don't bother doing this if it's just going to be promoted again later, as - // doing so might interfere with other combines. - if (getOperationAction(ISD::LOAD, LoadMVT) == Promote && - getTypeToPromoteTo(ISD::LOAD, LoadMVT) == BitcastVT.getSimpleVT()) - return false; - + virtual bool isLoadBitCastBeneficial(EVT /* Load */, + EVT /* Bitcast */) const { return true; } - /// Return true if the following transform is beneficial: - /// (store (y (conv x)), y*)) -> (store x, (x*)) - virtual bool isStoreBitCastBeneficial(EVT StoreVT, EVT BitcastVT) const { - // Default to the same logic as loads. - return isLoadBitCastBeneficial(StoreVT, BitcastVT); - } - /// Return true if it is expected to be cheaper to do a store of a non-zero /// vector constant with the given size and type for the address space than to /// store the individual scalar element constants. @@ -410,16 +280,6 @@ public: return false; } - /// Should we merge stores after Legalization (generally - /// better quality) or before (simpler) - virtual bool mergeStoresAfterLegalization() const { return false; } - - /// Returns if it's reasonable to merge stores to MemVT size. - virtual bool canMergeStoresTo(unsigned AS, EVT MemVT, - const SelectionDAG &DAG) const { - return true; - } - /// \brief Return true if it is cheap to speculate a call to intrinsic cttz. virtual bool isCheapToSpeculateCttz() const { return false; @@ -430,80 +290,19 @@ public: return false; } - /// \brief Return true if ctlz instruction is fast. - virtual bool isCtlzFast() const { - return false; - } - - /// Return true if it is safe to transform an integer-domain bitwise operation - /// into the equivalent floating-point operation. This should be set to true - /// if the target has IEEE-754-compliant fabs/fneg operations for the input - /// type. - virtual bool hasBitPreservingFPLogic(EVT VT) const { - return false; - } - - /// \brief Return true if it is cheaper to split the store of a merged int val - /// from a pair of smaller values into multiple stores. - virtual bool isMultiStoresCheaperThanBitsMerge(EVT LTy, EVT HTy) const { - return false; - } - /// \brief Return if the target supports combining a /// chain like: /// \code - /// %andResult = and %val1, #mask + /// %andResult = and %val1, #imm-with-one-bit-set; /// %icmpResult = icmp %andResult, 0 + /// br i1 %icmpResult, label %dest1, label %dest2 /// \endcode /// into a single machine instruction of a form like: /// \code - /// cc = test %register, #mask + /// brOnBitSet %register, #bitNumber, dest /// \endcode - virtual bool isMaskAndCmp0FoldingBeneficial(const Instruction &AndI) const { - return false; - } - - /// Use bitwise logic to make pairs of compares more efficient. For example: - /// and (seteq A, B), (seteq C, D) --> seteq (or (xor A, B), (xor C, D)), 0 - /// This should be true when it takes more than one instruction to lower - /// setcc (cmp+set on x86 scalar), when bitwise ops are faster than logic on - /// condition bits (crand on PowerPC), and/or when reducing cmp+br is a win. - virtual bool convertSetCCLogicToBitwiseLogic(EVT VT) const { - return false; - } - - /// Return the preferred operand type if the target has a quick way to compare - /// integer values of the given size. Assume that any legal integer type can - /// be compared efficiently. Targets may override this to allow illegal wide - /// types to return a vector type if there is support to compare that type. - virtual MVT hasFastEqualityCompare(unsigned NumBits) const { - MVT VT = MVT::getIntegerVT(NumBits); - return isTypeLegal(VT) ? VT : MVT::INVALID_SIMPLE_VALUE_TYPE; - } - - /// Return true if the target should transform: - /// (X & Y) == Y ---> (~X & Y) == 0 - /// (X & Y) != Y ---> (~X & Y) != 0 - /// - /// This may be profitable if the target has a bitwise and-not operation that - /// sets comparison flags. A target may want to limit the transformation based - /// on the type of Y or if Y is a constant. - /// - /// Note that the transform will not occur if Y is known to be a power-of-2 - /// because a mask and compare of a single bit can be handled by inverting the - /// predicate, for example: - /// (X & 8) == 8 ---> (X & 8) != 0 - virtual bool hasAndNotCompare(SDValue Y) const { - return false; - } - - /// Return true if the target has a bitwise and-not operation: - /// X = ~A & B - /// This can be used to simplify select or other instructions. - virtual bool hasAndNot(SDValue X) const { - // If the target has the more complex version of this operation, assume that - // it has this operation too. - return hasAndNotCompare(X); + bool isMaskAndBranchFoldingLegal() const { + return MaskAndBranchFoldingIsLegal; } /// \brief Return true if the target wants to use the optimization that @@ -688,29 +487,20 @@ public: unsigned &NumIntermediates, MVT &RegisterVT) const; - /// Certain targets such as MIPS require that some types such as vectors are - /// always broken down into scalars in some contexts. This occurs even if the - /// vector type is legal. - virtual unsigned getVectorTypeBreakdownForCallingConv( - LLVMContext &Context, EVT VT, EVT &IntermediateVT, - unsigned &NumIntermediates, MVT &RegisterVT) const { - return getVectorTypeBreakdown(Context, VT, IntermediateVT, NumIntermediates, - RegisterVT); - } - struct IntrinsicInfo { - unsigned opc = 0; // target opcode - EVT memVT; // memory VT - const Value* ptrVal = nullptr; // value representing memory location - int offset = 0; // offset off of ptrVal - unsigned size = 0; // the size of the memory location - // (taken from memVT if zero) - unsigned align = 1; // alignment - bool vol = false; // is volatile? - bool readMem = false; // reads memory? - bool writeMem = false; // writes memory? - - IntrinsicInfo() = default; + unsigned opc; // target opcode + EVT memVT; // memory VT + const Value* ptrVal; // value representing memory location + int offset; // offset off of ptrVal + unsigned size; // the size of the memory location + // (taken from memVT if zero) + unsigned align; // alignment + bool vol; // is volatile? + bool readMem; // reads memory? + bool writeMem; // writes memory? + + IntrinsicInfo() : opc(0), ptrVal(nullptr), offset(0), size(0), align(1), + vol(false), readMem(false), writeMem(false) {} }; /// Given an intrinsic, checks if on the target the intrinsic will need to map @@ -741,7 +531,7 @@ public: /// Returns true if the operation can trap for the value type. /// /// VT must be a legal type. By default, we optimistically assume most - /// operations don't trap except for integer divide and remainder. + /// operations don't trap except for divide and remainder. virtual bool canOpTrap(unsigned Op, EVT VT) const; /// Similar to isShuffleMaskLegal. This is used by Targets can use this to @@ -759,7 +549,7 @@ public: if (VT.isExtended()) return Expand; // If a target-specific SDNode requires legalization, require the target // to provide custom legalization for it. - if (Op >= array_lengthof(OpActions[0])) return Custom; + if (Op > array_lengthof(OpActions[0])) return Custom; return OpActions[(unsigned)VT.getSimpleVT().SimpleTy][Op]; } @@ -781,91 +571,6 @@ public: getOperationAction(Op, VT) == Promote); } - /// Return true if the specified operation is legal on this target or can be - /// made legal with custom lowering or using promotion. This is used to help - /// guide high-level lowering decisions. - bool isOperationLegalOrCustomOrPromote(unsigned Op, EVT VT) const { - return (VT == MVT::Other || isTypeLegal(VT)) && - (getOperationAction(Op, VT) == Legal || - getOperationAction(Op, VT) == Custom || - getOperationAction(Op, VT) == Promote); - } - - /// Return true if the specified operation is illegal but has a custom lowering - /// on that type. This is used to help guide high-level lowering - /// decisions. - bool isOperationCustom(unsigned Op, EVT VT) const { - return (!isTypeLegal(VT) && getOperationAction(Op, VT) == Custom); - } - - /// Return true if lowering to a jump table is allowed. - bool areJTsAllowed(const Function *Fn) const { - if (Fn->getFnAttribute("no-jump-tables").getValueAsString() == "true") - return false; - - return isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) || - isOperationLegalOrCustom(ISD::BRIND, MVT::Other); - } - - /// Check whether the range [Low,High] fits in a machine word. - bool rangeFitsInWord(const APInt &Low, const APInt &High, - const DataLayout &DL) const { - // FIXME: Using the pointer type doesn't seem ideal. - uint64_t BW = DL.getPointerSizeInBits(); - uint64_t Range = (High - Low).getLimitedValue(UINT64_MAX - 1) + 1; - return Range <= BW; - } - - /// Return true if lowering to a jump table is suitable for a set of case - /// clusters which may contain \p NumCases cases, \p Range range of values. - /// FIXME: This function check the maximum table size and density, but the - /// minimum size is not checked. It would be nice if the the minimum size is - /// also combined within this function. Currently, the minimum size check is - /// performed in findJumpTable() in SelectionDAGBuiler and - /// getEstimatedNumberOfCaseClusters() in BasicTTIImpl. - bool isSuitableForJumpTable(const SwitchInst *SI, uint64_t NumCases, - uint64_t Range) const { - const bool OptForSize = SI->getParent()->getParent()->optForSize(); - const unsigned MinDensity = getMinimumJumpTableDensity(OptForSize); - const unsigned MaxJumpTableSize = - OptForSize || getMaximumJumpTableSize() == 0 - ? UINT_MAX - : getMaximumJumpTableSize(); - // Check whether a range of clusters is dense enough for a jump table. - if (Range <= MaxJumpTableSize && - (NumCases * 100 >= Range * MinDensity)) { - return true; - } - return false; - } - - /// Return true if lowering to a bit test is suitable for a set of case - /// clusters which contains \p NumDests unique destinations, \p Low and - /// \p High as its lowest and highest case values, and expects \p NumCmps - /// case value comparisons. Check if the number of destinations, comparison - /// metric, and range are all suitable. - bool isSuitableForBitTests(unsigned NumDests, unsigned NumCmps, - const APInt &Low, const APInt &High, - const DataLayout &DL) const { - // FIXME: I don't think NumCmps is the correct metric: a single case and a - // range of cases both require only one branch to lower. Just looking at the - // number of clusters and destinations should be enough to decide whether to - // build bit tests. - - // To lower a range with bit tests, the range must fit the bitwidth of a - // machine word. - if (!rangeFitsInWord(Low, High, DL)) - return false; - - // Decide whether it's profitable to lower this range with bit tests. Each - // destination requires a bit test and branch, and there is an overall range - // check branch. For a small number of clusters, separate comparisons might - // be cheaper, and for many destinations, splitting the range might be - // better. - return (NumDests == 1 && NumCmps >= 3) || (NumDests == 2 && NumCmps >= 5) || - (NumDests == 3 && NumCmps >= 6); - } - /// Return true if the specified operation is illegal on this target or /// unlikely to be made legal with custom lowering. This is used to help guide /// high-level lowering decisions. @@ -889,20 +594,21 @@ public: unsigned MemI = (unsigned) MemVT.getSimpleVT().SimpleTy; assert(ExtType < ISD::LAST_LOADEXT_TYPE && ValI < MVT::LAST_VALUETYPE && MemI < MVT::LAST_VALUETYPE && "Table isn't big enough!"); - unsigned Shift = 4 * ExtType; - return (LegalizeAction)((LoadExtActions[ValI][MemI] >> Shift) & 0xf); + return LoadExtActions[ValI][MemI][ExtType]; } /// Return true if the specified load with extension is legal on this target. bool isLoadExtLegal(unsigned ExtType, EVT ValVT, EVT MemVT) const { - return getLoadExtAction(ExtType, ValVT, MemVT) == Legal; + return ValVT.isSimple() && MemVT.isSimple() && + getLoadExtAction(ExtType, ValVT, MemVT) == Legal; } /// Return true if the specified load with extension is legal or custom /// on this target. bool isLoadExtLegalOrCustom(unsigned ExtType, EVT ValVT, EVT MemVT) const { - return getLoadExtAction(ExtType, ValVT, MemVT) == Legal || - getLoadExtAction(ExtType, ValVT, MemVT) == Custom; + return ValVT.isSimple() && MemVT.isSimple() && + (getLoadExtAction(ExtType, ValVT, MemVT) == Legal || + getLoadExtAction(ExtType, ValVT, MemVT) == Custom); } /// Return how this store with truncation should be treated: either it is @@ -920,15 +626,8 @@ public: /// Return true if the specified store with truncation is legal on this /// target. bool isTruncStoreLegal(EVT ValVT, EVT MemVT) const { - return isTypeLegal(ValVT) && getTruncStoreAction(ValVT, MemVT) == Legal; - } - - /// Return true if the specified store with truncation has solution on this - /// target. - bool isTruncStoreLegalOrCustom(EVT ValVT, EVT MemVT) const { - return isTypeLegal(ValVT) && - (getTruncStoreAction(ValVT, MemVT) == Legal || - getTruncStoreAction(ValVT, MemVT) == Custom); + return isTypeLegal(ValVT) && MemVT.isSimple() && + getTruncStoreAction(ValVT.getSimpleVT(), MemVT.getSimpleVT()) == Legal; } /// Return how the indexed load should be treated: either it is legal, needs @@ -973,7 +672,7 @@ public: LegalizeAction getCondCodeAction(ISD::CondCode CC, MVT VT) const { assert((unsigned)CC < array_lengthof(CondCodeActions) && - ((unsigned)VT.SimpleTy >> 3) < array_lengthof(CondCodeActions[0]) && + ((unsigned)VT.SimpleTy >> 4) < array_lengthof(CondCodeActions[0]) && "Table isn't big enough!"); // See setCondCodeAction for how this is encoded. uint32_t Shift = 4 * (VT.SimpleTy & 0x7); @@ -990,6 +689,7 @@ public: getCondCodeAction(CC, VT) == Custom; } + /// If the action for this operation is to promote, this method returns the /// ValueType to promote to. MVT getTypeToPromoteTo(unsigned Op, MVT VT) const { @@ -1106,33 +806,6 @@ public: llvm_unreachable("Unsupported extended type!"); } - /// Certain combinations of ABIs, Targets and features require that types - /// are legal for some operations and not for other operations. - /// For MIPS all vector types must be passed through the integer register set. - virtual MVT getRegisterTypeForCallingConv(MVT VT) const { - return getRegisterType(VT); - } - - virtual MVT getRegisterTypeForCallingConv(LLVMContext &Context, - EVT VT) const { - return getRegisterType(Context, VT); - } - - /// Certain targets require unusual breakdowns of certain types. For MIPS, - /// this occurs when a vector type is used, as vector are passed through the - /// integer register set. - virtual unsigned getNumRegistersForCallingConv(LLVMContext &Context, - EVT VT) const { - return getNumRegisters(Context, VT); - } - - /// Certain targets have context senstive alignment requirements, where one - /// type has the alignment requirement of another type. - virtual unsigned getABIAlignmentForCallingConv(Type *ArgTy, - DataLayout DL) const { - return DL.getABITypeAlignment(ArgTy); - } - /// If true, then instruction selection should seek to shrink the FP constant /// of the specified type to a smaller type in order to save space and / or /// reduce runtime. @@ -1166,11 +839,6 @@ public: return GatherAllAliasesMaxDepth; } - /// Returns the size of the platform's va_list object. - virtual unsigned getVaListSizeInBits(const DataLayout &DL) const { - return getPointerTy(DL).getSizeInBits(); - } - /// \brief Get maximum # of store operations permitted for llvm.memset /// /// This function returns the maximum number of store operations permitted @@ -1191,16 +859,6 @@ public: return OptSize ? MaxStoresPerMemcpyOptSize : MaxStoresPerMemcpy; } - /// Get maximum # of load operations permitted for memcmp - /// - /// This function returns the maximum number of load operations permitted - /// to replace a call to memcmp. The value is set by the target at the - /// performance threshold for such a replacement. If OptSize is true, - /// return the limit for functions that have OptSize attribute. - unsigned getMaxExpandSizeMemcmp(bool OptSize) const { - return OptSize ? MaxLoadsPerMemcmpOptSize : MaxLoadsPerMemcmp; - } - /// \brief Get maximum # of store operations permitted for llvm.memmove /// /// This function returns the maximum number of store operations permitted @@ -1274,18 +932,10 @@ public: return UseUnderscoreLongJmp; } - /// Return lower limit for number of blocks in a jump table. - unsigned getMinimumJumpTableEntries() const; - - /// Return lower limit of the density in a jump table. - unsigned getMinimumJumpTableDensity(bool OptForSize) const; - - /// Return upper limit for number of entries in a jump table. - /// Zero if no limit. - unsigned getMaximumJumpTableSize() const; - - virtual bool isJumpTableRelative() const { - return TM.isPositionIndependent(); + /// Return integer threshold on number of blocks to use jump tables rather + /// than if sequence. + int getMinimumJumpTableEntries() const { + return MinimumJumpTableEntries; } /// If a physical register, this specifies the register that @@ -1310,10 +960,6 @@ public: return 0; } - virtual bool needsFixedCatchObjects() const { - report_fatal_error("Funclet EH is not implemented for this target"); - } - /// Returns the target's jmp_buf size in bytes (if never set, the default is /// 200) unsigned getJumpBufSize() const { @@ -1346,52 +992,29 @@ public: return PrefLoopAlignment; } - /// If the target has a standard location for the stack protector guard, - /// returns the address of that location. Otherwise, returns nullptr. - /// DEPRECATED: please override useLoadStackGuardNode and customize - /// LOAD_STACK_GUARD, or customize @llvm.stackguard(). - virtual Value *getIRStackGuard(IRBuilder<> &IRB) const; - - /// Inserts necessary declarations for SSP (stack protection) purpose. - /// Should be used only when getIRStackGuard returns nullptr. - virtual void insertSSPDeclarations(Module &M) const; - - /// Return the variable that's previously inserted by insertSSPDeclarations, - /// if any, otherwise return nullptr. Should be used only when - /// getIRStackGuard returns nullptr. - virtual Value *getSDagStackGuard(const Module &M) const; - - /// If the target has a standard stack protection check function that - /// performs validation and error handling, returns the function. Otherwise, - /// returns nullptr. Must be previously inserted by insertSSPDeclarations. - /// Should be used only when getIRStackGuard returns nullptr. - virtual Value *getSSPStackGuardCheck(const Module &M) const; + /// Return whether the DAG builder should automatically insert fences and + /// reduce ordering for atomics. + bool getInsertFencesForAtomic() const { + return InsertFencesForAtomic; + } -protected: - Value *getDefaultSafeStackPointerLocation(IRBuilder<> &IRB, - bool UseTLS) const; + /// Return true if the target stores stack protector cookies at a fixed offset + /// in some non-standard address space, and populates the address space and + /// offset as appropriate. + virtual bool getStackCookieLocation(unsigned &/*AddressSpace*/, + unsigned &/*Offset*/) const { + return false; + } -public: - /// Returns the target-specific address of the unsafe stack pointer. + /// If the target has a standard location for the unsafe stack pointer, + /// returns the address of that location. Otherwise, returns nullptr. virtual Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const; - /// Returns the name of the symbol used to emit stack probes or the empty - /// string if not applicable. - virtual StringRef getStackProbeSymbolName(MachineFunction &MF) const { - return ""; - } - /// Returns true if a cast between SrcAS and DestAS is a noop. virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { return false; } - /// Returns true if a cast from SrcAS to DestAS is "cheap", such that e.g. we - /// are happy to sink it into basic blocks. - virtual bool isCheapAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { - return isNoopAddrSpaceCast(SrcAS, DestAS); - } - /// Return true if the pointer arguments to CI should be aligned by aligning /// the object whose address is being passed. If so then MinSize is set to the /// minimum size the object must be to be aligned and PrefAlign is set to the @@ -1418,30 +1041,6 @@ public: /// \name Helpers for atomic expansion. /// @{ - /// Returns the maximum atomic operation size (in bits) supported by - /// the backend. Atomic operations greater than this size (as well - /// as ones that are not naturally aligned), will be expanded by - /// AtomicExpandPass into an __atomic_* library call. - unsigned getMaxAtomicSizeInBitsSupported() const { - return MaxAtomicSizeInBitsSupported; - } - - /// Returns the size of the smallest cmpxchg or ll/sc instruction - /// the backend supports. Any smaller operations are widened in - /// AtomicExpandPass. - /// - /// Note that *unlike* operations above the maximum size, atomic ops - /// are still natively supported below the minimum; they just - /// require a more complex expansion. - unsigned getMinCmpXchgSizeInBits() const { return MinCmpXchgSizeInBits; } - - /// Whether AtomicExpandPass should automatically insert fences and reduce - /// ordering for this atomic. This should be true for most architectures with - /// weak memory ordering. Defaults to false. - virtual bool shouldInsertFencesForAtomic(const Instruction *I) const { - return false; - } - /// Perform a load-linked operation on Addr, returning a "Value *" with the /// corresponding pointee type. This may entail some non-trivial operations to /// truncate or reconstruct types that will be illegal in the backend. See @@ -1460,15 +1059,12 @@ public: /// Inserts in the IR a target-specific intrinsic specifying a fence. /// It is called by AtomicExpandPass before expanding an - /// AtomicRMW/AtomicCmpXchg/AtomicStore/AtomicLoad - /// if shouldInsertFencesForAtomic returns true. - /// - /// Inst is the original atomic instruction, prior to other expansions that - /// may be performed. - /// + /// AtomicRMW/AtomicCmpXchg/AtomicStore/AtomicLoad. + /// RMW and CmpXchg set both IsStore and IsLoad to true. /// This function should either return a nullptr, or a pointer to an IR-level /// Instruction*. Even complex fence sequences can be represented by a /// single Instruction* through an intrinsic to be lowered later. + /// Backends with !getInsertFencesForAtomic() should keep a no-op here. /// Backends should override this method to produce target-specific intrinsic /// for their fences. /// FIXME: Please note that the default implementation here in terms of @@ -1491,18 +1087,25 @@ public: /// seq_cst. But if they are lowered to monotonic accesses, no amount of /// IR-level fences can prevent it. /// @{ - virtual Instruction *emitLeadingFence(IRBuilder<> &Builder, Instruction *Inst, - AtomicOrdering Ord) const { - if (isReleaseOrStronger(Ord) && Inst->hasAtomicStore()) + virtual Instruction *emitLeadingFence(IRBuilder<> &Builder, + AtomicOrdering Ord, bool IsStore, + bool IsLoad) const { + if (!getInsertFencesForAtomic()) + return nullptr; + + if (isAtLeastRelease(Ord) && IsStore) return Builder.CreateFence(Ord); else return nullptr; } virtual Instruction *emitTrailingFence(IRBuilder<> &Builder, - Instruction *Inst, - AtomicOrdering Ord) const { - if (isAcquireOrStronger(Ord)) + AtomicOrdering Ord, bool IsStore, + bool IsLoad) const { + if (!getInsertFencesForAtomic()) + return nullptr; + + if (isAtLeastAcquire(Ord)) return Builder.CreateFence(Ord); else return nullptr; @@ -1563,14 +1166,6 @@ public: return nullptr; } - /// Returns how the platform's atomic operations are extended (ZERO_EXTEND, - /// SIGN_EXTEND, or ANY_EXTEND). - virtual ISD::NodeType getExtendForAtomicOps() const { - return ISD::ZERO_EXTEND; - } - - /// @} - /// Returns true if we should normalize /// select(N0&N1, X, Y) => select(N0, select(N1, X, Y), Y) and /// select(N0|N1, X, Y) => select(N0, select(N1, X, Y, Y)) if it is likely @@ -1589,13 +1184,6 @@ public: Action != TypeSplitVector; } - /// Return true if a select of constants (select Cond, C1, C2) should be - /// transformed into simple math ops with the condition value. For example: - /// select Cond, C1, C1-1 --> add (zext Cond), C1-1 - virtual bool convertSelectOfConstantsToMath() const { - return false; - } - //===--------------------------------------------------------------------===// // TargetLowering Configuration Methods - These methods should be invoked by // the derived class constructor to configure this object for the target. @@ -1638,12 +1226,11 @@ protected: UseUnderscoreLongJmp = Val; } - /// Indicate the minimum number of blocks to generate jump tables. - void setMinimumJumpTableEntries(unsigned Val); - - /// Indicate the maximum number of entries in jump tables. - /// Set to zero to generate unlimited jump tables. - void setMaximumJumpTableSize(unsigned); + /// Indicate the number of blocks to generate jump tables rather than if + /// sequence. + void setMinimumJumpTableEntries(int Val) { + MinimumJumpTableEntries = Val; + } /// If set to a physical register, this specifies the register that /// llvm.savestack/llvm.restorestack should save and restore. @@ -1651,6 +1238,12 @@ protected: StackPointerRegisterToSaveRestore = R; } + /// Tells the code generator not to expand operations into sequences that use + /// the select operations if possible. + void setSelectIsExpensive(bool isExpensive = true) { + SelectIsExpensive = isExpensive; + } + /// Tells the code generator that the target has multiple (allocatable) /// condition registers that can be used to store the results of comparisons /// for use by selects and conditional branches. With multiple condition @@ -1673,6 +1266,10 @@ protected: /// control. void setJumpIsExpensive(bool isExpensive = true); + /// Tells the code generator that fsqrt is cheap, and should not be replaced + /// with an alternative sequence of instructions. + void setFsqrtIsCheap(bool isCheap = true) { FsqrtIsCheap = isCheap; } + /// Tells the code generator that this target supports floating point /// exceptions and cares about preserving floating point exception behavior. void setHasFloatingPointExceptions(bool FPExceptions = true) { @@ -1689,9 +1286,21 @@ protected: /// that class natively. void addRegisterClass(MVT VT, const TargetRegisterClass *RC) { assert((unsigned)VT.SimpleTy < array_lengthof(RegClassForVT)); + AvailableRegClasses.push_back(std::make_pair(VT, RC)); RegClassForVT[VT.SimpleTy] = RC; } + /// Remove all register classes. + void clearRegisterClasses() { + std::fill(std::begin(RegClassForVT), std::end(RegClassForVT), nullptr); + + AvailableRegClasses.clear(); + } + + /// \brief Remove all operation actions. + void clearOperationActions() { + } + /// Return the largest legal super-reg register class of the register class /// for the specified type and its associated "cost". virtual std::pair<const TargetRegisterClass *, uint8_t> @@ -1702,8 +1311,7 @@ protected: void computeRegisterProperties(const TargetRegisterInfo *TRI); /// Indicate that the specified operation does not work with the specified - /// type and indicate what to do about it. Note that VT may refer to either - /// the type of a result or that of an operand of Op. + /// type and indicate what to do about it. void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action) { assert(Op < array_lengthof(OpActions[0]) && "Table isn't big enough!"); @@ -1716,10 +1324,7 @@ protected: LegalizeAction Action) { assert(ExtType < ISD::LAST_LOADEXT_TYPE && ValVT.isValid() && MemVT.isValid() && "Table isn't big enough!"); - assert((unsigned)Action < 0x10 && "too many bits for bitfield array"); - unsigned Shift = 4 * ExtType; - LoadExtActions[ValVT.SimpleTy][MemVT.SimpleTy] &= ~((uint16_t)0xF << Shift); - LoadExtActions[ValVT.SimpleTy][MemVT.SimpleTy] |= (uint16_t)Action << Shift; + LoadExtActions[(unsigned)ValVT.SimpleTy][MemVT.SimpleTy][ExtType] = Action; } /// Indicate that the specified truncating store does not work with the @@ -1781,13 +1386,6 @@ protected: PromoteToType[std::make_pair(Opc, OrigVT.SimpleTy)] = DestVT.SimpleTy; } - /// Convenience method to set an operation to Promote and specify the type - /// in a single call. - void setOperationPromotedToType(unsigned Opc, MVT OrigVT, MVT DestVT) { - setOperationAction(Opc, OrigVT, Promote); - AddPromotedToType(Opc, OrigVT, DestVT); - } - /// Targets should invoke this method for each target independent node that /// they want to provide a custom DAG combiner for by implementing the /// PerformDAGCombine virtual method. @@ -1832,17 +1430,10 @@ protected: MinStackArgumentAlignment = Align; } - /// Set the maximum atomic operation size supported by the - /// backend. Atomic operations greater than this size (as well as - /// ones that are not naturally aligned), will be expanded by - /// AtomicExpandPass into an __atomic_* library call. - void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits) { - MaxAtomicSizeInBitsSupported = SizeInBits; - } - - // Sets the minimum cmpxchg or ll/sc size supported by the backend. - void setMinCmpXchgSizeInBits(unsigned SizeInBits) { - MinCmpXchgSizeInBits = SizeInBits; + /// Set if the DAG builder should automatically insert fences and reduce the + /// order of atomic memory operations to Monotonic. + void setInsertFencesForAtomic(bool fence) { + InsertFencesForAtomic = fence; } public: @@ -1855,9 +1446,10 @@ public: /// possible to be done in the address mode for that operand. This hook lets /// targets also pass back when this should be done on intrinsics which /// load/store. - virtual bool getAddrModeArguments(IntrinsicInst * /*I*/, + virtual bool GetAddrModeArguments(IntrinsicInst * /*I*/, SmallVectorImpl<Value*> &/*Ops*/, - Type *&/*AccessTy*/) const { + Type *&/*AccessTy*/, + unsigned AddrSpace = 0) const { return false; } @@ -1869,11 +1461,11 @@ public: /// If Scale is zero, there is no ScaleReg. Scale of 1 indicates a reg with /// no scale. struct AddrMode { - GlobalValue *BaseGV = nullptr; - int64_t BaseOffs = 0; - bool HasBaseReg = false; - int64_t Scale = 0; - AddrMode() = default; + GlobalValue *BaseGV; + int64_t BaseOffs; + bool HasBaseReg; + int64_t Scale; + AddrMode() : BaseGV(nullptr), BaseOffs(0), HasBaseReg(false), Scale(0) {} }; /// Return true if the addressing mode represented by AM is legal for this @@ -1904,10 +1496,6 @@ public: return -1; } - virtual bool isFoldableMemAccessOffset(Instruction *I, int64_t Offset) const { - return true; - } - /// Return true if the specified immediate is legal icmp immediate, that is /// the target has icmp instructions which can compare a register against the /// immediate without having to materialize the immediate into a register. @@ -1930,38 +1518,6 @@ public: return false; } - /// Returns true if the opcode is a commutative binary operation. - virtual bool isCommutativeBinOp(unsigned Opcode) const { - // FIXME: This should get its info from the td file. - switch (Opcode) { - case ISD::ADD: - case ISD::SMIN: - case ISD::SMAX: - case ISD::UMIN: - case ISD::UMAX: - case ISD::MUL: - case ISD::MULHU: - case ISD::MULHS: - case ISD::SMUL_LOHI: - case ISD::UMUL_LOHI: - case ISD::FADD: - case ISD::FMUL: - case ISD::AND: - case ISD::OR: - case ISD::XOR: - case ISD::SADDO: - case ISD::UADDO: - case ISD::ADDC: - case ISD::ADDE: - case ISD::FMINNUM: - case ISD::FMAXNUM: - case ISD::FMINNAN: - case ISD::FMAXNAN: - return true; - default: return false; - } - } - /// Return true if it's free to truncate a value of type FromTy to type /// ToTy. e.g. On x86 it's free to truncate a i32 value in register EAX to i16 /// by referencing its sub-register AX. @@ -2012,35 +1568,6 @@ public: return isExtFreeImpl(I); } - /// Return true if \p Load and \p Ext can form an ExtLoad. - /// For example, in AArch64 - /// %L = load i8, i8* %ptr - /// %E = zext i8 %L to i32 - /// can be lowered into one load instruction - /// ldrb w0, [x0] - bool isExtLoad(const LoadInst *Load, const Instruction *Ext, - const DataLayout &DL) const { - EVT VT = getValueType(DL, Ext->getType()); - EVT LoadVT = getValueType(DL, Load->getType()); - - // If the load has other users and the truncate is not free, the ext - // probably isn't free. - if (!Load->hasOneUse() && (isTypeLegal(LoadVT) || !isTypeLegal(VT)) && - !isTruncateFree(Ext->getType(), Load->getType())) - return false; - - // Check whether the target supports casts folded into loads. - unsigned LType; - if (isa<ZExtInst>(Ext)) - LType = ISD::ZEXTLOAD; - else { - assert(isa<SExtInst>(Ext) && "Unexpected ext type!"); - LType = ISD::SEXTLOAD; - } - - return isLoadExtLegal(LType, VT, LoadVT); - } - /// Return true if any actual instruction that defines a value of type FromTy /// implicitly zero-extends the value to ToTy in the result register. /// @@ -2080,8 +1607,13 @@ public: /// In other words, unless the target performs a post-isel load combining, /// this information should not be provided because it will generate more /// loads. + virtual bool hasPairedLoad(Type * /*LoadedType*/, + unsigned & /*RequiredAligment*/) const { + return false; + } + virtual bool hasPairedLoad(EVT /*LoadedType*/, - unsigned & /*RequiredAlignment*/) const { + unsigned & /*RequiredAligment*/) const { return false; } @@ -2226,15 +1758,13 @@ public: return LibcallCallingConvs[Call]; } - /// Execute target specific actions to finalize target lowering. - /// This is used to set extra flags in MachineFrameInformation and freezing - /// the set of reserved registers. - /// The default implementation just freezes the set of reserved registers. - virtual void finalizeLowering(MachineFunction &MF) const; - private: const TargetMachine &TM; + /// Tells the code generator not to expand operations into sequences that use + /// the select operations if possible. + bool SelectIsExpensive; + /// Tells the code generator that the target has multiple (allocatable) /// condition registers that can be used to store the results of comparisons /// for use by selects and conditional branches. With multiple condition @@ -2248,6 +1778,9 @@ private: /// combined with "shift" to BitExtract instructions. bool HasExtractBitsInsn; + // Don't expand fsqrt with an approximation based on the inverse sqrt. + bool FsqrtIsCheap; + /// Tells the code generator to bypass slow divide or remainder /// instructions. For example, BypassSlowDivWidths[32,8] tells the code /// generator to bypass 32-bit integer div/rem with an 8-bit unsigned integer @@ -2273,6 +1806,9 @@ private: /// Defaults to false. bool UseUnderscoreLongJmp; + /// Number of blocks threshold to use jump tables. + int MinimumJumpTableEntries; + /// Information about the contents of the high-bits in boolean values held in /// a type wider than i1. See getBooleanContents. BooleanContent BooleanContents; @@ -2309,13 +1845,10 @@ private: /// The preferred loop alignment. unsigned PrefLoopAlignment; - /// Size in bits of the maximum atomics size the backend supports. - /// Accesses larger than this will be expanded by AtomicExpandPass. - unsigned MaxAtomicSizeInBitsSupported; - - /// Size in bits of the minimum cmpxchg or ll/sc operation the - /// backend supports. - unsigned MinCmpXchgSizeInBits; + /// Whether the DAG builder should automatically insert fences and reduce + /// ordering for atomics. (This will be set for for most architectures with + /// weak memory ordering.) + bool InsertFencesForAtomic; /// If set to a physical register, this specifies the register that /// llvm.savestack/llvm.restorestack should save and restore. @@ -2356,9 +1889,9 @@ private: /// For each load extension type and each value type, keep a LegalizeAction /// that indicates how instruction selection should deal with a load of a - /// specific value type and extension type. Uses 4-bits to store the action - /// for each of the 4 load ext types. - uint16_t LoadExtActions[MVT::LAST_VALUETYPE][MVT::LAST_VALUETYPE]; + /// specific value type and extension type. + LegalizeAction LoadExtActions[MVT::LAST_VALUETYPE][MVT::LAST_VALUETYPE] + [ISD::LAST_LOADEXT_TYPE]; /// For each value type pair keep a LegalizeAction that indicates whether a /// truncating store of a specific value type and truncating type is legal. @@ -2386,6 +1919,9 @@ protected: private: LegalizeKind getTypeConversion(LLVMContext &Context, EVT VT) const; +private: + std::vector<std::pair<MVT, const TargetRegisterClass*> > AvailableRegClasses; + /// Targets can specify ISD nodes that they would like PerformDAGCombine /// callbacks for by calling setTargetDAGCombine(), which sets a bit in this /// array. @@ -2418,7 +1954,7 @@ protected: virtual bool isExtFreeImpl(const Instruction *I) const { return false; } /// Depth that GatherAllAliases should should continue looking for chain - /// dependencies when trying to find a more preferable chain. As an + /// dependencies when trying to find a more preferrable chain. As an /// approximation, this should be more than the number of consecutive stores /// expected to be merged. unsigned GatherAllAliasesMaxDepth; @@ -2455,8 +1991,6 @@ protected: /// Maximum number of store operations that may be substituted for a call to /// memcpy, used for functions with OptSize attribute. unsigned MaxStoresPerMemcpyOptSize; - unsigned MaxLoadsPerMemcmp; - unsigned MaxLoadsPerMemcmpOptSize; /// \brief Specify maximum bytes of store instructions per memmove call. /// @@ -2478,17 +2012,21 @@ protected: /// the branch is usually predicted right. bool PredictableSelectIsExpensive; + /// MaskAndBranchFoldingIsLegal - Indicates if the target supports folding + /// a mask of a single bit, a compare, and a branch into a single instruction. + bool MaskAndBranchFoldingIsLegal; + /// \see enableExtLdPromotion. bool EnableExtLdPromotion; +protected: /// Return true if the value types that can be represented by the specified /// register class are all legal. - bool isLegalRC(const TargetRegisterInfo &TRI, - const TargetRegisterClass &RC) const; + bool isLegalRC(const TargetRegisterClass *RC) const; /// Replace/modify any TargetFrameIndex operands with a targte-dependent /// sequence of memory operands that is recognized by PrologEpilogInserter. - MachineBasicBlock *emitPatchPoint(MachineInstr &MI, + MachineBasicBlock *emitPatchPoint(MachineInstr *MI, MachineBasicBlock *MBB) const; }; @@ -2498,17 +2036,13 @@ protected: /// This class also defines callbacks that targets must implement to lower /// target-specific constructs to SelectionDAG operators. class TargetLowering : public TargetLoweringBase { -public: - struct DAGCombinerInfo; - - TargetLowering(const TargetLowering &) = delete; - TargetLowering &operator=(const TargetLowering &) = delete; + TargetLowering(const TargetLowering&) = delete; + void operator=(const TargetLowering&) = delete; +public: /// NOTE: The TargetMachine owns TLOF. explicit TargetLowering(const TargetMachine &TM); - bool isPositionIndependent() const; - /// Returns true by value, base pointer and offset pointer and addressing mode /// by reference if the node's address can be legally represented as /// pre-indexed load / store address. @@ -2558,26 +2092,18 @@ public: bool isInTailCallPosition(SelectionDAG &DAG, SDNode *Node, SDValue &Chain) const; - void softenSetCCOperands(SelectionDAG &DAG, EVT VT, SDValue &NewLHS, - SDValue &NewRHS, ISD::CondCode &CCCode, - const SDLoc &DL) const; + void softenSetCCOperands(SelectionDAG &DAG, EVT VT, + SDValue &NewLHS, SDValue &NewRHS, + ISD::CondCode &CCCode, SDLoc DL) const; /// Returns a pair of (return value, chain). /// It is an error to pass RTLIB::UNKNOWN_LIBCALL as \p LC. std::pair<SDValue, SDValue> makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef<SDValue> Ops, - bool isSigned, const SDLoc &dl, + bool isSigned, SDLoc dl, bool doesNotReturn = false, bool isReturnValueUsed = true) const; - /// Check whether parameters to a call that are passed in callee saved - /// registers are the same as from the calling function. This needs to be - /// checked for tail call eligibility. - bool parametersInCSRMatch(const MachineRegisterInfo &MRI, - const uint32_t *CallerPreservedMask, - const SmallVectorImpl<CCValAssign> &ArgLocs, - const SmallVectorImpl<SDValue> &OutVals) const; - //===--------------------------------------------------------------------===// // TargetLowering Optimization Methods // @@ -2604,38 +2130,19 @@ public: New = N; return true; } - }; - - /// Check to see if the specified operand of the specified instruction is a - /// constant integer. If so, check to see if there are any bits set in the - /// constant that are not demanded. If so, shrink the constant and return - /// true. - bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded, - TargetLoweringOpt &TLO) const; - - // Target hook to do target-specific const optimization, which is called by - // ShrinkDemandedConstant. This function should return true if the target - // doesn't want ShrinkDemandedConstant to further optimize the constant. - virtual bool targetShrinkDemandedConstant(SDValue Op, const APInt &Demanded, - TargetLoweringOpt &TLO) const { - return false; - } - /// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This - /// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be - /// generalized for targets with other types of implicit widening casts. - bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded, - TargetLoweringOpt &TLO) const; - - /// Helper for SimplifyDemandedBits that can simplify an operation with - /// multiple uses. This function simplifies operand \p OpIdx of \p User and - /// then updates \p User with the simplified version. No other uses of - /// \p OpIdx are updated. If \p User is the only user of \p OpIdx, this - /// function behaves exactly like function SimplifyDemandedBits declared - /// below except that it also updates the DAG by calling - /// DCI.CommitTargetLoweringOpt. - bool SimplifyDemandedBits(SDNode *User, unsigned OpIdx, const APInt &Demanded, - DAGCombinerInfo &DCI, TargetLoweringOpt &TLO) const; + /// Check to see if the specified operand of the specified instruction is a + /// constant integer. If so, check to see if there are any bits set in the + /// constant that are not demanded. If so, shrink the constant and return + /// true. + bool ShrinkDemandedConstant(SDValue Op, const APInt &Demanded); + + /// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. This + /// uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be + /// generalized for targets with other types of implicit widening casts. + bool ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded, + SDLoc dl); + }; /// Look at Op. At this point, we know that only the DemandedMask bits of the /// result of Op are ever used downstream. If we can use this information to @@ -2644,38 +2151,21 @@ public: /// expression and return a mask of KnownOne and KnownZero bits for the /// expression (used to simplify the caller). The KnownZero/One bits may only /// be accurate for those bits in the DemandedMask. - /// \p AssumeSingleUse When this parameter is true, this function will - /// attempt to simplify \p Op even if there are multiple uses. - /// Callers are responsible for correctly updating the DAG based on the - /// results of this function, because simply replacing replacing TLO.Old - /// with TLO.New will be incorrect when this parameter is true and TLO.Old - /// has multiple uses. bool SimplifyDemandedBits(SDValue Op, const APInt &DemandedMask, - KnownBits &Known, - TargetLoweringOpt &TLO, - unsigned Depth = 0, - bool AssumeSingleUse = false) const; - - /// Helper wrapper around SimplifyDemandedBits - bool SimplifyDemandedBits(SDValue Op, APInt &DemandedMask, - DAGCombinerInfo &DCI) const; + APInt &KnownZero, APInt &KnownOne, + TargetLoweringOpt &TLO, unsigned Depth = 0) const; /// Determine which of the bits specified in Mask are known to be either zero - /// or one and return them in the KnownZero/KnownOne bitsets. The DemandedElts - /// argument allows us to only collect the known bits that are shared by the - /// requested vector elements. + /// or one and return them in the KnownZero/KnownOne bitsets. virtual void computeKnownBitsForTargetNode(const SDValue Op, - KnownBits &Known, - const APInt &DemandedElts, + APInt &KnownZero, + APInt &KnownOne, const SelectionDAG &DAG, unsigned Depth = 0) const; /// This method can be implemented by targets that want to expose additional - /// information about sign bits to the DAG Combiner. The DemandedElts - /// argument allows us to only collect the minimum sign bits that are shared - /// by the requested vector elements. + /// information about sign bits to the DAG Combiner. virtual unsigned ComputeNumSignBitsForTargetNode(SDValue Op, - const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth = 0) const; @@ -2683,7 +2173,6 @@ public: void *DC; // The DAG Combiner object. CombineLevel Level; bool CalledByLegalizer; - public: SelectionDAG &DAG; @@ -2699,6 +2188,7 @@ public: bool isCalledByLegalizer() const { return CalledByLegalizer; } void AddToWorklist(SDNode *N); + void RemoveFromWorklist(SDNode *N); SDValue CombineTo(SDNode *N, ArrayRef<SDValue> To, bool AddTo = true); SDValue CombineTo(SDNode *N, SDValue Res, bool AddTo = true); SDValue CombineTo(SDNode *N, SDValue Res0, SDValue Res1, bool AddTo = true); @@ -2714,18 +2204,11 @@ public: /// from getBooleanContents(). bool isConstFalseVal(const SDNode *N) const; - /// Return a constant of type VT that contains a true value that respects - /// getBooleanContents() - SDValue getConstTrueVal(SelectionDAG &DAG, EVT VT, const SDLoc &DL) const; - - /// Return if \p N is a True value when extended to \p VT. - bool isExtendedTrueVal(const ConstantSDNode *N, EVT VT, bool Signed) const; - /// Try to simplify a setcc built with the specified operands and cc. If it is /// unable to simplify it, return a null SDValue. - SDValue SimplifySetCC(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond, - bool foldBooleans, DAGCombinerInfo &DCI, - const SDLoc &dl) const; + SDValue SimplifySetCC(EVT VT, SDValue N0, SDValue N1, + ISD::CondCode Cond, bool foldBooleans, + DAGCombinerInfo &DCI, SDLoc dl) const; /// Returns true (and the GlobalValue and the offset) if the node is a /// GlobalAddress + offset. @@ -2752,22 +2235,10 @@ public: // This transformation may not be desirable if it disrupts a particularly // auspicious target-specific tree (e.g. bitfield extraction in AArch64). // By default, it returns true. - virtual bool isDesirableToCommuteWithShift(const SDNode *N) const { + virtual bool isDesirableToCommuteWithShift(const SDNode *N /*Op*/) const { return true; } - // Return true if it is profitable to combine a BUILD_VECTOR to a TRUNCATE. - // Example of such a combine: - // v4i32 build_vector((extract_elt V, 0), - // (extract_elt V, 2), - // (extract_elt V, 4), - // (extract_elt V, 6)) - // --> - // v4i32 truncate (bitcast V to v4i64) - virtual bool isDesirableToCombineBuildVectorToTruncate() const { - return false; - } - /// Return true if the target has native support for the specified value type /// and it is 'desirable' to use the type for the given node type. e.g. On x86 /// i16 is legal, but undesirable since i16 instruction encodings are longer @@ -2792,18 +2263,18 @@ public: return false; } - /// Return true if the target supports swifterror attribute. It optimizes - /// loads and stores to reading and writing a specific register. - virtual bool supportSwiftError() const { - return false; - } - /// Return true if the target supports that a subset of CSRs for the given /// machine function is handled explicitly via copies. virtual bool supportSplitCSR(MachineFunction *MF) const { return false; } + /// Return true if the MachineFunction contains a COPY which would imply + /// HasCopyImplyingStackAdjustment. + virtual bool hasCopyImplyingStackAdjustment(MachineFunction *MF) const { + return false; + } + /// Perform necessary initialization to handle a subset of CSRs explicitly /// via copies. This function is called at the beginning of instruction /// selection. @@ -2830,54 +2301,74 @@ public: /// described by the Ins array, into the specified DAG. The implementation /// should fill in the InVals array with legal-type argument values, and /// return the resulting token chain value. - virtual SDValue LowerFormalArguments( - SDValue /*Chain*/, CallingConv::ID /*CallConv*/, bool /*isVarArg*/, - const SmallVectorImpl<ISD::InputArg> & /*Ins*/, const SDLoc & /*dl*/, - SelectionDAG & /*DAG*/, SmallVectorImpl<SDValue> & /*InVals*/) const { + /// + virtual SDValue + LowerFormalArguments(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, + bool /*isVarArg*/, + const SmallVectorImpl<ISD::InputArg> &/*Ins*/, + SDLoc /*dl*/, SelectionDAG &/*DAG*/, + SmallVectorImpl<SDValue> &/*InVals*/) const { llvm_unreachable("Not Implemented"); } + struct ArgListEntry { + SDValue Node; + Type* Ty; + bool isSExt : 1; + bool isZExt : 1; + bool isInReg : 1; + bool isSRet : 1; + bool isNest : 1; + bool isByVal : 1; + bool isInAlloca : 1; + bool isReturned : 1; + uint16_t Alignment; + + ArgListEntry() : isSExt(false), isZExt(false), isInReg(false), + isSRet(false), isNest(false), isByVal(false), isInAlloca(false), + isReturned(false), Alignment(0) { } + + void setAttributes(ImmutableCallSite *CS, unsigned AttrIdx); + }; + typedef std::vector<ArgListEntry> ArgListTy; + /// This structure contains all information that is necessary for lowering /// calls. It is passed to TLI::LowerCallTo when the SelectionDAG builder /// needs to lower a call, and targets will see this struct in their LowerCall /// implementation. struct CallLoweringInfo { SDValue Chain; - Type *RetTy = nullptr; + Type *RetTy; bool RetSExt : 1; bool RetZExt : 1; bool IsVarArg : 1; bool IsInReg : 1; bool DoesNotReturn : 1; bool IsReturnValueUsed : 1; - bool IsConvergent : 1; - bool IsPatchPoint : 1; // IsTailCall should be modified by implementations of // TargetLowering::LowerCall that perform tail call conversions. - bool IsTailCall = false; - - // Is Call lowering done post SelectionDAG type legalization. - bool IsPostTypeLegalization = false; + bool IsTailCall; - unsigned NumFixedArgs = -1; - CallingConv::ID CallConv = CallingConv::C; + unsigned NumFixedArgs; + CallingConv::ID CallConv; SDValue Callee; ArgListTy Args; SelectionDAG &DAG; SDLoc DL; - ImmutableCallSite *CS = nullptr; + ImmutableCallSite *CS; + bool IsPatchPoint; SmallVector<ISD::OutputArg, 32> Outs; SmallVector<SDValue, 32> OutVals; SmallVector<ISD::InputArg, 32> Ins; - SmallVector<SDValue, 4> InVals; CallLoweringInfo(SelectionDAG &DAG) - : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false), - DoesNotReturn(false), IsReturnValueUsed(true), IsConvergent(false), - IsPatchPoint(false), DAG(DAG) {} + : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false), + IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), + IsTailCall(false), NumFixedArgs(-1), CallConv(CallingConv::C), + DAG(DAG), CS(nullptr), IsPatchPoint(false) {} - CallLoweringInfo &setDebugLoc(const SDLoc &dl) { + CallLoweringInfo &setDebugLoc(SDLoc dl) { DL = dl; return *this; } @@ -2887,26 +2378,14 @@ public: return *this; } - // setCallee with target/module-specific attributes - CallLoweringInfo &setLibCallee(CallingConv::ID CC, Type *ResultType, - SDValue Target, ArgListTy &&ArgsList) { - RetTy = ResultType; - Callee = Target; - CallConv = CC; - NumFixedArgs = Args.size(); - Args = std::move(ArgsList); - - DAG.getTargetLoweringInfo().markLibCallAttributes( - &(DAG.getMachineFunction()), CC, Args); - return *this; - } - CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultType, - SDValue Target, ArgListTy &&ArgsList) { + SDValue Target, ArgListTy &&ArgsList, + unsigned FixedArgs = -1) { RetTy = ResultType; Callee = Target; CallConv = CC; - NumFixedArgs = Args.size(); + NumFixedArgs = + (FixedArgs == static_cast<unsigned>(-1) ? Args.size() : FixedArgs); Args = std::move(ArgsList); return *this; } @@ -2916,15 +2395,12 @@ public: ImmutableCallSite &Call) { RetTy = ResultType; - IsInReg = Call.hasRetAttr(Attribute::InReg); - DoesNotReturn = - Call.doesNotReturn() || - (!Call.isInvoke() && - isa<UnreachableInst>(Call.getInstruction()->getNextNode())); + IsInReg = Call.paramHasAttr(0, Attribute::InReg); + DoesNotReturn = Call.doesNotReturn(); IsVarArg = FTy->isVarArg(); IsReturnValueUsed = !Call.getInstruction()->use_empty(); - RetSExt = Call.hasRetAttr(Attribute::SExt); - RetZExt = Call.hasRetAttr(Attribute::ZExt); + RetSExt = Call.paramHasAttr(0, Attribute::SExt); + RetZExt = Call.paramHasAttr(0, Attribute::ZExt); Callee = Target; @@ -2962,11 +2438,6 @@ public: return *this; } - CallLoweringInfo &setConvergent(bool Value = true) { - IsConvergent = Value; - return *this; - } - CallLoweringInfo &setSExtResult(bool Value = true) { RetSExt = Value; return *this; @@ -2982,14 +2453,10 @@ public: return *this; } - CallLoweringInfo &setIsPostTypeLegalization(bool Value=true) { - IsPostTypeLegalization = Value; - return *this; - } - ArgListTy &getArgs() { return Args; } + }; /// This function lowers an abstract call to a function into an actual call. @@ -3027,12 +2494,12 @@ public: /// This hook must be implemented to lower outgoing return values, described /// by the Outs array, into the specified DAG. The implementation should /// return the resulting token chain value. - virtual SDValue LowerReturn(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, - bool /*isVarArg*/, - const SmallVectorImpl<ISD::OutputArg> & /*Outs*/, - const SmallVectorImpl<SDValue> & /*OutVals*/, - const SDLoc & /*dl*/, - SelectionDAG & /*DAG*/) const { + virtual SDValue + LowerReturn(SDValue /*Chain*/, CallingConv::ID /*CallConv*/, + bool /*isVarArg*/, + const SmallVectorImpl<ISD::OutputArg> &/*Outs*/, + const SmallVectorImpl<SDValue> &/*OutVals*/, + SDLoc /*dl*/, SelectionDAG &/*DAG*/) const { llvm_unreachable("Not Implemented"); } @@ -3048,7 +2515,7 @@ public: /// Return true if the target may be able emit the call instruction as a tail /// call. This is used by optimization passes to determine if it's profitable /// to duplicate return instructions to enable tailcall optimization. - virtual bool mayBeEmittedAsTailCall(const CallInst *) const { + virtual bool mayBeEmittedAsTailCall(CallInst *) const { return false; } @@ -3067,12 +2534,12 @@ public: } /// Return the type that should be used to zero or sign extend a - /// zeroext/signext integer return value. FIXME: Some C calling conventions - /// require the return type to be promoted, but this is not true all the time, - /// e.g. i1/i8/i16 on x86/x86_64. It is also not necessary for non-C calling - /// conventions. The frontend should handle this and include all of the - /// necessary information. - virtual EVT getTypeForExtReturn(LLVMContext &Context, EVT VT, + /// zeroext/signext integer argument or return value. FIXME: Most C calling + /// convention requires the return type to be promoted, but this is not true + /// all the time, e.g. i1 on x86-64. It is also not necessary for non-C + /// calling conventions. The frontend should handle this and include all of + /// the necessary information. + virtual EVT getTypeForExtArgOrReturn(LLVMContext &Context, EVT VT, ISD::NodeType /*ExtendKind*/) const { EVT MinVT = getRegisterType(Context, MVT::i32); return VT.bitsLT(MinVT) ? MinVT : VT; @@ -3100,18 +2567,11 @@ public: /// which allows a CPU to reuse the result of a previous load indefinitely, /// even if a cache-coherent store is performed by another CPU. The default /// implementation does nothing. - virtual SDValue prepareVolatileOrAtomicLoad(SDValue Chain, const SDLoc &DL, + virtual SDValue prepareVolatileOrAtomicLoad(SDValue Chain, SDLoc DL, SelectionDAG &DAG) const { return Chain; } - /// This callback is used to inspect load/store instructions and add - /// target-specific MachineMemOperand flags to them. The default - /// implementation does nothing. - virtual MachineMemOperand::Flags getMMOFlags(const Instruction &I) const { - return MachineMemOperand::MONone; - } - /// This callback is invoked by the type legalizer to legalize nodes with an /// illegal operand type but legal result types. It replaces the /// LowerOperation callback in the type Legalizer. The reason we can not do @@ -3161,6 +2621,7 @@ public: return nullptr; } + bool verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const; @@ -3209,19 +2670,15 @@ public: /// Information about the constraint code, e.g. Register, RegisterClass, /// Memory, Other, Unknown. - TargetLowering::ConstraintType ConstraintType = TargetLowering::C_Unknown; + TargetLowering::ConstraintType ConstraintType; /// If this is the result output operand or a clobber, this is null, /// otherwise it is the incoming operand to the CallInst. This gets /// modified as the asm is processed. - Value *CallOperandVal = nullptr; + Value *CallOperandVal; /// The ValueType for the operand value. - MVT ConstraintVT = MVT::Other; - - /// Copy constructor for copying from a ConstraintInfo. - AsmOperandInfo(InlineAsm::ConstraintInfo Info) - : InlineAsm::ConstraintInfo(std::move(Info)) {} + MVT ConstraintVT; /// Return true of this is an input operand that is a matching constraint /// like "4". @@ -3230,9 +2687,15 @@ public: /// If this is an input matching constraint, this method returns the output /// operand it matches. unsigned getMatchedOperand() const; + + /// Copy constructor for copying from a ConstraintInfo. + AsmOperandInfo(InlineAsm::ConstraintInfo Info) + : InlineAsm::ConstraintInfo(std::move(Info)), + ConstraintType(TargetLowering::C_Unknown), CallOperandVal(nullptr), + ConstraintVT(MVT::Other) {} }; - using AsmOperandInfoVector = std::vector<AsmOperandInfo>; + typedef std::vector<AsmOperandInfo> AsmOperandInfoVector; /// Split up the constraint string from the inline assembly value into the /// specific constraints and their prefixes, and also tie in the associated @@ -3324,39 +2787,32 @@ public: /// Hooks for building estimates in place of slower divisions and square /// roots. - /// Return either a square root or its reciprocal estimate value for the input - /// operand. - /// \p Enabled is a ReciprocalEstimate enum with value either 'Unspecified' or - /// 'Enabled' as set by a potential default override attribute. - /// If \p RefinementSteps is 'Unspecified', the number of Newton-Raphson - /// refinement iterations required to generate a sufficient (though not - /// necessarily IEEE-754 compliant) estimate is returned in that parameter. + /// Return a reciprocal square root estimate value for the input operand. + /// The RefinementSteps output is the number of Newton-Raphson refinement + /// iterations required to generate a sufficient (though not necessarily + /// IEEE-754 compliant) estimate for the value type. /// The boolean UseOneConstNR output is used to select a Newton-Raphson - /// algorithm implementation that uses either one or two constants. - /// The boolean Reciprocal is used to select whether the estimate is for the - /// square root of the input operand or the reciprocal of its square root. + /// algorithm implementation that uses one constant or two constants. /// A target may choose to implement its own refinement within this function. /// If that's true, then return '0' as the number of RefinementSteps to avoid /// any further refinement of the estimate. /// An empty SDValue return means no estimate sequence can be created. - virtual SDValue getSqrtEstimate(SDValue Operand, SelectionDAG &DAG, - int Enabled, int &RefinementSteps, - bool &UseOneConstNR, bool Reciprocal) const { + virtual SDValue getRsqrtEstimate(SDValue Operand, DAGCombinerInfo &DCI, + unsigned &RefinementSteps, + bool &UseOneConstNR) const { return SDValue(); } /// Return a reciprocal estimate value for the input operand. - /// \p Enabled is a ReciprocalEstimate enum with value either 'Unspecified' or - /// 'Enabled' as set by a potential default override attribute. - /// If \p RefinementSteps is 'Unspecified', the number of Newton-Raphson - /// refinement iterations required to generate a sufficient (though not - /// necessarily IEEE-754 compliant) estimate is returned in that parameter. + /// The RefinementSteps output is the number of Newton-Raphson refinement + /// iterations required to generate a sufficient (though not necessarily + /// IEEE-754 compliant) estimate for the value type. /// A target may choose to implement its own refinement within this function. /// If that's true, then return '0' as the number of RefinementSteps to avoid /// any further refinement of the estimate. /// An empty SDValue return means no estimate sequence can be created. - virtual SDValue getRecipEstimate(SDValue Operand, SelectionDAG &DAG, - int Enabled, int &RefinementSteps) const { + virtual SDValue getRecipEstimate(SDValue Operand, DAGCombinerInfo &DCI, + unsigned &RefinementSteps) const { return SDValue(); } @@ -3364,22 +2820,6 @@ public: // Legalization utility functions // - /// Expand a MUL or [US]MUL_LOHI of n-bit values into two or four nodes, - /// respectively, each computing an n/2-bit part of the result. - /// \param Result A vector that will be filled with the parts of the result - /// in little-endian order. - /// \param LL Low bits of the LHS of the MUL. You can use this parameter - /// if you want to control how low bits are extracted from the LHS. - /// \param LH High bits of the LHS of the MUL. See LL for meaning. - /// \param RL Low bits of the RHS of the MUL. See LL for meaning - /// \param RH High bits of the RHS of the MUL. See LL for meaning. - /// \returns true if the node has been expanded, false if it has not - bool expandMUL_LOHI(unsigned Opcode, EVT VT, SDLoc dl, SDValue LHS, - SDValue RHS, SmallVectorImpl<SDValue> &Result, EVT HiLoVT, - SelectionDAG &DAG, MulExpansionKind Kind, - SDValue LL = SDValue(), SDValue LH = SDValue(), - SDValue RL = SDValue(), SDValue RH = SDValue()) const; - /// Expand a MUL into two nodes. One that computes the high bits of /// the result and one that computes the low bits. /// \param HiLoVT The value type to use for the Lo and Hi nodes. @@ -3390,9 +2830,9 @@ public: /// \param RH High bits of the RHS of the MUL. See LL for meaning. /// \returns true if the node has been expanded. false if it has not bool expandMUL(SDNode *N, SDValue &Lo, SDValue &Hi, EVT HiLoVT, - SelectionDAG &DAG, MulExpansionKind Kind, - SDValue LL = SDValue(), SDValue LH = SDValue(), - SDValue RL = SDValue(), SDValue RH = SDValue()) const; + SelectionDAG &DAG, SDValue LL = SDValue(), + SDValue LH = SDValue(), SDValue RL = SDValue(), + SDValue RH = SDValue()) const; /// Expand float(f32) to SINT(i64) conversion /// \param N Node to expand @@ -3400,43 +2840,6 @@ public: /// \returns True, if the expansion was successful, false otherwise bool expandFP_TO_SINT(SDNode *N, SDValue &Result, SelectionDAG &DAG) const; - /// Turn load of vector type into a load of the individual elements. - /// \param LD load to expand - /// \returns MERGE_VALUEs of the scalar loads with their chains. - SDValue scalarizeVectorLoad(LoadSDNode *LD, SelectionDAG &DAG) const; - - // Turn a store of a vector type into stores of the individual elements. - /// \param ST Store with a vector value type - /// \returns MERGE_VALUs of the individual store chains. - SDValue scalarizeVectorStore(StoreSDNode *ST, SelectionDAG &DAG) const; - - /// Expands an unaligned load to 2 half-size loads for an integer, and - /// possibly more for vectors. - std::pair<SDValue, SDValue> expandUnalignedLoad(LoadSDNode *LD, - SelectionDAG &DAG) const; - - /// Expands an unaligned store to 2 half-size stores for integer values, and - /// possibly more for vectors. - SDValue expandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG) const; - - /// Increments memory address \p Addr according to the type of the value - /// \p DataVT that should be stored. If the data is stored in compressed - /// form, the memory address should be incremented according to the number of - /// the stored elements. This number is equal to the number of '1's bits - /// in the \p Mask. - /// \p DataVT is a vector type. \p Mask is a vector value. - /// \p DataVT and \p Mask have the same number of vector elements. - SDValue IncrementMemoryAddress(SDValue Addr, SDValue Mask, const SDLoc &DL, - EVT DataVT, SelectionDAG &DAG, - bool IsCompressedMemory) const; - - /// Get a pointer to vector element \p Idx located in memory for a vector of - /// type \p VecVT starting at a base address of \p VecPtr. If \p Idx is out of - /// bounds the returned pointer is unspecified, but will be within the vector - /// bounds. - SDValue getVectorElementPointer(SelectionDAG &DAG, SDValue VecPtr, EVT VecVT, - SDValue Idx) const; - //===--------------------------------------------------------------------===// // Instruction Emitting Hooks // @@ -3450,14 +2853,14 @@ public: /// As long as the returned basic block is different (i.e., we created a new /// one), the custom inserter is free to modify the rest of \p MBB. virtual MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *MBB) const; + EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; /// This method should be implemented by targets that mark instructions with /// the 'hasPostISelHook' flag. These instructions must be adjusted after /// instruction selection by target hooks. e.g. To fill in optional defs for /// ARM 's' setting instructions. - virtual void AdjustInstrPostInstrSelection(MachineInstr &MI, - SDNode *Node) const; + virtual void + AdjustInstrPostInstrSelection(MachineInstr *MI, SDNode *Node) const; /// If this function returns true, SelectionDAGBuilder emits a /// LOAD_STACK_GUARD node when it is lowering Intrinsic::stackprotector. @@ -3468,26 +2871,15 @@ public: /// Lower TLS global address SDNode for target independent emulated TLS model. virtual SDValue LowerToTLSEmulatedModel(const GlobalAddressSDNode *GA, SelectionDAG &DAG) const; - - // seteq(x, 0) -> truncate(srl(ctlz(zext(x)), log2(#bits))) - // If we're comparing for equality to zero and isCtlzFast is true, expose the - // fact that this can be implemented as a ctlz/srl pair, so that the dag - // combiner can fold the new nodes. - SDValue lowerCmpEqZeroToCtlzSrl(SDValue Op, SelectionDAG &DAG) const; - -private: - SDValue simplifySetCCWithAnd(EVT VT, SDValue N0, SDValue N1, - ISD::CondCode Cond, DAGCombinerInfo &DCI, - const SDLoc &DL) const; }; /// Given an LLVM IR type and return type attributes, compute the return value /// EVTs and flags, and optionally also the offsets, if the return value is /// being lowered to memory. -void GetReturnInfo(Type *ReturnType, AttributeList attr, +void GetReturnInfo(Type *ReturnType, AttributeSet attr, SmallVectorImpl<ISD::OutputArg> &Outs, const TargetLowering &TLI, const DataLayout &DL); -} // end namespace llvm +} // end llvm namespace -#endif // LLVM_TARGET_TARGETLOWERING_H +#endif diff --git a/gnu/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/gnu/llvm/include/llvm/Target/TargetLoweringObjectFile.h index 80d4d8e42e5..cb52698c58b 100644 --- a/gnu/llvm/include/llvm/Target/TargetLoweringObjectFile.h +++ b/gnu/llvm/include/llvm/Target/TargetLoweringObjectFile.h @@ -16,52 +16,44 @@ #define LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/SectionKind.h" -#include <cstdint> namespace llvm { - -class GlobalValue; -class MachineModuleInfo; -class Mangler; -class MCContext; -class MCExpr; -class MCSection; -class MCSymbol; -class MCSymbolRefExpr; -class MCStreamer; -class MCValue; -class TargetMachine; + class MachineModuleInfo; + class Mangler; + class MCContext; + class MCExpr; + class MCSection; + class MCSymbol; + class MCSymbolRefExpr; + class MCStreamer; + class MCValue; + class ConstantExpr; + class GlobalValue; + class TargetMachine; class TargetLoweringObjectFile : public MCObjectFileInfo { - MCContext *Ctx = nullptr; + MCContext *Ctx; - /// Name-mangler for global names. - Mangler *Mang = nullptr; + TargetLoweringObjectFile( + const TargetLoweringObjectFile&) = delete; + void operator=(const TargetLoweringObjectFile&) = delete; protected: - bool SupportIndirectSymViaGOTPCRel = false; - bool SupportGOTPCRelWithOffset = true; + bool SupportIndirectSymViaGOTPCRel; + bool SupportGOTPCRelWithOffset; - /// This section contains the static constructor pointer list. - MCSection *StaticCtorSection; +public: + MCContext &getContext() const { return *Ctx; } - /// This section contains the static destructor pointer list. - MCSection *StaticDtorSection; + TargetLoweringObjectFile() + : MCObjectFileInfo(), Ctx(nullptr), SupportIndirectSymViaGOTPCRel(false), + SupportGOTPCRelWithOffset(true) {} -public: - TargetLoweringObjectFile() = default; - TargetLoweringObjectFile(const TargetLoweringObjectFile &) = delete; - TargetLoweringObjectFile & - operator=(const TargetLoweringObjectFile &) = delete; virtual ~TargetLoweringObjectFile(); - MCContext &getContext() const { return *Ctx; } - Mangler &getMangler() const { return *Mang; } - /// This method must be called before any actual lowering is done. This /// specifies the current context for codegen, and gives the lowering /// implementations a chance to set up their default sections. @@ -70,41 +62,41 @@ public: virtual void emitPersonalityValue(MCStreamer &Streamer, const DataLayout &TM, const MCSymbol *Sym) const; - /// Emit the module-level metadata that the platform cares about. - virtual void emitModuleMetadata(MCStreamer &Streamer, Module &M, - const TargetMachine &TM) const {} + /// Emit the module flags that the platform cares about. + virtual void emitModuleFlags(MCStreamer &Streamer, + ArrayRef<Module::ModuleFlagEntry> Flags, + Mangler &Mang, const TargetMachine &TM) const {} /// Given a constant with the SectionKind, return a section that it should be /// placed in. virtual MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, - const Constant *C, - unsigned &Align) const; + const Constant *C) const; /// Classify the specified global variable into a set of target independent /// categories embodied in SectionKind. - static SectionKind getKindForGlobal(const GlobalObject *GO, + static SectionKind getKindForGlobal(const GlobalValue *GV, const TargetMachine &TM); /// This method computes the appropriate section to emit the specified global /// variable or function definition. This should not be passed external (or /// available externally) globals. - MCSection *SectionForGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const; + MCSection *SectionForGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler &Mang, const TargetMachine &TM) const; /// This method computes the appropriate section to emit the specified global /// variable or function definition. This should not be passed external (or /// available externally) globals. - MCSection *SectionForGlobal(const GlobalObject *GO, + MCSection *SectionForGlobal(const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM) const { - return SectionForGlobal(GO, getKindForGlobal(GO, TM), TM); + return SectionForGlobal(GV, getKindForGlobal(GV, TM), Mang, TM); } virtual void getNameWithPrefix(SmallVectorImpl<char> &OutName, - const GlobalValue *GV, + const GlobalValue *GV, Mangler &Mang, const TargetMachine &TM) const; - virtual MCSection *getSectionForJumpTable(const Function &F, + virtual MCSection *getSectionForJumpTable(const Function &F, Mangler &Mang, const TargetMachine &TM) const; virtual bool shouldPutJumpTableInFunctionSection(bool UsesLabelDifference, @@ -112,32 +104,40 @@ public: /// Targets should implement this method to assign a section to globals with /// an explicit section specfied. The implementation of this method can - /// assume that GO->hasSection() is true. + /// assume that GV->hasSection() is true. virtual MCSection * - getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, - const TargetMachine &TM) const = 0; + getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, + Mangler &Mang, const TargetMachine &TM) const = 0; + + /// Allow the target to completely override section assignment of a global. + virtual const MCSection *getSpecialCasedSectionGlobals(const GlobalValue *GV, + SectionKind Kind, + Mangler &Mang) const { + return nullptr; + } /// Return an MCExpr to use for a reference to the specified global variable /// from exception handling information. - virtual const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, - unsigned Encoding, - const TargetMachine &TM, - MachineModuleInfo *MMI, - MCStreamer &Streamer) const; + virtual const MCExpr * + getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding, + Mangler &Mang, const TargetMachine &TM, + MachineModuleInfo *MMI, MCStreamer &Streamer) const; /// Return the MCSymbol for a private symbol with global value name as its /// base, with the specified suffix. MCSymbol *getSymbolWithGlobalValueBase(const GlobalValue *GV, - StringRef Suffix, + StringRef Suffix, Mangler &Mang, const TargetMachine &TM) const; // The symbol that gets passed to .cfi_personality. virtual MCSymbol *getCFIPersonalitySymbol(const GlobalValue *GV, + Mangler &Mang, const TargetMachine &TM, MachineModuleInfo *MMI) const; - const MCExpr *getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding, - MCStreamer &Streamer) const; + const MCExpr * + getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding, + MCStreamer &Streamer) const; virtual MCSection *getStaticCtorSection(unsigned Priority, const MCSymbol *KeySym) const { @@ -153,9 +153,9 @@ public: /// emitting the address in debug info. virtual const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const; - virtual const MCExpr *lowerRelativeReference(const GlobalValue *LHS, - const GlobalValue *RHS, - const TargetMachine &TM) const { + virtual const MCExpr * + getExecutableRelativeSymbol(const ConstantExpr *CE, Mangler &Mang, + const TargetMachine &TM) const { return nullptr; } @@ -180,15 +180,15 @@ public: return nullptr; } - virtual void emitLinkerFlagsForGlobal(raw_ostream &OS, - const GlobalValue *GV) const {} + virtual void emitLinkerFlagsForGlobal(raw_ostream &OS, const GlobalValue *GV, + const Mangler &Mang) const {} protected: - virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO, - SectionKind Kind, + virtual MCSection *SelectSectionForGlobal(const GlobalValue *GV, + SectionKind Kind, Mangler &Mang, const TargetMachine &TM) const = 0; }; } // end namespace llvm -#endif // LLVM_TARGET_TARGETLOWERINGOBJECTFILE_H +#endif diff --git a/gnu/llvm/include/llvm/Target/TargetOpcodes.h b/gnu/llvm/include/llvm/Target/TargetOpcodes.h index 33df133a4d5..db37bdb6258 100644 --- a/gnu/llvm/include/llvm/Target/TargetOpcodes.h +++ b/gnu/llvm/include/llvm/Target/TargetOpcodes.h @@ -18,25 +18,122 @@ namespace llvm { /// Invariant opcodes: All instruction sets have these as their low opcodes. /// +/// Every instruction defined here must also appear in Target.td and the order +/// must be the same as in CodeGenTarget.cpp. +/// namespace TargetOpcode { enum { -#define HANDLE_TARGET_OPCODE(OPC) OPC, -#define HANDLE_TARGET_OPCODE_MARKER(IDENT, OPC) IDENT = OPC, -#include "llvm/Target/TargetOpcodes.def" + PHI = 0, + INLINEASM = 1, + CFI_INSTRUCTION = 2, + EH_LABEL = 3, + GC_LABEL = 4, + + /// KILL - This instruction is a noop that is used only to adjust the + /// liveness of registers. This can be useful when dealing with + /// sub-registers. + KILL = 5, + + /// EXTRACT_SUBREG - This instruction takes two operands: a register + /// that has subregisters, and a subregister index. It returns the + /// extracted subregister value. This is commonly used to implement + /// truncation operations on target architectures which support it. + EXTRACT_SUBREG = 6, + + /// INSERT_SUBREG - This instruction takes three operands: a register that + /// has subregisters, a register providing an insert value, and a + /// subregister index. It returns the value of the first register with the + /// value of the second register inserted. The first register is often + /// defined by an IMPLICIT_DEF, because it is commonly used to implement + /// anyext operations on target architectures which support it. + INSERT_SUBREG = 7, + + /// IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef. + IMPLICIT_DEF = 8, + + /// SUBREG_TO_REG - This instruction is similar to INSERT_SUBREG except that + /// the first operand is an immediate integer constant. This constant is + /// often zero, because it is commonly used to assert that the instruction + /// defining the register implicitly clears the high bits. + SUBREG_TO_REG = 9, + + /// COPY_TO_REGCLASS - This instruction is a placeholder for a plain + /// register-to-register copy into a specific register class. This is only + /// used between instruction selection and MachineInstr creation, before + /// virtual registers have been created for all the instructions, and it's + /// only needed in cases where the register classes implied by the + /// instructions are insufficient. It is emitted as a COPY MachineInstr. + COPY_TO_REGCLASS = 10, + + /// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic + DBG_VALUE = 11, + + /// REG_SEQUENCE - This variadic instruction is used to form a register that + /// represents a consecutive sequence of sub-registers. It's used as a + /// register coalescing / allocation aid and must be eliminated before code + /// emission. + // In SDNode form, the first operand encodes the register class created by + // the REG_SEQUENCE, while each subsequent pair names a vreg + subreg index + // pair. Once it has been lowered to a MachineInstr, the regclass operand + // is no longer present. + /// e.g. v1027 = REG_SEQUENCE v1024, 3, v1025, 4, v1026, 5 + /// After register coalescing references of v1024 should be replace with + /// v1027:3, v1025 with v1027:4, etc. + REG_SEQUENCE = 12, + + /// COPY - Target-independent register copy. This instruction can also be + /// used to copy between subregisters of virtual registers. + COPY = 13, + + /// BUNDLE - This instruction represents an instruction bundle. Instructions + /// which immediately follow a BUNDLE instruction which are marked with + /// 'InsideBundle' flag are inside the bundle. + BUNDLE = 14, + + /// Lifetime markers. + LIFETIME_START = 15, + LIFETIME_END = 16, + + /// A Stackmap instruction captures the location of live variables at its + /// position in the instruction stream. It is followed by a shadow of bytes + /// that must lie within the function and not contain another stackmap. + STACKMAP = 17, + + /// Patchable call instruction - this instruction represents a call to a + /// constant address, followed by a series of NOPs. It is intended to + /// support optimizations for dynamic languages (such as javascript) that + /// rewrite calls to runtimes with more efficient code sequences. + /// This also implies a stack map. + PATCHPOINT = 18, + + /// This pseudo-instruction loads the stack guard value. Targets which need + /// to prevent the stack guard value or address from being spilled to the + /// stack should override TargetLowering::emitLoadStackGuardNode and + /// additionally expand this pseudo after register allocation. + LOAD_STACK_GUARD = 19, + + /// Call instruction with associated vm state for deoptimization and list + /// of live pointers for relocation by the garbage collector. It is + /// intended to support garbage collection with fully precise relocating + /// collectors and deoptimizations in either the callee or caller. + STATEPOINT = 20, + + /// Instruction that records the offset of a local stack allocation passed to + /// llvm.localescape. It has two arguments: the symbol for the label and the + /// frame index of the local stack allocation. + LOCAL_ESCAPE = 21, + + /// Loading instruction that may page fault, bundled with associated + /// information on how to handle such a page fault. It is intended to support + /// "zero cost" null checks in managed languages by allowing LLVM to fold + /// comparisons into existing memory operations. + FAULTING_LOAD_OP = 22, + + /// BUILTIN_OP_END - This must be the last enum value in this list. + /// The target-specific post-isel opcode values start here. + GENERIC_OP_END = FAULTING_LOAD_OP, }; } // end namespace TargetOpcode - -/// Check whether the given Opcode is a generic opcode that is not supposed -/// to appear after ISel. -static inline bool isPreISelGenericOpcode(unsigned Opcode) { - return Opcode >= TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START && - Opcode <= TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; -} - -/// Check whether the given Opcode is a target-specific opcode. -static inline bool isTargetSpecificOpcode(unsigned Opcode) { - return Opcode > TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END; -} } // end namespace llvm #endif diff --git a/gnu/llvm/include/llvm/Target/TargetRegisterInfo.h b/gnu/llvm/include/llvm/Target/TargetRegisterInfo.h index b6839dad106..fccaad4705d 100644 --- a/gnu/llvm/include/llvm/Target/TargetRegisterInfo.h +++ b/gnu/llvm/include/llvm/Target/TargetRegisterInfo.h @@ -1,4 +1,4 @@ -//==- Target/TargetRegisterInfo.h - Target Register Information --*- C++ -*-==// +//=== Target/TargetRegisterInfo.h - Target Register Information -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,40 +17,52 @@ #define LLVM_TARGET_TARGETREGISTERINFO_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/IR/CallingConv.h" -#include "llvm/MC/LaneBitmask.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Printable.h" #include <cassert> -#include <cstdint> #include <functional> namespace llvm { class BitVector; -class LiveRegMatrix; class MachineFunction; -class MachineInstr; class RegScavenger; +template<class T> class SmallVectorImpl; class VirtRegMap; +class raw_ostream; +class LiveRegMatrix; + +/// A bitmask representing the covering of a register with sub-registers. +/// +/// This is typically used to track liveness at sub-register granularity. +/// Lane masks for sub-register indices are similar to register units for +/// physical registers. The individual bits in a lane mask can't be assigned +/// any specific meaning. They can be used to check if two sub-register +/// indices overlap. +/// +/// Iff the target has a register such that: +/// +/// getSubReg(Reg, A) overlaps getSubReg(Reg, B) +/// +/// then: +/// +/// (getSubRegIndexLaneMask(A) & getSubRegIndexLaneMask(B)) != 0 +typedef unsigned LaneBitmask; class TargetRegisterClass { public: - using iterator = const MCPhysReg *; - using const_iterator = const MCPhysReg *; - using sc_iterator = const TargetRegisterClass* const *; + typedef const MCPhysReg* iterator; + typedef const MCPhysReg* const_iterator; + typedef const MVT::SimpleValueType* vt_iterator; + typedef const TargetRegisterClass* const * sc_iterator; // Instance variables filled by tablegen, do not use! const MCRegisterClass *MC; - const uint16_t SpillSize, SpillAlignment; - const MVT::SimpleValueType *VTs; + const vt_iterator VTs; const uint32_t *SubClassMask; const uint16_t *SuperRegIndices; const LaneBitmask LaneMask; @@ -59,9 +71,6 @@ public: const uint8_t AllocationPriority; /// Whether the class supports two (or more) disjunct subregister indices. const bool HasDisjunctSubRegs; - /// Whether a combination of subregisters can cover every register in the - /// class. See also the CoveredBySubRegs description in Target.td. - const bool CoveredBySubRegs; const sc_iterator SuperClasses; ArrayRef<MCPhysReg> (*OrderFunc)(const MachineFunction&); @@ -76,11 +85,6 @@ public: /// Return the number of registers in this class. unsigned getNumRegs() const { return MC->getNumRegs(); } - iterator_range<SmallVectorImpl<MCPhysReg>::const_iterator> - getRegisters() const { - return make_range(MC->begin(), MC->end()); - } - /// Return the specified register in the class. unsigned getRegister(unsigned i) const { return MC->getRegister(i); @@ -97,6 +101,13 @@ public: return MC->contains(Reg1, Reg2); } + /// Return the size of the register in bytes, which is also the size + /// of a stack slot allocated to hold a spilled copy of this register. + unsigned getSize() const { return MC->getSize(); } + + /// Return the minimum required alignment for a register of this class. + unsigned getAlignment() const { return MC->getAlignment(); } + /// Return the cost of copying a value between two registers in this class. /// A negative number means the register class is very expensive /// to copy e.g. status flag register classes. @@ -106,6 +117,26 @@ public: /// registers. bool isAllocatable() const { return MC->isAllocatable(); } + /// Return true if this TargetRegisterClass has the ValueType vt. + bool hasType(MVT vt) const { + for(int i = 0; VTs[i] != MVT::Other; ++i) + if (MVT(VTs[i]) == vt) + return true; + return false; + } + + /// vt_begin / vt_end - Loop over all of the value types that can be + /// represented by values in this register class. + vt_iterator vt_begin() const { + return VTs; + } + + vt_iterator vt_end() const { + vt_iterator I = VTs; + while (*I != MVT::Other) ++I; + return I; + } + /// Return true if the specified TargetRegisterClass /// is a proper sub-class of this TargetRegisterClass. bool hasSubClass(const TargetRegisterClass *RC) const { @@ -130,21 +161,8 @@ public: } /// Returns a bit vector of subclasses, including this one. - /// The vector is indexed by class IDs. - /// - /// To use it, consider the returned array as a chunk of memory that - /// contains an array of bits of size NumRegClasses. Each 32-bit chunk - /// contains a bitset of the ID of the subclasses in big-endian style. - - /// I.e., the representation of the memory from left to right at the - /// bit level looks like: - /// [31 30 ... 1 0] [ 63 62 ... 33 32] ... - /// [ XXX NumRegClasses NumRegClasses - 1 ... ] - /// Where the number represents the class ID and XXX bits that - /// should be ignored. - /// - /// See the implementation of hasSubClassEq for an example of how it - /// can be used. + /// The vector is indexed by class IDs, see hasSubClassEq() above for how to + /// use it. const uint32_t *getSubClassMask() const { return SubClassMask; } @@ -156,6 +174,7 @@ public: /// There exists SuperRC where: /// For all Reg in SuperRC: /// this->contains(Reg:Idx) + /// const uint16_t *getSuperRegIndices() const { return SuperRegIndices; } @@ -186,13 +205,14 @@ public: /// other criteria. /// /// By default, this method returns all registers in the class. + /// ArrayRef<MCPhysReg> getRawAllocationOrder(const MachineFunction &MF) const { return OrderFunc ? OrderFunc(MF) : makeArrayRef(begin(), getNumRegs()); } /// Returns the combination of all lane masks of register in this class. /// The lane masks of the registers are the combination of all lane masks - /// of their subregisters. Returns 1 if there are no subregisters. + /// of their subregisters. LaneBitmask getLaneMask() const { return LaneMask; } @@ -220,9 +240,7 @@ struct RegClassWeight { /// class TargetRegisterInfo : public MCRegisterInfo { public: - using regclass_iterator = const TargetRegisterClass * const *; - using vt_iterator = const MVT::SimpleValueType *; - + typedef const TargetRegisterClass * const * regclass_iterator; private: const TargetRegisterInfoDesc *InfoDesc; // Extra desc array for codegen const char *const *SubRegIndexNames; // Names of subreg indexes. @@ -230,7 +248,7 @@ private: const LaneBitmask *SubRegIndexLaneMasks; regclass_iterator RegClassBegin, RegClassEnd; // List of regclasses - LaneBitmask CoveringLanes; + unsigned CoveringLanes; protected: TargetRegisterInfo(const TargetRegisterInfoDesc *ID, @@ -238,10 +256,10 @@ protected: regclass_iterator RegClassEnd, const char *const *SRINames, const LaneBitmask *SRILaneMasks, - LaneBitmask CoveringLanes); + unsigned CoveringLanes); virtual ~TargetRegisterInfo(); - public: + // Register numbers can represent physical registers, virtual registers, and // sometimes stack slots. The unsigned values are divided into these ranges: // @@ -304,44 +322,6 @@ public: return Index | (1u << 31); } - /// Return the size in bits of a register from class RC. - unsigned getRegSizeInBits(const TargetRegisterClass &RC) const { - return RC.SpillSize * 8; - } - - /// Return the size in bytes of the stack slot allocated to hold a spilled - /// copy of a register from class RC. - unsigned getSpillSize(const TargetRegisterClass &RC) const { - return RC.SpillSize; - } - - /// Return the minimum required alignment for a spill slot for a register - /// of this class. - unsigned getSpillAlignment(const TargetRegisterClass &RC) const { - return RC.SpillAlignment; - } - - /// Return true if the given TargetRegisterClass has the ValueType T. - bool isTypeLegalForClass(const TargetRegisterClass &RC, MVT T) const { - for (int i = 0; RC.VTs[i] != MVT::Other; ++i) - if (MVT(RC.VTs[i]) == T) - return true; - return false; - } - - /// Loop over all of the value types that can be represented by values - // in the given register class. - vt_iterator legalclasstypes_begin(const TargetRegisterClass &RC) const { - return RC.VTs; - } - - vt_iterator legalclasstypes_end(const TargetRegisterClass &RC) const { - vt_iterator I = RC.VTs; - while (*I != MVT::Other) - ++I; - return I; - } - /// Returns the Register Class of a physical register of the given type, /// picking the most sub register class of the right type that contains this /// physreg. @@ -442,12 +422,15 @@ public: /// this target. The register should be in the order of desired callee-save /// stack frame offset. The first register is closest to the incoming stack /// pointer if stack grows down, and vice versa. - /// Notice: This function does not take into account disabled CSRs. - /// In most cases you will want to use instead the function - /// getCalleeSavedRegs that is implemented in MachineRegisterInfo. + /// virtual const MCPhysReg* getCalleeSavedRegs(const MachineFunction *MF) const = 0; + virtual const MCPhysReg* + getCalleeSavedRegsViaCopy(const MachineFunction *MF) const { + return nullptr; + } + /// Return a mask of call-preserved registers for the given calling convention /// on the current function. The mask should include all call-preserved /// aliases. This is used by the register allocator to determine which @@ -474,47 +457,23 @@ public: /// Return a register mask that clobbers everything. virtual const uint32_t *getNoPreservedMask() const { - llvm_unreachable("target does not provide no preserved mask"); + llvm_unreachable("target does not provide no presered mask"); } - /// Return true if all bits that are set in mask \p mask0 are also set in - /// \p mask1. - bool regmaskSubsetEqual(const uint32_t *mask0, const uint32_t *mask1) const; - /// Return all the call-preserved register masks defined for this target. virtual ArrayRef<const uint32_t *> getRegMasks() const = 0; virtual ArrayRef<const char *> getRegMaskNames() const = 0; /// Returns a bitset indexed by physical register number indicating if a /// register is a special register that has particular uses and should be - /// considered unavailable at all times, e.g. stack pointer, return address. - /// A reserved register: - /// - is not allocatable - /// - is considered always live - /// - is ignored by liveness tracking - /// It is often necessary to reserve the super registers of a reserved - /// register as well, to avoid them getting allocated indirectly. You may use - /// markSuperRegs() and checkAllSuperRegsMarked() in this case. + /// considered unavailable at all times, e.g. SP, RA. This is + /// used by register scavenger to determine what registers are free. virtual BitVector getReservedRegs(const MachineFunction &MF) const = 0; - /// Returns true if PhysReg is unallocatable and constant throughout the - /// function. Used by MachineRegisterInfo::isConstantPhysReg(). - virtual bool isConstantPhysReg(unsigned PhysReg) const { return false; } - - /// Physical registers that may be modified within a function but are - /// guaranteed to be restored before any uses. This is useful for targets that - /// have call sequences where a GOT register may be updated by the caller - /// prior to a call and is guaranteed to be restored (also by the caller) - /// after the call. - virtual bool isCallerPreservedPhysReg(unsigned PhysReg, - const MachineFunction &MF) const { - return false; - } - /// Prior to adding the live-out mask to a stackmap or patchpoint /// instruction, provide the target the opportunity to adjust it (mainly to /// remove pseudo-registers that should be ignored). - virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const {} + virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const { } /// Return a super-register of the specified register /// Reg so its sub-register of index SubIdx is Reg. @@ -534,7 +493,7 @@ public: // For a copy-like instruction that defines a register of class DefRC with // subreg index DefSubReg, reading from another source with class SrcRC and - // subregister SrcSubReg return true if this is a preferable copy + // subregister SrcSubReg return true if this is a preferrable copy // instruction or an earlier use should be used. virtual bool shouldRewriteCopySrc(const TargetRegisterClass *DefRC, unsigned DefSubReg, @@ -572,6 +531,7 @@ public: /// The ARM register Q0 has two D subregs dsub_0:D0 and dsub_1:D1. It also has /// ssub_0:S0 - ssub_3:S3 subregs. /// If you compose subreg indices dsub_1, ssub_0 you get ssub_2. + /// unsigned composeSubRegIndices(unsigned a, unsigned b) const { if (!a) return b; if (!b) return a; @@ -588,20 +548,6 @@ public: return composeSubRegIndexLaneMaskImpl(IdxA, Mask); } - /// Transform a lanemask given for a virtual register to the corresponding - /// lanemask before using subregister with index \p IdxA. - /// This is the reverse of composeSubRegIndexLaneMask(), assuming Mask is a - /// valie lane mask (no invalid bits set) the following holds: - /// X0 = composeSubRegIndexLaneMask(Idx, Mask) - /// X1 = reverseComposeSubRegIndexLaneMask(Idx, X0) - /// => X1 == Mask - LaneBitmask reverseComposeSubRegIndexLaneMask(unsigned IdxA, - LaneBitmask LaneMask) const { - if (!IdxA) - return LaneMask; - return reverseComposeSubRegIndexLaneMaskImpl(IdxA, LaneMask); - } - /// Debugging helper: dump register in human readable form to dbgs() stream. static void dumpReg(unsigned Reg, unsigned SubRegIndex = 0, const TargetRegisterInfo* TRI = nullptr); @@ -618,11 +564,6 @@ protected: llvm_unreachable("Target has no sub-registers"); } - virtual LaneBitmask reverseComposeSubRegIndexLaneMaskImpl(unsigned, - LaneBitmask) const { - llvm_unreachable("Target has no sub-registers"); - } - public: /// Find a common super-register class if it exists. /// @@ -646,6 +587,7 @@ public: /// corresponding argument register class. /// /// The function returns NULL if no register class can be found. + /// const TargetRegisterClass* getCommonSuperRegClass(const TargetRegisterClass *RCA, unsigned SubA, const TargetRegisterClass *RCB, unsigned SubB, @@ -656,11 +598,9 @@ public: // /// Register class iterators + /// regclass_iterator regclass_begin() const { return RegClassBegin; } regclass_iterator regclass_end() const { return RegClassEnd; } - iterator_range<regclass_iterator> regclasses() const { - return make_range(regclass_begin(), regclass_end()); - } unsigned getNumRegClasses() const { return (unsigned)(regclass_end()-regclass_begin()); @@ -830,13 +770,6 @@ public: return false; } - /// Returns true if the target requires using the RegScavenger directly for - /// frame elimination despite using requiresFrameIndexScavenging. - virtual bool requiresFrameIndexReplacementScavenging( - const MachineFunction &MF) const { - return false; - } - /// Returns true if the target wants the LocalStackAllocation pass to be run /// and virtual base registers used for more efficient stack access. virtual bool requiresVirtualBaseRegisters(const MachineFunction &MF) const { @@ -910,6 +843,7 @@ public: /// Return true if the register was spilled, false otherwise. /// If this function does not spill the register, the scavenger /// will instead spill it to the emergency spill slot. + /// virtual bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock::iterator &UseMI, @@ -929,17 +863,6 @@ public: int SPAdj, unsigned FIOperandNum, RegScavenger *RS = nullptr) const = 0; - /// Return the assembly name for \p Reg. - virtual StringRef getRegAsmName(unsigned Reg) const { - // FIXME: We are assuming that the assembly name is equal to the TableGen - // name converted to lower case - // - // The TableGen name is the name of the definition for this register in the - // target's tablegen files. For example, the TableGen name of - // def EAX : Register <...>; is "EAX" - return StringRef(getName(Reg)); - } - //===--------------------------------------------------------------------===// /// Subtarget Hooks @@ -958,16 +881,9 @@ public: /// getFrameRegister - This method should return the register used as a base /// for values allocated in the current stack frame. virtual unsigned getFrameRegister(const MachineFunction &MF) const = 0; - - /// Mark a register and all its aliases as reserved in the given set. - void markSuperRegs(BitVector &RegisterSet, unsigned Reg) const; - - /// Returns true if for every register in the set all super registers are part - /// of the set as well. - bool checkAllSuperRegsMarked(const BitVector &RegisterSet, - ArrayRef<MCPhysReg> Exceptions = ArrayRef<MCPhysReg>()) const; }; + //===----------------------------------------------------------------------===// // SuperRegClassIterator //===----------------------------------------------------------------------===// @@ -986,7 +902,7 @@ public: // class SuperRegClassIterator { const unsigned RCMaskWords; - unsigned SubReg = 0; + unsigned SubReg; const uint16_t *Idx; const uint32_t *Mask; @@ -997,7 +913,9 @@ public: const TargetRegisterInfo *TRI, bool IncludeSelf = false) : RCMaskWords((TRI->getNumRegClasses() + 31) / 32), - Idx(RC->getSuperRegIndices()), Mask(RC->getSubClassMask()) { + SubReg(0), + Idx(RC->getSuperRegIndices()), + Mask(RC->getSubClassMask()) { if (!IncludeSelf) ++*this; } @@ -1008,9 +926,8 @@ public: /// Returns the current sub-register index. unsigned getSubReg() const { return SubReg; } - /// Returns the bit mask of register classes that getSubReg() projects into + /// Returns the bit mask if register classes that getSubReg() projects into /// RC. - /// See TargetRegisterClass::getSubClassMask() for how to use it. const uint32_t *getMask() const { return Mask; } /// Advance iterator to the next entry. @@ -1023,96 +940,6 @@ public: } }; -//===----------------------------------------------------------------------===// -// BitMaskClassIterator -//===----------------------------------------------------------------------===// -/// This class encapuslates the logic to iterate over bitmask returned by -/// the various RegClass related APIs. -/// E.g., this class can be used to iterate over the subclasses provided by -/// TargetRegisterClass::getSubClassMask or SuperRegClassIterator::getMask. -class BitMaskClassIterator { - /// Total number of register classes. - const unsigned NumRegClasses; - /// Base index of CurrentChunk. - /// In other words, the number of bit we read to get at the - /// beginning of that chunck. - unsigned Base = 0; - /// Adjust base index of CurrentChunk. - /// Base index + how many bit we read within CurrentChunk. - unsigned Idx = 0; - /// Current register class ID. - unsigned ID = 0; - /// Mask we are iterating over. - const uint32_t *Mask; - /// Current chunk of the Mask we are traversing. - uint32_t CurrentChunk; - - /// Move ID to the next set bit. - void moveToNextID() { - // If the current chunk of memory is empty, move to the next one, - // while making sure we do not go pass the number of register - // classes. - while (!CurrentChunk) { - // Move to the next chunk. - Base += 32; - if (Base >= NumRegClasses) { - ID = NumRegClasses; - return; - } - CurrentChunk = *++Mask; - Idx = Base; - } - // Otherwise look for the first bit set from the right - // (representation of the class ID is big endian). - // See getSubClassMask for more details on the representation. - unsigned Offset = countTrailingZeros(CurrentChunk); - // Add the Offset to the adjusted base number of this chunk: Idx. - // This is the ID of the register class. - ID = Idx + Offset; - - // Consume the zeros, if any, and the bit we just read - // so that we are at the right spot for the next call. - // Do not do Offset + 1 because Offset may be 31 and 32 - // will be UB for the shift, though in that case we could - // have make the chunk being equal to 0, but that would - // have introduced a if statement. - moveNBits(Offset); - moveNBits(1); - } - - /// Move \p NumBits Bits forward in CurrentChunk. - void moveNBits(unsigned NumBits) { - assert(NumBits < 32 && "Undefined behavior spotted!"); - // Consume the bit we read for the next call. - CurrentChunk >>= NumBits; - // Adjust the base for the chunk. - Idx += NumBits; - } - -public: - /// Create a BitMaskClassIterator that visits all the register classes - /// represented by \p Mask. - /// - /// \pre \p Mask != nullptr - BitMaskClassIterator(const uint32_t *Mask, const TargetRegisterInfo &TRI) - : NumRegClasses(TRI.getNumRegClasses()), Mask(Mask), CurrentChunk(*Mask) { - // Move to the first ID. - moveToNextID(); - } - - /// Returns true if this iterator is still pointing at a valid entry. - bool isValid() const { return getID() != NumRegClasses; } - - /// Returns the current register class ID. - unsigned getID() const { return ID; } - - /// Advance iterator to the next entry. - void operator++() { - assert(isValid() && "Cannot move iterator past end."); - moveToNextID(); - } -}; - // This is useful when building IndexedMaps keyed on virtual registers struct VirtReg2IndexFunctor : public std::unary_function<unsigned, unsigned> { unsigned operator()(unsigned Reg) const { @@ -1147,6 +974,9 @@ Printable PrintRegUnit(unsigned Unit, const TargetRegisterInfo *TRI); /// registers on a \ref raw_ostream. Printable PrintVRegOrUnit(unsigned VRegOrUnit, const TargetRegisterInfo *TRI); -} // end namespace llvm +/// Create Printable object to print LaneBitmasks on a \ref raw_ostream. +Printable PrintLaneMask(LaneBitmask LaneMask); + +} // End llvm namespace -#endif // LLVM_TARGET_TARGETREGISTERINFO_H +#endif diff --git a/gnu/llvm/include/llvm/Target/TargetSubtargetInfo.h b/gnu/llvm/include/llvm/Target/TargetSubtargetInfo.h index 9440c56dcf1..d50aa4932f8 100644 --- a/gnu/llvm/include/llvm/Target/TargetSubtargetInfo.h +++ b/gnu/llvm/include/llvm/Target/TargetSubtargetInfo.h @@ -1,4 +1,4 @@ -//===- llvm/Target/TargetSubtargetInfo.h - Target Information ---*- C++ -*-===// +//==-- llvm/Target/TargetSubtargetInfo.h - Target Information ----*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -14,35 +14,17 @@ #ifndef LLVM_TARGET_TARGETSUBTARGETINFO_H #define LLVM_TARGET_TARGETSUBTARGETINFO_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/PBQPRAConstraint.h" -#include "llvm/CodeGen/ScheduleDAGMutation.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/CodeGen.h" -#include <memory> -#include <vector> - namespace llvm { -class CallLowering; -class InstrItineraryData; -struct InstrStage; -class InstructionSelector; -class LegalizerInfo; +class DataLayout; +class MachineFunction; class MachineInstr; -struct MachineSchedPolicy; -struct MCReadAdvanceEntry; -struct MCWriteLatencyEntry; -struct MCWriteProcResEntry; -class RegisterBankInfo; class SDep; -class SelectionDAGTargetInfo; -struct SubtargetFeatureKV; -struct SubtargetInfoKV; class SUnit; class TargetFrameLowering; class TargetInstrInfo; @@ -50,7 +32,9 @@ class TargetLowering; class TargetRegisterClass; class TargetRegisterInfo; class TargetSchedModel; -class Triple; +class TargetSelectionDAGInfo; +struct MachineSchedPolicy; +template <typename T> class SmallVectorImpl; //===----------------------------------------------------------------------===// /// @@ -59,6 +43,10 @@ class Triple; /// be exposed through a TargetSubtargetInfo-derived class. /// class TargetSubtargetInfo : public MCSubtargetInfo { + TargetSubtargetInfo(const TargetSubtargetInfo &) = delete; + void operator=(const TargetSubtargetInfo &) = delete; + TargetSubtargetInfo() = delete; + protected: // Can only create subclasses... TargetSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS, ArrayRef<SubtargetFeatureKV> PF, @@ -72,15 +60,10 @@ protected: // Can only create subclasses... public: // AntiDepBreakMode - Type of anti-dependence breaking that should // be performed before post-RA scheduling. - using AntiDepBreakMode = enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL }; - using RegClassVector = SmallVectorImpl<const TargetRegisterClass *>; + typedef enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL } AntiDepBreakMode; + typedef SmallVectorImpl<const TargetRegisterClass *> RegClassVector; - TargetSubtargetInfo() = delete; - TargetSubtargetInfo(const TargetSubtargetInfo &) = delete; - TargetSubtargetInfo &operator=(const TargetSubtargetInfo &) = delete; - ~TargetSubtargetInfo() override; - - virtual bool isXRaySupported() const { return false; } + virtual ~TargetSubtargetInfo(); // Interfaces to the major aspects of target machine information: // @@ -88,7 +71,6 @@ public: // -- Pipelines and scheduling information // -- Stack frame information // -- Selection DAG lowering information - // -- Call lowering information // // N.B. These objects may change during compilation. It's not safe to cache // them between functions. @@ -97,37 +79,24 @@ public: return nullptr; } virtual const TargetLowering *getTargetLowering() const { return nullptr; } - virtual const SelectionDAGTargetInfo *getSelectionDAGInfo() const { - return nullptr; - } - virtual const CallLowering *getCallLowering() const { return nullptr; } - - // FIXME: This lets targets specialize the selector by subtarget (which lets - // us do things like a dedicated avx512 selector). However, we might want - // to also specialize selectors by MachineFunction, which would let us be - // aware of optsize/optnone and such. - virtual const InstructionSelector *getInstructionSelector() const { + virtual const TargetSelectionDAGInfo *getSelectionDAGInfo() const { return nullptr; } - /// Target can subclass this hook to select a different DAG scheduler. virtual RegisterScheduler::FunctionPassCtor getDAGScheduler(CodeGenOpt::Level) const { return nullptr; } - virtual const LegalizerInfo *getLegalizerInfo() const { return nullptr; } - /// getRegisterInfo - If register information is available, return it. If - /// not, return null. + /// not, return null. This is kept separate from RegInfo until RegInfo has + /// details of graph coloring register allocation removed from it. + /// virtual const TargetRegisterInfo *getRegisterInfo() const { return nullptr; } - /// If the information for the register banks is available, return it. - /// Otherwise return nullptr. - virtual const RegisterBankInfo *getRegBankInfo() const { return nullptr; } - /// getInstrItineraryData - Returns instruction itinerary data for the target /// or specific subtarget. + /// virtual const InstrItineraryData *getInstrItineraryData() const { return nullptr; } @@ -150,9 +119,6 @@ public: /// TargetLowering preference). It does not yet disable the postRA scheduler. virtual bool enableMachineScheduler() const; - /// \brief Support printing of [latency:throughput] comment in output .S file. - virtual bool supportPrintSchedInfo() const { return false; } - /// \brief True if the machine scheduler should disable the TLI preference /// for preRA scheduling with the source level scheduler. virtual bool enableMachineSchedDefaultSched() const { return true; } @@ -178,6 +144,7 @@ public: /// scheduling heuristics (no custom MachineSchedStrategy) to make /// changes to the generic scheduling policy. virtual void overrideSchedPolicy(MachineSchedPolicy &Policy, + MachineInstr *begin, MachineInstr *end, unsigned NumRegionInstrs) const {} // \brief Perform target specific adjustments to the latency of a schedule @@ -195,18 +162,6 @@ public: return CriticalPathRCs.clear(); } - // \brief Provide an ordered list of schedule DAG mutations for the post-RA - // scheduler. - virtual void getPostRAMutations( - std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const { - } - - // \brief Provide an ordered list of schedule DAG mutations for the machine - // pipeliner. - virtual void getSMSMutations( - std::vector<std::unique_ptr<ScheduleDAGMutation>> &Mutations) const { - } - // For use with PostRAScheduling: get the minimum optimization level needed // to enable post-RA scheduling. virtual CodeGenOpt::Level getOptLevelToEnablePostRAScheduler() const { @@ -234,15 +189,9 @@ public: } /// Enable tracking of subregister liveness in register allocator. - /// Please use MachineRegisterInfo::subRegLivenessEnabled() instead where - /// possible. virtual bool enableSubRegLiveness() const { return false; } - - /// Returns string representation of scheduler comment - std::string getSchedInfoStr(const MachineInstr &MI) const override; - std::string getSchedInfoStr(MCInst const &MCI) const override; }; -} // end namespace llvm +} // End llvm namespace -#endif // LLVM_TARGET_TARGETSUBTARGETINFO_H +#endif diff --git a/gnu/llvm/include/llvm/Transforms/Utils/CmpInstAnalysis.h b/gnu/llvm/include/llvm/Transforms/Utils/CmpInstAnalysis.h index 5ec3888d453..73c15e42c35 100644 --- a/gnu/llvm/include/llvm/Transforms/Utils/CmpInstAnalysis.h +++ b/gnu/llvm/include/llvm/Transforms/Utils/CmpInstAnalysis.h @@ -21,13 +21,13 @@ namespace llvm { class ICmpInst; class Value; - /// Encode a icmp predicate into a three bit mask. These bits are carefully - /// arranged to allow folding of expressions such as: + /// getICmpCode - Encode a icmp predicate into a three bit mask. These bits + /// are carefully arranged to allow folding of expressions such as: /// /// (A < B) | (A > B) --> (A != B) /// /// Note that this is only valid if the first and second predicates have the - /// same sign. It is illegal to do: (A u< B) | (A s> B) + /// same sign. Is illegal to do: (A u< B) | (A s> B) /// /// Three bits are used to represent the condition, as follows: /// 0 A > B @@ -46,25 +46,20 @@ namespace llvm { /// unsigned getICmpCode(const ICmpInst *ICI, bool InvertPred = false); - /// This is the complement of getICmpCode, which turns an opcode and two - /// operands into either a constant true or false, or the predicate for a new - /// ICmp instruction. The sign is passed in to determine which kind of - /// predicate to use in the new icmp instruction. + /// getICmpValue - This is the complement of getICmpCode, which turns an + /// opcode and two operands into either a constant true or false, or the + /// predicate for a new ICmp instruction. The sign is passed in to determine + /// which kind of predicate to use in the new icmp instruction. /// Non-NULL return value will be a true or false constant. - /// NULL return means a new ICmp is needed. The predicate for which is output - /// in NewICmpPred. + /// NULL return means a new ICmp is needed. The predicate for which is + /// output in NewICmpPred. Value *getICmpValue(bool Sign, unsigned Code, Value *LHS, Value *RHS, CmpInst::Predicate &NewICmpPred); - /// Return true if both predicates match sign or if at least one of them is an - /// equality comparison (which is signless). + /// PredicatesFoldable - Return true if both predicates match sign or if at + /// least one of them is an equality comparison (which is signless). bool PredicatesFoldable(CmpInst::Predicate p1, CmpInst::Predicate p2); - /// Decompose an icmp into the form ((X & Y) pred Z) if possible. The returned - /// predicate is either == or !=. Returns false if decomposition fails. - bool decomposeBitTestICmp(const ICmpInst *I, CmpInst::Predicate &Pred, - Value *&X, Value *&Y, Value *&Z); - } // end namespace llvm #endif diff --git a/gnu/llvm/lib/Analysis/SparsePropagation.cpp b/gnu/llvm/lib/Analysis/SparsePropagation.cpp index 470f4bee1e0..f5a927b8052 100644 --- a/gnu/llvm/lib/Analysis/SparsePropagation.cpp +++ b/gnu/llvm/lib/Analysis/SparsePropagation.cpp @@ -195,7 +195,7 @@ void SparseSolver::getFeasibleSuccessors(TerminatorInst &TI, Succs.assign(TI.getNumSuccessors(), true); return; } - SwitchInst::CaseHandle Case = *SI.findCaseValue(cast<ConstantInt>(C)); + SwitchInst::CaseIt Case = SI.findCaseValue(cast<ConstantInt>(C)); Succs[Case.getSuccessorIndex()] = true; } @@ -320,8 +320,8 @@ void SparseSolver::Solve(Function &F) { // Notify all instructions in this basic block that they are newly // executable. - for (Instruction &I : *BB) - visitInst(I); + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) + visitInst(*I); } } } diff --git a/gnu/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp b/gnu/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp index 0e240f482a1..a506e0571c0 100644 --- a/gnu/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/gnu/llvm/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -1,4 +1,4 @@ -//===- LiveIntervalAnalysis.cpp - Live Interval Analysis ------------------===// +//===-- LiveIntervalAnalysis.cpp - Live Interval Analysis -----------------===// // // The LLVM Compiler Infrastructure // @@ -7,52 +7,38 @@ // //===----------------------------------------------------------------------===// // -/// \file This file implements the LiveInterval analysis pass which is used -/// by the Linear Scan Register allocator. This pass linearizes the -/// basic blocks of the function in DFS order and computes live intervals for -/// each virtual and physical register. +// This file implements the LiveInterval analysis pass which is used +// by the Linear Scan Register allocator. This pass linearizes the +// basic blocks of the function in DFS order and uses the +// LiveVariables pass to conservatively compute live intervals for +// each virtual and physical register. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "LiveRangeCalc.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DepthFirstIterator.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveVariables.h" -#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineDominators.h" -#include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineInstrBundle.h" -#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" -#include "llvm/CodeGen/SlotIndexes.h" #include "llvm/CodeGen/VirtRegMap.h" -#include "llvm/MC/LaneBitmask.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Pass.h" +#include "llvm/IR/Value.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include <algorithm> -#include <cassert> -#include <cstdint> -#include <iterator> -#include <tuple> -#include <utility> - +#include <cmath> +#include <limits> using namespace llvm; #define DEBUG_TYPE "regalloc" @@ -62,6 +48,7 @@ char &llvm::LiveIntervalsID = LiveIntervals::ID; INITIALIZE_PASS_BEGIN(LiveIntervals, "liveintervals", "Live Interval Analysis", false, false) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LiveVariables) INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) INITIALIZE_PASS_DEPENDENCY(SlotIndexes) INITIALIZE_PASS_END(LiveIntervals, "liveintervals", @@ -75,19 +62,25 @@ static cl::opt<bool> EnablePrecomputePhysRegs( static bool EnablePrecomputePhysRegs = false; #endif // NDEBUG -namespace llvm { +static cl::opt<bool> EnableSubRegLiveness( + "enable-subreg-liveness", cl::Hidden, cl::init(true), + cl::desc("Enable subregister liveness tracking.")); +namespace llvm { cl::opt<bool> UseSegmentSetForPhysRegs( "use-segment-set-for-physregs", cl::Hidden, cl::init(true), cl::desc( "Use segment set for the computation of the live ranges of physregs.")); - -} // end namespace llvm +} void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired<AAResultsWrapperPass>(); AU.addPreserved<AAResultsWrapperPass>(); + // LiveVariables isn't really required by this analysis, it is only required + // here to make sure it is live during TwoAddressInstructionPass and + // PHIElimination. This is temporary. + AU.addRequired<LiveVariables>(); AU.addPreserved<LiveVariables>(); AU.addPreservedID(MachineLoopInfoID); AU.addRequiredTransitiveID(MachineDominatorsID); @@ -97,7 +90,8 @@ void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const { MachineFunctionPass::getAnalysisUsage(AU); } -LiveIntervals::LiveIntervals() : MachineFunctionPass(ID) { +LiveIntervals::LiveIntervals() : MachineFunctionPass(ID), + DomTree(nullptr), LRCalc(nullptr) { initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); } @@ -114,14 +108,16 @@ void LiveIntervals::releaseMemory() { RegMaskBits.clear(); RegMaskBlocks.clear(); - for (LiveRange *LR : RegUnitRanges) - delete LR; + for (unsigned i = 0, e = RegUnitRanges.size(); i != e; ++i) + delete RegUnitRanges[i]; RegUnitRanges.clear(); // Release VNInfo memory regions, VNInfo objects don't need to be dtor'd. VNInfoAllocator.Reset(); } +/// runOnMachineFunction - calculates LiveIntervals +/// bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { MF = &fn; MRI = &MF->getRegInfo(); @@ -131,6 +127,9 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { Indexes = &getAnalysis<SlotIndexes>(); DomTree = &getAnalysis<MachineDominatorTree>(); + if (EnableSubRegLiveness && MF->getSubtarget().enableSubRegLiveness()) + MRI->enableSubRegLiveness(true); + if (!LRCalc) LRCalc = new LiveRangeCalc(); @@ -151,13 +150,14 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) { return true; } +/// print - Implement the dump method. void LiveIntervals::print(raw_ostream &OS, const Module* ) const { OS << "********** INTERVALS **********\n"; // Dump the regunits. - for (unsigned Unit = 0, UnitE = RegUnitRanges.size(); Unit != UnitE; ++Unit) - if (LiveRange *LR = RegUnitRanges[Unit]) - OS << PrintRegUnit(Unit, TRI) << ' ' << *LR << '\n'; + for (unsigned i = 0, e = RegUnitRanges.size(); i != e; ++i) + if (LiveRange *LR = RegUnitRanges[i]) + OS << PrintRegUnit(i, TRI) << ' ' << *LR << '\n'; // Dump the virtregs. for (unsigned i = 0, e = MRI->getNumVirtRegs(); i != e; ++i) { @@ -167,8 +167,8 @@ void LiveIntervals::print(raw_ostream &OS, const Module* ) const { } OS << "RegMasks:"; - for (SlotIndex Idx : RegMaskSlots) - OS << ' ' << Idx; + for (unsigned i = 0, e = RegMaskSlots.size(); i != e; ++i) + OS << ' ' << RegMaskSlots[i]; OS << '\n'; printInstrs(OS); @@ -180,23 +180,33 @@ void LiveIntervals::printInstrs(raw_ostream &OS) const { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void LiveIntervals::dumpInstrs() const { +void LiveIntervals::dumpInstrs() const { printInstrs(dbgs()); } #endif LiveInterval* LiveIntervals::createInterval(unsigned reg) { - float Weight = TargetRegisterInfo::isPhysicalRegister(reg) ? huge_valf : 0.0F; + float Weight = TargetRegisterInfo::isPhysicalRegister(reg) ? + llvm::huge_valf : 0.0F; return new LiveInterval(reg, Weight); } -/// Compute the live interval of a virtual register, based on defs and uses. + +/// computeVirtRegInterval - Compute the live interval of a virtual register, +/// based on defs and uses. void LiveIntervals::computeVirtRegInterval(LiveInterval &LI) { assert(LRCalc && "LRCalc not initialized."); assert(LI.empty() && "Should only compute empty intervals."); + bool ShouldTrackSubRegLiveness = MRI->shouldTrackSubRegLiveness(LI.reg); LRCalc->reset(MF, getSlotIndexes(), DomTree, &getVNInfoAllocator()); - LRCalc->calculate(LI, MRI->shouldTrackSubRegLiveness(LI.reg)); - computeDeadValues(LI, nullptr); + LRCalc->calculate(LI, ShouldTrackSubRegLiveness); + bool SeparatedComponents = computeDeadValues(LI, nullptr); + if (SeparatedComponents) { + assert(ShouldTrackSubRegLiveness + && "Separated components should only occur for unused subreg defs"); + SmallVector<LiveInterval*, 8> SplitLIs; + splitSeparateComponents(LI, SplitLIs); + } } void LiveIntervals::computeVirtRegs() { @@ -212,7 +222,7 @@ void LiveIntervals::computeRegMasks() { RegMaskBlocks.resize(MF->getNumBlockIDs()); // Find all instructions with regmask operands. - for (const MachineBasicBlock &MBB : *MF) { + for (MachineBasicBlock &MBB : *MF) { std::pair<unsigned, unsigned> &RMB = RegMaskBlocks[MBB.getNumber()]; RMB.first = RegMaskSlots.size(); @@ -222,22 +232,18 @@ void LiveIntervals::computeRegMasks() { RegMaskBits.push_back(Mask); } - for (const MachineInstr &MI : MBB) { + for (MachineInstr &MI : MBB) { for (const MachineOperand &MO : MI.operands()) { if (!MO.isRegMask()) continue; - RegMaskSlots.push_back(Indexes->getInstructionIndex(MI).getRegSlot()); + RegMaskSlots.push_back(Indexes->getInstructionIndex(&MI).getRegSlot()); RegMaskBits.push_back(MO.getRegMask()); } } - // Some block ends, such as funclet returns, create masks. Put the mask on - // the last instruction of the block, because MBB slot index intervals are - // half-open. + // Some block ends, such as funclet returns, create masks. if (const uint32_t *Mask = MBB.getEndClobberMask(TRI)) { - assert(!MBB.empty() && "empty return block?"); - RegMaskSlots.push_back( - Indexes->getInstructionIndex(MBB.back()).getRegSlot()); + RegMaskSlots.push_back(Indexes->getMBBEndIdx(&MBB)); RegMaskBits.push_back(Mask); } @@ -257,9 +263,9 @@ void LiveIntervals::computeRegMasks() { // interference. // -/// Compute the live range of a register unit, based on the uses and defs of -/// aliasing registers. The range should be empty, or contain only dead -/// phi-defs from ABI blocks. +/// computeRegUnitInterval - Compute the live range of a register unit, based +/// on the uses and defs of aliasing registers. The range should be empty, +/// or contain only dead phi-defs from ABI blocks. void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) { assert(LRCalc && "LRCalc not initialized."); LRCalc->reset(MF, getSlotIndexes(), DomTree, &getVNInfoAllocator()); @@ -269,34 +275,22 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) { // may share super-registers. That's OK because createDeadDefs() is // idempotent. It is very rare for a register unit to have multiple roots, so // uniquing super-registers is probably not worthwhile. - bool IsReserved = false; - for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) { - bool IsRootReserved = true; - for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true); - Super.isValid(); ++Super) { - unsigned Reg = *Super; - if (!MRI->reg_empty(Reg)) - LRCalc->createDeadDefs(LR, Reg); - // A register unit is considered reserved if all its roots and all their - // super registers are reserved. - if (!MRI->isReserved(Reg)) - IsRootReserved = false; + for (MCRegUnitRootIterator Roots(Unit, TRI); Roots.isValid(); ++Roots) { + for (MCSuperRegIterator Supers(*Roots, TRI, /*IncludeSelf=*/true); + Supers.isValid(); ++Supers) { + if (!MRI->reg_empty(*Supers)) + LRCalc->createDeadDefs(LR, *Supers); } - IsReserved |= IsRootReserved; } - assert(IsReserved == MRI->isReservedRegUnit(Unit) && - "reserved computation mismatch"); // Now extend LR to reach all uses. // Ignore uses of reserved registers. We only track defs of those. - if (!IsReserved) { - for (MCRegUnitRootIterator Root(Unit, TRI); Root.isValid(); ++Root) { - for (MCSuperRegIterator Super(*Root, TRI, /*IncludeSelf=*/true); - Super.isValid(); ++Super) { - unsigned Reg = *Super; - if (!MRI->reg_empty(Reg)) - LRCalc->extendToUses(LR, Reg); - } + for (MCRegUnitRootIterator Roots(Unit, TRI); Roots.isValid(); ++Roots) { + for (MCSuperRegIterator Supers(*Roots, TRI, /*IncludeSelf=*/true); + Supers.isValid(); ++Supers) { + unsigned Reg = *Supers; + if (!MRI->isReserved(Reg) && !MRI->reg_empty(Reg)) + LRCalc->extendToUses(LR, Reg); } } @@ -305,9 +299,11 @@ void LiveIntervals::computeRegUnitRange(LiveRange &LR, unsigned Unit) { LR.flushSegmentSet(); } -/// Precompute the live ranges of any register units that are live-in to an ABI -/// block somewhere. Register values can appear without a corresponding def when -/// entering the entry block or a landing pad. + +/// computeLiveInRegUnits - Precompute the live ranges of any register units +/// that are live-in to an ABI block somewhere. Register values can appear +/// without a corresponding def when entering the entry block or a landing pad. +/// void LiveIntervals::computeLiveInRegUnits() { RegUnitRanges.resize(TRI->getNumRegUnits()); DEBUG(dbgs() << "Computing live-in reg-units in ABI blocks.\n"); @@ -316,15 +312,18 @@ void LiveIntervals::computeLiveInRegUnits() { SmallVector<unsigned, 8> NewRanges; // Check all basic blocks for live-ins. - for (const MachineBasicBlock &MBB : *MF) { + for (MachineFunction::const_iterator MFI = MF->begin(), MFE = MF->end(); + MFI != MFE; ++MFI) { + const MachineBasicBlock *MBB = &*MFI; + // We only care about ABI blocks: Entry + landing pads. - if ((&MBB != &MF->front() && !MBB.isEHPad()) || MBB.livein_empty()) + if ((MFI != MF->begin() && !MBB->isEHPad()) || MBB->livein_empty()) continue; // Create phi-defs at Begin for all live-in registers. - SlotIndex Begin = Indexes->getMBBStartIdx(&MBB); - DEBUG(dbgs() << Begin << "\tBB#" << MBB.getNumber()); - for (const auto &LI : MBB.liveins()) { + SlotIndex Begin = Indexes->getMBBStartIdx(MBB); + DEBUG(dbgs() << Begin << "\tBB#" << MBB->getNumber()); + for (const auto &LI : MBB->liveins()) { for (MCRegUnitIterator Units(LI.PhysReg, TRI); Units.isValid(); ++Units) { unsigned Unit = *Units; LiveRange *LR = RegUnitRanges[Unit]; @@ -343,13 +342,16 @@ void LiveIntervals::computeLiveInRegUnits() { DEBUG(dbgs() << "Created " << NewRanges.size() << " new intervals.\n"); // Compute the 'normal' part of the ranges. - for (unsigned Unit : NewRanges) + for (unsigned i = 0, e = NewRanges.size(); i != e; ++i) { + unsigned Unit = NewRanges[i]; computeRegUnitRange(*RegUnitRanges[Unit], Unit); + } } + static void createSegmentsForValues(LiveRange &LR, - iterator_range<LiveInterval::vni_iterator> VNIs) { - for (VNInfo *VNI : VNIs) { + iterator_range<LiveInterval::vni_iterator> VNIs) { + for (auto VNI : VNIs) { if (VNI->isUnused()) continue; SlotIndex Def = VNI->def; @@ -357,7 +359,7 @@ static void createSegmentsForValues(LiveRange &LR, } } -using ShrinkToUsesWorkList = SmallVector<std::pair<SlotIndex, VNInfo*>, 16>; +typedef SmallVector<std::pair<SlotIndex, VNInfo*>, 16> ShrinkToUsesWorkList; static void extendSegmentsToUses(LiveRange &LR, const SlotIndexes &Indexes, ShrinkToUsesWorkList &WorkList, @@ -365,7 +367,7 @@ static void extendSegmentsToUses(LiveRange &LR, const SlotIndexes &Indexes, // Keep track of the PHIs that are in use. SmallPtrSet<VNInfo*, 8> UsedPHIs; // Blocks that have already been added to WorkList as live-out. - SmallPtrSet<const MachineBasicBlock*, 16> LiveOut; + SmallPtrSet<MachineBasicBlock*, 16> LiveOut; // Extend intervals to reach all uses in WorkList. while (!WorkList.empty()) { @@ -384,7 +386,7 @@ static void extendSegmentsToUses(LiveRange &LR, const SlotIndexes &Indexes, !UsedPHIs.insert(VNI).second) continue; // The PHI is live, make sure the predecessors are live-out. - for (const MachineBasicBlock *Pred : MBB->predecessors()) { + for (auto &Pred : MBB->predecessors()) { if (!LiveOut.insert(Pred).second) continue; SlotIndex Stop = Indexes.getMBBEndIdx(Pred); @@ -400,7 +402,7 @@ static void extendSegmentsToUses(LiveRange &LR, const SlotIndexes &Indexes, LR.addSegment(LiveRange::Segment(BlockStart, Idx, VNI)); // Make sure VNI is live-out from the predecessors. - for (const MachineBasicBlock *Pred : MBB->predecessors()) { + for (auto &Pred : MBB->predecessors()) { if (!LiveOut.insert(Pred).second) continue; SlotIndex Stop = Indexes.getMBBEndIdx(Pred); @@ -431,9 +433,11 @@ bool LiveIntervals::shrinkToUses(LiveInterval *li, ShrinkToUsesWorkList WorkList; // Visit all instructions reading li->reg. - unsigned Reg = li->reg; - for (MachineInstr &UseMI : MRI->reg_instructions(Reg)) { - if (UseMI.isDebugValue() || !UseMI.readsVirtualRegister(Reg)) + for (MachineRegisterInfo::reg_instr_iterator + I = MRI->reg_instr_begin(li->reg), E = MRI->reg_instr_end(); + I != E; ) { + MachineInstr *UseMI = &*(I++); + if (UseMI->isDebugValue() || !UseMI->readsVirtualRegister(li->reg)) continue; SlotIndex Idx = getInstructionIndex(UseMI).getRegSlot(); LiveQueryResult LRQ = li->Query(Idx); @@ -442,9 +446,9 @@ bool LiveIntervals::shrinkToUses(LiveInterval *li, // This shouldn't happen: readsVirtualRegister returns true, but there is // no live value. It is likely caused by a target getting <undef> flags // wrong. - DEBUG(dbgs() << Idx << '\t' << UseMI + DEBUG(dbgs() << Idx << '\t' << *UseMI << "Warning: Instr claims to read non-existent value in " - << *li << '\n'); + << *li << '\n'); continue; } // Special case: An early-clobber tied operand reads and writes the @@ -472,7 +476,7 @@ bool LiveIntervals::shrinkToUses(LiveInterval *li, bool LiveIntervals::computeDeadValues(LiveInterval &LI, SmallVectorImpl<MachineInstr*> *dead) { bool MayHaveSplitComponents = false; - for (VNInfo *VNI : LI.valnos) { + for (auto VNI : LI.valnos) { if (VNI->isUnused()) continue; SlotIndex Def = VNI->def; @@ -481,11 +485,13 @@ bool LiveIntervals::computeDeadValues(LiveInterval &LI, // Is the register live before? Otherwise we may have to add a read-undef // flag for subregister defs. + bool DeadBeforeDef = false; unsigned VReg = LI.reg; if (MRI->shouldTrackSubRegLiveness(VReg)) { if ((I == LI.begin() || std::prev(I)->end < Def) && !VNI->isPHIDef()) { MachineInstr *MI = getInstructionFromIndex(Def); MI->setRegisterDefReadUndef(VReg); + DeadBeforeDef = true; } } @@ -501,7 +507,15 @@ bool LiveIntervals::computeDeadValues(LiveInterval &LI, // This is a dead def. Make sure the instruction knows. MachineInstr *MI = getInstructionFromIndex(Def); assert(MI && "No instruction defining live value"); - MI->addRegisterDead(LI.reg, TRI); + MI->addRegisterDead(VReg, TRI); + + // If we have a dead def that is completely separate from the rest of + // the liverange then we rewrite it to use a different VReg to not violate + // the rule that the liveness of a virtual register forms a connected + // component. This should only happen if subregister liveness is tracked. + if (DeadBeforeDef) + MayHaveSplitComponents = true; + if (dead && MI->allDefsAreDead()) { DEBUG(dbgs() << "All defs dead: " << Def << '\t' << *MI); dead->push_back(MI); @@ -511,7 +525,8 @@ bool LiveIntervals::computeDeadValues(LiveInterval &LI, return MayHaveSplitComponents; } -void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) { +void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) +{ DEBUG(dbgs() << "Shrink: " << SR << '\n'); assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Can only shrink virtual registers"); @@ -520,20 +535,19 @@ void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) { // Visit all instructions reading Reg. SlotIndex LastIdx; - for (MachineOperand &MO : MRI->use_nodbg_operands(Reg)) { - // Skip "undef" uses. - if (!MO.readsReg()) + for (MachineOperand &MO : MRI->reg_operands(Reg)) { + MachineInstr *UseMI = MO.getParent(); + if (UseMI->isDebugValue()) continue; // Maybe the operand is for a subregister we don't care about. unsigned SubReg = MO.getSubReg(); if (SubReg != 0) { LaneBitmask LaneMask = TRI->getSubRegIndexLaneMask(SubReg); - if ((LaneMask & SR.LaneMask).none()) + if ((LaneMask & SR.LaneMask) == 0) continue; } // We only need to visit each instruction once. - MachineInstr *UseMI = MO.getParent(); - SlotIndex Idx = getInstructionIndex(*UseMI).getRegSlot(); + SlotIndex Idx = getInstructionIndex(UseMI).getRegSlot(); if (Idx == LastIdx) continue; LastIdx = Idx; @@ -562,7 +576,7 @@ void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) { SR.segments.swap(NewLR.segments); // Remove dead PHI value numbers - for (VNInfo *VNI : SR.valnos) { + for (auto VNI : SR.valnos) { if (VNI->isUnused()) continue; const LiveRange::Segment *Segment = SR.getSegmentContaining(VNI->def); @@ -571,9 +585,9 @@ void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) { continue; if (VNI->isPHIDef()) { // This is a dead PHI. Remove it. - DEBUG(dbgs() << "Dead PHI at " << VNI->def << " may separate interval\n"); VNI->markUnused(); SR.removeSegment(*Segment); + DEBUG(dbgs() << "Dead PHI at " << VNI->def << " may separate interval\n"); } } @@ -581,12 +595,11 @@ void LiveIntervals::shrinkToUses(LiveInterval::SubRange &SR, unsigned Reg) { } void LiveIntervals::extendToIndices(LiveRange &LR, - ArrayRef<SlotIndex> Indices, - ArrayRef<SlotIndex> Undefs) { + ArrayRef<SlotIndex> Indices) { assert(LRCalc && "LRCalc not initialized."); LRCalc->reset(MF, getSlotIndexes(), DomTree, &getVNInfoAllocator()); - for (SlotIndex Idx : Indices) - LRCalc->extend(LR, Idx, /*PhysReg=*/0, Undefs); + for (unsigned i = 0, e = Indices.size(); i != e; ++i) + LRCalc->extend(LR, Indices[i]); } void LiveIntervals::pruneValue(LiveRange &LR, SlotIndex Kill, @@ -613,11 +626,13 @@ void LiveIntervals::pruneValue(LiveRange &LR, SlotIndex Kill, // Find all blocks that are reachable from KillMBB without leaving VNI's live // range. It is possible that KillMBB itself is reachable, so start a DFS // from each successor. - using VisitedTy = df_iterator_default_set<MachineBasicBlock*,9>; + typedef SmallPtrSet<MachineBasicBlock*, 9> VisitedTy; VisitedTy Visited; - for (MachineBasicBlock *Succ : KillMBB->successors()) { + for (MachineBasicBlock::succ_iterator + SuccI = KillMBB->succ_begin(), SuccE = KillMBB->succ_end(); + SuccI != SuccE; ++SuccI) { for (df_ext_iterator<MachineBasicBlock*, VisitedTy> - I = df_ext_begin(Succ, Visited), E = df_ext_end(Succ, Visited); + I = df_ext_begin(*SuccI, Visited), E = df_ext_end(*SuccI, Visited); I != E;) { MachineBasicBlock *MBB = *I; @@ -669,9 +684,9 @@ void LiveIntervals::addKillFlags(const VirtRegMap *VRM) { // Find the regunit intervals for the assigned register. They may overlap // the virtual register live range, cancelling any kills. RU.clear(); - for (MCRegUnitIterator Unit(VRM->getPhys(Reg), TRI); Unit.isValid(); - ++Unit) { - const LiveRange &RURange = getRegUnit(*Unit); + for (MCRegUnitIterator Units(VRM->getPhys(Reg), TRI); Units.isValid(); + ++Units) { + const LiveRange &RURange = getRegUnit(*Units); if (RURange.empty()) continue; RU.push_back(std::make_pair(&RURange, RURange.find(LI.begin()->end))); @@ -730,7 +745,7 @@ void LiveIntervals::addKillFlags(const VirtRegMap *VRM) { LaneBitmask DefinedLanesMask; if (!SRs.empty()) { // Compute a mask of lanes that are defined. - DefinedLanesMask = LaneBitmask::getNone(); + DefinedLanesMask = 0; for (auto &SRP : SRs) { const LiveInterval::SubRange &SR = *SRP.first; LiveRange::const_iterator &I = SRP.second; @@ -743,7 +758,7 @@ void LiveIntervals::addKillFlags(const VirtRegMap *VRM) { DefinedLanesMask |= SR.LaneMask; } } else - DefinedLanesMask = LaneBitmask::getAll(); + DefinedLanesMask = ~0u; bool IsFullWrite = false; for (const MachineOperand &MO : MI->operands()) { @@ -752,7 +767,7 @@ void LiveIntervals::addKillFlags(const VirtRegMap *VRM) { if (MO.isUse()) { // Reading any undefined lanes? LaneBitmask UseMask = TRI->getSubRegIndexLaneMask(MO.getSubReg()); - if ((UseMask & ~DefinedLanesMask).any()) + if ((UseMask & ~DefinedLanesMask) != 0) goto CancelKill; } else if (MO.getSubReg() == 0) { // Writing to the full register? @@ -814,34 +829,38 @@ LiveIntervals::hasPHIKill(const LiveInterval &LI, const VNInfo *VNI) const { // Conservatively return true instead of scanning huge predecessor lists. if (PHIMBB->pred_size() > 100) return true; - for (const MachineBasicBlock *Pred : PHIMBB->predecessors()) - if (VNI == LI.getVNInfoBefore(Indexes->getMBBEndIdx(Pred))) + for (MachineBasicBlock::const_pred_iterator + PI = PHIMBB->pred_begin(), PE = PHIMBB->pred_end(); PI != PE; ++PI) + if (VNI == LI.getVNInfoBefore(Indexes->getMBBEndIdx(*PI))) return true; } return false; } -float LiveIntervals::getSpillWeight(bool isDef, bool isUse, - const MachineBlockFrequencyInfo *MBFI, - const MachineInstr &MI) { - BlockFrequency Freq = MBFI->getBlockFreq(MI.getParent()); +float +LiveIntervals::getSpillWeight(bool isDef, bool isUse, + const MachineBlockFrequencyInfo *MBFI, + const MachineInstr *MI) { + BlockFrequency Freq = MBFI->getBlockFreq(MI->getParent()); const float Scale = 1.0f / MBFI->getEntryFreq(); return (isDef + isUse) * (Freq.getFrequency() * Scale); } LiveRange::Segment -LiveIntervals::addSegmentToEndOfBlock(unsigned reg, MachineInstr &startInst) { +LiveIntervals::addSegmentToEndOfBlock(unsigned reg, MachineInstr* startInst) { LiveInterval& Interval = createEmptyInterval(reg); - VNInfo *VN = Interval.getNextValue( - SlotIndex(getInstructionIndex(startInst).getRegSlot()), - getVNInfoAllocator()); - LiveRange::Segment S(SlotIndex(getInstructionIndex(startInst).getRegSlot()), - getMBBEndIdx(startInst.getParent()), VN); + VNInfo* VN = Interval.getNextValue( + SlotIndex(getInstructionIndex(startInst).getRegSlot()), + getVNInfoAllocator()); + LiveRange::Segment S( + SlotIndex(getInstructionIndex(startInst).getRegSlot()), + getMBBEndIdx(startInst->getParent()), VN); Interval.addSegment(S); return S; } + //===----------------------------------------------------------------------===// // Register mask functions //===----------------------------------------------------------------------===// @@ -874,7 +893,7 @@ bool LiveIntervals::checkRegMaskInterference(LiveInterval &LI, return false; bool Found = false; - while (true) { + for (;;) { assert(*SlotI >= LiveI->start); // Loop over all slots overlapping this segment. while (*SlotI < LiveI->end) { @@ -905,7 +924,7 @@ bool LiveIntervals::checkRegMaskInterference(LiveInterval &LI, // IntervalUpdate class. //===----------------------------------------------------------------------===// -/// Toolkit used by handleMove to trim or extend live intervals. +// HMEditor is a toolkit used by handleMove to trim or extend live intervals. class LiveIntervals::HMEditor { private: LiveIntervals& LIS; @@ -928,7 +947,7 @@ public: // kill flags. This is wasteful. Eventually, LiveVariables will strip all kill // flags, and postRA passes will use a live register utility instead. LiveRange *getRegUnitLI(unsigned Unit) { - if (UpdateFlags && !MRI.isReservedRegUnit(Unit)) + if (UpdateFlags) return &LIS.getRegUnit(Unit); return LIS.getCachedRegUnit(Unit); } @@ -943,13 +962,10 @@ public: hasRegMask = true; if (!MO.isReg()) continue; - if (MO.isUse()) { - if (!MO.readsReg()) - continue; - // Aggressively clear all kill flags. - // They are reinserted by VirtRegRewriter. + // Aggressively clear all kill flags. + // They are reinserted by VirtRegRewriter. + if (MO.isUse()) MO.setIsKill(false); - } unsigned Reg = MO.getReg(); if (!Reg) @@ -958,15 +974,14 @@ public: LiveInterval &LI = LIS.getInterval(Reg); if (LI.hasSubRanges()) { unsigned SubReg = MO.getSubReg(); - LaneBitmask LaneMask = SubReg ? TRI.getSubRegIndexLaneMask(SubReg) - : MRI.getMaxLaneMaskForVReg(Reg); + LaneBitmask LaneMask = TRI.getSubRegIndexLaneMask(SubReg); for (LiveInterval::SubRange &S : LI.subranges()) { - if ((S.LaneMask & LaneMask).none()) + if ((S.LaneMask & LaneMask) == 0) continue; updateRange(S, Reg, S.LaneMask); } } - updateRange(LI, Reg, LaneBitmask::getNone()); + updateRange(LI, Reg, 0); continue; } @@ -974,7 +989,7 @@ public: // precomputed live range. for (MCRegUnitIterator Units(Reg, &TRI); Units.isValid(); ++Units) if (LiveRange *LR = getRegUnitLI(*Units)) - updateRange(*LR, *Units, LaneBitmask::getNone()); + updateRange(*LR, *Units, 0); } if (hasRegMask) updateRegMaskSlots(); @@ -990,7 +1005,7 @@ private: dbgs() << " "; if (TargetRegisterInfo::isVirtualRegister(Reg)) { dbgs() << PrintReg(Reg); - if (LaneMask.any()) + if (LaneMask != 0) dbgs() << " L" << PrintLaneMask(LaneMask); } else { dbgs() << PrintRegUnit(Reg, &TRI); @@ -1006,300 +1021,172 @@ private: } /// Update LR to reflect an instruction has been moved downwards from OldIdx - /// to NewIdx (OldIdx < NewIdx). + /// to NewIdx. + /// + /// 1. Live def at OldIdx: + /// Move def to NewIdx, assert endpoint after NewIdx. + /// + /// 2. Live def at OldIdx, killed at NewIdx: + /// Change to dead def at NewIdx. + /// (Happens when bundling def+kill together). + /// + /// 3. Dead def at OldIdx: + /// Move def to NewIdx, possibly across another live value. + /// + /// 4. Def at OldIdx AND at NewIdx: + /// Remove segment [OldIdx;NewIdx) and value defined at OldIdx. + /// (Happens when bundling multiple defs together). + /// + /// 5. Value read at OldIdx, killed before NewIdx: + /// Extend kill to NewIdx. + /// void handleMoveDown(LiveRange &LR) { + // First look for a kill at OldIdx. + LiveRange::iterator I = LR.find(OldIdx.getBaseIndex()); LiveRange::iterator E = LR.end(); - // Segment going into OldIdx. - LiveRange::iterator OldIdxIn = LR.find(OldIdx.getBaseIndex()); - - // No value live before or after OldIdx? Nothing to do. - if (OldIdxIn == E || SlotIndex::isEarlierInstr(OldIdx, OldIdxIn->start)) + // Is LR even live at OldIdx? + if (I == E || SlotIndex::isEarlierInstr(OldIdx, I->start)) return; - LiveRange::iterator OldIdxOut; - // Do we have a value live-in to OldIdx? - if (SlotIndex::isEarlierInstr(OldIdxIn->start, OldIdx)) { + // Handle a live-in value. + if (!SlotIndex::isSameInstr(I->start, OldIdx)) { + bool isKill = SlotIndex::isSameInstr(OldIdx, I->end); // If the live-in value already extends to NewIdx, there is nothing to do. - if (SlotIndex::isEarlierEqualInstr(NewIdx, OldIdxIn->end)) + if (!SlotIndex::isEarlierInstr(I->end, NewIdx)) return; // Aggressively remove all kill flags from the old kill point. // Kill flags shouldn't be used while live intervals exist, they will be // reinserted by VirtRegRewriter. - if (MachineInstr *KillMI = LIS.getInstructionFromIndex(OldIdxIn->end)) - for (MIBundleOperands MO(*KillMI); MO.isValid(); ++MO) + if (MachineInstr *KillMI = LIS.getInstructionFromIndex(I->end)) + for (MIBundleOperands MO(KillMI); MO.isValid(); ++MO) if (MO->isReg() && MO->isUse()) MO->setIsKill(false); - - // Is there a def before NewIdx which is not OldIdx? - LiveRange::iterator Next = std::next(OldIdxIn); - if (Next != E && !SlotIndex::isSameInstr(OldIdx, Next->start) && - SlotIndex::isEarlierInstr(Next->start, NewIdx)) { - // If we are here then OldIdx was just a use but not a def. We only have - // to ensure liveness extends to NewIdx. - LiveRange::iterator NewIdxIn = - LR.advanceTo(Next, NewIdx.getBaseIndex()); - // Extend the segment before NewIdx if necessary. - if (NewIdxIn == E || - !SlotIndex::isEarlierInstr(NewIdxIn->start, NewIdx)) { - LiveRange::iterator Prev = std::prev(NewIdxIn); - Prev->end = NewIdx.getRegSlot(); - } - // Extend OldIdxIn. - OldIdxIn->end = Next->start; - return; - } - - // Adjust OldIdxIn->end to reach NewIdx. This may temporarily make LR - // invalid by overlapping ranges. - bool isKill = SlotIndex::isSameInstr(OldIdx, OldIdxIn->end); - OldIdxIn->end = NewIdx.getRegSlot(OldIdxIn->end.isEarlyClobber()); - // If this was not a kill, then there was no def and we're done. + // Adjust I->end to reach NewIdx. This may temporarily make LR invalid by + // overlapping ranges. Case 5 above. + I->end = NewIdx.getRegSlot(I->end.isEarlyClobber()); + // If this was a kill, there may also be a def. Otherwise we're done. if (!isKill) return; - - // Did we have a Def at OldIdx? - OldIdxOut = Next; - if (OldIdxOut == E || !SlotIndex::isSameInstr(OldIdx, OldIdxOut->start)) - return; - } else { - OldIdxOut = OldIdxIn; + ++I; } - // If we are here then there is a Definition at OldIdx. OldIdxOut points - // to the segment starting there. - assert(OldIdxOut != E && SlotIndex::isSameInstr(OldIdx, OldIdxOut->start) && - "No def?"); - VNInfo *OldIdxVNI = OldIdxOut->valno; - assert(OldIdxVNI->def == OldIdxOut->start && "Inconsistent def"); - - // If the defined value extends beyond NewIdx, just move the beginning - // of the segment to NewIdx. - SlotIndex NewIdxDef = NewIdx.getRegSlot(OldIdxOut->start.isEarlyClobber()); - if (SlotIndex::isEarlierInstr(NewIdxDef, OldIdxOut->end)) { - OldIdxVNI->def = NewIdxDef; - OldIdxOut->start = OldIdxVNI->def; + // Check for a def at OldIdx. + if (I == E || !SlotIndex::isSameInstr(OldIdx, I->start)) return; - } - - // If we are here then we have a Definition at OldIdx which ends before - // NewIdx. - - // Is there an existing Def at NewIdx? - LiveRange::iterator AfterNewIdx - = LR.advanceTo(OldIdxOut, NewIdx.getRegSlot()); - bool OldIdxDefIsDead = OldIdxOut->end.isDead(); - if (!OldIdxDefIsDead && - SlotIndex::isEarlierInstr(OldIdxOut->end, NewIdxDef)) { - // OldIdx is not a dead def, and NewIdxDef is inside a new interval. - VNInfo *DefVNI; - if (OldIdxOut != LR.begin() && - !SlotIndex::isEarlierInstr(std::prev(OldIdxOut)->end, - OldIdxOut->start)) { - // There is no gap between OldIdxOut and its predecessor anymore, - // merge them. - LiveRange::iterator IPrev = std::prev(OldIdxOut); - DefVNI = OldIdxVNI; - IPrev->end = OldIdxOut->end; - } else { - // The value is live in to OldIdx - LiveRange::iterator INext = std::next(OldIdxOut); - assert(INext != E && "Must have following segment"); - // We merge OldIdxOut and its successor. As we're dealing with subreg - // reordering, there is always a successor to OldIdxOut in the same BB - // We don't need INext->valno anymore and will reuse for the new segment - // we create later. - DefVNI = OldIdxVNI; - INext->start = OldIdxOut->end; - INext->valno->def = INext->start; - } - // If NewIdx is behind the last segment, extend that and append a new one. - if (AfterNewIdx == E) { - // OldIdxOut is undef at this point, Slide (OldIdxOut;AfterNewIdx] up - // one position. - // |- ?/OldIdxOut -| |- X0 -| ... |- Xn -| end - // => |- X0/OldIdxOut -| ... |- Xn -| |- undef/NewS -| end - std::copy(std::next(OldIdxOut), E, OldIdxOut); - // The last segment is undefined now, reuse it for a dead def. - LiveRange::iterator NewSegment = std::prev(E); - *NewSegment = LiveRange::Segment(NewIdxDef, NewIdxDef.getDeadSlot(), - DefVNI); - DefVNI->def = NewIdxDef; - - LiveRange::iterator Prev = std::prev(NewSegment); - Prev->end = NewIdxDef; - } else { - // OldIdxOut is undef at this point, Slide (OldIdxOut;AfterNewIdx] up - // one position. - // |- ?/OldIdxOut -| |- X0 -| ... |- Xn/AfterNewIdx -| |- Next -| - // => |- X0/OldIdxOut -| ... |- Xn -| |- Xn/AfterNewIdx -| |- Next -| - std::copy(std::next(OldIdxOut), std::next(AfterNewIdx), OldIdxOut); - LiveRange::iterator Prev = std::prev(AfterNewIdx); - // We have two cases: - if (SlotIndex::isEarlierInstr(Prev->start, NewIdxDef)) { - // Case 1: NewIdx is inside a liverange. Split this liverange at - // NewIdxDef into the segment "Prev" followed by "NewSegment". - LiveRange::iterator NewSegment = AfterNewIdx; - *NewSegment = LiveRange::Segment(NewIdxDef, Prev->end, Prev->valno); - Prev->valno->def = NewIdxDef; - - *Prev = LiveRange::Segment(Prev->start, NewIdxDef, DefVNI); - DefVNI->def = Prev->start; - } else { - // Case 2: NewIdx is in a lifetime hole. Keep AfterNewIdx as is and - // turn Prev into a segment from NewIdx to AfterNewIdx->start. - *Prev = LiveRange::Segment(NewIdxDef, AfterNewIdx->start, DefVNI); - DefVNI->def = NewIdxDef; - assert(DefVNI != AfterNewIdx->valno); - } - } + // We have a def at OldIdx. + VNInfo *DefVNI = I->valno; + assert(DefVNI->def == I->start && "Inconsistent def"); + DefVNI->def = NewIdx.getRegSlot(I->start.isEarlyClobber()); + // If the defined value extends beyond NewIdx, just move the def down. + // This is case 1 above. + if (SlotIndex::isEarlierInstr(NewIdx, I->end)) { + I->start = DefVNI->def; return; } - - if (AfterNewIdx != E && - SlotIndex::isSameInstr(AfterNewIdx->start, NewIdxDef)) { - // There is an existing def at NewIdx. The def at OldIdx is coalesced into - // that value. - assert(AfterNewIdx->valno != OldIdxVNI && "Multiple defs of value?"); - LR.removeValNo(OldIdxVNI); - } else { - // There was no existing def at NewIdx. We need to create a dead def - // at NewIdx. Shift segments over the old OldIdxOut segment, this frees - // a new segment at the place where we want to construct the dead def. - // |- OldIdxOut -| |- X0 -| ... |- Xn -| |- AfterNewIdx -| - // => |- X0/OldIdxOut -| ... |- Xn -| |- undef/NewS. -| |- AfterNewIdx -| - assert(AfterNewIdx != OldIdxOut && "Inconsistent iterators"); - std::copy(std::next(OldIdxOut), AfterNewIdx, OldIdxOut); - // We can reuse OldIdxVNI now. - LiveRange::iterator NewSegment = std::prev(AfterNewIdx); - VNInfo *NewSegmentVNI = OldIdxVNI; - NewSegmentVNI->def = NewIdxDef; - *NewSegment = LiveRange::Segment(NewIdxDef, NewIdxDef.getDeadSlot(), - NewSegmentVNI); + // The remaining possibilities are now: + // 2. Live def at OldIdx, killed at NewIdx: isSameInstr(I->end, NewIdx). + // 3. Dead def at OldIdx: I->end = OldIdx.getDeadSlot(). + // In either case, it is possible that there is an existing def at NewIdx. + assert((I->end == OldIdx.getDeadSlot() || + SlotIndex::isSameInstr(I->end, NewIdx)) && + "Cannot move def below kill"); + LiveRange::iterator NewI = LR.advanceTo(I, NewIdx.getRegSlot()); + if (NewI != E && SlotIndex::isSameInstr(NewI->start, NewIdx)) { + // There is an existing def at NewIdx, case 4 above. The def at OldIdx is + // coalesced into that value. + assert(NewI->valno != DefVNI && "Multiple defs of value?"); + LR.removeValNo(DefVNI); + return; } + // There was no existing def at NewIdx. Turn *I into a dead def at NewIdx. + // If the def at OldIdx was dead, we allow it to be moved across other LR + // values. The new range should be placed immediately before NewI, move any + // intermediate ranges up. + assert(NewI != I && "Inconsistent iterators"); + std::copy(std::next(I), NewI, I); + *std::prev(NewI) + = LiveRange::Segment(DefVNI->def, NewIdx.getDeadSlot(), DefVNI); } /// Update LR to reflect an instruction has been moved upwards from OldIdx - /// to NewIdx (NewIdx < OldIdx). + /// to NewIdx. + /// + /// 1. Live def at OldIdx: + /// Hoist def to NewIdx. + /// + /// 2. Dead def at OldIdx: + /// Hoist def+end to NewIdx, possibly move across other values. + /// + /// 3. Dead def at OldIdx AND existing def at NewIdx: + /// Remove value defined at OldIdx, coalescing it with existing value. + /// + /// 4. Live def at OldIdx AND existing def at NewIdx: + /// Remove value defined at NewIdx, hoist OldIdx def to NewIdx. + /// (Happens when bundling multiple defs together). + /// + /// 5. Value killed at OldIdx: + /// Hoist kill to NewIdx, then scan for last kill between NewIdx and + /// OldIdx. + /// void handleMoveUp(LiveRange &LR, unsigned Reg, LaneBitmask LaneMask) { + // First look for a kill at OldIdx. + LiveRange::iterator I = LR.find(OldIdx.getBaseIndex()); LiveRange::iterator E = LR.end(); - // Segment going into OldIdx. - LiveRange::iterator OldIdxIn = LR.find(OldIdx.getBaseIndex()); - - // No value live before or after OldIdx? Nothing to do. - if (OldIdxIn == E || SlotIndex::isEarlierInstr(OldIdx, OldIdxIn->start)) + // Is LR even live at OldIdx? + if (I == E || SlotIndex::isEarlierInstr(OldIdx, I->start)) return; - LiveRange::iterator OldIdxOut; - // Do we have a value live-in to OldIdx? - if (SlotIndex::isEarlierInstr(OldIdxIn->start, OldIdx)) { - // If the live-in value isn't killed here, then we have no Def at - // OldIdx, moreover the value must be live at NewIdx so there is nothing - // to do. - bool isKill = SlotIndex::isSameInstr(OldIdx, OldIdxIn->end); - if (!isKill) + // Handle a live-in value. + if (!SlotIndex::isSameInstr(I->start, OldIdx)) { + // If the live-in value isn't killed here, there is nothing to do. + if (!SlotIndex::isSameInstr(OldIdx, I->end)) return; - - // At this point we have to move OldIdxIn->end back to the nearest - // previous use or (dead-)def but no further than NewIdx. - SlotIndex DefBeforeOldIdx - = std::max(OldIdxIn->start.getDeadSlot(), - NewIdx.getRegSlot(OldIdxIn->end.isEarlyClobber())); - OldIdxIn->end = findLastUseBefore(DefBeforeOldIdx, Reg, LaneMask); - - // Did we have a Def at OldIdx? If not we are done now. - OldIdxOut = std::next(OldIdxIn); - if (OldIdxOut == E || !SlotIndex::isSameInstr(OldIdx, OldIdxOut->start)) + // Adjust I->end to end at NewIdx. If we are hoisting a kill above + // another use, we need to search for that use. Case 5 above. + I->end = NewIdx.getRegSlot(I->end.isEarlyClobber()); + ++I; + // If OldIdx also defines a value, there couldn't have been another use. + if (I == E || !SlotIndex::isSameInstr(I->start, OldIdx)) { + // No def, search for the new kill. + // This can never be an early clobber kill since there is no def. + std::prev(I)->end = findLastUseBefore(Reg, LaneMask).getRegSlot(); return; - } else { - OldIdxOut = OldIdxIn; - OldIdxIn = OldIdxOut != LR.begin() ? std::prev(OldIdxOut) : E; + } } - // If we are here then there is a Definition at OldIdx. OldIdxOut points - // to the segment starting there. - assert(OldIdxOut != E && SlotIndex::isSameInstr(OldIdx, OldIdxOut->start) && - "No def?"); - VNInfo *OldIdxVNI = OldIdxOut->valno; - assert(OldIdxVNI->def == OldIdxOut->start && "Inconsistent def"); - bool OldIdxDefIsDead = OldIdxOut->end.isDead(); - - // Is there an existing def at NewIdx? - SlotIndex NewIdxDef = NewIdx.getRegSlot(OldIdxOut->start.isEarlyClobber()); - LiveRange::iterator NewIdxOut = LR.find(NewIdx.getRegSlot()); - if (SlotIndex::isSameInstr(NewIdxOut->start, NewIdx)) { - assert(NewIdxOut->valno != OldIdxVNI && - "Same value defined more than once?"); - // If OldIdx was a dead def remove it. - if (!OldIdxDefIsDead) { - // Remove segment starting at NewIdx and move begin of OldIdxOut to - // NewIdx so it can take its place. - OldIdxVNI->def = NewIdxDef; - OldIdxOut->start = NewIdxDef; - LR.removeValNo(NewIdxOut->valno); - } else { - // Simply remove the dead def at OldIdx. - LR.removeValNo(OldIdxVNI); - } - } else { - // Previously nothing was live after NewIdx, so all we have to do now is - // move the begin of OldIdxOut to NewIdx. - if (!OldIdxDefIsDead) { - // Do we have any intermediate Defs between OldIdx and NewIdx? - if (OldIdxIn != E && - SlotIndex::isEarlierInstr(NewIdxDef, OldIdxIn->start)) { - // OldIdx is not a dead def and NewIdx is before predecessor start. - LiveRange::iterator NewIdxIn = NewIdxOut; - assert(NewIdxIn == LR.find(NewIdx.getBaseIndex())); - const SlotIndex SplitPos = NewIdxDef; - OldIdxVNI = OldIdxIn->valno; - - // Merge the OldIdxIn and OldIdxOut segments into OldIdxOut. - OldIdxOut->valno->def = OldIdxIn->start; - *OldIdxOut = LiveRange::Segment(OldIdxIn->start, OldIdxOut->end, - OldIdxOut->valno); - // OldIdxIn and OldIdxVNI are now undef and can be overridden. - // We Slide [NewIdxIn, OldIdxIn) down one position. - // |- X0/NewIdxIn -| ... |- Xn-1 -||- Xn/OldIdxIn -||- OldIdxOut -| - // => |- undef/NexIdxIn -| |- X0 -| ... |- Xn-1 -| |- Xn/OldIdxOut -| - std::copy_backward(NewIdxIn, OldIdxIn, OldIdxOut); - // NewIdxIn is now considered undef so we can reuse it for the moved - // value. - LiveRange::iterator NewSegment = NewIdxIn; - LiveRange::iterator Next = std::next(NewSegment); - if (SlotIndex::isEarlierInstr(Next->start, NewIdx)) { - // There is no gap between NewSegment and its predecessor. - *NewSegment = LiveRange::Segment(Next->start, SplitPos, - Next->valno); - *Next = LiveRange::Segment(SplitPos, Next->end, OldIdxVNI); - Next->valno->def = SplitPos; - } else { - // There is a gap between NewSegment and its predecessor - // Value becomes live in. - *NewSegment = LiveRange::Segment(SplitPos, Next->start, OldIdxVNI); - NewSegment->valno->def = SplitPos; - } - } else { - // Leave the end point of a live def. - OldIdxOut->start = NewIdxDef; - OldIdxVNI->def = NewIdxDef; - if (OldIdxIn != E && SlotIndex::isEarlierInstr(NewIdx, OldIdxIn->end)) - OldIdxIn->end = NewIdx.getRegSlot(); - } - } else { - // OldIdxVNI is a dead def. It may have been moved across other values - // in LR, so move OldIdxOut up to NewIdxOut. Slide [NewIdxOut;OldIdxOut) - // down one position. - // |- X0/NewIdxOut -| ... |- Xn-1 -| |- Xn/OldIdxOut -| |- next - | - // => |- undef/NewIdxOut -| |- X0 -| ... |- Xn-1 -| |- next -| - std::copy_backward(NewIdxOut, OldIdxOut, std::next(OldIdxOut)); - // OldIdxVNI can be reused now to build a new dead def segment. - LiveRange::iterator NewSegment = NewIdxOut; - VNInfo *NewSegmentVNI = OldIdxVNI; - *NewSegment = LiveRange::Segment(NewIdxDef, NewIdxDef.getDeadSlot(), - NewSegmentVNI); - NewSegmentVNI->def = NewIdxDef; + // Now deal with the def at OldIdx. + assert(I != E && SlotIndex::isSameInstr(I->start, OldIdx) && "No def?"); + VNInfo *DefVNI = I->valno; + assert(DefVNI->def == I->start && "Inconsistent def"); + DefVNI->def = NewIdx.getRegSlot(I->start.isEarlyClobber()); + + // Check for an existing def at NewIdx. + LiveRange::iterator NewI = LR.find(NewIdx.getRegSlot()); + if (SlotIndex::isSameInstr(NewI->start, NewIdx)) { + assert(NewI->valno != DefVNI && "Same value defined more than once?"); + // There is an existing def at NewIdx. + if (I->end.isDead()) { + // Case 3: Remove the dead def at OldIdx. + LR.removeValNo(DefVNI); + return; } + // Case 4: Replace def at NewIdx with live def at OldIdx. + I->start = DefVNI->def; + LR.removeValNo(NewI->valno); + return; + } + + // There is no existing def at NewIdx. Hoist DefVNI. + if (!I->end.isDead()) { + // Leave the end point of a live def. + I->start = DefVNI->def; + return; } + + // DefVNI is a dead def. It may have been moved across other values in LR, + // so move I up to NewI. Slide [NewI;I) down one position. + std::copy_backward(NewI, I, std::next(I)); + *NewI = LiveRange::Segment(DefVNI->def, NewIdx.getDeadSlot(), DefVNI); } void updateRegMaskSlots() { @@ -1318,31 +1205,29 @@ private: } // Return the last use of reg between NewIdx and OldIdx. - SlotIndex findLastUseBefore(SlotIndex Before, unsigned Reg, - LaneBitmask LaneMask) { + SlotIndex findLastUseBefore(unsigned Reg, LaneBitmask LaneMask) { + if (TargetRegisterInfo::isVirtualRegister(Reg)) { - SlotIndex LastUse = Before; + SlotIndex LastUse = NewIdx; for (MachineOperand &MO : MRI.use_nodbg_operands(Reg)) { - if (MO.isUndef()) - continue; unsigned SubReg = MO.getSubReg(); - if (SubReg != 0 && LaneMask.any() - && (TRI.getSubRegIndexLaneMask(SubReg) & LaneMask).none()) + if (SubReg != 0 && LaneMask != 0 + && (TRI.getSubRegIndexLaneMask(SubReg) & LaneMask) == 0) continue; - const MachineInstr &MI = *MO.getParent(); + const MachineInstr *MI = MO.getParent(); SlotIndex InstSlot = LIS.getSlotIndexes()->getInstructionIndex(MI); if (InstSlot > LastUse && InstSlot < OldIdx) - LastUse = InstSlot.getRegSlot(); + LastUse = InstSlot; } return LastUse; } // This is a regunit interval, so scanning the use list could be very // expensive. Scan upwards from OldIdx instead. - assert(Before < OldIdx && "Expected upwards move"); + assert(NewIdx < OldIdx && "Expected upwards move"); SlotIndexes *Indexes = LIS.getSlotIndexes(); - MachineBasicBlock *MBB = Indexes->getMBBFromIndex(Before); + MachineBasicBlock *MBB = Indexes->getMBBFromIndex(NewIdx); // OldIdx may not correspond to an instruction any longer, so set MII to // point to the next instruction after OldIdx, or MBB->end(). @@ -1356,44 +1241,44 @@ private: while (MII != Begin) { if ((--MII)->isDebugValue()) continue; - SlotIndex Idx = Indexes->getInstructionIndex(*MII); + SlotIndex Idx = Indexes->getInstructionIndex(MII); - // Stop searching when Before is reached. - if (!SlotIndex::isEarlierInstr(Before, Idx)) - return Before; + // Stop searching when NewIdx is reached. + if (!SlotIndex::isEarlierInstr(NewIdx, Idx)) + return NewIdx; // Check if MII uses Reg. - for (MIBundleOperands MO(*MII); MO.isValid(); ++MO) - if (MO->isReg() && !MO->isUndef() && + for (MIBundleOperands MO(MII); MO.isValid(); ++MO) + if (MO->isReg() && TargetRegisterInfo::isPhysicalRegister(MO->getReg()) && TRI.hasRegUnit(MO->getReg(), Reg)) - return Idx.getRegSlot(); + return Idx; } - // Didn't reach Before. It must be the first instruction in the block. - return Before; + // Didn't reach NewIdx. It must be the first instruction in the block. + return NewIdx; } }; -void LiveIntervals::handleMove(MachineInstr &MI, bool UpdateFlags) { - assert(!MI.isBundled() && "Can't handle bundled instructions yet."); +void LiveIntervals::handleMove(MachineInstr* MI, bool UpdateFlags) { + assert(!MI->isBundled() && "Can't handle bundled instructions yet."); SlotIndex OldIndex = Indexes->getInstructionIndex(MI); Indexes->removeMachineInstrFromMaps(MI); SlotIndex NewIndex = Indexes->insertMachineInstrInMaps(MI); - assert(getMBBStartIdx(MI.getParent()) <= OldIndex && - OldIndex < getMBBEndIdx(MI.getParent()) && + assert(getMBBStartIdx(MI->getParent()) <= OldIndex && + OldIndex < getMBBEndIdx(MI->getParent()) && "Cannot handle moves across basic block boundaries."); HMEditor HME(*this, *MRI, *TRI, OldIndex, NewIndex, UpdateFlags); - HME.updateAllRanges(&MI); + HME.updateAllRanges(MI); } -void LiveIntervals::handleMoveIntoBundle(MachineInstr &MI, - MachineInstr &BundleStart, +void LiveIntervals::handleMoveIntoBundle(MachineInstr* MI, + MachineInstr* BundleStart, bool UpdateFlags) { SlotIndex OldIndex = Indexes->getInstructionIndex(MI); SlotIndex NewIndex = Indexes->getInstructionIndex(BundleStart); HMEditor HME(*this, *MRI, *TRI, OldIndex, NewIndex, UpdateFlags); - HME.updateAllRanges(&MI); + HME.updateAllRanges(MI); } void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin, @@ -1403,11 +1288,6 @@ void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin, LaneBitmask LaneMask) { LiveInterval::iterator LII = LR.find(endIdx); SlotIndex lastUseIdx; - if (LII == LR.begin()) { - // This happens when the function is called for a subregister that only - // occurs _after_ the range that is to be repaired. - return; - } if (LII != LR.end() && LII->start < endIdx) lastUseIdx = LII->end; else @@ -1415,8 +1295,8 @@ void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin, for (MachineBasicBlock::iterator I = End; I != Begin;) { --I; - MachineInstr &MI = *I; - if (MI.isDebugValue()) + MachineInstr *MI = I; + if (MI->isDebugValue()) continue; SlotIndex instrIdx = getInstructionIndex(MI); @@ -1425,16 +1305,15 @@ void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin, // FIXME: This doesn't currently handle early-clobber or multiple removed // defs inside of the region to repair. - for (MachineInstr::mop_iterator OI = MI.operands_begin(), - OE = MI.operands_end(); - OI != OE; ++OI) { + for (MachineInstr::mop_iterator OI = MI->operands_begin(), + OE = MI->operands_end(); OI != OE; ++OI) { const MachineOperand &MO = *OI; if (!MO.isReg() || MO.getReg() != Reg) continue; unsigned SubReg = MO.getSubReg(); LaneBitmask Mask = TRI->getSubRegIndexLaneMask(SubReg); - if ((Mask & LaneMask).none()) + if ((Mask & LaneMask) == 0) continue; if (MO.isDef()) { @@ -1497,27 +1376,26 @@ LiveIntervals::repairIntervalsInRange(MachineBasicBlock *MBB, ArrayRef<unsigned> OrigRegs) { // Find anchor points, which are at the beginning/end of blocks or at // instructions that already have indexes. - while (Begin != MBB->begin() && !Indexes->hasIndex(*Begin)) + while (Begin != MBB->begin() && !Indexes->hasIndex(Begin)) --Begin; - while (End != MBB->end() && !Indexes->hasIndex(*End)) + while (End != MBB->end() && !Indexes->hasIndex(End)) ++End; SlotIndex endIdx; if (End == MBB->end()) endIdx = getMBBEndIdx(MBB).getPrevSlot(); else - endIdx = getInstructionIndex(*End); + endIdx = getInstructionIndex(End); Indexes->repairIndexesInRange(MBB, Begin, End); for (MachineBasicBlock::iterator I = End; I != Begin;) { --I; - MachineInstr &MI = *I; - if (MI.isDebugValue()) + MachineInstr *MI = I; + if (MI->isDebugValue()) continue; - for (MachineInstr::const_mop_iterator MOI = MI.operands_begin(), - MOE = MI.operands_end(); - MOI != MOE; ++MOI) { + for (MachineInstr::const_mop_iterator MOI = MI->operands_begin(), + MOE = MI->operands_end(); MOI != MOE; ++MOI) { if (MOI->isReg() && TargetRegisterInfo::isVirtualRegister(MOI->getReg()) && !hasInterval(MOI->getReg())) { @@ -1526,7 +1404,8 @@ LiveIntervals::repairIntervalsInRange(MachineBasicBlock *MBB, } } - for (unsigned Reg : OrigRegs) { + for (unsigned i = 0, e = OrigRegs.size(); i != e; ++i) { + unsigned Reg = OrigRegs[i]; if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; @@ -1535,35 +1414,31 @@ LiveIntervals::repairIntervalsInRange(MachineBasicBlock *MBB, if (!LI.hasAtLeastOneValue()) continue; - for (LiveInterval::SubRange &S : LI.subranges()) + for (LiveInterval::SubRange &S : LI.subranges()) { repairOldRegInRange(Begin, End, endIdx, S, Reg, S.LaneMask); - + } repairOldRegInRange(Begin, End, endIdx, LI, Reg); } } void LiveIntervals::removePhysRegDefAt(unsigned Reg, SlotIndex Pos) { - for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) { - if (LiveRange *LR = getCachedRegUnit(*Unit)) + for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units) { + if (LiveRange *LR = getCachedRegUnit(*Units)) if (VNInfo *VNI = LR->getVNInfoAt(Pos)) LR->removeValNo(VNI); } } void LiveIntervals::removeVRegDefAt(LiveInterval &LI, SlotIndex Pos) { - // LI may not have the main range computed yet, but its subranges may - // be present. VNInfo *VNI = LI.getVNInfoAt(Pos); - if (VNI != nullptr) { - assert(VNI->def.getBaseIndex() == Pos.getBaseIndex()); - LI.removeValNo(VNI); - } + if (VNI == nullptr) + return; + LI.removeValNo(VNI); - // Also remove the value defined in subranges. + // Also remove the value in subranges. for (LiveInterval::SubRange &S : LI.subranges()) { if (VNInfo *SVNI = S.getVNInfoAt(Pos)) - if (SVNI->def.getBaseIndex() == Pos.getBaseIndex()) - S.removeValNo(SVNI); + S.removeValNo(SVNI); } LI.removeEmptySubRanges(); } @@ -1584,9 +1459,3 @@ void LiveIntervals::splitSeparateComponents(LiveInterval &LI, } ConEQ.Distribute(LI, SplitLIs.data(), *MRI); } - -void LiveIntervals::constructMainRangeFromSubranges(LiveInterval &LI) { - assert(LRCalc && "LRCalc not initialized."); - LRCalc->reset(MF, getSlotIndexes(), DomTree, &getVNInfoAllocator()); - LRCalc->constructMainRangeFromSubranges(LI); -} diff --git a/gnu/llvm/lib/CodeGen/LiveStackAnalysis.cpp b/gnu/llvm/lib/CodeGen/LiveStackAnalysis.cpp index b51f8b0aa6b..5c9c679e97b 100644 --- a/gnu/llvm/lib/CodeGen/LiveStackAnalysis.cpp +++ b/gnu/llvm/lib/CodeGen/LiveStackAnalysis.cpp @@ -14,21 +14,23 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include <limits> using namespace llvm; #define DEBUG_TYPE "livestacks" char LiveStacks::ID = 0; -INITIALIZE_PASS_BEGIN(LiveStacks, DEBUG_TYPE, +INITIALIZE_PASS_BEGIN(LiveStacks, "livestacks", "Live Stack Slot Analysis", false, false) INITIALIZE_PASS_DEPENDENCY(SlotIndexes) -INITIALIZE_PASS_END(LiveStacks, DEBUG_TYPE, +INITIALIZE_PASS_END(LiveStacks, "livestacks", "Live Stack Slot Analysis", false, false) char &llvm::LiveStacksID = LiveStacks::ID; diff --git a/gnu/llvm/lib/Fuzzer/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/CMakeLists.txt index bc744890b99..d4d85041d21 100644 --- a/gnu/llvm/lib/Fuzzer/CMakeLists.txt +++ b/gnu/llvm/lib/Fuzzer/CMakeLists.txt @@ -1,68 +1,34 @@ -include(CheckCXXSourceCompiles) - -if( APPLE ) - CHECK_CXX_SOURCE_COMPILES(" - static thread_local int blah; - int main() { - return 0; - } - " HAS_THREAD_LOCAL) - - if( NOT HAS_THREAD_LOCAL ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dthread_local=__thread") - endif() -endif() - -set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}") +set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS_RELEASE}") +# Disable the coverage and sanitizer instrumentation for the fuzzer itself. +set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O2 -fno-sanitize=all") if( LLVM_USE_SANITIZE_COVERAGE ) - if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address") - message(FATAL_ERROR - "LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and " - "LLVM_USE_SANITIZE_COVERAGE=YES to be set." - ) - endif() - - # Disable the coverage and sanitizer instrumentation for the fuzzer itself. - set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters -Werror") -endif() - -# Compile libFuzzer if the compilation is specifically requested, OR -# if the platform is known to be working. -if ( LLVM_USE_SANITIZE_COVERAGE OR CMAKE_SYSTEM_NAME MATCHES "Darwin|Linux" ) add_library(LLVMFuzzerNoMainObjects OBJECT - FuzzerCrossOver.cpp - FuzzerDriver.cpp - FuzzerExtFunctionsDlsym.cpp - FuzzerExtFunctionsDlsymWin.cpp - FuzzerExtFunctionsWeak.cpp - FuzzerExtraCounters.cpp - FuzzerIO.cpp - FuzzerIOPosix.cpp - FuzzerIOWindows.cpp - FuzzerLoop.cpp - FuzzerMerge.cpp - FuzzerMutate.cpp - FuzzerSHA1.cpp - FuzzerShmemPosix.cpp - FuzzerShmemWindows.cpp - FuzzerTracePC.cpp - FuzzerUtil.cpp - FuzzerUtilDarwin.cpp - FuzzerUtilLinux.cpp - FuzzerUtilPosix.cpp - FuzzerUtilWindows.cpp - ) + FuzzerCrossOver.cpp + FuzzerInterface.cpp + FuzzerTraceState.cpp + FuzzerDriver.cpp + FuzzerIO.cpp + FuzzerLoop.cpp + FuzzerMutate.cpp + FuzzerSanitizerOptions.cpp + FuzzerSHA1.cpp + FuzzerUtil.cpp + ) add_library(LLVMFuzzerNoMain STATIC - $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> - ) - target_link_libraries(LLVMFuzzerNoMain ${LLVM_PTHREAD_LIB}) + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> + ) + if( HAVE_LIBPTHREAD ) + target_link_libraries(LLVMFuzzerNoMain pthread) + endif() add_library(LLVMFuzzer STATIC - FuzzerMain.cpp - $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> - ) - target_link_libraries(LLVMFuzzer ${LLVM_PTHREAD_LIB}) -endif() + FuzzerMain.cpp + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> + ) + if( HAVE_LIBPTHREAD ) + target_link_libraries(LLVMFuzzer pthread) + endif() -if( LLVM_USE_SANITIZE_COVERAGE AND LLVM_INCLUDE_TESTS ) - add_subdirectory(test) + if( LLVM_INCLUDE_TESTS ) + add_subdirectory(test) + endif() endif() diff --git a/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp index 8b0fd7d529a..5203deaf912 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerCrossOver.cpp @@ -9,11 +9,10 @@ // Cross over test inputs. //===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" #include <cstring> +#include "FuzzerInternal.h" + namespace fuzzer { // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out. diff --git a/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp index fd8cab38a7b..66e46dbf3aa 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -9,25 +9,19 @@ // FuzzerDriver and flag parsing. //===----------------------------------------------------------------------===// -#include "FuzzerCorpus.h" -#include "FuzzerIO.h" #include "FuzzerInterface.h" #include "FuzzerInternal.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerShmem.h" -#include "FuzzerTracePC.h" -#include <algorithm> -#include <atomic> -#include <chrono> + #include <cstring> +#include <chrono> +#include <unistd.h> +#include <thread> +#include <atomic> #include <mutex> #include <string> -#include <thread> - -// This function should be present in the libFuzzer so that the client -// binary can test for its existence. -extern "C" __attribute__((used)) void __libfuzzer_is_present() {} +#include <sstream> +#include <algorithm> +#include <iterator> namespace fuzzer { @@ -42,20 +36,16 @@ struct FlagDescription { }; struct { -#define FUZZER_DEPRECATED_FLAG(Name) #define FUZZER_FLAG_INT(Name, Default, Description) int Name; #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name; #define FUZZER_FLAG_STRING(Name, Description) const char *Name; #include "FuzzerFlags.def" -#undef FUZZER_DEPRECATED_FLAG #undef FUZZER_FLAG_INT #undef FUZZER_FLAG_UNSIGNED #undef FUZZER_FLAG_STRING } Flags; static const FlagDescription FlagDescriptions [] { -#define FUZZER_DEPRECATED_FLAG(Name) \ - {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr}, #define FUZZER_FLAG_INT(Name, Default, Description) \ {#Name, Description, Default, &Flags.Name, nullptr, nullptr}, #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \ @@ -64,7 +54,6 @@ static const FlagDescription FlagDescriptions [] { #define FUZZER_FLAG_STRING(Name, Description) \ {#Name, Description, 0, nullptr, &Flags.Name, nullptr}, #include "FuzzerFlags.def" -#undef FUZZER_DEPRECATED_FLAG #undef FUZZER_FLAG_INT #undef FUZZER_FLAG_UNSIGNED #undef FUZZER_FLAG_STRING @@ -77,14 +66,8 @@ static std::vector<std::string> *Inputs; static std::string *ProgName; static void PrintHelp() { - Printf("Usage:\n"); - auto Prog = ProgName->c_str(); - Printf("\nTo run fuzzing pass 0 or more directories.\n"); - Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog); - - Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n"); - Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog); - + Printf("Usage: %s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", + ProgName->c_str()); Printf("\nFlags: (strictly in form -flag=value)\n"); size_t MaxFlagLen = 0; for (size_t F = 0; F < kNumFlags; F++) @@ -92,7 +75,6 @@ static void PrintHelp() { for (size_t F = 0; F < kNumFlags; F++) { const auto &D = FlagDescriptions[F]; - if (strstr(D.Description, "internal flag") == D.Description) continue; Printf(" %s", D.Name); for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++) Printf(" "); @@ -111,34 +93,14 @@ static const char *FlagValue(const char *Param, const char *Name) { return nullptr; } -// Avoid calling stol as it triggers a bug in clang/glibc build. -static long MyStol(const char *Str) { - long Res = 0; - long Sign = 1; - if (*Str == '-') { - Str++; - Sign = -1; - } - for (size_t i = 0; Str[i]; i++) { - char Ch = Str[i]; - if (Ch < '0' || Ch > '9') - return Res; - Res = Res * 10 + (Ch - '0'); - } - return Res * Sign; -} - static bool ParseOneFlag(const char *Param) { if (Param[0] != '-') return false; if (Param[1] == '-') { static bool PrintedWarning = false; if (!PrintedWarning) { PrintedWarning = true; - Printf("INFO: libFuzzer ignores flags that start with '--'\n"); + Printf("WARNING: libFuzzer ignores flags that start with '--'\n"); } - for (size_t F = 0; F < kNumFlags; F++) - if (FlagValue(Param + 1, FlagDescriptions[F].Name)) - Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1); return true; } for (size_t F = 0; F < kNumFlags; F++) { @@ -146,10 +108,10 @@ static bool ParseOneFlag(const char *Param) { const char *Str = FlagValue(Param, Name); if (Str) { if (FlagDescriptions[F].IntFlag) { - int Val = MyStol(Str); + int Val = std::stol(Str); *FlagDescriptions[F].IntFlag = Val; if (Flags.verbosity >= 2) - Printf("Flag: %s %d\n", Name, Val); + Printf("Flag: %s %d\n", Name, Val);; return true; } else if (FlagDescriptions[F].UIntFlag) { unsigned int Val = std::stoul(Str); @@ -162,15 +124,11 @@ static bool ParseOneFlag(const char *Param) { if (Flags.verbosity >= 2) Printf("Flag: %s %s\n", Name, Str); return true; - } else { // Deprecated flag. - Printf("Flag: %s: deprecated, don't use\n", Name); - return true; } } } - Printf("\n\nWARNING: unrecognized flag '%s'; " - "use -help=1 to list all flags\n\n", Param); - return true; + PrintHelp(); + exit(1); } // We don't use any library to minimize dependencies. @@ -186,11 +144,7 @@ static void ParseFlags(const std::vector<std::string> &Args) { } Inputs = new std::vector<std::string>; for (size_t A = 1; A < Args.size(); A++) { - if (ParseOneFlag(Args[A].c_str())) { - if (Flags.ignore_remaining_args) - break; - continue; - } + if (ParseOneFlag(Args[A].c_str())) continue; Inputs->push_back(Args[A]); } } @@ -199,396 +153,120 @@ static std::mutex Mu; static void PulseThread() { while (true) { - SleepSeconds(600); + std::this_thread::sleep_for(std::chrono::seconds(600)); std::lock_guard<std::mutex> Lock(Mu); Printf("pulse...\n"); } } -static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter, - unsigned NumJobs, std::atomic<bool> *HasErrors) { +static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter, + int NumJobs, std::atomic<bool> *HasErrors) { while (true) { - unsigned C = (*Counter)++; + int C = (*Counter)++; if (C >= NumJobs) break; std::string Log = "fuzz-" + std::to_string(C) + ".log"; std::string ToRun = Cmd + " > " + Log + " 2>&1\n"; if (Flags.verbosity) Printf("%s", ToRun.c_str()); - int ExitCode = ExecuteCommand(ToRun); + int ExitCode = ExecuteCommand(ToRun.c_str()); if (ExitCode != 0) *HasErrors = true; std::lock_guard<std::mutex> Lock(Mu); - Printf("================== Job %u exited with exit code %d ============\n", + Printf("================== Job %d exited with exit code %d ============\n", C, ExitCode); fuzzer::CopyFileToErr(Log); } } -std::string CloneArgsWithoutX(const std::vector<std::string> &Args, - const char *X1, const char *X2) { +static int RunInMultipleProcesses(const std::vector<std::string> &Args, + int NumWorkers, int NumJobs) { + std::atomic<int> Counter(0); + std::atomic<bool> HasErrors(false); std::string Cmd; for (auto &S : Args) { - if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2)) + if (FlagValue(S.c_str(), "jobs") || FlagValue(S.c_str(), "workers")) continue; Cmd += S + " "; } - return Cmd; -} - -static int RunInMultipleProcesses(const std::vector<std::string> &Args, - unsigned NumWorkers, unsigned NumJobs) { - std::atomic<unsigned> Counter(0); - std::atomic<bool> HasErrors(false); - std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers"); std::vector<std::thread> V; std::thread Pulse(PulseThread); Pulse.detach(); - for (unsigned i = 0; i < NumWorkers; i++) + for (int i = 0; i < NumWorkers; i++) V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors)); for (auto &T : V) T.join(); return HasErrors ? 1 : 0; } -static void RssThread(Fuzzer *F, size_t RssLimitMb) { - while (true) { - SleepSeconds(1); - size_t Peak = GetPeakRSSMb(); - if (Peak > RssLimitMb) - F->RssLimitCallback(); - } -} - -static void StartRssThread(Fuzzer *F, size_t RssLimitMb) { - if (!RssLimitMb) return; - std::thread T(RssThread, F, RssLimitMb); - T.detach(); -} - -int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) { +int RunOneTest(Fuzzer *F, const char *InputFilePath) { Unit U = FileToVector(InputFilePath); - if (MaxLen && MaxLen < U.size()) - U.resize(MaxLen); - F->ExecuteCallback(U.data(), U.size()); - F->TryDetectingAMemoryLeak(U.data(), U.size(), true); - return 0; -} - -static bool AllInputsAreFiles() { - if (Inputs->empty()) return false; - for (auto &Path : *Inputs) - if (!IsFile(Path)) - return false; - return true; -} - -static std::string GetDedupTokenFromFile(const std::string &Path) { - auto S = FileToString(Path); - auto Beg = S.find("DEDUP_TOKEN:"); - if (Beg == std::string::npos) - return ""; - auto End = S.find('\n', Beg); - if (End == std::string::npos) - return ""; - return S.substr(Beg, End - Beg); -} - -int CleanseCrashInput(const std::vector<std::string> &Args, - const FuzzingOptions &Options) { - if (Inputs->size() != 1 || !Flags.exact_artifact_path) { - Printf("ERROR: -cleanse_crash should be given one input file and" - " -exact_artifact_path\n"); - exit(1); - } - std::string InputFilePath = Inputs->at(0); - std::string OutputFilePath = Flags.exact_artifact_path; - std::string BaseCmd = - CloneArgsWithoutX(Args, "cleanse_crash", "cleanse_crash"); - - auto InputPos = BaseCmd.find(" " + InputFilePath + " "); - assert(InputPos != std::string::npos); - BaseCmd.erase(InputPos, InputFilePath.size() + 1); - - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - auto TmpFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro"); - auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; - - auto Cmd = BaseCmd + " " + TmpFilePath + LogFileRedirect; - - std::string CurrentFilePath = InputFilePath; - auto U = FileToVector(CurrentFilePath); - size_t Size = U.size(); - - const std::vector<uint8_t> ReplacementBytes = {' ', 0xff}; - for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { - bool Changed = false; - for (size_t Idx = 0; Idx < Size; Idx++) { - Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts, - Idx, Size); - uint8_t OriginalByte = U[Idx]; - if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(), - ReplacementBytes.end(), - OriginalByte)) - continue; - for (auto NewByte : ReplacementBytes) { - U[Idx] = NewByte; - WriteToFile(U, TmpFilePath); - auto ExitCode = ExecuteCommand(Cmd); - RemoveFile(TmpFilePath); - if (!ExitCode) { - U[Idx] = OriginalByte; - } else { - Changed = true; - Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte); - WriteToFile(U, OutputFilePath); - break; - } - } - } - if (!Changed) break; - } - RemoveFile(LogFilePath); + Unit PreciseSizedU(U); + assert(PreciseSizedU.size() == PreciseSizedU.capacity()); + F->ExecuteCallback(PreciseSizedU); return 0; } -int MinimizeCrashInput(const std::vector<std::string> &Args, - const FuzzingOptions &Options) { - if (Inputs->size() != 1) { - Printf("ERROR: -minimize_crash should be given one input file\n"); - exit(1); - } - std::string InputFilePath = Inputs->at(0); - auto BaseCmd = SplitBefore( - "-ignore_remaining_args=1", - CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path")); - auto InputPos = BaseCmd.first.find(" " + InputFilePath + " "); - assert(InputPos != std::string::npos); - BaseCmd.first.erase(InputPos, InputFilePath.size() + 1); - if (Flags.runs <= 0 && Flags.max_total_time == 0) { - Printf("INFO: you need to specify -runs=N or " - "-max_total_time=N with -minimize_crash=1\n" - "INFO: defaulting to -max_total_time=600\n"); - BaseCmd.first += " -max_total_time=600"; - } - - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - auto LogFileRedirect = " > " + LogFilePath + " 2>&1 "; - - std::string CurrentFilePath = InputFilePath; - while (true) { - Unit U = FileToVector(CurrentFilePath); - Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n", - CurrentFilePath.c_str(), U.size()); - - auto Cmd = BaseCmd.first + " " + CurrentFilePath + LogFileRedirect + " " + - BaseCmd.second; - - Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); - int ExitCode = ExecuteCommand(Cmd); - if (ExitCode == 0) { - Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str()); - exit(1); - } - Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize " - "it further\n", - CurrentFilePath.c_str(), U.size()); - auto DedupToken1 = GetDedupTokenFromFile(LogFilePath); - if (!DedupToken1.empty()) - Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str()); - - std::string ArtifactPath = - Flags.exact_artifact_path - ? Flags.exact_artifact_path - : Options.ArtifactPrefix + "minimized-from-" + Hash(U); - Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" + - ArtifactPath; - Printf("CRASH_MIN: executing: %s\n", Cmd.c_str()); - ExitCode = ExecuteCommand(Cmd); - CopyFileToErr(LogFilePath); - if (ExitCode == 0) { - if (Flags.exact_artifact_path) { - CurrentFilePath = Flags.exact_artifact_path; - WriteToFile(U, CurrentFilePath); - } - Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n", - CurrentFilePath.c_str(), U.size()); - break; - } - auto DedupToken2 = GetDedupTokenFromFile(LogFilePath); - if (!DedupToken2.empty()) - Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str()); - - if (DedupToken1 != DedupToken2) { - if (Flags.exact_artifact_path) { - CurrentFilePath = Flags.exact_artifact_path; - WriteToFile(U, CurrentFilePath); - } - Printf("CRASH_MIN: mismatch in dedup tokens" - " (looks like a different bug). Won't minimize further\n"); - break; - } - - CurrentFilePath = ArtifactPath; - Printf("*********************************\n"); - } - RemoveFile(LogFilePath); - return 0; +int FuzzerDriver(int argc, char **argv, UserCallback Callback) { + FuzzerRandomLibc Rand(0); + SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); + return FuzzerDriver(argc, argv, SUSF); } -int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { - assert(Inputs->size() == 1); - std::string InputFilePath = Inputs->at(0); - Unit U = FileToVector(InputFilePath); - Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size()); - if (U.size() < 2) { - Printf("INFO: The input is small enough, exiting\n"); - exit(0); - } - F->SetMaxInputLen(U.size()); - F->SetMaxMutationLen(U.size() - 1); - F->MinimizeCrashLoop(U); - Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n"); - exit(0); - return 0; +int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) { + std::vector<std::string> Args(argv, argv + argc); + return FuzzerDriver(Args, USF); } -int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit>& Dict, - UnitVector& Corpus) { - Printf("Started dictionary minimization (up to %d tests)\n", - Dict.size() * Corpus.size() * 2); - - // Scores and usage count for each dictionary unit. - std::vector<int> Scores(Dict.size()); - std::vector<int> Usages(Dict.size()); - - std::vector<size_t> InitialFeatures; - std::vector<size_t> ModifiedFeatures; - for (auto &C : Corpus) { - // Get coverage for the testcase without modifications. - F->ExecuteCallback(C.data(), C.size()); - InitialFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { - InitialFeatures.push_back(Feature); - return true; - }); - - for (size_t i = 0; i < Dict.size(); ++i) { - auto Data = C; - auto StartPos = std::search(Data.begin(), Data.end(), - Dict[i].begin(), Dict[i].end()); - // Skip dictionary unit, if the testcase does not contain it. - if (StartPos == Data.end()) - continue; - - ++Usages[i]; - while (StartPos != Data.end()) { - // Replace all occurrences of dictionary unit in the testcase. - auto EndPos = StartPos + Dict[i].size(); - for (auto It = StartPos; It != EndPos; ++It) - *It ^= 0xFF; - - StartPos = std::search(EndPos, Data.end(), - Dict[i].begin(), Dict[i].end()); - } - - // Get coverage for testcase with masked occurrences of dictionary unit. - F->ExecuteCallback(Data.data(), Data.size()); - ModifiedFeatures.clear(); - TPC.CollectFeatures([&](size_t Feature) -> bool { - ModifiedFeatures.push_back(Feature); - return true; - }); - - if (InitialFeatures == ModifiedFeatures) - --Scores[i]; - else - Scores[i] += 2; - } - } - - Printf("###### Useless dictionary elements. ######\n"); - for (size_t i = 0; i < Dict.size(); ++i) { - // Dictionary units with positive score are treated as useful ones. - if (Scores[i] > 0) - continue; - - Printf("\""); - PrintASCII(Dict[i].data(), Dict[i].size(), "\""); - Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); - } - Printf("###### End of useless dictionary elements. ######\n"); - return 0; +int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback) { + FuzzerRandomLibc Rand(0); + SimpleUserSuppliedFuzzer SUSF(&Rand, Callback); + return FuzzerDriver(Args, SUSF); } -int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { +int FuzzerDriver(const std::vector<std::string> &Args, + UserSuppliedFuzzer &USF) { using namespace fuzzer; - assert(argc && argv && "Argument pointers cannot be nullptr"); - std::string Argv0((*argv)[0]); - EF = new ExternalFunctions(); - if (EF->LLVMFuzzerInitialize) - EF->LLVMFuzzerInitialize(argc, argv); - const std::vector<std::string> Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); - if (Argv0 != *ProgName) { - Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n"); - exit(1); - } ParseFlags(Args); if (Flags.help) { PrintHelp(); return 0; } - if (Flags.close_fd_mask & 2) - DupAndCloseStderr(); - if (Flags.close_fd_mask & 1) - CloseStdout(); - if (Flags.jobs > 0 && Flags.workers == 0) { Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs); if (Flags.workers > 1) - Printf("Running %u workers\n", Flags.workers); + Printf("Running %d workers\n", Flags.workers); } if (Flags.workers > 0 && Flags.jobs > 0) return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs); - const size_t kMaxSaneLen = 1 << 20; - const size_t kMinDefaultLen = 4096; - FuzzingOptions Options; + Fuzzer::FuzzingOptions Options; Options.Verbosity = Flags.verbosity; Options.MaxLen = Flags.max_len; - Options.ExperimentalLenControl = Flags.experimental_len_control; - if (Flags.experimental_len_control && Flags.max_len == kMinDefaultLen) - Options.MaxLen = 1 << 20; Options.UnitTimeoutSec = Flags.timeout; - Options.ErrorExitCode = Flags.error_exitcode; - Options.TimeoutExitCode = Flags.timeout_exitcode; Options.MaxTotalTimeSec = Flags.max_total_time; Options.DoCrossOver = Flags.cross_over; Options.MutateDepth = Flags.mutate_depth; + Options.ExitOnFirst = Flags.exit_on_first; Options.UseCounters = Flags.use_counters; Options.UseIndirCalls = Flags.use_indir_calls; - Options.UseMemmem = Flags.use_memmem; - Options.UseCmp = Flags.use_cmp; - Options.UseValueProfile = Flags.use_value_profile; - Options.Shrink = Flags.shrink; - Options.ReduceInputs = Flags.reduce_inputs; + Options.UseTraces = Flags.use_traces; Options.ShuffleAtStartUp = Flags.shuffle; - Options.PreferSmall = Flags.prefer_small; - Options.ReloadIntervalSec = Flags.reload; + Options.PreferSmallDuringInitialShuffle = + Flags.prefer_small_during_initial_shuffle; + Options.Reload = Flags.reload; Options.OnlyASCII = Flags.only_ascii; - Options.DetectLeaks = Flags.detect_leaks; - Options.TraceMalloc = Flags.trace_malloc; - Options.RssLimitMb = Flags.rss_limit_mb; + Options.OutputCSV = Flags.output_csv; if (Flags.runs >= 0) Options.MaxNumberOfRuns = Flags.runs; - if (!Inputs->empty() && !Flags.minimize_crash_internal_step) + if (!Inputs->empty()) Options.OutputCorpus = (*Inputs)[0]; + if (Flags.sync_command) + Options.SyncCommand = Flags.sync_command; + Options.SyncTimeout = Flags.sync_timeout; Options.ReportSlowUnits = Flags.report_slow_units; if (Flags.artifact_prefix) Options.ArtifactPrefix = Flags.artifact_prefix; @@ -600,164 +278,59 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { return 1; if (Flags.verbosity > 0 && !Dictionary.empty()) Printf("Dictionary: %zd entries\n", Dictionary.size()); - bool DoPlainRun = AllInputsAreFiles(); - Options.SaveArtifacts = - !DoPlainRun || Flags.minimize_crash_internal_step; - Options.PrintNewCovPcs = Flags.print_pcs; - Options.PrintFinalStats = Flags.print_final_stats; - Options.PrintCorpusStats = Flags.print_corpus_stats; - Options.PrintCoverage = Flags.print_coverage; - Options.DumpCoverage = Flags.dump_coverage; - if (Flags.exit_on_src_pos) - Options.ExitOnSrcPos = Flags.exit_on_src_pos; - if (Flags.exit_on_item) - Options.ExitOnItem = Flags.exit_on_item; + Options.SaveArtifacts = !Flags.test_single_input; + Options.PrintNewCovPcs = Flags.print_new_cov_pcs; - unsigned Seed = Flags.seed; - // Initialize Seed. - if (Seed == 0) - Seed = - std::chrono::system_clock::now().time_since_epoch().count() + GetPid(); - if (Flags.verbosity) - Printf("INFO: Seed: %u\n", Seed); - - Random Rand(Seed); - auto *MD = new MutationDispatcher(Rand, Options); - auto *Corpus = new InputCorpus(Options.OutputCorpus); - auto *F = new Fuzzer(Callback, *Corpus, *MD, Options); + Fuzzer F(USF, Options); for (auto &U: Dictionary) - if (U.size() <= Word::GetMaxSize()) - MD->AddWordToManualDictionary(Word(U.data(), U.size())); - - StartRssThread(F, Flags.rss_limit_mb); - - Options.HandleAbrt = Flags.handle_abrt; - Options.HandleBus = Flags.handle_bus; - Options.HandleFpe = Flags.handle_fpe; - Options.HandleIll = Flags.handle_ill; - Options.HandleInt = Flags.handle_int; - Options.HandleSegv = Flags.handle_segv; - Options.HandleTerm = Flags.handle_term; - Options.HandleXfsz = Flags.handle_xfsz; - SetSignalHandler(Options); - - if (Flags.minimize_crash) - return MinimizeCrashInput(Args, Options); - - if (Flags.minimize_crash_internal_step) - return MinimizeCrashInputInternalStep(F, Corpus); - - if (Flags.cleanse_crash) - return CleanseCrashInput(Args, Options); - - if (auto Name = Flags.run_equivalence_server) { - SMR.Destroy(Name); - if (!SMR.Create(Name)) { - Printf("ERROR: can't create shared memory region\n"); - return 1; - } - Printf("INFO: EQUIVALENCE SERVER UP\n"); - while (true) { - SMR.WaitClient(); - size_t Size = SMR.ReadByteArraySize(); - SMR.WriteByteArray(nullptr, 0); - const Unit tmp(SMR.GetByteArray(), SMR.GetByteArray() + Size); - F->ExecuteCallback(tmp.data(), tmp.size()); - SMR.PostServer(); - } - return 0; - } + USF.GetMD().AddWordToManualDictionary(U); - if (auto Name = Flags.use_equivalence_server) { - if (!SMR.Open(Name)) { - Printf("ERROR: can't open shared memory region\n"); - return 1; - } - Printf("INFO: EQUIVALENCE CLIENT UP\n"); - } + // Timer + if (Flags.timeout > 0) + SetTimer(Flags.timeout / 2 + 1); - if (DoPlainRun) { - Options.SaveArtifacts = false; - int Runs = std::max(1, Flags.runs); - Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(), - Inputs->size(), Runs); - for (auto &Path : *Inputs) { - auto StartTime = system_clock::now(); - Printf("Running: %s\n", Path.c_str()); - for (int Iter = 0; Iter < Runs; Iter++) - RunOneTest(F, Path.c_str(), Options.MaxLen); - auto StopTime = system_clock::now(); - auto MS = duration_cast<milliseconds>(StopTime - StartTime).count(); - Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS); - } - Printf("***\n" - "*** NOTE: fuzzing was not performed, you have only\n" - "*** executed the target code on a fixed set of inputs.\n" - "***\n"); - F->PrintFinalStats(); - exit(0); - } - - if (Flags.merge) { - if (Options.MaxLen == 0) - F->SetMaxInputLen(kMaxSaneLen); - if (Flags.merge_control_file) - F->CrashResistantMergeInternalStep(Flags.merge_control_file); - else - F->CrashResistantMerge(Args, *Inputs, - Flags.load_coverage_summary, - Flags.save_coverage_summary); + if (Flags.test_single_input) { + RunOneTest(&F, Flags.test_single_input); exit(0); } - size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen; - - UnitVector InitialCorpus; - for (auto &Inp : *Inputs) { - Printf("Loading corpus dir: %s\n", Inp.c_str()); - ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr, - TemporaryMaxLen, /*ExitOnError=*/false); + if (Flags.save_minimized_corpus) { + Printf("The flag -save_minimized_corpus is deprecated; use -merge=1\n"); + exit(1); } - if (Flags.analyze_dict) { - if (Dictionary.empty() || Inputs->empty()) { - Printf("ERROR: can't analyze dict without dict and corpus provided\n"); - return 1; - } - if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { - Printf("Dictionary analysis failed\n"); - exit(1); - } - Printf("Dictionary analysis suceeded\n"); + if (Flags.merge) { + F.Merge(*Inputs); exit(0); } - if (Options.MaxLen == 0) { - size_t MaxLen = 0; - for (auto &U : InitialCorpus) - MaxLen = std::max(U.size(), MaxLen); - F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen)); - } - - if (InitialCorpus.empty()) { - InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input. - if (Options.Verbosity) - Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); - } - F->ShuffleAndMinimize(&InitialCorpus); - InitialCorpus.clear(); // Don't need this memory any more. - F->Loop(); + unsigned Seed = Flags.seed; + // Initialize Seed. + if (Seed == 0) + Seed = time(0) * 10000 + getpid(); + if (Flags.verbosity) + Printf("Seed: %u\n", Seed); + USF.GetRand().ResetSeed(Seed); + + F.RereadOutputCorpus(); + for (auto &inp : *Inputs) + if (inp != Options.OutputCorpus) + F.ReadDir(inp, nullptr); + + if (F.CorpusSize() == 0) + F.AddToCorpus(Unit()); // Can't fuzz empty corpus, so add an empty input. + F.ShuffleAndMinimize(); + if (Flags.drill) + F.Drill(); + else + F.Loop(); if (Flags.verbosity) - Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(), - F->secondsSinceProcessStartUp()); - F->PrintFinalStats(); + Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(), + F.secondsSinceProcessStartUp()); exit(0); // Don't let F destroy itself. } -// Storage for global ExternalFunctions object. -ExternalFunctions *EF = nullptr; - } // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerFlags.def b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def index 526805705b2..977efb76922 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerFlags.def +++ b/gnu/llvm/lib/Fuzzer/FuzzerFlags.def @@ -14,74 +14,49 @@ FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.") FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.") FUZZER_FLAG_INT(runs, -1, "Number of individual test runs (-1 for infinite runs).") -FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. " - "If 0, libFuzzer tries to guess a good value based on the corpus " - "and reports it. ") -FUZZER_FLAG_INT(experimental_len_control, 0, "experimental flag") +FUZZER_FLAG_INT(max_len, 64, "Maximum length of the test input.") FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") FUZZER_FLAG_INT(mutate_depth, 5, "Apply this number of consecutive mutations to each input.") FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup") -FUZZER_FLAG_INT(prefer_small, 1, - "If 1, always prefer smaller inputs during the corpus shuffle.") +FUZZER_FLAG_INT( + prefer_small_during_initial_shuffle, -1, + "If 1, always prefer smaller inputs during the initial corpus shuffle." + " If 0, never do that. If -1, do it sometimes.") +FUZZER_FLAG_INT(exit_on_first, 0, + "If 1, exit after the first new interesting input is found.") FUZZER_FLAG_INT( timeout, 1200, "Timeout in seconds (if positive). " "If one unit runs more than this number of seconds the process will abort.") -FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug " - "this exit code will be used.") -FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout " - "this exit code will be used.") FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " "time in seconds to run the fuzzer.") FUZZER_FLAG_INT(help, 0, "Print help.") +FUZZER_FLAG_INT(save_minimized_corpus, 0, "Deprecated. Use -merge=1") FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " - "merged into the 1-st corpus. Only interesting units will be taken. " - "This flag can be used to minimize a corpus.") -FUZZER_FLAG_STRING(merge_control_file, "internal flag") -FUZZER_FLAG_STRING(save_coverage_summary, "Experimental:" - " save coverage summary to a given file." - " Used with -merge=1") -FUZZER_FLAG_STRING(load_coverage_summary, "Experimental:" - " load coverage summary from a given file." - " Treat this coverage as belonging to the first corpus. " - " Used with -merge=1") -FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided" - " crash input. Use with -runs=N or -max_total_time=N to limit " - "the number attempts." - " Use with -exact_artifact_path to specify the output." - " Combine with ASAN_OPTIONS=dedup_token_length=3 (or similar) to ensure that" - " the minimized input triggers the same crash." - ) -FUZZER_FLAG_INT(cleanse_crash, 0, "If 1, tries to cleanse the provided" - " crash input to make it contain fewer original bytes." - " Use with -exact_artifact_path to specify the output." - ) -FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag") + "merged into the 1-st corpus. Only interesting units will be taken.") FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") -FUZZER_FLAG_INT(use_memmem, 1, - "Use hints from intercepting memmem, strstr, etc") -FUZZER_FLAG_INT(use_value_profile, 0, - "Experimental. Use value profile to guide fuzzing.") -FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations") -FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus inputs.") -FUZZER_FLAG_INT(reduce_inputs, 0, "Experimental. " - "Try to reduce the size of inputs wile preserving their full feature sets") -FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" +FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces") +FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn" " this number of jobs in separate worker processes" " with stdout/stderr redirected to fuzz-JOB.log.") -FUZZER_FLAG_UNSIGNED(workers, 0, +FUZZER_FLAG_INT(workers, 0, "Number of simultaneous worker processes to run the jobs." " If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload, 1, - "Reload the main corpus every <N> seconds to get new units" - " discovered by other processes. If 0, disabled") + "Reload the main corpus periodically to get new units" + " discovered by other processes.") +FUZZER_FLAG_STRING(sync_command, "Execute an external command " + "\"<sync_command> <test_corpus>\" " + "to synchronize the test corpus.") +FUZZER_FLAG_INT(sync_timeout, 600, "Minimum timeout between syncs.") FUZZER_FLAG_INT(report_slow_units, 10, "Report slowest units if they run for more than this number of seconds.") FUZZER_FLAG_INT(only_ascii, 0, "If 1, generate only ASCII (isprint+isspace) inputs.") FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.") +FUZZER_FLAG_STRING(test_single_input, "Use specified file as test input.") FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, " "timeout, or slow inputs) as " "$(artifact_prefix)file") @@ -90,50 +65,8 @@ FUZZER_FLAG_STRING(exact_artifact_path, "as $(exact_artifact_path). This overrides -artifact_prefix " "and will not use checksum in the file name. Do not " "use the same path for several parallel processes.") -FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.") -FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.") -FUZZER_FLAG_INT(print_corpus_stats, 0, - "If 1, print statistics on corpus elements at exit.") -FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information as text" - " at exit.") -FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information as a" - " .sancov file at exit.") -FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.") -FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGBUS.") -FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.") -FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.") -FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.") -FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.") -FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.") -FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.") -FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; " - "if 2, close stderr; if 3, close both. " - "Be careful, this will also close e.g. asan's stderr/stdout.") -FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled " - "try to detect memory leaks during fuzzing (i.e. not only at shut down).") -FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. " - "If >= 2 will also print stack traces.") -FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" - "reaching this limit of RSS memory usage.") -FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates" - " from the given source location. Example: -exit_on_src_pos=foo.cc:123. " - "Used primarily for testing libFuzzer itself.") -FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" - " was added to the corpus. " - "Used primarily for testing libFuzzer itself.") -FUZZER_FLAG_INT(ignore_remaining_args, 0, "If 1, ignore all arguments passed " - "after this one. Useful for fuzzers that need to do their own " - "argument parsing.") - -FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") -FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") -FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") +FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed " + "corpus, then merge with the initial corpus") +FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.") +FUZZER_FLAG_INT(print_new_cov_pcs, 0, "If 1, print out new covered pcs.") -FUZZER_DEPRECATED_FLAG(exit_on_first) -FUZZER_DEPRECATED_FLAG(save_minimized_corpus) -FUZZER_DEPRECATED_FLAG(sync_command) -FUZZER_DEPRECATED_FLAG(sync_timeout) -FUZZER_DEPRECATED_FLAG(test_single_input) -FUZZER_DEPRECATED_FLAG(drill) -FUZZER_DEPRECATED_FLAG(truncate_units) -FUZZER_DEPRECATED_FLAG(output_csv) diff --git a/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp index e3f609ed8a8..043fad396d5 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerIO.cpp @@ -8,44 +8,54 @@ //===----------------------------------------------------------------------===// // IO functions. //===----------------------------------------------------------------------===// - -#include "FuzzerIO.h" -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include <algorithm> -#include <cstdarg> -#include <fstream> +#include "FuzzerInternal.h" #include <iterator> -#include <sys/stat.h> +#include <fstream> +#include <dirent.h> #include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <cstdarg> +#include <cstdio> namespace fuzzer { -static FILE *OutputFile = stderr; - -long GetEpoch(const std::string &Path) { +static long GetEpoch(const std::string &Path) { struct stat St; if (stat(Path.c_str(), &St)) return 0; // Can't stat, be conservative. return St.st_mtime; } -Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { +static std::vector<std::string> ListFilesInDir(const std::string &Dir, + long *Epoch) { + std::vector<std::string> V; + if (Epoch) { + auto E = GetEpoch(Dir); + if (*Epoch >= E) return V; + *Epoch = E; + } + DIR *D = opendir(Dir.c_str()); + if (!D) { + Printf("No such directory: %s; exiting\n", Dir.c_str()); + exit(1); + } + while (auto E = readdir(D)) { + if (E->d_type == DT_REG || E->d_type == DT_LNK) + V.push_back(E->d_name); + } + closedir(D); + return V; +} + +Unit FileToVector(const std::string &Path) { std::ifstream T(Path); - if (ExitOnError && !T) { + if (!T) { Printf("No such directory: %s; exiting\n", Path.c_str()); exit(1); } - - T.seekg(0, T.end); - size_t FileLen = T.tellg(); - if (MaxSize) - FileLen = std::min(FileLen, MaxSize); - - T.seekg(0, T.beg); - Unit Res(FileLen); - T.read(reinterpret_cast<char *>(Res.data()), FileLen); - return Res; + return Unit((std::istreambuf_iterator<char>(T)), + std::istreambuf_iterator<char>()); } std::string FileToString(const std::string &Path) { @@ -67,52 +77,25 @@ void WriteToFile(const Unit &U, const std::string &Path) { } void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, - long *Epoch, size_t MaxSize, bool ExitOnError) { + long *Epoch) { long E = Epoch ? *Epoch : 0; - std::vector<std::string> Files; - ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); - size_t NumLoaded = 0; - for (size_t i = 0; i < Files.size(); i++) { - auto &X = Files[i]; - if (Epoch && GetEpoch(X) < E) continue; - NumLoaded++; - if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024) - Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path); - auto S = FileToVector(X, MaxSize, ExitOnError); - if (!S.empty()) - V->push_back(S); + for (auto &X : ListFilesInDir(Path, Epoch)) { + auto FilePath = DirPlusFile(Path, X); + if (Epoch && GetEpoch(FilePath) < E) continue; + V->push_back(FileToVector(FilePath)); } } std::string DirPlusFile(const std::string &DirPath, const std::string &FileName) { - return DirPath + GetSeparator() + FileName; -} - -void DupAndCloseStderr() { - int OutputFd = DuplicateFile(2); - if (OutputFd > 0) { - FILE *NewOutputFile = OpenFile(OutputFd, "w"); - if (NewOutputFile) { - OutputFile = NewOutputFile; - if (EF->__sanitizer_set_report_fd) - EF->__sanitizer_set_report_fd( - reinterpret_cast<void *>(GetHandleFromFd(OutputFd))); - DiscardOutput(2); - } - } -} - -void CloseStdout() { - DiscardOutput(1); + return DirPath + "/" + FileName; } void Printf(const char *Fmt, ...) { va_list ap; va_start(ap, Fmt); - vfprintf(OutputFile, Fmt, ap); + vfprintf(stderr, Fmt, ap); va_end(ap); - fflush(OutputFile); } } // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInterface.h b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h index c2c0a39843c..e22b27a3dd2 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerInterface.h +++ b/gnu/llvm/lib/Fuzzer/FuzzerInterface.h @@ -6,62 +6,193 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// Define the interface between libFuzzer and the library being tested. +// Define the interface between the Fuzzer and the library being tested. //===----------------------------------------------------------------------===// -// NOTE: the libFuzzer interface is thin and in the majority of cases -// you should not include this file into your target. In 95% of cases -// all you need is to define the following function in your file: -// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); - -// WARNING: keep the interface in C. +// WARNING: keep the interface free of STL or any other header-based C++ lib, +// to avoid bad interactions between the code used in the fuzzer and +// the code used in the target function. #ifndef LLVM_FUZZER_INTERFACE_H #define LLVM_FUZZER_INTERFACE_H -#include <stddef.h> -#include <stdint.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// Mandatory user-provided target function. -// Executes the code under test with [Data, Data+Size) as the input. -// libFuzzer will invoke this function *many* times with different inputs. -// Must return 0. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); - -// Optional user-provided initialization function. -// If provided, this function will be called by libFuzzer once at startup. -// It may read and modify argc/argv. -// Must return 0. -int LLVMFuzzerInitialize(int *argc, char ***argv); - -// Optional user-provided custom mutator. -// Mutates raw data in [Data, Data+Size) inplace. -// Returns the new size, which is not greater than MaxSize. -// Given the same Seed produces the same mutation. -size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, - unsigned int Seed); - -// Optional user-provided custom cross-over function. -// Combines pieces of Data1 & Data2 together into Out. -// Returns the new size, which is not greater than MaxOutSize. -// Should produce the same mutation given the same Seed. -size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1, - const uint8_t *Data2, size_t Size2, - uint8_t *Out, size_t MaxOutSize, - unsigned int Seed); - -// Experimental, may go away in future. -// libFuzzer-provided function to be used inside LLVMFuzzerCustomMutator. -// Mutates raw data in [Data, Data+Size) inplace. -// Returns the new size, which is not greater than MaxSize. -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus +#include <limits> +#include <cstddef> +#include <cstdint> +#include <vector> +#include <string> + +namespace fuzzer { +typedef std::vector<uint8_t> Unit; + +/// Returns an int 0. Values other than zero are reserved for future. +typedef int (*UserCallback)(const uint8_t *Data, size_t Size); +/** Simple C-like interface with a single user-supplied callback. + +Usage: + +#\code +#include "FuzzerInterface.h" + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + DoStuffWithData(Data, Size); + return 0; +} + +// Implement your own main() or use the one from FuzzerMain.cpp. +int main(int argc, char **argv) { + InitializeMeIfNeeded(); + return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); +} +#\endcode +*/ +int FuzzerDriver(int argc, char **argv, UserCallback Callback); + +class FuzzerRandomBase { + public: + FuzzerRandomBase(){} + virtual ~FuzzerRandomBase(){}; + virtual void ResetSeed(unsigned int seed) = 0; + // Return a random number. + virtual size_t Rand() = 0; + // Return a random number in range [0,n). + size_t operator()(size_t n) { return n ? Rand() % n : 0; } + bool RandBool() { return Rand() % 2; } +}; + +class FuzzerRandomLibc : public FuzzerRandomBase { + public: + FuzzerRandomLibc(unsigned int seed) { ResetSeed(seed); } + void ResetSeed(unsigned int seed) override; + ~FuzzerRandomLibc() override {} + size_t Rand() override; +}; + +class MutationDispatcher { + public: + MutationDispatcher(FuzzerRandomBase &Rand); + ~MutationDispatcher(); + /// Indicate that we are about to start a new sequence of mutations. + void StartMutationSequence(); + /// Print the current sequence of mutations. + void PrintMutationSequence(); + /// Mutates data by shuffling bytes. + size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by erasing a byte. + size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by inserting a byte. + size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one byte. + size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize); + /// Mutates data by chanding one bit. + size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Mutates data by adding a word from the manual dictionary. + size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Mutates data by adding a word from the automatic dictionary. + size_t Mutate_AddWordFromAutoDictionary(uint8_t *Data, size_t Size, + size_t MaxSize); + + /// Tries to find an ASCII integer in Data, changes it to another ASCII int. + size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize); + + /// CrossOver Data with some other element of the corpus. + size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Applies one of the above mutations. + /// Returns the new size of data which could be up to MaxSize. + size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + + /// Creates a cross-over of two pieces of Data, returns its size. + size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, + size_t Size2, uint8_t *Out, size_t MaxOutSize); + + void AddWordToManualDictionary(const Unit &Word); + + void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint); + void ClearAutoDictionary(); + + void SetCorpus(const std::vector<Unit> *Corpus); + + private: + FuzzerRandomBase &Rand; + struct Impl; + Impl *MDImpl; +}; + +// For backward compatibility only, deprecated. +static inline size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, + FuzzerRandomBase &Rand) { + MutationDispatcher MD(Rand); + return MD.Mutate(Data, Size, MaxSize); +} + +/** An abstract class that allows to use user-supplied mutators with libFuzzer. + +Usage: + +#\code +#include "FuzzerInterface.h" +class MyFuzzer : public fuzzer::UserSuppliedFuzzer { + public: + MyFuzzer(fuzzer::FuzzerRandomBase *Rand); + // Must define the target function. + int TargetFunction(...) { ...; return 0; } + // Optionally define the mutator. + size_t Mutate(...) { ... } + // Optionally define the CrossOver method. + size_t CrossOver(...) { ... } +}; + +int main(int argc, char **argv) { + MyFuzzer F; + fuzzer::FuzzerDriver(argc, argv, F); +} +#\endcode +*/ +class UserSuppliedFuzzer { + public: + UserSuppliedFuzzer(FuzzerRandomBase *Rand); + /// Executes the target function on 'Size' bytes of 'Data'. + virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0; + virtual void StartMutationSequence() { MD.StartMutationSequence(); } + virtual void PrintMutationSequence() { MD.PrintMutationSequence(); } + virtual void SetCorpus(const std::vector<Unit> *Corpus) { + MD.SetCorpus(Corpus); + } + /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes, + /// returns the new size of the data, which should be positive. + virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + return MD.Mutate(Data, Size, MaxSize); + } + /// Crosses 'Data1' and 'Data2', writes up to 'MaxOutSize' bytes into Out, + /// returns the number of bytes written, which should be positive. + virtual size_t CrossOver(const uint8_t *Data1, size_t Size1, + const uint8_t *Data2, size_t Size2, + uint8_t *Out, size_t MaxOutSize) { + return MD.CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize); + } + virtual ~UserSuppliedFuzzer(); + + FuzzerRandomBase &GetRand() { return *Rand; } + + MutationDispatcher &GetMD() { return MD; } + + private: + bool OwnRand = false; + FuzzerRandomBase *Rand; + MutationDispatcher MD; +}; + +/// Runs the fuzzing with the UserSuppliedFuzzer. +int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF); + +/// More C++-ish interface. +int FuzzerDriver(const std::vector<std::string> &Args, UserSuppliedFuzzer &USF); +int FuzzerDriver(const std::vector<std::string> &Args, UserCallback Callback); + +} // namespace fuzzer #endif // LLVM_FUZZER_INTERFACE_H diff --git a/gnu/llvm/lib/Fuzzer/FuzzerInternal.h b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h index 3fc3fe004ce..c1e9daac980 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerInternal.h +++ b/gnu/llvm/lib/Fuzzer/FuzzerInternal.h @@ -12,132 +12,196 @@ #ifndef LLVM_FUZZER_INTERNAL_H #define LLVM_FUZZER_INTERNAL_H -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include "FuzzerInterface.h" -#include "FuzzerOptions.h" -#include "FuzzerSHA1.h" -#include "FuzzerValueBitMap.h" -#include <algorithm> -#include <atomic> -#include <chrono> +#include <cassert> #include <climits> +#include <chrono> +#include <cstddef> #include <cstdlib> -#include <string.h> +#include <string> +#include <vector> +#include <unordered_set> -namespace fuzzer { +#include "FuzzerInterface.h" +namespace fuzzer { using namespace std::chrono; -class Fuzzer { -public: +std::string FileToString(const std::string &Path); +Unit FileToVector(const std::string &Path); +void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V, + long *Epoch); +void WriteToFile(const Unit &U, const std::string &Path); +void CopyFileToErr(const std::string &Path); +// Returns "Dir/FileName" or equivalent for the current OS. +std::string DirPlusFile(const std::string &DirPath, + const std::string &FileName); + +void Printf(const char *Fmt, ...); +void Print(const Unit &U, const char *PrintAfter = ""); +void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = ""); +void PrintASCII(const Unit &U, const char *PrintAfter = ""); +std::string Hash(const Unit &U); +void SetTimer(int Seconds); +std::string Base64(const Unit &U); +int ExecuteCommand(const std::string &Command); + +// Private copy of SHA1 implementation. +static const int kSHA1NumBytes = 20; +// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'. +void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out); + +// Changes U to contain only ASCII (isprint+isspace) characters. +// Returns true iff U has been changed. +bool ToASCII(Unit &U); +bool IsASCII(const Unit &U); + +int NumberOfCpuCores(); +int GetPid(); + +// Dictionary. + +// Parses one dictionary entry. +// If successfull, write the enty to Unit and returns true, +// otherwise returns false. +bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); +// Parses the dictionary file, fills Units, returns true iff all lines +// were parsed succesfully. +bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units); - Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, - FuzzingOptions Options); - ~Fuzzer(); +class Fuzzer { + public: + struct FuzzingOptions { + int Verbosity = 1; + int MaxLen = 0; + int UnitTimeoutSec = 300; + int MaxTotalTimeSec = 0; + bool DoCrossOver = true; + int MutateDepth = 5; + bool ExitOnFirst = false; + bool UseCounters = false; + bool UseIndirCalls = true; + bool UseTraces = false; + bool UseFullCoverageSet = false; + bool Reload = true; + bool ShuffleAtStartUp = true; + int PreferSmallDuringInitialShuffle = -1; + size_t MaxNumberOfRuns = ULONG_MAX; + int SyncTimeout = 600; + int ReportSlowUnits = 10; + bool OnlyASCII = false; + std::string OutputCorpus; + std::string SyncCommand; + std::string ArtifactPrefix = "./"; + std::string ExactArtifactPath; + bool SaveArtifacts = true; + bool PrintNEW = true; // Print a status line when new units are found; + bool OutputCSV = false; + bool PrintNewCovPcs = false; + }; + Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options); + void AddToCorpus(const Unit &U) { Corpus.push_back(U); } + size_t ChooseUnitIdxToMutate(); + const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; }; void Loop(); - void MinimizeCrashLoop(const Unit &U); - void ShuffleAndMinimize(UnitVector *V); - void RereadOutputCorpus(size_t MaxSize); + void Drill(); + void ShuffleAndMinimize(); + void InitializeTraceState(); + size_t CorpusSize() const { return Corpus.size(); } + void ReadDir(const std::string &Path, long *Epoch) { + Printf("Loading corpus: %s\n", Path.c_str()); + ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch); + } + void RereadOutputCorpus(); + // Save the current corpus to OutputCorpus. + void SaveCorpus(); size_t secondsSinceProcessStartUp() { return duration_cast<seconds>(system_clock::now() - ProcessStartTime) .count(); } - bool TimedOut() { - return Options.MaxTotalTimeSec > 0 && - secondsSinceProcessStartUp() > - static_cast<size_t>(Options.MaxTotalTimeSec); - } - - size_t execPerSec() { - size_t Seconds = secondsSinceProcessStartUp(); - return Seconds ? TotalNumberOfRuns / Seconds : 0; - } - size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; } static void StaticAlarmCallback(); - static void StaticCrashSignalCallback(); - static void StaticInterruptCallback(); - static void StaticFileSizeExceedCallback(); - void ExecuteCallback(const uint8_t *Data, size_t Size); - bool RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile = false, - InputInfo *II = nullptr); + void ExecuteCallback(const Unit &U); // Merge Corpora[1:] into Corpora[0]. void Merge(const std::vector<std::string> &Corpora); - void CrashResistantMerge(const std::vector<std::string> &Args, - const std::vector<std::string> &Corpora, - const char *CoverageSummaryInputPathOrNull, - const char *CoverageSummaryOutputPathOrNull); - void CrashResistantMergeInternalStep(const std::string &ControlFilePath); - MutationDispatcher &GetMD() { return MD; } - void PrintFinalStats(); - void SetMaxInputLen(size_t MaxInputLen); - void SetMaxMutationLen(size_t MaxMutationLen); - void RssLimitCallback(); - - bool InFuzzingThread() const { return IsMyThread; } - size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const; - void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, - bool DuringInitialCorpusExecution); - - void HandleMalloc(size_t Size); - void AnnounceOutput(const uint8_t *Data, size_t Size); - -private: + + private: void AlarmCallback(); - void CrashCallback(); - void CrashOnOverwrittenData(); - void InterruptCallback(); void MutateAndTestOne(); - void ReportNewCoverage(InputInfo *II, const Unit &U); - void PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size); + void ReportNewCoverage(const Unit &U); + bool RunOne(const Unit &U); + void RunOneAndUpdateCorpus(Unit &U); void WriteToOutputCorpus(const Unit &U); void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix); - void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0); - void PrintStatusForNewUnit(const Unit &U, const char *Text); - void ShuffleCorpus(UnitVector *V); - void CheckExitOnSrcPosOrItem(); + void PrintStats(const char *Where, const char *End = "\n"); + void PrintStatusForNewUnit(const Unit &U); + void PrintUnitInASCII(const Unit &U, const char *PrintAfter = ""); + + void SyncCorpus(); + + size_t RecordBlockCoverage(); + size_t RecordCallerCalleeCoverage(); + void PrepareCoverageBeforeRun(); + bool CheckCoverageAfterRun(); + + + // Trace-based fuzzing: we run a unit with some kind of tracing + // enabled and record potentially useful mutations. Then + // We apply these mutations one by one to the unit and run it again. + + // Start tracing; forget all previously proposed mutations. + void StartTraceRecording(); + // Stop tracing. + void StopTraceRecording(); + void SetDeathCallback(); static void StaticDeathCallback(); - void DumpCurrentUnit(const char *Prefix); void DeathCallback(); - - void AllocateCurrentUnitData(); - uint8_t *CurrentUnitData = nullptr; - std::atomic<size_t> CurrentUnitSize; - uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit. - bool RunningCB = false; + Unit CurrentUnit; size_t TotalNumberOfRuns = 0; - size_t NumberOfNewUnitsAdded = 0; + size_t TotalNumberOfExecutedTraceBasedMutations = 0; - bool HasMoreMallocsThanFrees = false; - size_t NumberOfLeakDetectionAttempts = 0; + std::vector<Unit> Corpus; + std::unordered_set<std::string> UnitHashesAddedToCorpus; - UserCallback CB; - InputCorpus &Corpus; - MutationDispatcher &MD; - FuzzingOptions Options; + // For UseCounters + std::vector<uint8_t> CounterBitmap; + size_t TotalBits() { // Slow. Call it only for printing stats. + size_t Res = 0; + for (auto x : CounterBitmap) Res += __builtin_popcount(x); + return Res; + } + UserSuppliedFuzzer &USF; + FuzzingOptions Options; system_clock::time_point ProcessStartTime = system_clock::now(); - system_clock::time_point UnitStartTime, UnitStopTime; + system_clock::time_point LastExternalSync = system_clock::now(); + system_clock::time_point UnitStartTime; long TimeOfLongestUnitInSeconds = 0; long EpochOfLastReadOfOutputCorpus = 0; + size_t LastRecordedBlockCoverage = 0; + size_t LastRecordedCallerCalleeCoverage = 0; + size_t LastCoveragePcBufferLen = 0; +}; - size_t MaxInputLen = 0; - size_t MaxMutationLen = 0; +class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer { + public: + SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback) + : UserSuppliedFuzzer(Rand), Callback(Callback) {} - std::vector<uint32_t> UniqFeatureSetTmp; + virtual int TargetFunction(const uint8_t *Data, size_t Size) override { + return Callback(Data, Size); + } - // Need to know our own thread. - static thread_local bool IsMyThread; + private: + UserCallback Callback = nullptr; }; -} // namespace fuzzer +}; // namespace fuzzer #endif // LLVM_FUZZER_INTERNAL_H diff --git a/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp index 8ac7a847aef..5237682ff24 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerLoop.cpp @@ -9,136 +9,65 @@ // Fuzzer's main loop. //===----------------------------------------------------------------------===// -#include "FuzzerCorpus.h" -#include "FuzzerIO.h" #include "FuzzerInternal.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerShmem.h" -#include "FuzzerTracePC.h" #include <algorithm> -#include <cstring> -#include <memory> -#include <set> #if defined(__has_include) -#if __has_include(<sanitizer / lsan_interface.h>) -#include <sanitizer/lsan_interface.h> -#endif +# if __has_include(<sanitizer/coverage_interface.h>) +# include <sanitizer/coverage_interface.h> +# endif #endif -#define NO_SANITIZE_MEMORY -#if defined(__has_feature) -#if __has_feature(memory_sanitizer) -#undef NO_SANITIZE_MEMORY -#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) -#endif -#endif +extern "C" { +// Re-declare some of the sanitizer functions as "weak" so that +// libFuzzer can be linked w/o the sanitizers and sanitizer-coverage +// (in which case it will complain at start-up time). +__attribute__((weak)) void __sanitizer_print_stack_trace(); +__attribute__((weak)) void __sanitizer_reset_coverage(); +__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs(); +__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage(); +__attribute__((weak)) +void __sanitizer_set_death_callback(void (*callback)(void)); +__attribute__((weak)) size_t __sanitizer_get_number_of_counters(); +__attribute__((weak)) +uintptr_t __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset); +__attribute__((weak)) uintptr_t +__sanitizer_get_coverage_pc_buffer(uintptr_t **data); +} namespace fuzzer { static const size_t kMaxUnitSizeToPrint = 256; -thread_local bool Fuzzer::IsMyThread; +static void MissingWeakApiFunction(const char *FnName) { + Printf("ERROR: %s is not defined. Exiting.\n" + "Did you use -fsanitize-coverage=... to build your code?\n", FnName); + exit(1); +} -SharedMemoryRegion SMR; +#define CHECK_WEAK_API_FUNCTION(fn) \ + do { \ + if (!fn) \ + MissingWeakApiFunction(#fn); \ + } while (false) // Only one Fuzzer per process. static Fuzzer *F; -// Leak detection is expensive, so we first check if there were more mallocs -// than frees (using the sanitizer malloc hooks) and only then try to call lsan. -struct MallocFreeTracer { - void Start(int TraceLevel) { - this->TraceLevel = TraceLevel; - if (TraceLevel) - Printf("MallocFreeTracer: START\n"); - Mallocs = 0; - Frees = 0; - } - // Returns true if there were more mallocs than frees. - bool Stop() { - if (TraceLevel) - Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), - Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); - bool Result = Mallocs > Frees; - Mallocs = 0; - Frees = 0; - TraceLevel = 0; - return Result; - } - std::atomic<size_t> Mallocs; - std::atomic<size_t> Frees; - int TraceLevel = 0; -}; - -static MallocFreeTracer AllocTracer; - -ATTRIBUTE_NO_SANITIZE_MEMORY -void MallocHook(const volatile void *ptr, size_t size) { - size_t N = AllocTracer.Mallocs++; - F->HandleMalloc(size); - if (int TraceLevel = AllocTracer.TraceLevel) { - Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); - if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); - } -} - -ATTRIBUTE_NO_SANITIZE_MEMORY -void FreeHook(const volatile void *ptr) { - size_t N = AllocTracer.Frees++; - if (int TraceLevel = AllocTracer.TraceLevel) { - Printf("FREE[%zd] %p\n", N, ptr); - if (TraceLevel >= 2 && EF) - EF->__sanitizer_print_stack_trace(); - } -} - -// Crash on a single malloc that exceeds the rss limit. -void Fuzzer::HandleMalloc(size_t Size) { - if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb) - return; - Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), - Size); - Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - DumpCurrentUnit("oom-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, - FuzzingOptions Options) - : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { - if (EF->__sanitizer_set_death_callback) - EF->__sanitizer_set_death_callback(StaticDeathCallback); +Fuzzer::Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options) + : USF(USF), Options(Options) { + SetDeathCallback(); + InitializeTraceState(); assert(!F); F = this; - TPC.ResetMaps(); - IsMyThread = true; - if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) - EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); - TPC.SetUseCounters(Options.UseCounters); - TPC.SetUseValueProfile(Options.UseValueProfile); - TPC.SetPrintNewPCs(Options.PrintNewCovPcs); - - if (Options.Verbosity) - TPC.PrintModuleInfo(); - if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) - EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); - MaxInputLen = MaxMutationLen = Options.MaxLen; - AllocateCurrentUnitData(); - CurrentUnitSize = 0; - memset(BaseSha1, 0, sizeof(BaseSha1)); } -Fuzzer::~Fuzzer() { } +void Fuzzer::SetDeathCallback() { + CHECK_WEAK_API_FUNCTION(__sanitizer_set_death_callback); + __sanitizer_set_death_callback(StaticDeathCallback); +} -void Fuzzer::AllocateCurrentUnitData() { - if (CurrentUnitData || MaxInputLen == 0) return; - CurrentUnitData = new uint8_t[MaxInputLen]; +void Fuzzer::PrintUnitInASCII(const Unit &U, const char *PrintAfter) { + PrintASCII(U, PrintAfter); } void Fuzzer::StaticDeathCallback() { @@ -146,23 +75,13 @@ void Fuzzer::StaticDeathCallback() { F->DeathCallback(); } -void Fuzzer::DumpCurrentUnit(const char *Prefix) { - if (!CurrentUnitData) return; // Happens when running individual inputs. - MD.PrintMutationSequence(); - Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); - size_t UnitSize = CurrentUnitSize; - if (UnitSize <= kMaxUnitSizeToPrint) { - PrintHexArray(CurrentUnitData, UnitSize, "\n"); - PrintASCII(CurrentUnitData, UnitSize, "\n"); - } - WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, - Prefix); -} - -NO_SANITIZE_MEMORY void Fuzzer::DeathCallback() { - DumpCurrentUnit("crash-"); - PrintFinalStats(); + Printf("DEATH:\n"); + if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { + Print(CurrentUnit, "\n"); + PrintUnitInASCII(CurrentUnit, "\n"); + } + WriteUnitToFileWithPrefix(CurrentUnit, "crash-"); } void Fuzzer::StaticAlarmCallback() { @@ -170,328 +89,224 @@ void Fuzzer::StaticAlarmCallback() { F->AlarmCallback(); } -void Fuzzer::StaticCrashSignalCallback() { - assert(F); - F->CrashCallback(); -} - -void Fuzzer::StaticInterruptCallback() { - assert(F); - F->InterruptCallback(); -} - -void Fuzzer::StaticFileSizeExceedCallback() { - Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); - exit(1); -} - -void Fuzzer::CrashCallback() { - Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); - Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" - " Combine libFuzzer with AddressSanitizer or similar for better " - "crash reports.\n"); - Printf("SUMMARY: libFuzzer: deadly signal\n"); - DumpCurrentUnit("crash-"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} - -void Fuzzer::InterruptCallback() { - Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); - PrintFinalStats(); - _Exit(0); // Stop right now, don't perform any at-exit actions. -} - -NO_SANITIZE_MEMORY void Fuzzer::AlarmCallback() { assert(Options.UnitTimeoutSec > 0); - // In Windows Alarm callback is executed by a different thread. -#if !LIBFUZZER_WINDOWS - if (!InFuzzingThread()) return; -#endif - if (!RunningCB) - return; // We have not started running units yet. size_t Seconds = duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); - if (Seconds == 0) - return; + if (Seconds == 0) return; if (Options.Verbosity >= 2) Printf("AlarmCallback %zd\n", Seconds); if (Seconds >= (size_t)Options.UnitTimeoutSec) { Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); Printf(" and the timeout value is %d (use -timeout=N to change)\n", Options.UnitTimeoutSec); - DumpCurrentUnit("timeout-"); - Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), + if (CurrentUnit.size() <= kMaxUnitSizeToPrint) { + Print(CurrentUnit, "\n"); + PrintUnitInASCII(CurrentUnit, "\n"); + } + WriteUnitToFileWithPrefix(CurrentUnit, "timeout-"); + Printf("==%d== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), Seconds); - if (EF->__sanitizer_print_stack_trace) - EF->__sanitizer_print_stack_trace(); + if (__sanitizer_print_stack_trace) + __sanitizer_print_stack_trace(); Printf("SUMMARY: libFuzzer: timeout\n"); - PrintFinalStats(); - _Exit(Options.TimeoutExitCode); // Stop right now. + exit(1); } } -void Fuzzer::RssLimitCallback() { - Printf( - "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", - GetPid(), GetPeakRSSMb(), Options.RssLimitMb); - Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); - if (EF->__sanitizer_print_memory_profile) - EF->__sanitizer_print_memory_profile(95, 8); - DumpCurrentUnit("oom-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // Stop right now. -} +void Fuzzer::PrintStats(const char *Where, const char *End) { + size_t Seconds = secondsSinceProcessStartUp(); + size_t ExecPerSec = (Seconds ? TotalNumberOfRuns / Seconds : 0); -void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { - size_t ExecPerSec = execPerSec(); - if (!Options.Verbosity) - return; - Printf("#%zd\t%s", TotalNumberOfRuns, Where); - if (size_t N = TPC.GetTotalPCCoverage()) - Printf(" cov: %zd", N); - if (size_t N = Corpus.NumFeatures()) - Printf( " ft: %zd", N); - if (!Corpus.empty()) { - Printf(" corp: %zd", Corpus.NumActiveUnits()); - if (size_t N = Corpus.SizeInBytes()) { - if (N < (1<<14)) - Printf("/%zdb", N); - else if (N < (1 << 24)) - Printf("/%zdKb", N >> 10); - else - Printf("/%zdMb", N >> 20); + if (Options.OutputCSV) { + static bool csvHeaderPrinted = false; + if (!csvHeaderPrinted) { + csvHeaderPrinted = true; + Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n"); } + Printf("%zd,%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns, + LastRecordedBlockCoverage, TotalBits(), + LastRecordedCallerCalleeCoverage, Corpus.size(), ExecPerSec, + TotalNumberOfExecutedTraceBasedMutations, Where); } - if (Units) - Printf(" units: %zd", Units); - Printf(" exec/s: %zd", ExecPerSec); - Printf(" rss: %zdMb", GetPeakRSSMb()); + if (!Options.Verbosity) + return; + Printf("#%zd\t%s", TotalNumberOfRuns, Where); + if (LastRecordedBlockCoverage) + Printf(" cov: %zd", LastRecordedBlockCoverage); + if (auto TB = TotalBits()) + Printf(" bits: %zd", TB); + if (LastRecordedCallerCalleeCoverage) + Printf(" indir: %zd", LastRecordedCallerCalleeCoverage); + Printf(" units: %zd exec/s: %zd", Corpus.size(), ExecPerSec); + if (TotalNumberOfExecutedTraceBasedMutations) + Printf(" tbm: %zd", TotalNumberOfExecutedTraceBasedMutations); Printf("%s", End); } -void Fuzzer::PrintFinalStats() { - if (Options.PrintCoverage) - TPC.PrintCoverage(); - if (Options.DumpCoverage) - TPC.DumpCoverage(); - if (Options.PrintCorpusStats) - Corpus.PrintStats(); - if (!Options.PrintFinalStats) return; - size_t ExecPerSec = execPerSec(); - Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); - Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); - Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); - Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); - Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); -} - -void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { - assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. - assert(MaxInputLen); - this->MaxInputLen = MaxInputLen; - this->MaxMutationLen = MaxInputLen; - AllocateCurrentUnitData(); - Printf("INFO: -max_len is not provided; " - "libFuzzer will not generate inputs larger than %zd bytes\n", - MaxInputLen); -} - -void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { - assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); - this->MaxMutationLen = MaxMutationLen; -} - -void Fuzzer::CheckExitOnSrcPosOrItem() { - if (!Options.ExitOnSrcPos.empty()) { - static auto *PCsSet = new std::set<uintptr_t>; - for (size_t i = 1, N = TPC.GetNumPCs(); i < N; i++) { - uintptr_t PC = TPC.GetPC(i); - if (!PC) continue; - if (!PCsSet->insert(PC).second) continue; - std::string Descr = DescribePC("%L", PC); - if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { - Printf("INFO: found line matching '%s', exiting.\n", - Options.ExitOnSrcPos.c_str()); - _Exit(0); - } - } - } - if (!Options.ExitOnItem.empty()) { - if (Corpus.HasUnit(Options.ExitOnItem)) { - Printf("INFO: found item with checksum '%s', exiting.\n", - Options.ExitOnItem.c_str()); - _Exit(0); - } - } -} - -void Fuzzer::RereadOutputCorpus(size_t MaxSize) { - if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; +void Fuzzer::RereadOutputCorpus() { + if (Options.OutputCorpus.empty()) return; std::vector<Unit> AdditionalCorpus; ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, - &EpochOfLastReadOfOutputCorpus, MaxSize, - /*ExitOnError*/ false); + &EpochOfLastReadOfOutputCorpus); + if (Corpus.empty()) { + Corpus = AdditionalCorpus; + return; + } + if (!Options.Reload) return; if (Options.Verbosity >= 2) - Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); - bool Reloaded = false; - for (auto &U : AdditionalCorpus) { - if (U.size() > MaxSize) - U.resize(MaxSize); - if (!Corpus.HasUnit(U)) { - if (RunOne(U.data(), U.size())) - Reloaded = true; + Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); + for (auto &X : AdditionalCorpus) { + if (X.size() > (size_t)Options.MaxLen) + X.resize(Options.MaxLen); + if (UnitHashesAddedToCorpus.insert(Hash(X)).second) { + CurrentUnit.clear(); + CurrentUnit.insert(CurrentUnit.begin(), X.begin(), X.end()); + if (RunOne(CurrentUnit)) { + Corpus.push_back(X); + PrintStats("RELOAD"); + } } } - if (Reloaded) - PrintStats("RELOAD"); } -void Fuzzer::ShuffleCorpus(UnitVector *V) { - std::shuffle(V->begin(), V->end(), MD.GetRand()); - if (Options.PreferSmall) - std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) { - return A.size() < B.size(); - }); -} - -void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { - Printf("#0\tREAD units: %zd\n", InitialCorpus->size()); - if (Options.ShuffleAtStartUp) - ShuffleCorpus(InitialCorpus); - - // Test the callback with empty input and never try it again. - uint8_t dummy; - ExecuteCallback(&dummy, 0); - - for (const auto &U : *InitialCorpus) { - RunOne(U.data(), U.size()); - TryDetectingAMemoryLeak(U.data(), U.size(), - /*DuringInitialCorpusExecution*/ true); +void Fuzzer::ShuffleAndMinimize() { + bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 || + (Options.PreferSmallDuringInitialShuffle == -1 && + USF.GetRand().RandBool())); + if (Options.Verbosity) + Printf("PreferSmall: %d\n", PreferSmall); + PrintStats("READ "); + std::vector<Unit> NewCorpus; + if (Options.ShuffleAtStartUp) { + std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand()); + if (PreferSmall) + std::stable_sort( + Corpus.begin(), Corpus.end(), + [](const Unit &A, const Unit &B) { return A.size() < B.size(); }); } - PrintStats("INITED"); - if (Corpus.empty()) { - Printf("ERROR: no interesting inputs were found. " - "Is the code instrumented for coverage? Exiting.\n"); - exit(1); + Unit &U = CurrentUnit; + for (const auto &C : Corpus) { + for (size_t First = 0; First < 1; First++) { + U.clear(); + size_t Last = std::min(First + Options.MaxLen, C.size()); + U.insert(U.begin(), C.begin() + First, C.begin() + Last); + if (Options.OnlyASCII) + ToASCII(U); + if (RunOne(U)) { + NewCorpus.push_back(U); + if (Options.Verbosity >= 2) + Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size()); + } + } } + Corpus = NewCorpus; + for (auto &X : Corpus) + UnitHashesAddedToCorpus.insert(Hash(X)); + PrintStats("INITED"); } -void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { +bool Fuzzer::RunOne(const Unit &U) { + UnitStartTime = system_clock::now(); + TotalNumberOfRuns++; + + PrepareCoverageBeforeRun(); + ExecuteCallback(U); + bool Res = CheckCoverageAfterRun(); + + auto UnitStopTime = system_clock::now(); auto TimeOfUnit = duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && secondsSinceProcessStartUp() >= 2) PrintStats("pulse "); - if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && + if (TimeOfUnit > TimeOfLongestUnitInSeconds && TimeOfUnit >= Options.ReportSlowUnits) { TimeOfLongestUnitInSeconds = TimeOfUnit; Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); - WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); + WriteUnitToFileWithPrefix(U, "slow-unit-"); } + return Res; } -bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, - InputInfo *II) { - if (!Size) return false; - - ExecuteCallback(Data, Size); - - UniqFeatureSetTmp.clear(); - size_t FoundUniqFeaturesOfII = 0; - size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); - TPC.CollectFeatures([&](size_t Feature) { - if (Corpus.AddFeature(Feature, Size, Options.Shrink)) - UniqFeatureSetTmp.push_back(Feature); - if (Options.ReduceInputs && II) - if (std::binary_search(II->UniqFeatureSet.begin(), - II->UniqFeatureSet.end(), Feature)) - FoundUniqFeaturesOfII++; - }); - PrintPulseAndReportSlowInput(Data, Size); - size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; - if (NumNewFeatures) { - Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, - UniqFeatureSetTmp); - CheckExitOnSrcPosOrItem(); - return true; - } - if (II && FoundUniqFeaturesOfII && - FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && - II->U.size() > Size) { - Corpus.Replace(II, {Data, Data + Size}); - CheckExitOnSrcPosOrItem(); - return true; - } - return false; +void Fuzzer::RunOneAndUpdateCorpus(Unit &U) { + if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) + return; + if (Options.OnlyASCII) + ToASCII(U); + if (RunOne(U)) + ReportNewCoverage(U); +} + +void Fuzzer::ExecuteCallback(const Unit &U) { + const uint8_t *Data = U.data(); + uint8_t EmptyData; + if (!Data) + Data = &EmptyData; + int Res = USF.TargetFunction(Data, U.size()); + (void)Res; + assert(Res == 0); } -size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { - assert(InFuzzingThread()); - *Data = CurrentUnitData; - return CurrentUnitSize; +size_t Fuzzer::RecordBlockCoverage() { + CHECK_WEAK_API_FUNCTION(__sanitizer_get_total_unique_coverage); + uintptr_t PrevCoverage = LastRecordedBlockCoverage; + LastRecordedBlockCoverage = __sanitizer_get_total_unique_coverage(); + + if (PrevCoverage == LastRecordedBlockCoverage || !Options.PrintNewCovPcs) + return LastRecordedBlockCoverage; + + uintptr_t PrevBufferLen = LastCoveragePcBufferLen; + uintptr_t *CoverageBuf; + LastCoveragePcBufferLen = __sanitizer_get_coverage_pc_buffer(&CoverageBuf); + assert(CoverageBuf); + for (size_t i = PrevBufferLen; i < LastCoveragePcBufferLen; ++i) { + Printf("0x%x\n", CoverageBuf[i]); + } + + return LastRecordedBlockCoverage; } -void Fuzzer::CrashOnOverwrittenData() { - Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", - GetPid()); - DumpCurrentUnit("crash-"); - Printf("SUMMARY: libFuzzer: out-of-memory\n"); - _Exit(Options.ErrorExitCode); // Stop right now. +size_t Fuzzer::RecordCallerCalleeCoverage() { + if (!Options.UseIndirCalls) + return 0; + if (!__sanitizer_get_total_unique_caller_callee_pairs) + return 0; + return LastRecordedCallerCalleeCoverage = + __sanitizer_get_total_unique_caller_callee_pairs(); } -// Compare two arrays, but not all bytes if the arrays are large. -static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { - const size_t Limit = 64; - if (Size <= 64) - return !memcmp(A, B, Size); - // Compare first and last Limit/2 bytes. - return !memcmp(A, B, Limit / 2) && - !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); +void Fuzzer::PrepareCoverageBeforeRun() { + if (Options.UseCounters) { + size_t NumCounters = __sanitizer_get_number_of_counters(); + CounterBitmap.resize(NumCounters); + __sanitizer_update_counter_bitset_and_clear_counters(0); + } + RecordBlockCoverage(); + RecordCallerCalleeCoverage(); } -void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { - TotalNumberOfRuns++; - assert(InFuzzingThread()); - if (SMR.IsClient()) - SMR.WriteByteArray(Data, Size); - // We copy the contents of Unit into a separate heap buffer - // so that we reliably find buffer overflows in it. - uint8_t *DataCopy = new uint8_t[Size]; - memcpy(DataCopy, Data, Size); - if (CurrentUnitData && CurrentUnitData != Data) - memcpy(CurrentUnitData, Data, Size); - CurrentUnitSize = Size; - AllocTracer.Start(Options.TraceMalloc); - UnitStartTime = system_clock::now(); - TPC.ResetMaps(); - RunningCB = true; - int Res = CB(DataCopy, Size); - RunningCB = false; - UnitStopTime = system_clock::now(); - (void)Res; - assert(Res == 0); - HasMoreMallocsThanFrees = AllocTracer.Stop(); - if (!LooseMemeq(DataCopy, Data, Size)) - CrashOnOverwrittenData(); - CurrentUnitSize = 0; - delete[] DataCopy; +bool Fuzzer::CheckCoverageAfterRun() { + size_t OldCoverage = LastRecordedBlockCoverage; + size_t NewCoverage = RecordBlockCoverage(); + size_t OldCallerCalleeCoverage = LastRecordedCallerCalleeCoverage; + size_t NewCallerCalleeCoverage = RecordCallerCalleeCoverage(); + size_t NumNewBits = 0; + if (Options.UseCounters) + NumNewBits = __sanitizer_update_counter_bitset_and_clear_counters( + CounterBitmap.data()); + return NewCoverage > OldCoverage || + NewCallerCalleeCoverage > OldCallerCalleeCoverage || NumNewBits; } void Fuzzer::WriteToOutputCorpus(const Unit &U) { - if (Options.OnlyASCII) - assert(IsASCII(U)); - if (Options.OutputCorpus.empty()) - return; + if (Options.OutputCorpus.empty()) return; std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); WriteToFile(U, Path); if (Options.Verbosity >= 2) Printf("Written to %s\n", Path.c_str()); + assert(!Options.OnlyASCII || IsASCII(U)); } void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { @@ -499,7 +314,7 @@ void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { return; std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); if (!Options.ExactArtifactPath.empty()) - Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. + Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. WriteToFile(U, Path); Printf("artifact_prefix='%s'; Test unit written to %s\n", Options.ArtifactPrefix.c_str(), Path.c_str()); @@ -507,189 +322,191 @@ void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { Printf("Base64: %s\n", Base64(U).c_str()); } -void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { +void Fuzzer::SaveCorpus() { + if (Options.OutputCorpus.empty()) return; + for (const auto &U : Corpus) + WriteToFile(U, DirPlusFile(Options.OutputCorpus, Hash(U))); + if (Options.Verbosity) + Printf("Written corpus of %zd files to %s\n", Corpus.size(), + Options.OutputCorpus.c_str()); +} + +void Fuzzer::PrintStatusForNewUnit(const Unit &U) { if (!Options.PrintNEW) return; - PrintStats(Text, ""); + PrintStats("NEW ", ""); if (Options.Verbosity) { Printf(" L: %zd ", U.size()); - MD.PrintMutationSequence(); + USF.PrintMutationSequence(); Printf("\n"); } } -void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { - II->NumSuccessfullMutations++; - MD.RecordSuccessfulMutationSequence(); - PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : - "NEW "); +void Fuzzer::ReportNewCoverage(const Unit &U) { + Corpus.push_back(U); + UnitHashesAddedToCorpus.insert(Hash(U)); + PrintStatusForNewUnit(U); WriteToOutputCorpus(U); - NumberOfNewUnitsAdded++; - TPC.PrintNewPCs(); + if (Options.ExitOnFirst) + exit(0); } -// Tries detecting a memory leak on the particular input that we have just -// executed before calling this function. -void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, - bool DuringInitialCorpusExecution) { - if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. - if (!Options.DetectLeaks) return; - if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || - !(EF->__lsan_do_recoverable_leak_check)) - return; // No lsan. - // Run the target once again, but with lsan disabled so that if there is - // a real leak we do not report it twice. - EF->__lsan_disable(); - ExecuteCallback(Data, Size); - EF->__lsan_enable(); - if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. - if (NumberOfLeakDetectionAttempts++ > 1000) { - Options.DetectLeaks = false; - Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" - " Most likely the target function accumulates allocated\n" - " memory in a global state w/o actually leaking it.\n" - " You may try running this binary with -trace_malloc=[12]" - " to get a trace of mallocs and frees.\n" - " If LeakSanitizer is enabled in this process it will still\n" - " run on the process shutdown.\n"); +void Fuzzer::Merge(const std::vector<std::string> &Corpora) { + if (Corpora.size() <= 1) { + Printf("Merge requires two or more corpus dirs\n"); return; } - // Now perform the actual lsan pass. This is expensive and we must ensure - // we don't call it too often. - if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. - if (DuringInitialCorpusExecution) - Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); - Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); - CurrentUnitSize = Size; - DumpCurrentUnit("leak-"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. + auto InitialCorpusDir = Corpora[0]; + ReadDir(InitialCorpusDir, nullptr); + Printf("Merge: running the initial corpus '%s' of %d units\n", + InitialCorpusDir.c_str(), Corpus.size()); + for (auto &U : Corpus) + RunOne(U); + + std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end()); + + size_t NumTried = 0; + size_t NumMerged = 0; + for (auto &C : ExtraCorpora) { + Corpus.clear(); + ReadDir(C, nullptr); + Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(), + Corpus.size()); + for (auto &U : Corpus) { + NumTried++; + if (RunOne(U)) { + WriteToOutputCorpus(U); + NumMerged++; + } + } } -} - -static size_t ComputeMutationLen(size_t MaxInputSize, size_t MaxMutationLen, - Random &Rand) { - assert(MaxInputSize <= MaxMutationLen); - if (MaxInputSize == MaxMutationLen) return MaxMutationLen; - size_t Result = MaxInputSize; - size_t R = Rand.Rand(); - if ((R % (1U << 7)) == 0) - Result++; - if ((R % (1U << 15)) == 0) - Result += 10 + Result / 2; - return Min(Result, MaxMutationLen); + Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried); } void Fuzzer::MutateAndTestOne() { - MD.StartMutationSequence(); - - auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); - const auto &U = II.U; - memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); - assert(CurrentUnitData); - size_t Size = U.size(); - assert(Size <= MaxInputLen && "Oversized Unit"); - memcpy(CurrentUnitData, U.data(), Size); + auto &U = CurrentUnit; + USF.StartMutationSequence(); - assert(MaxMutationLen > 0); - - size_t CurrentMaxMutationLen = - Options.ExperimentalLenControl - ? ComputeMutationLen(Corpus.MaxInputSize(), MaxMutationLen, - MD.GetRand()) - : MaxMutationLen; + U = ChooseUnitToMutate(); for (int i = 0; i < Options.MutateDepth; i++) { - if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) - break; - size_t NewSize = 0; - NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); + size_t Size = U.size(); + U.resize(Options.MaxLen); + size_t NewSize = USF.Mutate(U.data(), Size, U.size()); assert(NewSize > 0 && "Mutator returned empty unit"); - assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); - Size = NewSize; - II.NumExecutedMutations++; - if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) - ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); - - TryDetectingAMemoryLeak(CurrentUnitData, Size, - /*DuringInitialCorpusExecution*/ false); + assert(NewSize <= (size_t)Options.MaxLen && + "Mutator return overisized unit"); + U.resize(NewSize); + if (i == 0) + StartTraceRecording(); + RunOneAndUpdateCorpus(U); + StopTraceRecording(); } } +// Returns an index of random unit from the corpus to mutate. +// Hypothesis: units added to the corpus last are more likely to be interesting. +// This function gives more wieght to the more recent units. +size_t Fuzzer::ChooseUnitIdxToMutate() { + size_t N = Corpus.size(); + size_t Total = (N + 1) * N / 2; + size_t R = USF.GetRand()(Total); + size_t IdxBeg = 0, IdxEnd = N; + // Binary search. + while (IdxEnd - IdxBeg >= 2) { + size_t Idx = IdxBeg + (IdxEnd - IdxBeg) / 2; + if (R > (Idx + 1) * Idx / 2) + IdxBeg = Idx; + else + IdxEnd = Idx; + } + assert(IdxBeg < N); + return IdxBeg; +} + +// Experimental search heuristic: drilling. +// - Read, shuffle, execute and minimize the corpus. +// - Choose one random unit. +// - Reset the coverage. +// - Start fuzzing as if the chosen unit was the only element of the corpus. +// - When done, reset the coverage again. +// - Merge the newly created corpus into the original one. +void Fuzzer::Drill() { + // The corpus is already read, shuffled, and minimized. + assert(!Corpus.empty()); + Options.PrintNEW = false; // Don't print NEW status lines when drilling. + + Unit U = ChooseUnitToMutate(); + + CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage); + __sanitizer_reset_coverage(); + + std::vector<Unit> SavedCorpus; + SavedCorpus.swap(Corpus); + Corpus.push_back(U); + assert(Corpus.size() == 1); + RunOne(U); + PrintStats("DRILL "); + std::string SavedOutputCorpusPath; // Don't write new units while drilling. + SavedOutputCorpusPath.swap(Options.OutputCorpus); + Loop(); + + __sanitizer_reset_coverage(); + + PrintStats("REINIT"); + SavedOutputCorpusPath.swap(Options.OutputCorpus); + for (auto &U : SavedCorpus) { + CurrentUnit = U; + RunOne(U); + } + PrintStats("MERGE "); + Options.PrintNEW = true; + size_t NumMerged = 0; + for (auto &U : Corpus) { + CurrentUnit = U; + if (RunOne(U)) { + PrintStatusForNewUnit(U); + NumMerged++; + WriteToOutputCorpus(U); + } + } + PrintStats("MERGED"); + if (NumMerged && Options.Verbosity) + Printf("Drilling discovered %zd new units\n", NumMerged); +} + void Fuzzer::Loop() { - TPC.InitializePrintNewPCs(); system_clock::time_point LastCorpusReload = system_clock::now(); if (Options.DoCrossOver) - MD.SetCorpus(&Corpus); + USF.SetCorpus(&Corpus); while (true) { + SyncCorpus(); auto Now = system_clock::now(); - if (duration_cast<seconds>(Now - LastCorpusReload).count() >= - Options.ReloadIntervalSec) { - RereadOutputCorpus(MaxInputLen); - LastCorpusReload = system_clock::now(); + if (duration_cast<seconds>(Now - LastCorpusReload).count()) { + RereadOutputCorpus(); + LastCorpusReload = Now; } if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) break; - if (TimedOut()) break; + if (Options.MaxTotalTimeSec > 0 && + secondsSinceProcessStartUp() > + static_cast<size_t>(Options.MaxTotalTimeSec)) + break; // Perform several mutations and runs. MutateAndTestOne(); } PrintStats("DONE ", "\n"); - MD.PrintRecommendedDictionary(); -} - -void Fuzzer::MinimizeCrashLoop(const Unit &U) { - if (U.size() <= 1) return; - while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { - MD.StartMutationSequence(); - memcpy(CurrentUnitData, U.data(), U.size()); - for (int i = 0; i < Options.MutateDepth; i++) { - size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); - assert(NewSize > 0 && NewSize <= MaxMutationLen); - ExecuteCallback(CurrentUnitData, NewSize); - PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); - TryDetectingAMemoryLeak(CurrentUnitData, NewSize, - /*DuringInitialCorpusExecution*/ false); - } - } -} - -void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { - if (SMR.IsServer()) { - SMR.WriteByteArray(Data, Size); - } else if (SMR.IsClient()) { - SMR.PostClient(); - SMR.WaitServer(); - size_t OtherSize = SMR.ReadByteArraySize(); - uint8_t *OtherData = SMR.GetByteArray(); - if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { - size_t i = 0; - for (i = 0; i < Min(Size, OtherSize); i++) - if (Data[i] != OtherData[i]) - break; - Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " - "offset %zd\n", GetPid(), Size, OtherSize, i); - DumpCurrentUnit("mismatch-"); - Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); - PrintFinalStats(); - _Exit(Options.ErrorExitCode); - } - } } -} // namespace fuzzer - -extern "C" { - -size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { - assert(fuzzer::F); - return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); +void Fuzzer::SyncCorpus() { + if (Options.SyncCommand.empty() || Options.OutputCorpus.empty()) return; + auto Now = system_clock::now(); + if (duration_cast<seconds>(Now - LastExternalSync).count() < + Options.SyncTimeout) + return; + LastExternalSync = Now; + ExecuteCommand(Options.SyncCommand + " " + Options.OutputCorpus); } -// Experimental -void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { - assert(fuzzer::F); - fuzzer::F->AnnounceOutput(Data, Size); -} -} // extern "C" +} // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp index af8657200be..c5af5b05909 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerMain.cpp @@ -9,13 +9,12 @@ // main() and flags. //===----------------------------------------------------------------------===// -#include "FuzzerDefs.h" +#include "FuzzerInterface.h" +#include "FuzzerInternal.h" -extern "C" { // This function should be defined by the user. -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); -} // extern "C" +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); int main(int argc, char **argv) { - return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput); + return fuzzer::FuzzerDriver(argc, argv, LLVMFuzzerTestOneInput); } diff --git a/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp index 5998ef9d319..30e5b43c083 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerMutate.cpp @@ -9,113 +9,95 @@ // Mutate a test input. //===----------------------------------------------------------------------===// -#include "FuzzerMutate.h" -#include "FuzzerCorpus.h" -#include "FuzzerDefs.h" -#include "FuzzerExtFunctions.h" -#include "FuzzerIO.h" -#include "FuzzerOptions.h" +#include <cstring> -namespace fuzzer { - -const size_t Dictionary::kMaxDictSize; +#include "FuzzerInternal.h" -static void PrintASCII(const Word &W, const char *PrintAfter) { - PrintASCII(W.data(), W.size(), PrintAfter); -} +#include <algorithm> -MutationDispatcher::MutationDispatcher(Random &Rand, - const FuzzingOptions &Options) - : Rand(Rand), Options(Options) { - DefaultMutators.insert( - DefaultMutators.begin(), - { - {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, - {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, - {&MutationDispatcher::Mutate_InsertRepeatedBytes, - "InsertRepeatedBytes"}, - {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, - {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, - {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, - {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, - {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, - {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, - {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, - {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "ManualDict"}, - {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "PersAutoDict"}, - }); - if(Options.UseCmp) - DefaultMutators.push_back( - {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); +namespace fuzzer { - if (EF->LLVMFuzzerCustomMutator) - Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); +struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; +}; + +struct DictionaryEntry { + Unit Word; + size_t PositionHint; +}; + +struct MutationDispatcher::Impl { + std::vector<DictionaryEntry> ManualDictionary; + std::vector<DictionaryEntry> AutoDictionary; + std::vector<Mutator> Mutators; + std::vector<Mutator> CurrentMutatorSequence; + std::vector<DictionaryEntry> CurrentDictionaryEntrySequence; + const std::vector<Unit> *Corpus = nullptr; + FuzzerRandomBase &Rand; + + void Add(Mutator M) { Mutators.push_back(M); } + Impl(FuzzerRandomBase &Rand) : Rand(Rand) { + Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"}); + Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"}); + Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}); + Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}); + Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}); + Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}); + Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"}); + Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}); + Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary, + "AddFromAutoDict"}); + } + void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; } + size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D, + uint8_t *Data, size_t Size, size_t MaxSize); +}; + +static char FlipRandomBit(char X, FuzzerRandomBase &Rand) { + int Bit = Rand(8); + char Mask = 1 << Bit; + char R; + if (X & (1 << Bit)) + R = X & ~Mask; else - Mutators = DefaultMutators; - - if (EF->LLVMFuzzerCustomCrossOver) - Mutators.push_back( - {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); + R = X | Mask; + assert(R != X); + return R; } -static char RandCh(Random &Rand) { +static char RandCh(FuzzerRandomBase &Rand) { if (Rand.RandBool()) return Rand(256); - const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; + const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~."; return Special[Rand(sizeof(Special) - 1)]; } -size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, - size_t MaxSize) { - return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); -} - -size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (!Corpus || Corpus->size() < 2 || Size == 0) - return 0; - size_t Idx = Rand(Corpus->size()); - const Unit &Other = (*Corpus)[Idx]; - if (Other.empty()) - return 0; - CustomCrossOverInPlaceHere.resize(MaxSize); - auto &U = CustomCrossOverInPlaceHere; - size_t NewSize = EF->LLVMFuzzerCustomCrossOver( - Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); - if (!NewSize) - return 0; - assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); - memcpy(Data, U.data(), NewSize); - return NewSize; -} - size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize || Size == 0) return 0; + assert(Size); size_t ShuffleAmount = Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. size_t ShuffleStart = Rand(Size - ShuffleAmount); assert(ShuffleStart + ShuffleAmount <= Size); - std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); + std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, + Rand); return Size; } -size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size <= 1) return 0; - size_t N = Rand(Size / 2) + 1; - assert(N < Size); - size_t Idx = Rand(Size - N + 1); - // Erase Data[Idx:Idx+N]. - memmove(Data + Idx, Data + Idx + N, Size - Idx - N); - // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); - return Size - N; +size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size, + size_t MaxSize) { + assert(Size); + if (Size == 1) return 0; + size_t Idx = Rand(Size); + // Erase Data[Idx]. + memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1); + return Size - 1; } size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size >= MaxSize) return 0; + if (Size == MaxSize) return 0; size_t Idx = Rand(Size + 1); // Insert new value at Data[Idx]. memmove(Data + Idx + 1, Data + Idx, Size - Idx); @@ -123,27 +105,8 @@ size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, return Size + 1; } -size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, - size_t Size, - size_t MaxSize) { - const size_t kMinBytesToInsert = 3; - if (Size + kMinBytesToInsert >= MaxSize) return 0; - size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); - size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; - assert(Size + N <= MaxSize && N); - size_t Idx = Rand(Size + 1); - // Insert new values at Data[Idx]. - memmove(Data + Idx + N, Data + Idx, Size - Idx); - // Give preference to 0x00 and 0xff. - uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); - for (size_t i = 0; i < N; i++) - Data[Idx + i] = Byte; - return Size + N; -} - size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; size_t Idx = Rand(Size); Data[Idx] = RandCh(Rand); return Size; @@ -151,203 +114,51 @@ size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; size_t Idx = Rand(Size); - Data[Idx] ^= 1 << Rand(8); + Data[Idx] = FlipRandomBit(Data[Idx], Rand); return Size; } size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, size_t MaxSize) { - return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); + return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size, + MaxSize); } -size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, - size_t MaxSize, - DictionaryEntry &DE) { - const Word &W = DE.GetW(); - bool UsePositionHint = DE.HasPositionHint() && - DE.GetPositionHint() + W.size() < Size && - Rand.RandBool(); - if (Rand.RandBool()) { // Insert W. - if (Size + W.size() > MaxSize) return 0; - size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); - memmove(Data + Idx + W.size(), Data + Idx, Size - Idx); - memcpy(Data + Idx, W.data(), W.size()); - Size += W.size(); - } else { // Overwrite some bytes with W. - if (W.size() > Size) return 0; - size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); - memcpy(Data + Idx, W.data(), W.size()); - } - return Size; -} - -// Somewhere in the past we have observed a comparison instructions -// with arguments Arg1 Arg2. This function tries to guess a dictionary -// entry that will satisfy that comparison. -// It first tries to find one of the arguments (possibly swapped) in the -// input and if it succeeds it creates a DE with a position hint. -// Otherwise it creates a DE with one of the arguments w/o a position hint. -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - const void *Arg1, const void *Arg2, - const void *Arg1Mutation, const void *Arg2Mutation, - size_t ArgSize, const uint8_t *Data, - size_t Size) { - ScopedDoingMyOwnMemOrStr scoped_doing_my_own_mem_os_str; - bool HandleFirst = Rand.RandBool(); - const void *ExistingBytes, *DesiredBytes; - Word W; - const uint8_t *End = Data + Size; - for (int Arg = 0; Arg < 2; Arg++) { - ExistingBytes = HandleFirst ? Arg1 : Arg2; - DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation; - HandleFirst = !HandleFirst; - W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize); - const size_t kMaxNumPositions = 8; - size_t Positions[kMaxNumPositions]; - size_t NumPositions = 0; - for (const uint8_t *Cur = Data; - Cur < End && NumPositions < kMaxNumPositions; Cur++) { - Cur = - (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize); - if (!Cur) break; - Positions[NumPositions++] = Cur - Data; - } - if (!NumPositions) continue; - return DictionaryEntry(W, Positions[Rand(NumPositions)]); - } - DictionaryEntry DE(W); - return DE; -} - - -template <class T> -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - T Arg1, T Arg2, const uint8_t *Data, size_t Size) { - if (Rand.RandBool()) Arg1 = Bswap(Arg1); - if (Rand.RandBool()) Arg2 = Bswap(Arg2); - T Arg1Mutation = Arg1 + Rand(-1, 1); - T Arg2Mutation = Arg2 + Rand(-1, 1); - return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation, - sizeof(Arg1), Data, Size); -} - -DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( - const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) { - return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(), - Arg2.data(), Arg1.size(), Data, Size); -} - -size_t MutationDispatcher::Mutate_AddWordFromTORC( - uint8_t *Data, size_t Size, size_t MaxSize) { - Word W; - DictionaryEntry DE; - switch (Rand(4)) { - case 0: { - auto X = TPC.TORC8.Get(Rand.Rand()); - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 1: { - auto X = TPC.TORC4.Get(Rand.Rand()); - if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) - DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size); - else - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 2: { - auto X = TPC.TORCW.Get(Rand.Rand()); - DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); - } break; - case 3: if (Options.UseMemmem) { - auto X = TPC.MMT.Get(Rand.Rand()); - DE = DictionaryEntry(X); - } break; - default: - assert(0); - } - if (!DE.GetW().size()) return 0; - Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); - if (!Size) return 0; - DictionaryEntry &DERef = - CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % - kCmpDictionaryEntriesDequeSize]; - DERef = DE; - CurrentDictionaryEntrySequence.push_back(&DERef); - return Size; +size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data, + size_t Size, + size_t MaxSize) { + return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size, + MaxSize); } -size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( - uint8_t *Data, size_t Size, size_t MaxSize) { - return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); -} - -size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, - size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; +size_t MutationDispatcher::Impl::AddWordFromDictionary( + const std::vector<DictionaryEntry> &D, uint8_t *Data, size_t Size, + size_t MaxSize) { if (D.empty()) return 0; - DictionaryEntry &DE = D[Rand(D.size())]; - Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); - if (!Size) return 0; - DE.IncUseCount(); - CurrentDictionaryEntrySequence.push_back(&DE); - return Size; -} - -// Overwrites part of To[0,ToSize) with a part of From[0,FromSize). -// Returns ToSize. -size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize, - uint8_t *To, size_t ToSize) { - // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize). - size_t ToBeg = Rand(ToSize); - size_t CopySize = Rand(ToSize - ToBeg) + 1; - assert(ToBeg + CopySize <= ToSize); - CopySize = std::min(CopySize, FromSize); - size_t FromBeg = Rand(FromSize - CopySize + 1); - assert(FromBeg + CopySize <= FromSize); - memmove(To + ToBeg, From + FromBeg, CopySize); - return ToSize; -} - -// Inserts part of From[0,ToSize) into To. -// Returns new size of To on success or 0 on failure. -size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize, - uint8_t *To, size_t ToSize, - size_t MaxToSize) { - if (ToSize >= MaxToSize) return 0; - size_t AvailableSpace = MaxToSize - ToSize; - size_t MaxCopySize = std::min(AvailableSpace, FromSize); - size_t CopySize = Rand(MaxCopySize) + 1; - size_t FromBeg = Rand(FromSize - CopySize + 1); - assert(FromBeg + CopySize <= FromSize); - size_t ToInsertPos = Rand(ToSize + 1); - assert(ToInsertPos + CopySize <= MaxToSize); - size_t TailSize = ToSize - ToInsertPos; - if (To == From) { - MutateInPlaceHere.resize(MaxToSize); - memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize); - memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); - memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize); - } else { - memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); - memmove(To + ToInsertPos, From + FromBeg, CopySize); + const DictionaryEntry &DE = D[Rand(D.size())]; + const Unit &Word = DE.Word; + size_t PositionHint = DE.PositionHint; + bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() && + PositionHint + Word.size() < Size && Rand.RandBool(); + if (Rand.RandBool()) { // Insert Word. + if (Size + Word.size() > MaxSize) return 0; + size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1); + memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx); + memcpy(Data + Idx, Word.data(), Word.size()); + Size += Word.size(); + } else { // Overwrite some bytes with Word. + if (Word.size() > Size) return 0; + size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size()); + memcpy(Data + Idx, Word.data(), Word.size()); } - return ToSize + CopySize; -} - -size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, - size_t MaxSize) { - if (Size > MaxSize || Size == 0) return 0; - if (Rand.RandBool()) - return CopyPartOf(Data, Size, Data, Size); - else - return InsertPartOf(Data, Size, Data, Size, MaxSize); + CurrentDictionaryEntrySequence.push_back(DE); + return Size; } size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; size_t B = Rand(Size); while (B < Size && !isdigit(Data[B])) B++; if (B == Size) return 0; @@ -379,69 +190,16 @@ size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, return Size; } -template<class T> -size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { - if (Size < sizeof(T)) return 0; - size_t Off = Rand(Size - sizeof(T) + 1); - assert(Off + sizeof(T) <= Size); - T Val; - if (Off < 64 && !Rand(4)) { - Val = Size; - if (Rand.RandBool()) - Val = Bswap(Val); - } else { - memcpy(&Val, Data + Off, sizeof(Val)); - T Add = Rand(21); - Add -= 10; - if (Rand.RandBool()) - Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. - else - Val = Val + Add; // Add assuming current endiannes. - if (Add == 0 || Rand.RandBool()) // Maybe negate. - Val = -Val; - } - memcpy(Data + Off, &Val, sizeof(Val)); - return Size; -} - -size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, - size_t Size, - size_t MaxSize) { - if (Size > MaxSize) return 0; - switch (Rand(4)) { - case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand); - case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand); - case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand); - case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand); - default: assert(0); - } - return 0; -} - size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize) { - if (Size > MaxSize) return 0; + auto Corpus = MDImpl->Corpus; if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; size_t Idx = Rand(Corpus->size()); - const Unit &O = (*Corpus)[Idx]; - if (O.empty()) return 0; - MutateInPlaceHere.resize(MaxSize); - auto &U = MutateInPlaceHere; - size_t NewSize = 0; - switch(Rand(3)) { - case 0: - NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size()); - break; - case 1: - NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize); - if (!NewSize) - NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); - break; - case 2: - NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); - break; - default: assert(0); - } + const Unit &Other = (*Corpus)[Idx]; + if (Other.empty()) return 0; + Unit U(MaxSize); + size_t NewSize = + CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size()); assert(NewSize > 0 && "CrossOver returned empty unit"); assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); memcpy(Data, U.data(), NewSize); @@ -449,85 +207,72 @@ size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, } void MutationDispatcher::StartMutationSequence() { - CurrentMutatorSequence.clear(); - CurrentDictionaryEntrySequence.clear(); -} - -// Copy successful dictionary entries to PersistentAutoDictionary. -void MutationDispatcher::RecordSuccessfulMutationSequence() { - for (auto DE : CurrentDictionaryEntrySequence) { - // PersistentAutoDictionary.AddWithSuccessCountOne(DE); - DE->IncSuccessCount(); - assert(DE->GetW().size()); - // Linear search is fine here as this happens seldom. - if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) - PersistentAutoDictionary.push_back({DE->GetW(), 1}); - } -} - -void MutationDispatcher::PrintRecommendedDictionary() { - std::vector<DictionaryEntry> V; - for (auto &DE : PersistentAutoDictionary) - if (!ManualDictionary.ContainsWord(DE.GetW())) - V.push_back(DE); - if (V.empty()) return; - Printf("###### Recommended dictionary. ######\n"); - for (auto &DE: V) { - assert(DE.GetW().size()); - Printf("\""); - PrintASCII(DE.GetW(), "\""); - Printf(" # Uses: %zd\n", DE.GetUseCount()); - } - Printf("###### End of recommended dictionary. ######\n"); + MDImpl->CurrentMutatorSequence.clear(); + MDImpl->CurrentDictionaryEntrySequence.clear(); } void MutationDispatcher::PrintMutationSequence() { - Printf("MS: %zd ", CurrentMutatorSequence.size()); - for (auto M : CurrentMutatorSequence) + Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size()); + for (auto M : MDImpl->CurrentMutatorSequence) Printf("%s-", M.Name); - if (!CurrentDictionaryEntrySequence.empty()) { + if (!MDImpl->CurrentDictionaryEntrySequence.empty()) { Printf(" DE: "); - for (auto DE : CurrentDictionaryEntrySequence) { + for (auto DE : MDImpl->CurrentDictionaryEntrySequence) { Printf("\""); - PrintASCII(DE->GetW(), "\"-"); + PrintASCII(DE.Word, "\"-"); } } } -size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { - return MutateImpl(Data, Size, MaxSize, Mutators); -} - -size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, - size_t MaxSize) { - return MutateImpl(Data, Size, MaxSize, DefaultMutators); -} - // Mutates Data in place, returns new size. -size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, - size_t MaxSize, - const std::vector<Mutator> &Mutators) { +size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(MaxSize > 0); + assert(Size <= MaxSize); + if (Size == 0) { + for (size_t i = 0; i < MaxSize; i++) + Data[i] = RandCh(Rand); + return MaxSize; + } + assert(Size > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. // Try several times before returning un-mutated data. - for (int Iter = 0; Iter < 100; Iter++) { - auto M = Mutators[Rand(Mutators.size())]; + for (int Iter = 0; Iter < 10; Iter++) { + size_t MutatorIdx = Rand(MDImpl->Mutators.size()); + auto M = MDImpl->Mutators[MutatorIdx]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); - if (NewSize && NewSize <= MaxSize) { - if (Options.OnlyASCII) - ToASCII(Data, NewSize); - CurrentMutatorSequence.push_back(M); + if (NewSize) { + MDImpl->CurrentMutatorSequence.push_back(M); return NewSize; } } - *Data = ' '; - return 1; // Fallback, should not happen frequently. + return Size; +} + +void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) { + MDImpl->SetCorpus(Corpus); +} + +void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) { + MDImpl->ManualDictionary.push_back( + {Word, std::numeric_limits<size_t>::max()}); } -void MutationDispatcher::AddWordToManualDictionary(const Word &W) { - ManualDictionary.push_back( - {W, std::numeric_limits<size_t>::max()}); +void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word, + size_t PositionHint) { + static const size_t kMaxAutoDictSize = 1 << 14; + if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return; + MDImpl->AutoDictionary.push_back({Word, PositionHint}); } +void MutationDispatcher::ClearAutoDictionary() { + MDImpl->AutoDictionary.clear(); +} + +MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) { + MDImpl = new Impl(Rand); +} + +MutationDispatcher::~MutationDispatcher() { delete MDImpl; } + } // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp index d2f8e811bbf..b42a04854cd 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerSHA1.cpp @@ -16,15 +16,12 @@ // For the same reason we do not want to depend on SHA1 from LLVM tree. //===----------------------------------------------------------------------===// -#include "FuzzerSHA1.h" -#include "FuzzerDefs.h" +#include "FuzzerInternal.h" /* This code is public-domain - it is based on libcrypt * placed in the public domain by Wei Dai and other contributors. */ -#include <iomanip> -#include <sstream> #include <stdint.h> #include <string.h> @@ -196,27 +193,10 @@ uint8_t* sha1_result(sha1nfo *s) { } // namespace; Added for LibFuzzer -namespace fuzzer { - // The rest is added for LibFuzzer -void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { +void fuzzer::ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) { sha1nfo s; sha1_init(&s); sha1_write(&s, (const char*)Data, Len); memcpy(Out, sha1_result(&s), HASH_LENGTH); } - -std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) { - std::stringstream SS; - for (int i = 0; i < kSHA1NumBytes; i++) - SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i]; - return SS.str(); -} - -std::string Hash(const Unit &U) { - uint8_t Hash[kSHA1NumBytes]; - ComputeSHA1(U.data(), U.size(), Hash); - return Sha1ToString(Hash); -} - -} diff --git a/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp index 2d95f40e46a..d7226cfce96 100644 --- a/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp +++ b/gnu/llvm/lib/Fuzzer/FuzzerUtil.cpp @@ -9,30 +9,22 @@ // Misc utils. //===----------------------------------------------------------------------===// -#include "FuzzerUtil.h" -#include "FuzzerIO.h" #include "FuzzerInternal.h" +#include <sstream> +#include <iomanip> +#include <sys/time.h> #include <cassert> -#include <chrono> #include <cstring> -#include <errno.h> #include <signal.h> #include <sstream> -#include <stdio.h> -#include <sys/types.h> -#include <thread> +#include <unistd.h> namespace fuzzer { -void PrintHexArray(const uint8_t *Data, size_t Size, - const char *PrintAfter) { - for (size_t i = 0; i < Size; i++) - Printf("0x%x,", (unsigned)Data[i]); - Printf("%s", PrintAfter); -} - void Print(const Unit &v, const char *PrintAfter) { - PrintHexArray(v.data(), v.size(), PrintAfter); + for (auto x : v) + Printf("0x%x,", (unsigned) x); + Printf("%s", PrintAfter); } void PrintASCIIByte(uint8_t Byte) { @@ -53,13 +45,50 @@ void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { } void PrintASCII(const Unit &U, const char *PrintAfter) { - PrintASCII(U.data(), U.size(), PrintAfter); + for (auto X : U) + PrintASCIIByte(X); + Printf("%s", PrintAfter); } -bool ToASCII(uint8_t *Data, size_t Size) { +std::string Hash(const Unit &U) { + uint8_t Hash[kSHA1NumBytes]; + ComputeSHA1(U.data(), U.size(), Hash); + std::stringstream SS; + for (int i = 0; i < kSHA1NumBytes; i++) + SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Hash[i]; + return SS.str(); +} + +static void AlarmHandler(int, siginfo_t *, void *) { + Fuzzer::StaticAlarmCallback(); +} + +void SetTimer(int Seconds) { + struct itimerval T {{Seconds, 0}, {Seconds, 0}}; + int Res = setitimer(ITIMER_REAL, &T, nullptr); + assert(Res == 0); + struct sigaction sigact; + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_sigaction = AlarmHandler; + Res = sigaction(SIGALRM, &sigact, 0); + assert(Res == 0); +} + +int NumberOfCpuCores() { + FILE *F = popen("nproc", "r"); + int N = 0; + fscanf(F, "%d", &N); + fclose(F); + return N; +} + +int ExecuteCommand(const std::string &Command) { + return system(Command.c_str()); +} + +bool ToASCII(Unit &U) { bool Changed = false; - for (size_t i = 0; i < Size; i++) { - uint8_t &X = Data[i]; + for (auto &X : U) { auto NewX = X; NewX &= 127; if (!isspace(NewX) && !isprint(NewX)) @@ -70,11 +99,9 @@ bool ToASCII(uint8_t *Data, size_t Size) { return Changed; } -bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); } - -bool IsASCII(const uint8_t *Data, size_t Size) { - for (size_t i = 0; i < Size; i++) - if (!(isprint(Data[i]) || isspace(Data[i]))) return false; +bool IsASCII(const Unit &U) { + for (auto X : U) + if (!(isprint(X) || isspace(X))) return false; return true; } @@ -151,6 +178,9 @@ bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) { return true; } +int GetPid() { return getpid(); } + + std::string Base64(const Unit &U) { static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" @@ -179,47 +209,4 @@ std::string Base64(const Unit &U) { return Res; } -std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) { - if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>"; - char PcDescr[1024]; - EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC), - SymbolizedFMT, PcDescr, sizeof(PcDescr)); - PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case. - return PcDescr; -} - -void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) { - if (EF->__sanitizer_symbolize_pc) - Printf("%s", DescribePC(SymbolizedFMT, PC).c_str()); - else - Printf(FallbackFMT, PC); -} - -unsigned NumberOfCpuCores() { - unsigned N = std::thread::hardware_concurrency(); - if (!N) { - Printf("WARNING: std::thread::hardware_concurrency not well defined for " - "your platform. Assuming CPU count of 1.\n"); - N = 1; - } - return N; -} - -bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) { - FILE *Pipe = OpenProcessPipe(Command.c_str(), "r"); - if (!Pipe) return false; - char Buff[1024]; - size_t N; - while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0) - Out->append(Buff, N); - return true; -} - -size_t SimpleFastHash(const uint8_t *Data, size_t Size) { - size_t Res = 0; - for (size_t i = 0; i < Size; i++) - Res = Res * 11 + Data[i]; - return Res; -} - } // namespace fuzzer diff --git a/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt index 43aea2b7a18..cd0b167eb38 100644 --- a/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt +++ b/gnu/llvm/lib/Fuzzer/test/CMakeLists.txt @@ -1,277 +1,118 @@ # Build all these tests with -O0, otherwise optimizations may merge some # basic blocks and we'll fail to discover the targets. -# We change the flags for every build type because we might be doing -# a multi-configuration build (e.g. Xcode) where CMAKE_BUILD_TYPE doesn't -# mean anything. -set(variables_to_filter - CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_DEBUG - CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_MINSIZEREL - LIBFUZZER_FLAGS_BASE - ) -foreach (VARNAME ${variables_to_filter}) - string(REGEX REPLACE "([-/]O)[123s]" "\\10" ${VARNAME} "${${VARNAME}}") -endforeach() - -# Enable the coverage instrumentation (it is disabled for the Fuzzer lib). -set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fsanitize-coverage=trace-pc-guard,indirect-calls,trace-cmp,trace-div,trace-gep -gline-tables-only") - -if(MSVC) - # For tests use the CRT specified for release build - # (asan doesn't support MDd and MTd) - if ("${LLVM_USE_CRT_RELEASE}" STREQUAL "") - set(CRT_FLAG " /MD ") - else() - set(CRT_FLAG " /${LLVM_USE_CRT_RELEASE} ") - endif() - # In order to use the sanitizers in Windows, we need to link against many - # runtime libraries which will depend on the target being created - # (executable or dll) and the c runtime library used (MT/MD). - # By default, cmake uses link.exe for linking, which fails because we don't - # specify the appropiate dependencies. - # As we don't want to consider all of that possible situations which depends - # on the implementation of the compiler-rt, the simplest option is to change - # the rules for linking executables and shared libraries, using the compiler - # instead of link.exe. Clang will consider the sanitizer flags, and - # automatically provide the required libraries to the linker. - set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> ${CMAKE_CXX_FLAGS} ${CRT_FLAG} <OBJECTS> -o <TARGET> <LINK_LIBRARIES> /link <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS>") - set(CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_CXX_COMPILER> ${CMAKE_CXX_FLAGS} ${CRT_FLAG} /LD <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG> <TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES> /link <LINK_FLAGS>") -endif() - -add_custom_target(TestBinaries) - -# add_libfuzzer_test(<name> -# SOURCES source0.cpp [source1.cpp ...] -# ) -# -# Declares a LibFuzzer test executable with target name LLVMFuzzer-<name>. -# -# One or more source files to be compiled into the binary must be declared -# after the SOURCES keyword. -function(add_libfuzzer_test name) - set(multi_arg_options "SOURCES") - cmake_parse_arguments( - "add_libfuzzer_test" "" "" "${multi_arg_options}" ${ARGN}) - if ("${add_libfuzzer_test_SOURCES}" STREQUAL "") - message(FATAL_ERROR "Source files must be specified") - endif() - add_executable(LLVMFuzzer-${name} - ${add_libfuzzer_test_SOURCES} - ) - target_link_libraries(LLVMFuzzer-${name} LLVMFuzzer) - # Place binary where llvm-lit expects to find it - set_target_properties(LLVMFuzzer-${name} - PROPERTIES RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_BINARY_DIR}/lib/Fuzzer/test" - ) - add_dependencies(TestBinaries LLVMFuzzer-${name}) -endfunction() +# Also enable the coverage instrumentation back (it is disabled +# for the Fuzzer lib) +set(CMAKE_CXX_FLAGS_RELEASE "${LIBFUZZER_FLAGS_BASE} -O0 -fsanitize-coverage=edge,indirect-calls") -############################################################################### -# Basic tests -############################################################################### +set(DFSanTests + MemcmpTest + SimpleCmpTest + StrcmpTest + StrncmpTest + SwitchTest + ) set(Tests - AbsNegAndConstantTest - AbsNegAndConstant64Test - AccumulateAllocationsTest - BadStrcmpTest - BogusInitializeTest - BufferOverflowOnInput CallerCalleeTest - CleanseTest CounterTest - CustomCrossOverAndMutateTest - CustomCrossOverTest - CustomMutatorTest - CxxStringEqTest - DivTest - EmptyTest - EquivalenceATest - EquivalenceBTest - FlagsTest FourIndependentBranchesTest FullCoverageSetTest - InitializeTest - Memcmp64BytesTest MemcmpTest - LeakTest - LeakTimeoutTest - LoadTest NullDerefTest - NullDerefOnEmptyTest - NthRunCrashTest - OneHugeAllocTest - OutOfMemoryTest - OutOfMemorySingleLargeMallocTest - OverwriteInputTest - RepeatedMemcmp - RepeatedBytesTest SimpleCmpTest SimpleDictionaryTest SimpleHashTest SimpleTest - SimpleThreadedTest - SingleByteInputTest - SingleMemcmpTest - SingleStrcmpTest - SingleStrncmpTest - SpamyTest - ShrinkControlFlowTest - ShrinkControlFlowSimpleTest - ShrinkValueProfileTest StrcmpTest - StrncmpOOBTest StrncmpTest - StrstrTest - SwapCmpTest SwitchTest - Switch2Test - TableLookupTest - ThreadedLeakTest ThreadedTest TimeoutTest - TimeoutEmptyTest - TraceMallocTest - TwoDifferentBugsTest ) -if(APPLE OR MSVC) - # LeakSanitizer is not supported on OSX and Windows right now - set(HAS_LSAN 0) - message(WARNING "LeakSanitizer is not supported." - " Building and running LibFuzzer LeakSanitizer tests is disabled." - ) -else() - set(HAS_LSAN 1) -endif() +set(CustomMainTests + UserSuppliedFuzzerTest + ) + +set(UninstrumentedTests + UninstrumentedTest + ) + +set(TraceBBTests + SimpleTest + ) + +set(TestBinaries) foreach(Test ${Tests}) - add_libfuzzer_test(${Test} SOURCES ${Test}.cpp) + add_executable(LLVMFuzzer-${Test} + ${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test} + LLVMFuzzer + ) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}) endforeach() -function(test_export_symbol target symbol) - if(MSVC) - set_target_properties(LLVMFuzzer-${target} PROPERTIES LINK_FLAGS - "-export:${symbol}") - endif() -endfunction() +foreach(Test ${CustomMainTests}) + add_executable(LLVMFuzzer-${Test} + ${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test} + LLVMFuzzerNoMain + ) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}) +endforeach() -test_export_symbol(InitializeTest "LLVMFuzzerInitialize") -test_export_symbol(BogusInitializeTest "LLVMFuzzerInitialize") -test_export_symbol(CustomCrossOverTest "LLVMFuzzerCustomCrossOver") -test_export_symbol(CustomMutatorTest "LLVMFuzzerCustomMutator") -############################################################################### -# Unit tests -############################################################################### +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + ) -add_executable(LLVMFuzzer-Unittest - FuzzerUnittest.cpp +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg ) -add_executable(LLVMFuzzer-StandaloneInitializeTest - InitializeTest.cpp - ../standalone/StandaloneFuzzTargetMain.c +include_directories(..) +include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) + +add_executable(LLVMFuzzer-Unittest + FuzzerUnittest.cpp + $<TARGET_OBJECTS:LLVMFuzzerNoMainObjects> ) target_link_libraries(LLVMFuzzer-Unittest gtest gtest_main - LLVMFuzzerNoMain - ) - -target_include_directories(LLVMFuzzer-Unittest PRIVATE - "${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include" ) -add_dependencies(TestBinaries LLVMFuzzer-Unittest) -set_target_properties(LLVMFuzzer-Unittest - PROPERTIES RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_CURRENT_BINARY_DIR}" -) - -add_dependencies(TestBinaries LLVMFuzzer-StandaloneInitializeTest) -set_target_properties(LLVMFuzzer-StandaloneInitializeTest - PROPERTIES RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_CURRENT_BINARY_DIR}" -) - -############################################################################### -# Additional tests -############################################################################### - -include_directories(..) - -# add_subdirectory(uninstrumented) -add_subdirectory(no-coverage) -add_subdirectory(trace-pc) -add_subdirectory(ubsan) -if (NOT MSVC) - add_subdirectory(inline-8bit-counters) -endif() - -add_library(LLVMFuzzer-DSO1 SHARED DSO1.cpp) -add_library(LLVMFuzzer-DSO2 SHARED DSO2.cpp) +set(TestBinaries ${TestBinaries} LLVMFuzzer-Unittest) -add_executable(LLVMFuzzer-DSOTest - DSOTestMain.cpp - DSOTestExtra.cpp) - -target_link_libraries(LLVMFuzzer-DSOTest - LLVMFuzzer-DSO1 - LLVMFuzzer-DSO2 - LLVMFuzzer - ) +add_subdirectory(dfsan) -set_target_properties(LLVMFuzzer-DSOTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY - "${CMAKE_BINARY_DIR}/lib/Fuzzer/test") +foreach(Test ${DFSanTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-DFSan) +endforeach() -if(MSVC) - set_output_directory(LLVMFuzzer-DSO1 - BINARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/test" - LIBRARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/test") - set_output_directory(LLVMFuzzer-DSO2 - BINARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/test" - LIBRARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/test") -else(MSVC) - set_output_directory(LLVMFuzzer-DSO1 - LIBRARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") - set_output_directory(LLVMFuzzer-DSO2 - LIBRARY_DIR "${CMAKE_BINARY_DIR}/lib/Fuzzer/lib") -endif() +add_subdirectory(uninstrumented) -add_dependencies(TestBinaries LLVMFuzzer-DSOTest) +foreach(Test ${UninstrumentedTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-Uninstrumented) +endforeach() -############################################################################### -# Configure lit to run the tests -# -# Note this is done after declaring all tests so we can inform lit if any tests -# need to be disabled. -############################################################################### -set(LIBFUZZER_POSIX 1) -if (MSVC) - set(LIBFUZZER_POSIX 0) -endif() +add_subdirectory(trace-bb) -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg - ) +foreach(Test ${TraceBBTests}) + set(TestBinaries ${TestBinaries} LLVMFuzzer-${Test}-TraceBB) +endforeach() -configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/unit/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/unit/lit.site.cfg +set_target_properties(${TestBinaries} + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_lit_testsuite(check-fuzzer "Running Fuzzer tests" ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS TestBinaries + DEPENDS ${TestBinaries} FileCheck not ) - -# Don't add dependencies on Windows. The linker step would fail on Windows, -# since cmake will use link.exe for linking and won't include compiler-rt libs. -if(NOT MSVC) - add_dependencies(check-fuzzer FileCheck sancov not) -endif() diff --git a/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp index ed9f37cc152..150b2fc0405 100644 --- a/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/CallerCalleeTest.cpp @@ -1,11 +1,8 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. // Try to find the target using the indirect caller-callee pairs. -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <cstring> #include <iostream> diff --git a/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp index 4917934c62e..b61f419c499 100644 --- a/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/CounterTest.cpp @@ -1,6 +1,3 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Test for a fuzzer: must find the case where a particular basic block is // executed many times. #include <iostream> diff --git a/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp index ba963d9b1de..6007dd4a027 100644 --- a/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/FourIndependentBranchesTest.cpp @@ -1,14 +1,10 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the string "FUZZ". -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <iostream> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size > 64) return 0; int bits = 0; if (Size > 0 && Data[0] == 'F') bits |= 1; if (Size > 1 && Data[1] == 'U') bits |= 2; diff --git a/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp index 6d7e48fe51f..a868084a0ce 100644 --- a/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/FullCoverageSetTest.cpp @@ -1,10 +1,7 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the string "FUZZER". -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <iostream> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { diff --git a/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp index eba2663029b..b33e0c96145 100644 --- a/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/FuzzerUnittest.cpp @@ -1,38 +1,18 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - -// Avoid ODR violations (LibFuzzer is built without ASan and this test is built -// with ASan) involving C++ standard library types when using libcxx. -#define _LIBCPP_HAS_NO_ASAN - -// Do not attempt to use LLVM ostream from gtest. -#define GTEST_NO_LLVM_RAW_OSTREAM 1 - -#include "FuzzerCorpus.h" -#include "FuzzerDictionary.h" #include "FuzzerInternal.h" -#include "FuzzerMerge.h" -#include "FuzzerMutate.h" -#include "FuzzerRandom.h" -#include "FuzzerTracePC.h" #include "gtest/gtest.h" -#include <memory> #include <set> -#include <sstream> using namespace fuzzer; // For now, have LLVMFuzzerTestOneInput just to make it link. // Later we may want to make unittests that actually call LLVMFuzzerTestOneInput. -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { +extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { abort(); } TEST(Fuzzer, CrossOver) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); Unit A({0, 1, 2}), B({5, 6, 7}); Unit C; Unit Expected[] = { @@ -98,9 +78,7 @@ TEST(Fuzzer, Hash) { typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size, size_t MaxSize); -void TestEraseBytes(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); +void TestEraseByte(Mutator M, int NumIter) { uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -109,18 +87,8 @@ void TestEraseBytes(Mutator M, int NumIter) { uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77}; uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77}; uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - - uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; - uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77}; - - uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77}; - - - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; for (int i = 0; i < NumIter; i++) { uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -133,30 +101,20 @@ void TestEraseBytes(Mutator M, int NumIter) { if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5; if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6; if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7; - - if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8; - if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9; - if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10; - - if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11; - if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12; - if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13; } - EXPECT_EQ(FoundMask, (1 << 14) - 1); + EXPECT_EQ(FoundMask, 255); } -TEST(FuzzerMutate, EraseBytes1) { - TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200); +TEST(FuzzerMutate, EraseByte1) { + TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100); } -TEST(FuzzerMutate, EraseBytes2) { - TestEraseBytes(&MutationDispatcher::Mutate, 2000); +TEST(FuzzerMutate, EraseByte2) { + TestEraseByte(&MutationDispatcher::Mutate, 1000); } void TestInsertByte(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; @@ -188,55 +146,9 @@ TEST(FuzzerMutate, InsertByte2) { TestInsertByte(&MutationDispatcher::Mutate, 1 << 17); } -void TestInsertRepeatedBytes(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'}; - uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33}; - uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33}; - uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33}; - uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33}; - - uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'}; - uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33}; - uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33}; - uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33}; - uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33}; - size_t NewSize = (MD.*M)(T, 4, 8); - if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4; - - if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7; - if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8; - if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9; - - } - EXPECT_EQ(FoundMask, (1 << 10) - 1); -} - -TEST(FuzzerMutate, InsertRepeatedBytes1) { - TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000); -} -TEST(FuzzerMutate, InsertRepeatedBytes2) { - TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000); -} - void TestChangeByte(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -269,10 +181,8 @@ TEST(FuzzerMutate, ChangeByte2) { } void TestChangeBit(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; @@ -305,10 +215,8 @@ TEST(FuzzerMutate, ChangeBit2) { } void TestShuffleBytes(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); int FoundMask = 0; uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66}; uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66}; @@ -328,69 +236,19 @@ void TestShuffleBytes(Mutator M, int NumIter) { } TEST(FuzzerMutate, ShuffleBytes1) { - TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 16); + TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 15); } TEST(FuzzerMutate, ShuffleBytes2) { - TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20); -} - -void TestCopyPart(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - int FoundMask = 0; - uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11}; - uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66}; - uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66}; - uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66}; - uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66}; - size_t NewSize = (MD.*M)(T, 7, 7); - if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0; - if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1; - if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2; - if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3; - if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4; - } - - uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22}; - uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44}; - uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44}; - uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44}; - - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 5, 8); - if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8; - if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9; - } - - EXPECT_EQ(FoundMask, 1023); -} - -TEST(FuzzerMutate, CopyPart1) { - TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10); -} -TEST(FuzzerMutate, CopyPart2) { - TestCopyPart(&MutationDispatcher::Mutate, 1 << 13); + TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 19); } void TestAddWordFromDictionary(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD}; uint8_t Word2[3] = {0xFF, 0xEE, 0xEF}; - MD.AddWordToManualDictionary(Word(Word1, sizeof(Word1))); - MD.AddWordToManualDictionary(Word(Word2, sizeof(Word2))); + MD.AddWordToManualDictionary(Unit(Word1, Word1 + sizeof(Word1))); + MD.AddWordToManualDictionary(Unit(Word2, Word2 + sizeof(Word2))); int FoundMask = 0; uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD}; uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22}; @@ -424,11 +282,36 @@ TEST(FuzzerMutate, AddWordFromDictionary2) { TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15); } +void TestAddWordFromDictionaryWithHint(Mutator M, int NumIter) { + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); + uint8_t Word[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xFF, 0xEE, 0xEF}; + size_t PosHint = 7777; + MD.AddWordToAutoDictionary(Unit(Word, Word + sizeof(Word)), PosHint); + int FoundMask = 0; + for (int i = 0; i < NumIter; i++) { + uint8_t T[10000]; + memset(T, 0, sizeof(T)); + size_t NewSize = (MD.*M)(T, 9000, 10000); + if (NewSize >= PosHint + sizeof(Word) && + !memcmp(Word, T + PosHint, sizeof(Word))) + FoundMask = 1; + } + EXPECT_EQ(FoundMask, 1); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) { + TestAddWordFromDictionaryWithHint( + &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5); +} + +TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) { + TestAddWordFromDictionaryWithHint(&MutationDispatcher::Mutate, 1 << 10); +} + void TestChangeASCIIInteger(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); + FuzzerRandomLibc Rand(0); + MutationDispatcher MD(Rand); uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'}; uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'}; @@ -456,46 +339,6 @@ TEST(FuzzerMutate, ChangeASCIIInteger2) { TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15); } -void TestChangeBinaryInteger(Mutator M, int NumIter) { - std::unique_ptr<ExternalFunctions> t(new ExternalFunctions()); - fuzzer::EF = t.get(); - Random Rand(0); - MutationDispatcher MD(Rand, {}); - - uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79}; - uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77}; - uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77}; - uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88}; - uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size - uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size) - - int FoundMask = 0; - for (int i = 0; i < NumIter; i++) { - uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}; - size_t NewSize = (MD.*M)(T, 8, 8); - /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0; - else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1; - else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2; - else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3; - else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4; - else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5; - else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6; - else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7; - } - EXPECT_EQ(FoundMask, 255); -} - -TEST(FuzzerMutate, ChangeBinaryInteger1) { - TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger, - 1 << 12); -} - -TEST(FuzzerMutate, ChangeBinaryInteger2) { - TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15); -} - TEST(FuzzerDictionary, ParseOneDictionaryEntry) { Unit U; @@ -557,205 +400,3 @@ TEST(FuzzerUtil, Base64) { EXPECT_EQ("YWJjeHk=", Base64({'a', 'b', 'c', 'x', 'y'})); EXPECT_EQ("YWJjeHl6", Base64({'a', 'b', 'c', 'x', 'y', 'z'})); } - -TEST(Corpus, Distribution) { - Random Rand(0); - std::unique_ptr<InputCorpus> C(new InputCorpus("")); - size_t N = 10; - size_t TriesPerUnit = 1<<16; - for (size_t i = 0; i < N; i++) - C->AddToCorpus(Unit{ static_cast<uint8_t>(i) }, 1, false, {}); - - std::vector<size_t> Hist(N); - for (size_t i = 0; i < N * TriesPerUnit; i++) { - Hist[C->ChooseUnitIdxToMutate(Rand)]++; - } - for (size_t i = 0; i < N; i++) { - // A weak sanity check that every unit gets invoked. - EXPECT_GT(Hist[i], TriesPerUnit / N / 3); - } -} - -TEST(Merge, Bad) { - const char *kInvalidInputs[] = { - "", - "x", - "3\nx", - "2\n3", - "2\n2", - "2\n2\nA\n", - "2\n2\nA\nB\nC\n", - "0\n0\n", - "1\n1\nA\nDONE 0", - "1\n1\nA\nSTARTED 1", - }; - Merger M; - for (auto S : kInvalidInputs) { - // fprintf(stderr, "TESTING:\n%s\n", S); - EXPECT_FALSE(M.Parse(S, false)); - } -} - -void EQ(const std::vector<uint32_t> &A, const std::vector<uint32_t> &B) { - EXPECT_EQ(A, B); -} - -void EQ(const std::vector<std::string> &A, const std::vector<std::string> &B) { - std::set<std::string> a(A.begin(), A.end()); - std::set<std::string> b(B.begin(), B.end()); - EXPECT_EQ(a, b); -} - -static void Merge(const std::string &Input, - const std::vector<std::string> Result, - size_t NumNewFeatures) { - Merger M; - std::vector<std::string> NewFiles; - EXPECT_TRUE(M.Parse(Input, true)); - std::stringstream SS; - M.PrintSummary(SS); - EXPECT_EQ(NumNewFeatures, M.Merge(&NewFiles)); - EXPECT_EQ(M.AllFeatures(), M.ParseSummary(SS)); - EQ(NewFiles, Result); -} - -TEST(Merge, Good) { - Merger M; - - EXPECT_TRUE(M.Parse("1\n0\nAA\n", false)); - EXPECT_EQ(M.Files.size(), 1U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 0U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_TRUE(M.LastFailure.empty()); - EXPECT_EQ(M.FirstNotProcessedFile, 0U); - - EXPECT_TRUE(M.Parse("2\n1\nAA\nBB\nSTARTED 0 42\n", false)); - EXPECT_EQ(M.Files.size(), 2U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_EQ(M.Files[1].Name, "BB"); - EXPECT_EQ(M.LastFailure, "AA"); - EXPECT_EQ(M.FirstNotProcessedFile, 1U); - - EXPECT_TRUE(M.Parse("3\n1\nAA\nBB\nC\n" - "STARTED 0 1000\n" - "DONE 0 1 2 3\n" - "STARTED 1 1001\n" - "DONE 1 4 5 6 \n" - "STARTED 2 1002\n" - "", true)); - EXPECT_EQ(M.Files.size(), 3U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 1U); - EXPECT_EQ(M.Files[0].Name, "AA"); - EXPECT_EQ(M.Files[0].Size, 1000U); - EXPECT_EQ(M.Files[1].Name, "BB"); - EXPECT_EQ(M.Files[1].Size, 1001U); - EXPECT_EQ(M.Files[2].Name, "C"); - EXPECT_EQ(M.Files[2].Size, 1002U); - EXPECT_EQ(M.LastFailure, "C"); - EXPECT_EQ(M.FirstNotProcessedFile, 3U); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - - - std::vector<std::string> NewFiles; - - EXPECT_TRUE(M.Parse("3\n2\nAA\nBB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n" - "", true)); - EXPECT_EQ(M.Files.size(), 3U); - EXPECT_EQ(M.NumFilesInFirstCorpus, 2U); - EXPECT_TRUE(M.LastFailure.empty()); - EXPECT_EQ(M.FirstNotProcessedFile, 3U); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - EQ(M.Files[2].Features, {1, 3, 6}); - EXPECT_EQ(0U, M.Merge(&NewFiles)); - EQ(NewFiles, {}); - - EXPECT_TRUE(M.Parse("3\n1\nA\nB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3\n" - "", true)); - EQ(M.Files[0].Features, {1, 2, 3}); - EQ(M.Files[1].Features, {4, 5, 6}); - EQ(M.Files[2].Features, {1, 3, 6}); - EXPECT_EQ(3U, M.Merge(&NewFiles)); - EQ(NewFiles, {"B"}); - - // Same as the above, but with InitialFeatures. - EXPECT_TRUE(M.Parse("2\n0\nB\nC\n" - "STARTED 0 1001\nDONE 0 4 5 6 \n" - "STARTED 1 1002\nDONE 1 6 1 3\n" - "", true)); - EQ(M.Files[0].Features, {4, 5, 6}); - EQ(M.Files[1].Features, {1, 3, 6}); - EXPECT_EQ(3U, M.Merge({1, 2, 3}, &NewFiles)); - EQ(NewFiles, {"B"}); -} - -TEST(Merge, Merge) { - - Merge("3\n1\nA\nB\nC\n" - "STARTED 0 1000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n", - {"B"}, 3); - - Merge("3\n0\nA\nB\nC\n" - "STARTED 0 2000\nDONE 0 1 2 3\n" - "STARTED 1 1001\nDONE 1 4 5 6 \n" - "STARTED 2 1002\nDONE 2 6 1 3 \n", - {"A", "B", "C"}, 6); - - Merge("4\n0\nA\nB\nC\nD\n" - "STARTED 0 2000\nDONE 0 1 2 3\n" - "STARTED 1 1101\nDONE 1 4 5 6 \n" - "STARTED 2 1102\nDONE 2 6 1 3 100 \n" - "STARTED 3 1000\nDONE 3 1 \n", - {"A", "B", "C", "D"}, 7); - - Merge("4\n1\nA\nB\nC\nD\n" - "STARTED 0 2000\nDONE 0 4 5 6 7 8\n" - "STARTED 1 1100\nDONE 1 1 2 3 \n" - "STARTED 2 1100\nDONE 2 2 3 \n" - "STARTED 3 1000\nDONE 3 1 \n", - {"B", "D"}, 3); -} - -TEST(Fuzzer, ForEachNonZeroByte) { - const size_t N = 64; - alignas(64) uint8_t Ar[N + 8] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 2, 0, 0, 0, 0, 0, 0, - 0, 0, 3, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 5, 0, 6, 0, 0, - 0, 0, 0, 0, 0, 0, 7, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 8, - 9, 9, 9, 9, 9, 9, 9, 9, - }; - typedef std::vector<std::pair<size_t, uint8_t> > Vec; - Vec Res, Expected; - auto CB = [&](size_t Idx, uint8_t V) { Res.push_back({Idx, V}); }; - ForEachNonZeroByte(Ar, Ar + N, 100, CB); - Expected = {{108, 1}, {109, 2}, {118, 3}, {120, 4}, - {135, 5}, {137, 6}, {146, 7}, {163, 8}}; - EXPECT_EQ(Res, Expected); - - Res.clear(); - ForEachNonZeroByte(Ar + 9, Ar + N, 109, CB); - Expected = { {109, 2}, {118, 3}, {120, 4}, - {135, 5}, {137, 6}, {146, 7}, {163, 8}}; - EXPECT_EQ(Res, Expected); - - Res.clear(); - ForEachNonZeroByte(Ar + 9, Ar + N - 9, 109, CB); - Expected = { {109, 2}, {118, 3}, {120, 4}, - {135, 5}, {137, 6}, {146, 7}}; - EXPECT_EQ(Res, Expected); -} diff --git a/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp index 8dbb7d84fbb..c19c95717bb 100644 --- a/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/MemcmpTest.cpp @@ -1,18 +1,15 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find a particular string. +#include <cstring> #include <cstdint> #include <cstdio> #include <cstdlib> -#include <cstring> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { // TODO: check other sizes. if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) { if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) { if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) { - if (Size >= 17 && memcmp(Data + 14, "KLM", 3) == 0) { + if (Size >= 16 && memcmp(Data + 14, "KLM", 3) == 0) { if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){ fprintf(stderr, "BINGO %zd\n", Size); for (size_t i = 0; i < Size; i++) { diff --git a/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp index 1b44b682ace..200c56ccbbc 100644 --- a/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/NullDerefTest.cpp @@ -1,10 +1,7 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <iostream> static volatile int Sink; diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp index 8acad4ac77e..8568c737efb 100644 --- a/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/SimpleCmpTest.cpp @@ -1,47 +1,31 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find several narrow ranges. #include <cstdint> -#include <cstdio> #include <cstdlib> #include <cstring> - -extern int AllLines[]; - -bool PrintOnce(int Line) { - if (!AllLines[Line]) - fprintf(stderr, "Seen line %d\n", Line); - AllLines[Line] = 1; - return true; -} +#include <cstdio> extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size != 22) return 0; + if (Size < 14) return 0; uint64_t x = 0; int64_t y = 0; - int32_t z = 0; - uint16_t a = 0; - memcpy(&x, Data, 8); // 8 - memcpy(&y, Data + 8, 8); // 16 - memcpy(&z, Data + 16, sizeof(z)); // 20 - memcpy(&a, Data + 20, sizeof(a)); // 22 - const bool k32bit = sizeof(void*) == 4; + int z = 0; + unsigned short a = 0; + memcpy(&x, Data, 8); + memcpy(&y, Data + Size - 8, 8); + memcpy(&z, Data + Size / 2, sizeof(z)); + memcpy(&a, Data + Size / 2 + 4, sizeof(a)); - if ((k32bit || x > 1234567890) && PrintOnce(__LINE__) && - (k32bit || x < 1234567895) && PrintOnce(__LINE__) && - a == 0x4242 && PrintOnce(__LINE__) && - (k32bit || y >= 987654321) && PrintOnce(__LINE__) && - (k32bit || y <= 987654325) && PrintOnce(__LINE__) && - z < -10000 && PrintOnce(__LINE__) && - z >= -10005 && PrintOnce(__LINE__) && - z != -10003 && PrintOnce(__LINE__) && - true) { + if (x > 1234567890 && + x < 1234567895 && + y >= 987654321 && + y <= 987654325 && + z < -10000 && + z >= -10005 && + z != -10003 && + a == 4242) { fprintf(stderr, "BINGO; Found the target: size %zd (%zd, %zd, %d, %d), exiting.\n", Size, x, y, z, a); exit(1); } return 0; } - -int AllLines[__LINE__ + 1]; // Must be the last line. diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp index a1cd2004722..b9cb2f0270a 100644 --- a/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/SimpleDictionaryTest.cpp @@ -1,13 +1,10 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. // The fuzzer must find a string based on dictionary words: // "Elvis" // "Presley" -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <cstring> #include <iostream> diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp index a3f4211ebee..5bab3fa7f64 100644 --- a/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/SimpleHashTest.cpp @@ -1,13 +1,10 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // This test computes a checksum of the data (all but the last 4 bytes), // and then compares the last 4 bytes with the computed value. // A fuzzer with cmp traces is expected to defeat this check. #include <cstdint> -#include <cstdio> #include <cstdlib> #include <cstring> +#include <cstdio> // A modified jenkins_one_at_a_time_hash initialized by non-zero, // so that simple_hash(0) != 0. See also @@ -26,7 +23,7 @@ static uint32_t simple_hash(const uint8_t *Data, size_t Size) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size < 14 || Size > 64) + if (Size < 14) return 0; uint32_t Hash = simple_hash(&Data[0], Size - 4); diff --git a/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp index a8b4988dff1..04225a889f5 100644 --- a/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/SimpleTest.cpp @@ -1,11 +1,8 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the string "Hi!". #include <assert.h> -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <iostream> static volatile int Sink; diff --git a/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp index e7636e8812f..835819ae2f4 100644 --- a/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/StrcmpTest.cpp @@ -1,12 +1,9 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Break through a series of strcmp. -#include <cassert> +#include <cstring> #include <cstdint> #include <cstdio> #include <cstdlib> -#include <cstring> +#include <cassert> bool Eq(const uint8_t *Data, size_t Size, const char *Str) { char Buff[1024]; @@ -20,9 +17,9 @@ bool Eq(const uint8_t *Data, size_t Size, const char *Str) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Eq(Data, Size, "ABC") && - Size >= 3 && Eq(Data + 3, Size - 3, "QWER") && - Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") && + if (Eq(Data, Size, "AAA") && + Size >= 3 && Eq(Data + 3, Size - 3, "BBBB") && + Size >= 7 && Eq(Data + 7, Size - 7, "CCCCCC") && Size >= 14 && Data[13] == 42 ) { fprintf(stderr, "BINGO\n"); diff --git a/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp index f71f01ee309..55344d75e0b 100644 --- a/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/StrncmpTest.cpp @@ -1,11 +1,8 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find a particular string. +#include <cstring> #include <cstdint> #include <cstdio> #include <cstdlib> -#include <cstring> static volatile int sink; @@ -17,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (Size >= 8 && strncmp(S, "01234567", 8) == 0) { if (Size >= 12 && strncmp(S + 8, "ABCD", 4) == 0) { if (Size >= 14 && strncmp(S + 12, "XY", 2) == 0) { - if (Size >= 17 && strncmp(S + 14, "KLM", 3) == 0) { + if (Size >= 16 && strncmp(S + 14, "KLM", 3) == 0) { fprintf(stderr, "BINGO\n"); exit(1); } diff --git a/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp index 86944cad21c..5de7fff7452 100644 --- a/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/SwitchTest.cpp @@ -1,12 +1,9 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the interesting switch value. -#include <cstddef> #include <cstdint> -#include <cstdio> #include <cstdlib> +#include <cstdio> #include <cstring> +#include <cstddef> static volatile int Sink; diff --git a/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp index bb51ba764eb..7aa114a41f3 100644 --- a/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/ThreadedTest.cpp @@ -1,10 +1,7 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Threaded test for a fuzzer. The fuzzer should not crash. #include <assert.h> -#include <cstddef> #include <cstdint> +#include <cstddef> #include <cstring> #include <thread> diff --git a/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp index e3cdba3eec3..71790ded95a 100644 --- a/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp +++ b/gnu/llvm/lib/Fuzzer/test/TimeoutTest.cpp @@ -1,10 +1,7 @@ -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. - // Simple test for a fuzzer. The fuzzer must find the string "Hi!". -#include <cstddef> #include <cstdint> #include <cstdlib> +#include <cstddef> #include <iostream> static volatile int Sink; diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test index beb08671183..c3a9e8a3a9e 100644 --- a/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer-timeout.test @@ -7,13 +7,7 @@ TimeoutTest: #1 TimeoutTest: #2 TimeoutTest: SUMMARY: libFuzzer: timeout -RUN: not LLVMFuzzer-TimeoutTest -timeout=1 %S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest -SingleInputTimeoutTest: ALARM: working on the last Unit for {{[1-3]}} seconds +RUN: not LLVMFuzzer-TimeoutTest -timeout=1 -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInputTimeoutTest +SingleInputTimeoutTest: ALARM: working on the last Unit for SingleInputTimeoutTest-NOT: Test unit written to ./timeout- -RUN: LLVMFuzzer-TimeoutTest -timeout=1 -timeout_exitcode=0 - -RUN: not LLVMFuzzer-TimeoutEmptyTest -timeout=1 2>&1 | FileCheck %s --check-prefix=TimeoutEmptyTest -TimeoutEmptyTest: ALARM: working on the last Unit for -TimeoutEmptyTest: == ERROR: libFuzzer: timeout after -TimeoutEmptyTest: SUMMARY: libFuzzer: timeout diff --git a/gnu/llvm/lib/Fuzzer/test/fuzzer.test b/gnu/llvm/lib/Fuzzer/test/fuzzer.test index ff46d32b387..c63014f59d6 100644 --- a/gnu/llvm/lib/Fuzzer/test/fuzzer.test +++ b/gnu/llvm/lib/Fuzzer/test/fuzzer.test @@ -2,59 +2,35 @@ CHECK: BINGO Done1000000: Done 1000000 runs in RUN: LLVMFuzzer-SimpleTest 2>&1 | FileCheck %s +RUN: not LLVMFuzzer-NullDerefTest -test_single_input=%S/hi.txt 2>&1 | FileCheck %s --check-prefix=SingleInput +SingleInput-NOT: Test unit written to ./crash- -# only_ascii mode. Will perform some minimal self-validation. -RUN: LLVMFuzzer-SimpleTest -only_ascii=1 2>&1 - -RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 -use_cmp=0 2>&1 | FileCheck %s --check-prefix=MaxTotalTime +RUN: LLVMFuzzer-SimpleCmpTest -max_total_time=1 2>&1 | FileCheck %s --check-prefix=MaxTotalTime MaxTotalTime: Done {{.*}} runs in {{.}} second(s) -RUN: not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest -RUN: not LLVMFuzzer-NullDerefTest -close_fd_mask=3 2>&1 | FileCheck %s --check-prefix=NullDerefTest -NullDerefTest: ERROR: AddressSanitizer: {{SEGV|access-violation}} on unknown address +RUN: not LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest NullDerefTest: Test unit written to ./crash- RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ 2>&1 | FileCheck %s --check-prefix=NullDerefTestPrefix NullDerefTestPrefix: Test unit written to ZZZcrash- RUN: not LLVMFuzzer-NullDerefTest -artifact_prefix=ZZZ -exact_artifact_path=FOOBAR 2>&1 | FileCheck %s --check-prefix=NullDerefTestExactPath NullDerefTestExactPath: Test unit written to FOOBAR -RUN: not LLVMFuzzer-NullDerefOnEmptyTest -print_final_stats=1 2>&1 | FileCheck %s --check-prefix=NULL_DEREF_ON_EMPTY -NULL_DEREF_ON_EMPTY: stat::number_of_executed_units: - #not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s -RUN: not LLVMFuzzer-CounterTest -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s --check-prefix=COUNTERS +RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s -COUNTERS: INITED {{.*}} {{bits:|ft:}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: NEW {{.*}} {{bits:|ft:}} {{[1-9]*}} -COUNTERS: BINGO - -# Don't run UninstrumentedTest for now since we build libFuzzer itself with asan. -DISABLED: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED -UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. +RUN: not LLVMFuzzer-CallerCalleeTest -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s +# This one is flaky, may actually find the goal even w/o use_indir_calls. +# LLVMFuzzer-CallerCalleeTest -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=Done1000000 -RUN: not LLVMFuzzer-NotinstrumentedTest-NoCoverage 2>&1 | FileCheck %s --check-prefix=NO_COVERAGE -NO_COVERAGE: ERROR: no interesting inputs were found. Is the code instrumented for coverage? Exiting -RUN: not LLVMFuzzer-BufferOverflowOnInput 2>&1 | FileCheck %s --check-prefix=OOB -OOB: AddressSanitizer: heap-buffer-overflow -OOB: is located 0 bytes to the right of 3-byte region +RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s -RUN: not LLVMFuzzer-InitializeTest -use_value_profile=1 2>&1 | FileCheck %s - -RUN: not LLVMFuzzer-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO -DSO: INFO: Loaded 3 modules -DSO: BINGO - -RUN: LLVMFuzzer-SimpleTest -exit_on_src_pos=SimpleTest.cpp:17 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS -RUN: LLVMFuzzer-ShrinkControlFlowTest -exit_on_src_pos=ShrinkControlFlowTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS -EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting. +RUN: not LLVMFuzzer-UninstrumentedTest-Uninstrumented 2>&1 | FileCheck %s --check-prefix=UNINSTRUMENTED +UNINSTRUMENTED: ERROR: __sanitizer_set_death_callback is not defined. Exiting. -RUN: env ASAN_OPTIONS=strict_string_checks=1 not LLVMFuzzer-StrncmpOOBTest -seed=1 -runs=1000000 2>&1 | FileCheck %s --check-prefix=STRNCMP -STRNCMP: AddressSanitizer: heap-buffer-overflow -STRNCMP-NOT: __sanitizer_weak_hook_strncmp -STRNCMP: in LLVMFuzzerTestOneInput +RUN: LLVMFuzzer-SimpleTest -print_new_cov_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS +PCS:{{^0x[a-f0-9]+}} +PCS:NEW +PCS:BINGO -RUN: not LLVMFuzzer-BogusInitializeTest 2>&1 | FileCheck %s --check-prefix=BOGUS_INITIALIZE -BOGUS_INITIALIZE: argv[0] has been modified in LLVMFuzzerInitialize diff --git a/gnu/llvm/lib/Fuzzer/test/lit.cfg b/gnu/llvm/lib/Fuzzer/test/lit.cfg index 85c95b42d1e..2140a97668b 100644 --- a/gnu/llvm/lib/Fuzzer/test/lit.cfg +++ b/gnu/llvm/lib/Fuzzer/test/lit.cfg @@ -1,28 +1,10 @@ import lit.formats -import sys config.name = "LLVMFuzzer" config.test_format = lit.formats.ShTest(True) config.suffixes = ['.test'] config.test_source_root = os.path.dirname(__file__) -# Choose between lit's internal shell pipeline runner and a real shell. If -# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override. -use_lit_shell = os.environ.get("LIT_USE_INTERNAL_SHELL") -if use_lit_shell: - # 0 is external, "" is default, and everything else is internal. - execute_external = (use_lit_shell == "0") -else: - # Otherwise we default to internal on Windows and external elsewhere, as - # bash on Windows is usually very slow. - execute_external = (not sys.platform in ['win32']) - -# testFormat: The test format to use to interpret tests. -# -# For now we require '&&' between commands, until they get globally killed and -# the test runner updated. -config.test_format = lit.formats.ShTest(execute_external) - # Tweak PATH to include llvm tools dir and current exec dir. llvm_tools_dir = getattr(config, 'llvm_tools_dir', None) if (not llvm_tools_dir) or (not os.path.exists(llvm_tools_dir)): @@ -31,25 +13,3 @@ path = os.path.pathsep.join((llvm_tools_dir, config.test_exec_root, config.environment['PATH'])) config.environment['PATH'] = path -if config.has_lsan: - lit_config.note('lsan feature available') - config.available_features.add('lsan') -else: - lit_config.note('lsan feature unavailable') - -if sys.platform.startswith('win') or sys.platform.startswith('cygwin'): - config.available_features.add('windows') - -if sys.platform.startswith('darwin'): - config.available_features.add('darwin') - -if config.is_posix: - config.available_features.add('posix') - -if sys.platform.startswith('linux'): - # Note the value of ``sys.platform`` is not consistent - # between python 2 and 3, hence the use of ``.startswith()``. - lit_config.note('linux feature available') - config.available_features.add('linux') -else: - lit_config.note('linux feature unavailable') diff --git a/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in b/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in index 069f2b72c0d..e520db8e881 100644 --- a/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in +++ b/gnu/llvm/lib/Fuzzer/test/lit.site.cfg.in @@ -1,5 +1,3 @@ config.test_exec_root = "@CMAKE_CURRENT_BINARY_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.has_lsan = True if @HAS_LSAN@ == 1 else False -config.is_posix = @LIBFUZZER_POSIX@ lit_config.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") diff --git a/gnu/llvm/lib/Fuzzer/test/merge.test b/gnu/llvm/lib/Fuzzer/test/merge.test index e59da8c3e09..57ecc141bbf 100644 --- a/gnu/llvm/lib/Fuzzer/test/merge.test +++ b/gnu/llvm/lib/Fuzzer/test/merge.test @@ -1,16 +1,15 @@ CHECK: BINGO -RUN: rm -rf %tmp/T0 %tmp/T1 %tmp/T2 -RUN: mkdir -p %tmp/T0 %tmp/T1 %tmp/T2 -RUN: echo F..... > %tmp/T0/1 -RUN: echo .U.... > %tmp/T0/2 -RUN: echo ..Z... > %tmp/T0/3 +RUN: rm -rf %tmp/T1 %tmp/T2 +RUN: mkdir -p %tmp/T1 %tmp/T2 +RUN: echo F..... > %tmp/T1/1 +RUN: echo .U.... > %tmp/T1/2 +RUN: echo ..Z... > %tmp/T1/3 # T1 has 3 elements, T2 is empty. -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 -CHECK1: MERGE-OUTER: 3 files, 3 in the initial corpus -CHECK1: MERGE-OUTER: 0 new files with 0 new features added +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: Merge: running the initial corpus {{.*}} of 3 units +CHECK1: Merge: written 0 out of 0 units RUN: echo ...Z.. > %tmp/T2/1 RUN: echo ....E. > %tmp/T2/2 @@ -20,34 +19,11 @@ RUN: echo .U.... > %tmp/T2/b RUN: echo ..Z... > %tmp/T2/c # T1 has 3 elements, T2 has 6 elements, only 3 are new. -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 -CHECK2: MERGE-OUTER: 9 files, 3 in the initial corpus -CHECK2: MERGE-OUTER: 3 new files with 3 new features added +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: Merge: running the initial corpus {{.*}} of 3 units +CHECK2: Merge: written 3 out of 6 units # Now, T1 has 6 units and T2 has no new interesting units. -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 -CHECK3: MERGE-OUTER: 12 files, 6 in the initial corpus -CHECK3: MERGE-OUTER: 0 new files with 0 new features added - -# Check that we respect max_len during the merge and don't crash. -RUN: rm %tmp/T1/* -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: echo looooooooong > %tmp/T2/looooooooong -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=6 2>&1 | FileCheck %s --check-prefix=MAX_LEN -MAX_LEN: MERGE-OUTER: 3 new files - -# Check that merge tolerates failures. -RUN: rm %tmp/T1/* -RUN: cp %tmp/T0/* %tmp/T1/ -RUN: echo 'FUZZER' > %tmp/T2/FUZZER -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=MERGE_WITH_CRASH -MERGE_WITH_CRASH: MERGE-OUTER: succesfull in 2 attempt(s) -MERGE_WITH_CRASH: MERGE-OUTER: 3 new files - -# Check that we actually limit the size with max_len -RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 -max_len=5 2>&1 | FileCheck %s --check-prefix=MERGE_LEN5 -MERGE_LEN5: MERGE-OUTER: succesfull in 1 attempt(s) - -RUN: rm -rf %tmp/T1/* %tmp/T2/* -RUN: not LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=EMPTY -EMPTY: MERGE-OUTER: zero succesfull attempts, exiting +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: Merge: running the initial corpus {{.*}} of 6 units +CHECK3: Merge: written 0 out of 6 units diff --git a/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt index f4ab59e5b18..443ba3716f6 100644 --- a/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt +++ b/gnu/llvm/lib/Fuzzer/test/uninstrumented/CMakeLists.txt @@ -1,13 +1,14 @@ -# These tests are not instrumented with coverage and don't -# have coverage rt in the binary. +# These tests are not instrumented with coverage. -set(CMAKE_CXX_FLAGS - "${LIBFUZZER_FLAGS_BASE} -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters,trace-pc-guard") - -set(UninstrumentedTests - UninstrumentedTest - ) +set(CMAKE_CXX_FLAGS_RELEASE + "${LIBFUZZER_FLAGS_BASE} -O0 -fno-sanitize=all") foreach(Test ${UninstrumentedTests}) - add_libfuzzer_test(${Test}-Uninstrumented SOURCES ../${Test}.cpp) + add_executable(LLVMFuzzer-${Test}-Uninstrumented + ../${Test}.cpp + ) + target_link_libraries(LLVMFuzzer-${Test}-Uninstrumented + LLVMFuzzer + ) endforeach() + diff --git a/gnu/llvm/lib/IR/GCOV.cpp b/gnu/llvm/lib/IR/GCOV.cpp index d4b45522822..35b8157751b 100644 --- a/gnu/llvm/lib/IR/GCOV.cpp +++ b/gnu/llvm/lib/IR/GCOV.cpp @@ -17,11 +17,11 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MemoryObject.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <system_error> - using namespace llvm; //===----------------------------------------------------------------------===// @@ -103,17 +103,11 @@ bool GCOVFile::readGCDA(GCOVBuffer &Buffer) { return true; } -void GCOVFile::print(raw_ostream &OS) const { - for (const auto &FPtr : Functions) - FPtr->print(OS); -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// dump - Dump GCOVFile content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVFile::dump() const { - print(dbgs()); +void GCOVFile::dump() const { + for (const auto &FPtr : Functions) + FPtr->dump(); } -#endif /// collectLineCounts - Collect line counts. This must be used after /// reading .gcno and .gcda files. @@ -253,12 +247,10 @@ bool GCOVFunction::readGCNO(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { /// readGCDA - Read a function from the GCDA buffer. Return false if an error /// occurs. bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { - uint32_t HeaderLength; - if (!Buff.readInt(HeaderLength)) + uint32_t Dummy; + if (!Buff.readInt(Dummy)) return false; // Function header length - uint64_t EndPos = Buff.getCursor() + HeaderLength * sizeof(uint32_t); - uint32_t GCDAIdent; if (!Buff.readInt(GCDAIdent)) return false; @@ -288,15 +280,13 @@ bool GCOVFunction::readGCDA(GCOVBuffer &Buff, GCOV::GCOVVersion Version) { } } - if (Buff.getCursor() < EndPos) { - StringRef GCDAName; - if (!Buff.readString(GCDAName)) - return false; - if (Name != GCDAName) { - errs() << "Function names do not match: " << Name << " != " << GCDAName - << ".\n"; - return false; - } + StringRef GCDAName; + if (!Buff.readString(GCDAName)) + return false; + if (Name != GCDAName) { + errs() << "Function names do not match: " << Name << " != " << GCDAName + << ".\n"; + return false; } if (!Buff.readArcTag()) { @@ -349,19 +339,13 @@ uint64_t GCOVFunction::getExitCount() const { return Blocks.back()->getCount(); } -void GCOVFunction::print(raw_ostream &OS) const { - OS << "===== " << Name << " (" << Ident << ") @ " << Filename << ":" - << LineNumber << "\n"; - for (const auto &Block : Blocks) - Block->print(OS); -} - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// dump - Dump GCOVFunction content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVFunction::dump() const { - print(dbgs()); +void GCOVFunction::dump() const { + dbgs() << "===== " << Name << " (" << Ident << ") @ " << Filename << ":" + << LineNumber << "\n"; + for (const auto &Block : Blocks) + Block->dump(); } -#endif /// collectLineCounts - Collect line counts. This must be used after /// reading .gcno and .gcda files. @@ -412,35 +396,29 @@ void GCOVBlock::collectLineCounts(FileInfo &FI) { FI.addBlockLine(Parent.getFilename(), N, this); } -void GCOVBlock::print(raw_ostream &OS) const { - OS << "Block : " << Number << " Counter : " << Counter << "\n"; +/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. +void GCOVBlock::dump() const { + dbgs() << "Block : " << Number << " Counter : " << Counter << "\n"; if (!SrcEdges.empty()) { - OS << "\tSource Edges : "; + dbgs() << "\tSource Edges : "; for (const GCOVEdge *Edge : SrcEdges) - OS << Edge->Src.Number << " (" << Edge->Count << "), "; - OS << "\n"; + dbgs() << Edge->Src.Number << " (" << Edge->Count << "), "; + dbgs() << "\n"; } if (!DstEdges.empty()) { - OS << "\tDestination Edges : "; + dbgs() << "\tDestination Edges : "; for (const GCOVEdge *Edge : DstEdges) - OS << Edge->Dst.Number << " (" << Edge->Count << "), "; - OS << "\n"; + dbgs() << Edge->Dst.Number << " (" << Edge->Count << "), "; + dbgs() << "\n"; } if (!Lines.empty()) { - OS << "\tLines : "; + dbgs() << "\tLines : "; for (uint32_t N : Lines) - OS << (N) << ","; - OS << "\n"; + dbgs() << (N) << ","; + dbgs() << "\n"; } } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -/// dump - Dump GCOVBlock content to dbgs() for debugging purposes. -LLVM_DUMP_METHOD void GCOVBlock::dump() const { - print(dbgs()); -} -#endif - //===----------------------------------------------------------------------===// // FileInfo implementation. @@ -518,7 +496,7 @@ public: OS << format("%5u:", LineNum) << Line << "\n"; } }; -} // end anonymous namespace +} /// Convert a path to a gcov filename. If PreservePaths is true, this /// translates "/" to "#", ".." to "^", and drops ".", to match gcov. @@ -589,12 +567,8 @@ FileInfo::openCoveragePath(StringRef CoveragePath) { /// print - Print source files with collected line count information. void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, StringRef GCNOFile, StringRef GCDAFile) { - SmallVector<StringRef, 4> Filenames; - for (const auto &LI : LineInfo) - Filenames.push_back(LI.first()); - std::sort(Filenames.begin(), Filenames.end()); - - for (StringRef Filename : Filenames) { + for (const auto &LI : LineInfo) { + StringRef Filename = LI.first(); auto AllLines = LineConsumer(Filename); std::string CoveragePath = getCoveragePath(Filename, MainFilename); @@ -607,7 +581,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, CovOS << " -: 0:Runs:" << RunCount << "\n"; CovOS << " -: 0:Programs:" << ProgramCount << "\n"; - const LineData &Line = LineInfo[Filename]; + const LineData &Line = LI.second; GCOVCoverage FileCoverage(Filename); for (uint32_t LineIndex = 0; LineIndex < Line.LastLine || !AllLines.empty(); ++LineIndex) { @@ -709,6 +683,7 @@ void FileInfo::print(raw_ostream &InfoOS, StringRef MainFilename, if (Options.FuncCoverage) printFuncCoverage(InfoOS); printFileCoverage(InfoOS); + return; } /// printFunctionSummary - Print function and block summary. diff --git a/gnu/llvm/lib/Target/AMDGPU/CIInstructions.td b/gnu/llvm/lib/Target/AMDGPU/CIInstructions.td index 26a483a8abf..c543814cae0 100644 --- a/gnu/llvm/lib/Target/AMDGPU/CIInstructions.td +++ b/gnu/llvm/lib/Target/AMDGPU/CIInstructions.td @@ -12,4 +12,322 @@ // S_CBRANCH_CDBGUSER // S_CBRANCH_CDBGSYS // S_CBRANCH_CDBGSYS_OR_USER -// S_CBRANCH_CDBGSYS_AND_USER
\ No newline at end of file +// S_CBRANCH_CDBGSYS_AND_USER +// DS_NOP +// DS_GWS_SEMA_RELEASE_ALL +// DS_WRAP_RTN_B32 +// DS_CNDXCHG32_RTN_B64 +// DS_WRITE_B96 +// DS_WRITE_B128 +// DS_CONDXCHG32_RTN_B128 +// DS_READ_B96 +// DS_READ_B128 +// BUFFER_LOAD_DWORDX3 +// BUFFER_STORE_DWORDX3 + + +def isCIVI : Predicate < + "Subtarget->getGeneration() == AMDGPUSubtarget::SEA_ISLANDS || " + "Subtarget->getGeneration() == AMDGPUSubtarget::VOLCANIC_ISLANDS" +>, AssemblerPredicate<"FeatureCIInsts">; + +def HasFlatAddressSpace : Predicate<"Subtarget->hasFlatAddressSpace()">; + +//===----------------------------------------------------------------------===// +// VOP1 Instructions +//===----------------------------------------------------------------------===// + +let SubtargetPredicate = isCIVI in { + +let SchedRW = [WriteDoubleAdd] in { +defm V_TRUNC_F64 : VOP1Inst <vop1<0x17>, "v_trunc_f64", + VOP_F64_F64, ftrunc +>; +defm V_CEIL_F64 : VOP1Inst <vop1<0x18>, "v_ceil_f64", + VOP_F64_F64, fceil +>; +defm V_FLOOR_F64 : VOP1Inst <vop1<0x1A>, "v_floor_f64", + VOP_F64_F64, ffloor +>; +defm V_RNDNE_F64 : VOP1Inst <vop1<0x19>, "v_rndne_f64", + VOP_F64_F64, frint +>; +} // End SchedRW = [WriteDoubleAdd] + +let SchedRW = [WriteQuarterRate32] in { +defm V_LOG_LEGACY_F32 : VOP1Inst <vop1<0x45, 0x4c>, "v_log_legacy_f32", + VOP_F32_F32 +>; +defm V_EXP_LEGACY_F32 : VOP1Inst <vop1<0x46, 0x4b>, "v_exp_legacy_f32", + VOP_F32_F32 +>; +} // End SchedRW = [WriteQuarterRate32] + +//===----------------------------------------------------------------------===// +// VOP3 Instructions +//===----------------------------------------------------------------------===// + +defm V_QSAD_PK_U16_U8 : VOP3Inst <vop3<0x173>, "v_qsad_pk_u16_u8", + VOP_I32_I32_I32 +>; +defm V_MQSAD_U16_U8 : VOP3Inst <vop3<0x172>, "v_mqsad_u16_u8", + VOP_I32_I32_I32 +>; +defm V_MQSAD_U32_U8 : VOP3Inst <vop3<0x175>, "v_mqsad_u32_u8", + VOP_I32_I32_I32 +>; + +let isCommutable = 1 in { +defm V_MAD_U64_U32 : VOP3Inst <vop3<0x176>, "v_mad_u64_u32", + VOP_I64_I32_I32_I64 +>; + +// XXX - Does this set VCC? +defm V_MAD_I64_I32 : VOP3Inst <vop3<0x177>, "v_mad_i64_i32", + VOP_I64_I32_I32_I64 +>; +} // End isCommutable = 1 + + +//===----------------------------------------------------------------------===// +// DS Instructions +//===----------------------------------------------------------------------===// +defm DS_WRAP_RTN_F32 : DS_1A1D_RET <0x34, "ds_wrap_rtn_f32", VGPR_32, "ds_wrap_f32">; + +// DS_CONDXCHG32_RTN_B64 +// DS_CONDXCHG32_RTN_B128 + +//===----------------------------------------------------------------------===// +// SMRD Instructions +//===----------------------------------------------------------------------===// + +defm S_DCACHE_INV_VOL : SMRD_Inval <smrd<0x1d, 0x22>, + "s_dcache_inv_vol", int_amdgcn_s_dcache_inv_vol>; + +//===----------------------------------------------------------------------===// +// MUBUF Instructions +//===----------------------------------------------------------------------===// + +defm BUFFER_WBINVL1_VOL : MUBUF_Invalidate <mubuf<0x70, 0x3f>, + "buffer_wbinvl1_vol", int_amdgcn_buffer_wbinvl1_vol +>; + +//===----------------------------------------------------------------------===// +// Flat Instructions +//===----------------------------------------------------------------------===// + +defm FLAT_LOAD_UBYTE : FLAT_Load_Helper < + flat<0x8, 0x10>, "flat_load_ubyte", VGPR_32 +>; +defm FLAT_LOAD_SBYTE : FLAT_Load_Helper < + flat<0x9, 0x11>, "flat_load_sbyte", VGPR_32 +>; +defm FLAT_LOAD_USHORT : FLAT_Load_Helper < + flat<0xa, 0x12>, "flat_load_ushort", VGPR_32 +>; +defm FLAT_LOAD_SSHORT : FLAT_Load_Helper < + flat<0xb, 0x13>, "flat_load_sshort", VGPR_32> +; +defm FLAT_LOAD_DWORD : FLAT_Load_Helper < + flat<0xc, 0x14>, "flat_load_dword", VGPR_32 +>; +defm FLAT_LOAD_DWORDX2 : FLAT_Load_Helper < + flat<0xd, 0x15>, "flat_load_dwordx2", VReg_64 +>; +defm FLAT_LOAD_DWORDX4 : FLAT_Load_Helper < + flat<0xe, 0x17>, "flat_load_dwordx4", VReg_128 +>; +defm FLAT_LOAD_DWORDX3 : FLAT_Load_Helper < + flat<0xf, 0x16>, "flat_load_dwordx3", VReg_96 +>; +defm FLAT_STORE_BYTE : FLAT_Store_Helper < + flat<0x18>, "flat_store_byte", VGPR_32 +>; +defm FLAT_STORE_SHORT : FLAT_Store_Helper < + flat <0x1a>, "flat_store_short", VGPR_32 +>; +defm FLAT_STORE_DWORD : FLAT_Store_Helper < + flat<0x1c>, "flat_store_dword", VGPR_32 +>; +defm FLAT_STORE_DWORDX2 : FLAT_Store_Helper < + flat<0x1d>, "flat_store_dwordx2", VReg_64 +>; +defm FLAT_STORE_DWORDX4 : FLAT_Store_Helper < + flat<0x1e, 0x1f>, "flat_store_dwordx4", VReg_128 +>; +defm FLAT_STORE_DWORDX3 : FLAT_Store_Helper < + flat<0x1f, 0x1e>, "flat_store_dwordx3", VReg_96 +>; +defm FLAT_ATOMIC_SWAP : FLAT_ATOMIC < + flat<0x30, 0x40>, "flat_atomic_swap", VGPR_32 +>; +defm FLAT_ATOMIC_CMPSWAP : FLAT_ATOMIC < + flat<0x31, 0x41>, "flat_atomic_cmpswap", VGPR_32, VReg_64 +>; +defm FLAT_ATOMIC_ADD : FLAT_ATOMIC < + flat<0x32, 0x42>, "flat_atomic_add", VGPR_32 +>; +defm FLAT_ATOMIC_SUB : FLAT_ATOMIC < + flat<0x33, 0x43>, "flat_atomic_sub", VGPR_32 +>; +defm FLAT_ATOMIC_SMIN : FLAT_ATOMIC < + flat<0x35, 0x44>, "flat_atomic_smin", VGPR_32 +>; +defm FLAT_ATOMIC_UMIN : FLAT_ATOMIC < + flat<0x36, 0x45>, "flat_atomic_umin", VGPR_32 +>; +defm FLAT_ATOMIC_SMAX : FLAT_ATOMIC < + flat<0x37, 0x46>, "flat_atomic_smax", VGPR_32 +>; +defm FLAT_ATOMIC_UMAX : FLAT_ATOMIC < + flat<0x38, 0x47>, "flat_atomic_umax", VGPR_32 +>; +defm FLAT_ATOMIC_AND : FLAT_ATOMIC < + flat<0x39, 0x48>, "flat_atomic_and", VGPR_32 +>; +defm FLAT_ATOMIC_OR : FLAT_ATOMIC < + flat<0x3a, 0x49>, "flat_atomic_or", VGPR_32 +>; +defm FLAT_ATOMIC_XOR : FLAT_ATOMIC < + flat<0x3b, 0x4a>, "flat_atomic_xor", VGPR_32 +>; +defm FLAT_ATOMIC_INC : FLAT_ATOMIC < + flat<0x3c, 0x4b>, "flat_atomic_inc", VGPR_32 +>; +defm FLAT_ATOMIC_DEC : FLAT_ATOMIC < + flat<0x3d, 0x4c>, "flat_atomic_dec", VGPR_32 +>; +defm FLAT_ATOMIC_SWAP_X2 : FLAT_ATOMIC < + flat<0x50, 0x60>, "flat_atomic_swap_x2", VReg_64 +>; +defm FLAT_ATOMIC_CMPSWAP_X2 : FLAT_ATOMIC < + flat<0x51, 0x61>, "flat_atomic_cmpswap_x2", VReg_64, VReg_128 +>; +defm FLAT_ATOMIC_ADD_X2 : FLAT_ATOMIC < + flat<0x52, 0x62>, "flat_atomic_add_x2", VReg_64 +>; +defm FLAT_ATOMIC_SUB_X2 : FLAT_ATOMIC < + flat<0x53, 0x63>, "flat_atomic_sub_x2", VReg_64 +>; +defm FLAT_ATOMIC_SMIN_X2 : FLAT_ATOMIC < + flat<0x55, 0x64>, "flat_atomic_smin_x2", VReg_64 +>; +defm FLAT_ATOMIC_UMIN_X2 : FLAT_ATOMIC < + flat<0x56, 0x65>, "flat_atomic_umin_x2", VReg_64 +>; +defm FLAT_ATOMIC_SMAX_X2 : FLAT_ATOMIC < + flat<0x57, 0x66>, "flat_atomic_smax_x2", VReg_64 +>; +defm FLAT_ATOMIC_UMAX_X2 : FLAT_ATOMIC < + flat<0x58, 0x67>, "flat_atomic_umax_x2", VReg_64 +>; +defm FLAT_ATOMIC_AND_X2 : FLAT_ATOMIC < + flat<0x59, 0x68>, "flat_atomic_and_x2", VReg_64 +>; +defm FLAT_ATOMIC_OR_X2 : FLAT_ATOMIC < + flat<0x5a, 0x69>, "flat_atomic_or_x2", VReg_64 +>; +defm FLAT_ATOMIC_XOR_X2 : FLAT_ATOMIC < + flat<0x5b, 0x6a>, "flat_atomic_xor_x2", VReg_64 +>; +defm FLAT_ATOMIC_INC_X2 : FLAT_ATOMIC < + flat<0x5c, 0x6b>, "flat_atomic_inc_x2", VReg_64 +>; +defm FLAT_ATOMIC_DEC_X2 : FLAT_ATOMIC < + flat<0x5d, 0x6c>, "flat_atomic_dec_x2", VReg_64 +>; + +} // End SubtargetPredicate = isCIVI + +// CI Only flat instructions + +let SubtargetPredicate = isCI, VIAssemblerPredicate = DisableInst in { + +defm FLAT_ATOMIC_FCMPSWAP : FLAT_ATOMIC < + flat<0x3e>, "flat_atomic_fcmpswap", VGPR_32, VReg_64 +>; +defm FLAT_ATOMIC_FMIN : FLAT_ATOMIC < + flat<0x3f>, "flat_atomic_fmin", VGPR_32 +>; +defm FLAT_ATOMIC_FMAX : FLAT_ATOMIC < + flat<0x40>, "flat_atomic_fmax", VGPR_32 +>; +defm FLAT_ATOMIC_FCMPSWAP_X2 : FLAT_ATOMIC < + flat<0x5e>, "flat_atomic_fcmpswap_x2", VReg_64, VReg_128 +>; +defm FLAT_ATOMIC_FMIN_X2 : FLAT_ATOMIC < + flat<0x5f>, "flat_atomic_fmin_x2", VReg_64 +>; +defm FLAT_ATOMIC_FMAX_X2 : FLAT_ATOMIC < + flat<0x60>, "flat_atomic_fmax_x2", VReg_64 +>; + +} // End let SubtargetPredicate = isCI, VIAssemblerPredicate = DisableInst + +let Predicates = [isCI] in { + +// Convert (x - floor(x)) to fract(x) +def : Pat < + (f32 (fsub (f32 (VOP3Mods f32:$x, i32:$mods)), + (f32 (ffloor (f32 (VOP3Mods f32:$x, i32:$mods)))))), + (V_FRACT_F32_e64 $mods, $x, DSTCLAMP.NONE, DSTOMOD.NONE) +>; + +// Convert (x + (-floor(x))) to fract(x) +def : Pat < + (f64 (fadd (f64 (VOP3Mods f64:$x, i32:$mods)), + (f64 (fneg (f64 (ffloor (f64 (VOP3Mods f64:$x, i32:$mods)))))))), + (V_FRACT_F64_e64 $mods, $x, DSTCLAMP.NONE, DSTOMOD.NONE) +>; + +} // End Predicates = [isCI] + + +//===----------------------------------------------------------------------===// +// Flat Patterns +//===----------------------------------------------------------------------===// + +let Predicates = [isCIVI] in { + +// Patterns for global loads with no offset +class FlatLoadPat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat < + (vt (node i64:$addr)), + (inst $addr, 0, 0, 0) +>; + +def : FlatLoadPat <FLAT_LOAD_UBYTE, flat_az_extloadi8, i32>; +def : FlatLoadPat <FLAT_LOAD_SBYTE, flat_sextloadi8, i32>; +def : FlatLoadPat <FLAT_LOAD_USHORT, flat_az_extloadi16, i32>; +def : FlatLoadPat <FLAT_LOAD_SSHORT, flat_sextloadi16, i32>; +def : FlatLoadPat <FLAT_LOAD_DWORD, flat_load, i32>; +def : FlatLoadPat <FLAT_LOAD_DWORDX2, flat_load, v2i32>; +def : FlatLoadPat <FLAT_LOAD_DWORDX4, flat_load, v4i32>; + +class FlatStorePat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat < + (node vt:$data, i64:$addr), + (inst $data, $addr, 0, 0, 0) +>; + +def : FlatStorePat <FLAT_STORE_BYTE, flat_truncstorei8, i32>; +def : FlatStorePat <FLAT_STORE_SHORT, flat_truncstorei16, i32>; +def : FlatStorePat <FLAT_STORE_DWORD, flat_store, i32>; +def : FlatStorePat <FLAT_STORE_DWORDX2, flat_store, v2i32>; +def : FlatStorePat <FLAT_STORE_DWORDX4, flat_store, v4i32>; + +class FlatAtomicPat <FLAT inst, SDPatternOperator node, ValueType vt> : Pat < + (vt (node i64:$addr, vt:$data)), + (inst $addr, $data, 0, 0) +>; + +def : FlatAtomicPat <FLAT_ATOMIC_ADD_RTN, atomic_add_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_AND_RTN, atomic_and_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_SUB_RTN, atomic_sub_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_SMAX_RTN, atomic_max_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_UMAX_RTN, atomic_umax_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_SMIN_RTN, atomic_min_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_UMIN_RTN, atomic_umin_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_OR_RTN, atomic_or_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_SWAP_RTN, atomic_swap_global, i32>; +def : FlatAtomicPat <FLAT_ATOMIC_XOR_RTN, atomic_xor_global, i32>; + +} // End Predicates = [isCIVI] diff --git a/gnu/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp b/gnu/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp index d4d3959658e..636750dcfba 100644 --- a/gnu/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp +++ b/gnu/llvm/lib/Target/AMDGPU/SIFixControlFlowLiveIntervals.cpp @@ -37,7 +37,9 @@ public: bool runOnMachineFunction(MachineFunction &MF) override; - StringRef getPassName() const override { return "SI Fix CF Live Intervals"; } + const char *getPassName() const override { + return "SI Fix CF Live Intervals"; + } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<LiveIntervals>(); diff --git a/gnu/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td b/gnu/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td index 400c17333f7..4c28b28337f 100644 --- a/gnu/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td +++ b/gnu/llvm/lib/Target/Hexagon/HexagonIntrinsicsDerived.td @@ -20,21 +20,21 @@ def : Pat <(mul DoubleRegs:$src1, DoubleRegs:$src2), (EXTRACT_SUBREG (i64 (M2_dpmpyuu_s0 (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), - isub_lo)), + subreg_loreg)), (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), - isub_lo)))), - isub_hi)), - (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_lo)), - (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), isub_hi))), - (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), isub_lo)), - (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_hi))), + subreg_loreg)))), + subreg_hireg)), + (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_loreg)), + (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), subreg_hireg))), + (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), subreg_loreg)), + (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_hireg))), (i32 (EXTRACT_SUBREG (i64 (M2_dpmpyuu_s0 - (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), isub_lo)), + (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src1), subreg_loreg)), (i32 (EXTRACT_SUBREG (i64 DoubleRegs:$src2), - isub_lo)))), isub_lo))))>; + subreg_loreg)))), subreg_loreg))))>; diff --git a/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td b/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td index 26062bfb2b8..da305a2d508 100644 --- a/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td +++ b/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrFormats.td @@ -71,197 +71,16 @@ class POOL32S_DALIGN_FM_MMR6 { class POOL32A_DIVMOD_FM_MMR6<string instr_asm, bits<9> funct> : MMR6Arch<instr_asm> { - bits<5> rt; - bits<5> rs; - bits<5> rd; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-11} = rd; - let Inst{10-9} = 0b00; - let Inst{8-0} = funct; -} - -class POOL32S_DMFTC0_FM_MMR6<string instr_asm, bits<5> funct> - : MMR6Arch<instr_asm>, MipsR6Inst { - bits<5> rt; - bits<5> rs; - bits<3> sel; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-14} = 0; - let Inst{13-11} = sel; - let Inst{10-6} = funct; - let Inst{5-0} = 0b111100; -} - -class POOL32S_ARITH_FM_MMR6<string opstr, bits<9> funct> - : MMR6Arch<opstr> { - bits<5> rt; - bits<5> rs; bits<5> rd; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-11} = rd; - let Inst{10-9} = 0b00; - let Inst{8-0} = funct; -} - -class DADDIU_FM_MMR6<string opstr> : MMR6Arch<opstr> { - bits<5> rt; - bits<5> rs; - bits<16> imm16; - - bits<32> Inst; - - let Inst{31-26} = 0b010111; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-0} = imm16; -} - -class PCREL18_FM_MMR6<bits<3> funct> : MipsR6Inst { - bits<5> rt; - bits<18> imm; - - bits<32> Inst; - - let Inst{31-26} = 0b011110; - let Inst{25-21} = rt; - let Inst{20-18} = funct; - let Inst{17-0} = imm; -} - -class POOL32S_2R_FM_MMR6<string instr_asm, bits<10> funct> - : MMR6Arch<instr_asm>, MipsR6Inst { - bits<5> rt; - bits<5> rs; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-6} = funct; - let Inst{5-0} = 0b111100; -} - -class POOL32S_2RSA5B0_FM_MMR6<string instr_asm, bits<9> funct> - : MMR6Arch<instr_asm>, MipsR6Inst { - bits<5> rt; bits<5> rs; - bits<5> sa; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-11} = sa; - let Inst{10-9} = 0b00; - let Inst{8-0} = funct; -} - -class LD_SD_32_2R_OFFSET16_FM_MMR6<string instr_asm, bits<6> op> - : MMR6Arch<instr_asm>, MipsR6Inst { - bits<5> rt; - bits<21> addr; - bits<5> base = addr{20-16}; - bits<16> offset = addr{15-0}; - - bits<32> Inst; - - let Inst{31-26} = op; - let Inst{25-21} = rt; - let Inst{20-16} = base; - let Inst{15-0} = offset; -} - -class POOL32C_2R_OFFSET12_FM_MMR6<string instr_asm, bits<4> funct> - : MMR6Arch<instr_asm>, MipsR6Inst { bits<5> rt; - bits<21> addr; - bits<5> base = addr{20-16}; - bits<12> offset = addr{11-0}; - - bits<32> Inst; - - let Inst{31-26} = 0b011000; - let Inst{25-21} = rt; - let Inst{20-16} = base; - let Inst{15-12} = funct; - let Inst{11-0} = offset; -} - -class POOL32S_3R_FM_MMR6<string instr_asm, bits<9> funct> - : MMR6Arch<instr_asm>, MipsR6Inst { - bits<5> rt; - bits<5> rs; - bits<5> rd; bits<32> Inst; let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; + let Inst{25-21} = rd; let Inst{20-16} = rs; - let Inst{15-11} = rd; + let Inst{15-11} = rt; let Inst{10-9} = 0b00; - let Inst{8-0} = funct; -} - -class POOL32S_DBITSWAP_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>, - MipsR6Inst { - bits<5> rt; - bits<5> rd; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rd; - let Inst{15-12} = 0b0000; - let Inst{11-6} = 0b101100; - let Inst{5-0} = 0b111100; -} - -class POOL32S_3RSA_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>, - MipsR6Inst { - bits<5> rt; - bits<5> rs; - bits<5> rd; - bits<2> sa; - - bits<32> Inst; - - let Inst{31-26} = 0b010110; - let Inst{25-21} = rt; - let Inst{20-16} = rs; - let Inst{15-11} = rd; - let Inst{10-9} = sa; - let Inst{8-6} = 0b100; - let Inst{5-0} = 0b000100; -} - -class PCREL_1ROFFSET19_FM_MMR6<string instr_asm> : MMR6Arch<instr_asm>, - MipsR6Inst { - bits<5> rt; - bits<19> offset; - - bits<32> Inst; - - let Inst{31-26} = 0b011110; - let Inst{25-21} = rt; - let Inst{20-19} = 0b10; - let Inst{18-0} = offset; + let Inst{8-0} = funct; } diff --git a/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td b/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td index 38b09d105dd..ec1aef86a94 100644 --- a/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td +++ b/gnu/llvm/lib/Target/Mips/MicroMips64r6InstrInfo.td @@ -28,48 +28,6 @@ class DDIV_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"ddiv", 0b100011000>; class DMOD_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"dmod", 0b101011000>; class DDIVU_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"ddivu", 0b110011000>; class DMODU_MM64R6_ENC : POOL32A_DIVMOD_FM_MMR6<"dmodu", 0b111011000>; -class DINSU_MM64R6_ENC : POOL32S_EXTBITS_FM_MMR6<0b110100>; -class DINSM_MM64R6_ENC : POOL32S_EXTBITS_FM_MMR6<0b000100>; -class DINS_MM64R6_ENC : POOL32S_EXTBITS_FM_MMR6<0b001100>; -class DMTC0_MM64R6_ENC : POOL32S_DMFTC0_FM_MMR6<"dmtc0", 0b01011>; -class DMTC1_MM64R6_ENC : POOL32F_MFTC1_FM_MMR6<"dmtc1", 0b10110000>; -class DMTC2_MM64R6_ENC : POOL32A_MFTC2_FM_MMR6<"dmtc2", 0b0111110100>; -class DMFC0_MM64R6_ENC : POOL32S_DMFTC0_FM_MMR6<"dmfc0", 0b00011>; -class DMFC1_MM64R6_ENC : POOL32F_MFTC1_FM_MMR6<"dmfc1", 0b10010000>; -class DMFC2_MM64R6_ENC : POOL32A_MFTC2_FM_MMR6<"dmfc2", 0b0110110100>; -class DADD_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dadd", 0b100010000>; -class DADDIU_MM64R6_ENC : DADDIU_FM_MMR6<"daddiu">; -class DADDU_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"daddu", 0b101010000>; -class LDPC_MMR646_ENC : PCREL18_FM_MMR6<0b110>; -class DSUB_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dsub", 0b110010000>; -class DSUBU_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dsubu", 0b111010000>; -class DMUL_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dmul", 0b000011000>; -class DMUH_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dmuh", 0b001011000>; -class DMULU_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dmulu", 0b010011000>; -class DMUHU_MM64R6_ENC : POOL32S_ARITH_FM_MMR6<"dmuhu", 0b011011000>; -class DSBH_MM64R6_ENC : POOL32S_2R_FM_MMR6<"dsbh", 0b0111101100>; -class DSHD_MM64R6_ENC : POOL32S_2R_FM_MMR6<"dshd", 0b1111101100>; -class DSLL_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsll", 0b000000000>; -class DSLL32_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsll32", 0b000001000>; -class DSLLV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"dsllv", 0b000010000>; -class DSRAV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"dsrav", 0b010010000>; -class DSRA_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsra", 0b010000000>; -class DSRA32_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsra32", 0b010000100>; -class DCLO_MM64R6_ENC : POOL32S_2R_FM_MMR6<"dclo", 0b0100101100>; -class DCLZ_MM64R6_ENC : POOL32S_2R_FM_MMR6<"dclz", 0b0101101100>; -class DROTR_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"drotr", 0b011000000>; -class DROTR32_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"drotr32", 0b011001000>; -class DROTRV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"drotrv", 0b011010000>; -class LD_MM64R6_ENC : LD_SD_32_2R_OFFSET16_FM_MMR6<"ld", 0b110111>; -class LLD_MM64R6_ENC : POOL32C_2R_OFFSET12_FM_MMR6<"lld", 0b0111>; -class LWU_MM64R6_ENC : POOL32C_2R_OFFSET12_FM_MMR6<"lwu", 0b1110>; -class SD_MM64R6_ENC : LD_SD_32_2R_OFFSET16_FM_MMR6<"sd", 0b110110>; -class DSRL_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsrl", 0b001000000>; -class DSRL32_MM64R6_ENC : POOL32S_2RSA5B0_FM_MMR6<"dsrl32", 0b001001000>; -class DSRLV_MM64R6_ENC : POOL32S_3R_FM_MMR6<"dsrlv", 0b001010000>; -class DBITSWAP_MM64R6_ENC : POOL32S_DBITSWAP_FM_MMR6<"dbitswap">; -class DLSA_MM64R6_ENC : POOL32S_3RSA_FM_MMR6<"dlsa">; -class LWUPC_MM64R6_ENC : PCREL_1ROFFSET19_FM_MMR6<"lwupc">; //===----------------------------------------------------------------------===// // @@ -77,28 +35,24 @@ class LWUPC_MM64R6_ENC : PCREL_1ROFFSET19_FM_MMR6<"lwupc">; // //===----------------------------------------------------------------------===// -class DAUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, - InstrItinClass Itin> +class DAUI_MMR6_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : MMR6Arch<instr_asm>, MipsR6Inst { dag OutOperandList = (outs GPROpnd:$rt); - dag InOperandList = (ins GPROpnd:$rs, uimm16:$imm); + dag InOperandList = (ins GPROpnd:$rs, simm16:$imm); string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm"); list<dag> Pattern = []; - InstrItinClass Itinerary = Itin; } -class DAUI_MMR6_DESC : DAUI_MMR6_DESC_BASE<"daui", GPR64Opnd, II_DAUI>; +class DAUI_MMR6_DESC : DAUI_MMR6_DESC_BASE<"daui", GPR64Opnd>; -class DAHI_DATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, - InstrItinClass Itin> +class DAHI_DATI_DESC_BASE<string instr_asm, RegisterOperand GPROpnd> : MMR6Arch<instr_asm>, MipsR6Inst { dag OutOperandList = (outs GPROpnd:$rs); - dag InOperandList = (ins GPROpnd:$rt, uimm16:$imm); - string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm"); + dag InOperandList = (ins GPROpnd:$rt, simm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $imm"); string Constraints = "$rs = $rt"; - InstrItinClass Itinerary = Itin; } -class DAHI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dahi", GPR64Opnd, II_DAHI>; -class DATI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dati", GPR64Opnd, II_DATI>; +class DAHI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dahi", GPR64Opnd>; +class DATI_MMR6_DESC : DAHI_DATI_DESC_BASE<"dati", GPR64Opnd>; class EXTBITS_DESC_BASE<string instr_asm, RegisterOperand RO, Operand PosOpnd, Operand SizeOpnd, SDPatternOperator Op = null_frag> @@ -114,7 +68,7 @@ class EXTBITS_DESC_BASE<string instr_asm, RegisterOperand RO, Operand PosOpnd, // TODO: Add 'pos + size' constraint check to dext* instructions // DEXT: 0 < pos + size <= 63 // DEXTM, DEXTU: 32 < pos + size <= 64 -class DEXT_MMR6_DESC : EXTBITS_DESC_BASE<"dext", GPR64Opnd, uimm5_report_uimm6, +class DEXT_MMR6_DESC : EXTBITS_DESC_BASE<"dext", GPR64Opnd, uimm5, uimm5_plus1, MipsExt>; class DEXTM_MMR6_DESC : EXTBITS_DESC_BASE<"dextm", GPR64Opnd, uimm5, uimm5_plus33, MipsExt>; @@ -122,235 +76,19 @@ class DEXTU_MMR6_DESC : EXTBITS_DESC_BASE<"dextu", GPR64Opnd, uimm5_plus32, uimm5_plus1, MipsExt>; class DALIGN_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, - Operand ImmOpnd, InstrItinClass itin> - : MMR6Arch<instr_asm>, MipsR6Inst { + Operand ImmOpnd> : MMR6Arch<instr_asm>, MipsR6Inst { dag OutOperandList = (outs GPROpnd:$rd); dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt, ImmOpnd:$bp); string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt, $bp"); list<dag> Pattern = []; - InstrItinClass Itinerary = itin; -} - -class DALIGN_MMR6_DESC : DALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3, - II_DALIGN>; - -class DDIV_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddiv", GPR64Opnd, II_DDIV, - sdiv>; -class DMOD_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmod", GPR64Opnd, II_DMOD, - srem>; -class DDIVU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"ddivu", GPR64Opnd, II_DDIVU, - udiv>; -class DMODU_MM64R6_DESC : DIVMOD_MMR6_DESC_BASE<"dmodu", GPR64Opnd, II_DMODU, - urem>; - -class DCLO_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins GPR64Opnd:$rs); - string AsmString = !strconcat("dclo", "\t$rt, $rs"); - list<dag> Pattern = [(set GPR64Opnd:$rt, (ctlz (not GPR64Opnd:$rs)))]; - InstrItinClass Itinerary = II_DCLO; - Format Form = FrmR; - string BaseOpcode = "dclo"; -} - -class DCLZ_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins GPR64Opnd:$rs); - string AsmString = !strconcat("dclz", "\t$rt, $rs"); - list<dag> Pattern = [(set GPR64Opnd:$rt, (ctlz GPR64Opnd:$rs))]; - InstrItinClass Itinerary = II_DCLZ; - Format Form = FrmR; - string BaseOpcode = "dclz"; -} - -class DINSU_MM64R6_DESC : InsBase<"dinsu", GPR64Opnd, uimm5_plus32, - uimm5_inssize_plus1, MipsIns>; -class DINSM_MM64R6_DESC : InsBase<"dinsm", GPR64Opnd, uimm5, uimm_range_2_64>; -class DINS_MM64R6_DESC : InsBase<"dins", GPR64Opnd, uimm5, uimm5_inssize_plus1, - MipsIns>; -class DMTC0_MM64R6_DESC : MTC0_MMR6_DESC_BASE<"dmtc0", COP0Opnd, GPR64Opnd, - II_DMTC0>; -class DMTC1_MM64R6_DESC : MTC1_MMR6_DESC_BASE<"dmtc1", FGR64Opnd, GPR64Opnd, - II_DMTC1, bitconvert>; -class DMTC2_MM64R6_DESC : MTC2_MMR6_DESC_BASE<"dmtc2", COP2Opnd, GPR64Opnd, - II_DMTC2>; -class DMFC0_MM64R6_DESC : MFC0_MMR6_DESC_BASE<"dmfc0", GPR64Opnd, COP0Opnd, - II_DMFC0>; -class DMFC1_MM64R6_DESC : MFC1_MMR6_DESC_BASE<"dmfc1", GPR64Opnd, FGR64Opnd, - II_DMFC1, bitconvert>; -class DMFC2_MM64R6_DESC : MFC2_MMR6_DESC_BASE<"dmfc2", GPR64Opnd, COP2Opnd, - II_DMFC2>; -class DADD_MM64R6_DESC : ArithLogicR<"dadd", GPR64Opnd, 1, II_DADD>; -class DADDIU_MM64R6_DESC : ArithLogicI<"daddiu", simm16_64, GPR64Opnd, - II_DADDIU, immSExt16, add>, - IsAsCheapAsAMove; -class DADDU_MM64R6_DESC : ArithLogicR<"daddu", GPR64Opnd, 1, II_DADDU, add>; - -class DSUB_DESC_BASE<string instr_asm, RegisterOperand RO, - InstrItinClass Itin = NoItinerary, - SDPatternOperator OpNode = null_frag> - : MipsR6Inst { - dag OutOperandList = (outs RO:$rd); - dag InOperandList = (ins RO:$rs, RO:$rt); - string AsmString = !strconcat(instr_asm, "\t$rd, $rs, $rt"); - list<dag> Pattern = [(set RO:$rd, (OpNode RO:$rs, RO:$rt))]; - InstrItinClass Itinerary = Itin; - Format Form = FrmR; - string BaseOpcode = instr_asm; - let isCommutable = 0; - let isReMaterializable = 1; - let TwoOperandAliasConstraint = "$rd = $rs"; -} -class DSUB_MM64R6_DESC : DSUB_DESC_BASE<"dsub", GPR64Opnd, II_DSUB>; -class DSUBU_MM64R6_DESC : DSUB_DESC_BASE<"dsubu", GPR64Opnd, II_DSUBU, sub>; - -class LDPC_MM64R6_DESC : PCREL_MMR6_DESC_BASE<"ldpc", GPR64Opnd, simm18_lsl3, - II_LDPC>; - -class MUL_MM64R6_DESC_BASE<string opstr, RegisterOperand GPROpnd, - InstrItinClass Itin = NoItinerary, - SDPatternOperator Op = null_frag> : MipsR6Inst { - dag OutOperandList = (outs GPROpnd:$rd); - dag InOperandList = (ins GPROpnd:$rs, GPROpnd:$rt); - string AsmString = !strconcat(opstr, "\t$rd, $rs, $rt"); - InstrItinClass Itinerary = Itin; - list<dag> Pattern = [(set GPROpnd:$rd, (Op GPROpnd:$rs, GPROpnd:$rt))]; -} - -class DMUL_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmul", GPR64Opnd, II_DMUL, mul>; -class DMUH_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmuh", GPR64Opnd, II_DMUH, - mulhs>; -class DMULU_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmulu", GPR64Opnd, II_DMULU>; -class DMUHU_MM64R6_DESC : MUL_MM64R6_DESC_BASE<"dmuhu", GPR64Opnd, II_DMUHU, - mulhu>; - -class DSBH_DSHD_DESC_BASE<string instr_asm, RegisterOperand GPROpnd, - InstrItinClass Itin> { - dag OutOperandList = (outs GPROpnd:$rt); - dag InOperandList = (ins GPROpnd:$rs); - string AsmString = !strconcat(instr_asm, "\t$rt, $rs"); - bit hasSideEffects = 0; - list<dag> Pattern = []; - InstrItinClass Itinerary = Itin; - Format Form = FrmR; - string BaseOpcode = instr_asm; -} - -class DSBH_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dsbh", GPR64Opnd, II_DSBH>; -class DSHD_MM64R6_DESC : DSBH_DSHD_DESC_BASE<"dshd", GPR64Opnd, II_DSHD>; - -class SHIFT_ROTATE_IMM_MM64R6<string instr_asm, Operand ImmOpnd, - InstrItinClass itin, - SDPatternOperator OpNode = null_frag, - SDPatternOperator PO = null_frag> { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins GPR64Opnd:$rs, ImmOpnd:$sa); - string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $sa"); - list<dag> Pattern = [(set GPR64Opnd:$rt, (OpNode GPR64Opnd:$rs, PO:$sa))]; - InstrItinClass Itinerary = itin; - Format Form = FrmR; - string TwoOperandAliasConstraint = "$rs = $rt"; - string BaseOpcode = instr_asm; -} - -class SHIFT_ROTATE_REG_MM64R6<string instr_asm, InstrItinClass itin, - SDPatternOperator OpNode = null_frag> { - dag OutOperandList = (outs GPR64Opnd:$rd); - dag InOperandList = (ins GPR64Opnd:$rt, GPR32Opnd:$rs); - string AsmString = !strconcat(instr_asm, "\t$rd, $rt, $rs"); - list<dag> Pattern = [(set GPR64Opnd:$rd, - (OpNode GPR64Opnd:$rt, GPR32Opnd:$rs))]; - InstrItinClass Itinerary = itin; - Format Form = FrmR; - string BaseOpcode = instr_asm; -} - -class DSLL_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsll", uimm6, II_DSLL, shl, - immZExt6>; -class DSLL32_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsll32", uimm5, II_DSLL32>; -class DSLLV_MM64R6_DESC : SHIFT_ROTATE_REG_MM64R6<"dsllv", II_DSLLV, shl>; -class DSRAV_MM64R6_DESC : SHIFT_ROTATE_REG_MM64R6<"dsrav", II_DSRAV, sra>; -class DSRA_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsra", uimm6, II_DSRA, sra, - immZExt6>; -class DSRA32_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsra32", uimm5, II_DSRA32>; -class DROTR_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"drotr", uimm6, II_DROTR, - rotr, immZExt6>; -class DROTR32_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"drotr32", uimm5, - II_DROTR32>; -class DROTRV_MM64R6_DESC : SHIFT_ROTATE_REG_MM64R6<"drotrv", II_DROTRV, rotr>; -class DSRL_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsrl", uimm6, II_DSRL, srl, - immZExt6>; -class DSRL32_MM64R6_DESC : SHIFT_ROTATE_IMM_MM64R6<"dsrl32", uimm5, II_DSRL32>; -class DSRLV_MM64R6_DESC : SHIFT_ROTATE_REG_MM64R6<"dsrlv", II_DSRLV, srl>; - -class Load_MM64R6<string instr_asm, Operand MemOpnd, InstrItinClass itin, - SDPatternOperator OpNode = null_frag> { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins MemOpnd:$addr); - string AsmString = !strconcat(instr_asm, "\t$rt, $addr"); - list<dag> Pattern = [(set GPR64Opnd:$rt, (OpNode addr:$addr))]; - InstrItinClass Itinerary = itin; - Format Form = FrmI; - bit mayLoad = 1; - bit canFoldAsLoad = 1; - string BaseOpcode = instr_asm; -} - -class LD_MM64R6_DESC : Load_MM64R6<"ld", mem_simm16, II_LD, load> { - string DecoderMethod = "DecodeMemMMImm16"; -} -class LWU_MM64R6_DESC : Load_MM64R6<"lwu", mem_simm12, II_LWU, zextloadi32>{ - string DecoderMethod = "DecodeMemMMImm12"; -} - -class LLD_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins mem_simm12:$addr); - string AsmString = "lld\t$rt, $addr"; - list<dag> Pattern = []; - bit mayLoad = 1; - InstrItinClass Itinerary = II_LLD; - string BaseOpcode = "lld"; - string DecoderMethod = "DecodeMemMMImm12"; -} - -class SD_MM64R6_DESC { - dag OutOperandList = (outs); - dag InOperandList = (ins GPR64Opnd:$rt, mem_simm16:$addr); - string AsmString = "sd\t$rt, $addr"; - list<dag> Pattern = [(store GPR64Opnd:$rt, addr:$addr)]; - InstrItinClass Itinerary = II_SD; - Format Form = FrmI; - bit mayStore = 1; - string BaseOpcode = "sd"; - string DecoderMethod = "DecodeMemMMImm16"; } -class DBITSWAP_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rd); - dag InOperandList = (ins GPR64Opnd:$rt); - string AsmString = !strconcat("dbitswap", "\t$rd, $rt"); - list<dag> Pattern = []; - InstrItinClass Itinerary = II_DBITSWAP; -} - -class DLSA_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rd); - dag InOperandList = (ins GPR64Opnd:$rt, GPR64Opnd:$rs, uimm2_plus1:$sa); - string AsmString = "dlsa\t$rt, $rs, $rd, $sa"; - list<dag> Pattern = []; - InstrItinClass Itinerary = II_DLSA; -} +class DALIGN_MMR6_DESC : DALIGN_DESC_BASE<"dalign", GPR64Opnd, uimm3>; -class LWUPC_MM64R6_DESC { - dag OutOperandList = (outs GPR64Opnd:$rt); - dag InOperandList = (ins simm19_lsl2:$offset); - string AsmString = "lwupc\t$rt, $offset"; - list<dag> Pattern = []; - InstrItinClass Itinerary = II_LWUPC; - bit mayLoad = 1; - bit IsPCRelativeLoad = 1; -} +class DDIV_MM64R6_DESC : ArithLogicR<"ddiv", GPR32Opnd>; +class DMOD_MM64R6_DESC : ArithLogicR<"dmod", GPR32Opnd>; +class DDIVU_MM64R6_DESC : ArithLogicR<"ddivu", GPR32Opnd>; +class DMODU_MM64R6_DESC : ArithLogicR<"dmodu", GPR32Opnd>; //===----------------------------------------------------------------------===// // @@ -360,10 +98,8 @@ class LWUPC_MM64R6_DESC { let DecoderNamespace = "MicroMipsR6" in { def DAUI_MM64R6 : StdMMR6Rel, DAUI_MMR6_DESC, DAUI_MMR6_ENC, ISA_MICROMIPS64R6; - let DecoderMethod = "DecodeDAHIDATIMMR6" in { - def DAHI_MM64R6 : StdMMR6Rel, DAHI_MMR6_DESC, DAHI_MMR6_ENC, ISA_MICROMIPS64R6; - def DATI_MM64R6 : StdMMR6Rel, DATI_MMR6_DESC, DATI_MMR6_ENC, ISA_MICROMIPS64R6; - } + def DAHI_MM64R6 : StdMMR6Rel, DAHI_MMR6_DESC, DAHI_MMR6_ENC, ISA_MICROMIPS64R6; + def DATI_MM64R6 : StdMMR6Rel, DATI_MMR6_DESC, DATI_MMR6_ENC, ISA_MICROMIPS64R6; def DEXT_MM64R6 : StdMMR6Rel, DEXT_MMR6_DESC, DEXT_MMR6_ENC, ISA_MICROMIPS64R6; def DEXTM_MM64R6 : StdMMR6Rel, DEXTM_MMR6_DESC, DEXTM_MMR6_ENC, @@ -380,183 +116,4 @@ let DecoderNamespace = "MicroMipsR6" in { ISA_MICROMIPS64R6; def DMODU_MM64R6 : R6MMR6Rel, DMODU_MM64R6_DESC, DMODU_MM64R6_ENC, ISA_MICROMIPS64R6; - def DINSU_MM64R6: R6MMR6Rel, DINSU_MM64R6_DESC, DINSU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DINSM_MM64R6: R6MMR6Rel, DINSM_MM64R6_DESC, DINSM_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DINS_MM64R6: R6MMR6Rel, DINS_MM64R6_DESC, DINS_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMTC0_MM64R6 : StdMMR6Rel, DMTC0_MM64R6_ENC, DMTC0_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DMTC1_MM64R6 : StdMMR6Rel, DMTC1_MM64R6_DESC, DMTC1_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMTC2_MM64R6 : StdMMR6Rel, DMTC2_MM64R6_ENC, DMTC2_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DMFC0_MM64R6 : StdMMR6Rel, DMFC0_MM64R6_ENC, DMFC0_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DMFC1_MM64R6 : StdMMR6Rel, DMFC1_MM64R6_DESC, DMFC1_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMFC2_MM64R6 : StdMMR6Rel, DMFC2_MM64R6_ENC, DMFC2_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DADD_MM64R6: StdMMR6Rel, DADD_MM64R6_DESC, DADD_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DADDIU_MM64R6: StdMMR6Rel, DADDIU_MM64R6_DESC, DADDIU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DADDU_MM64R6: StdMMR6Rel, DADDU_MM64R6_DESC, DADDU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def LDPC_MM64R6 : R6MMR6Rel, LDPC_MMR646_ENC, LDPC_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSUB_MM64R6 : StdMMR6Rel, DSUB_MM64R6_DESC, DSUB_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DSUBU_MM64R6 : StdMMR6Rel, DSUBU_MM64R6_DESC, DSUBU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMUL_MM64R6 : R6MMR6Rel, DMUL_MM64R6_DESC, DMUL_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMUH_MM64R6 : R6MMR6Rel, DMUH_MM64R6_DESC, DMUH_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMULU_MM64R6 : R6MMR6Rel, DMULU_MM64R6_DESC, DMULU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DMUHU_MM64R6 : R6MMR6Rel, DMUHU_MM64R6_DESC, DMUHU_MM64R6_ENC, - ISA_MICROMIPS64R6; - def DSBH_MM64R6 : R6MMR6Rel, DSBH_MM64R6_ENC, DSBH_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSHD_MM64R6 : R6MMR6Rel, DSHD_MM64R6_ENC, DSHD_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSLL_MM64R6 : StdMMR6Rel, DSLL_MM64R6_ENC, DSLL_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSLL32_MM64R6 : StdMMR6Rel, DSLL32_MM64R6_ENC, DSLL32_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSLLV_MM64R6 : StdMMR6Rel, DSLLV_MM64R6_ENC, DSLLV_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRAV_MM64R6 : StdMMR6Rel, DSRAV_MM64R6_ENC, DSRAV_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRA_MM64R6 : StdMMR6Rel, DSRA_MM64R6_ENC, DSRA_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRA32_MM64R6 : StdMMR6Rel, DSRA32_MM64R6_ENC, DSRA32_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DCLO_MM64R6 : StdMMR6Rel, R6MMR6Rel, DCLO_MM64R6_ENC, DCLO_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DCLZ_MM64R6 : StdMMR6Rel, R6MMR6Rel, DCLZ_MM64R6_ENC, DCLZ_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DROTR_MM64R6 : StdMMR6Rel, DROTR_MM64R6_ENC, DROTR_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DROTR32_MM64R6 : StdMMR6Rel, DROTR32_MM64R6_ENC, DROTR32_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DROTRV_MM64R6 : StdMMR6Rel, DROTRV_MM64R6_ENC, DROTRV_MM64R6_DESC, - ISA_MICROMIPS64R6; - def LD_MM64R6 : StdMMR6Rel, LD_MM64R6_ENC, LD_MM64R6_DESC, - ISA_MICROMIPS64R6; - def LLD_MM64R6 : StdMMR6Rel, R6MMR6Rel, LLD_MM64R6_ENC, LLD_MM64R6_DESC, - ISA_MICROMIPS64R6; - def LWU_MM64R6 : StdMMR6Rel, LWU_MM64R6_ENC, LWU_MM64R6_DESC, - ISA_MICROMIPS64R6; - def SD_MM64R6 : StdMMR6Rel, SD_MM64R6_ENC, SD_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRL_MM64R6 : StdMMR6Rel, DSRL_MM64R6_ENC, DSRL_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRL32_MM64R6 : StdMMR6Rel, DSRL32_MM64R6_ENC, DSRL32_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DSRLV_MM64R6 : StdMMR6Rel, DSRLV_MM64R6_ENC, DSRLV_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DBITSWAP_MM64R6 : R6MMR6Rel, DBITSWAP_MM64R6_ENC, DBITSWAP_MM64R6_DESC, - ISA_MICROMIPS64R6; - def DLSA_MM64R6 : R6MMR6Rel, DLSA_MM64R6_ENC, DLSA_MM64R6_DESC, - ISA_MICROMIPS64R6; - def LWUPC_MM64R6 : R6MMR6Rel, LWUPC_MM64R6_ENC, LWUPC_MM64R6_DESC, - ISA_MICROMIPS64R6; } - -let AdditionalPredicates = [InMicroMips] in -defm : MaterializeImms<i64, ZERO_64, DADDIU_MM64R6, LUi64, ORi64>; - -//===----------------------------------------------------------------------===// -// -// Arbitrary patterns that map to one or more instructions -// -//===----------------------------------------------------------------------===// - -defm : MipsHiLoRelocs<LUi64, DADDIU_MM64R6, ZERO_64, GPR64Opnd>, SYM_32, - ISA_MICROMIPS64R6; - -defm : MipsHighestHigherHiLoRelocs<LUi64, DADDIU_MM64R6>, SYM_64, - ISA_MICROMIPS64R6; - -def : MipsPat<(addc GPR64:$lhs, GPR64:$rhs), - (DADDU_MM64R6 GPR64:$lhs, GPR64:$rhs)>, ISA_MICROMIPS64R6; -def : MipsPat<(addc GPR64:$lhs, immSExt16:$imm), - (DADDIU_MM64R6 GPR64:$lhs, imm:$imm)>, ISA_MICROMIPS64R6; - - -def : MipsPat<(rotr GPR64:$rt, (i32 (trunc GPR64:$rs))), - (DROTRV_MM64R6 GPR64:$rt, (EXTRACT_SUBREG GPR64:$rs, sub_32))>, - ISA_MICROMIPS64R6; - - -def : WrapperPat<tglobaladdr, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; -def : WrapperPat<tconstpool, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; -def : WrapperPat<texternalsym, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; -def : WrapperPat<tblockaddress, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; -def : WrapperPat<tjumptable, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; -def : WrapperPat<tglobaltlsaddr, DADDIU_MM64R6, GPR64>, ISA_MICROMIPS64R6; - -// Carry pattern -def : MipsPat<(subc GPR64:$lhs, GPR64:$rhs), - (DSUBU_MM64R6 GPR64:$lhs, GPR64:$rhs)>, ISA_MICROMIPS64R6; - -def : MipsPat<(atomic_load_64 addr:$a), (LD_MM64R6 addr:$a)>, ISA_MICROMIPS64R6; - -//===----------------------------------------------------------------------===// -// -// Instruction aliases -// -//===----------------------------------------------------------------------===// - -def : MipsInstAlias<"dmtc0 $rt, $rd", - (DMTC0_MM64R6 COP0Opnd:$rd, GPR64Opnd:$rt, 0), 0>; -def : MipsInstAlias<"dmfc0 $rt, $rd", - (DMFC0_MM64R6 GPR64Opnd:$rt, COP0Opnd:$rd, 0), 0>, - ISA_MICROMIPS64R6; -def : MipsInstAlias<"daddu $rs, $rt, $imm", - (DADDIU_MM64R6 GPR64Opnd:$rs, - GPR64Opnd:$rt, - simm16_64:$imm), - 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"daddu $rs, $imm", - (DADDIU_MM64R6 GPR64Opnd:$rs, - GPR64Opnd:$rs, - simm16_64:$imm), - 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsubu $rt, $rs, $imm", - (DADDIU_MM64R6 GPR64Opnd:$rt, - GPR64Opnd:$rs, - InvertedImOperand64:$imm), - 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsubu $rs, $imm", - (DADDIU_MM64R6 GPR64Opnd:$rs, - GPR64Opnd:$rs, - InvertedImOperand64:$imm), - 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dneg $rt, $rs", - (DSUB_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>, - ISA_MICROMIPS64R6; -def : MipsInstAlias<"dneg $rt", - (DSUB_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>, - ISA_MICROMIPS64R6; -def : MipsInstAlias<"dnegu $rt, $rs", - (DSUBU_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rs), 1>, - ISA_MICROMIPS64R6; -def : MipsInstAlias<"dnegu $rt", - (DSUBU_MM64R6 GPR64Opnd:$rt, ZERO_64, GPR64Opnd:$rt), 1>, - ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsll $rd, $rt, $rs", - (DSLLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rt, - GPR32Opnd:$rs), 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsrl $rd, $rt, $rs", - (DSRLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rt, - GPR32Opnd:$rs), 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsrl $rd, $rt", - (DSRLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rd, - GPR32Opnd:$rt), 0>, ISA_MICROMIPS64R6; -def : MipsInstAlias<"dsll $rd, $rt", - (DSLLV_MM64R6 GPR64Opnd:$rd, GPR64Opnd:$rd, - GPR32Opnd:$rt), 0>, ISA_MICROMIPS64R6; diff --git a/gnu/llvm/lib/Transforms/Utils/CmpInstAnalysis.cpp b/gnu/llvm/lib/Transforms/Utils/CmpInstAnalysis.cpp index d9294c49930..3b15a0a3e60 100644 --- a/gnu/llvm/lib/Transforms/Utils/CmpInstAnalysis.cpp +++ b/gnu/llvm/lib/Transforms/Utils/CmpInstAnalysis.cpp @@ -18,6 +18,29 @@ using namespace llvm; +/// getICmpCode - Encode a icmp predicate into a three bit mask. These bits +/// are carefully arranged to allow folding of expressions such as: +/// +/// (A < B) | (A > B) --> (A != B) +/// +/// Note that this is only valid if the first and second predicates have the +/// same sign. Is illegal to do: (A u< B) | (A s> B) +/// +/// Three bits are used to represent the condition, as follows: +/// 0 A > B +/// 1 A == B +/// 2 A < B +/// +/// <=> Value Definition +/// 000 0 Always false +/// 001 1 A > B +/// 010 2 A == B +/// 011 3 A >= B +/// 100 4 A < B +/// 101 5 A != B +/// 110 6 A <= B +/// 111 7 Always true +/// unsigned llvm::getICmpCode(const ICmpInst *ICI, bool InvertPred) { ICmpInst::Predicate Pred = InvertPred ? ICI->getInversePredicate() : ICI->getPredicate(); @@ -39,6 +62,13 @@ unsigned llvm::getICmpCode(const ICmpInst *ICI, bool InvertPred) { } } +/// getICmpValue - This is the complement of getICmpCode, which turns an +/// opcode and two operands into either a constant true or false, or the +/// predicate for a new ICmp instruction. The sign is passed in to determine +/// which kind of predicate to use in the new icmp instruction. +/// Non-NULL return value will be a true or false constant. +/// NULL return means a new ICmp is needed. The predicate for which is +/// output in NewICmpPred. Value *llvm::getICmpValue(bool Sign, unsigned Code, Value *LHS, Value *RHS, CmpInst::Predicate &NewICmpPred) { switch (Code) { @@ -57,52 +87,10 @@ Value *llvm::getICmpValue(bool Sign, unsigned Code, Value *LHS, Value *RHS, return nullptr; } +/// PredicatesFoldable - Return true if both predicates match sign or if at +/// least one of them is an equality comparison (which is signless). bool llvm::PredicatesFoldable(ICmpInst::Predicate p1, ICmpInst::Predicate p2) { return (CmpInst::isSigned(p1) == CmpInst::isSigned(p2)) || (CmpInst::isSigned(p1) && ICmpInst::isEquality(p2)) || (CmpInst::isSigned(p2) && ICmpInst::isEquality(p1)); } - -bool llvm::decomposeBitTestICmp(const ICmpInst *I, CmpInst::Predicate &Pred, - Value *&X, Value *&Y, Value *&Z) { - ConstantInt *C = dyn_cast<ConstantInt>(I->getOperand(1)); - if (!C) - return false; - - switch (I->getPredicate()) { - default: - return false; - case ICmpInst::ICMP_SLT: - // X < 0 is equivalent to (X & SignMask) != 0. - if (!C->isZero()) - return false; - Y = ConstantInt::get(I->getContext(), APInt::getSignMask(C->getBitWidth())); - Pred = ICmpInst::ICMP_NE; - break; - case ICmpInst::ICMP_SGT: - // X > -1 is equivalent to (X & SignMask) == 0. - if (!C->isMinusOne()) - return false; - Y = ConstantInt::get(I->getContext(), APInt::getSignMask(C->getBitWidth())); - Pred = ICmpInst::ICMP_EQ; - break; - case ICmpInst::ICMP_ULT: - // X <u 2^n is equivalent to (X & ~(2^n-1)) == 0. - if (!C->getValue().isPowerOf2()) - return false; - Y = ConstantInt::get(I->getContext(), -C->getValue()); - Pred = ICmpInst::ICMP_EQ; - break; - case ICmpInst::ICMP_UGT: - // X >u 2^n-1 is equivalent to (X & ~(2^n-1)) != 0. - if (!(C->getValue() + 1).isPowerOf2()) - return false; - Y = ConstantInt::get(I->getContext(), ~C->getValue()); - Pred = ICmpInst::ICMP_NE; - break; - } - - X = I->getOperand(0); - Z = ConstantInt::getNullValue(C->getType()); - return true; -} diff --git a/gnu/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h b/gnu/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h index ec7549d4535..931190e43a6 100644 --- a/gnu/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h +++ b/gnu/llvm/tools/clang/include/clang/Analysis/AnalysisContext.h @@ -201,10 +201,6 @@ public: } return static_cast<T*>(data); } - - /// Returns true if the root namespace of the given declaration is the 'std' - /// C++ namespace. - static bool isInStdNamespace(const Decl *D); private: ManagedAnalysis *&getAnalysisImpl(const void* tag); @@ -406,8 +402,7 @@ private: }; class AnalysisDeclContextManager { - typedef llvm::DenseMap<const Decl *, std::unique_ptr<AnalysisDeclContext>> - ContextMap; + typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap; ContextMap Contexts; LocationContextManager LocContexts; @@ -426,7 +421,6 @@ public: bool addImplicitDtors = false, bool addInitializers = false, bool addTemporaryDtors = false, - bool addLifetime = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, diff --git a/gnu/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/gnu/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h index b72bce5fc9f..197d27a2f37 100644 --- a/gnu/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h +++ b/gnu/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -19,7 +19,6 @@ #include "llvm/ADT/FoldingSet.h" namespace clang { -class CFGBlock; namespace ento { @@ -59,9 +58,10 @@ public: /// /// The last parameter can be used to register a new visitor with the given /// BugReport while processing a node. - virtual std::shared_ptr<PathDiagnosticPiece> - VisitNode(const ExplodedNode *Succ, const ExplodedNode *Pred, - BugReporterContext &BRC, BugReport &BR) = 0; + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) = 0; /// \brief Provide custom definition for the final diagnostic piece on the /// path - the piece, which is displayed before the path is expanded. @@ -120,10 +120,10 @@ public: void Profile(llvm::FoldingSetNodeID &ID) const override; - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) override; + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; }; class TrackConstraintBRVisitor final @@ -149,10 +149,10 @@ public: /// to make all PathDiagnosticPieces created by this visitor. static const char *getTag(); - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) override; + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; private: /// Checks if the constraint is valid in the current state. @@ -171,10 +171,10 @@ public: ID.AddPointer(&x); } - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) override; + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; /// If the statement is a message send expression with nil receiver, returns /// the receiver expression. Returns NULL otherwise. @@ -184,11 +184,6 @@ public: /// Visitor that tries to report interesting diagnostics from conditions. class ConditionBRVisitor final : public BugReporterVisitorImpl<ConditionBRVisitor> { - - // FIXME: constexpr initialization isn't supported by MSVC2013. - static const char *const GenericTrueMessage; - static const char *const GenericFalseMessage; - public: void Profile(llvm::FoldingSetNodeID &ID) const override { static int x = 0; @@ -199,48 +194,56 @@ public: /// to make all PathDiagnosticPieces created by this visitor. static const char *getTag(); - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *Prev, - BugReporterContext &BRC, - BugReport &BR) override; - - std::shared_ptr<PathDiagnosticPiece> VisitNodeImpl(const ExplodedNode *N, - const ExplodedNode *Prev, - BugReporterContext &BRC, - BugReport &BR); - - std::shared_ptr<PathDiagnosticPiece> - VisitTerminator(const Stmt *Term, const ExplodedNode *N, - const CFGBlock *srcBlk, const CFGBlock *dstBlk, BugReport &R, - BugReporterContext &BRC); - - std::shared_ptr<PathDiagnosticPiece> - VisitTrueTest(const Expr *Cond, bool tookTrue, BugReporterContext &BRC, - BugReport &R, const ExplodedNode *N); + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) override; - std::shared_ptr<PathDiagnosticPiece> - VisitTrueTest(const Expr *Cond, const DeclRefExpr *DR, const bool tookTrue, - BugReporterContext &BRC, BugReport &R, const ExplodedNode *N); - - std::shared_ptr<PathDiagnosticPiece> - VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr, - const bool tookTrue, BugReporterContext &BRC, BugReport &R, - const ExplodedNode *N); - - std::shared_ptr<PathDiagnosticPiece> - VisitConditionVariable(StringRef LhsString, const Expr *CondVarExpr, - const bool tookTrue, BugReporterContext &BRC, - BugReport &R, const ExplodedNode *N); + PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR); + + PathDiagnosticPiece *VisitTerminator(const Stmt *Term, + const ExplodedNode *N, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReport &R, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const BinaryOperator *BExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, + const Expr *CondVarExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); bool patternMatch(const Expr *Ex, - const Expr *ParentEx, raw_ostream &Out, BugReporterContext &BRC, BugReport &R, const ExplodedNode *N, Optional<bool> &prunable); - - static bool isPieceMessageGeneric(const PathDiagnosticPiece *Piece); }; /// \brief Suppress reports that might lead to known false positives. @@ -258,10 +261,10 @@ public: ID.AddPointer(getTag()); } - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *Prev, - BugReporterContext &BRC, - BugReport &BR) override { + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR) override { return nullptr; } @@ -290,10 +293,10 @@ public: ID.AddPointer(R); } - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) override; + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) override; }; class SuppressInlineDefensiveChecksVisitor final @@ -321,26 +324,10 @@ public: /// to make all PathDiagnosticPieces created by this visitor. static const char *getTag(); - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ, - const ExplodedNode *Pred, - BugReporterContext &BRC, - BugReport &BR) override; -}; - -class CXXSelfAssignmentBRVisitor final - : public BugReporterVisitorImpl<CXXSelfAssignmentBRVisitor> { - - bool Satisfied; - -public: - CXXSelfAssignmentBRVisitor() : Satisfied(false) {} - - void Profile(llvm::FoldingSetNodeID &ID) const override {} - - std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *Succ, - const ExplodedNode *Pred, - BugReporterContext &BRC, - BugReport &BR) override; + PathDiagnosticPiece *VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) override; }; namespace bugreporter { diff --git a/gnu/llvm/tools/clang/lib/Analysis/BodyFarm.h b/gnu/llvm/tools/clang/lib/Analysis/BodyFarm.h index edbe9962465..91379437231 100644 --- a/gnu/llvm/tools/clang/lib/Analysis/BodyFarm.h +++ b/gnu/llvm/tools/clang/lib/Analysis/BodyFarm.h @@ -15,7 +15,6 @@ #ifndef LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H #define LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H -#include "clang/AST/DeclBase.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" @@ -23,6 +22,7 @@ namespace clang { class ASTContext; +class Decl; class FunctionDecl; class ObjCMethodDecl; class ObjCPropertyDecl; |