Index: vendor/llvm/dist-release_70/include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- vendor/llvm/dist-release_70/include/llvm/CodeGen/GlobalISel/IRTranslator.h (revision 338377) +++ vendor/llvm/dist-release_70/include/llvm/CodeGen/GlobalISel/IRTranslator.h (revision 338378) @@ -1,545 +1,546 @@ //===- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// \file /// This file declares the IRTranslator pass. /// This pass is responsible for translating LLVM IR into MachineInstr. /// It uses target hooks to lower the ABI but aside from that, the pass /// generated code is generic. This is the default translator used for /// GlobalISel. /// /// \todo Replace the comments with actual doxygen comments. //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H #define LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Types.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/Support/Allocator.h" #include "llvm/IR/Intrinsics.h" #include #include namespace llvm { class AllocaInst; class BasicBlock; class CallInst; class CallLowering; class Constant; class DataLayout; class Instruction; class MachineBasicBlock; class MachineFunction; class MachineInstr; class MachineRegisterInfo; class OptimizationRemarkEmitter; class PHINode; class TargetPassConfig; class User; class Value; // Technically the pass should run on an hypothetical MachineModule, // since it should translate Global into some sort of MachineGlobal. // The MachineGlobal should ultimately just be a transfer of ownership of // the interesting bits that are relevant to represent a global value. // That being said, we could investigate what would it cost to just duplicate // the information from the LLVM IR. // The idea is that ultimately we would be able to free up the memory used // by the LLVM IR as soon as the translation is over. class IRTranslator : public MachineFunctionPass { public: static char ID; private: /// Interface used to lower the everything related to calls. const CallLowering *CLI; /// This class contains the mapping between the Values to vreg related data. class ValueToVRegInfo { public: ValueToVRegInfo() = default; using VRegListT = SmallVector; using OffsetListT = SmallVector; using const_vreg_iterator = DenseMap::const_iterator; using const_offset_iterator = DenseMap::const_iterator; inline const_vreg_iterator vregs_end() const { return ValToVRegs.end(); } VRegListT *getVRegs(const Value &V) { auto It = ValToVRegs.find(&V); if (It != ValToVRegs.end()) return It->second; return insertVRegs(V); } OffsetListT *getOffsets(const Value &V) { auto It = TypeToOffsets.find(V.getType()); if (It != TypeToOffsets.end()) return It->second; return insertOffsets(V); } const_vreg_iterator findVRegs(const Value &V) const { return ValToVRegs.find(&V); } bool contains(const Value &V) const { return ValToVRegs.find(&V) != ValToVRegs.end(); } void reset() { ValToVRegs.clear(); TypeToOffsets.clear(); VRegAlloc.DestroyAll(); OffsetAlloc.DestroyAll(); } private: VRegListT *insertVRegs(const Value &V) { assert(ValToVRegs.find(&V) == ValToVRegs.end() && "Value already exists"); // We placement new using our fast allocator since we never try to free // the vectors until translation is finished. auto *VRegList = new (VRegAlloc.Allocate()) VRegListT(); ValToVRegs[&V] = VRegList; return VRegList; } OffsetListT *insertOffsets(const Value &V) { assert(TypeToOffsets.find(V.getType()) == TypeToOffsets.end() && "Type already exists"); auto *OffsetList = new (OffsetAlloc.Allocate()) OffsetListT(); TypeToOffsets[V.getType()] = OffsetList; return OffsetList; } SpecificBumpPtrAllocator VRegAlloc; SpecificBumpPtrAllocator OffsetAlloc; // We store pointers to vectors here since references may be invalidated // while we hold them if we stored the vectors directly. DenseMap ValToVRegs; DenseMap TypeToOffsets; }; /// Mapping of the values of the current LLVM IR function to the related /// virtual registers and offsets. ValueToVRegInfo VMap; // N.b. it's not completely obvious that this will be sufficient for every // LLVM IR construct (with "invoke" being the obvious candidate to mess up our // lives. DenseMap BBToMBB; // One BasicBlock can be translated to multiple MachineBasicBlocks. For such // BasicBlocks translated to multiple MachineBasicBlocks, MachinePreds retains // a mapping between the edges arriving at the BasicBlock to the corresponding // created MachineBasicBlocks. Some BasicBlocks that get translated to a // single MachineBasicBlock may also end up in this Map. using CFGEdge = std::pair; DenseMap> MachinePreds; // List of stubbed PHI instructions, for values and basic blocks to be filled // in once all MachineBasicBlocks have been created. SmallVector>, 4> PendingPHIs; /// Record of what frame index has been allocated to specified allocas for /// this function. DenseMap FrameIndices; /// \name Methods for translating form LLVM IR to MachineInstr. /// \see ::translate for general information on the translate methods. /// @{ /// Translate \p Inst into its corresponding MachineInstr instruction(s). /// Insert the newly translated instruction(s) right where the CurBuilder /// is set. /// /// The general algorithm is: /// 1. Look for a virtual register for each operand or /// create one. /// 2 Update the VMap accordingly. /// 2.alt. For constant arguments, if they are compile time constants, /// produce an immediate in the right operand and do not touch /// ValToReg. Actually we will go with a virtual register for each /// constants because it may be expensive to actually materialize the /// constant. Moreover, if the constant spans on several instructions, /// CSE may not catch them. /// => Update ValToVReg and remember that we saw a constant in Constants. /// We will materialize all the constants in finalize. /// Note: we would need to do something so that we can recognize such operand /// as constants. /// 3. Create the generic instruction. /// /// \return true if the translation succeeded. bool translate(const Instruction &Inst); /// Materialize \p C into virtual-register \p Reg. The generic instructions /// performing this materialization will be inserted into the entry block of /// the function. /// /// \return true if the materialization succeeded. bool translate(const Constant &C, unsigned Reg); /// Translate an LLVM bitcast into generic IR. Either a COPY or a G_BITCAST is /// emitted. bool translateBitCast(const User &U, MachineIRBuilder &MIRBuilder); /// Translate an LLVM load instruction into generic IR. bool translateLoad(const User &U, MachineIRBuilder &MIRBuilder); /// Translate an LLVM store instruction into generic IR. bool translateStore(const User &U, MachineIRBuilder &MIRBuilder); /// Translate an LLVM string intrinsic (memcpy, memset, ...). bool translateMemfunc(const CallInst &CI, MachineIRBuilder &MIRBuilder, unsigned ID); void getStackGuard(unsigned DstReg, MachineIRBuilder &MIRBuilder); bool translateOverflowIntrinsic(const CallInst &CI, unsigned Op, MachineIRBuilder &MIRBuilder); bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder); bool translateInlineAsm(const CallInst &CI, MachineIRBuilder &MIRBuilder); // FIXME: temporary function to expose previous interface to call lowering // until it is refactored. /// Combines all component registers of \p V into a single scalar with size /// "max(Offsets) + last size". unsigned packRegs(const Value &V, MachineIRBuilder &MIRBuilder); void unpackRegs(const Value &V, unsigned Src, MachineIRBuilder &MIRBuilder); /// Returns true if the value should be split into multiple LLTs. /// If \p Offsets is given then the split type's offsets will be stored in it. + /// If \p Offsets is not empty it will be cleared first. bool valueIsSplit(const Value &V, SmallVectorImpl *Offsets = nullptr); /// Translate call instruction. /// \pre \p U is a call instruction. bool translateCall(const User &U, MachineIRBuilder &MIRBuilder); bool translateInvoke(const User &U, MachineIRBuilder &MIRBuilder); bool translateLandingPad(const User &U, MachineIRBuilder &MIRBuilder); /// Translate one of LLVM's cast instructions into MachineInstrs, with the /// given generic Opcode. bool translateCast(unsigned Opcode, const User &U, MachineIRBuilder &MIRBuilder); /// Translate a phi instruction. bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder); /// Translate a comparison (icmp or fcmp) instruction or constant. bool translateCompare(const User &U, MachineIRBuilder &MIRBuilder); /// Translate an integer compare instruction (or constant). bool translateICmp(const User &U, MachineIRBuilder &MIRBuilder) { return translateCompare(U, MIRBuilder); } /// Translate a floating-point compare instruction (or constant). bool translateFCmp(const User &U, MachineIRBuilder &MIRBuilder) { return translateCompare(U, MIRBuilder); } /// Add remaining operands onto phis we've translated. Executed after all /// MachineBasicBlocks for the function have been created. void finishPendingPhis(); /// Translate \p Inst into a binary operation \p Opcode. /// \pre \p U is a binary operation. bool translateBinaryOp(unsigned Opcode, const User &U, MachineIRBuilder &MIRBuilder); /// Translate branch (br) instruction. /// \pre \p U is a branch instruction. bool translateBr(const User &U, MachineIRBuilder &MIRBuilder); bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder); bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder); bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder); bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder); bool translateSelect(const User &U, MachineIRBuilder &MIRBuilder); bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder); bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder); /// Translate return (ret) instruction. /// The target needs to implement CallLowering::lowerReturn for /// this to succeed. /// \pre \p U is a return instruction. bool translateRet(const User &U, MachineIRBuilder &MIRBuilder); bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder); bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder); } bool translateSub(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_SUB, U, MIRBuilder); } bool translateAnd(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_AND, U, MIRBuilder); } bool translateMul(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_MUL, U, MIRBuilder); } bool translateOr(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_OR, U, MIRBuilder); } bool translateXor(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_XOR, U, MIRBuilder); } bool translateUDiv(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_UDIV, U, MIRBuilder); } bool translateSDiv(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_SDIV, U, MIRBuilder); } bool translateURem(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_UREM, U, MIRBuilder); } bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder); } bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder); } bool translatePtrToInt(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_PTRTOINT, U, MIRBuilder); } bool translateTrunc(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_TRUNC, U, MIRBuilder); } bool translateFPTrunc(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_FPTRUNC, U, MIRBuilder); } bool translateFPExt(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_FPEXT, U, MIRBuilder); } bool translateFPToUI(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_FPTOUI, U, MIRBuilder); } bool translateFPToSI(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_FPTOSI, U, MIRBuilder); } bool translateUIToFP(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_UITOFP, U, MIRBuilder); } bool translateSIToFP(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_SITOFP, U, MIRBuilder); } bool translateUnreachable(const User &U, MachineIRBuilder &MIRBuilder) { return true; } bool translateSExt(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_SEXT, U, MIRBuilder); } bool translateZExt(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_ZEXT, U, MIRBuilder); } bool translateShl(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_SHL, U, MIRBuilder); } bool translateLShr(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_LSHR, U, MIRBuilder); } bool translateAShr(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_ASHR, U, MIRBuilder); } bool translateFAdd(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FADD, U, MIRBuilder); } bool translateFMul(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FMUL, U, MIRBuilder); } bool translateFDiv(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FDIV, U, MIRBuilder); } bool translateFRem(const User &U, MachineIRBuilder &MIRBuilder) { return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder); } bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder); bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder); bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder); bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder); bool translateAtomicCmpXchg(const User &U, MachineIRBuilder &MIRBuilder); bool translateAtomicRMW(const User &U, MachineIRBuilder &MIRBuilder); // Stubs to keep the compiler happy while we implement the rest of the // translation. bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateCleanupRet(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateCatchRet(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateCatchSwitch(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateFence(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateAddrSpaceCast(const User &U, MachineIRBuilder &MIRBuilder) { return translateCast(TargetOpcode::G_ADDRSPACE_CAST, U, MIRBuilder); } bool translateCleanupPad(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateCatchPad(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateUserOp1(const User &U, MachineIRBuilder &MIRBuilder) { return false; } bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) { return false; } /// @} // Builder for machine instruction a la IRBuilder. // I.e., compared to regular MIBuilder, this one also inserts the instruction // in the current block, it can creates block, etc., basically a kind of // IRBuilder, but for Machine IR. MachineIRBuilder CurBuilder; // Builder set to the entry block (just after ABI lowering instructions). Used // as a convenient location for Constants. MachineIRBuilder EntryBuilder; // The MachineFunction currently being translated. MachineFunction *MF; /// MachineRegisterInfo used to create virtual registers. MachineRegisterInfo *MRI = nullptr; const DataLayout *DL; /// Current target configuration. Controls how the pass handles errors. const TargetPassConfig *TPC; /// Current optimization remark emitter. Used to report failures. std::unique_ptr ORE; // * Insert all the code needed to materialize the constants // at the proper place. E.g., Entry block or dominator block // of each constant depending on how fancy we want to be. // * Clear the different maps. void finalizeFunction(); /// Get the VRegs that represent \p Val. /// Non-aggregate types have just one corresponding VReg and the list can be /// used as a single "unsigned". Aggregates get flattened. If such VRegs do /// not exist, they are created. ArrayRef getOrCreateVRegs(const Value &Val); unsigned getOrCreateVReg(const Value &Val) { auto Regs = getOrCreateVRegs(Val); if (Regs.empty()) return 0; assert(Regs.size() == 1 && "attempt to get single VReg for aggregate or void"); return Regs[0]; } /// Allocate some vregs and offsets in the VMap. Then populate just the /// offsets while leaving the vregs empty. ValueToVRegInfo::VRegListT &allocateVRegs(const Value &Val); /// Get the frame index that represents \p Val. /// If such VReg does not exist, it is created. int getOrCreateFrameIndex(const AllocaInst &AI); /// Get the alignment of the given memory operation instruction. This will /// either be the explicitly specified value or the ABI-required alignment for /// the type being accessed (according to the Module's DataLayout). unsigned getMemOpAlignment(const Instruction &I); /// Get the MachineBasicBlock that represents \p BB. Specifically, the block /// returned will be the head of the translated block (suitable for branch /// destinations). MachineBasicBlock &getMBB(const BasicBlock &BB); /// Record \p NewPred as a Machine predecessor to `Edge.second`, corresponding /// to `Edge.first` at the IR level. This is used when IRTranslation creates /// multiple MachineBasicBlocks for a given IR block and the CFG is no longer /// represented simply by the IR-level CFG. void addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred); /// Returns the Machine IR predecessors for the given IR CFG edge. Usually /// this is just the single MachineBasicBlock corresponding to the predecessor /// in the IR. More complex lowering can result in multiple MachineBasicBlocks /// preceding the original though (e.g. switch instructions). SmallVector getMachinePredBBs(CFGEdge Edge) { auto RemappedEdge = MachinePreds.find(Edge); if (RemappedEdge != MachinePreds.end()) return RemappedEdge->second; return SmallVector(1, &getMBB(*Edge.first)); } public: // Ctor, nothing fancy. IRTranslator(); StringRef getPassName() const override { return "IRTranslator"; } void getAnalysisUsage(AnalysisUsage &AU) const override; // Algo: // CallLowering = MF.subtarget.getCallLowering() // F = MF.getParent() // MIRBuilder.reset(MF) // getMBB(F.getEntryBB()) // CallLowering->translateArguments(MIRBuilder, F, ValToVReg) // for each bb in F // getMBB(bb) // for each inst in bb // if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence)) // report_fatal_error("Don't know how to translate input"); // finalize() bool runOnMachineFunction(MachineFunction &MF) override; }; } // end namespace llvm #endif // LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H Index: vendor/llvm/dist-release_70/include/llvm/IR/Function.h =================================================================== --- vendor/llvm/dist-release_70/include/llvm/IR/Function.h (revision 338377) +++ vendor/llvm/dist-release_70/include/llvm/IR/Function.h (revision 338378) @@ -1,816 +1,816 @@ //===- llvm/Function.h - Class to represent a single function ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the declaration of the Function class, which represents a // single function/procedure in LLVM. // // A function basically consists of a list of basic blocks, a list of arguments, // and a symbol table. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_FUNCTION_H #define LLVM_IR_FUNCTION_H #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_node.h" #include "llvm/ADT/iterator_range.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/OperandTraits.h" #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include #include #include #include #include namespace llvm { namespace Intrinsic { enum ID : unsigned; } class AssemblyAnnotationWriter; class Constant; class DISubprogram; class LLVMContext; class Module; template class Optional; class raw_ostream; class Type; class User; class Function : public GlobalObject, public ilist_node { public: using BasicBlockListType = SymbolTableList; // BasicBlock iterators... using iterator = BasicBlockListType::iterator; using const_iterator = BasicBlockListType::const_iterator; using arg_iterator = Argument *; using const_arg_iterator = const Argument *; private: // Important things that make up a function! BasicBlockListType BasicBlocks; ///< The basic blocks mutable Argument *Arguments = nullptr; ///< The formal arguments size_t NumArgs; std::unique_ptr SymTab; ///< Symbol table of args/instructions AttributeList AttributeSets; ///< Parameter attributes /* * Value::SubclassData * * bit 0 : HasLazyArguments * bit 1 : HasPrefixData * bit 2 : HasPrologueData * bit 3 : HasPersonalityFn * bits 4-13 : CallingConvention * bits 14 : HasGC * bits 15 : [reserved] */ /// Bits from GlobalObject::GlobalObjectSubclassData. enum { /// Whether this function is materializable. IsMaterializableBit = 0, }; friend class SymbolTableListTraits; /// hasLazyArguments/CheckLazyArguments - The argument list of a function is /// built on demand, so that the list isn't allocated until the first client /// needs it. The hasLazyArguments predicate returns true if the arg list /// hasn't been set up yet. public: bool hasLazyArguments() const { return getSubclassDataFromValue() & (1<<0); } private: void CheckLazyArguments() const { if (hasLazyArguments()) BuildLazyArguments(); } void BuildLazyArguments() const; void clearArguments(); /// Function ctor - If the (optional) Module argument is specified, the /// function is automatically inserted into the end of the function list for /// the module. /// Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &N = "", Module *M = nullptr); public: Function(const Function&) = delete; void operator=(const Function&) = delete; ~Function(); // This is here to help easily convert from FunctionT * (Function * or // MachineFunction *) in BlockFrequencyInfoImpl to Function * by calling // FunctionT->getFunction(). const Function &getFunction() const { return *this; } static Function *Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N = "", Module *M = nullptr) { return new Function(Ty, Linkage, N, M); } // Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Returns the number of non-debug IR instructions in this function. /// This is equivalent to the sum of the sizes of each basic block contained /// within this function. unsigned getInstructionCount(); /// Returns the FunctionType for me. FunctionType *getFunctionType() const { return cast(getValueType()); } /// Returns the type of the ret val. Type *getReturnType() const { return getFunctionType()->getReturnType(); } /// getContext - Return a reference to the LLVMContext associated with this /// function. LLVMContext &getContext() const; /// isVarArg - Return true if this function takes a variable number of /// arguments. bool isVarArg() const { return getFunctionType()->isVarArg(); } bool isMaterializable() const { return getGlobalObjectSubClassData() & (1 << IsMaterializableBit); } void setIsMaterializable(bool V) { unsigned Mask = 1 << IsMaterializableBit; setGlobalObjectSubClassData((~Mask & getGlobalObjectSubClassData()) | (V ? Mask : 0u)); } /// getIntrinsicID - This method returns the ID number of the specified /// function, or Intrinsic::not_intrinsic if the function is not an /// intrinsic, or if the pointer is null. This value is always defined to be /// zero to allow easy checking for whether a function is intrinsic or not. /// The particular intrinsic functions which correspond to this value are /// defined in llvm/Intrinsics.h. Intrinsic::ID getIntrinsicID() const LLVM_READONLY { return IntID; } /// isIntrinsic - Returns true if the function's name starts with "llvm.". /// It's possible for this function to return true while getIntrinsicID() /// returns Intrinsic::not_intrinsic! bool isIntrinsic() const { return HasLLVMReservedName; } static Intrinsic::ID lookupIntrinsicID(StringRef Name); /// Recalculate the ID for this function if it is an Intrinsic defined /// in llvm/Intrinsics.h. Sets the intrinsic ID to Intrinsic::not_intrinsic /// if the name of this function does not match an intrinsic in that header. /// Note, this method does not need to be called directly, as it is called /// from Value::setName() whenever the name of this function changes. void recalculateIntrinsicID(); /// getCallingConv()/setCallingConv(CC) - These method get and set the /// calling convention of this function. The enum values for the known /// calling conventions are defined in CallingConv.h. CallingConv::ID getCallingConv() const { return static_cast((getSubclassDataFromValue() >> 4) & CallingConv::MaxID); } void setCallingConv(CallingConv::ID CC) { auto ID = static_cast(CC); assert(!(ID & ~CallingConv::MaxID) && "Unsupported calling convention"); setValueSubclassData((getSubclassDataFromValue() & 0xc00f) | (ID << 4)); } /// Return the attribute list for this Function. AttributeList getAttributes() const { return AttributeSets; } /// Set the attribute list for this Function. void setAttributes(AttributeList Attrs) { AttributeSets = Attrs; } /// Add function attributes to this function. void addFnAttr(Attribute::AttrKind Kind) { addAttribute(AttributeList::FunctionIndex, Kind); } /// Add function attributes to this function. void addFnAttr(StringRef Kind, StringRef Val = StringRef()) { addAttribute(AttributeList::FunctionIndex, Attribute::get(getContext(), Kind, Val)); } /// Add function attributes to this function. void addFnAttr(Attribute Attr) { addAttribute(AttributeList::FunctionIndex, Attr); } /// Remove function attributes from this function. void removeFnAttr(Attribute::AttrKind Kind) { removeAttribute(AttributeList::FunctionIndex, Kind); } /// Remove function attribute from this function. void removeFnAttr(StringRef Kind) { setAttributes(getAttributes().removeAttribute( getContext(), AttributeList::FunctionIndex, Kind)); } enum ProfileCountType { PCT_Invalid, PCT_Real, PCT_Synthetic }; /// Class to represent profile counts. /// /// This class represents both real and synthetic profile counts. class ProfileCount { private: uint64_t Count; ProfileCountType PCT; static ProfileCount Invalid; public: ProfileCount() : Count(-1), PCT(PCT_Invalid) {} ProfileCount(uint64_t Count, ProfileCountType PCT) : Count(Count), PCT(PCT) {} bool hasValue() const { return PCT != PCT_Invalid; } uint64_t getCount() const { return Count; } ProfileCountType getType() const { return PCT; } bool isSynthetic() const { return PCT == PCT_Synthetic; } explicit operator bool() { return hasValue(); } bool operator!() const { return !hasValue(); } // Update the count retaining the same profile count type. ProfileCount &setCount(uint64_t C) { Count = C; return *this; } static ProfileCount getInvalid() { return ProfileCount(-1, PCT_Invalid); } }; /// Set the entry count for this function. /// /// Entry count is the number of times this function was executed based on /// pgo data. \p Imports points to a set of GUIDs that needs to /// be imported by the function for sample PGO, to enable the same inlines as /// the profiled optimized binary. void setEntryCount(ProfileCount Count, const DenseSet *Imports = nullptr); /// A convenience wrapper for setting entry count void setEntryCount(uint64_t Count, ProfileCountType Type = PCT_Real, const DenseSet *Imports = nullptr); /// Get the entry count for this function. /// /// Entry count is the number of times the function was executed based on /// pgo data. ProfileCount getEntryCount() const; /// Return true if the function is annotated with profile data. /// /// Presence of entry counts from a profile run implies the function has /// profile annotations. bool hasProfileData() const { return getEntryCount().hasValue(); } /// Returns the set of GUIDs that needs to be imported to the function for /// sample PGO, to enable the same inlines as the profiled optimized binary. DenseSet getImportGUIDs() const; /// Set the section prefix for this function. void setSectionPrefix(StringRef Prefix); /// Get the section prefix for this function. Optional getSectionPrefix() const; /// Return true if the function has the attribute. bool hasFnAttribute(Attribute::AttrKind Kind) const { return AttributeSets.hasFnAttribute(Kind); } /// Return true if the function has the attribute. bool hasFnAttribute(StringRef Kind) const { return AttributeSets.hasFnAttribute(Kind); } /// Return the attribute for the given attribute kind. Attribute getFnAttribute(Attribute::AttrKind Kind) const { return getAttribute(AttributeList::FunctionIndex, Kind); } /// Return the attribute for the given attribute kind. Attribute getFnAttribute(StringRef Kind) const { return getAttribute(AttributeList::FunctionIndex, Kind); } /// Return the stack alignment for the function. unsigned getFnStackAlignment() const { if (!hasFnAttribute(Attribute::StackAlignment)) return 0; return AttributeSets.getStackAlignment(AttributeList::FunctionIndex); } /// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm /// to use during code generation. bool hasGC() const { return getSubclassDataFromValue() & (1<<14); } const std::string &getGC() const; void setGC(std::string Str); void clearGC(); /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute::AttrKind Kind); /// adds the attribute to the list of attributes. void addAttribute(unsigned i, Attribute Attr); /// adds the attributes to the list of attributes. void addAttributes(unsigned i, const AttrBuilder &Attrs); /// adds the attribute to the list of attributes for the given arg. void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind); /// adds the attribute to the list of attributes for the given arg. void addParamAttr(unsigned ArgNo, Attribute Attr); /// adds the attributes to the list of attributes for the given arg. void addParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs); /// removes the attribute from the list of attributes. void removeAttribute(unsigned i, Attribute::AttrKind Kind); /// removes the attribute from the list of attributes. void removeAttribute(unsigned i, StringRef Kind); /// removes the attributes from the list of attributes. void removeAttributes(unsigned i, const AttrBuilder &Attrs); /// removes the attribute from the list of attributes. void removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind); /// removes the attribute from the list of attributes. void removeParamAttr(unsigned ArgNo, StringRef Kind); /// removes the attribute from the list of attributes. void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs); /// check if an attributes is in the list of attributes. bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const { return getAttributes().hasAttribute(i, Kind); } /// check if an attributes is in the list of attributes. bool hasParamAttribute(unsigned ArgNo, Attribute::AttrKind Kind) const { return getAttributes().hasParamAttribute(ArgNo, Kind); } /// gets the attribute from the list of attributes. Attribute getAttribute(unsigned i, Attribute::AttrKind Kind) const { return AttributeSets.getAttribute(i, Kind); } /// gets the attribute from the list of attributes. Attribute getAttribute(unsigned i, StringRef Kind) const { return AttributeSets.getAttribute(i, Kind); } /// adds the dereferenceable attribute to the list of attributes. void addDereferenceableAttr(unsigned i, uint64_t Bytes); /// adds the dereferenceable attribute to the list of attributes for /// the given arg. void addDereferenceableParamAttr(unsigned ArgNo, uint64_t Bytes); /// adds the dereferenceable_or_null attribute to the list of /// attributes. void addDereferenceableOrNullAttr(unsigned i, uint64_t Bytes); /// adds the dereferenceable_or_null attribute to the list of /// attributes for the given arg. void addDereferenceableOrNullParamAttr(unsigned ArgNo, uint64_t Bytes); /// Extract the alignment for a call or parameter (0=unknown). unsigned getParamAlignment(unsigned ArgNo) const { return AttributeSets.getParamAlignment(ArgNo); } /// Extract the number of dereferenceable bytes for a call or /// parameter (0=unknown). /// @param i AttributeList index, referring to a return value or argument. uint64_t getDereferenceableBytes(unsigned i) const { return AttributeSets.getDereferenceableBytes(i); } /// Extract the number of dereferenceable bytes for a parameter. /// @param ArgNo Index of an argument, with 0 being the first function arg. uint64_t getParamDereferenceableBytes(unsigned ArgNo) const { return AttributeSets.getParamDereferenceableBytes(ArgNo); } /// Extract the number of dereferenceable_or_null bytes for a call or /// parameter (0=unknown). /// @param i AttributeList index, referring to a return value or argument. uint64_t getDereferenceableOrNullBytes(unsigned i) const { return AttributeSets.getDereferenceableOrNullBytes(i); } /// Extract the number of dereferenceable_or_null bytes for a /// parameter. /// @param ArgNo AttributeList ArgNo, referring to an argument. uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const { return AttributeSets.getParamDereferenceableOrNullBytes(ArgNo); } /// Determine if the function does not access memory. bool doesNotAccessMemory() const { return hasFnAttribute(Attribute::ReadNone); } void setDoesNotAccessMemory() { addFnAttr(Attribute::ReadNone); } /// Determine if the function does not access or only reads memory. bool onlyReadsMemory() const { return doesNotAccessMemory() || hasFnAttribute(Attribute::ReadOnly); } void setOnlyReadsMemory() { addFnAttr(Attribute::ReadOnly); } /// Determine if the function does not access or only writes memory. bool doesNotReadMemory() const { return doesNotAccessMemory() || hasFnAttribute(Attribute::WriteOnly); } void setDoesNotReadMemory() { addFnAttr(Attribute::WriteOnly); } /// Determine if the call can access memmory only using pointers based /// on its arguments. bool onlyAccessesArgMemory() const { return hasFnAttribute(Attribute::ArgMemOnly); } void setOnlyAccessesArgMemory() { addFnAttr(Attribute::ArgMemOnly); } /// Determine if the function may only access memory that is /// inaccessible from the IR. bool onlyAccessesInaccessibleMemory() const { return hasFnAttribute(Attribute::InaccessibleMemOnly); } void setOnlyAccessesInaccessibleMemory() { addFnAttr(Attribute::InaccessibleMemOnly); } /// Determine if the function may only access memory that is /// either inaccessible from the IR or pointed to by its arguments. bool onlyAccessesInaccessibleMemOrArgMem() const { return hasFnAttribute(Attribute::InaccessibleMemOrArgMemOnly); } void setOnlyAccessesInaccessibleMemOrArgMem() { addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); } /// Determine if the function cannot return. bool doesNotReturn() const { return hasFnAttribute(Attribute::NoReturn); } void setDoesNotReturn() { addFnAttr(Attribute::NoReturn); } /// Determine if the function should not perform indirect branch tracking. bool doesNoCfCheck() const { return hasFnAttribute(Attribute::NoCfCheck); } /// Determine if the function cannot unwind. bool doesNotThrow() const { return hasFnAttribute(Attribute::NoUnwind); } void setDoesNotThrow() { addFnAttr(Attribute::NoUnwind); } /// Determine if the call cannot be duplicated. bool cannotDuplicate() const { return hasFnAttribute(Attribute::NoDuplicate); } void setCannotDuplicate() { addFnAttr(Attribute::NoDuplicate); } /// Determine if the call is convergent. bool isConvergent() const { return hasFnAttribute(Attribute::Convergent); } void setConvergent() { addFnAttr(Attribute::Convergent); } void setNotConvergent() { removeFnAttr(Attribute::Convergent); } /// Determine if the call has sideeffects. bool isSpeculatable() const { return hasFnAttribute(Attribute::Speculatable); } void setSpeculatable() { addFnAttr(Attribute::Speculatable); } /// Determine if the function is known not to recurse, directly or /// indirectly. bool doesNotRecurse() const { return hasFnAttribute(Attribute::NoRecurse); } void setDoesNotRecurse() { addFnAttr(Attribute::NoRecurse); } /// True if the ABI mandates (or the user requested) that this /// function be in a unwind table. bool hasUWTable() const { return hasFnAttribute(Attribute::UWTable); } void setHasUWTable() { addFnAttr(Attribute::UWTable); } /// True if this function needs an unwind table. bool needsUnwindTableEntry() const { - return hasUWTable() || !doesNotThrow(); + return hasUWTable() || !doesNotThrow() || hasPersonalityFn(); } /// Determine if the function returns a structure through first /// or second pointer argument. bool hasStructRetAttr() const { return AttributeSets.hasParamAttribute(0, Attribute::StructRet) || AttributeSets.hasParamAttribute(1, Attribute::StructRet); } /// Determine if the parameter or return value is marked with NoAlias /// attribute. bool returnDoesNotAlias() const { return AttributeSets.hasAttribute(AttributeList::ReturnIndex, Attribute::NoAlias); } void setReturnDoesNotAlias() { addAttribute(AttributeList::ReturnIndex, Attribute::NoAlias); } /// Optimize this function for minimum size (-Oz). bool optForMinSize() const { return hasFnAttribute(Attribute::MinSize); } /// Optimize this function for size (-Os) or minimum size (-Oz). bool optForSize() const { return hasFnAttribute(Attribute::OptimizeForSize) || optForMinSize(); } /// copyAttributesFrom - copy all additional attributes (those not needed to /// create a Function) from the Function Src to this one. void copyAttributesFrom(const Function *Src); /// deleteBody - This method deletes the body of the function, and converts /// the linkage to external. /// void deleteBody() { dropAllReferences(); setLinkage(ExternalLinkage); } /// removeFromParent - This method unlinks 'this' from the containing module, /// but does not delete it. /// void removeFromParent(); /// eraseFromParent - This method unlinks 'this' from the containing module /// and deletes it. /// void eraseFromParent(); /// Steal arguments from another function. /// /// Drop this function's arguments and splice in the ones from \c Src. /// Requires that this has no function body. void stealArgumentListFrom(Function &Src); /// Get the underlying elements of the Function... the basic block list is /// empty for external functions. /// const BasicBlockListType &getBasicBlockList() const { return BasicBlocks; } BasicBlockListType &getBasicBlockList() { return BasicBlocks; } static BasicBlockListType Function::*getSublistAccess(BasicBlock*) { return &Function::BasicBlocks; } const BasicBlock &getEntryBlock() const { return front(); } BasicBlock &getEntryBlock() { return front(); } //===--------------------------------------------------------------------===// // Symbol Table Accessing functions... /// getSymbolTable() - Return the symbol table if any, otherwise nullptr. /// inline ValueSymbolTable *getValueSymbolTable() { return SymTab.get(); } inline const ValueSymbolTable *getValueSymbolTable() const { return SymTab.get(); } //===--------------------------------------------------------------------===// // BasicBlock iterator forwarding functions // iterator begin() { return BasicBlocks.begin(); } const_iterator begin() const { return BasicBlocks.begin(); } iterator end () { return BasicBlocks.end(); } const_iterator end () const { return BasicBlocks.end(); } size_t size() const { return BasicBlocks.size(); } bool empty() const { return BasicBlocks.empty(); } const BasicBlock &front() const { return BasicBlocks.front(); } BasicBlock &front() { return BasicBlocks.front(); } const BasicBlock &back() const { return BasicBlocks.back(); } BasicBlock &back() { return BasicBlocks.back(); } /// @name Function Argument Iteration /// @{ arg_iterator arg_begin() { CheckLazyArguments(); return Arguments; } const_arg_iterator arg_begin() const { CheckLazyArguments(); return Arguments; } arg_iterator arg_end() { CheckLazyArguments(); return Arguments + NumArgs; } const_arg_iterator arg_end() const { CheckLazyArguments(); return Arguments + NumArgs; } iterator_range args() { return make_range(arg_begin(), arg_end()); } iterator_range args() const { return make_range(arg_begin(), arg_end()); } /// @} size_t arg_size() const { return NumArgs; } bool arg_empty() const { return arg_size() == 0; } /// Check whether this function has a personality function. bool hasPersonalityFn() const { return getSubclassDataFromValue() & (1<<3); } /// Get the personality function associated with this function. Constant *getPersonalityFn() const; void setPersonalityFn(Constant *Fn); /// Check whether this function has prefix data. bool hasPrefixData() const { return getSubclassDataFromValue() & (1<<1); } /// Get the prefix data associated with this function. Constant *getPrefixData() const; void setPrefixData(Constant *PrefixData); /// Check whether this function has prologue data. bool hasPrologueData() const { return getSubclassDataFromValue() & (1<<2); } /// Get the prologue data associated with this function. Constant *getPrologueData() const; void setPrologueData(Constant *PrologueData); /// Print the function to an output stream with an optional /// AssemblyAnnotationWriter. void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW = nullptr, bool ShouldPreserveUseListOrder = false, bool IsForDebug = false) const; /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the /// program, displaying the CFG of the current function with the code for each /// basic block inside. This depends on there being a 'dot' and 'gv' program /// in your path. /// void viewCFG() const; /// viewCFGOnly - This function is meant for use from the debugger. It works /// just like viewCFG, but it does not include the contents of basic blocks /// into the nodes, just the label. If you are only interested in the CFG /// this can make the graph smaller. /// void viewCFGOnly() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Value *V) { return V->getValueID() == Value::FunctionVal; } /// dropAllReferences() - This method causes all the subinstructions to "let /// go" of all references that they are maintaining. This allows one to /// 'delete' a whole module at a time, even though there may be circular /// references... first all references are dropped, and all use counts go to /// zero. Then everything is deleted for real. Note that no operations are /// valid on an object that has "dropped all references", except operator /// delete. /// /// Since no other object in the module can have references into the body of a /// function, dropping all references deletes the entire body of the function, /// including any contained basic blocks. /// void dropAllReferences(); /// hasAddressTaken - returns true if there are any uses of this function /// other than direct calls or invokes to it, or blockaddress expressions. /// Optionally passes back an offending user for diagnostic purposes. /// bool hasAddressTaken(const User** = nullptr) const; /// isDefTriviallyDead - Return true if it is trivially safe to remove /// this function definition from the module (because it isn't externally /// visible, does not have its address taken, and has no callers). To make /// this more accurate, call removeDeadConstantUsers first. bool isDefTriviallyDead() const; /// callsFunctionThatReturnsTwice - Return true if the function has a call to /// setjmp or other function that gcc recognizes as "returning twice". bool callsFunctionThatReturnsTwice() const; /// Set the attached subprogram. /// /// Calls \a setMetadata() with \a LLVMContext::MD_dbg. void setSubprogram(DISubprogram *SP); /// Get the attached subprogram. /// /// Calls \a getMetadata() with \a LLVMContext::MD_dbg and casts the result /// to \a DISubprogram. DISubprogram *getSubprogram() const; /// Returns true if we should emit debug info for profiling. bool isDebugInfoForProfiling() const; /// Check if null pointer dereferencing is considered undefined behavior for /// the function. /// Return value: false => null pointer dereference is undefined. /// Return value: true => null pointer dereference is not undefined. bool nullPointerIsDefined() const; private: void allocHungoffUselist(); template void setHungoffOperand(Constant *C); /// Shadow Value::setValueSubclassData with a private forwarding method so /// that subclasses cannot accidentally use it. void setValueSubclassData(unsigned short D) { Value::setValueSubclassData(D); } void setValueSubclassDataBit(unsigned Bit, bool On); }; /// Check whether null pointer dereferencing is considered undefined behavior /// for a given function or an address space. /// Null pointer access in non-zero address space is not considered undefined. /// Return value: false => null pointer dereference is undefined. /// Return value: true => null pointer dereference is not undefined. bool NullPointerIsDefined(const Function *F, unsigned AS = 0); template <> struct OperandTraits : public HungoffOperandTraits<3> {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(Function, Value) } // end namespace llvm #endif // LLVM_IR_FUNCTION_H Index: vendor/llvm/dist-release_70/include/llvm/MC/MCExpr.h =================================================================== --- vendor/llvm/dist-release_70/include/llvm/MC/MCExpr.h (revision 338377) +++ vendor/llvm/dist-release_70/include/llvm/MC/MCExpr.h (revision 338378) @@ -1,606 +1,608 @@ //===- MCExpr.h - Assembly Level Expressions --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCEXPR_H #define LLVM_MC_MCEXPR_H #include "llvm/ADT/DenseMap.h" #include "llvm/Support/SMLoc.h" #include namespace llvm { class MCAsmInfo; class MCAsmLayout; class MCAssembler; class MCContext; class MCFixup; class MCFragment; class MCSection; class MCStreamer; class MCSymbol; class MCValue; class raw_ostream; class StringRef; using SectionAddrMap = DenseMap; /// Base class for the full range of assembler expressions which are /// needed for parsing. class MCExpr { public: enum ExprKind { Binary, ///< Binary expressions. Constant, ///< Constant expressions. SymbolRef, ///< References to labels and assigned expressions. Unary, ///< Unary expressions. Target ///< Target specific expression. }; private: ExprKind Kind; SMLoc Loc; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs) const; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet) const; protected: explicit MCExpr(ExprKind Kind, SMLoc Loc) : Kind(Kind), Loc(Loc) {} bool evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const MCFixup *Fixup, const SectionAddrMap *Addrs, bool InSet) const; public: MCExpr(const MCExpr &) = delete; MCExpr &operator=(const MCExpr &) = delete; /// \name Accessors /// @{ ExprKind getKind() const { return Kind; } SMLoc getLoc() const { return Loc; } /// @} /// \name Utility Methods /// @{ void print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens = false) const; void dump() const; /// @} /// \name Expression Evaluation /// @{ /// Try to evaluate the expression to an absolute value. /// /// \param Res - The absolute value, if evaluation succeeds. /// \param Layout - The assembler layout object to use for evaluating symbol /// values. If not given, then only non-symbolic expressions will be /// evaluated. /// \return - True on success. bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout, const SectionAddrMap &Addrs) const; bool evaluateAsAbsolute(int64_t &Res) const; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const; bool evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const; bool evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const; bool evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const; /// Try to evaluate the expression to a relocatable value, i.e. an /// expression of the fixed form (a - b + constant). /// /// \param Res - The relocatable value, if evaluation succeeds. /// \param Layout - The assembler layout object to use for evaluating values. /// \param Fixup - The Fixup object if available. /// \return - True on success. bool evaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const; /// Try to evaluate the expression to the form (a - b + constant) where /// neither a nor b are variables. /// /// This is a more aggressive variant of evaluateAsRelocatable. The intended /// use is for when relocations are not available, like the .size directive. bool evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const; /// Find the "associated section" for this expression, which is /// currently defined as the absolute section for constants, or /// otherwise the section associated with the first defined symbol in the /// expression. MCFragment *findAssociatedFragment() const; /// @} }; inline raw_ostream &operator<<(raw_ostream &OS, const MCExpr &E) { E.print(OS, nullptr); return OS; } //// Represent a constant integer expression. class MCConstantExpr : public MCExpr { int64_t Value; explicit MCConstantExpr(int64_t Value) : MCExpr(MCExpr::Constant, SMLoc()), Value(Value) {} public: /// \name Construction /// @{ static const MCConstantExpr *create(int64_t Value, MCContext &Ctx); /// @} /// \name Accessors /// @{ int64_t getValue() const { return Value; } /// @} static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Constant; } }; /// Represent a reference to a symbol from inside an expression. /// /// A symbol reference in an expression may be a use of a label, a use of an /// assembler variable (defined constant), or constitute an implicit definition /// of the symbol as external. class MCSymbolRefExpr : public MCExpr { public: enum VariantKind : uint16_t { VK_None, VK_Invalid, VK_GOT, VK_GOTOFF, VK_GOTREL, VK_GOTPCREL, VK_GOTTPOFF, VK_INDNTPOFF, VK_NTPOFF, VK_GOTNTPOFF, VK_PLT, VK_TLSGD, VK_TLSLD, VK_TLSLDM, VK_TPOFF, VK_DTPOFF, VK_TLSCALL, // symbol(tlscall) VK_TLSDESC, // symbol(tlsdesc) VK_TLVP, // Mach-O thread local variable relocations VK_TLVPPAGE, VK_TLVPPAGEOFF, VK_PAGE, VK_PAGEOFF, VK_GOTPAGE, VK_GOTPAGEOFF, VK_SECREL, VK_SIZE, // symbol@SIZE VK_WEAKREF, // The link between the symbols in .weakref foo, bar VK_X86_ABS8, VK_ARM_NONE, VK_ARM_GOT_PREL, VK_ARM_TARGET1, VK_ARM_TARGET2, VK_ARM_PREL31, VK_ARM_SBREL, // symbol(sbrel) VK_ARM_TLSLDO, // symbol(tlsldo) VK_ARM_TLSDESCSEQ, VK_AVR_NONE, VK_AVR_LO8, VK_AVR_HI8, VK_AVR_HLO8, VK_AVR_DIFF8, VK_AVR_DIFF16, VK_AVR_DIFF32, VK_PPC_LO, // symbol@l VK_PPC_HI, // symbol@h VK_PPC_HA, // symbol@ha VK_PPC_HIGH, // symbol@high VK_PPC_HIGHA, // symbol@higha VK_PPC_HIGHER, // symbol@higher VK_PPC_HIGHERA, // symbol@highera VK_PPC_HIGHEST, // symbol@highest VK_PPC_HIGHESTA, // symbol@highesta VK_PPC_GOT_LO, // symbol@got@l VK_PPC_GOT_HI, // symbol@got@h VK_PPC_GOT_HA, // symbol@got@ha VK_PPC_TOCBASE, // symbol@tocbase VK_PPC_TOC, // symbol@toc VK_PPC_TOC_LO, // symbol@toc@l VK_PPC_TOC_HI, // symbol@toc@h VK_PPC_TOC_HA, // symbol@toc@ha VK_PPC_DTPMOD, // symbol@dtpmod VK_PPC_TPREL_LO, // symbol@tprel@l VK_PPC_TPREL_HI, // symbol@tprel@h VK_PPC_TPREL_HA, // symbol@tprel@ha VK_PPC_TPREL_HIGH, // symbol@tprel@high VK_PPC_TPREL_HIGHA, // symbol@tprel@higha VK_PPC_TPREL_HIGHER, // symbol@tprel@higher VK_PPC_TPREL_HIGHERA, // symbol@tprel@highera VK_PPC_TPREL_HIGHEST, // symbol@tprel@highest VK_PPC_TPREL_HIGHESTA, // symbol@tprel@highesta VK_PPC_DTPREL_LO, // symbol@dtprel@l VK_PPC_DTPREL_HI, // symbol@dtprel@h VK_PPC_DTPREL_HA, // symbol@dtprel@ha VK_PPC_DTPREL_HIGH, // symbol@dtprel@high VK_PPC_DTPREL_HIGHA, // symbol@dtprel@higha VK_PPC_DTPREL_HIGHER, // symbol@dtprel@higher VK_PPC_DTPREL_HIGHERA, // symbol@dtprel@highera VK_PPC_DTPREL_HIGHEST, // symbol@dtprel@highest VK_PPC_DTPREL_HIGHESTA,// symbol@dtprel@highesta VK_PPC_GOT_TPREL, // symbol@got@tprel VK_PPC_GOT_TPREL_LO, // symbol@got@tprel@l VK_PPC_GOT_TPREL_HI, // symbol@got@tprel@h VK_PPC_GOT_TPREL_HA, // symbol@got@tprel@ha VK_PPC_GOT_DTPREL, // symbol@got@dtprel VK_PPC_GOT_DTPREL_LO, // symbol@got@dtprel@l VK_PPC_GOT_DTPREL_HI, // symbol@got@dtprel@h VK_PPC_GOT_DTPREL_HA, // symbol@got@dtprel@ha VK_PPC_TLS, // symbol@tls VK_PPC_GOT_TLSGD, // symbol@got@tlsgd VK_PPC_GOT_TLSGD_LO, // symbol@got@tlsgd@l VK_PPC_GOT_TLSGD_HI, // symbol@got@tlsgd@h VK_PPC_GOT_TLSGD_HA, // symbol@got@tlsgd@ha VK_PPC_TLSGD, // symbol@tlsgd VK_PPC_GOT_TLSLD, // symbol@got@tlsld VK_PPC_GOT_TLSLD_LO, // symbol@got@tlsld@l VK_PPC_GOT_TLSLD_HI, // symbol@got@tlsld@h VK_PPC_GOT_TLSLD_HA, // symbol@got@tlsld@ha VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local VK_COFF_IMGREL32, // symbol@imgrel (image-relative) VK_Hexagon_PCREL, VK_Hexagon_LO16, VK_Hexagon_HI16, VK_Hexagon_GPREL, VK_Hexagon_GD_GOT, VK_Hexagon_LD_GOT, VK_Hexagon_GD_PLT, VK_Hexagon_LD_PLT, VK_Hexagon_IE, VK_Hexagon_IE_GOT, VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr VK_WebAssembly_TYPEINDEX,// Type table index VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi VK_AMDGPU_REL32_LO, // symbol@rel32@lo VK_AMDGPU_REL32_HI, // symbol@rel32@hi VK_AMDGPU_REL64, // symbol@rel64 VK_TPREL, VK_DTPREL }; private: /// The symbol reference modifier. const VariantKind Kind; /// Specifies how the variant kind should be printed. const unsigned UseParensForSymbolVariant : 1; // FIXME: Remove this bit. const unsigned HasSubsectionsViaSymbols : 1; /// The symbol being referenced. const MCSymbol *Symbol; explicit MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind, const MCAsmInfo *MAI, SMLoc Loc = SMLoc()); public: /// \name Construction /// @{ static const MCSymbolRefExpr *create(const MCSymbol *Symbol, MCContext &Ctx) { return MCSymbolRefExpr::create(Symbol, VK_None, Ctx); } static const MCSymbolRefExpr *create(const MCSymbol *Symbol, VariantKind Kind, MCContext &Ctx, SMLoc Loc = SMLoc()); static const MCSymbolRefExpr *create(StringRef Name, VariantKind Kind, MCContext &Ctx); /// @} /// \name Accessors /// @{ const MCSymbol &getSymbol() const { return *Symbol; } VariantKind getKind() const { return Kind; } void printVariantKind(raw_ostream &OS) const; bool hasSubsectionsViaSymbols() const { return HasSubsectionsViaSymbols; } /// @} /// \name Static Utility Functions /// @{ static StringRef getVariantKindName(VariantKind Kind); static VariantKind getVariantKindForName(StringRef Name); /// @} static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::SymbolRef; } }; /// Unary assembler expressions. class MCUnaryExpr : public MCExpr { public: enum Opcode { LNot, ///< Logical negation. Minus, ///< Unary minus. Not, ///< Bitwise negation. Plus ///< Unary plus. }; private: Opcode Op; const MCExpr *Expr; MCUnaryExpr(Opcode Op, const MCExpr *Expr, SMLoc Loc) : MCExpr(MCExpr::Unary, Loc), Op(Op), Expr(Expr) {} public: /// \name Construction /// @{ static const MCUnaryExpr *create(Opcode Op, const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()); static const MCUnaryExpr *createLNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { return create(LNot, Expr, Ctx, Loc); } static const MCUnaryExpr *createMinus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { return create(Minus, Expr, Ctx, Loc); } static const MCUnaryExpr *createNot(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { return create(Not, Expr, Ctx, Loc); } static const MCUnaryExpr *createPlus(const MCExpr *Expr, MCContext &Ctx, SMLoc Loc = SMLoc()) { return create(Plus, Expr, Ctx, Loc); } /// @} /// \name Accessors /// @{ /// Get the kind of this unary expression. Opcode getOpcode() const { return Op; } /// Get the child of this unary expression. const MCExpr *getSubExpr() const { return Expr; } /// @} static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Unary; } }; /// Binary assembler expressions. class MCBinaryExpr : public MCExpr { public: enum Opcode { Add, ///< Addition. And, ///< Bitwise and. Div, ///< Signed division. EQ, ///< Equality comparison. GT, ///< Signed greater than comparison (result is either 0 or some ///< target-specific non-zero value) GTE, ///< Signed greater than or equal comparison (result is either 0 or ///< some target-specific non-zero value). LAnd, ///< Logical and. LOr, ///< Logical or. LT, ///< Signed less than comparison (result is either 0 or ///< some target-specific non-zero value). LTE, ///< Signed less than or equal comparison (result is either 0 or ///< some target-specific non-zero value). Mod, ///< Signed remainder. Mul, ///< Multiplication. NE, ///< Inequality comparison. Or, ///< Bitwise or. Shl, ///< Shift left. AShr, ///< Arithmetic shift right. LShr, ///< Logical shift right. Sub, ///< Subtraction. Xor ///< Bitwise exclusive or. }; private: Opcode Op; const MCExpr *LHS, *RHS; MCBinaryExpr(Opcode Op, const MCExpr *LHS, const MCExpr *RHS, SMLoc Loc = SMLoc()) : MCExpr(MCExpr::Binary, Loc), Op(Op), LHS(LHS), RHS(RHS) {} public: /// \name Construction /// @{ static const MCBinaryExpr *create(Opcode Op, const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc = SMLoc()); static const MCBinaryExpr *createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Add, LHS, RHS, Ctx); } static const MCBinaryExpr *createAnd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(And, LHS, RHS, Ctx); } static const MCBinaryExpr *createDiv(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Div, LHS, RHS, Ctx); } static const MCBinaryExpr *createEQ(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(EQ, LHS, RHS, Ctx); } static const MCBinaryExpr *createGT(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(GT, LHS, RHS, Ctx); } static const MCBinaryExpr *createGTE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(GTE, LHS, RHS, Ctx); } static const MCBinaryExpr *createLAnd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LAnd, LHS, RHS, Ctx); } static const MCBinaryExpr *createLOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LOr, LHS, RHS, Ctx); } static const MCBinaryExpr *createLT(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LT, LHS, RHS, Ctx); } static const MCBinaryExpr *createLTE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LTE, LHS, RHS, Ctx); } static const MCBinaryExpr *createMod(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Mod, LHS, RHS, Ctx); } static const MCBinaryExpr *createMul(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Mul, LHS, RHS, Ctx); } static const MCBinaryExpr *createNE(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(NE, LHS, RHS, Ctx); } static const MCBinaryExpr *createOr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Or, LHS, RHS, Ctx); } static const MCBinaryExpr *createShl(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Shl, LHS, RHS, Ctx); } static const MCBinaryExpr *createAShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(AShr, LHS, RHS, Ctx); } static const MCBinaryExpr *createLShr(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(LShr, LHS, RHS, Ctx); } static const MCBinaryExpr *createSub(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Sub, LHS, RHS, Ctx); } static const MCBinaryExpr *createXor(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx) { return create(Xor, LHS, RHS, Ctx); } /// @} /// \name Accessors /// @{ /// Get the kind of this binary expression. Opcode getOpcode() const { return Op; } /// Get the left-hand side expression of the binary operator. const MCExpr *getLHS() const { return LHS; } /// Get the right-hand side expression of the binary operator. const MCExpr *getRHS() const { return RHS; } /// @} static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Binary; } }; /// This is an extension point for target-specific MCExpr subclasses to /// implement. /// /// NOTE: All subclasses are required to have trivial destructors because /// MCExprs are bump pointer allocated and not destructed. class MCTargetExpr : public MCExpr { virtual void anchor(); protected: MCTargetExpr() : MCExpr(Target, SMLoc()) {} virtual ~MCTargetExpr() = default; public: virtual void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const = 0; virtual bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const = 0; + // allow Target Expressions to be checked for equality + virtual bool isEqualTo(const MCExpr *x) const { return false; } // This should be set when assigned expressions are not valid ".set" // expressions, e.g. registers, and must be inlined. virtual bool inlineAssignedExpr() const { return false; } virtual void visitUsedExpr(MCStreamer& Streamer) const = 0; virtual MCFragment *findAssociatedFragment() const = 0; virtual void fixELFSymbolsInTLSFixups(MCAssembler &) const = 0; static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; } }; } // end namespace llvm #endif // LLVM_MC_MCEXPR_H Index: vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCAsmParserUtils.h =================================================================== --- vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCAsmParserUtils.h (revision 338377) +++ vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCAsmParserUtils.h (revision 338378) @@ -1,34 +1,34 @@ //===- llvm/MC/MCAsmParserUtils.h - Asm Parser Utilities --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCPARSER_MCASMPARSERUTILS_H #define LLVM_MC_MCPARSER_MCASMPARSERUTILS_H namespace llvm { class MCAsmParser; class MCExpr; class MCSymbol; class StringRef; namespace MCParserUtils { /// Parse a value expression and return whether it can be assigned to a symbol /// with the given name. /// /// On success, returns false and sets the Symbol and Value output parameters. bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Symbol, - const MCExpr *&Value, bool AllowExtendedExpr = false); + const MCExpr *&Value); } // namespace MCParserUtils } // namespace llvm #endif // LLVM_MC_MCPARSER_MCASMPARSERUTILS_H Index: vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCTargetAsmParser.h =================================================================== --- vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCTargetAsmParser.h (revision 338377) +++ vendor/llvm/dist-release_70/include/llvm/MC/MCParser/MCTargetAsmParser.h (revision 338378) @@ -1,494 +1,494 @@ //===- llvm/MC/MCTargetAsmParser.h - Target Assembly Parser -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_MC_MCPARSER_MCTARGETASMPARSER_H #define LLVM_MC_MCPARSER_MCTARGETASMPARSER_H #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/SMLoc.h" #include #include namespace llvm { class MCInst; class MCParsedAsmOperand; class MCStreamer; class MCSubtargetInfo; template class SmallVectorImpl; using OperandVector = SmallVectorImpl>; enum AsmRewriteKind { AOK_Align, // Rewrite align as .align. AOK_EVEN, // Rewrite even as .even. AOK_Emit, // Rewrite _emit as .byte. AOK_Input, // Rewrite in terms of $N. AOK_Output, // Rewrite in terms of $N. AOK_SizeDirective, // Add a sizing directive (e.g., dword ptr). AOK_Label, // Rewrite local labels. AOK_EndOfStatement, // Add EndOfStatement (e.g., "\n\t"). AOK_Skip, // Skip emission (e.g., offset/type operators). AOK_IntelExpr // SizeDirective SymDisp [BaseReg + IndexReg * Scale + ImmDisp] }; const char AsmRewritePrecedence [] = { 2, // AOK_Align 2, // AOK_EVEN 2, // AOK_Emit 3, // AOK_Input 3, // AOK_Output 5, // AOK_SizeDirective 1, // AOK_Label 5, // AOK_EndOfStatement 2, // AOK_Skip 2 // AOK_IntelExpr }; // Represnt the various parts which makes up an intel expression, // used for emitting compound intel expressions struct IntelExpr { bool NeedBracs; int64_t Imm; StringRef BaseReg; StringRef IndexReg; unsigned Scale; IntelExpr(bool needBracs = false) : NeedBracs(needBracs), Imm(0), BaseReg(StringRef()), IndexReg(StringRef()), Scale(1) {} // Compund immediate expression IntelExpr(int64_t imm, bool needBracs) : IntelExpr(needBracs) { Imm = imm; } // [Reg + ImmediateExpression] // We don't bother to emit an immediate expression evaluated to zero IntelExpr(StringRef reg, int64_t imm = 0, unsigned scale = 0, bool needBracs = true) : IntelExpr(imm, needBracs) { IndexReg = reg; if (scale) Scale = scale; } // [BaseReg + IndexReg * ScaleExpression + ImmediateExpression] IntelExpr(StringRef baseReg, StringRef indexReg, unsigned scale = 0, int64_t imm = 0, bool needBracs = true) : IntelExpr(indexReg, imm, scale, needBracs) { BaseReg = baseReg; } bool hasBaseReg() const { return BaseReg.size(); } bool hasIndexReg() const { return IndexReg.size(); } bool hasRegs() const { return hasBaseReg() || hasIndexReg(); } bool isValid() const { return (Scale == 1) || (hasIndexReg() && (Scale == 2 || Scale == 4 || Scale == 8)); } }; struct AsmRewrite { AsmRewriteKind Kind; SMLoc Loc; unsigned Len; int64_t Val; StringRef Label; IntelExpr IntelExp; public: AsmRewrite(AsmRewriteKind kind, SMLoc loc, unsigned len = 0, int64_t val = 0) : Kind(kind), Loc(loc), Len(len), Val(val) {} AsmRewrite(AsmRewriteKind kind, SMLoc loc, unsigned len, StringRef label) : AsmRewrite(kind, loc, len) { Label = label; } AsmRewrite(SMLoc loc, unsigned len, IntelExpr exp) : AsmRewrite(AOK_IntelExpr, loc, len) { IntelExp = exp; } }; struct ParseInstructionInfo { SmallVectorImpl *AsmRewrites = nullptr; ParseInstructionInfo() = default; ParseInstructionInfo(SmallVectorImpl *rewrites) : AsmRewrites(rewrites) {} }; enum OperandMatchResultTy { MatchOperand_Success, // operand matched successfully MatchOperand_NoMatch, // operand did not match MatchOperand_ParseFail // operand matched but had errors }; enum class DiagnosticPredicateTy { Match, NearMatch, NoMatch, }; // When an operand is parsed, the assembler will try to iterate through a set of // possible operand classes that the operand might match and call the // corresponding PredicateMethod to determine that. // // If there are two AsmOperands that would give a specific diagnostic if there // is no match, there is currently no mechanism to distinguish which operand is // a closer match. The DiagnosticPredicate distinguishes between 'completely // no match' and 'near match', so the assembler can decide whether to give a // specific diagnostic, or use 'InvalidOperand' and continue to find a // 'better matching' diagnostic. // // For example: // opcode opnd0, onpd1, opnd2 // // where: // opnd2 could be an 'immediate of range [-8, 7]' // opnd2 could be a 'register + shift/extend'. // // If opnd2 is a valid register, but with a wrong shift/extend suffix, it makes // little sense to give a diagnostic that the operand should be an immediate // in range [-8, 7]. // // This is a light-weight alternative to the 'NearMissInfo' approach // below which collects *all* possible diagnostics. This alternative // is optional and fully backward compatible with existing // PredicateMethods that return a 'bool' (match or no match). struct DiagnosticPredicate { DiagnosticPredicateTy Type; explicit DiagnosticPredicate(bool Match) : Type(Match ? DiagnosticPredicateTy::Match : DiagnosticPredicateTy::NearMatch) {} DiagnosticPredicate(DiagnosticPredicateTy T) : Type(T) {} DiagnosticPredicate(const DiagnosticPredicate &) = default; operator bool() const { return Type == DiagnosticPredicateTy::Match; } bool isMatch() const { return Type == DiagnosticPredicateTy::Match; } bool isNearMatch() const { return Type == DiagnosticPredicateTy::NearMatch; } bool isNoMatch() const { return Type == DiagnosticPredicateTy::NoMatch; } }; // When matching of an assembly instruction fails, there may be multiple // encodings that are close to being a match. It's often ambiguous which one // the programmer intended to use, so we want to report an error which mentions // each of these "near-miss" encodings. This struct contains information about // one such encoding, and why it did not match the parsed instruction. class NearMissInfo { public: enum NearMissKind { NoNearMiss, NearMissOperand, NearMissFeature, NearMissPredicate, NearMissTooFewOperands, }; // The encoding is valid for the parsed assembly string. This is only used // internally to the table-generated assembly matcher. static NearMissInfo getSuccess() { return NearMissInfo(); } // The instruction encoding is not valid because it requires some target // features that are not currently enabled. MissingFeatures has a bit set for // each feature that the encoding needs but which is not enabled. static NearMissInfo getMissedFeature(uint64_t MissingFeatures) { NearMissInfo Result; Result.Kind = NearMissFeature; Result.Features = MissingFeatures; return Result; } // The instruction encoding is not valid because the target-specific // predicate function returned an error code. FailureCode is the // target-specific error code returned by the predicate. static NearMissInfo getMissedPredicate(unsigned FailureCode) { NearMissInfo Result; Result.Kind = NearMissPredicate; Result.PredicateError = FailureCode; return Result; } // The instruction encoding is not valid because one (and only one) parsed // operand is not of the correct type. OperandError is the error code // relating to the operand class expected by the encoding. OperandClass is // the type of the expected operand. Opcode is the opcode of the encoding. // OperandIndex is the index into the parsed operand list. static NearMissInfo getMissedOperand(unsigned OperandError, unsigned OperandClass, unsigned Opcode, unsigned OperandIndex) { NearMissInfo Result; Result.Kind = NearMissOperand; Result.MissedOperand.Error = OperandError; Result.MissedOperand.Class = OperandClass; Result.MissedOperand.Opcode = Opcode; Result.MissedOperand.Index = OperandIndex; return Result; } // The instruction encoding is not valid because it expects more operands // than were parsed. OperandClass is the class of the expected operand that // was not provided. Opcode is the instruction encoding. static NearMissInfo getTooFewOperands(unsigned OperandClass, unsigned Opcode) { NearMissInfo Result; Result.Kind = NearMissTooFewOperands; Result.TooFewOperands.Class = OperandClass; Result.TooFewOperands.Opcode = Opcode; return Result; } operator bool() const { return Kind != NoNearMiss; } NearMissKind getKind() const { return Kind; } // Feature flags required by the instruction, that the current target does // not have. uint64_t getFeatures() const { assert(Kind == NearMissFeature); return Features; } // Error code returned by the target predicate when validating this // instruction encoding. unsigned getPredicateError() const { assert(Kind == NearMissPredicate); return PredicateError; } // MatchClassKind of the operand that we expected to see. unsigned getOperandClass() const { assert(Kind == NearMissOperand || Kind == NearMissTooFewOperands); return MissedOperand.Class; } // Opcode of the encoding we were trying to match. unsigned getOpcode() const { assert(Kind == NearMissOperand || Kind == NearMissTooFewOperands); return MissedOperand.Opcode; } // Error code returned when validating the operand. unsigned getOperandError() const { assert(Kind == NearMissOperand); return MissedOperand.Error; } // Index of the actual operand we were trying to match in the list of parsed // operands. unsigned getOperandIndex() const { assert(Kind == NearMissOperand); return MissedOperand.Index; } private: NearMissKind Kind; // These two structs share a common prefix, so we can safely rely on the fact // that they overlap in the union. struct MissedOpInfo { unsigned Class; unsigned Opcode; unsigned Error; unsigned Index; }; struct TooFewOperandsInfo { unsigned Class; unsigned Opcode; }; union { uint64_t Features; unsigned PredicateError; MissedOpInfo MissedOperand; TooFewOperandsInfo TooFewOperands; }; NearMissInfo() : Kind(NoNearMiss) {} }; /// MCTargetAsmParser - Generic interface to target specific assembly parsers. class MCTargetAsmParser : public MCAsmParserExtension { public: enum MatchResultTy { Match_InvalidOperand, Match_InvalidTiedOperand, Match_MissingFeature, Match_MnemonicFail, Match_Success, Match_NearMisses, FIRST_TARGET_MATCH_RESULT_TY }; protected: // Can only create subclasses. MCTargetAsmParser(MCTargetOptions const &, const MCSubtargetInfo &STI, const MCInstrInfo &MII); /// Create a copy of STI and return a non-const reference to it. MCSubtargetInfo ©STI(); /// AvailableFeatures - The current set of available features. uint64_t AvailableFeatures = 0; /// ParsingInlineAsm - Are we parsing ms-style inline assembly? bool ParsingInlineAsm = false; /// SemaCallback - The Sema callback implementation. Must be set when parsing /// ms-style inline assembly. MCAsmParserSemaCallback *SemaCallback; /// Set of options which affects instrumentation of inline assembly. MCTargetOptions MCOptions; /// Current STI. const MCSubtargetInfo *STI; const MCInstrInfo &MII; public: MCTargetAsmParser(const MCTargetAsmParser &) = delete; MCTargetAsmParser &operator=(const MCTargetAsmParser &) = delete; ~MCTargetAsmParser() override; const MCSubtargetInfo &getSTI() const; uint64_t getAvailableFeatures() const { return AvailableFeatures; } void setAvailableFeatures(uint64_t Value) { AvailableFeatures = Value; } bool isParsingInlineAsm () { return ParsingInlineAsm; } void setParsingInlineAsm (bool Value) { ParsingInlineAsm = Value; } MCTargetOptions getTargetOptions() const { return MCOptions; } void setSemaCallback(MCAsmParserSemaCallback *Callback) { SemaCallback = Callback; } - // Target-specific parsing of assembler-level variable assignment. - virtual bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) { - return getParser().parseExpression(Res, EndLoc); + // Target-specific parsing of expression. + virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { + return getParser().parsePrimaryExpr(Res, EndLoc); } virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) = 0; /// Sets frame register corresponding to the current MachineFunction. virtual void SetFrameRegister(unsigned RegNo) {} /// ParseInstruction - Parse one assembly instruction. /// /// The parser is positioned following the instruction name. The target /// specific instruction parser should parse the entire instruction and /// construct the appropriate MCInst, or emit an error. On success, the entire /// line should be parsed up to and including the end-of-statement token. On /// failure, the parser is not required to read to the end of the line. // /// \param Name - The instruction name. /// \param NameLoc - The source location of the name. /// \param Operands [out] - The list of parsed operands, this returns /// ownership of them to the caller. /// \return True on failure. virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) = 0; virtual bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, AsmToken Token, OperandVector &Operands) { return ParseInstruction(Info, Name, Token.getLoc(), Operands); } /// ParseDirective - Parse a target specific assembler directive /// /// The parser is positioned following the directive name. The target /// specific directive parser should parse the entire directive doing or /// recording any target specific work, or return true and do nothing if the /// directive is not target specific. If the directive is specific for /// the target, the entire line is parsed up to and including the /// end-of-statement token and false is returned. /// /// \param DirectiveID - the identifier token of the directive. virtual bool ParseDirective(AsmToken DirectiveID) = 0; /// MatchAndEmitInstruction - Recognize a series of operands of a parsed /// instruction as an actual MCInst and emit it to the specified MCStreamer. /// This returns false on success and returns true on failure to match. /// /// On failure, the target parser is responsible for emitting a diagnostic /// explaining the match failure. virtual bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) = 0; /// Allows targets to let registers opt out of clobber lists. virtual bool OmitRegisterFromClobberLists(unsigned RegNo) { return false; } /// Allow a target to add special case operand matching for things that /// tblgen doesn't/can't handle effectively. For example, literal /// immediates on ARM. TableGen expects a token operand, but the parser /// will recognize them as immediates. virtual unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) { return Match_InvalidOperand; } /// Validate the instruction match against any complex target predicates /// before rendering any operands to it. virtual unsigned checkEarlyTargetMatchPredicate(MCInst &Inst, const OperandVector &Operands) { return Match_Success; } /// checkTargetMatchPredicate - Validate the instruction match against /// any complex target predicates not expressible via match classes. virtual unsigned checkTargetMatchPredicate(MCInst &Inst) { return Match_Success; } virtual void convertToMapAndConstraints(unsigned Kind, const OperandVector &Operands) = 0; /// Returns whether two registers are equal and is used by the tied-operands /// checks in the AsmMatcher. This method can be overridden allow e.g. a /// sub- or super-register as the tied operand. virtual bool regsEqual(const MCParsedAsmOperand &Op1, const MCParsedAsmOperand &Op2) const { assert(Op1.isReg() && Op2.isReg() && "Operands not all regs"); return Op1.getReg() == Op2.getReg(); } // Return whether this parser uses assignment statements with equals tokens virtual bool equalIsAsmAssignment() { return true; }; // Return whether this start of statement identifier is a label virtual bool isLabel(AsmToken &Token) { return true; }; // Return whether this parser accept star as start of statement virtual bool starIsStartOfStatement() { return false; }; virtual const MCExpr *applyModifierToExpr(const MCExpr *E, MCSymbolRefExpr::VariantKind, MCContext &Ctx) { return nullptr; } virtual void onLabelParsed(MCSymbol *Symbol) {} /// Ensure that all previously parsed instructions have been emitted to the /// output streamer, if the target does not emit them immediately. virtual void flushPendingInstructions(MCStreamer &Out) {} virtual const MCExpr *createTargetUnaryExpr(const MCExpr *E, AsmToken::TokenKind OperatorToken, MCContext &Ctx) { return nullptr; } }; } // end namespace llvm #endif // LLVM_MC_MCPARSER_MCTARGETASMPARSER_H Index: vendor/llvm/dist-release_70/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/CodeGen/CodeGenPrepare.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/CodeGen/CodeGenPrepare.cpp (revision 338378) @@ -1,6887 +1,6929 @@ //===- CodeGenPrepare.cpp - Prepare a function for code generation --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This pass munges the code in the input function to better prepare it for // SelectionDAG-based code generation. This works around limitations in it's // basic-block-at-a-time approach. It should eventually be removed. // //===----------------------------------------------------------------------===// #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Statepoint.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/ValueMap.h" #include "llvm/Pass.h" #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/BranchProbability.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MachineValueType.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/BypassSlowDivision.h" #include "llvm/Transforms/Utils/SimplifyLibCalls.h" #include #include #include #include #include #include #include #include using namespace llvm; using namespace llvm::PatternMatch; #define DEBUG_TYPE "codegenprepare" STATISTIC(NumBlocksElim, "Number of blocks eliminated"); STATISTIC(NumPHIsElim, "Number of trivial PHIs eliminated"); STATISTIC(NumGEPsElim, "Number of GEPs converted to casts"); STATISTIC(NumCmpUses, "Number of uses of Cmp expressions replaced with uses of " "sunken Cmps"); STATISTIC(NumCastUses, "Number of uses of Cast expressions replaced with uses " "of sunken Casts"); STATISTIC(NumMemoryInsts, "Number of memory instructions whose address " "computations were sunk"); STATISTIC(NumMemoryInstsPhiCreated, "Number of phis created when address " "computations were sunk to memory instructions"); STATISTIC(NumMemoryInstsSelectCreated, "Number of select created when address " "computations were sunk to memory instructions"); STATISTIC(NumExtsMoved, "Number of [s|z]ext instructions combined with loads"); STATISTIC(NumExtUses, "Number of uses of [s|z]ext instructions optimized"); STATISTIC(NumAndsAdded, "Number of and mask instructions added to form ext loads"); STATISTIC(NumAndUses, "Number of uses of and mask instructions optimized"); STATISTIC(NumRetsDup, "Number of return instructions duplicated"); STATISTIC(NumDbgValueMoved, "Number of debug value instructions moved"); STATISTIC(NumSelectsExpanded, "Number of selects turned into branches"); STATISTIC(NumStoreExtractExposed, "Number of store(extractelement) exposed"); static cl::opt DisableBranchOpts( "disable-cgp-branch-opts", cl::Hidden, cl::init(false), cl::desc("Disable branch optimizations in CodeGenPrepare")); static cl::opt DisableGCOpts("disable-cgp-gc-opts", cl::Hidden, cl::init(false), cl::desc("Disable GC optimizations in CodeGenPrepare")); static cl::opt DisableSelectToBranch( "disable-cgp-select2branch", cl::Hidden, cl::init(false), cl::desc("Disable select to branch conversion.")); static cl::opt AddrSinkUsingGEPs( "addr-sink-using-gep", cl::Hidden, cl::init(true), cl::desc("Address sinking in CGP using GEPs.")); static cl::opt EnableAndCmpSinking( "enable-andcmp-sinking", cl::Hidden, cl::init(true), cl::desc("Enable sinkinig and/cmp into branches.")); static cl::opt DisableStoreExtract( "disable-cgp-store-extract", cl::Hidden, cl::init(false), cl::desc("Disable store(extract) optimizations in CodeGenPrepare")); static cl::opt StressStoreExtract( "stress-cgp-store-extract", cl::Hidden, cl::init(false), cl::desc("Stress test store(extract) optimizations in CodeGenPrepare")); static cl::opt DisableExtLdPromotion( "disable-cgp-ext-ld-promotion", cl::Hidden, cl::init(false), cl::desc("Disable ext(promotable(ld)) -> promoted(ext(ld)) optimization in " "CodeGenPrepare")); static cl::opt StressExtLdPromotion( "stress-cgp-ext-ld-promotion", cl::Hidden, cl::init(false), cl::desc("Stress test ext(promotable(ld)) -> promoted(ext(ld)) " "optimization in CodeGenPrepare")); static cl::opt DisablePreheaderProtect( "disable-preheader-prot", cl::Hidden, cl::init(false), cl::desc("Disable protection against removing loop preheaders")); static cl::opt ProfileGuidedSectionPrefix( "profile-guided-section-prefix", cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::desc("Use profile info to add section prefix for hot/cold functions")); static cl::opt FreqRatioToSkipMerge( "cgp-freq-ratio-to-skip-merge", cl::Hidden, cl::init(2), cl::desc("Skip merging empty blocks if (frequency of empty block) / " "(frequency of destination block) is greater than this ratio")); static cl::opt ForceSplitStore( "force-split-store", cl::Hidden, cl::init(false), cl::desc("Force store splitting no matter what the target query says.")); static cl::opt EnableTypePromotionMerge("cgp-type-promotion-merge", cl::Hidden, cl::desc("Enable merging of redundant sexts when one is dominating" " the other."), cl::init(true)); static cl::opt DisableComplexAddrModes( "disable-complex-addr-modes", cl::Hidden, cl::init(false), cl::desc("Disables combining addressing modes with different parts " "in optimizeMemoryInst.")); static cl::opt AddrSinkNewPhis("addr-sink-new-phis", cl::Hidden, cl::init(false), cl::desc("Allow creation of Phis in Address sinking.")); static cl::opt AddrSinkNewSelects("addr-sink-new-select", cl::Hidden, cl::init(true), cl::desc("Allow creation of selects in Address sinking.")); static cl::opt AddrSinkCombineBaseReg( "addr-sink-combine-base-reg", cl::Hidden, cl::init(true), cl::desc("Allow combining of BaseReg field in Address sinking.")); static cl::opt AddrSinkCombineBaseGV( "addr-sink-combine-base-gv", cl::Hidden, cl::init(true), cl::desc("Allow combining of BaseGV field in Address sinking.")); static cl::opt AddrSinkCombineBaseOffs( "addr-sink-combine-base-offs", cl::Hidden, cl::init(true), cl::desc("Allow combining of BaseOffs field in Address sinking.")); static cl::opt AddrSinkCombineScaledReg( "addr-sink-combine-scaled-reg", cl::Hidden, cl::init(true), cl::desc("Allow combining of ScaledReg field in Address sinking.")); static cl::opt EnableGEPOffsetSplit("cgp-split-large-offset-gep", cl::Hidden, cl::init(true), cl::desc("Enable splitting large offset of GEP.")); namespace { +enum ExtType { + ZeroExtension, // Zero extension has been seen. + SignExtension, // Sign extension has been seen. + BothExtension // This extension type is used if we saw sext after + // ZeroExtension had been set, or if we saw zext after + // SignExtension had been set. It makes the type + // information of a promoted instruction invalid. +}; + using SetOfInstrs = SmallPtrSet; -using TypeIsSExt = PointerIntPair; +using TypeIsSExt = PointerIntPair; using InstrToOrigTy = DenseMap; using SExts = SmallVector; using ValueToSExts = DenseMap; class TypePromotionTransaction; class CodeGenPrepare : public FunctionPass { const TargetMachine *TM = nullptr; const TargetSubtargetInfo *SubtargetInfo; const TargetLowering *TLI = nullptr; const TargetRegisterInfo *TRI; const TargetTransformInfo *TTI = nullptr; const TargetLibraryInfo *TLInfo; const LoopInfo *LI; std::unique_ptr BFI; std::unique_ptr BPI; /// As we scan instructions optimizing them, this is the next instruction /// to optimize. Transforms that can invalidate this should update it. BasicBlock::iterator CurInstIterator; /// Keeps track of non-local addresses that have been sunk into a block. /// This allows us to avoid inserting duplicate code for blocks with /// multiple load/stores of the same address. The usage of WeakTrackingVH /// enables SunkAddrs to be treated as a cache whose entries can be /// invalidated if a sunken address computation has been erased. ValueMap SunkAddrs; /// Keeps track of all instructions inserted for the current function. SetOfInstrs InsertedInsts; /// Keeps track of the type of the related instruction before their /// promotion for the current function. InstrToOrigTy PromotedInsts; /// Keep track of instructions removed during promotion. SetOfInstrs RemovedInsts; /// Keep track of sext chains based on their initial value. DenseMap SeenChainsForSExt; /// Keep track of GEPs accessing the same data structures such as structs or /// arrays that are candidates to be split later because of their large /// size. DenseMap< AssertingVH, SmallVector, int64_t>, 32>> LargeOffsetGEPMap; /// Keep track of new GEP base after splitting the GEPs having large offset. SmallSet, 2> NewGEPBases; /// Map serial numbers to Large offset GEPs. DenseMap, int> LargeOffsetGEPID; /// Keep track of SExt promoted. ValueToSExts ValToSExtendedUses; /// True if CFG is modified in any way. bool ModifiedDT; /// True if optimizing for size. bool OptSize; /// DataLayout for the Function being processed. const DataLayout *DL = nullptr; public: static char ID; // Pass identification, replacement for typeid CodeGenPrepare() : FunctionPass(ID) { initializeCodeGenPreparePass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override; StringRef getPassName() const override { return "CodeGen Prepare"; } void getAnalysisUsage(AnalysisUsage &AU) const override { // FIXME: When we can selectively preserve passes, preserve the domtree. AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addRequired(); } private: bool eliminateFallThrough(Function &F); bool eliminateMostlyEmptyBlocks(Function &F); BasicBlock *findDestBlockOfMergeableEmptyBlock(BasicBlock *BB); bool canMergeBlocks(const BasicBlock *BB, const BasicBlock *DestBB) const; void eliminateMostlyEmptyBlock(BasicBlock *BB); bool isMergingEmptyBlockProfitable(BasicBlock *BB, BasicBlock *DestBB, bool isPreheader); bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT); bool optimizeInst(Instruction *I, bool &ModifiedDT); bool optimizeMemoryInst(Instruction *MemoryInst, Value *Addr, Type *AccessTy, unsigned AddrSpace); bool optimizeInlineAsmInst(CallInst *CS); bool optimizeCallInst(CallInst *CI, bool &ModifiedDT); bool optimizeExt(Instruction *&I); bool optimizeExtUses(Instruction *I); bool optimizeLoadExt(LoadInst *Load); bool optimizeSelectInst(SelectInst *SI); bool optimizeShuffleVectorInst(ShuffleVectorInst *SVI); bool optimizeSwitchInst(SwitchInst *SI); bool optimizeExtractElementInst(Instruction *Inst); bool dupRetToEnableTailCallOpts(BasicBlock *BB); bool placeDbgValues(Function &F); bool canFormExtLd(const SmallVectorImpl &MovedExts, LoadInst *&LI, Instruction *&Inst, bool HasPromoted); bool tryToPromoteExts(TypePromotionTransaction &TPT, const SmallVectorImpl &Exts, SmallVectorImpl &ProfitablyMovedExts, unsigned CreatedInstsCost = 0); bool mergeSExts(Function &F); bool splitLargeGEPOffsets(); bool performAddressTypePromotion( Instruction *&Inst, bool AllowPromotionWithoutCommonHeader, bool HasPromoted, TypePromotionTransaction &TPT, SmallVectorImpl &SpeculativelyMovedExts); bool splitBranchCondition(Function &F); bool simplifyOffsetableRelocate(Instruction &I); }; } // end anonymous namespace char CodeGenPrepare::ID = 0; INITIALIZE_PASS_BEGIN(CodeGenPrepare, DEBUG_TYPE, "Optimize for code generation", false, false) INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) INITIALIZE_PASS_END(CodeGenPrepare, DEBUG_TYPE, "Optimize for code generation", false, false) FunctionPass *llvm::createCodeGenPreparePass() { return new CodeGenPrepare(); } bool CodeGenPrepare::runOnFunction(Function &F) { if (skipFunction(F)) return false; DL = &F.getParent()->getDataLayout(); bool EverMadeChange = false; // Clear per function information. InsertedInsts.clear(); PromotedInsts.clear(); ModifiedDT = false; if (auto *TPC = getAnalysisIfAvailable()) { TM = &TPC->getTM(); SubtargetInfo = TM->getSubtargetImpl(F); TLI = SubtargetInfo->getTargetLowering(); TRI = SubtargetInfo->getRegisterInfo(); } TLInfo = &getAnalysis().getTLI(); TTI = &getAnalysis().getTTI(F); LI = &getAnalysis().getLoopInfo(); BPI.reset(new BranchProbabilityInfo(F, *LI)); BFI.reset(new BlockFrequencyInfo(F, *BPI, *LI)); OptSize = F.optForSize(); ProfileSummaryInfo *PSI = getAnalysis().getPSI(); if (ProfileGuidedSectionPrefix) { if (PSI->isFunctionHotInCallGraph(&F, *BFI)) F.setSectionPrefix(".hot"); else if (PSI->isFunctionColdInCallGraph(&F, *BFI)) F.setSectionPrefix(".unlikely"); } /// This optimization identifies DIV instructions that can be /// profitably bypassed and carried out with a shorter, faster divide. if (!OptSize && !PSI->hasHugeWorkingSetSize() && TLI && TLI->isSlowDivBypassed()) { const DenseMap &BypassWidths = TLI->getBypassSlowDivWidths(); BasicBlock* BB = &*F.begin(); while (BB != nullptr) { // bypassSlowDivision may create new BBs, but we don't want to reapply the // optimization to those blocks. BasicBlock* Next = BB->getNextNode(); EverMadeChange |= bypassSlowDivision(BB, BypassWidths); BB = Next; } } // Eliminate blocks that contain only PHI nodes and an // unconditional branch. EverMadeChange |= eliminateMostlyEmptyBlocks(F); // llvm.dbg.value is far away from the value then iSel may not be able // handle it properly. iSel will drop llvm.dbg.value if it can not // find a node corresponding to the value. EverMadeChange |= placeDbgValues(F); if (!DisableBranchOpts) EverMadeChange |= splitBranchCondition(F); // Split some critical edges where one of the sources is an indirect branch, // to help generate sane code for PHIs involving such edges. EverMadeChange |= SplitIndirectBrCriticalEdges(F); bool MadeChange = true; while (MadeChange) { MadeChange = false; SeenChainsForSExt.clear(); ValToSExtendedUses.clear(); RemovedInsts.clear(); LargeOffsetGEPMap.clear(); LargeOffsetGEPID.clear(); for (Function::iterator I = F.begin(); I != F.end(); ) { BasicBlock *BB = &*I++; bool ModifiedDTOnIteration = false; MadeChange |= optimizeBlock(*BB, ModifiedDTOnIteration); // Restart BB iteration if the dominator tree of the Function was changed if (ModifiedDTOnIteration) break; } if (EnableTypePromotionMerge && !ValToSExtendedUses.empty()) MadeChange |= mergeSExts(F); if (!LargeOffsetGEPMap.empty()) MadeChange |= splitLargeGEPOffsets(); // Really free removed instructions during promotion. for (Instruction *I : RemovedInsts) I->deleteValue(); EverMadeChange |= MadeChange; } SunkAddrs.clear(); if (!DisableBranchOpts) { MadeChange = false; // Use a set vector to get deterministic iteration order. The order the // blocks are removed may affect whether or not PHI nodes in successors // are removed. SmallSetVector WorkList; for (BasicBlock &BB : F) { SmallVector Successors(succ_begin(&BB), succ_end(&BB)); MadeChange |= ConstantFoldTerminator(&BB, true); if (!MadeChange) continue; for (SmallVectorImpl::iterator II = Successors.begin(), IE = Successors.end(); II != IE; ++II) if (pred_begin(*II) == pred_end(*II)) WorkList.insert(*II); } // Delete the dead blocks and any of their dead successors. MadeChange |= !WorkList.empty(); while (!WorkList.empty()) { BasicBlock *BB = WorkList.pop_back_val(); SmallVector Successors(succ_begin(BB), succ_end(BB)); DeleteDeadBlock(BB); for (SmallVectorImpl::iterator II = Successors.begin(), IE = Successors.end(); II != IE; ++II) if (pred_begin(*II) == pred_end(*II)) WorkList.insert(*II); } // Merge pairs of basic blocks with unconditional branches, connected by // a single edge. if (EverMadeChange || MadeChange) MadeChange |= eliminateFallThrough(F); EverMadeChange |= MadeChange; } if (!DisableGCOpts) { SmallVector Statepoints; for (BasicBlock &BB : F) for (Instruction &I : BB) if (isStatepoint(I)) Statepoints.push_back(&I); for (auto &I : Statepoints) EverMadeChange |= simplifyOffsetableRelocate(*I); } return EverMadeChange; } /// Merge basic blocks which are connected by a single edge, where one of the /// basic blocks has a single successor pointing to the other basic block, /// which has a single predecessor. bool CodeGenPrepare::eliminateFallThrough(Function &F) { bool Changed = false; // Scan all of the blocks in the function, except for the entry block. // Use a temporary array to avoid iterator being invalidated when // deleting blocks. SmallVector Blocks; for (auto &Block : llvm::make_range(std::next(F.begin()), F.end())) Blocks.push_back(&Block); for (auto &Block : Blocks) { auto *BB = cast_or_null(Block); if (!BB) continue; // If the destination block has a single pred, then this is a trivial // edge, just collapse it. BasicBlock *SinglePred = BB->getSinglePredecessor(); // Don't merge if BB's address is taken. if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue; BranchInst *Term = dyn_cast(SinglePred->getTerminator()); if (Term && !Term->isConditional()) { Changed = true; LLVM_DEBUG(dbgs() << "To merge:\n" << *BB << "\n\n\n"); // Merge BB into SinglePred and delete it. MergeBlockIntoPredecessor(BB); } } return Changed; } /// Find a destination block from BB if BB is mergeable empty block. BasicBlock *CodeGenPrepare::findDestBlockOfMergeableEmptyBlock(BasicBlock *BB) { // If this block doesn't end with an uncond branch, ignore it. BranchInst *BI = dyn_cast(BB->getTerminator()); if (!BI || !BI->isUnconditional()) return nullptr; // If the instruction before the branch (skipping debug info) isn't a phi // node, then other stuff is happening here. BasicBlock::iterator BBI = BI->getIterator(); if (BBI != BB->begin()) { --BBI; while (isa(BBI)) { if (BBI == BB->begin()) break; --BBI; } if (!isa(BBI) && !isa(BBI)) return nullptr; } // Do not break infinite loops. BasicBlock *DestBB = BI->getSuccessor(0); if (DestBB == BB) return nullptr; if (!canMergeBlocks(BB, DestBB)) DestBB = nullptr; return DestBB; } /// Eliminate blocks that contain only PHI nodes, debug info directives, and an /// unconditional branch. Passes before isel (e.g. LSR/loopsimplify) often split /// edges in ways that are non-optimal for isel. Start by eliminating these /// blocks so we can split them the way we want them. bool CodeGenPrepare::eliminateMostlyEmptyBlocks(Function &F) { SmallPtrSet Preheaders; SmallVector LoopList(LI->begin(), LI->end()); while (!LoopList.empty()) { Loop *L = LoopList.pop_back_val(); LoopList.insert(LoopList.end(), L->begin(), L->end()); if (BasicBlock *Preheader = L->getLoopPreheader()) Preheaders.insert(Preheader); } bool MadeChange = false; // Copy blocks into a temporary array to avoid iterator invalidation issues // as we remove them. // Note that this intentionally skips the entry block. SmallVector Blocks; for (auto &Block : llvm::make_range(std::next(F.begin()), F.end())) Blocks.push_back(&Block); for (auto &Block : Blocks) { BasicBlock *BB = cast_or_null(Block); if (!BB) continue; BasicBlock *DestBB = findDestBlockOfMergeableEmptyBlock(BB); if (!DestBB || !isMergingEmptyBlockProfitable(BB, DestBB, Preheaders.count(BB))) continue; eliminateMostlyEmptyBlock(BB); MadeChange = true; } return MadeChange; } bool CodeGenPrepare::isMergingEmptyBlockProfitable(BasicBlock *BB, BasicBlock *DestBB, bool isPreheader) { // Do not delete loop preheaders if doing so would create a critical edge. // Loop preheaders can be good locations to spill registers. If the // preheader is deleted and we create a critical edge, registers may be // spilled in the loop body instead. if (!DisablePreheaderProtect && isPreheader && !(BB->getSinglePredecessor() && BB->getSinglePredecessor()->getSingleSuccessor())) return false; // Try to skip merging if the unique predecessor of BB is terminated by a // switch or indirect branch instruction, and BB is used as an incoming block // of PHIs in DestBB. In such case, merging BB and DestBB would cause ISel to // add COPY instructions in the predecessor of BB instead of BB (if it is not // merged). Note that the critical edge created by merging such blocks wont be // split in MachineSink because the jump table is not analyzable. By keeping // such empty block (BB), ISel will place COPY instructions in BB, not in the // predecessor of BB. BasicBlock *Pred = BB->getUniquePredecessor(); if (!Pred || !(isa(Pred->getTerminator()) || isa(Pred->getTerminator()))) return true; if (BB->getTerminator() != BB->getFirstNonPHI()) return true; // We use a simple cost heuristic which determine skipping merging is // profitable if the cost of skipping merging is less than the cost of // merging : Cost(skipping merging) < Cost(merging BB), where the // Cost(skipping merging) is Freq(BB) * (Cost(Copy) + Cost(Branch)), and // the Cost(merging BB) is Freq(Pred) * Cost(Copy). // Assuming Cost(Copy) == Cost(Branch), we could simplify it to : // Freq(Pred) / Freq(BB) > 2. // Note that if there are multiple empty blocks sharing the same incoming // value for the PHIs in the DestBB, we consider them together. In such // case, Cost(merging BB) will be the sum of their frequencies. if (!isa(DestBB->begin())) return true; SmallPtrSet SameIncomingValueBBs; // Find all other incoming blocks from which incoming values of all PHIs in // DestBB are the same as the ones from BB. for (pred_iterator PI = pred_begin(DestBB), E = pred_end(DestBB); PI != E; ++PI) { BasicBlock *DestBBPred = *PI; if (DestBBPred == BB) continue; if (llvm::all_of(DestBB->phis(), [&](const PHINode &DestPN) { return DestPN.getIncomingValueForBlock(BB) == DestPN.getIncomingValueForBlock(DestBBPred); })) SameIncomingValueBBs.insert(DestBBPred); } // See if all BB's incoming values are same as the value from Pred. In this // case, no reason to skip merging because COPYs are expected to be place in // Pred already. if (SameIncomingValueBBs.count(Pred)) return true; BlockFrequency PredFreq = BFI->getBlockFreq(Pred); BlockFrequency BBFreq = BFI->getBlockFreq(BB); for (auto SameValueBB : SameIncomingValueBBs) if (SameValueBB->getUniquePredecessor() == Pred && DestBB == findDestBlockOfMergeableEmptyBlock(SameValueBB)) BBFreq += BFI->getBlockFreq(SameValueBB); return PredFreq.getFrequency() <= BBFreq.getFrequency() * FreqRatioToSkipMerge; } /// Return true if we can merge BB into DestBB if there is a single /// unconditional branch between them, and BB contains no other non-phi /// instructions. bool CodeGenPrepare::canMergeBlocks(const BasicBlock *BB, const BasicBlock *DestBB) const { // We only want to eliminate blocks whose phi nodes are used by phi nodes in // the successor. If there are more complex condition (e.g. preheaders), // don't mess around with them. for (const PHINode &PN : BB->phis()) { for (const User *U : PN.users()) { const Instruction *UI = cast(U); if (UI->getParent() != DestBB || !isa(UI)) return false; // If User is inside DestBB block and it is a PHINode then check // incoming value. If incoming value is not from BB then this is // a complex condition (e.g. preheaders) we want to avoid here. if (UI->getParent() == DestBB) { if (const PHINode *UPN = dyn_cast(UI)) for (unsigned I = 0, E = UPN->getNumIncomingValues(); I != E; ++I) { Instruction *Insn = dyn_cast(UPN->getIncomingValue(I)); if (Insn && Insn->getParent() == BB && Insn->getParent() != UPN->getIncomingBlock(I)) return false; } } } } // If BB and DestBB contain any common predecessors, then the phi nodes in BB // and DestBB may have conflicting incoming values for the block. If so, we // can't merge the block. const PHINode *DestBBPN = dyn_cast(DestBB->begin()); if (!DestBBPN) return true; // no conflict. // Collect the preds of BB. SmallPtrSet BBPreds; if (const PHINode *BBPN = dyn_cast(BB->begin())) { // It is faster to get preds from a PHI than with pred_iterator. for (unsigned i = 0, e = BBPN->getNumIncomingValues(); i != e; ++i) BBPreds.insert(BBPN->getIncomingBlock(i)); } else { BBPreds.insert(pred_begin(BB), pred_end(BB)); } // Walk the preds of DestBB. for (unsigned i = 0, e = DestBBPN->getNumIncomingValues(); i != e; ++i) { BasicBlock *Pred = DestBBPN->getIncomingBlock(i); if (BBPreds.count(Pred)) { // Common predecessor? for (const PHINode &PN : DestBB->phis()) { const Value *V1 = PN.getIncomingValueForBlock(Pred); const Value *V2 = PN.getIncomingValueForBlock(BB); // If V2 is a phi node in BB, look up what the mapped value will be. if (const PHINode *V2PN = dyn_cast(V2)) if (V2PN->getParent() == BB) V2 = V2PN->getIncomingValueForBlock(Pred); // If there is a conflict, bail out. if (V1 != V2) return false; } } } return true; } /// Eliminate a basic block that has only phi's and an unconditional branch in /// it. void CodeGenPrepare::eliminateMostlyEmptyBlock(BasicBlock *BB) { BranchInst *BI = cast(BB->getTerminator()); BasicBlock *DestBB = BI->getSuccessor(0); LLVM_DEBUG(dbgs() << "MERGING MOSTLY EMPTY BLOCKS - BEFORE:\n" << *BB << *DestBB); // If the destination block has a single pred, then this is a trivial edge, // just collapse it. if (BasicBlock *SinglePred = DestBB->getSinglePredecessor()) { if (SinglePred != DestBB) { assert(SinglePred == BB && "Single predecessor not the same as predecessor"); // Merge DestBB into SinglePred/BB and delete it. MergeBlockIntoPredecessor(DestBB); // Note: BB(=SinglePred) will not be deleted on this path. // DestBB(=its single successor) is the one that was deleted. LLVM_DEBUG(dbgs() << "AFTER:\n" << *SinglePred << "\n\n\n"); return; } } // Otherwise, we have multiple predecessors of BB. Update the PHIs in DestBB // to handle the new incoming edges it is about to have. for (PHINode &PN : DestBB->phis()) { // Remove the incoming value for BB, and remember it. Value *InVal = PN.removeIncomingValue(BB, false); // Two options: either the InVal is a phi node defined in BB or it is some // value that dominates BB. PHINode *InValPhi = dyn_cast(InVal); if (InValPhi && InValPhi->getParent() == BB) { // Add all of the input values of the input PHI as inputs of this phi. for (unsigned i = 0, e = InValPhi->getNumIncomingValues(); i != e; ++i) PN.addIncoming(InValPhi->getIncomingValue(i), InValPhi->getIncomingBlock(i)); } else { // Otherwise, add one instance of the dominating value for each edge that // we will be adding. if (PHINode *BBPN = dyn_cast(BB->begin())) { for (unsigned i = 0, e = BBPN->getNumIncomingValues(); i != e; ++i) PN.addIncoming(InVal, BBPN->getIncomingBlock(i)); } else { for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) PN.addIncoming(InVal, *PI); } } } // The PHIs are now updated, change everything that refers to BB to use // DestBB and remove BB. BB->replaceAllUsesWith(DestBB); BB->eraseFromParent(); ++NumBlocksElim; LLVM_DEBUG(dbgs() << "AFTER:\n" << *DestBB << "\n\n\n"); } // Computes a map of base pointer relocation instructions to corresponding // derived pointer relocation instructions given a vector of all relocate calls static void computeBaseDerivedRelocateMap( const SmallVectorImpl &AllRelocateCalls, DenseMap> &RelocateInstMap) { // Collect information in two maps: one primarily for locating the base object // while filling the second map; the second map is the final structure holding // a mapping between Base and corresponding Derived relocate calls DenseMap, GCRelocateInst *> RelocateIdxMap; for (auto *ThisRelocate : AllRelocateCalls) { auto K = std::make_pair(ThisRelocate->getBasePtrIndex(), ThisRelocate->getDerivedPtrIndex()); RelocateIdxMap.insert(std::make_pair(K, ThisRelocate)); } for (auto &Item : RelocateIdxMap) { std::pair Key = Item.first; if (Key.first == Key.second) // Base relocation: nothing to insert continue; GCRelocateInst *I = Item.second; auto BaseKey = std::make_pair(Key.first, Key.first); // We're iterating over RelocateIdxMap so we cannot modify it. auto MaybeBase = RelocateIdxMap.find(BaseKey); if (MaybeBase == RelocateIdxMap.end()) // TODO: We might want to insert a new base object relocate and gep off // that, if there are enough derived object relocates. continue; RelocateInstMap[MaybeBase->second].push_back(I); } } // Accepts a GEP and extracts the operands into a vector provided they're all // small integer constants static bool getGEPSmallConstantIntOffsetV(GetElementPtrInst *GEP, SmallVectorImpl &OffsetV) { for (unsigned i = 1; i < GEP->getNumOperands(); i++) { // Only accept small constant integer operands auto Op = dyn_cast(GEP->getOperand(i)); if (!Op || Op->getZExtValue() > 20) return false; } for (unsigned i = 1; i < GEP->getNumOperands(); i++) OffsetV.push_back(GEP->getOperand(i)); return true; } // Takes a RelocatedBase (base pointer relocation instruction) and Targets to // replace, computes a replacement, and affects it. static bool simplifyRelocatesOffABase(GCRelocateInst *RelocatedBase, const SmallVectorImpl &Targets) { bool MadeChange = false; // We must ensure the relocation of derived pointer is defined after // relocation of base pointer. If we find a relocation corresponding to base // defined earlier than relocation of base then we move relocation of base // right before found relocation. We consider only relocation in the same // basic block as relocation of base. Relocations from other basic block will // be skipped by optimization and we do not care about them. for (auto R = RelocatedBase->getParent()->getFirstInsertionPt(); &*R != RelocatedBase; ++R) if (auto RI = dyn_cast(R)) if (RI->getStatepoint() == RelocatedBase->getStatepoint()) if (RI->getBasePtrIndex() == RelocatedBase->getBasePtrIndex()) { RelocatedBase->moveBefore(RI); break; } for (GCRelocateInst *ToReplace : Targets) { assert(ToReplace->getBasePtrIndex() == RelocatedBase->getBasePtrIndex() && "Not relocating a derived object of the original base object"); if (ToReplace->getBasePtrIndex() == ToReplace->getDerivedPtrIndex()) { // A duplicate relocate call. TODO: coalesce duplicates. continue; } if (RelocatedBase->getParent() != ToReplace->getParent()) { // Base and derived relocates are in different basic blocks. // In this case transform is only valid when base dominates derived // relocate. However it would be too expensive to check dominance // for each such relocate, so we skip the whole transformation. continue; } Value *Base = ToReplace->getBasePtr(); auto Derived = dyn_cast(ToReplace->getDerivedPtr()); if (!Derived || Derived->getPointerOperand() != Base) continue; SmallVector OffsetV; if (!getGEPSmallConstantIntOffsetV(Derived, OffsetV)) continue; // Create a Builder and replace the target callsite with a gep assert(RelocatedBase->getNextNode() && "Should always have one since it's not a terminator"); // Insert after RelocatedBase IRBuilder<> Builder(RelocatedBase->getNextNode()); Builder.SetCurrentDebugLocation(ToReplace->getDebugLoc()); // If gc_relocate does not match the actual type, cast it to the right type. // In theory, there must be a bitcast after gc_relocate if the type does not // match, and we should reuse it to get the derived pointer. But it could be // cases like this: // bb1: // ... // %g1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(...) // br label %merge // // bb2: // ... // %g2 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(...) // br label %merge // // merge: // %p1 = phi i8 addrspace(1)* [ %g1, %bb1 ], [ %g2, %bb2 ] // %cast = bitcast i8 addrspace(1)* %p1 in to i32 addrspace(1)* // // In this case, we can not find the bitcast any more. So we insert a new bitcast // no matter there is already one or not. In this way, we can handle all cases, and // the extra bitcast should be optimized away in later passes. Value *ActualRelocatedBase = RelocatedBase; if (RelocatedBase->getType() != Base->getType()) { ActualRelocatedBase = Builder.CreateBitCast(RelocatedBase, Base->getType()); } Value *Replacement = Builder.CreateGEP( Derived->getSourceElementType(), ActualRelocatedBase, makeArrayRef(OffsetV)); Replacement->takeName(ToReplace); // If the newly generated derived pointer's type does not match the original derived // pointer's type, cast the new derived pointer to match it. Same reasoning as above. Value *ActualReplacement = Replacement; if (Replacement->getType() != ToReplace->getType()) { ActualReplacement = Builder.CreateBitCast(Replacement, ToReplace->getType()); } ToReplace->replaceAllUsesWith(ActualReplacement); ToReplace->eraseFromParent(); MadeChange = true; } return MadeChange; } // Turns this: // // %base = ... // %ptr = gep %base + 15 // %tok = statepoint (%fun, i32 0, i32 0, i32 0, %base, %ptr) // %base' = relocate(%tok, i32 4, i32 4) // %ptr' = relocate(%tok, i32 4, i32 5) // %val = load %ptr' // // into this: // // %base = ... // %ptr = gep %base + 15 // %tok = statepoint (%fun, i32 0, i32 0, i32 0, %base, %ptr) // %base' = gc.relocate(%tok, i32 4, i32 4) // %ptr' = gep %base' + 15 // %val = load %ptr' bool CodeGenPrepare::simplifyOffsetableRelocate(Instruction &I) { bool MadeChange = false; SmallVector AllRelocateCalls; for (auto *U : I.users()) if (GCRelocateInst *Relocate = dyn_cast(U)) // Collect all the relocate calls associated with a statepoint AllRelocateCalls.push_back(Relocate); // We need atleast one base pointer relocation + one derived pointer // relocation to mangle if (AllRelocateCalls.size() < 2) return false; // RelocateInstMap is a mapping from the base relocate instruction to the // corresponding derived relocate instructions DenseMap> RelocateInstMap; computeBaseDerivedRelocateMap(AllRelocateCalls, RelocateInstMap); if (RelocateInstMap.empty()) return false; for (auto &Item : RelocateInstMap) // Item.first is the RelocatedBase to offset against // Item.second is the vector of Targets to replace MadeChange = simplifyRelocatesOffABase(Item.first, Item.second); return MadeChange; } /// SinkCast - Sink the specified cast instruction into its user blocks static bool SinkCast(CastInst *CI) { BasicBlock *DefBB = CI->getParent(); /// InsertedCasts - Only insert a cast in each block once. DenseMap InsertedCasts; bool MadeChange = false; for (Value::user_iterator UI = CI->user_begin(), E = CI->user_end(); UI != E; ) { Use &TheUse = UI.getUse(); Instruction *User = cast(*UI); // Figure out which BB this cast is used in. For PHI's this is the // appropriate predecessor block. BasicBlock *UserBB = User->getParent(); if (PHINode *PN = dyn_cast(User)) { UserBB = PN->getIncomingBlock(TheUse); } // Preincrement use iterator so we don't invalidate it. ++UI; // The first insertion point of a block containing an EH pad is after the // pad. If the pad is the user, we cannot sink the cast past the pad. if (User->isEHPad()) continue; // If the block selected to receive the cast is an EH pad that does not // allow non-PHI instructions before the terminator, we can't sink the // cast. if (UserBB->getTerminator()->isEHPad()) continue; // If this user is in the same block as the cast, don't change the cast. if (UserBB == DefBB) continue; // If we have already inserted a cast into this block, use it. CastInst *&InsertedCast = InsertedCasts[UserBB]; if (!InsertedCast) { BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt(); assert(InsertPt != UserBB->end()); InsertedCast = CastInst::Create(CI->getOpcode(), CI->getOperand(0), CI->getType(), "", &*InsertPt); InsertedCast->setDebugLoc(CI->getDebugLoc()); } // Replace a use of the cast with a use of the new cast. TheUse = InsertedCast; MadeChange = true; ++NumCastUses; } // If we removed all uses, nuke the cast. if (CI->use_empty()) { salvageDebugInfo(*CI); CI->eraseFromParent(); MadeChange = true; } return MadeChange; } /// If the specified cast instruction is a noop copy (e.g. it's casting from /// one pointer type to another, i32->i8 on PPC), sink it into user blocks to /// reduce the number of virtual registers that must be created and coalesced. /// /// Return true if any changes are made. static bool OptimizeNoopCopyExpression(CastInst *CI, const TargetLowering &TLI, const DataLayout &DL) { // Sink only "cheap" (or nop) address-space casts. This is a weaker condition // than sinking only nop casts, but is helpful on some platforms. if (auto *ASC = dyn_cast(CI)) { if (!TLI.isCheapAddrSpaceCast(ASC->getSrcAddressSpace(), ASC->getDestAddressSpace())) return false; } // If this is a noop copy, EVT SrcVT = TLI.getValueType(DL, CI->getOperand(0)->getType()); EVT DstVT = TLI.getValueType(DL, CI->getType()); // This is an fp<->int conversion? if (SrcVT.isInteger() != DstVT.isInteger()) return false; // If this is an extension, it will be a zero or sign extension, which // isn't a noop. if (SrcVT.bitsLT(DstVT)) return false; // If these values will be promoted, find out what they will be promoted // to. This helps us consider truncates on PPC as noop copies when they // are. if (TLI.getTypeAction(CI->getContext(), SrcVT) == TargetLowering::TypePromoteInteger) SrcVT = TLI.getTypeToTransformTo(CI->getContext(), SrcVT); if (TLI.getTypeAction(CI->getContext(), DstVT) == TargetLowering::TypePromoteInteger) DstVT = TLI.getTypeToTransformTo(CI->getContext(), DstVT); // If, after promotion, these are the same types, this is a noop copy. if (SrcVT != DstVT) return false; return SinkCast(CI); } /// Try to combine CI into a call to the llvm.uadd.with.overflow intrinsic if /// possible. /// /// Return true if any changes were made. static bool CombineUAddWithOverflow(CmpInst *CI) { Value *A, *B; Instruction *AddI; if (!match(CI, m_UAddWithOverflow(m_Value(A), m_Value(B), m_Instruction(AddI)))) return false; Type *Ty = AddI->getType(); if (!isa(Ty)) return false; // We don't want to move around uses of condition values this late, so we we // check if it is legal to create the call to the intrinsic in the basic // block containing the icmp: if (AddI->getParent() != CI->getParent() && !AddI->hasOneUse()) return false; #ifndef NDEBUG // Someday m_UAddWithOverflow may get smarter, but this is a safe assumption // for now: if (AddI->hasOneUse()) assert(*AddI->user_begin() == CI && "expected!"); #endif Module *M = CI->getModule(); Value *F = Intrinsic::getDeclaration(M, Intrinsic::uadd_with_overflow, Ty); auto *InsertPt = AddI->hasOneUse() ? CI : AddI; auto *UAddWithOverflow = CallInst::Create(F, {A, B}, "uadd.overflow", InsertPt); auto *UAdd = ExtractValueInst::Create(UAddWithOverflow, 0, "uadd", InsertPt); auto *Overflow = ExtractValueInst::Create(UAddWithOverflow, 1, "overflow", InsertPt); CI->replaceAllUsesWith(Overflow); AddI->replaceAllUsesWith(UAdd); CI->eraseFromParent(); AddI->eraseFromParent(); return true; } /// Sink the given CmpInst into user blocks to reduce the number of virtual /// registers that must be created and coalesced. This is a clear win except on /// targets with multiple condition code registers (PowerPC), where it might /// lose; some adjustment may be wanted there. /// /// Return true if any changes are made. static bool SinkCmpExpression(CmpInst *CI, const TargetLowering *TLI) { BasicBlock *DefBB = CI->getParent(); // Avoid sinking soft-FP comparisons, since this can move them into a loop. if (TLI && TLI->useSoftFloat() && isa(CI)) return false; // Only insert a cmp in each block once. DenseMap InsertedCmps; bool MadeChange = false; for (Value::user_iterator UI = CI->user_begin(), E = CI->user_end(); UI != E; ) { Use &TheUse = UI.getUse(); Instruction *User = cast(*UI); // Preincrement use iterator so we don't invalidate it. ++UI; // Don't bother for PHI nodes. if (isa(User)) continue; // Figure out which BB this cmp is used in. BasicBlock *UserBB = User->getParent(); // If this user is in the same block as the cmp, don't change the cmp. if (UserBB == DefBB) continue; // If we have already inserted a cmp into this block, use it. CmpInst *&InsertedCmp = InsertedCmps[UserBB]; if (!InsertedCmp) { BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt(); assert(InsertPt != UserBB->end()); InsertedCmp = CmpInst::Create(CI->getOpcode(), CI->getPredicate(), CI->getOperand(0), CI->getOperand(1), "", &*InsertPt); // Propagate the debug info. InsertedCmp->setDebugLoc(CI->getDebugLoc()); } // Replace a use of the cmp with a use of the new cmp. TheUse = InsertedCmp; MadeChange = true; ++NumCmpUses; } // If we removed all uses, nuke the cmp. if (CI->use_empty()) { CI->eraseFromParent(); MadeChange = true; } return MadeChange; } static bool OptimizeCmpExpression(CmpInst *CI, const TargetLowering *TLI) { if (SinkCmpExpression(CI, TLI)) return true; if (CombineUAddWithOverflow(CI)) return true; return false; } /// Duplicate and sink the given 'and' instruction into user blocks where it is /// used in a compare to allow isel to generate better code for targets where /// this operation can be combined. /// /// Return true if any changes are made. static bool sinkAndCmp0Expression(Instruction *AndI, const TargetLowering &TLI, SetOfInstrs &InsertedInsts) { // Double-check that we're not trying to optimize an instruction that was // already optimized by some other part of this pass. assert(!InsertedInsts.count(AndI) && "Attempting to optimize already optimized and instruction"); (void) InsertedInsts; // Nothing to do for single use in same basic block. if (AndI->hasOneUse() && AndI->getParent() == cast(*AndI->user_begin())->getParent()) return false; // Try to avoid cases where sinking/duplicating is likely to increase register // pressure. if (!isa(AndI->getOperand(0)) && !isa(AndI->getOperand(1)) && AndI->getOperand(0)->hasOneUse() && AndI->getOperand(1)->hasOneUse()) return false; for (auto *U : AndI->users()) { Instruction *User = cast(U); // Only sink for and mask feeding icmp with 0. if (!isa(User)) return false; auto *CmpC = dyn_cast(User->getOperand(1)); if (!CmpC || !CmpC->isZero()) return false; } if (!TLI.isMaskAndCmp0FoldingBeneficial(*AndI)) return false; LLVM_DEBUG(dbgs() << "found 'and' feeding only icmp 0;\n"); LLVM_DEBUG(AndI->getParent()->dump()); // Push the 'and' into the same block as the icmp 0. There should only be // one (icmp (and, 0)) in each block, since CSE/GVN should have removed any // others, so we don't need to keep track of which BBs we insert into. for (Value::user_iterator UI = AndI->user_begin(), E = AndI->user_end(); UI != E; ) { Use &TheUse = UI.getUse(); Instruction *User = cast(*UI); // Preincrement use iterator so we don't invalidate it. ++UI; LLVM_DEBUG(dbgs() << "sinking 'and' use: " << *User << "\n"); // Keep the 'and' in the same place if the use is already in the same block. Instruction *InsertPt = User->getParent() == AndI->getParent() ? AndI : User; Instruction *InsertedAnd = BinaryOperator::Create(Instruction::And, AndI->getOperand(0), AndI->getOperand(1), "", InsertPt); // Propagate the debug info. InsertedAnd->setDebugLoc(AndI->getDebugLoc()); // Replace a use of the 'and' with a use of the new 'and'. TheUse = InsertedAnd; ++NumAndUses; LLVM_DEBUG(User->getParent()->dump()); } // We removed all uses, nuke the and. AndI->eraseFromParent(); return true; } /// Check if the candidates could be combined with a shift instruction, which /// includes: /// 1. Truncate instruction /// 2. And instruction and the imm is a mask of the low bits: /// imm & (imm+1) == 0 static bool isExtractBitsCandidateUse(Instruction *User) { if (!isa(User)) { if (User->getOpcode() != Instruction::And || !isa(User->getOperand(1))) return false; const APInt &Cimm = cast(User->getOperand(1))->getValue(); if ((Cimm & (Cimm + 1)).getBoolValue()) return false; } return true; } /// Sink both shift and truncate instruction to the use of truncate's BB. static bool SinkShiftAndTruncate(BinaryOperator *ShiftI, Instruction *User, ConstantInt *CI, DenseMap &InsertedShifts, const TargetLowering &TLI, const DataLayout &DL) { BasicBlock *UserBB = User->getParent(); DenseMap InsertedTruncs; TruncInst *TruncI = dyn_cast(User); bool MadeChange = false; for (Value::user_iterator TruncUI = TruncI->user_begin(), TruncE = TruncI->user_end(); TruncUI != TruncE;) { Use &TruncTheUse = TruncUI.getUse(); Instruction *TruncUser = cast(*TruncUI); // Preincrement use iterator so we don't invalidate it. ++TruncUI; int ISDOpcode = TLI.InstructionOpcodeToISD(TruncUser->getOpcode()); if (!ISDOpcode) continue; // If the use is actually a legal node, there will not be an // implicit truncate. // FIXME: always querying the result type is just an // approximation; some nodes' legality is determined by the // operand or other means. There's no good way to find out though. if (TLI.isOperationLegalOrCustom( ISDOpcode, TLI.getValueType(DL, TruncUser->getType(), true))) continue; // Don't bother for PHI nodes. if (isa(TruncUser)) continue; BasicBlock *TruncUserBB = TruncUser->getParent(); if (UserBB == TruncUserBB) continue; BinaryOperator *&InsertedShift = InsertedShifts[TruncUserBB]; CastInst *&InsertedTrunc = InsertedTruncs[TruncUserBB]; if (!InsertedShift && !InsertedTrunc) { BasicBlock::iterator InsertPt = TruncUserBB->getFirstInsertionPt(); assert(InsertPt != TruncUserBB->end()); // Sink the shift if (ShiftI->getOpcode() == Instruction::AShr) InsertedShift = BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "", &*InsertPt); else InsertedShift = BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "", &*InsertPt); // Sink the trunc BasicBlock::iterator TruncInsertPt = TruncUserBB->getFirstInsertionPt(); TruncInsertPt++; assert(TruncInsertPt != TruncUserBB->end()); InsertedTrunc = CastInst::Create(TruncI->getOpcode(), InsertedShift, TruncI->getType(), "", &*TruncInsertPt); MadeChange = true; TruncTheUse = InsertedTrunc; } } return MadeChange; } /// Sink the shift *right* instruction into user blocks if the uses could /// potentially be combined with this shift instruction and generate BitExtract /// instruction. It will only be applied if the architecture supports BitExtract /// instruction. Here is an example: /// BB1: /// %x.extract.shift = lshr i64 %arg1, 32 /// BB2: /// %x.extract.trunc = trunc i64 %x.extract.shift to i16 /// ==> /// /// BB2: /// %x.extract.shift.1 = lshr i64 %arg1, 32 /// %x.extract.trunc = trunc i64 %x.extract.shift.1 to i16 /// /// CodeGen will recognize the pattern in BB2 and generate BitExtract /// instruction. /// Return true if any changes are made. static bool OptimizeExtractBits(BinaryOperator *ShiftI, ConstantInt *CI, const TargetLowering &TLI, const DataLayout &DL) { BasicBlock *DefBB = ShiftI->getParent(); /// Only insert instructions in each block once. DenseMap InsertedShifts; bool shiftIsLegal = TLI.isTypeLegal(TLI.getValueType(DL, ShiftI->getType())); bool MadeChange = false; for (Value::user_iterator UI = ShiftI->user_begin(), E = ShiftI->user_end(); UI != E;) { Use &TheUse = UI.getUse(); Instruction *User = cast(*UI); // Preincrement use iterator so we don't invalidate it. ++UI; // Don't bother for PHI nodes. if (isa(User)) continue; if (!isExtractBitsCandidateUse(User)) continue; BasicBlock *UserBB = User->getParent(); if (UserBB == DefBB) { // If the shift and truncate instruction are in the same BB. The use of // the truncate(TruncUse) may still introduce another truncate if not // legal. In this case, we would like to sink both shift and truncate // instruction to the BB of TruncUse. // for example: // BB1: // i64 shift.result = lshr i64 opnd, imm // trunc.result = trunc shift.result to i16 // // BB2: // ----> We will have an implicit truncate here if the architecture does // not have i16 compare. // cmp i16 trunc.result, opnd2 // if (isa(User) && shiftIsLegal // If the type of the truncate is legal, no truncate will be // introduced in other basic blocks. && (!TLI.isTypeLegal(TLI.getValueType(DL, User->getType())))) MadeChange = SinkShiftAndTruncate(ShiftI, User, CI, InsertedShifts, TLI, DL); continue; } // If we have already inserted a shift into this block, use it. BinaryOperator *&InsertedShift = InsertedShifts[UserBB]; if (!InsertedShift) { BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt(); assert(InsertPt != UserBB->end()); if (ShiftI->getOpcode() == Instruction::AShr) InsertedShift = BinaryOperator::CreateAShr(ShiftI->getOperand(0), CI, "", &*InsertPt); else InsertedShift = BinaryOperator::CreateLShr(ShiftI->getOperand(0), CI, "", &*InsertPt); MadeChange = true; } // Replace a use of the shift with a use of the new shift. TheUse = InsertedShift; } // If we removed all uses, nuke the shift. if (ShiftI->use_empty()) ShiftI->eraseFromParent(); return MadeChange; } /// If counting leading or trailing zeros is an expensive operation and a zero /// input is defined, add a check for zero to avoid calling the intrinsic. /// /// We want to transform: /// %z = call i64 @llvm.cttz.i64(i64 %A, i1 false) /// /// into: /// entry: /// %cmpz = icmp eq i64 %A, 0 /// br i1 %cmpz, label %cond.end, label %cond.false /// cond.false: /// %z = call i64 @llvm.cttz.i64(i64 %A, i1 true) /// br label %cond.end /// cond.end: /// %ctz = phi i64 [ 64, %entry ], [ %z, %cond.false ] /// /// If the transform is performed, return true and set ModifiedDT to true. static bool despeculateCountZeros(IntrinsicInst *CountZeros, const TargetLowering *TLI, const DataLayout *DL, bool &ModifiedDT) { if (!TLI || !DL) return false; // If a zero input is undefined, it doesn't make sense to despeculate that. if (match(CountZeros->getOperand(1), m_One())) return false; // If it's cheap to speculate, there's nothing to do. auto IntrinsicID = CountZeros->getIntrinsicID(); if ((IntrinsicID == Intrinsic::cttz && TLI->isCheapToSpeculateCttz()) || (IntrinsicID == Intrinsic::ctlz && TLI->isCheapToSpeculateCtlz())) return false; // Only handle legal scalar cases. Anything else requires too much work. Type *Ty = CountZeros->getType(); unsigned SizeInBits = Ty->getPrimitiveSizeInBits(); if (Ty->isVectorTy() || SizeInBits > DL->getLargestLegalIntTypeSizeInBits()) return false; // The intrinsic will be sunk behind a compare against zero and branch. BasicBlock *StartBlock = CountZeros->getParent(); BasicBlock *CallBlock = StartBlock->splitBasicBlock(CountZeros, "cond.false"); // Create another block after the count zero intrinsic. A PHI will be added // in this block to select the result of the intrinsic or the bit-width // constant if the input to the intrinsic is zero. BasicBlock::iterator SplitPt = ++(BasicBlock::iterator(CountZeros)); BasicBlock *EndBlock = CallBlock->splitBasicBlock(SplitPt, "cond.end"); // Set up a builder to create a compare, conditional branch, and PHI. IRBuilder<> Builder(CountZeros->getContext()); Builder.SetInsertPoint(StartBlock->getTerminator()); Builder.SetCurrentDebugLocation(CountZeros->getDebugLoc()); // Replace the unconditional branch that was created by the first split with // a compare against zero and a conditional branch. Value *Zero = Constant::getNullValue(Ty); Value *Cmp = Builder.CreateICmpEQ(CountZeros->getOperand(0), Zero, "cmpz"); Builder.CreateCondBr(Cmp, EndBlock, CallBlock); StartBlock->getTerminator()->eraseFromParent(); // Create a PHI in the end block to select either the output of the intrinsic // or the bit width of the operand. Builder.SetInsertPoint(&EndBlock->front()); PHINode *PN = Builder.CreatePHI(Ty, 2, "ctz"); CountZeros->replaceAllUsesWith(PN); Value *BitWidth = Builder.getInt(APInt(SizeInBits, SizeInBits)); PN->addIncoming(BitWidth, StartBlock); PN->addIncoming(CountZeros, CallBlock); // We are explicitly handling the zero case, so we can set the intrinsic's // undefined zero argument to 'true'. This will also prevent reprocessing the // intrinsic; we only despeculate when a zero input is defined. CountZeros->setArgOperand(1, Builder.getTrue()); ModifiedDT = true; return true; } bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool &ModifiedDT) { BasicBlock *BB = CI->getParent(); // Lower inline assembly if we can. // If we found an inline asm expession, and if the target knows how to // lower it to normal LLVM code, do so now. if (TLI && isa(CI->getCalledValue())) { if (TLI->ExpandInlineAsm(CI)) { // Avoid invalidating the iterator. CurInstIterator = BB->begin(); // Avoid processing instructions out of order, which could cause // reuse before a value is defined. SunkAddrs.clear(); return true; } // Sink address computing for memory operands into the block. if (optimizeInlineAsmInst(CI)) return true; } // Align the pointer arguments to this call if the target thinks it's a good // idea unsigned MinSize, PrefAlign; if (TLI && TLI->shouldAlignPointerArgs(CI, MinSize, PrefAlign)) { for (auto &Arg : CI->arg_operands()) { // We want to align both objects whose address is used directly and // objects whose address is used in casts and GEPs, though it only makes // sense for GEPs if the offset is a multiple of the desired alignment and // if size - offset meets the size threshold. if (!Arg->getType()->isPointerTy()) continue; APInt Offset(DL->getIndexSizeInBits( cast(Arg->getType())->getAddressSpace()), 0); Value *Val = Arg->stripAndAccumulateInBoundsConstantOffsets(*DL, Offset); uint64_t Offset2 = Offset.getLimitedValue(); if ((Offset2 & (PrefAlign-1)) != 0) continue; AllocaInst *AI; if ((AI = dyn_cast(Val)) && AI->getAlignment() < PrefAlign && DL->getTypeAllocSize(AI->getAllocatedType()) >= MinSize + Offset2) AI->setAlignment(PrefAlign); // Global variables can only be aligned if they are defined in this // object (i.e. they are uniquely initialized in this object), and // over-aligning global variables that have an explicit section is // forbidden. GlobalVariable *GV; if ((GV = dyn_cast(Val)) && GV->canIncreaseAlignment() && GV->getPointerAlignment(*DL) < PrefAlign && DL->getTypeAllocSize(GV->getValueType()) >= MinSize + Offset2) GV->setAlignment(PrefAlign); } // If this is a memcpy (or similar) then we may be able to improve the // alignment if (MemIntrinsic *MI = dyn_cast(CI)) { unsigned DestAlign = getKnownAlignment(MI->getDest(), *DL); if (DestAlign > MI->getDestAlignment()) MI->setDestAlignment(DestAlign); if (MemTransferInst *MTI = dyn_cast(MI)) { unsigned SrcAlign = getKnownAlignment(MTI->getSource(), *DL); if (SrcAlign > MTI->getSourceAlignment()) MTI->setSourceAlignment(SrcAlign); } } } // If we have a cold call site, try to sink addressing computation into the // cold block. This interacts with our handling for loads and stores to // ensure that we can fold all uses of a potential addressing computation // into their uses. TODO: generalize this to work over profiling data if (!OptSize && CI->hasFnAttr(Attribute::Cold)) for (auto &Arg : CI->arg_operands()) { if (!Arg->getType()->isPointerTy()) continue; unsigned AS = Arg->getType()->getPointerAddressSpace(); return optimizeMemoryInst(CI, Arg, Arg->getType(), AS); } IntrinsicInst *II = dyn_cast(CI); if (II) { switch (II->getIntrinsicID()) { default: break; case Intrinsic::objectsize: { // Lower all uses of llvm.objectsize.* ConstantInt *RetVal = lowerObjectSizeCall(II, *DL, TLInfo, /*MustSucceed=*/true); // Substituting this can cause recursive simplifications, which can // invalidate our iterator. Use a WeakTrackingVH to hold onto it in case // this // happens. Value *CurValue = &*CurInstIterator; WeakTrackingVH IterHandle(CurValue); replaceAndRecursivelySimplify(CI, RetVal, TLInfo, nullptr); // If the iterator instruction was recursively deleted, start over at the // start of the block. if (IterHandle != CurValue) { CurInstIterator = BB->begin(); SunkAddrs.clear(); } return true; } case Intrinsic::aarch64_stlxr: case Intrinsic::aarch64_stxr: { ZExtInst *ExtVal = dyn_cast(CI->getArgOperand(0)); if (!ExtVal || !ExtVal->hasOneUse() || ExtVal->getParent() == CI->getParent()) return false; // Sink a zext feeding stlxr/stxr before it, so it can be folded into it. ExtVal->moveBefore(CI); // Mark this instruction as "inserted by CGP", so that other // optimizations don't touch it. InsertedInsts.insert(ExtVal); return true; } case Intrinsic::launder_invariant_group: case Intrinsic::strip_invariant_group: II->replaceAllUsesWith(II->getArgOperand(0)); II->eraseFromParent(); return true; case Intrinsic::cttz: case Intrinsic::ctlz: // If counting zeros is expensive, try to avoid it. return despeculateCountZeros(II, TLI, DL, ModifiedDT); } if (TLI) { SmallVector PtrOps; Type *AccessTy; if (TLI->getAddrModeArguments(II, PtrOps, AccessTy)) while (!PtrOps.empty()) { Value *PtrVal = PtrOps.pop_back_val(); unsigned AS = PtrVal->getType()->getPointerAddressSpace(); if (optimizeMemoryInst(II, PtrVal, AccessTy, AS)) return true; } } } // From here on out we're working with named functions. if (!CI->getCalledFunction()) return false; // Lower all default uses of _chk calls. This is very similar // to what InstCombineCalls does, but here we are only lowering calls // to fortified library functions (e.g. __memcpy_chk) that have the default // "don't know" as the objectsize. Anything else should be left alone. FortifiedLibCallSimplifier Simplifier(TLInfo, true); if (Value *V = Simplifier.optimizeCall(CI)) { CI->replaceAllUsesWith(V); CI->eraseFromParent(); return true; } return false; } /// Look for opportunities to duplicate return instructions to the predecessor /// to enable tail call optimizations. The case it is currently looking for is: /// @code /// bb0: /// %tmp0 = tail call i32 @f0() /// br label %return /// bb1: /// %tmp1 = tail call i32 @f1() /// br label %return /// bb2: /// %tmp2 = tail call i32 @f2() /// br label %return /// return: /// %retval = phi i32 [ %tmp0, %bb0 ], [ %tmp1, %bb1 ], [ %tmp2, %bb2 ] /// ret i32 %retval /// @endcode /// /// => /// /// @code /// bb0: /// %tmp0 = tail call i32 @f0() /// ret i32 %tmp0 /// bb1: /// %tmp1 = tail call i32 @f1() /// ret i32 %tmp1 /// bb2: /// %tmp2 = tail call i32 @f2() /// ret i32 %tmp2 /// @endcode bool CodeGenPrepare::dupRetToEnableTailCallOpts(BasicBlock *BB) { if (!TLI) return false; ReturnInst *RetI = dyn_cast(BB->getTerminator()); if (!RetI) return false; PHINode *PN = nullptr; BitCastInst *BCI = nullptr; Value *V = RetI->getReturnValue(); if (V) { BCI = dyn_cast(V); if (BCI) V = BCI->getOperand(0); PN = dyn_cast(V); if (!PN) return false; } if (PN && PN->getParent() != BB) return false; // Make sure there are no instructions between the PHI and return, or that the // return is the first instruction in the block. if (PN) { BasicBlock::iterator BI = BB->begin(); do { ++BI; } while (isa(BI)); if (&*BI == BCI) // Also skip over the bitcast. ++BI; if (&*BI != RetI) return false; } else { BasicBlock::iterator BI = BB->begin(); while (isa(BI)) ++BI; if (&*BI != RetI) return false; } /// Only dup the ReturnInst if the CallInst is likely to be emitted as a tail /// call. const Function *F = BB->getParent(); SmallVector TailCalls; if (PN) { for (unsigned I = 0, E = PN->getNumIncomingValues(); I != E; ++I) { CallInst *CI = dyn_cast(PN->getIncomingValue(I)); // Make sure the phi value is indeed produced by the tail call. if (CI && CI->hasOneUse() && CI->getParent() == PN->getIncomingBlock(I) && TLI->mayBeEmittedAsTailCall(CI) && attributesPermitTailCall(F, CI, RetI, *TLI)) TailCalls.push_back(CI); } } else { SmallPtrSet VisitedBBs; for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) { if (!VisitedBBs.insert(*PI).second) continue; BasicBlock::InstListType &InstList = (*PI)->getInstList(); BasicBlock::InstListType::reverse_iterator RI = InstList.rbegin(); BasicBlock::InstListType::reverse_iterator RE = InstList.rend(); do { ++RI; } while (RI != RE && isa(&*RI)); if (RI == RE) continue; CallInst *CI = dyn_cast(&*RI); if (CI && CI->use_empty() && TLI->mayBeEmittedAsTailCall(CI) && attributesPermitTailCall(F, CI, RetI, *TLI)) TailCalls.push_back(CI); } } bool Changed = false; for (unsigned i = 0, e = TailCalls.size(); i != e; ++i) { CallInst *CI = TailCalls[i]; CallSite CS(CI); // Conservatively require the attributes of the call to match those of the // return. Ignore noalias because it doesn't affect the call sequence. AttributeList CalleeAttrs = CS.getAttributes(); if (AttrBuilder(CalleeAttrs, AttributeList::ReturnIndex) .removeAttribute(Attribute::NoAlias) != AttrBuilder(CalleeAttrs, AttributeList::ReturnIndex) .removeAttribute(Attribute::NoAlias)) continue; // Make sure the call instruction is followed by an unconditional branch to // the return block. BasicBlock *CallBB = CI->getParent(); BranchInst *BI = dyn_cast(CallBB->getTerminator()); if (!BI || !BI->isUnconditional() || BI->getSuccessor(0) != BB) continue; // Duplicate the return into CallBB. (void)FoldReturnIntoUncondBranch(RetI, BB, CallBB); ModifiedDT = Changed = true; ++NumRetsDup; } // If we eliminated all predecessors of the block, delete the block now. if (Changed && !BB->hasAddressTaken() && pred_begin(BB) == pred_end(BB)) BB->eraseFromParent(); return Changed; } //===----------------------------------------------------------------------===// // Memory Optimization //===----------------------------------------------------------------------===// namespace { /// This is an extended version of TargetLowering::AddrMode /// which holds actual Value*'s for register values. struct ExtAddrMode : public TargetLowering::AddrMode { Value *BaseReg = nullptr; Value *ScaledReg = nullptr; Value *OriginalValue = nullptr; enum FieldName { NoField = 0x00, BaseRegField = 0x01, BaseGVField = 0x02, BaseOffsField = 0x04, ScaledRegField = 0x08, ScaleField = 0x10, MultipleFields = 0xff }; ExtAddrMode() = default; void print(raw_ostream &OS) const; void dump() const; FieldName compare(const ExtAddrMode &other) { // First check that the types are the same on each field, as differing types // is something we can't cope with later on. if (BaseReg && other.BaseReg && BaseReg->getType() != other.BaseReg->getType()) return MultipleFields; if (BaseGV && other.BaseGV && BaseGV->getType() != other.BaseGV->getType()) return MultipleFields; if (ScaledReg && other.ScaledReg && ScaledReg->getType() != other.ScaledReg->getType()) return MultipleFields; // Check each field to see if it differs. unsigned Result = NoField; if (BaseReg != other.BaseReg) Result |= BaseRegField; if (BaseGV != other.BaseGV) Result |= BaseGVField; if (BaseOffs != other.BaseOffs) Result |= BaseOffsField; if (ScaledReg != other.ScaledReg) Result |= ScaledRegField; // Don't count 0 as being a different scale, because that actually means // unscaled (which will already be counted by having no ScaledReg). if (Scale && other.Scale && Scale != other.Scale) Result |= ScaleField; if (countPopulation(Result) > 1) return MultipleFields; else return static_cast(Result); } // An AddrMode is trivial if it involves no calculation i.e. it is just a base // with no offset. bool isTrivial() { // An AddrMode is (BaseGV + BaseReg + BaseOffs + ScaleReg * Scale) so it is // trivial if at most one of these terms is nonzero, except that BaseGV and // BaseReg both being zero actually means a null pointer value, which we // consider to be 'non-zero' here. return !BaseOffs && !Scale && !(BaseGV && BaseReg); } Value *GetFieldAsValue(FieldName Field, Type *IntPtrTy) { switch (Field) { default: return nullptr; case BaseRegField: return BaseReg; case BaseGVField: return BaseGV; case ScaledRegField: return ScaledReg; case BaseOffsField: return ConstantInt::get(IntPtrTy, BaseOffs); } } void SetCombinedField(FieldName Field, Value *V, const SmallVectorImpl &AddrModes) { switch (Field) { default: llvm_unreachable("Unhandled fields are expected to be rejected earlier"); break; case ExtAddrMode::BaseRegField: BaseReg = V; break; case ExtAddrMode::BaseGVField: // A combined BaseGV is an Instruction, not a GlobalValue, so it goes // in the BaseReg field. assert(BaseReg == nullptr); BaseReg = V; BaseGV = nullptr; break; case ExtAddrMode::ScaledRegField: ScaledReg = V; // If we have a mix of scaled and unscaled addrmodes then we want scale // to be the scale and not zero. if (!Scale) for (const ExtAddrMode &AM : AddrModes) if (AM.Scale) { Scale = AM.Scale; break; } break; case ExtAddrMode::BaseOffsField: // The offset is no longer a constant, so it goes in ScaledReg with a // scale of 1. assert(ScaledReg == nullptr); ScaledReg = V; Scale = 1; BaseOffs = 0; break; } } }; } // end anonymous namespace #ifndef NDEBUG static inline raw_ostream &operator<<(raw_ostream &OS, const ExtAddrMode &AM) { AM.print(OS); return OS; } #endif #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) void ExtAddrMode::print(raw_ostream &OS) const { bool NeedPlus = false; OS << "["; if (BaseGV) { OS << (NeedPlus ? " + " : "") << "GV:"; BaseGV->printAsOperand(OS, /*PrintType=*/false); NeedPlus = true; } if (BaseOffs) { OS << (NeedPlus ? " + " : "") << BaseOffs; NeedPlus = true; } if (BaseReg) { OS << (NeedPlus ? " + " : "") << "Base:"; BaseReg->printAsOperand(OS, /*PrintType=*/false); NeedPlus = true; } if (Scale) { OS << (NeedPlus ? " + " : "") << Scale << "*"; ScaledReg->printAsOperand(OS, /*PrintType=*/false); } OS << ']'; } LLVM_DUMP_METHOD void ExtAddrMode::dump() const { print(dbgs()); dbgs() << '\n'; } #endif namespace { /// This class provides transaction based operation on the IR. /// Every change made through this class is recorded in the internal state and /// can be undone (rollback) until commit is called. class TypePromotionTransaction { /// This represents the common interface of the individual transaction. /// Each class implements the logic for doing one specific modification on /// the IR via the TypePromotionTransaction. class TypePromotionAction { protected: /// The Instruction modified. Instruction *Inst; public: /// Constructor of the action. /// The constructor performs the related action on the IR. TypePromotionAction(Instruction *Inst) : Inst(Inst) {} virtual ~TypePromotionAction() = default; /// Undo the modification done by this action. /// When this method is called, the IR must be in the same state as it was /// before this action was applied. /// \pre Undoing the action works if and only if the IR is in the exact same /// state as it was directly after this action was applied. virtual void undo() = 0; /// Advocate every change made by this action. /// When the results on the IR of the action are to be kept, it is important /// to call this function, otherwise hidden information may be kept forever. virtual void commit() { // Nothing to be done, this action is not doing anything. } }; /// Utility to remember the position of an instruction. class InsertionHandler { /// Position of an instruction. /// Either an instruction: /// - Is the first in a basic block: BB is used. /// - Has a previous instruction: PrevInst is used. union { Instruction *PrevInst; BasicBlock *BB; } Point; /// Remember whether or not the instruction had a previous instruction. bool HasPrevInstruction; public: /// Record the position of \p Inst. InsertionHandler(Instruction *Inst) { BasicBlock::iterator It = Inst->getIterator(); HasPrevInstruction = (It != (Inst->getParent()->begin())); if (HasPrevInstruction) Point.PrevInst = &*--It; else Point.BB = Inst->getParent(); } /// Insert \p Inst at the recorded position. void insert(Instruction *Inst) { if (HasPrevInstruction) { if (Inst->getParent()) Inst->removeFromParent(); Inst->insertAfter(Point.PrevInst); } else { Instruction *Position = &*Point.BB->getFirstInsertionPt(); if (Inst->getParent()) Inst->moveBefore(Position); else Inst->insertBefore(Position); } } }; /// Move an instruction before another. class InstructionMoveBefore : public TypePromotionAction { /// Original position of the instruction. InsertionHandler Position; public: /// Move \p Inst before \p Before. InstructionMoveBefore(Instruction *Inst, Instruction *Before) : TypePromotionAction(Inst), Position(Inst) { LLVM_DEBUG(dbgs() << "Do: move: " << *Inst << "\nbefore: " << *Before << "\n"); Inst->moveBefore(Before); } /// Move the instruction back to its original position. void undo() override { LLVM_DEBUG(dbgs() << "Undo: moveBefore: " << *Inst << "\n"); Position.insert(Inst); } }; /// Set the operand of an instruction with a new value. class OperandSetter : public TypePromotionAction { /// Original operand of the instruction. Value *Origin; /// Index of the modified instruction. unsigned Idx; public: /// Set \p Idx operand of \p Inst with \p NewVal. OperandSetter(Instruction *Inst, unsigned Idx, Value *NewVal) : TypePromotionAction(Inst), Idx(Idx) { LLVM_DEBUG(dbgs() << "Do: setOperand: " << Idx << "\n" << "for:" << *Inst << "\n" << "with:" << *NewVal << "\n"); Origin = Inst->getOperand(Idx); Inst->setOperand(Idx, NewVal); } /// Restore the original value of the instruction. void undo() override { LLVM_DEBUG(dbgs() << "Undo: setOperand:" << Idx << "\n" << "for: " << *Inst << "\n" << "with: " << *Origin << "\n"); Inst->setOperand(Idx, Origin); } }; /// Hide the operands of an instruction. /// Do as if this instruction was not using any of its operands. class OperandsHider : public TypePromotionAction { /// The list of original operands. SmallVector OriginalValues; public: /// Remove \p Inst from the uses of the operands of \p Inst. OperandsHider(Instruction *Inst) : TypePromotionAction(Inst) { LLVM_DEBUG(dbgs() << "Do: OperandsHider: " << *Inst << "\n"); unsigned NumOpnds = Inst->getNumOperands(); OriginalValues.reserve(NumOpnds); for (unsigned It = 0; It < NumOpnds; ++It) { // Save the current operand. Value *Val = Inst->getOperand(It); OriginalValues.push_back(Val); // Set a dummy one. // We could use OperandSetter here, but that would imply an overhead // that we are not willing to pay. Inst->setOperand(It, UndefValue::get(Val->getType())); } } /// Restore the original list of uses. void undo() override { LLVM_DEBUG(dbgs() << "Undo: OperandsHider: " << *Inst << "\n"); for (unsigned It = 0, EndIt = OriginalValues.size(); It != EndIt; ++It) Inst->setOperand(It, OriginalValues[It]); } }; /// Build a truncate instruction. class TruncBuilder : public TypePromotionAction { Value *Val; public: /// Build a truncate instruction of \p Opnd producing a \p Ty /// result. /// trunc Opnd to Ty. TruncBuilder(Instruction *Opnd, Type *Ty) : TypePromotionAction(Opnd) { IRBuilder<> Builder(Opnd); Val = Builder.CreateTrunc(Opnd, Ty, "promoted"); LLVM_DEBUG(dbgs() << "Do: TruncBuilder: " << *Val << "\n"); } /// Get the built value. Value *getBuiltValue() { return Val; } /// Remove the built instruction. void undo() override { LLVM_DEBUG(dbgs() << "Undo: TruncBuilder: " << *Val << "\n"); if (Instruction *IVal = dyn_cast(Val)) IVal->eraseFromParent(); } }; /// Build a sign extension instruction. class SExtBuilder : public TypePromotionAction { Value *Val; public: /// Build a sign extension instruction of \p Opnd producing a \p Ty /// result. /// sext Opnd to Ty. SExtBuilder(Instruction *InsertPt, Value *Opnd, Type *Ty) : TypePromotionAction(InsertPt) { IRBuilder<> Builder(InsertPt); Val = Builder.CreateSExt(Opnd, Ty, "promoted"); LLVM_DEBUG(dbgs() << "Do: SExtBuilder: " << *Val << "\n"); } /// Get the built value. Value *getBuiltValue() { return Val; } /// Remove the built instruction. void undo() override { LLVM_DEBUG(dbgs() << "Undo: SExtBuilder: " << *Val << "\n"); if (Instruction *IVal = dyn_cast(Val)) IVal->eraseFromParent(); } }; /// Build a zero extension instruction. class ZExtBuilder : public TypePromotionAction { Value *Val; public: /// Build a zero extension instruction of \p Opnd producing a \p Ty /// result. /// zext Opnd to Ty. ZExtBuilder(Instruction *InsertPt, Value *Opnd, Type *Ty) : TypePromotionAction(InsertPt) { IRBuilder<> Builder(InsertPt); Val = Builder.CreateZExt(Opnd, Ty, "promoted"); LLVM_DEBUG(dbgs() << "Do: ZExtBuilder: " << *Val << "\n"); } /// Get the built value. Value *getBuiltValue() { return Val; } /// Remove the built instruction. void undo() override { LLVM_DEBUG(dbgs() << "Undo: ZExtBuilder: " << *Val << "\n"); if (Instruction *IVal = dyn_cast(Val)) IVal->eraseFromParent(); } }; /// Mutate an instruction to another type. class TypeMutator : public TypePromotionAction { /// Record the original type. Type *OrigTy; public: /// Mutate the type of \p Inst into \p NewTy. TypeMutator(Instruction *Inst, Type *NewTy) : TypePromotionAction(Inst), OrigTy(Inst->getType()) { LLVM_DEBUG(dbgs() << "Do: MutateType: " << *Inst << " with " << *NewTy << "\n"); Inst->mutateType(NewTy); } /// Mutate the instruction back to its original type. void undo() override { LLVM_DEBUG(dbgs() << "Undo: MutateType: " << *Inst << " with " << *OrigTy << "\n"); Inst->mutateType(OrigTy); } }; /// Replace the uses of an instruction by another instruction. class UsesReplacer : public TypePromotionAction { /// Helper structure to keep track of the replaced uses. struct InstructionAndIdx { /// The instruction using the instruction. Instruction *Inst; /// The index where this instruction is used for Inst. unsigned Idx; InstructionAndIdx(Instruction *Inst, unsigned Idx) : Inst(Inst), Idx(Idx) {} }; /// Keep track of the original uses (pair Instruction, Index). SmallVector OriginalUses; using use_iterator = SmallVectorImpl::iterator; public: /// Replace all the use of \p Inst by \p New. UsesReplacer(Instruction *Inst, Value *New) : TypePromotionAction(Inst) { LLVM_DEBUG(dbgs() << "Do: UsersReplacer: " << *Inst << " with " << *New << "\n"); // Record the original uses. for (Use &U : Inst->uses()) { Instruction *UserI = cast(U.getUser()); OriginalUses.push_back(InstructionAndIdx(UserI, U.getOperandNo())); } // Now, we can replace the uses. Inst->replaceAllUsesWith(New); } /// Reassign the original uses of Inst to Inst. void undo() override { LLVM_DEBUG(dbgs() << "Undo: UsersReplacer: " << *Inst << "\n"); for (use_iterator UseIt = OriginalUses.begin(), EndIt = OriginalUses.end(); UseIt != EndIt; ++UseIt) { UseIt->Inst->setOperand(UseIt->Idx, Inst); } } }; /// Remove an instruction from the IR. class InstructionRemover : public TypePromotionAction { /// Original position of the instruction. InsertionHandler Inserter; /// Helper structure to hide all the link to the instruction. In other /// words, this helps to do as if the instruction was removed. OperandsHider Hider; /// Keep track of the uses replaced, if any. UsesReplacer *Replacer = nullptr; /// Keep track of instructions removed. SetOfInstrs &RemovedInsts; public: /// Remove all reference of \p Inst and optionally replace all its /// uses with New. /// \p RemovedInsts Keep track of the instructions removed by this Action. /// \pre If !Inst->use_empty(), then New != nullptr InstructionRemover(Instruction *Inst, SetOfInstrs &RemovedInsts, Value *New = nullptr) : TypePromotionAction(Inst), Inserter(Inst), Hider(Inst), RemovedInsts(RemovedInsts) { if (New) Replacer = new UsesReplacer(Inst, New); LLVM_DEBUG(dbgs() << "Do: InstructionRemover: " << *Inst << "\n"); RemovedInsts.insert(Inst); /// The instructions removed here will be freed after completing /// optimizeBlock() for all blocks as we need to keep track of the /// removed instructions during promotion. Inst->removeFromParent(); } ~InstructionRemover() override { delete Replacer; } /// Resurrect the instruction and reassign it to the proper uses if /// new value was provided when build this action. void undo() override { LLVM_DEBUG(dbgs() << "Undo: InstructionRemover: " << *Inst << "\n"); Inserter.insert(Inst); if (Replacer) Replacer->undo(); Hider.undo(); RemovedInsts.erase(Inst); } }; public: /// Restoration point. /// The restoration point is a pointer to an action instead of an iterator /// because the iterator may be invalidated but not the pointer. using ConstRestorationPt = const TypePromotionAction *; TypePromotionTransaction(SetOfInstrs &RemovedInsts) : RemovedInsts(RemovedInsts) {} /// Advocate every changes made in that transaction. void commit(); /// Undo all the changes made after the given point. void rollback(ConstRestorationPt Point); /// Get the current restoration point. ConstRestorationPt getRestorationPoint() const; /// \name API for IR modification with state keeping to support rollback. /// @{ /// Same as Instruction::setOperand. void setOperand(Instruction *Inst, unsigned Idx, Value *NewVal); /// Same as Instruction::eraseFromParent. void eraseInstruction(Instruction *Inst, Value *NewVal = nullptr); /// Same as Value::replaceAllUsesWith. void replaceAllUsesWith(Instruction *Inst, Value *New); /// Same as Value::mutateType. void mutateType(Instruction *Inst, Type *NewTy); /// Same as IRBuilder::createTrunc. Value *createTrunc(Instruction *Opnd, Type *Ty); /// Same as IRBuilder::createSExt. Value *createSExt(Instruction *Inst, Value *Opnd, Type *Ty); /// Same as IRBuilder::createZExt. Value *createZExt(Instruction *Inst, Value *Opnd, Type *Ty); /// Same as Instruction::moveBefore. void moveBefore(Instruction *Inst, Instruction *Before); /// @} private: /// The ordered list of actions made so far. SmallVector, 16> Actions; using CommitPt = SmallVectorImpl>::iterator; SetOfInstrs &RemovedInsts; }; } // end anonymous namespace void TypePromotionTransaction::setOperand(Instruction *Inst, unsigned Idx, Value *NewVal) { Actions.push_back(llvm::make_unique( Inst, Idx, NewVal)); } void TypePromotionTransaction::eraseInstruction(Instruction *Inst, Value *NewVal) { Actions.push_back( llvm::make_unique( Inst, RemovedInsts, NewVal)); } void TypePromotionTransaction::replaceAllUsesWith(Instruction *Inst, Value *New) { Actions.push_back( llvm::make_unique(Inst, New)); } void TypePromotionTransaction::mutateType(Instruction *Inst, Type *NewTy) { Actions.push_back( llvm::make_unique(Inst, NewTy)); } Value *TypePromotionTransaction::createTrunc(Instruction *Opnd, Type *Ty) { std::unique_ptr Ptr(new TruncBuilder(Opnd, Ty)); Value *Val = Ptr->getBuiltValue(); Actions.push_back(std::move(Ptr)); return Val; } Value *TypePromotionTransaction::createSExt(Instruction *Inst, Value *Opnd, Type *Ty) { std::unique_ptr Ptr(new SExtBuilder(Inst, Opnd, Ty)); Value *Val = Ptr->getBuiltValue(); Actions.push_back(std::move(Ptr)); return Val; } Value *TypePromotionTransaction::createZExt(Instruction *Inst, Value *Opnd, Type *Ty) { std::unique_ptr Ptr(new ZExtBuilder(Inst, Opnd, Ty)); Value *Val = Ptr->getBuiltValue(); Actions.push_back(std::move(Ptr)); return Val; } void TypePromotionTransaction::moveBefore(Instruction *Inst, Instruction *Before) { Actions.push_back( llvm::make_unique( Inst, Before)); } TypePromotionTransaction::ConstRestorationPt TypePromotionTransaction::getRestorationPoint() const { return !Actions.empty() ? Actions.back().get() : nullptr; } void TypePromotionTransaction::commit() { for (CommitPt It = Actions.begin(), EndIt = Actions.end(); It != EndIt; ++It) (*It)->commit(); Actions.clear(); } void TypePromotionTransaction::rollback( TypePromotionTransaction::ConstRestorationPt Point) { while (!Actions.empty() && Point != Actions.back().get()) { std::unique_ptr Curr = Actions.pop_back_val(); Curr->undo(); } } namespace { /// A helper class for matching addressing modes. /// /// This encapsulates the logic for matching the target-legal addressing modes. class AddressingModeMatcher { SmallVectorImpl &AddrModeInsts; const TargetLowering &TLI; const TargetRegisterInfo &TRI; const DataLayout &DL; /// AccessTy/MemoryInst - This is the type for the access (e.g. double) and /// the memory instruction that we're computing this address for. Type *AccessTy; unsigned AddrSpace; Instruction *MemoryInst; /// This is the addressing mode that we're building up. This is /// part of the return value of this addressing mode matching stuff. ExtAddrMode &AddrMode; /// The instructions inserted by other CodeGenPrepare optimizations. const SetOfInstrs &InsertedInsts; /// A map from the instructions to their type before promotion. InstrToOrigTy &PromotedInsts; /// The ongoing transaction where every action should be registered. TypePromotionTransaction &TPT; // A GEP which has too large offset to be folded into the addressing mode. std::pair, int64_t> &LargeOffsetGEP; /// This is set to true when we should not do profitability checks. /// When true, IsProfitableToFoldIntoAddressingMode always returns true. bool IgnoreProfitability; AddressingModeMatcher( SmallVectorImpl &AMI, const TargetLowering &TLI, const TargetRegisterInfo &TRI, Type *AT, unsigned AS, Instruction *MI, ExtAddrMode &AM, const SetOfInstrs &InsertedInsts, InstrToOrigTy &PromotedInsts, TypePromotionTransaction &TPT, std::pair, int64_t> &LargeOffsetGEP) : AddrModeInsts(AMI), TLI(TLI), TRI(TRI), DL(MI->getModule()->getDataLayout()), AccessTy(AT), AddrSpace(AS), MemoryInst(MI), AddrMode(AM), InsertedInsts(InsertedInsts), PromotedInsts(PromotedInsts), TPT(TPT), LargeOffsetGEP(LargeOffsetGEP) { IgnoreProfitability = false; } public: /// Find the maximal addressing mode that a load/store of V can fold, /// give an access type of AccessTy. This returns a list of involved /// instructions in AddrModeInsts. /// \p InsertedInsts The instructions inserted by other CodeGenPrepare /// optimizations. /// \p PromotedInsts maps the instructions to their type before promotion. /// \p The ongoing transaction where every action should be registered. static ExtAddrMode Match(Value *V, Type *AccessTy, unsigned AS, Instruction *MemoryInst, SmallVectorImpl &AddrModeInsts, const TargetLowering &TLI, const TargetRegisterInfo &TRI, const SetOfInstrs &InsertedInsts, InstrToOrigTy &PromotedInsts, TypePromotionTransaction &TPT, std::pair, int64_t> &LargeOffsetGEP) { ExtAddrMode Result; bool Success = AddressingModeMatcher(AddrModeInsts, TLI, TRI, AccessTy, AS, MemoryInst, Result, InsertedInsts, PromotedInsts, TPT, LargeOffsetGEP) .matchAddr(V, 0); (void)Success; assert(Success && "Couldn't select *anything*?"); return Result; } private: bool matchScaledValue(Value *ScaleReg, int64_t Scale, unsigned Depth); bool matchAddr(Value *Addr, unsigned Depth); bool matchOperationAddr(User *AddrInst, unsigned Opcode, unsigned Depth, bool *MovedAway = nullptr); bool isProfitableToFoldIntoAddressingMode(Instruction *I, ExtAddrMode &AMBefore, ExtAddrMode &AMAfter); bool valueAlreadyLiveAtInst(Value *Val, Value *KnownLive1, Value *KnownLive2); bool isPromotionProfitable(unsigned NewCost, unsigned OldCost, Value *PromotedOperand) const; }; /// Keep track of simplification of Phi nodes. /// Accept the set of all phi nodes and erase phi node from this set /// if it is simplified. class SimplificationTracker { DenseMap Storage; const SimplifyQuery &SQ; // Tracks newly created Phi nodes. We use a SetVector to get deterministic // order when iterating over the set in MatchPhiSet. SmallSetVector AllPhiNodes; // Tracks newly created Select nodes. SmallPtrSet AllSelectNodes; public: SimplificationTracker(const SimplifyQuery &sq) : SQ(sq) {} Value *Get(Value *V) { do { auto SV = Storage.find(V); if (SV == Storage.end()) return V; V = SV->second; } while (true); } Value *Simplify(Value *Val) { SmallVector WorkList; SmallPtrSet Visited; WorkList.push_back(Val); while (!WorkList.empty()) { auto P = WorkList.pop_back_val(); if (!Visited.insert(P).second) continue; if (auto *PI = dyn_cast(P)) if (Value *V = SimplifyInstruction(cast(PI), SQ)) { for (auto *U : PI->users()) WorkList.push_back(cast(U)); Put(PI, V); PI->replaceAllUsesWith(V); if (auto *PHI = dyn_cast(PI)) AllPhiNodes.remove(PHI); if (auto *Select = dyn_cast(PI)) AllSelectNodes.erase(Select); PI->eraseFromParent(); } } return Get(Val); } void Put(Value *From, Value *To) { Storage.insert({ From, To }); } void ReplacePhi(PHINode *From, PHINode *To) { Value* OldReplacement = Get(From); while (OldReplacement != From) { From = To; To = dyn_cast(OldReplacement); OldReplacement = Get(From); } assert(Get(To) == To && "Replacement PHI node is already replaced."); Put(From, To); From->replaceAllUsesWith(To); AllPhiNodes.remove(From); From->eraseFromParent(); } SmallSetVector& newPhiNodes() { return AllPhiNodes; } void insertNewPhi(PHINode *PN) { AllPhiNodes.insert(PN); } void insertNewSelect(SelectInst *SI) { AllSelectNodes.insert(SI); } unsigned countNewPhiNodes() const { return AllPhiNodes.size(); } unsigned countNewSelectNodes() const { return AllSelectNodes.size(); } void destroyNewNodes(Type *CommonType) { // For safe erasing, replace the uses with dummy value first. auto Dummy = UndefValue::get(CommonType); for (auto I : AllPhiNodes) { I->replaceAllUsesWith(Dummy); I->eraseFromParent(); } AllPhiNodes.clear(); for (auto I : AllSelectNodes) { I->replaceAllUsesWith(Dummy); I->eraseFromParent(); } AllSelectNodes.clear(); } }; /// A helper class for combining addressing modes. class AddressingModeCombiner { typedef std::pair ValueInBB; typedef DenseMap FoldAddrToValueMapping; typedef std::pair PHIPair; private: /// The addressing modes we've collected. SmallVector AddrModes; /// The field in which the AddrModes differ, when we have more than one. ExtAddrMode::FieldName DifferentField = ExtAddrMode::NoField; /// Are the AddrModes that we have all just equal to their original values? bool AllAddrModesTrivial = true; /// Common Type for all different fields in addressing modes. Type *CommonType; /// SimplifyQuery for simplifyInstruction utility. const SimplifyQuery &SQ; /// Original Address. ValueInBB Original; public: AddressingModeCombiner(const SimplifyQuery &_SQ, ValueInBB OriginalValue) : CommonType(nullptr), SQ(_SQ), Original(OriginalValue) {} /// Get the combined AddrMode const ExtAddrMode &getAddrMode() const { return AddrModes[0]; } /// Add a new AddrMode if it's compatible with the AddrModes we already /// have. /// \return True iff we succeeded in doing so. bool addNewAddrMode(ExtAddrMode &NewAddrMode) { // Take note of if we have any non-trivial AddrModes, as we need to detect // when all AddrModes are trivial as then we would introduce a phi or select // which just duplicates what's already there. AllAddrModesTrivial = AllAddrModesTrivial && NewAddrMode.isTrivial(); // If this is the first addrmode then everything is fine. if (AddrModes.empty()) { AddrModes.emplace_back(NewAddrMode); return true; } // Figure out how different this is from the other address modes, which we // can do just by comparing against the first one given that we only care // about the cumulative difference. ExtAddrMode::FieldName ThisDifferentField = AddrModes[0].compare(NewAddrMode); if (DifferentField == ExtAddrMode::NoField) DifferentField = ThisDifferentField; else if (DifferentField != ThisDifferentField) DifferentField = ExtAddrMode::MultipleFields; // If NewAddrMode differs in more than one dimension we cannot handle it. bool CanHandle = DifferentField != ExtAddrMode::MultipleFields; // If Scale Field is different then we reject. CanHandle = CanHandle && DifferentField != ExtAddrMode::ScaleField; // We also must reject the case when base offset is different and // scale reg is not null, we cannot handle this case due to merge of // different offsets will be used as ScaleReg. CanHandle = CanHandle && (DifferentField != ExtAddrMode::BaseOffsField || !NewAddrMode.ScaledReg); // We also must reject the case when GV is different and BaseReg installed // due to we want to use base reg as a merge of GV values. CanHandle = CanHandle && (DifferentField != ExtAddrMode::BaseGVField || !NewAddrMode.HasBaseReg); // Even if NewAddMode is the same we still need to collect it due to // original value is different. And later we will need all original values // as anchors during finding the common Phi node. if (CanHandle) AddrModes.emplace_back(NewAddrMode); else AddrModes.clear(); return CanHandle; } /// Combine the addressing modes we've collected into a single /// addressing mode. /// \return True iff we successfully combined them or we only had one so /// didn't need to combine them anyway. bool combineAddrModes() { // If we have no AddrModes then they can't be combined. if (AddrModes.size() == 0) return false; // A single AddrMode can trivially be combined. if (AddrModes.size() == 1 || DifferentField == ExtAddrMode::NoField) return true; // If the AddrModes we collected are all just equal to the value they are // derived from then combining them wouldn't do anything useful. if (AllAddrModesTrivial) return false; if (!addrModeCombiningAllowed()) return false; // Build a map between to // value of base register. // Bail out if there is no common type. FoldAddrToValueMapping Map; if (!initializeMap(Map)) return false; Value *CommonValue = findCommon(Map); if (CommonValue) AddrModes[0].SetCombinedField(DifferentField, CommonValue, AddrModes); return CommonValue != nullptr; } private: /// Initialize Map with anchor values. For address seen in some BB /// we set the value of different field saw in this address. /// If address is not an instruction than basic block is set to null. /// At the same time we find a common type for different field we will /// use to create new Phi/Select nodes. Keep it in CommonType field. /// Return false if there is no common type found. bool initializeMap(FoldAddrToValueMapping &Map) { // Keep track of keys where the value is null. We will need to replace it // with constant null when we know the common type. SmallVector NullValue; Type *IntPtrTy = SQ.DL.getIntPtrType(AddrModes[0].OriginalValue->getType()); for (auto &AM : AddrModes) { BasicBlock *BB = nullptr; if (Instruction *I = dyn_cast(AM.OriginalValue)) BB = I->getParent(); Value *DV = AM.GetFieldAsValue(DifferentField, IntPtrTy); if (DV) { auto *Type = DV->getType(); if (CommonType && CommonType != Type) return false; CommonType = Type; Map[{ AM.OriginalValue, BB }] = DV; } else { NullValue.push_back({ AM.OriginalValue, BB }); } } assert(CommonType && "At least one non-null value must be!"); for (auto VIBB : NullValue) Map[VIBB] = Constant::getNullValue(CommonType); return true; } /// We have mapping between value A and basic block where value A /// seen to other value B where B was a field in addressing mode represented /// by A. Also we have an original value C representing an address in some /// basic block. Traversing from C through phi and selects we ended up with /// A's in a map. This utility function tries to find a value V which is a /// field in addressing mode C and traversing through phi nodes and selects /// we will end up in corresponded values B in a map. /// The utility will create a new Phi/Selects if needed. // The simple example looks as follows: // BB1: // p1 = b1 + 40 // br cond BB2, BB3 // BB2: // p2 = b2 + 40 // br BB3 // BB3: // p = phi [p1, BB1], [p2, BB2] // v = load p // Map is // -> b1 // -> b2 // Request is // -> ? // The function tries to find or build phi [b1, BB1], [b2, BB2] in BB3 Value *findCommon(FoldAddrToValueMapping &Map) { // Tracks the simplification of newly created phi nodes. The reason we use // this mapping is because we will add new created Phi nodes in AddrToBase. // Simplification of Phi nodes is recursive, so some Phi node may // be simplified after we added it to AddrToBase. // Using this mapping we can find the current value in AddrToBase. SimplificationTracker ST(SQ); // First step, DFS to create PHI nodes for all intermediate blocks. // Also fill traverse order for the second step. SmallVector TraverseOrder; InsertPlaceholders(Map, TraverseOrder, ST); // Second Step, fill new nodes by merged values and simplify if possible. FillPlaceholders(Map, TraverseOrder, ST); if (!AddrSinkNewSelects && ST.countNewSelectNodes() > 0) { ST.destroyNewNodes(CommonType); return nullptr; } // Now we'd like to match New Phi nodes to existed ones. unsigned PhiNotMatchedCount = 0; if (!MatchPhiSet(ST, AddrSinkNewPhis, PhiNotMatchedCount)) { ST.destroyNewNodes(CommonType); return nullptr; } auto *Result = ST.Get(Map.find(Original)->second); if (Result) { NumMemoryInstsPhiCreated += ST.countNewPhiNodes() + PhiNotMatchedCount; NumMemoryInstsSelectCreated += ST.countNewSelectNodes(); } return Result; } /// Try to match PHI node to Candidate. /// Matcher tracks the matched Phi nodes. bool MatchPhiNode(PHINode *PHI, PHINode *Candidate, SmallSetVector &Matcher, SmallSetVector &PhiNodesToMatch) { SmallVector WorkList; Matcher.insert({ PHI, Candidate }); WorkList.push_back({ PHI, Candidate }); SmallSet Visited; while (!WorkList.empty()) { auto Item = WorkList.pop_back_val(); if (!Visited.insert(Item).second) continue; // We iterate over all incoming values to Phi to compare them. // If values are different and both of them Phi and the first one is a // Phi we added (subject to match) and both of them is in the same basic // block then we can match our pair if values match. So we state that // these values match and add it to work list to verify that. for (auto B : Item.first->blocks()) { Value *FirstValue = Item.first->getIncomingValueForBlock(B); Value *SecondValue = Item.second->getIncomingValueForBlock(B); if (FirstValue == SecondValue) continue; PHINode *FirstPhi = dyn_cast(FirstValue); PHINode *SecondPhi = dyn_cast(SecondValue); // One of them is not Phi or // The first one is not Phi node from the set we'd like to match or // Phi nodes from different basic blocks then // we will not be able to match. if (!FirstPhi || !SecondPhi || !PhiNodesToMatch.count(FirstPhi) || FirstPhi->getParent() != SecondPhi->getParent()) return false; // If we already matched them then continue. if (Matcher.count({ FirstPhi, SecondPhi })) continue; // So the values are different and does not match. So we need them to // match. Matcher.insert({ FirstPhi, SecondPhi }); // But me must check it. WorkList.push_back({ FirstPhi, SecondPhi }); } } return true; } /// For the given set of PHI nodes (in the SimplificationTracker) try /// to find their equivalents. /// Returns false if this matching fails and creation of new Phi is disabled. bool MatchPhiSet(SimplificationTracker &ST, bool AllowNewPhiNodes, unsigned &PhiNotMatchedCount) { // Use a SetVector for Matched to make sure we do replacements (ReplacePhi) // in a deterministic order below. SmallSetVector Matched; SmallPtrSet WillNotMatch; SmallSetVector &PhiNodesToMatch = ST.newPhiNodes(); while (PhiNodesToMatch.size()) { PHINode *PHI = *PhiNodesToMatch.begin(); // Add us, if no Phi nodes in the basic block we do not match. WillNotMatch.clear(); WillNotMatch.insert(PHI); // Traverse all Phis until we found equivalent or fail to do that. bool IsMatched = false; for (auto &P : PHI->getParent()->phis()) { if (&P == PHI) continue; if ((IsMatched = MatchPhiNode(PHI, &P, Matched, PhiNodesToMatch))) break; // If it does not match, collect all Phi nodes from matcher. // if we end up with no match, them all these Phi nodes will not match // later. for (auto M : Matched) WillNotMatch.insert(M.first); Matched.clear(); } if (IsMatched) { // Replace all matched values and erase them. for (auto MV : Matched) ST.ReplacePhi(MV.first, MV.second); Matched.clear(); continue; } // If we are not allowed to create new nodes then bail out. if (!AllowNewPhiNodes) return false; // Just remove all seen values in matcher. They will not match anything. PhiNotMatchedCount += WillNotMatch.size(); for (auto *P : WillNotMatch) PhiNodesToMatch.remove(P); } return true; } /// Fill the placeholder with values from predecessors and simplify it. void FillPlaceholders(FoldAddrToValueMapping &Map, SmallVectorImpl &TraverseOrder, SimplificationTracker &ST) { while (!TraverseOrder.empty()) { auto Current = TraverseOrder.pop_back_val(); assert(Map.find(Current) != Map.end() && "No node to fill!!!"); Value *CurrentValue = Current.first; BasicBlock *CurrentBlock = Current.second; Value *V = Map[Current]; if (SelectInst *Select = dyn_cast(V)) { // CurrentValue also must be Select. auto *CurrentSelect = cast(CurrentValue); auto *TrueValue = CurrentSelect->getTrueValue(); ValueInBB TrueItem = { TrueValue, isa(TrueValue) ? CurrentBlock : nullptr }; assert(Map.find(TrueItem) != Map.end() && "No True Value!"); Select->setTrueValue(ST.Get(Map[TrueItem])); auto *FalseValue = CurrentSelect->getFalseValue(); ValueInBB FalseItem = { FalseValue, isa(FalseValue) ? CurrentBlock : nullptr }; assert(Map.find(FalseItem) != Map.end() && "No False Value!"); Select->setFalseValue(ST.Get(Map[FalseItem])); } else { // Must be a Phi node then. PHINode *PHI = cast(V); // Fill the Phi node with values from predecessors. bool IsDefinedInThisBB = cast(CurrentValue)->getParent() == CurrentBlock; auto *CurrentPhi = dyn_cast(CurrentValue); for (auto B : predecessors(CurrentBlock)) { Value *PV = IsDefinedInThisBB ? CurrentPhi->getIncomingValueForBlock(B) : CurrentValue; ValueInBB item = { PV, isa(PV) ? B : nullptr }; assert(Map.find(item) != Map.end() && "No predecessor Value!"); PHI->addIncoming(ST.Get(Map[item]), B); } } // Simplify if possible. Map[Current] = ST.Simplify(V); } } /// Starting from value recursively iterates over predecessors up to known /// ending values represented in a map. For each traversed block inserts /// a placeholder Phi or Select. /// Reports all new created Phi/Select nodes by adding them to set. /// Also reports and order in what basic blocks have been traversed. void InsertPlaceholders(FoldAddrToValueMapping &Map, SmallVectorImpl &TraverseOrder, SimplificationTracker &ST) { SmallVector Worklist; assert((isa(Original.first) || isa(Original.first)) && "Address must be a Phi or Select node"); auto *Dummy = UndefValue::get(CommonType); Worklist.push_back(Original); while (!Worklist.empty()) { auto Current = Worklist.pop_back_val(); // If value is not an instruction it is something global, constant, // parameter and we can say that this value is observable in any block. // Set block to null to denote it. // Also please take into account that it is how we build anchors. if (!isa(Current.first)) Current.second = nullptr; // if it is already visited or it is an ending value then skip it. if (Map.find(Current) != Map.end()) continue; TraverseOrder.push_back(Current); Value *CurrentValue = Current.first; BasicBlock *CurrentBlock = Current.second; // CurrentValue must be a Phi node or select. All others must be covered // by anchors. Instruction *CurrentI = cast(CurrentValue); bool IsDefinedInThisBB = CurrentI->getParent() == CurrentBlock; unsigned PredCount = pred_size(CurrentBlock); // if Current Value is not defined in this basic block we are interested // in values in predecessors. if (!IsDefinedInThisBB) { assert(PredCount && "Unreachable block?!"); PHINode *PHI = PHINode::Create(CommonType, PredCount, "sunk_phi", &CurrentBlock->front()); Map[Current] = PHI; ST.insertNewPhi(PHI); // Add all predecessors in work list. for (auto B : predecessors(CurrentBlock)) Worklist.push_back({ CurrentValue, B }); continue; } // Value is defined in this basic block. if (SelectInst *OrigSelect = dyn_cast(CurrentI)) { // Is it OK to get metadata from OrigSelect?! // Create a Select placeholder with dummy value. SelectInst *Select = SelectInst::Create(OrigSelect->getCondition(), Dummy, Dummy, OrigSelect->getName(), OrigSelect, OrigSelect); Map[Current] = Select; ST.insertNewSelect(Select); // We are interested in True and False value in this basic block. Worklist.push_back({ OrigSelect->getTrueValue(), CurrentBlock }); Worklist.push_back({ OrigSelect->getFalseValue(), CurrentBlock }); } else { // It must be a Phi node then. auto *CurrentPhi = cast(CurrentI); // Create new Phi node for merge of bases. assert(PredCount && "Unreachable block?!"); PHINode *PHI = PHINode::Create(CommonType, PredCount, "sunk_phi", &CurrentBlock->front()); Map[Current] = PHI; ST.insertNewPhi(PHI); // Add all predecessors in work list. for (auto B : predecessors(CurrentBlock)) Worklist.push_back({ CurrentPhi->getIncomingValueForBlock(B), B }); } } } bool addrModeCombiningAllowed() { if (DisableComplexAddrModes) return false; switch (DifferentField) { default: return false; case ExtAddrMode::BaseRegField: return AddrSinkCombineBaseReg; case ExtAddrMode::BaseGVField: return AddrSinkCombineBaseGV; case ExtAddrMode::BaseOffsField: return AddrSinkCombineBaseOffs; case ExtAddrMode::ScaledRegField: return AddrSinkCombineScaledReg; } } }; } // end anonymous namespace /// Try adding ScaleReg*Scale to the current addressing mode. /// Return true and update AddrMode if this addr mode is legal for the target, /// false if not. bool AddressingModeMatcher::matchScaledValue(Value *ScaleReg, int64_t Scale, unsigned Depth) { // If Scale is 1, then this is the same as adding ScaleReg to the addressing // mode. Just process that directly. if (Scale == 1) return matchAddr(ScaleReg, Depth); // If the scale is 0, it takes nothing to add this. if (Scale == 0) return true; // If we already have a scale of this value, we can add to it, otherwise, we // need an available scale field. if (AddrMode.Scale != 0 && AddrMode.ScaledReg != ScaleReg) return false; ExtAddrMode TestAddrMode = AddrMode; // Add scale to turn X*4+X*3 -> X*7. This could also do things like // [A+B + A*7] -> [B+A*8]. TestAddrMode.Scale += Scale; TestAddrMode.ScaledReg = ScaleReg; // If the new address isn't legal, bail out. if (!TLI.isLegalAddressingMode(DL, TestAddrMode, AccessTy, AddrSpace)) return false; // It was legal, so commit it. AddrMode = TestAddrMode; // Okay, we decided that we can add ScaleReg+Scale to AddrMode. Check now // to see if ScaleReg is actually X+C. If so, we can turn this into adding // X*Scale + C*Scale to addr mode. ConstantInt *CI = nullptr; Value *AddLHS = nullptr; if (isa(ScaleReg) && // not a constant expr. match(ScaleReg, m_Add(m_Value(AddLHS), m_ConstantInt(CI)))) { TestAddrMode.ScaledReg = AddLHS; TestAddrMode.BaseOffs += CI->getSExtValue()*TestAddrMode.Scale; // If this addressing mode is legal, commit it and remember that we folded // this instruction. if (TLI.isLegalAddressingMode(DL, TestAddrMode, AccessTy, AddrSpace)) { AddrModeInsts.push_back(cast(ScaleReg)); AddrMode = TestAddrMode; return true; } } // Otherwise, not (x+c)*scale, just return what we have. return true; } /// This is a little filter, which returns true if an addressing computation /// involving I might be folded into a load/store accessing it. /// This doesn't need to be perfect, but needs to accept at least /// the set of instructions that MatchOperationAddr can. static bool MightBeFoldableInst(Instruction *I) { switch (I->getOpcode()) { case Instruction::BitCast: case Instruction::AddrSpaceCast: // Don't touch identity bitcasts. if (I->getType() == I->getOperand(0)->getType()) return false; return I->getType()->isIntOrPtrTy(); case Instruction::PtrToInt: // PtrToInt is always a noop, as we know that the int type is pointer sized. return true; case Instruction::IntToPtr: // We know the input is intptr_t, so this is foldable. return true; case Instruction::Add: return true; case Instruction::Mul: case Instruction::Shl: // Can only handle X*C and X << C. return isa(I->getOperand(1)); case Instruction::GetElementPtr: return true; default: return false; } } /// Check whether or not \p Val is a legal instruction for \p TLI. /// \note \p Val is assumed to be the product of some type promotion. /// Therefore if \p Val has an undefined state in \p TLI, this is assumed /// to be legal, as the non-promoted value would have had the same state. static bool isPromotedInstructionLegal(const TargetLowering &TLI, const DataLayout &DL, Value *Val) { Instruction *PromotedInst = dyn_cast(Val); if (!PromotedInst) return false; int ISDOpcode = TLI.InstructionOpcodeToISD(PromotedInst->getOpcode()); // If the ISDOpcode is undefined, it was undefined before the promotion. if (!ISDOpcode) return true; // Otherwise, check if the promoted instruction is legal or not. return TLI.isOperationLegalOrCustom( ISDOpcode, TLI.getValueType(DL, PromotedInst->getType())); } namespace { /// Hepler class to perform type promotion. class TypePromotionHelper { + /// Utility function to add a promoted instruction \p ExtOpnd to + /// \p PromotedInsts and record the type of extension we have seen. + static void addPromotedInst(InstrToOrigTy &PromotedInsts, + Instruction *ExtOpnd, + bool IsSExt) { + ExtType ExtTy = IsSExt ? SignExtension : ZeroExtension; + InstrToOrigTy::iterator It = PromotedInsts.find(ExtOpnd); + if (It != PromotedInsts.end()) { + // If the new extension is same as original, the information in + // PromotedInsts[ExtOpnd] is still correct. + if (It->second.getInt() == ExtTy) + return; + + // Now the new extension is different from old extension, we make + // the type information invalid by setting extension type to + // BothExtension. + ExtTy = BothExtension; + } + PromotedInsts[ExtOpnd] = TypeIsSExt(ExtOpnd->getType(), ExtTy); + } + + /// Utility function to query the original type of instruction \p Opnd + /// with a matched extension type. If the extension doesn't match, we + /// cannot use the information we had on the original type. + /// BothExtension doesn't match any extension type. + static const Type *getOrigType(const InstrToOrigTy &PromotedInsts, + Instruction *Opnd, + bool IsSExt) { + ExtType ExtTy = IsSExt ? SignExtension : ZeroExtension; + InstrToOrigTy::const_iterator It = PromotedInsts.find(Opnd); + if (It != PromotedInsts.end() && It->second.getInt() == ExtTy) + return It->second.getPointer(); + return nullptr; + } + /// Utility function to check whether or not a sign or zero extension /// of \p Inst with \p ConsideredExtType can be moved through \p Inst by /// either using the operands of \p Inst or promoting \p Inst. /// The type of the extension is defined by \p IsSExt. /// In other words, check if: /// ext (Ty Inst opnd1 opnd2 ... opndN) to ConsideredExtType. /// #1 Promotion applies: /// ConsideredExtType Inst (ext opnd1 to ConsideredExtType, ...). /// #2 Operand reuses: /// ext opnd1 to ConsideredExtType. /// \p PromotedInsts maps the instructions to their type before promotion. static bool canGetThrough(const Instruction *Inst, Type *ConsideredExtType, const InstrToOrigTy &PromotedInsts, bool IsSExt); /// Utility function to determine if \p OpIdx should be promoted when /// promoting \p Inst. static bool shouldExtOperand(const Instruction *Inst, int OpIdx) { return !(isa(Inst) && OpIdx == 0); } /// Utility function to promote the operand of \p Ext when this /// operand is a promotable trunc or sext or zext. /// \p PromotedInsts maps the instructions to their type before promotion. /// \p CreatedInstsCost[out] contains the cost of all instructions /// created to promote the operand of Ext. /// Newly added extensions are inserted in \p Exts. /// Newly added truncates are inserted in \p Truncs. /// Should never be called directly. /// \return The promoted value which is used instead of Ext. static Value *promoteOperandForTruncAndAnyExt( Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI); /// Utility function to promote the operand of \p Ext when this /// operand is promotable and is not a supported trunc or sext. /// \p PromotedInsts maps the instructions to their type before promotion. /// \p CreatedInstsCost[out] contains the cost of all the instructions /// created to promote the operand of Ext. /// Newly added extensions are inserted in \p Exts. /// Newly added truncates are inserted in \p Truncs. /// Should never be called directly. /// \return The promoted value which is used instead of Ext. static Value *promoteOperandForOther(Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI, bool IsSExt); /// \see promoteOperandForOther. static Value *signExtendOperandForOther( Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI) { return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost, Exts, Truncs, TLI, true); } /// \see promoteOperandForOther. static Value *zeroExtendOperandForOther( Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI) { return promoteOperandForOther(Ext, TPT, PromotedInsts, CreatedInstsCost, Exts, Truncs, TLI, false); } public: /// Type for the utility function that promotes the operand of Ext. using Action = Value *(*)(Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI); /// Given a sign/zero extend instruction \p Ext, return the appropriate /// action to promote the operand of \p Ext instead of using Ext. /// \return NULL if no promotable action is possible with the current /// sign extension. /// \p InsertedInsts keeps track of all the instructions inserted by the /// other CodeGenPrepare optimizations. This information is important /// because we do not want to promote these instructions as CodeGenPrepare /// will reinsert them later. Thus creating an infinite loop: create/remove. /// \p PromotedInsts maps the instructions to their type before promotion. static Action getAction(Instruction *Ext, const SetOfInstrs &InsertedInsts, const TargetLowering &TLI, const InstrToOrigTy &PromotedInsts); }; } // end anonymous namespace bool TypePromotionHelper::canGetThrough(const Instruction *Inst, Type *ConsideredExtType, const InstrToOrigTy &PromotedInsts, bool IsSExt) { // The promotion helper does not know how to deal with vector types yet. // To be able to fix that, we would need to fix the places where we // statically extend, e.g., constants and such. if (Inst->getType()->isVectorTy()) return false; // We can always get through zext. if (isa(Inst)) return true; // sext(sext) is ok too. if (IsSExt && isa(Inst)) return true; // We can get through binary operator, if it is legal. In other words, the // binary operator must have a nuw or nsw flag. const BinaryOperator *BinOp = dyn_cast(Inst); if (BinOp && isa(BinOp) && ((!IsSExt && BinOp->hasNoUnsignedWrap()) || (IsSExt && BinOp->hasNoSignedWrap()))) return true; // ext(and(opnd, cst)) --> and(ext(opnd), ext(cst)) if ((Inst->getOpcode() == Instruction::And || Inst->getOpcode() == Instruction::Or)) return true; // ext(xor(opnd, cst)) --> xor(ext(opnd), ext(cst)) if (Inst->getOpcode() == Instruction::Xor) { const ConstantInt *Cst = dyn_cast(Inst->getOperand(1)); // Make sure it is not a NOT. if (Cst && !Cst->getValue().isAllOnesValue()) return true; } // zext(shrl(opnd, cst)) --> shrl(zext(opnd), zext(cst)) // It may change a poisoned value into a regular value, like // zext i32 (shrl i8 %val, 12) --> shrl i32 (zext i8 %val), 12 // poisoned value regular value // It should be OK since undef covers valid value. if (Inst->getOpcode() == Instruction::LShr && !IsSExt) return true; // and(ext(shl(opnd, cst)), cst) --> and(shl(ext(opnd), ext(cst)), cst) // It may change a poisoned value into a regular value, like // zext i32 (shl i8 %val, 12) --> shl i32 (zext i8 %val), 12 // poisoned value regular value // It should be OK since undef covers valid value. if (Inst->getOpcode() == Instruction::Shl && Inst->hasOneUse()) { const Instruction *ExtInst = dyn_cast(*Inst->user_begin()); if (ExtInst->hasOneUse()) { const Instruction *AndInst = dyn_cast(*ExtInst->user_begin()); if (AndInst && AndInst->getOpcode() == Instruction::And) { const ConstantInt *Cst = dyn_cast(AndInst->getOperand(1)); if (Cst && Cst->getValue().isIntN(Inst->getType()->getIntegerBitWidth())) return true; } } } // Check if we can do the following simplification. // ext(trunc(opnd)) --> ext(opnd) if (!isa(Inst)) return false; Value *OpndVal = Inst->getOperand(0); // Check if we can use this operand in the extension. // If the type is larger than the result type of the extension, we cannot. if (!OpndVal->getType()->isIntegerTy() || OpndVal->getType()->getIntegerBitWidth() > ConsideredExtType->getIntegerBitWidth()) return false; // If the operand of the truncate is not an instruction, we will not have // any information on the dropped bits. // (Actually we could for constant but it is not worth the extra logic). Instruction *Opnd = dyn_cast(OpndVal); if (!Opnd) return false; // Check if the source of the type is narrow enough. // I.e., check that trunc just drops extended bits of the same kind of // the extension. // #1 get the type of the operand and check the kind of the extended bits. - const Type *OpndType; - InstrToOrigTy::const_iterator It = PromotedInsts.find(Opnd); - if (It != PromotedInsts.end() && It->second.getInt() == IsSExt) - OpndType = It->second.getPointer(); + const Type *OpndType = getOrigType(PromotedInsts, Opnd, IsSExt); + if (OpndType) + ; else if ((IsSExt && isa(Opnd)) || (!IsSExt && isa(Opnd))) OpndType = Opnd->getOperand(0)->getType(); else return false; // #2 check that the truncate just drops extended bits. return Inst->getType()->getIntegerBitWidth() >= OpndType->getIntegerBitWidth(); } TypePromotionHelper::Action TypePromotionHelper::getAction( Instruction *Ext, const SetOfInstrs &InsertedInsts, const TargetLowering &TLI, const InstrToOrigTy &PromotedInsts) { assert((isa(Ext) || isa(Ext)) && "Unexpected instruction type"); Instruction *ExtOpnd = dyn_cast(Ext->getOperand(0)); Type *ExtTy = Ext->getType(); bool IsSExt = isa(Ext); // If the operand of the extension is not an instruction, we cannot // get through. // If it, check we can get through. if (!ExtOpnd || !canGetThrough(ExtOpnd, ExtTy, PromotedInsts, IsSExt)) return nullptr; // Do not promote if the operand has been added by codegenprepare. // Otherwise, it means we are undoing an optimization that is likely to be // redone, thus causing potential infinite loop. if (isa(ExtOpnd) && InsertedInsts.count(ExtOpnd)) return nullptr; // SExt or Trunc instructions. // Return the related handler. if (isa(ExtOpnd) || isa(ExtOpnd) || isa(ExtOpnd)) return promoteOperandForTruncAndAnyExt; // Regular instruction. // Abort early if we will have to insert non-free instructions. if (!ExtOpnd->hasOneUse() && !TLI.isTruncateFree(ExtTy, ExtOpnd->getType())) return nullptr; return IsSExt ? signExtendOperandForOther : zeroExtendOperandForOther; } Value *TypePromotionHelper::promoteOperandForTruncAndAnyExt( Instruction *SExt, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI) { // By construction, the operand of SExt is an instruction. Otherwise we cannot // get through it and this method should not be called. Instruction *SExtOpnd = cast(SExt->getOperand(0)); Value *ExtVal = SExt; bool HasMergedNonFreeExt = false; if (isa(SExtOpnd)) { // Replace s|zext(zext(opnd)) // => zext(opnd). HasMergedNonFreeExt = !TLI.isExtFree(SExtOpnd); Value *ZExt = TPT.createZExt(SExt, SExtOpnd->getOperand(0), SExt->getType()); TPT.replaceAllUsesWith(SExt, ZExt); TPT.eraseInstruction(SExt); ExtVal = ZExt; } else { // Replace z|sext(trunc(opnd)) or sext(sext(opnd)) // => z|sext(opnd). TPT.setOperand(SExt, 0, SExtOpnd->getOperand(0)); } CreatedInstsCost = 0; // Remove dead code. if (SExtOpnd->use_empty()) TPT.eraseInstruction(SExtOpnd); // Check if the extension is still needed. Instruction *ExtInst = dyn_cast(ExtVal); if (!ExtInst || ExtInst->getType() != ExtInst->getOperand(0)->getType()) { if (ExtInst) { if (Exts) Exts->push_back(ExtInst); CreatedInstsCost = !TLI.isExtFree(ExtInst) && !HasMergedNonFreeExt; } return ExtVal; } // At this point we have: ext ty opnd to ty. // Reassign the uses of ExtInst to the opnd and remove ExtInst. Value *NextVal = ExtInst->getOperand(0); TPT.eraseInstruction(ExtInst, NextVal); return NextVal; } Value *TypePromotionHelper::promoteOperandForOther( Instruction *Ext, TypePromotionTransaction &TPT, InstrToOrigTy &PromotedInsts, unsigned &CreatedInstsCost, SmallVectorImpl *Exts, SmallVectorImpl *Truncs, const TargetLowering &TLI, bool IsSExt) { // By construction, the operand of Ext is an instruction. Otherwise we cannot // get through it and this method should not be called. Instruction *ExtOpnd = cast(Ext->getOperand(0)); CreatedInstsCost = 0; if (!ExtOpnd->hasOneUse()) { // ExtOpnd will be promoted. // All its uses, but Ext, will need to use a truncated value of the // promoted version. // Create the truncate now. Value *Trunc = TPT.createTrunc(Ext, ExtOpnd->getType()); if (Instruction *ITrunc = dyn_cast(Trunc)) { // Insert it just after the definition. ITrunc->moveAfter(ExtOpnd); if (Truncs) Truncs->push_back(ITrunc); } TPT.replaceAllUsesWith(ExtOpnd, Trunc); // Restore the operand of Ext (which has been replaced by the previous call // to replaceAllUsesWith) to avoid creating a cycle trunc <-> sext. TPT.setOperand(Ext, 0, ExtOpnd); } // Get through the Instruction: // 1. Update its type. // 2. Replace the uses of Ext by Inst. // 3. Extend each operand that needs to be extended. // Remember the original type of the instruction before promotion. // This is useful to know that the high bits are sign extended bits. - PromotedInsts.insert(std::pair( - ExtOpnd, TypeIsSExt(ExtOpnd->getType(), IsSExt))); + addPromotedInst(PromotedInsts, ExtOpnd, IsSExt); // Step #1. TPT.mutateType(ExtOpnd, Ext->getType()); // Step #2. TPT.replaceAllUsesWith(Ext, ExtOpnd); // Step #3. Instruction *ExtForOpnd = Ext; LLVM_DEBUG(dbgs() << "Propagate Ext to operands\n"); for (int OpIdx = 0, EndOpIdx = ExtOpnd->getNumOperands(); OpIdx != EndOpIdx; ++OpIdx) { LLVM_DEBUG(dbgs() << "Operand:\n" << *(ExtOpnd->getOperand(OpIdx)) << '\n'); if (ExtOpnd->getOperand(OpIdx)->getType() == Ext->getType() || !shouldExtOperand(ExtOpnd, OpIdx)) { LLVM_DEBUG(dbgs() << "No need to propagate\n"); continue; } // Check if we can statically extend the operand. Value *Opnd = ExtOpnd->getOperand(OpIdx); if (const ConstantInt *Cst = dyn_cast(Opnd)) { LLVM_DEBUG(dbgs() << "Statically extend\n"); unsigned BitWidth = Ext->getType()->getIntegerBitWidth(); APInt CstVal = IsSExt ? Cst->getValue().sext(BitWidth) : Cst->getValue().zext(BitWidth); TPT.setOperand(ExtOpnd, OpIdx, ConstantInt::get(Ext->getType(), CstVal)); continue; } // UndefValue are typed, so we have to statically sign extend them. if (isa(Opnd)) { LLVM_DEBUG(dbgs() << "Statically extend\n"); TPT.setOperand(ExtOpnd, OpIdx, UndefValue::get(Ext->getType())); continue; } // Otherwise we have to explicitly sign extend the operand. // Check if Ext was reused to extend an operand. if (!ExtForOpnd) { // If yes, create a new one. LLVM_DEBUG(dbgs() << "More operands to ext\n"); Value *ValForExtOpnd = IsSExt ? TPT.createSExt(Ext, Opnd, Ext->getType()) : TPT.createZExt(Ext, Opnd, Ext->getType()); if (!isa(ValForExtOpnd)) { TPT.setOperand(ExtOpnd, OpIdx, ValForExtOpnd); continue; } ExtForOpnd = cast(ValForExtOpnd); } if (Exts) Exts->push_back(ExtForOpnd); TPT.setOperand(ExtForOpnd, 0, Opnd); // Move the sign extension before the insertion point. TPT.moveBefore(ExtForOpnd, ExtOpnd); TPT.setOperand(ExtOpnd, OpIdx, ExtForOpnd); CreatedInstsCost += !TLI.isExtFree(ExtForOpnd); // If more sext are required, new instructions will have to be created. ExtForOpnd = nullptr; } if (ExtForOpnd == Ext) { LLVM_DEBUG(dbgs() << "Extension is useless now\n"); TPT.eraseInstruction(Ext); } return ExtOpnd; } /// Check whether or not promoting an instruction to a wider type is profitable. /// \p NewCost gives the cost of extension instructions created by the /// promotion. /// \p OldCost gives the cost of extension instructions before the promotion /// plus the number of instructions that have been /// matched in the addressing mode the promotion. /// \p PromotedOperand is the value that has been promoted. /// \return True if the promotion is profitable, false otherwise. bool AddressingModeMatcher::isPromotionProfitable( unsigned NewCost, unsigned OldCost, Value *PromotedOperand) const { LLVM_DEBUG(dbgs() << "OldCost: " << OldCost << "\tNewCost: " << NewCost << '\n'); // The cost of the new extensions is greater than the cost of the // old extension plus what we folded. // This is not profitable. if (NewCost > OldCost) return false; if (NewCost < OldCost) return true; // The promotion is neutral but it may help folding the sign extension in // loads for instance. // Check that we did not create an illegal instruction. return isPromotedInstructionLegal(TLI, DL, PromotedOperand); } /// Given an instruction or constant expr, see if we can fold the operation /// into the addressing mode. If so, update the addressing mode and return /// true, otherwise return false without modifying AddrMode. /// If \p MovedAway is not NULL, it contains the information of whether or /// not AddrInst has to be folded into the addressing mode on success. /// If \p MovedAway == true, \p AddrInst will not be part of the addressing /// because it has been moved away. /// Thus AddrInst must not be added in the matched instructions. /// This state can happen when AddrInst is a sext, since it may be moved away. /// Therefore, AddrInst may not be valid when MovedAway is true and it must /// not be referenced anymore. bool AddressingModeMatcher::matchOperationAddr(User *AddrInst, unsigned Opcode, unsigned Depth, bool *MovedAway) { // Avoid exponential behavior on extremely deep expression trees. if (Depth >= 5) return false; // By default, all matched instructions stay in place. if (MovedAway) *MovedAway = false; switch (Opcode) { case Instruction::PtrToInt: // PtrToInt is always a noop, as we know that the int type is pointer sized. return matchAddr(AddrInst->getOperand(0), Depth); case Instruction::IntToPtr: { auto AS = AddrInst->getType()->getPointerAddressSpace(); auto PtrTy = MVT::getIntegerVT(DL.getPointerSizeInBits(AS)); // This inttoptr is a no-op if the integer type is pointer sized. if (TLI.getValueType(DL, AddrInst->getOperand(0)->getType()) == PtrTy) return matchAddr(AddrInst->getOperand(0), Depth); return false; } case Instruction::BitCast: // BitCast is always a noop, and we can handle it as long as it is // int->int or pointer->pointer (we don't want int<->fp or something). if (AddrInst->getOperand(0)->getType()->isIntOrPtrTy() && // Don't touch identity bitcasts. These were probably put here by LSR, // and we don't want to mess around with them. Assume it knows what it // is doing. AddrInst->getOperand(0)->getType() != AddrInst->getType()) return matchAddr(AddrInst->getOperand(0), Depth); return false; case Instruction::AddrSpaceCast: { unsigned SrcAS = AddrInst->getOperand(0)->getType()->getPointerAddressSpace(); unsigned DestAS = AddrInst->getType()->getPointerAddressSpace(); if (TLI.isNoopAddrSpaceCast(SrcAS, DestAS)) return matchAddr(AddrInst->getOperand(0), Depth); return false; } case Instruction::Add: { // Check to see if we can merge in the RHS then the LHS. If so, we win. ExtAddrMode BackupAddrMode = AddrMode; unsigned OldSize = AddrModeInsts.size(); // Start a transaction at this point. // The LHS may match but not the RHS. // Therefore, we need a higher level restoration point to undo partially // matched operation. TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); if (matchAddr(AddrInst->getOperand(1), Depth+1) && matchAddr(AddrInst->getOperand(0), Depth+1)) return true; // Restore the old addr mode info. AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); TPT.rollback(LastKnownGood); // Otherwise this was over-aggressive. Try merging in the LHS then the RHS. if (matchAddr(AddrInst->getOperand(0), Depth+1) && matchAddr(AddrInst->getOperand(1), Depth+1)) return true; // Otherwise we definitely can't merge the ADD in. AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); TPT.rollback(LastKnownGood); break; } //case Instruction::Or: // TODO: We can handle "Or Val, Imm" iff this OR is equivalent to an ADD. //break; case Instruction::Mul: case Instruction::Shl: { // Can only handle X*C and X << C. ConstantInt *RHS = dyn_cast(AddrInst->getOperand(1)); if (!RHS || RHS->getBitWidth() > 64) return false; int64_t Scale = RHS->getSExtValue(); if (Opcode == Instruction::Shl) Scale = 1LL << Scale; return matchScaledValue(AddrInst->getOperand(0), Scale, Depth); } case Instruction::GetElementPtr: { // Scan the GEP. We check it if it contains constant offsets and at most // one variable offset. int VariableOperand = -1; unsigned VariableScale = 0; int64_t ConstantOffset = 0; gep_type_iterator GTI = gep_type_begin(AddrInst); for (unsigned i = 1, e = AddrInst->getNumOperands(); i != e; ++i, ++GTI) { if (StructType *STy = GTI.getStructTypeOrNull()) { const StructLayout *SL = DL.getStructLayout(STy); unsigned Idx = cast(AddrInst->getOperand(i))->getZExtValue(); ConstantOffset += SL->getElementOffset(Idx); } else { uint64_t TypeSize = DL.getTypeAllocSize(GTI.getIndexedType()); if (ConstantInt *CI = dyn_cast(AddrInst->getOperand(i))) { ConstantOffset += CI->getSExtValue() * TypeSize; } else if (TypeSize) { // Scales of zero don't do anything. // We only allow one variable index at the moment. if (VariableOperand != -1) return false; // Remember the variable index. VariableOperand = i; VariableScale = TypeSize; } } } // A common case is for the GEP to only do a constant offset. In this case, // just add it to the disp field and check validity. if (VariableOperand == -1) { AddrMode.BaseOffs += ConstantOffset; if (ConstantOffset == 0 || TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) { // Check to see if we can fold the base pointer in too. if (matchAddr(AddrInst->getOperand(0), Depth+1)) return true; } else if (EnableGEPOffsetSplit && isa(AddrInst) && TLI.shouldConsiderGEPOffsetSplit() && Depth == 0 && ConstantOffset > 0) { // Record GEPs with non-zero offsets as candidates for splitting in the // event that the offset cannot fit into the r+i addressing mode. // Simple and common case that only one GEP is used in calculating the // address for the memory access. Value *Base = AddrInst->getOperand(0); auto *BaseI = dyn_cast(Base); auto *GEP = cast(AddrInst); if (isa(Base) || isa(Base) || (BaseI && !isa(BaseI) && !isa(BaseI))) { // If the base is an instruction, make sure the GEP is not in the same // basic block as the base. If the base is an argument or global // value, make sure the GEP is not in the entry block. Otherwise, // instruction selection can undo the split. Also make sure the // parent block allows inserting non-PHI instructions before the // terminator. BasicBlock *Parent = BaseI ? BaseI->getParent() : &GEP->getFunction()->getEntryBlock(); if (GEP->getParent() != Parent && !Parent->getTerminator()->isEHPad()) LargeOffsetGEP = std::make_pair(GEP, ConstantOffset); } } AddrMode.BaseOffs -= ConstantOffset; return false; } // Save the valid addressing mode in case we can't match. ExtAddrMode BackupAddrMode = AddrMode; unsigned OldSize = AddrModeInsts.size(); // See if the scale and offset amount is valid for this target. AddrMode.BaseOffs += ConstantOffset; // Match the base operand of the GEP. if (!matchAddr(AddrInst->getOperand(0), Depth+1)) { // If it couldn't be matched, just stuff the value in a register. if (AddrMode.HasBaseReg) { AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); return false; } AddrMode.HasBaseReg = true; AddrMode.BaseReg = AddrInst->getOperand(0); } // Match the remaining variable portion of the GEP. if (!matchScaledValue(AddrInst->getOperand(VariableOperand), VariableScale, Depth)) { // If it couldn't be matched, try stuffing the base into a register // instead of matching it, and retrying the match of the scale. AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); if (AddrMode.HasBaseReg) return false; AddrMode.HasBaseReg = true; AddrMode.BaseReg = AddrInst->getOperand(0); AddrMode.BaseOffs += ConstantOffset; if (!matchScaledValue(AddrInst->getOperand(VariableOperand), VariableScale, Depth)) { // If even that didn't work, bail. AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); return false; } } return true; } case Instruction::SExt: case Instruction::ZExt: { Instruction *Ext = dyn_cast(AddrInst); if (!Ext) return false; // Try to move this ext out of the way of the addressing mode. // Ask for a method for doing so. TypePromotionHelper::Action TPH = TypePromotionHelper::getAction(Ext, InsertedInsts, TLI, PromotedInsts); if (!TPH) return false; TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); unsigned CreatedInstsCost = 0; unsigned ExtCost = !TLI.isExtFree(Ext); Value *PromotedOperand = TPH(Ext, TPT, PromotedInsts, CreatedInstsCost, nullptr, nullptr, TLI); // SExt has been moved away. // Thus either it will be rematched later in the recursive calls or it is // gone. Anyway, we must not fold it into the addressing mode at this point. // E.g., // op = add opnd, 1 // idx = ext op // addr = gep base, idx // is now: // promotedOpnd = ext opnd <- no match here // op = promoted_add promotedOpnd, 1 <- match (later in recursive calls) // addr = gep base, op <- match if (MovedAway) *MovedAway = true; assert(PromotedOperand && "TypePromotionHelper should have filtered out those cases"); ExtAddrMode BackupAddrMode = AddrMode; unsigned OldSize = AddrModeInsts.size(); if (!matchAddr(PromotedOperand, Depth) || // The total of the new cost is equal to the cost of the created // instructions. // The total of the old cost is equal to the cost of the extension plus // what we have saved in the addressing mode. !isPromotionProfitable(CreatedInstsCost, ExtCost + (AddrModeInsts.size() - OldSize), PromotedOperand)) { AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); LLVM_DEBUG(dbgs() << "Sign extension does not pay off: rollback\n"); TPT.rollback(LastKnownGood); return false; } return true; } } return false; } /// If we can, try to add the value of 'Addr' into the current addressing mode. /// If Addr can't be added to AddrMode this returns false and leaves AddrMode /// unmodified. This assumes that Addr is either a pointer type or intptr_t /// for the target. /// bool AddressingModeMatcher::matchAddr(Value *Addr, unsigned Depth) { // Start a transaction at this point that we will rollback if the matching // fails. TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); if (ConstantInt *CI = dyn_cast(Addr)) { // Fold in immediates if legal for the target. AddrMode.BaseOffs += CI->getSExtValue(); if (TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) return true; AddrMode.BaseOffs -= CI->getSExtValue(); } else if (GlobalValue *GV = dyn_cast(Addr)) { // If this is a global variable, try to fold it into the addressing mode. if (!AddrMode.BaseGV) { AddrMode.BaseGV = GV; if (TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) return true; AddrMode.BaseGV = nullptr; } } else if (Instruction *I = dyn_cast(Addr)) { ExtAddrMode BackupAddrMode = AddrMode; unsigned OldSize = AddrModeInsts.size(); // Check to see if it is possible to fold this operation. bool MovedAway = false; if (matchOperationAddr(I, I->getOpcode(), Depth, &MovedAway)) { // This instruction may have been moved away. If so, there is nothing // to check here. if (MovedAway) return true; // Okay, it's possible to fold this. Check to see if it is actually // *profitable* to do so. We use a simple cost model to avoid increasing // register pressure too much. if (I->hasOneUse() || isProfitableToFoldIntoAddressingMode(I, BackupAddrMode, AddrMode)) { AddrModeInsts.push_back(I); return true; } // It isn't profitable to do this, roll back. //cerr << "NOT FOLDING: " << *I; AddrMode = BackupAddrMode; AddrModeInsts.resize(OldSize); TPT.rollback(LastKnownGood); } } else if (ConstantExpr *CE = dyn_cast(Addr)) { if (matchOperationAddr(CE, CE->getOpcode(), Depth)) return true; TPT.rollback(LastKnownGood); } else if (isa(Addr)) { // Null pointer gets folded without affecting the addressing mode. return true; } // Worse case, the target should support [reg] addressing modes. :) if (!AddrMode.HasBaseReg) { AddrMode.HasBaseReg = true; AddrMode.BaseReg = Addr; // Still check for legality in case the target supports [imm] but not [i+r]. if (TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) return true; AddrMode.HasBaseReg = false; AddrMode.BaseReg = nullptr; } // If the base register is already taken, see if we can do [r+r]. if (AddrMode.Scale == 0) { AddrMode.Scale = 1; AddrMode.ScaledReg = Addr; if (TLI.isLegalAddressingMode(DL, AddrMode, AccessTy, AddrSpace)) return true; AddrMode.Scale = 0; AddrMode.ScaledReg = nullptr; } // Couldn't match. TPT.rollback(LastKnownGood); return false; } /// Check to see if all uses of OpVal by the specified inline asm call are due /// to memory operands. If so, return true, otherwise return false. static bool IsOperandAMemoryOperand(CallInst *CI, InlineAsm *IA, Value *OpVal, const TargetLowering &TLI, const TargetRegisterInfo &TRI) { const Function *F = CI->getFunction(); TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints(F->getParent()->getDataLayout(), &TRI, ImmutableCallSite(CI)); for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(OpInfo, SDValue()); // If this asm operand is our Value*, and if it isn't an indirect memory // operand, we can't fold it! if (OpInfo.CallOperandVal == OpVal && (OpInfo.ConstraintType != TargetLowering::C_Memory || !OpInfo.isIndirect)) return false; } return true; } // Max number of memory uses to look at before aborting the search to conserve // compile time. static constexpr int MaxMemoryUsesToScan = 20; /// Recursively walk all the uses of I until we find a memory use. /// If we find an obviously non-foldable instruction, return true. /// Add the ultimately found memory instructions to MemoryUses. static bool FindAllMemoryUses( Instruction *I, SmallVectorImpl> &MemoryUses, SmallPtrSetImpl &ConsideredInsts, const TargetLowering &TLI, const TargetRegisterInfo &TRI, int SeenInsts = 0) { // If we already considered this instruction, we're done. if (!ConsideredInsts.insert(I).second) return false; // If this is an obviously unfoldable instruction, bail out. if (!MightBeFoldableInst(I)) return true; const bool OptSize = I->getFunction()->optForSize(); // Loop over all the uses, recursively processing them. for (Use &U : I->uses()) { // Conservatively return true if we're seeing a large number or a deep chain // of users. This avoids excessive compilation times in pathological cases. if (SeenInsts++ >= MaxMemoryUsesToScan) return true; Instruction *UserI = cast(U.getUser()); if (LoadInst *LI = dyn_cast(UserI)) { MemoryUses.push_back(std::make_pair(LI, U.getOperandNo())); continue; } if (StoreInst *SI = dyn_cast(UserI)) { unsigned opNo = U.getOperandNo(); if (opNo != StoreInst::getPointerOperandIndex()) return true; // Storing addr, not into addr. MemoryUses.push_back(std::make_pair(SI, opNo)); continue; } if (AtomicRMWInst *RMW = dyn_cast(UserI)) { unsigned opNo = U.getOperandNo(); if (opNo != AtomicRMWInst::getPointerOperandIndex()) return true; // Storing addr, not into addr. MemoryUses.push_back(std::make_pair(RMW, opNo)); continue; } if (AtomicCmpXchgInst *CmpX = dyn_cast(UserI)) { unsigned opNo = U.getOperandNo(); if (opNo != AtomicCmpXchgInst::getPointerOperandIndex()) return true; // Storing addr, not into addr. MemoryUses.push_back(std::make_pair(CmpX, opNo)); continue; } if (CallInst *CI = dyn_cast(UserI)) { // If this is a cold call, we can sink the addressing calculation into // the cold path. See optimizeCallInst if (!OptSize && CI->hasFnAttr(Attribute::Cold)) continue; InlineAsm *IA = dyn_cast(CI->getCalledValue()); if (!IA) return true; // If this is a memory operand, we're cool, otherwise bail out. if (!IsOperandAMemoryOperand(CI, IA, I, TLI, TRI)) return true; continue; } if (FindAllMemoryUses(UserI, MemoryUses, ConsideredInsts, TLI, TRI, SeenInsts)) return true; } return false; } /// Return true if Val is already known to be live at the use site that we're /// folding it into. If so, there is no cost to include it in the addressing /// mode. KnownLive1 and KnownLive2 are two values that we know are live at the /// instruction already. bool AddressingModeMatcher::valueAlreadyLiveAtInst(Value *Val,Value *KnownLive1, Value *KnownLive2) { // If Val is either of the known-live values, we know it is live! if (Val == nullptr || Val == KnownLive1 || Val == KnownLive2) return true; // All values other than instructions and arguments (e.g. constants) are live. if (!isa(Val) && !isa(Val)) return true; // If Val is a constant sized alloca in the entry block, it is live, this is // true because it is just a reference to the stack/frame pointer, which is // live for the whole function. if (AllocaInst *AI = dyn_cast(Val)) if (AI->isStaticAlloca()) return true; // Check to see if this value is already used in the memory instruction's // block. If so, it's already live into the block at the very least, so we // can reasonably fold it. return Val->isUsedInBasicBlock(MemoryInst->getParent()); } /// It is possible for the addressing mode of the machine to fold the specified /// instruction into a load or store that ultimately uses it. /// However, the specified instruction has multiple uses. /// Given this, it may actually increase register pressure to fold it /// into the load. For example, consider this code: /// /// X = ... /// Y = X+1 /// use(Y) -> nonload/store /// Z = Y+1 /// load Z /// /// In this case, Y has multiple uses, and can be folded into the load of Z /// (yielding load [X+2]). However, doing this will cause both "X" and "X+1" to /// be live at the use(Y) line. If we don't fold Y into load Z, we use one /// fewer register. Since Y can't be folded into "use(Y)" we don't increase the /// number of computations either. /// /// Note that this (like most of CodeGenPrepare) is just a rough heuristic. If /// X was live across 'load Z' for other reasons, we actually *would* want to /// fold the addressing mode in the Z case. This would make Y die earlier. bool AddressingModeMatcher:: isProfitableToFoldIntoAddressingMode(Instruction *I, ExtAddrMode &AMBefore, ExtAddrMode &AMAfter) { if (IgnoreProfitability) return true; // AMBefore is the addressing mode before this instruction was folded into it, // and AMAfter is the addressing mode after the instruction was folded. Get // the set of registers referenced by AMAfter and subtract out those // referenced by AMBefore: this is the set of values which folding in this // address extends the lifetime of. // // Note that there are only two potential values being referenced here, // BaseReg and ScaleReg (global addresses are always available, as are any // folded immediates). Value *BaseReg = AMAfter.BaseReg, *ScaledReg = AMAfter.ScaledReg; // If the BaseReg or ScaledReg was referenced by the previous addrmode, their // lifetime wasn't extended by adding this instruction. if (valueAlreadyLiveAtInst(BaseReg, AMBefore.BaseReg, AMBefore.ScaledReg)) BaseReg = nullptr; if (valueAlreadyLiveAtInst(ScaledReg, AMBefore.BaseReg, AMBefore.ScaledReg)) ScaledReg = nullptr; // If folding this instruction (and it's subexprs) didn't extend any live // ranges, we're ok with it. if (!BaseReg && !ScaledReg) return true; // If all uses of this instruction can have the address mode sunk into them, // we can remove the addressing mode and effectively trade one live register // for another (at worst.) In this context, folding an addressing mode into // the use is just a particularly nice way of sinking it. SmallVector, 16> MemoryUses; SmallPtrSet ConsideredInsts; if (FindAllMemoryUses(I, MemoryUses, ConsideredInsts, TLI, TRI)) return false; // Has a non-memory, non-foldable use! // Now that we know that all uses of this instruction are part of a chain of // computation involving only operations that could theoretically be folded // into a memory use, loop over each of these memory operation uses and see // if they could *actually* fold the instruction. The assumption is that // addressing modes are cheap and that duplicating the computation involved // many times is worthwhile, even on a fastpath. For sinking candidates // (i.e. cold call sites), this serves as a way to prevent excessive code // growth since most architectures have some reasonable small and fast way to // compute an effective address. (i.e LEA on x86) SmallVector MatchedAddrModeInsts; for (unsigned i = 0, e = MemoryUses.size(); i != e; ++i) { Instruction *User = MemoryUses[i].first; unsigned OpNo = MemoryUses[i].second; // Get the access type of this use. If the use isn't a pointer, we don't // know what it accesses. Value *Address = User->getOperand(OpNo); PointerType *AddrTy = dyn_cast(Address->getType()); if (!AddrTy) return false; Type *AddressAccessTy = AddrTy->getElementType(); unsigned AS = AddrTy->getAddressSpace(); // Do a match against the root of this address, ignoring profitability. This // will tell us if the addressing mode for the memory operation will // *actually* cover the shared instruction. ExtAddrMode Result; std::pair, int64_t> LargeOffsetGEP(nullptr, 0); TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); AddressingModeMatcher Matcher( MatchedAddrModeInsts, TLI, TRI, AddressAccessTy, AS, MemoryInst, Result, InsertedInsts, PromotedInsts, TPT, LargeOffsetGEP); Matcher.IgnoreProfitability = true; bool Success = Matcher.matchAddr(Address, 0); (void)Success; assert(Success && "Couldn't select *anything*?"); // The match was to check the profitability, the changes made are not // part of the original matcher. Therefore, they should be dropped // otherwise the original matcher will not present the right state. TPT.rollback(LastKnownGood); // If the match didn't cover I, then it won't be shared by it. if (!is_contained(MatchedAddrModeInsts, I)) return false; MatchedAddrModeInsts.clear(); } return true; } /// Return true if the specified values are defined in a /// different basic block than BB. static bool IsNonLocalValue(Value *V, BasicBlock *BB) { if (Instruction *I = dyn_cast(V)) return I->getParent() != BB; return false; } /// Sink addressing mode computation immediate before MemoryInst if doing so /// can be done without increasing register pressure. The need for the /// register pressure constraint means this can end up being an all or nothing /// decision for all uses of the same addressing computation. /// /// Load and Store Instructions often have addressing modes that can do /// significant amounts of computation. As such, instruction selection will try /// to get the load or store to do as much computation as possible for the /// program. The problem is that isel can only see within a single block. As /// such, we sink as much legal addressing mode work into the block as possible. /// /// This method is used to optimize both load/store and inline asms with memory /// operands. It's also used to sink addressing computations feeding into cold /// call sites into their (cold) basic block. /// /// The motivation for handling sinking into cold blocks is that doing so can /// both enable other address mode sinking (by satisfying the register pressure /// constraint above), and reduce register pressure globally (by removing the /// addressing mode computation from the fast path entirely.). bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr, Type *AccessTy, unsigned AddrSpace) { Value *Repl = Addr; // Try to collapse single-value PHI nodes. This is necessary to undo // unprofitable PRE transformations. SmallVector worklist; SmallPtrSet Visited; worklist.push_back(Addr); // Use a worklist to iteratively look through PHI and select nodes, and // ensure that the addressing mode obtained from the non-PHI/select roots of // the graph are compatible. bool PhiOrSelectSeen = false; SmallVector AddrModeInsts; const SimplifyQuery SQ(*DL, TLInfo); AddressingModeCombiner AddrModes(SQ, { Addr, MemoryInst->getParent() }); TypePromotionTransaction TPT(RemovedInsts); TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); while (!worklist.empty()) { Value *V = worklist.back(); worklist.pop_back(); // We allow traversing cyclic Phi nodes. // In case of success after this loop we ensure that traversing through // Phi nodes ends up with all cases to compute address of the form // BaseGV + Base + Scale * Index + Offset // where Scale and Offset are constans and BaseGV, Base and Index // are exactly the same Values in all cases. // It means that BaseGV, Scale and Offset dominate our memory instruction // and have the same value as they had in address computation represented // as Phi. So we can safely sink address computation to memory instruction. if (!Visited.insert(V).second) continue; // For a PHI node, push all of its incoming values. if (PHINode *P = dyn_cast(V)) { for (Value *IncValue : P->incoming_values()) worklist.push_back(IncValue); PhiOrSelectSeen = true; continue; } // Similar for select. if (SelectInst *SI = dyn_cast(V)) { worklist.push_back(SI->getFalseValue()); worklist.push_back(SI->getTrueValue()); PhiOrSelectSeen = true; continue; } // For non-PHIs, determine the addressing mode being computed. Note that // the result may differ depending on what other uses our candidate // addressing instructions might have. AddrModeInsts.clear(); std::pair, int64_t> LargeOffsetGEP(nullptr, 0); ExtAddrMode NewAddrMode = AddressingModeMatcher::Match( V, AccessTy, AddrSpace, MemoryInst, AddrModeInsts, *TLI, *TRI, InsertedInsts, PromotedInsts, TPT, LargeOffsetGEP); GetElementPtrInst *GEP = LargeOffsetGEP.first; if (GEP && GEP->getParent() != MemoryInst->getParent() && !NewGEPBases.count(GEP)) { // If splitting the underlying data structure can reduce the offset of a // GEP, collect the GEP. Skip the GEPs that are the new bases of // previously split data structures. LargeOffsetGEPMap[GEP->getPointerOperand()].push_back(LargeOffsetGEP); if (LargeOffsetGEPID.find(GEP) == LargeOffsetGEPID.end()) LargeOffsetGEPID[GEP] = LargeOffsetGEPID.size(); } NewAddrMode.OriginalValue = V; if (!AddrModes.addNewAddrMode(NewAddrMode)) break; } // Try to combine the AddrModes we've collected. If we couldn't collect any, // or we have multiple but either couldn't combine them or combining them // wouldn't do anything useful, bail out now. if (!AddrModes.combineAddrModes()) { TPT.rollback(LastKnownGood); return false; } TPT.commit(); // Get the combined AddrMode (or the only AddrMode, if we only had one). ExtAddrMode AddrMode = AddrModes.getAddrMode(); // If all the instructions matched are already in this BB, don't do anything. // If we saw a Phi node then it is not local definitely, and if we saw a select // then we want to push the address calculation past it even if it's already // in this BB. if (!PhiOrSelectSeen && none_of(AddrModeInsts, [&](Value *V) { return IsNonLocalValue(V, MemoryInst->getParent()); })) { LLVM_DEBUG(dbgs() << "CGP: Found local addrmode: " << AddrMode << "\n"); return false; } // Insert this computation right after this user. Since our caller is // scanning from the top of the BB to the bottom, reuse of the expr are // guaranteed to happen later. IRBuilder<> Builder(MemoryInst); // Now that we determined the addressing expression we want to use and know // that we have to sink it into this block. Check to see if we have already // done this for some other load/store instr in this block. If so, reuse // the computation. Before attempting reuse, check if the address is valid // as it may have been erased. WeakTrackingVH SunkAddrVH = SunkAddrs[Addr]; Value * SunkAddr = SunkAddrVH.pointsToAliveValue() ? SunkAddrVH : nullptr; if (SunkAddr) { LLVM_DEBUG(dbgs() << "CGP: Reusing nonlocal addrmode: " << AddrMode << " for " << *MemoryInst << "\n"); if (SunkAddr->getType() != Addr->getType()) SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType()); } else if (AddrSinkUsingGEPs || (!AddrSinkUsingGEPs.getNumOccurrences() && TM && TTI->useAA())) { // By default, we use the GEP-based method when AA is used later. This // prevents new inttoptr/ptrtoint pairs from degrading AA capabilities. LLVM_DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode << " for " << *MemoryInst << "\n"); Type *IntPtrTy = DL->getIntPtrType(Addr->getType()); Value *ResultPtr = nullptr, *ResultIndex = nullptr; // First, find the pointer. if (AddrMode.BaseReg && AddrMode.BaseReg->getType()->isPointerTy()) { ResultPtr = AddrMode.BaseReg; AddrMode.BaseReg = nullptr; } if (AddrMode.Scale && AddrMode.ScaledReg->getType()->isPointerTy()) { // We can't add more than one pointer together, nor can we scale a // pointer (both of which seem meaningless). if (ResultPtr || AddrMode.Scale != 1) return false; ResultPtr = AddrMode.ScaledReg; AddrMode.Scale = 0; } // It is only safe to sign extend the BaseReg if we know that the math // required to create it did not overflow before we extend it. Since // the original IR value was tossed in favor of a constant back when // the AddrMode was created we need to bail out gracefully if widths // do not match instead of extending it. // // (See below for code to add the scale.) if (AddrMode.Scale) { Type *ScaledRegTy = AddrMode.ScaledReg->getType(); if (cast(IntPtrTy)->getBitWidth() > cast(ScaledRegTy)->getBitWidth()) return false; } if (AddrMode.BaseGV) { if (ResultPtr) return false; ResultPtr = AddrMode.BaseGV; } // If the real base value actually came from an inttoptr, then the matcher // will look through it and provide only the integer value. In that case, // use it here. if (!DL->isNonIntegralPointerType(Addr->getType())) { if (!ResultPtr && AddrMode.BaseReg) { ResultPtr = Builder.CreateIntToPtr(AddrMode.BaseReg, Addr->getType(), "sunkaddr"); AddrMode.BaseReg = nullptr; } else if (!ResultPtr && AddrMode.Scale == 1) { ResultPtr = Builder.CreateIntToPtr(AddrMode.ScaledReg, Addr->getType(), "sunkaddr"); AddrMode.Scale = 0; } } if (!ResultPtr && !AddrMode.BaseReg && !AddrMode.Scale && !AddrMode.BaseOffs) { SunkAddr = Constant::getNullValue(Addr->getType()); } else if (!ResultPtr) { return false; } else { Type *I8PtrTy = Builder.getInt8PtrTy(Addr->getType()->getPointerAddressSpace()); Type *I8Ty = Builder.getInt8Ty(); // Start with the base register. Do this first so that subsequent address // matching finds it last, which will prevent it from trying to match it // as the scaled value in case it happens to be a mul. That would be // problematic if we've sunk a different mul for the scale, because then // we'd end up sinking both muls. if (AddrMode.BaseReg) { Value *V = AddrMode.BaseReg; if (V->getType() != IntPtrTy) V = Builder.CreateIntCast(V, IntPtrTy, /*isSigned=*/true, "sunkaddr"); ResultIndex = V; } // Add the scale value. if (AddrMode.Scale) { Value *V = AddrMode.ScaledReg; if (V->getType() == IntPtrTy) { // done. } else { assert(cast(IntPtrTy)->getBitWidth() < cast(V->getType())->getBitWidth() && "We can't transform if ScaledReg is too narrow"); V = Builder.CreateTrunc(V, IntPtrTy, "sunkaddr"); } if (AddrMode.Scale != 1) V = Builder.CreateMul(V, ConstantInt::get(IntPtrTy, AddrMode.Scale), "sunkaddr"); if (ResultIndex) ResultIndex = Builder.CreateAdd(ResultIndex, V, "sunkaddr"); else ResultIndex = V; } // Add in the Base Offset if present. if (AddrMode.BaseOffs) { Value *V = ConstantInt::get(IntPtrTy, AddrMode.BaseOffs); if (ResultIndex) { // We need to add this separately from the scale above to help with // SDAG consecutive load/store merging. if (ResultPtr->getType() != I8PtrTy) ResultPtr = Builder.CreatePointerCast(ResultPtr, I8PtrTy); ResultPtr = Builder.CreateGEP(I8Ty, ResultPtr, ResultIndex, "sunkaddr"); } ResultIndex = V; } if (!ResultIndex) { SunkAddr = ResultPtr; } else { if (ResultPtr->getType() != I8PtrTy) ResultPtr = Builder.CreatePointerCast(ResultPtr, I8PtrTy); SunkAddr = Builder.CreateGEP(I8Ty, ResultPtr, ResultIndex, "sunkaddr"); } if (SunkAddr->getType() != Addr->getType()) SunkAddr = Builder.CreatePointerCast(SunkAddr, Addr->getType()); } } else { // We'd require a ptrtoint/inttoptr down the line, which we can't do for // non-integral pointers, so in that case bail out now. Type *BaseTy = AddrMode.BaseReg ? AddrMode.BaseReg->getType() : nullptr; Type *ScaleTy = AddrMode.Scale ? AddrMode.ScaledReg->getType() : nullptr; PointerType *BasePtrTy = dyn_cast_or_null(BaseTy); PointerType *ScalePtrTy = dyn_cast_or_null(ScaleTy); if (DL->isNonIntegralPointerType(Addr->getType()) || (BasePtrTy && DL->isNonIntegralPointerType(BasePtrTy)) || (ScalePtrTy && DL->isNonIntegralPointerType(ScalePtrTy)) || (AddrMode.BaseGV && DL->isNonIntegralPointerType(AddrMode.BaseGV->getType()))) return false; LLVM_DEBUG(dbgs() << "CGP: SINKING nonlocal addrmode: " << AddrMode << " for " << *MemoryInst << "\n"); Type *IntPtrTy = DL->getIntPtrType(Addr->getType()); Value *Result = nullptr; // Start with the base register. Do this first so that subsequent address // matching finds it last, which will prevent it from trying to match it // as the scaled value in case it happens to be a mul. That would be // problematic if we've sunk a different mul for the scale, because then // we'd end up sinking both muls. if (AddrMode.BaseReg) { Value *V = AddrMode.BaseReg; if (V->getType()->isPointerTy()) V = Builder.CreatePtrToInt(V, IntPtrTy, "sunkaddr"); if (V->getType() != IntPtrTy) V = Builder.CreateIntCast(V, IntPtrTy, /*isSigned=*/true, "sunkaddr"); Result = V; } // Add the scale value. if (AddrMode.Scale) { Value *V = AddrMode.ScaledReg; if (V->getType() == IntPtrTy) { // done. } else if (V->getType()->isPointerTy()) { V = Builder.CreatePtrToInt(V, IntPtrTy, "sunkaddr"); } else if (cast(IntPtrTy)->getBitWidth() < cast(V->getType())->getBitWidth()) { V = Builder.CreateTrunc(V, IntPtrTy, "sunkaddr"); } else { // It is only safe to sign extend the BaseReg if we know that the math // required to create it did not overflow before we extend it. Since // the original IR value was tossed in favor of a constant back when // the AddrMode was created we need to bail out gracefully if widths // do not match instead of extending it. Instruction *I = dyn_cast_or_null(Result); if (I && (Result != AddrMode.BaseReg)) I->eraseFromParent(); return false; } if (AddrMode.Scale != 1) V = Builder.CreateMul(V, ConstantInt::get(IntPtrTy, AddrMode.Scale), "sunkaddr"); if (Result) Result = Builder.CreateAdd(Result, V, "sunkaddr"); else Result = V; } // Add in the BaseGV if present. if (AddrMode.BaseGV) { Value *V = Builder.CreatePtrToInt(AddrMode.BaseGV, IntPtrTy, "sunkaddr"); if (Result) Result = Builder.CreateAdd(Result, V, "sunkaddr"); else Result = V; } // Add in the Base Offset if present. if (AddrMode.BaseOffs) { Value *V = ConstantInt::get(IntPtrTy, AddrMode.BaseOffs); if (Result) Result = Builder.CreateAdd(Result, V, "sunkaddr"); else Result = V; } if (!Result) SunkAddr = Constant::getNullValue(Addr->getType()); else SunkAddr = Builder.CreateIntToPtr(Result, Addr->getType(), "sunkaddr"); } MemoryInst->replaceUsesOfWith(Repl, SunkAddr); // Store the newly computed address into the cache. In the case we reused a // value, this should be idempotent. SunkAddrs[Addr] = WeakTrackingVH(SunkAddr); // If we have no uses, recursively delete the value and all dead instructions // using it. if (Repl->use_empty()) { // This can cause recursive deletion, which can invalidate our iterator. // Use a WeakTrackingVH to hold onto it in case this happens. Value *CurValue = &*CurInstIterator; WeakTrackingVH IterHandle(CurValue); BasicBlock *BB = CurInstIterator->getParent(); RecursivelyDeleteTriviallyDeadInstructions(Repl, TLInfo); if (IterHandle != CurValue) { // If the iterator instruction was recursively deleted, start over at the // start of the block. CurInstIterator = BB->begin(); SunkAddrs.clear(); } } ++NumMemoryInsts; return true; } /// If there are any memory operands, use OptimizeMemoryInst to sink their /// address computing into the block when possible / profitable. bool CodeGenPrepare::optimizeInlineAsmInst(CallInst *CS) { bool MadeChange = false; const TargetRegisterInfo *TRI = TM->getSubtargetImpl(*CS->getFunction())->getRegisterInfo(); TargetLowering::AsmOperandInfoVector TargetConstraints = TLI->ParseConstraints(*DL, TRI, CS); unsigned ArgNo = 0; for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; // Compute the constraint code and ConstraintType to use. TLI->ComputeConstraintToUse(OpInfo, SDValue()); if (OpInfo.ConstraintType == TargetLowering::C_Memory && OpInfo.isIndirect) { Value *OpVal = CS->getArgOperand(ArgNo++); MadeChange |= optimizeMemoryInst(CS, OpVal, OpVal->getType(), ~0u); } else if (OpInfo.Type == InlineAsm::isInput) ArgNo++; } return MadeChange; } /// Check if all the uses of \p Val are equivalent (or free) zero or /// sign extensions. static bool hasSameExtUse(Value *Val, const TargetLowering &TLI) { assert(!Val->use_empty() && "Input must have at least one use"); const Instruction *FirstUser = cast(*Val->user_begin()); bool IsSExt = isa(FirstUser); Type *ExtTy = FirstUser->getType(); for (const User *U : Val->users()) { const Instruction *UI = cast(U); if ((IsSExt && !isa(UI)) || (!IsSExt && !isa(UI))) return false; Type *CurTy = UI->getType(); // Same input and output types: Same instruction after CSE. if (CurTy == ExtTy) continue; // If IsSExt is true, we are in this situation: // a = Val // b = sext ty1 a to ty2 // c = sext ty1 a to ty3 // Assuming ty2 is shorter than ty3, this could be turned into: // a = Val // b = sext ty1 a to ty2 // c = sext ty2 b to ty3 // However, the last sext is not free. if (IsSExt) return false; // This is a ZExt, maybe this is free to extend from one type to another. // In that case, we would not account for a different use. Type *NarrowTy; Type *LargeTy; if (ExtTy->getScalarType()->getIntegerBitWidth() > CurTy->getScalarType()->getIntegerBitWidth()) { NarrowTy = CurTy; LargeTy = ExtTy; } else { NarrowTy = ExtTy; LargeTy = CurTy; } if (!TLI.isZExtFree(NarrowTy, LargeTy)) return false; } // All uses are the same or can be derived from one another for free. return true; } /// Try to speculatively promote extensions in \p Exts and continue /// promoting through newly promoted operands recursively as far as doing so is /// profitable. Save extensions profitably moved up, in \p ProfitablyMovedExts. /// When some promotion happened, \p TPT contains the proper state to revert /// them. /// /// \return true if some promotion happened, false otherwise. bool CodeGenPrepare::tryToPromoteExts( TypePromotionTransaction &TPT, const SmallVectorImpl &Exts, SmallVectorImpl &ProfitablyMovedExts, unsigned CreatedInstsCost) { bool Promoted = false; // Iterate over all the extensions to try to promote them. for (auto I : Exts) { // Early check if we directly have ext(load). if (isa(I->getOperand(0))) { ProfitablyMovedExts.push_back(I); continue; } // Check whether or not we want to do any promotion. The reason we have // this check inside the for loop is to catch the case where an extension // is directly fed by a load because in such case the extension can be moved // up without any promotion on its operands. if (!TLI || !TLI->enableExtLdPromotion() || DisableExtLdPromotion) return false; // Get the action to perform the promotion. TypePromotionHelper::Action TPH = TypePromotionHelper::getAction(I, InsertedInsts, *TLI, PromotedInsts); // Check if we can promote. if (!TPH) { // Save the current extension as we cannot move up through its operand. ProfitablyMovedExts.push_back(I); continue; } // Save the current state. TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); SmallVector NewExts; unsigned NewCreatedInstsCost = 0; unsigned ExtCost = !TLI->isExtFree(I); // Promote. Value *PromotedVal = TPH(I, TPT, PromotedInsts, NewCreatedInstsCost, &NewExts, nullptr, *TLI); assert(PromotedVal && "TypePromotionHelper should have filtered out those cases"); // We would be able to merge only one extension in a load. // Therefore, if we have more than 1 new extension we heuristically // cut this search path, because it means we degrade the code quality. // With exactly 2, the transformation is neutral, because we will merge // one extension but leave one. However, we optimistically keep going, // because the new extension may be removed too. long long TotalCreatedInstsCost = CreatedInstsCost + NewCreatedInstsCost; // FIXME: It would be possible to propagate a negative value instead of // conservatively ceiling it to 0. TotalCreatedInstsCost = std::max((long long)0, (TotalCreatedInstsCost - ExtCost)); if (!StressExtLdPromotion && (TotalCreatedInstsCost > 1 || !isPromotedInstructionLegal(*TLI, *DL, PromotedVal))) { // This promotion is not profitable, rollback to the previous state, and // save the current extension in ProfitablyMovedExts as the latest // speculative promotion turned out to be unprofitable. TPT.rollback(LastKnownGood); ProfitablyMovedExts.push_back(I); continue; } // Continue promoting NewExts as far as doing so is profitable. SmallVector NewlyMovedExts; (void)tryToPromoteExts(TPT, NewExts, NewlyMovedExts, TotalCreatedInstsCost); bool NewPromoted = false; for (auto ExtInst : NewlyMovedExts) { Instruction *MovedExt = cast(ExtInst); Value *ExtOperand = MovedExt->getOperand(0); // If we have reached to a load, we need this extra profitability check // as it could potentially be merged into an ext(load). if (isa(ExtOperand) && !(StressExtLdPromotion || NewCreatedInstsCost <= ExtCost || (ExtOperand->hasOneUse() || hasSameExtUse(ExtOperand, *TLI)))) continue; ProfitablyMovedExts.push_back(MovedExt); NewPromoted = true; } // If none of speculative promotions for NewExts is profitable, rollback // and save the current extension (I) as the last profitable extension. if (!NewPromoted) { TPT.rollback(LastKnownGood); ProfitablyMovedExts.push_back(I); continue; } // The promotion is profitable. Promoted = true; } return Promoted; } /// Merging redundant sexts when one is dominating the other. bool CodeGenPrepare::mergeSExts(Function &F) { DominatorTree DT(F); bool Changed = false; for (auto &Entry : ValToSExtendedUses) { SExts &Insts = Entry.second; SExts CurPts; for (Instruction *Inst : Insts) { if (RemovedInsts.count(Inst) || !isa(Inst) || Inst->getOperand(0) != Entry.first) continue; bool inserted = false; for (auto &Pt : CurPts) { if (DT.dominates(Inst, Pt)) { Pt->replaceAllUsesWith(Inst); RemovedInsts.insert(Pt); Pt->removeFromParent(); Pt = Inst; inserted = true; Changed = true; break; } if (!DT.dominates(Pt, Inst)) // Give up if we need to merge in a common dominator as the // experiments show it is not profitable. continue; Inst->replaceAllUsesWith(Pt); RemovedInsts.insert(Inst); Inst->removeFromParent(); inserted = true; Changed = true; break; } if (!inserted) CurPts.push_back(Inst); } } return Changed; } // Spliting large data structures so that the GEPs accessing them can have // smaller offsets so that they can be sunk to the same blocks as their users. // For example, a large struct starting from %base is splitted into two parts // where the second part starts from %new_base. // // Before: // BB0: // %base = // // BB1: // %gep0 = gep %base, off0 // %gep1 = gep %base, off1 // %gep2 = gep %base, off2 // // BB2: // %load1 = load %gep0 // %load2 = load %gep1 // %load3 = load %gep2 // // After: // BB0: // %base = // %new_base = gep %base, off0 // // BB1: // %new_gep0 = %new_base // %new_gep1 = gep %new_base, off1 - off0 // %new_gep2 = gep %new_base, off2 - off0 // // BB2: // %load1 = load i32, i32* %new_gep0 // %load2 = load i32, i32* %new_gep1 // %load3 = load i32, i32* %new_gep2 // // %new_gep1 and %new_gep2 can be sunk to BB2 now after the splitting because // their offsets are smaller enough to fit into the addressing mode. bool CodeGenPrepare::splitLargeGEPOffsets() { bool Changed = false; for (auto &Entry : LargeOffsetGEPMap) { Value *OldBase = Entry.first; SmallVectorImpl, int64_t>> &LargeOffsetGEPs = Entry.second; auto compareGEPOffset = [&](const std::pair &LHS, const std::pair &RHS) { if (LHS.first == RHS.first) return false; if (LHS.second != RHS.second) return LHS.second < RHS.second; return LargeOffsetGEPID[LHS.first] < LargeOffsetGEPID[RHS.first]; }; // Sorting all the GEPs of the same data structures based on the offsets. llvm::sort(LargeOffsetGEPs.begin(), LargeOffsetGEPs.end(), compareGEPOffset); LargeOffsetGEPs.erase( std::unique(LargeOffsetGEPs.begin(), LargeOffsetGEPs.end()), LargeOffsetGEPs.end()); // Skip if all the GEPs have the same offsets. if (LargeOffsetGEPs.front().second == LargeOffsetGEPs.back().second) continue; GetElementPtrInst *BaseGEP = LargeOffsetGEPs.begin()->first; int64_t BaseOffset = LargeOffsetGEPs.begin()->second; Value *NewBaseGEP = nullptr; auto LargeOffsetGEP = LargeOffsetGEPs.begin(); while (LargeOffsetGEP != LargeOffsetGEPs.end()) { GetElementPtrInst *GEP = LargeOffsetGEP->first; int64_t Offset = LargeOffsetGEP->second; if (Offset != BaseOffset) { TargetLowering::AddrMode AddrMode; AddrMode.BaseOffs = Offset - BaseOffset; // The result type of the GEP might not be the type of the memory // access. if (!TLI->isLegalAddressingMode(*DL, AddrMode, GEP->getResultElementType(), GEP->getAddressSpace())) { // We need to create a new base if the offset to the current base is // too large to fit into the addressing mode. So, a very large struct // may be splitted into several parts. BaseGEP = GEP; BaseOffset = Offset; NewBaseGEP = nullptr; } } // Generate a new GEP to replace the current one. IRBuilder<> Builder(GEP); Type *IntPtrTy = DL->getIntPtrType(GEP->getType()); Type *I8PtrTy = Builder.getInt8PtrTy(GEP->getType()->getPointerAddressSpace()); Type *I8Ty = Builder.getInt8Ty(); if (!NewBaseGEP) { // Create a new base if we don't have one yet. Find the insertion // pointer for the new base first. BasicBlock::iterator NewBaseInsertPt; BasicBlock *NewBaseInsertBB; if (auto *BaseI = dyn_cast(OldBase)) { // If the base of the struct is an instruction, the new base will be // inserted close to it. NewBaseInsertBB = BaseI->getParent(); if (isa(BaseI)) NewBaseInsertPt = NewBaseInsertBB->getFirstInsertionPt(); else if (InvokeInst *Invoke = dyn_cast(BaseI)) { NewBaseInsertBB = SplitEdge(NewBaseInsertBB, Invoke->getNormalDest()); NewBaseInsertPt = NewBaseInsertBB->getFirstInsertionPt(); } else NewBaseInsertPt = std::next(BaseI->getIterator()); } else { // If the current base is an argument or global value, the new base // will be inserted to the entry block. NewBaseInsertBB = &BaseGEP->getFunction()->getEntryBlock(); NewBaseInsertPt = NewBaseInsertBB->getFirstInsertionPt(); } IRBuilder<> NewBaseBuilder(NewBaseInsertBB, NewBaseInsertPt); // Create a new base. Value *BaseIndex = ConstantInt::get(IntPtrTy, BaseOffset); NewBaseGEP = OldBase; if (NewBaseGEP->getType() != I8PtrTy) NewBaseGEP = NewBaseBuilder.CreatePointerCast(NewBaseGEP, I8PtrTy); NewBaseGEP = NewBaseBuilder.CreateGEP(I8Ty, NewBaseGEP, BaseIndex, "splitgep"); NewGEPBases.insert(NewBaseGEP); } Value *NewGEP = NewBaseGEP; if (Offset == BaseOffset) { if (GEP->getType() != I8PtrTy) NewGEP = Builder.CreatePointerCast(NewGEP, GEP->getType()); } else { // Calculate the new offset for the new GEP. Value *Index = ConstantInt::get(IntPtrTy, Offset - BaseOffset); NewGEP = Builder.CreateGEP(I8Ty, NewBaseGEP, Index); if (GEP->getType() != I8PtrTy) NewGEP = Builder.CreatePointerCast(NewGEP, GEP->getType()); } GEP->replaceAllUsesWith(NewGEP); LargeOffsetGEPID.erase(GEP); LargeOffsetGEP = LargeOffsetGEPs.erase(LargeOffsetGEP); GEP->eraseFromParent(); Changed = true; } } return Changed; } /// Return true, if an ext(load) can be formed from an extension in /// \p MovedExts. bool CodeGenPrepare::canFormExtLd( const SmallVectorImpl &MovedExts, LoadInst *&LI, Instruction *&Inst, bool HasPromoted) { for (auto *MovedExtInst : MovedExts) { if (isa(MovedExtInst->getOperand(0))) { LI = cast(MovedExtInst->getOperand(0)); Inst = MovedExtInst; break; } } if (!LI) return false; // If they're already in the same block, there's nothing to do. // Make the cheap checks first if we did not promote. // If we promoted, we need to check if it is indeed profitable. if (!HasPromoted && LI->getParent() == Inst->getParent()) return false; return TLI->isExtLoad(LI, Inst, *DL); } /// Move a zext or sext fed by a load into the same basic block as the load, /// unless conditions are unfavorable. This allows SelectionDAG to fold the /// extend into the load. /// /// E.g., /// \code /// %ld = load i32* %addr /// %add = add nuw i32 %ld, 4 /// %zext = zext i32 %add to i64 // \endcode /// => /// \code /// %ld = load i32* %addr /// %zext = zext i32 %ld to i64 /// %add = add nuw i64 %zext, 4 /// \encode /// Note that the promotion in %add to i64 is done in tryToPromoteExts(), which /// allow us to match zext(load i32*) to i64. /// /// Also, try to promote the computations used to obtain a sign extended /// value used into memory accesses. /// E.g., /// \code /// a = add nsw i32 b, 3 /// d = sext i32 a to i64 /// e = getelementptr ..., i64 d /// \endcode /// => /// \code /// f = sext i32 b to i64 /// a = add nsw i64 f, 3 /// e = getelementptr ..., i64 a /// \endcode /// /// \p Inst[in/out] the extension may be modified during the process if some /// promotions apply. bool CodeGenPrepare::optimizeExt(Instruction *&Inst) { // ExtLoad formation and address type promotion infrastructure requires TLI to // be effective. if (!TLI) return false; bool AllowPromotionWithoutCommonHeader = false; /// See if it is an interesting sext operations for the address type /// promotion before trying to promote it, e.g., the ones with the right /// type and used in memory accesses. bool ATPConsiderable = TTI->shouldConsiderAddressTypePromotion( *Inst, AllowPromotionWithoutCommonHeader); TypePromotionTransaction TPT(RemovedInsts); TypePromotionTransaction::ConstRestorationPt LastKnownGood = TPT.getRestorationPoint(); SmallVector Exts; SmallVector SpeculativelyMovedExts; Exts.push_back(Inst); bool HasPromoted = tryToPromoteExts(TPT, Exts, SpeculativelyMovedExts); // Look for a load being extended. LoadInst *LI = nullptr; Instruction *ExtFedByLoad; // Try to promote a chain of computation if it allows to form an extended // load. if (canFormExtLd(SpeculativelyMovedExts, LI, ExtFedByLoad, HasPromoted)) { assert(LI && ExtFedByLoad && "Expect a valid load and extension"); TPT.commit(); // Move the extend into the same block as the load ExtFedByLoad->moveAfter(LI); // CGP does not check if the zext would be speculatively executed when moved // to the same basic block as the load. Preserving its original location // would pessimize the debugging experience, as well as negatively impact // the quality of sample pgo. We don't want to use "line 0" as that has a // size cost in the line-table section and logically the zext can be seen as // part of the load. Therefore we conservatively reuse the same debug // location for the load and the zext. ExtFedByLoad->setDebugLoc(LI->getDebugLoc()); ++NumExtsMoved; Inst = ExtFedByLoad; return true; } // Continue promoting SExts if known as considerable depending on targets. if (ATPConsiderable && performAddressTypePromotion(Inst, AllowPromotionWithoutCommonHeader, HasPromoted, TPT, SpeculativelyMovedExts)) return true; TPT.rollback(LastKnownGood); return false; } // Perform address type promotion if doing so is profitable. // If AllowPromotionWithoutCommonHeader == false, we should find other sext // instructions that sign extended the same initial value. However, if // AllowPromotionWithoutCommonHeader == true, we expect promoting the // extension is just profitable. bool CodeGenPrepare::performAddressTypePromotion( Instruction *&Inst, bool AllowPromotionWithoutCommonHeader, bool HasPromoted, TypePromotionTransaction &TPT, SmallVectorImpl &SpeculativelyMovedExts) { bool Promoted = false; SmallPtrSet UnhandledExts; bool AllSeenFirst = true; for (auto I : SpeculativelyMovedExts) { Value *HeadOfChain = I->getOperand(0); DenseMap::iterator AlreadySeen = SeenChainsForSExt.find(HeadOfChain); // If there is an unhandled SExt which has the same header, try to promote // it as well. if (AlreadySeen != SeenChainsForSExt.end()) { if (AlreadySeen->second != nullptr) UnhandledExts.insert(AlreadySeen->second); AllSeenFirst = false; } } if (!AllSeenFirst || (AllowPromotionWithoutCommonHeader && SpeculativelyMovedExts.size() == 1)) { TPT.commit(); if (HasPromoted) Promoted = true; for (auto I : SpeculativelyMovedExts) { Value *HeadOfChain = I->getOperand(0); SeenChainsForSExt[HeadOfChain] = nullptr; ValToSExtendedUses[HeadOfChain].push_back(I); } // Update Inst as promotion happen. Inst = SpeculativelyMovedExts.pop_back_val(); } else { // This is the first chain visited from the header, keep the current chain // as unhandled. Defer to promote this until we encounter another SExt // chain derived from the same header. for (auto I : SpeculativelyMovedExts) { Value *HeadOfChain = I->getOperand(0); SeenChainsForSExt[HeadOfChain] = Inst; } return false; } if (!AllSeenFirst && !UnhandledExts.empty()) for (auto VisitedSExt : UnhandledExts) { if (RemovedInsts.count(VisitedSExt)) continue; TypePromotionTransaction TPT(RemovedInsts); SmallVector Exts; SmallVector Chains; Exts.push_back(VisitedSExt); bool HasPromoted = tryToPromoteExts(TPT, Exts, Chains); TPT.commit(); if (HasPromoted) Promoted = true; for (auto I : Chains) { Value *HeadOfChain = I->getOperand(0); // Mark this as handled. SeenChainsForSExt[HeadOfChain] = nullptr; ValToSExtendedUses[HeadOfChain].push_back(I); } } return Promoted; } bool CodeGenPrepare::optimizeExtUses(Instruction *I) { BasicBlock *DefBB = I->getParent(); // If the result of a {s|z}ext and its source are both live out, rewrite all // other uses of the source with result of extension. Value *Src = I->getOperand(0); if (Src->hasOneUse()) return false; // Only do this xform if truncating is free. if (TLI && !TLI->isTruncateFree(I->getType(), Src->getType())) return false; // Only safe to perform the optimization if the source is also defined in // this block. if (!isa(Src) || DefBB != cast(Src)->getParent()) return false; bool DefIsLiveOut = false; for (User *U : I->users()) { Instruction *UI = cast(U); // Figure out which BB this ext is used in. BasicBlock *UserBB = UI->getParent(); if (UserBB == DefBB) continue; DefIsLiveOut = true; break; } if (!DefIsLiveOut) return false; // Make sure none of the uses are PHI nodes. for (User *U : Src->users()) { Instruction *UI = cast(U); BasicBlock *UserBB = UI->getParent(); if (UserBB == DefBB) continue; // Be conservative. We don't want this xform to end up introducing // reloads just before load / store instructions. if (isa(UI) || isa(UI) || isa(UI)) return false; } // InsertedTruncs - Only insert one trunc in each block once. DenseMap InsertedTruncs; bool MadeChange = false; for (Use &U : Src->uses()) { Instruction *User = cast(U.getUser()); // Figure out which BB this ext is used in. BasicBlock *UserBB = User->getParent(); if (UserBB == DefBB) continue; // Both src and def are live in this block. Rewrite the use. Instruction *&InsertedTrunc = InsertedTruncs[UserBB]; if (!InsertedTrunc) { BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt(); assert(InsertPt != UserBB->end()); InsertedTrunc = new TruncInst(I, Src->getType(), "", &*InsertPt); InsertedInsts.insert(InsertedTrunc); } // Replace a use of the {s|z}ext source with a use of the result. U = InsertedTrunc; ++NumExtUses; MadeChange = true; } return MadeChange; } // Find loads whose uses only use some of the loaded value's bits. Add an "and" // just after the load if the target can fold this into one extload instruction, // with the hope of eliminating some of the other later "and" instructions using // the loaded value. "and"s that are made trivially redundant by the insertion // of the new "and" are removed by this function, while others (e.g. those whose // path from the load goes through a phi) are left for isel to potentially // remove. // // For example: // // b0: // x = load i32 // ... // b1: // y = and x, 0xff // z = use y // // becomes: // // b0: // x = load i32 // x' = and x, 0xff // ... // b1: // z = use x' // // whereas: // // b0: // x1 = load i32 // ... // b1: // x2 = load i32 // ... // b2: // x = phi x1, x2 // y = and x, 0xff // // becomes (after a call to optimizeLoadExt for each load): // // b0: // x1 = load i32 // x1' = and x1, 0xff // ... // b1: // x2 = load i32 // x2' = and x2, 0xff // ... // b2: // x = phi x1', x2' // y = and x, 0xff bool CodeGenPrepare::optimizeLoadExt(LoadInst *Load) { if (!Load->isSimple() || !Load->getType()->isIntOrPtrTy()) return false; // Skip loads we've already transformed. if (Load->hasOneUse() && InsertedInsts.count(cast(*Load->user_begin()))) return false; // Look at all uses of Load, looking through phis, to determine how many bits // of the loaded value are needed. SmallVector WorkList; SmallPtrSet Visited; SmallVector AndsToMaybeRemove; for (auto *U : Load->users()) WorkList.push_back(cast(U)); EVT LoadResultVT = TLI->getValueType(*DL, Load->getType()); unsigned BitWidth = LoadResultVT.getSizeInBits(); APInt DemandBits(BitWidth, 0); APInt WidestAndBits(BitWidth, 0); while (!WorkList.empty()) { Instruction *I = WorkList.back(); WorkList.pop_back(); // Break use-def graph loops. if (!Visited.insert(I).second) continue; // For a PHI node, push all of its users. if (auto *Phi = dyn_cast(I)) { for (auto *U : Phi->users()) WorkList.push_back(cast(U)); continue; } switch (I->getOpcode()) { case Instruction::And: { auto *AndC = dyn_cast(I->getOperand(1)); if (!AndC) return false; APInt AndBits = AndC->getValue(); DemandBits |= AndBits; // Keep track of the widest and mask we see. if (AndBits.ugt(WidestAndBits)) WidestAndBits = AndBits; if (AndBits == WidestAndBits && I->getOperand(0) == Load) AndsToMaybeRemove.push_back(I); break; } case Instruction::Shl: { auto *ShlC = dyn_cast(I->getOperand(1)); if (!ShlC) return false; uint64_t ShiftAmt = ShlC->getLimitedValue(BitWidth - 1); DemandBits.setLowBits(BitWidth - ShiftAmt); break; } case Instruction::Trunc: { EVT TruncVT = TLI->getValueType(*DL, I->getType()); unsigned TruncBitWidth = TruncVT.getSizeInBits(); DemandBits.setLowBits(TruncBitWidth); break; } default: return false; } } uint32_t ActiveBits = DemandBits.getActiveBits(); // Avoid hoisting (and (load x) 1) since it is unlikely to be folded by the // target even if isLoadExtLegal says an i1 EXTLOAD is valid. For example, // for the AArch64 target isLoadExtLegal(ZEXTLOAD, i32, i1) returns true, but // (and (load x) 1) is not matched as a single instruction, rather as a LDR // followed by an AND. // TODO: Look into removing this restriction by fixing backends to either // return false for isLoadExtLegal for i1 or have them select this pattern to // a single instruction. // // Also avoid hoisting if we didn't see any ands with the exact DemandBits // mask, since these are the only ands that will be removed by isel. if (ActiveBits <= 1 || !DemandBits.isMask(ActiveBits) || WidestAndBits != DemandBits) return false; LLVMContext &Ctx = Load->getType()->getContext(); Type *TruncTy = Type::getIntNTy(Ctx, ActiveBits); EVT TruncVT = TLI->getValueType(*DL, TruncTy); // Reject cases that won't be matched as extloads. if (!LoadResultVT.bitsGT(TruncVT) || !TruncVT.isRound() || !TLI->isLoadExtLegal(ISD::ZEXTLOAD, LoadResultVT, TruncVT)) return false; IRBuilder<> Builder(Load->getNextNode()); auto *NewAnd = dyn_cast( Builder.CreateAnd(Load, ConstantInt::get(Ctx, DemandBits))); // Mark this instruction as "inserted by CGP", so that other // optimizations don't touch it. InsertedInsts.insert(NewAnd); // Replace all uses of load with new and (except for the use of load in the // new and itself). Load->replaceAllUsesWith(NewAnd); NewAnd->setOperand(0, Load); // Remove any and instructions that are now redundant. for (auto *And : AndsToMaybeRemove) // Check that the and mask is the same as the one we decided to put on the // new and. if (cast(And->getOperand(1))->getValue() == DemandBits) { And->replaceAllUsesWith(NewAnd); if (&*CurInstIterator == And) CurInstIterator = std::next(And->getIterator()); And->eraseFromParent(); ++NumAndUses; } ++NumAndsAdded; return true; } /// Check if V (an operand of a select instruction) is an expensive instruction /// that is only used once. static bool sinkSelectOperand(const TargetTransformInfo *TTI, Value *V) { auto *I = dyn_cast(V); // If it's safe to speculatively execute, then it should not have side // effects; therefore, it's safe to sink and possibly *not* execute. return I && I->hasOneUse() && isSafeToSpeculativelyExecute(I) && TTI->getUserCost(I) >= TargetTransformInfo::TCC_Expensive; } /// Returns true if a SelectInst should be turned into an explicit branch. static bool isFormingBranchFromSelectProfitable(const TargetTransformInfo *TTI, const TargetLowering *TLI, SelectInst *SI) { // If even a predictable select is cheap, then a branch can't be cheaper. if (!TLI->isPredictableSelectExpensive()) return false; // FIXME: This should use the same heuristics as IfConversion to determine // whether a select is better represented as a branch. // If metadata tells us that the select condition is obviously predictable, // then we want to replace the select with a branch. uint64_t TrueWeight, FalseWeight; if (SI->extractProfMetadata(TrueWeight, FalseWeight)) { uint64_t Max = std::max(TrueWeight, FalseWeight); uint64_t Sum = TrueWeight + FalseWeight; if (Sum != 0) { auto Probability = BranchProbability::getBranchProbability(Max, Sum); if (Probability > TLI->getPredictableBranchThreshold()) return true; } } CmpInst *Cmp = dyn_cast(SI->getCondition()); // If a branch is predictable, an out-of-order CPU can avoid blocking on its // comparison condition. If the compare has more than one use, there's // probably another cmov or setcc around, so it's not worth emitting a branch. if (!Cmp || !Cmp->hasOneUse()) return false; // If either operand of the select is expensive and only needed on one side // of the select, we should form a branch. if (sinkSelectOperand(TTI, SI->getTrueValue()) || sinkSelectOperand(TTI, SI->getFalseValue())) return true; return false; } /// If \p isTrue is true, return the true value of \p SI, otherwise return /// false value of \p SI. If the true/false value of \p SI is defined by any /// select instructions in \p Selects, look through the defining select /// instruction until the true/false value is not defined in \p Selects. static Value *getTrueOrFalseValue( SelectInst *SI, bool isTrue, const SmallPtrSet &Selects) { Value *V; for (SelectInst *DefSI = SI; DefSI != nullptr && Selects.count(DefSI); DefSI = dyn_cast(V)) { assert(DefSI->getCondition() == SI->getCondition() && "The condition of DefSI does not match with SI"); V = (isTrue ? DefSI->getTrueValue() : DefSI->getFalseValue()); } return V; } /// If we have a SelectInst that will likely profit from branch prediction, /// turn it into a branch. bool CodeGenPrepare::optimizeSelectInst(SelectInst *SI) { // Find all consecutive select instructions that share the same condition. SmallVector ASI; ASI.push_back(SI); for (BasicBlock::iterator It = ++BasicBlock::iterator(SI); It != SI->getParent()->end(); ++It) { SelectInst *I = dyn_cast(&*It); if (I && SI->getCondition() == I->getCondition()) { ASI.push_back(I); } else { break; } } SelectInst *LastSI = ASI.back(); // Increment the current iterator to skip all the rest of select instructions // because they will be either "not lowered" or "all lowered" to branch. CurInstIterator = std::next(LastSI->getIterator()); bool VectorCond = !SI->getCondition()->getType()->isIntegerTy(1); // Can we convert the 'select' to CF ? if (DisableSelectToBranch || OptSize || !TLI || VectorCond || SI->getMetadata(LLVMContext::MD_unpredictable)) return false; TargetLowering::SelectSupportKind SelectKind; if (VectorCond) SelectKind = TargetLowering::VectorMaskSelect; else if (SI->getType()->isVectorTy()) SelectKind = TargetLowering::ScalarCondVectorVal; else SelectKind = TargetLowering::ScalarValSelect; if (TLI->isSelectSupported(SelectKind) && !isFormingBranchFromSelectProfitable(TTI, TLI, SI)) return false; ModifiedDT = true; // Transform a sequence like this: // start: // %cmp = cmp uge i32 %a, %b // %sel = select i1 %cmp, i32 %c, i32 %d // // Into: // start: // %cmp = cmp uge i32 %a, %b // br i1 %cmp, label %select.true, label %select.false // select.true: // br label %select.end // select.false: // br label %select.end // select.end: // %sel = phi i32 [ %c, %select.true ], [ %d, %select.false ] // // In addition, we may sink instructions that produce %c or %d from // the entry block into the destination(s) of the new branch. // If the true or false blocks do not contain a sunken instruction, that // block and its branch may be optimized away. In that case, one side of the // first branch will point directly to select.end, and the corresponding PHI // predecessor block will be the start block. // First, we split the block containing the select into 2 blocks. BasicBlock *StartBlock = SI->getParent(); BasicBlock::iterator SplitPt = ++(BasicBlock::iterator(LastSI)); BasicBlock *EndBlock = StartBlock->splitBasicBlock(SplitPt, "select.end"); // Delete the unconditional branch that was just created by the split. StartBlock->getTerminator()->eraseFromParent(); // These are the new basic blocks for the conditional branch. // At least one will become an actual new basic block. BasicBlock *TrueBlock = nullptr; BasicBlock *FalseBlock = nullptr; BranchInst *TrueBranch = nullptr; BranchInst *FalseBranch = nullptr; // Sink expensive instructions into the conditional blocks to avoid executing // them speculatively. for (SelectInst *SI : ASI) { if (sinkSelectOperand(TTI, SI->getTrueValue())) { if (TrueBlock == nullptr) { TrueBlock = BasicBlock::Create(SI->getContext(), "select.true.sink", EndBlock->getParent(), EndBlock); TrueBranch = BranchInst::Create(EndBlock, TrueBlock); } auto *TrueInst = cast(SI->getTrueValue()); TrueInst->moveBefore(TrueBranch); } if (sinkSelectOperand(TTI, SI->getFalseValue())) { if (FalseBlock == nullptr) { FalseBlock = BasicBlock::Create(SI->getContext(), "select.false.sink", EndBlock->getParent(), EndBlock); FalseBranch = BranchInst::Create(EndBlock, FalseBlock); } auto *FalseInst = cast(SI->getFalseValue()); FalseInst->moveBefore(FalseBranch); } } // If there was nothing to sink, then arbitrarily choose the 'false' side // for a new input value to the PHI. if (TrueBlock == FalseBlock) { assert(TrueBlock == nullptr && "Unexpected basic block transform while optimizing select"); FalseBlock = BasicBlock::Create(SI->getContext(), "select.false", EndBlock->getParent(), EndBlock); BranchInst::Create(EndBlock, FalseBlock); } // Insert the real conditional branch based on the original condition. // If we did not create a new block for one of the 'true' or 'false' paths // of the condition, it means that side of the branch goes to the end block // directly and the path originates from the start block from the point of // view of the new PHI. BasicBlock *TT, *FT; if (TrueBlock == nullptr) { TT = EndBlock; FT = FalseBlock; TrueBlock = StartBlock; } else if (FalseBlock == nullptr) { TT = TrueBlock; FT = EndBlock; FalseBlock = StartBlock; } else { TT = TrueBlock; FT = FalseBlock; } IRBuilder<>(SI).CreateCondBr(SI->getCondition(), TT, FT, SI); SmallPtrSet INS; INS.insert(ASI.begin(), ASI.end()); // Use reverse iterator because later select may use the value of the // earlier select, and we need to propagate value through earlier select // to get the PHI operand. for (auto It = ASI.rbegin(); It != ASI.rend(); ++It) { SelectInst *SI = *It; // The select itself is replaced with a PHI Node. PHINode *PN = PHINode::Create(SI->getType(), 2, "", &EndBlock->front()); PN->takeName(SI); PN->addIncoming(getTrueOrFalseValue(SI, true, INS), TrueBlock); PN->addIncoming(getTrueOrFalseValue(SI, false, INS), FalseBlock); SI->replaceAllUsesWith(PN); SI->eraseFromParent(); INS.erase(SI); ++NumSelectsExpanded; } // Instruct OptimizeBlock to skip to the next block. CurInstIterator = StartBlock->end(); return true; } static bool isBroadcastShuffle(ShuffleVectorInst *SVI) { SmallVector Mask(SVI->getShuffleMask()); int SplatElem = -1; for (unsigned i = 0; i < Mask.size(); ++i) { if (SplatElem != -1 && Mask[i] != -1 && Mask[i] != SplatElem) return false; SplatElem = Mask[i]; } return true; } /// Some targets have expensive vector shifts if the lanes aren't all the same /// (e.g. x86 only introduced "vpsllvd" and friends with AVX2). In these cases /// it's often worth sinking a shufflevector splat down to its use so that /// codegen can spot all lanes are identical. bool CodeGenPrepare::optimizeShuffleVectorInst(ShuffleVectorInst *SVI) { BasicBlock *DefBB = SVI->getParent(); // Only do this xform if variable vector shifts are particularly expensive. if (!TLI || !TLI->isVectorShiftByScalarCheap(SVI->getType())) return false; // We only expect better codegen by sinking a shuffle if we can recognise a // constant splat. if (!isBroadcastShuffle(SVI)) return false; // InsertedShuffles - Only insert a shuffle in each block once. DenseMap InsertedShuffles; bool MadeChange = false; for (User *U : SVI->users()) { Instruction *UI = cast(U); // Figure out which BB this ext is used in. BasicBlock *UserBB = UI->getParent(); if (UserBB == DefBB) continue; // For now only apply this when the splat is used by a shift instruction. if (!UI->isShift()) continue; // Everything checks out, sink the shuffle if the user's block doesn't // already have a copy. Instruction *&InsertedShuffle = InsertedShuffles[UserBB]; if (!InsertedShuffle) { BasicBlock::iterator InsertPt = UserBB->getFirstInsertionPt(); assert(InsertPt != UserBB->end()); InsertedShuffle = new ShuffleVectorInst(SVI->getOperand(0), SVI->getOperand(1), SVI->getOperand(2), "", &*InsertPt); } UI->replaceUsesOfWith(SVI, InsertedShuffle); MadeChange = true; } // If we removed all uses, nuke the shuffle. if (SVI->use_empty()) { SVI->eraseFromParent(); MadeChange = true; } return MadeChange; } bool CodeGenPrepare::optimizeSwitchInst(SwitchInst *SI) { if (!TLI || !DL) return false; Value *Cond = SI->getCondition(); Type *OldType = Cond->getType(); LLVMContext &Context = Cond->getContext(); MVT RegType = TLI->getRegisterType(Context, TLI->getValueType(*DL, OldType)); unsigned RegWidth = RegType.getSizeInBits(); if (RegWidth <= cast(OldType)->getBitWidth()) return false; // If the register width is greater than the type width, expand the condition // of the switch instruction and each case constant to the width of the // register. By widening the type of the switch condition, subsequent // comparisons (for case comparisons) will not need to be extended to the // preferred register width, so we will potentially eliminate N-1 extends, // where N is the number of cases in the switch. auto *NewType = Type::getIntNTy(Context, RegWidth); // Zero-extend the switch condition and case constants unless the switch // condition is a function argument that is already being sign-extended. // In that case, we can avoid an unnecessary mask/extension by sign-extending // everything instead. Instruction::CastOps ExtType = Instruction::ZExt; if (auto *Arg = dyn_cast(Cond)) if (Arg->hasSExtAttr()) ExtType = Instruction::SExt; auto *ExtInst = CastInst::Create(ExtType, Cond, NewType); ExtInst->insertBefore(SI); SI->setCondition(ExtInst); for (auto Case : SI->cases()) { APInt NarrowConst = Case.getCaseValue()->getValue(); APInt WideConst = (ExtType == Instruction::ZExt) ? NarrowConst.zext(RegWidth) : NarrowConst.sext(RegWidth); Case.setValue(ConstantInt::get(Context, WideConst)); } return true; } namespace { /// Helper class to promote a scalar operation to a vector one. /// This class is used to move downward extractelement transition. /// E.g., /// a = vector_op <2 x i32> /// b = extractelement <2 x i32> a, i32 0 /// c = scalar_op b /// store c /// /// => /// a = vector_op <2 x i32> /// c = vector_op a (equivalent to scalar_op on the related lane) /// * d = extractelement <2 x i32> c, i32 0 /// * store d /// Assuming both extractelement and store can be combine, we get rid of the /// transition. class VectorPromoteHelper { /// DataLayout associated with the current module. const DataLayout &DL; /// Used to perform some checks on the legality of vector operations. const TargetLowering &TLI; /// Used to estimated the cost of the promoted chain. const TargetTransformInfo &TTI; /// The transition being moved downwards. Instruction *Transition; /// The sequence of instructions to be promoted. SmallVector InstsToBePromoted; /// Cost of combining a store and an extract. unsigned StoreExtractCombineCost; /// Instruction that will be combined with the transition. Instruction *CombineInst = nullptr; /// The instruction that represents the current end of the transition. /// Since we are faking the promotion until we reach the end of the chain /// of computation, we need a way to get the current end of the transition. Instruction *getEndOfTransition() const { if (InstsToBePromoted.empty()) return Transition; return InstsToBePromoted.back(); } /// Return the index of the original value in the transition. /// E.g., for "extractelement <2 x i32> c, i32 1" the original value, /// c, is at index 0. unsigned getTransitionOriginalValueIdx() const { assert(isa(Transition) && "Other kind of transitions are not supported yet"); return 0; } /// Return the index of the index in the transition. /// E.g., for "extractelement <2 x i32> c, i32 0" the index /// is at index 1. unsigned getTransitionIdx() const { assert(isa(Transition) && "Other kind of transitions are not supported yet"); return 1; } /// Get the type of the transition. /// This is the type of the original value. /// E.g., for "extractelement <2 x i32> c, i32 1" the type of the /// transition is <2 x i32>. Type *getTransitionType() const { return Transition->getOperand(getTransitionOriginalValueIdx())->getType(); } /// Promote \p ToBePromoted by moving \p Def downward through. /// I.e., we have the following sequence: /// Def = Transition a to /// b = ToBePromoted Def, ... /// => /// b = ToBePromoted a, ... /// Def = Transition ToBePromoted to void promoteImpl(Instruction *ToBePromoted); /// Check whether or not it is profitable to promote all the /// instructions enqueued to be promoted. bool isProfitableToPromote() { Value *ValIdx = Transition->getOperand(getTransitionOriginalValueIdx()); unsigned Index = isa(ValIdx) ? cast(ValIdx)->getZExtValue() : -1; Type *PromotedType = getTransitionType(); StoreInst *ST = cast(CombineInst); unsigned AS = ST->getPointerAddressSpace(); unsigned Align = ST->getAlignment(); // Check if this store is supported. if (!TLI.allowsMisalignedMemoryAccesses( TLI.getValueType(DL, ST->getValueOperand()->getType()), AS, Align)) { // If this is not supported, there is no way we can combine // the extract with the store. return false; } // The scalar chain of computation has to pay for the transition // scalar to vector. // The vector chain has to account for the combining cost. uint64_t ScalarCost = TTI.getVectorInstrCost(Transition->getOpcode(), PromotedType, Index); uint64_t VectorCost = StoreExtractCombineCost; for (const auto &Inst : InstsToBePromoted) { // Compute the cost. // By construction, all instructions being promoted are arithmetic ones. // Moreover, one argument is a constant that can be viewed as a splat // constant. Value *Arg0 = Inst->getOperand(0); bool IsArg0Constant = isa(Arg0) || isa(Arg0) || isa(Arg0); TargetTransformInfo::OperandValueKind Arg0OVK = IsArg0Constant ? TargetTransformInfo::OK_UniformConstantValue : TargetTransformInfo::OK_AnyValue; TargetTransformInfo::OperandValueKind Arg1OVK = !IsArg0Constant ? TargetTransformInfo::OK_UniformConstantValue : TargetTransformInfo::OK_AnyValue; ScalarCost += TTI.getArithmeticInstrCost( Inst->getOpcode(), Inst->getType(), Arg0OVK, Arg1OVK); VectorCost += TTI.getArithmeticInstrCost(Inst->getOpcode(), PromotedType, Arg0OVK, Arg1OVK); } LLVM_DEBUG( dbgs() << "Estimated cost of computation to be promoted:\nScalar: " << ScalarCost << "\nVector: " << VectorCost << '\n'); return ScalarCost > VectorCost; } /// Generate a constant vector with \p Val with the same /// number of elements as the transition. /// \p UseSplat defines whether or not \p Val should be replicated /// across the whole vector. /// In other words, if UseSplat == true, we generate , /// otherwise we generate a vector with as many undef as possible: /// where \p Val is only /// used at the index of the extract. Value *getConstantVector(Constant *Val, bool UseSplat) const { unsigned ExtractIdx = std::numeric_limits::max(); if (!UseSplat) { // If we cannot determine where the constant must be, we have to // use a splat constant. Value *ValExtractIdx = Transition->getOperand(getTransitionIdx()); if (ConstantInt *CstVal = dyn_cast(ValExtractIdx)) ExtractIdx = CstVal->getSExtValue(); else UseSplat = true; } unsigned End = getTransitionType()->getVectorNumElements(); if (UseSplat) return ConstantVector::getSplat(End, Val); SmallVector ConstVec; UndefValue *UndefVal = UndefValue::get(Val->getType()); for (unsigned Idx = 0; Idx != End; ++Idx) { if (Idx == ExtractIdx) ConstVec.push_back(Val); else ConstVec.push_back(UndefVal); } return ConstantVector::get(ConstVec); } /// Check if promoting to a vector type an operand at \p OperandIdx /// in \p Use can trigger undefined behavior. static bool canCauseUndefinedBehavior(const Instruction *Use, unsigned OperandIdx) { // This is not safe to introduce undef when the operand is on // the right hand side of a division-like instruction. if (OperandIdx != 1) return false; switch (Use->getOpcode()) { default: return false; case Instruction::SDiv: case Instruction::UDiv: case Instruction::SRem: case Instruction::URem: return true; case Instruction::FDiv: case Instruction::FRem: return !Use->hasNoNaNs(); } llvm_unreachable(nullptr); } public: VectorPromoteHelper(const DataLayout &DL, const TargetLowering &TLI, const TargetTransformInfo &TTI, Instruction *Transition, unsigned CombineCost) : DL(DL), TLI(TLI), TTI(TTI), Transition(Transition), StoreExtractCombineCost(CombineCost) { assert(Transition && "Do not know how to promote null"); } /// Check if we can promote \p ToBePromoted to \p Type. bool canPromote(const Instruction *ToBePromoted) const { // We could support CastInst too. return isa(ToBePromoted); } /// Check if it is profitable to promote \p ToBePromoted /// by moving downward the transition through. bool shouldPromote(const Instruction *ToBePromoted) const { // Promote only if all the operands can be statically expanded. // Indeed, we do not want to introduce any new kind of transitions. for (const Use &U : ToBePromoted->operands()) { const Value *Val = U.get(); if (Val == getEndOfTransition()) { // If the use is a division and the transition is on the rhs, // we cannot promote the operation, otherwise we may create a // division by zero. if (canCauseUndefinedBehavior(ToBePromoted, U.getOperandNo())) return false; continue; } if (!isa(Val) && !isa(Val) && !isa(Val)) return false; } // Check that the resulting operation is legal. int ISDOpcode = TLI.InstructionOpcodeToISD(ToBePromoted->getOpcode()); if (!ISDOpcode) return false; return StressStoreExtract || TLI.isOperationLegalOrCustom( ISDOpcode, TLI.getValueType(DL, getTransitionType(), true)); } /// Check whether or not \p Use can be combined /// with the transition. /// I.e., is it possible to do Use(Transition) => AnotherUse? bool canCombine(const Instruction *Use) { return isa(Use); } /// Record \p ToBePromoted as part of the chain to be promoted. void enqueueForPromotion(Instruction *ToBePromoted) { InstsToBePromoted.push_back(ToBePromoted); } /// Set the instruction that will be combined with the transition. void recordCombineInstruction(Instruction *ToBeCombined) { assert(canCombine(ToBeCombined) && "Unsupported instruction to combine"); CombineInst = ToBeCombined; } /// Promote all the instructions enqueued for promotion if it is /// is profitable. /// \return True if the promotion happened, false otherwise. bool promote() { // Check if there is something to promote. // Right now, if we do not have anything to combine with, // we assume the promotion is not profitable. if (InstsToBePromoted.empty() || !CombineInst) return false; // Check cost. if (!StressStoreExtract && !isProfitableToPromote()) return false; // Promote. for (auto &ToBePromoted : InstsToBePromoted) promoteImpl(ToBePromoted); InstsToBePromoted.clear(); return true; } }; } // end anonymous namespace void VectorPromoteHelper::promoteImpl(Instruction *ToBePromoted) { // At this point, we know that all the operands of ToBePromoted but Def // can be statically promoted. // For Def, we need to use its parameter in ToBePromoted: // b = ToBePromoted ty1 a // Def = Transition ty1 b to ty2 // Move the transition down. // 1. Replace all uses of the promoted operation by the transition. // = ... b => = ... Def. assert(ToBePromoted->getType() == Transition->getType() && "The type of the result of the transition does not match " "the final type"); ToBePromoted->replaceAllUsesWith(Transition); // 2. Update the type of the uses. // b = ToBePromoted ty2 Def => b = ToBePromoted ty1 Def. Type *TransitionTy = getTransitionType(); ToBePromoted->mutateType(TransitionTy); // 3. Update all the operands of the promoted operation with promoted // operands. // b = ToBePromoted ty1 Def => b = ToBePromoted ty1 a. for (Use &U : ToBePromoted->operands()) { Value *Val = U.get(); Value *NewVal = nullptr; if (Val == Transition) NewVal = Transition->getOperand(getTransitionOriginalValueIdx()); else if (isa(Val) || isa(Val) || isa(Val)) { // Use a splat constant if it is not safe to use undef. NewVal = getConstantVector( cast(Val), isa(Val) || canCauseUndefinedBehavior(ToBePromoted, U.getOperandNo())); } else llvm_unreachable("Did you modified shouldPromote and forgot to update " "this?"); ToBePromoted->setOperand(U.getOperandNo(), NewVal); } Transition->moveAfter(ToBePromoted); Transition->setOperand(getTransitionOriginalValueIdx(), ToBePromoted); } /// Some targets can do store(extractelement) with one instruction. /// Try to push the extractelement towards the stores when the target /// has this feature and this is profitable. bool CodeGenPrepare::optimizeExtractElementInst(Instruction *Inst) { unsigned CombineCost = std::numeric_limits::max(); if (DisableStoreExtract || !TLI || (!StressStoreExtract && !TLI->canCombineStoreAndExtract(Inst->getOperand(0)->getType(), Inst->getOperand(1), CombineCost))) return false; // At this point we know that Inst is a vector to scalar transition. // Try to move it down the def-use chain, until: // - We can combine the transition with its single use // => we got rid of the transition. // - We escape the current basic block // => we would need to check that we are moving it at a cheaper place and // we do not do that for now. BasicBlock *Parent = Inst->getParent(); LLVM_DEBUG(dbgs() << "Found an interesting transition: " << *Inst << '\n'); VectorPromoteHelper VPH(*DL, *TLI, *TTI, Inst, CombineCost); // If the transition has more than one use, assume this is not going to be // beneficial. while (Inst->hasOneUse()) { Instruction *ToBePromoted = cast(*Inst->user_begin()); LLVM_DEBUG(dbgs() << "Use: " << *ToBePromoted << '\n'); if (ToBePromoted->getParent() != Parent) { LLVM_DEBUG(dbgs() << "Instruction to promote is in a different block (" << ToBePromoted->getParent()->getName() << ") than the transition (" << Parent->getName() << ").\n"); return false; } if (VPH.canCombine(ToBePromoted)) { LLVM_DEBUG(dbgs() << "Assume " << *Inst << '\n' << "will be combined with: " << *ToBePromoted << '\n'); VPH.recordCombineInstruction(ToBePromoted); bool Changed = VPH.promote(); NumStoreExtractExposed += Changed; return Changed; } LLVM_DEBUG(dbgs() << "Try promoting.\n"); if (!VPH.canPromote(ToBePromoted) || !VPH.shouldPromote(ToBePromoted)) return false; LLVM_DEBUG(dbgs() << "Promoting is possible... Enqueue for promotion!\n"); VPH.enqueueForPromotion(ToBePromoted); Inst = ToBePromoted; } return false; } /// For the instruction sequence of store below, F and I values /// are bundled together as an i64 value before being stored into memory. /// Sometimes it is more efficient to generate separate stores for F and I, /// which can remove the bitwise instructions or sink them to colder places. /// /// (store (or (zext (bitcast F to i32) to i64), /// (shl (zext I to i64), 32)), addr) --> /// (store F, addr) and (store I, addr+4) /// /// Similarly, splitting for other merged store can also be beneficial, like: /// For pair of {i32, i32}, i64 store --> two i32 stores. /// For pair of {i32, i16}, i64 store --> two i32 stores. /// For pair of {i16, i16}, i32 store --> two i16 stores. /// For pair of {i16, i8}, i32 store --> two i16 stores. /// For pair of {i8, i8}, i16 store --> two i8 stores. /// /// We allow each target to determine specifically which kind of splitting is /// supported. /// /// The store patterns are commonly seen from the simple code snippet below /// if only std::make_pair(...) is sroa transformed before inlined into hoo. /// void goo(const std::pair &); /// hoo() { /// ... /// goo(std::make_pair(tmp, ftmp)); /// ... /// } /// /// Although we already have similar splitting in DAG Combine, we duplicate /// it in CodeGenPrepare to catch the case in which pattern is across /// multiple BBs. The logic in DAG Combine is kept to catch case generated /// during code expansion. static bool splitMergedValStore(StoreInst &SI, const DataLayout &DL, const TargetLowering &TLI) { // Handle simple but common cases only. Type *StoreType = SI.getValueOperand()->getType(); if (DL.getTypeStoreSizeInBits(StoreType) != DL.getTypeSizeInBits(StoreType) || DL.getTypeSizeInBits(StoreType) == 0) return false; unsigned HalfValBitSize = DL.getTypeSizeInBits(StoreType) / 2; Type *SplitStoreType = Type::getIntNTy(SI.getContext(), HalfValBitSize); if (DL.getTypeStoreSizeInBits(SplitStoreType) != DL.getTypeSizeInBits(SplitStoreType)) return false; // Match the following patterns: // (store (or (zext LValue to i64), // (shl (zext HValue to i64), 32)), HalfValBitSize) // or // (store (or (shl (zext HValue to i64), 32)), HalfValBitSize) // (zext LValue to i64), // Expect both operands of OR and the first operand of SHL have only // one use. Value *LValue, *HValue; if (!match(SI.getValueOperand(), m_c_Or(m_OneUse(m_ZExt(m_Value(LValue))), m_OneUse(m_Shl(m_OneUse(m_ZExt(m_Value(HValue))), m_SpecificInt(HalfValBitSize)))))) return false; // Check LValue and HValue are int with size less or equal than 32. if (!LValue->getType()->isIntegerTy() || DL.getTypeSizeInBits(LValue->getType()) > HalfValBitSize || !HValue->getType()->isIntegerTy() || DL.getTypeSizeInBits(HValue->getType()) > HalfValBitSize) return false; // If LValue/HValue is a bitcast instruction, use the EVT before bitcast // as the input of target query. auto *LBC = dyn_cast(LValue); auto *HBC = dyn_cast(HValue); EVT LowTy = LBC ? EVT::getEVT(LBC->getOperand(0)->getType()) : EVT::getEVT(LValue->getType()); EVT HighTy = HBC ? EVT::getEVT(HBC->getOperand(0)->getType()) : EVT::getEVT(HValue->getType()); if (!ForceSplitStore && !TLI.isMultiStoresCheaperThanBitsMerge(LowTy, HighTy)) return false; // Start to split store. IRBuilder<> Builder(SI.getContext()); Builder.SetInsertPoint(&SI); // If LValue/HValue is a bitcast in another BB, create a new one in current // BB so it may be merged with the splitted stores by dag combiner. if (LBC && LBC->getParent() != SI.getParent()) LValue = Builder.CreateBitCast(LBC->getOperand(0), LBC->getType()); if (HBC && HBC->getParent() != SI.getParent()) HValue = Builder.CreateBitCast(HBC->getOperand(0), HBC->getType()); bool IsLE = SI.getModule()->getDataLayout().isLittleEndian(); auto CreateSplitStore = [&](Value *V, bool Upper) { V = Builder.CreateZExtOrBitCast(V, SplitStoreType); Value *Addr = Builder.CreateBitCast( SI.getOperand(1), SplitStoreType->getPointerTo(SI.getPointerAddressSpace())); if ((IsLE && Upper) || (!IsLE && !Upper)) Addr = Builder.CreateGEP( SplitStoreType, Addr, ConstantInt::get(Type::getInt32Ty(SI.getContext()), 1)); Builder.CreateAlignedStore( V, Addr, Upper ? SI.getAlignment() / 2 : SI.getAlignment()); }; CreateSplitStore(LValue, false); CreateSplitStore(HValue, true); // Delete the old store. SI.eraseFromParent(); return true; } // Return true if the GEP has two operands, the first operand is of a sequential // type, and the second operand is a constant. static bool GEPSequentialConstIndexed(GetElementPtrInst *GEP) { gep_type_iterator I = gep_type_begin(*GEP); return GEP->getNumOperands() == 2 && I.isSequential() && isa(GEP->getOperand(1)); } // Try unmerging GEPs to reduce liveness interference (register pressure) across // IndirectBr edges. Since IndirectBr edges tend to touch on many blocks, // reducing liveness interference across those edges benefits global register // allocation. Currently handles only certain cases. // // For example, unmerge %GEPI and %UGEPI as below. // // ---------- BEFORE ---------- // SrcBlock: // ... // %GEPIOp = ... // ... // %GEPI = gep %GEPIOp, Idx // ... // indirectbr ... [ label %DstB0, label %DstB1, ... label %DstBi ... ] // (* %GEPI is alive on the indirectbr edges due to other uses ahead) // (* %GEPIOp is alive on the indirectbr edges only because of it's used by // %UGEPI) // // DstB0: ... (there may be a gep similar to %UGEPI to be unmerged) // DstB1: ... (there may be a gep similar to %UGEPI to be unmerged) // ... // // DstBi: // ... // %UGEPI = gep %GEPIOp, UIdx // ... // --------------------------- // // ---------- AFTER ---------- // SrcBlock: // ... (same as above) // (* %GEPI is still alive on the indirectbr edges) // (* %GEPIOp is no longer alive on the indirectbr edges as a result of the // unmerging) // ... // // DstBi: // ... // %UGEPI = gep %GEPI, (UIdx-Idx) // ... // --------------------------- // // The register pressure on the IndirectBr edges is reduced because %GEPIOp is // no longer alive on them. // // We try to unmerge GEPs here in CodGenPrepare, as opposed to limiting merging // of GEPs in the first place in InstCombiner::visitGetElementPtrInst() so as // not to disable further simplications and optimizations as a result of GEP // merging. // // Note this unmerging may increase the length of the data flow critical path // (the path from %GEPIOp to %UGEPI would go through %GEPI), which is a tradeoff // between the register pressure and the length of data-flow critical // path. Restricting this to the uncommon IndirectBr case would minimize the // impact of potentially longer critical path, if any, and the impact on compile // time. static bool tryUnmergingGEPsAcrossIndirectBr(GetElementPtrInst *GEPI, const TargetTransformInfo *TTI) { BasicBlock *SrcBlock = GEPI->getParent(); // Check that SrcBlock ends with an IndirectBr. If not, give up. The common // (non-IndirectBr) cases exit early here. if (!isa(SrcBlock->getTerminator())) return false; // Check that GEPI is a simple gep with a single constant index. if (!GEPSequentialConstIndexed(GEPI)) return false; ConstantInt *GEPIIdx = cast(GEPI->getOperand(1)); // Check that GEPI is a cheap one. if (TTI->getIntImmCost(GEPIIdx->getValue(), GEPIIdx->getType()) > TargetTransformInfo::TCC_Basic) return false; Value *GEPIOp = GEPI->getOperand(0); // Check that GEPIOp is an instruction that's also defined in SrcBlock. if (!isa(GEPIOp)) return false; auto *GEPIOpI = cast(GEPIOp); if (GEPIOpI->getParent() != SrcBlock) return false; // Check that GEP is used outside the block, meaning it's alive on the // IndirectBr edge(s). if (find_if(GEPI->users(), [&](User *Usr) { if (auto *I = dyn_cast(Usr)) { if (I->getParent() != SrcBlock) { return true; } } return false; }) == GEPI->users().end()) return false; // The second elements of the GEP chains to be unmerged. std::vector UGEPIs; // Check each user of GEPIOp to check if unmerging would make GEPIOp not alive // on IndirectBr edges. for (User *Usr : GEPIOp->users()) { if (Usr == GEPI) continue; // Check if Usr is an Instruction. If not, give up. if (!isa(Usr)) return false; auto *UI = cast(Usr); // Check if Usr in the same block as GEPIOp, which is fine, skip. if (UI->getParent() == SrcBlock) continue; // Check if Usr is a GEP. If not, give up. if (!isa(Usr)) return false; auto *UGEPI = cast(Usr); // Check if UGEPI is a simple gep with a single constant index and GEPIOp is // the pointer operand to it. If so, record it in the vector. If not, give // up. if (!GEPSequentialConstIndexed(UGEPI)) return false; if (UGEPI->getOperand(0) != GEPIOp) return false; if (GEPIIdx->getType() != cast(UGEPI->getOperand(1))->getType()) return false; ConstantInt *UGEPIIdx = cast(UGEPI->getOperand(1)); if (TTI->getIntImmCost(UGEPIIdx->getValue(), UGEPIIdx->getType()) > TargetTransformInfo::TCC_Basic) return false; UGEPIs.push_back(UGEPI); } if (UGEPIs.size() == 0) return false; // Check the materializing cost of (Uidx-Idx). for (GetElementPtrInst *UGEPI : UGEPIs) { ConstantInt *UGEPIIdx = cast(UGEPI->getOperand(1)); APInt NewIdx = UGEPIIdx->getValue() - GEPIIdx->getValue(); unsigned ImmCost = TTI->getIntImmCost(NewIdx, GEPIIdx->getType()); if (ImmCost > TargetTransformInfo::TCC_Basic) return false; } // Now unmerge between GEPI and UGEPIs. for (GetElementPtrInst *UGEPI : UGEPIs) { UGEPI->setOperand(0, GEPI); ConstantInt *UGEPIIdx = cast(UGEPI->getOperand(1)); Constant *NewUGEPIIdx = ConstantInt::get(GEPIIdx->getType(), UGEPIIdx->getValue() - GEPIIdx->getValue()); UGEPI->setOperand(1, NewUGEPIIdx); // If GEPI is not inbounds but UGEPI is inbounds, change UGEPI to not // inbounds to avoid UB. if (!GEPI->isInBounds()) { UGEPI->setIsInBounds(false); } } // After unmerging, verify that GEPIOp is actually only used in SrcBlock (not // alive on IndirectBr edges). assert(find_if(GEPIOp->users(), [&](User *Usr) { return cast(Usr)->getParent() != SrcBlock; }) == GEPIOp->users().end() && "GEPIOp is used outside SrcBlock"); return true; } bool CodeGenPrepare::optimizeInst(Instruction *I, bool &ModifiedDT) { // Bail out if we inserted the instruction to prevent optimizations from // stepping on each other's toes. if (InsertedInsts.count(I)) return false; if (PHINode *P = dyn_cast(I)) { // It is possible for very late stage optimizations (such as SimplifyCFG) // to introduce PHI nodes too late to be cleaned up. If we detect such a // trivial PHI, go ahead and zap it here. if (Value *V = SimplifyInstruction(P, {*DL, TLInfo})) { P->replaceAllUsesWith(V); P->eraseFromParent(); ++NumPHIsElim; return true; } return false; } if (CastInst *CI = dyn_cast(I)) { // If the source of the cast is a constant, then this should have // already been constant folded. The only reason NOT to constant fold // it is if something (e.g. LSR) was careful to place the constant // evaluation in a block other than then one that uses it (e.g. to hoist // the address of globals out of a loop). If this is the case, we don't // want to forward-subst the cast. if (isa(CI->getOperand(0))) return false; if (TLI && OptimizeNoopCopyExpression(CI, *TLI, *DL)) return true; if (isa(I) || isa(I)) { /// Sink a zext or sext into its user blocks if the target type doesn't /// fit in one register if (TLI && TLI->getTypeAction(CI->getContext(), TLI->getValueType(*DL, CI->getType())) == TargetLowering::TypeExpandInteger) { return SinkCast(CI); } else { bool MadeChange = optimizeExt(I); return MadeChange | optimizeExtUses(I); } } return false; } if (CmpInst *CI = dyn_cast(I)) if (!TLI || !TLI->hasMultipleConditionRegisters()) return OptimizeCmpExpression(CI, TLI); if (LoadInst *LI = dyn_cast(I)) { LI->setMetadata(LLVMContext::MD_invariant_group, nullptr); if (TLI) { bool Modified = optimizeLoadExt(LI); unsigned AS = LI->getPointerAddressSpace(); Modified |= optimizeMemoryInst(I, I->getOperand(0), LI->getType(), AS); return Modified; } return false; } if (StoreInst *SI = dyn_cast(I)) { if (TLI && splitMergedValStore(*SI, *DL, *TLI)) return true; SI->setMetadata(LLVMContext::MD_invariant_group, nullptr); if (TLI) { unsigned AS = SI->getPointerAddressSpace(); return optimizeMemoryInst(I, SI->getOperand(1), SI->getOperand(0)->getType(), AS); } return false; } if (AtomicRMWInst *RMW = dyn_cast(I)) { unsigned AS = RMW->getPointerAddressSpace(); return optimizeMemoryInst(I, RMW->getPointerOperand(), RMW->getType(), AS); } if (AtomicCmpXchgInst *CmpX = dyn_cast(I)) { unsigned AS = CmpX->getPointerAddressSpace(); return optimizeMemoryInst(I, CmpX->getPointerOperand(), CmpX->getCompareOperand()->getType(), AS); } BinaryOperator *BinOp = dyn_cast(I); if (BinOp && (BinOp->getOpcode() == Instruction::And) && EnableAndCmpSinking && TLI) return sinkAndCmp0Expression(BinOp, *TLI, InsertedInsts); if (BinOp && (BinOp->getOpcode() == Instruction::AShr || BinOp->getOpcode() == Instruction::LShr)) { ConstantInt *CI = dyn_cast(BinOp->getOperand(1)); if (TLI && CI && TLI->hasExtractBitsInsn()) return OptimizeExtractBits(BinOp, CI, *TLI, *DL); return false; } if (GetElementPtrInst *GEPI = dyn_cast(I)) { if (GEPI->hasAllZeroIndices()) { /// The GEP operand must be a pointer, so must its result -> BitCast Instruction *NC = new BitCastInst(GEPI->getOperand(0), GEPI->getType(), GEPI->getName(), GEPI); NC->setDebugLoc(GEPI->getDebugLoc()); GEPI->replaceAllUsesWith(NC); GEPI->eraseFromParent(); ++NumGEPsElim; optimizeInst(NC, ModifiedDT); return true; } if (tryUnmergingGEPsAcrossIndirectBr(GEPI, TTI)) { return true; } return false; } if (CallInst *CI = dyn_cast(I)) return optimizeCallInst(CI, ModifiedDT); if (SelectInst *SI = dyn_cast(I)) return optimizeSelectInst(SI); if (ShuffleVectorInst *SVI = dyn_cast(I)) return optimizeShuffleVectorInst(SVI); if (auto *Switch = dyn_cast(I)) return optimizeSwitchInst(Switch); if (isa(I)) return optimizeExtractElementInst(I); return false; } /// Given an OR instruction, check to see if this is a bitreverse /// idiom. If so, insert the new intrinsic and return true. static bool makeBitReverse(Instruction &I, const DataLayout &DL, const TargetLowering &TLI) { if (!I.getType()->isIntegerTy() || !TLI.isOperationLegalOrCustom(ISD::BITREVERSE, TLI.getValueType(DL, I.getType(), true))) return false; SmallVector Insts; if (!recognizeBSwapOrBitReverseIdiom(&I, false, true, Insts)) return false; Instruction *LastInst = Insts.back(); I.replaceAllUsesWith(LastInst); RecursivelyDeleteTriviallyDeadInstructions(&I); return true; } // In this pass we look for GEP and cast instructions that are used // across basic blocks and rewrite them to improve basic-block-at-a-time // selection. bool CodeGenPrepare::optimizeBlock(BasicBlock &BB, bool &ModifiedDT) { SunkAddrs.clear(); bool MadeChange = false; CurInstIterator = BB.begin(); while (CurInstIterator != BB.end()) { MadeChange |= optimizeInst(&*CurInstIterator++, ModifiedDT); if (ModifiedDT) return true; } bool MadeBitReverse = true; while (TLI && MadeBitReverse) { MadeBitReverse = false; for (auto &I : reverse(BB)) { if (makeBitReverse(I, *DL, *TLI)) { MadeBitReverse = MadeChange = true; ModifiedDT = true; break; } } } MadeChange |= dupRetToEnableTailCallOpts(&BB); return MadeChange; } // llvm.dbg.value is far away from the value then iSel may not be able // handle it properly. iSel will drop llvm.dbg.value if it can not // find a node corresponding to the value. bool CodeGenPrepare::placeDbgValues(Function &F) { bool MadeChange = false; for (BasicBlock &BB : F) { Instruction *PrevNonDbgInst = nullptr; for (BasicBlock::iterator BI = BB.begin(), BE = BB.end(); BI != BE;) { Instruction *Insn = &*BI++; DbgValueInst *DVI = dyn_cast(Insn); // Leave dbg.values that refer to an alloca alone. These // intrinsics describe the address of a variable (= the alloca) // being taken. They should not be moved next to the alloca // (and to the beginning of the scope), but rather stay close to // where said address is used. if (!DVI || (DVI->getValue() && isa(DVI->getValue()))) { PrevNonDbgInst = Insn; continue; } Instruction *VI = dyn_cast_or_null(DVI->getValue()); if (VI && VI != PrevNonDbgInst && !VI->isTerminator()) { // If VI is a phi in a block with an EHPad terminator, we can't insert // after it. if (isa(VI) && VI->getParent()->getTerminator()->isEHPad()) continue; LLVM_DEBUG(dbgs() << "Moving Debug Value before :\n" << *DVI << ' ' << *VI); DVI->removeFromParent(); if (isa(VI)) DVI->insertBefore(&*VI->getParent()->getFirstInsertionPt()); else DVI->insertAfter(VI); MadeChange = true; ++NumDbgValueMoved; } } } return MadeChange; } /// Scale down both weights to fit into uint32_t. static void scaleWeights(uint64_t &NewTrue, uint64_t &NewFalse) { uint64_t NewMax = (NewTrue > NewFalse) ? NewTrue : NewFalse; uint32_t Scale = (NewMax / std::numeric_limits::max()) + 1; NewTrue = NewTrue / Scale; NewFalse = NewFalse / Scale; } /// Some targets prefer to split a conditional branch like: /// \code /// %0 = icmp ne i32 %a, 0 /// %1 = icmp ne i32 %b, 0 /// %or.cond = or i1 %0, %1 /// br i1 %or.cond, label %TrueBB, label %FalseBB /// \endcode /// into multiple branch instructions like: /// \code /// bb1: /// %0 = icmp ne i32 %a, 0 /// br i1 %0, label %TrueBB, label %bb2 /// bb2: /// %1 = icmp ne i32 %b, 0 /// br i1 %1, label %TrueBB, label %FalseBB /// \endcode /// This usually allows instruction selection to do even further optimizations /// and combine the compare with the branch instruction. Currently this is /// applied for targets which have "cheap" jump instructions. /// /// FIXME: Remove the (equivalent?) implementation in SelectionDAG. /// bool CodeGenPrepare::splitBranchCondition(Function &F) { if (!TM || !TM->Options.EnableFastISel || !TLI || TLI->isJumpExpensive()) return false; bool MadeChange = false; for (auto &BB : F) { // Does this BB end with the following? // %cond1 = icmp|fcmp|binary instruction ... // %cond2 = icmp|fcmp|binary instruction ... // %cond.or = or|and i1 %cond1, cond2 // br i1 %cond.or label %dest1, label %dest2" BinaryOperator *LogicOp; BasicBlock *TBB, *FBB; if (!match(BB.getTerminator(), m_Br(m_OneUse(m_BinOp(LogicOp)), TBB, FBB))) continue; auto *Br1 = cast(BB.getTerminator()); if (Br1->getMetadata(LLVMContext::MD_unpredictable)) continue; unsigned Opc; Value *Cond1, *Cond2; if (match(LogicOp, m_And(m_OneUse(m_Value(Cond1)), m_OneUse(m_Value(Cond2))))) Opc = Instruction::And; else if (match(LogicOp, m_Or(m_OneUse(m_Value(Cond1)), m_OneUse(m_Value(Cond2))))) Opc = Instruction::Or; else continue; if (!match(Cond1, m_CombineOr(m_Cmp(), m_BinOp())) || !match(Cond2, m_CombineOr(m_Cmp(), m_BinOp())) ) continue; LLVM_DEBUG(dbgs() << "Before branch condition splitting\n"; BB.dump()); // Create a new BB. auto TmpBB = BasicBlock::Create(BB.getContext(), BB.getName() + ".cond.split", BB.getParent(), BB.getNextNode()); // Update original basic block by using the first condition directly by the // branch instruction and removing the no longer needed and/or instruction. Br1->setCondition(Cond1); LogicOp->eraseFromParent(); // Depending on the condition we have to either replace the true or the // false successor of the original branch instruction. if (Opc == Instruction::And) Br1->setSuccessor(0, TmpBB); else Br1->setSuccessor(1, TmpBB); // Fill in the new basic block. auto *Br2 = IRBuilder<>(TmpBB).CreateCondBr(Cond2, TBB, FBB); if (auto *I = dyn_cast(Cond2)) { I->removeFromParent(); I->insertBefore(Br2); } // Update PHI nodes in both successors. The original BB needs to be // replaced in one successor's PHI nodes, because the branch comes now from // the newly generated BB (NewBB). In the other successor we need to add one // incoming edge to the PHI nodes, because both branch instructions target // now the same successor. Depending on the original branch condition // (and/or) we have to swap the successors (TrueDest, FalseDest), so that // we perform the correct update for the PHI nodes. // This doesn't change the successor order of the just created branch // instruction (or any other instruction). if (Opc == Instruction::Or) std::swap(TBB, FBB); // Replace the old BB with the new BB. for (PHINode &PN : TBB->phis()) { int i; while ((i = PN.getBasicBlockIndex(&BB)) >= 0) PN.setIncomingBlock(i, TmpBB); } // Add another incoming edge form the new BB. for (PHINode &PN : FBB->phis()) { auto *Val = PN.getIncomingValueForBlock(&BB); PN.addIncoming(Val, TmpBB); } // Update the branch weights (from SelectionDAGBuilder:: // FindMergedConditions). if (Opc == Instruction::Or) { // Codegen X | Y as: // BB1: // jmp_if_X TBB // jmp TmpBB // TmpBB: // jmp_if_Y TBB // jmp FBB // // We have flexibility in setting Prob for BB1 and Prob for NewBB. // The requirement is that // TrueProb for BB1 + (FalseProb for BB1 * TrueProb for TmpBB) // = TrueProb for original BB. // Assuming the original weights are A and B, one choice is to set BB1's // weights to A and A+2B, and set TmpBB's weights to A and 2B. This choice // assumes that // TrueProb for BB1 == FalseProb for BB1 * TrueProb for TmpBB. // Another choice is to assume TrueProb for BB1 equals to TrueProb for // TmpBB, but the math is more complicated. uint64_t TrueWeight, FalseWeight; if (Br1->extractProfMetadata(TrueWeight, FalseWeight)) { uint64_t NewTrueWeight = TrueWeight; uint64_t NewFalseWeight = TrueWeight + 2 * FalseWeight; scaleWeights(NewTrueWeight, NewFalseWeight); Br1->setMetadata(LLVMContext::MD_prof, MDBuilder(Br1->getContext()) .createBranchWeights(TrueWeight, FalseWeight)); NewTrueWeight = TrueWeight; NewFalseWeight = 2 * FalseWeight; scaleWeights(NewTrueWeight, NewFalseWeight); Br2->setMetadata(LLVMContext::MD_prof, MDBuilder(Br2->getContext()) .createBranchWeights(TrueWeight, FalseWeight)); } } else { // Codegen X & Y as: // BB1: // jmp_if_X TmpBB // jmp FBB // TmpBB: // jmp_if_Y TBB // jmp FBB // // This requires creation of TmpBB after CurBB. // We have flexibility in setting Prob for BB1 and Prob for TmpBB. // The requirement is that // FalseProb for BB1 + (TrueProb for BB1 * FalseProb for TmpBB) // = FalseProb for original BB. // Assuming the original weights are A and B, one choice is to set BB1's // weights to 2A+B and B, and set TmpBB's weights to 2A and B. This choice // assumes that // FalseProb for BB1 == TrueProb for BB1 * FalseProb for TmpBB. uint64_t TrueWeight, FalseWeight; if (Br1->extractProfMetadata(TrueWeight, FalseWeight)) { uint64_t NewTrueWeight = 2 * TrueWeight + FalseWeight; uint64_t NewFalseWeight = FalseWeight; scaleWeights(NewTrueWeight, NewFalseWeight); Br1->setMetadata(LLVMContext::MD_prof, MDBuilder(Br1->getContext()) .createBranchWeights(TrueWeight, FalseWeight)); NewTrueWeight = 2 * TrueWeight; NewFalseWeight = FalseWeight; scaleWeights(NewTrueWeight, NewFalseWeight); Br2->setMetadata(LLVMContext::MD_prof, MDBuilder(Br2->getContext()) .createBranchWeights(TrueWeight, FalseWeight)); } } // Note: No point in getting fancy here, since the DT info is never // available to CodeGenPrepare. ModifiedDT = true; MadeChange = true; LLVM_DEBUG(dbgs() << "After branch condition splitting\n"; BB.dump(); TmpBB->dump()); } return MadeChange; } Index: vendor/llvm/dist-release_70/lib/CodeGen/GlobalISel/IRTranslator.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/CodeGen/GlobalISel/IRTranslator.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/CodeGen/GlobalISel/IRTranslator.cpp (revision 338378) @@ -1,1681 +1,1683 @@ //===- llvm/CodeGen/GlobalISel/IRTranslator.cpp - IRTranslator ---*- C++ -*-==// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// \file /// This file implements the IRTranslator class. //===----------------------------------------------------------------------===// #include "llvm/CodeGen/GlobalISel/IRTranslator.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/StackProtector.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/MC/MCContext.h" #include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LowLevelTypeImpl.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" #include #include #include #include #include #include #include #define DEBUG_TYPE "irtranslator" using namespace llvm; char IRTranslator::ID = 0; INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI", false, false) INITIALIZE_PASS_DEPENDENCY(TargetPassConfig) INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI", false, false) static void reportTranslationError(MachineFunction &MF, const TargetPassConfig &TPC, OptimizationRemarkEmitter &ORE, OptimizationRemarkMissed &R) { MF.getProperties().set(MachineFunctionProperties::Property::FailedISel); // Print the function name explicitly if we don't have a debug location (which // makes the diagnostic less useful) or if we're going to emit a raw error. if (!R.getLocation().isValid() || TPC.isGlobalISelAbortEnabled()) R << (" (in function: " + MF.getName() + ")").str(); if (TPC.isGlobalISelAbortEnabled()) report_fatal_error(R.getMsg()); else ORE.emit(R); } IRTranslator::IRTranslator() : MachineFunctionPass(ID) { initializeIRTranslatorPass(*PassRegistry::getPassRegistry()); } void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); getSelectionDAGFallbackAnalysisUsage(AU); MachineFunctionPass::getAnalysisUsage(AU); } static void computeValueLLTs(const DataLayout &DL, Type &Ty, SmallVectorImpl &ValueTys, SmallVectorImpl *Offsets = nullptr, uint64_t StartingOffset = 0) { // Given a struct type, recursively traverse the elements. if (StructType *STy = dyn_cast(&Ty)) { const StructLayout *SL = DL.getStructLayout(STy); for (unsigned I = 0, E = STy->getNumElements(); I != E; ++I) computeValueLLTs(DL, *STy->getElementType(I), ValueTys, Offsets, StartingOffset + SL->getElementOffset(I)); return; } // Given an array type, recursively traverse the elements. if (ArrayType *ATy = dyn_cast(&Ty)) { Type *EltTy = ATy->getElementType(); uint64_t EltSize = DL.getTypeAllocSize(EltTy); for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) computeValueLLTs(DL, *EltTy, ValueTys, Offsets, StartingOffset + i * EltSize); return; } // Interpret void as zero return values. if (Ty.isVoidTy()) return; // Base case: we can get an LLT for this LLVM IR type. ValueTys.push_back(getLLTForType(Ty, DL)); if (Offsets != nullptr) Offsets->push_back(StartingOffset * 8); } IRTranslator::ValueToVRegInfo::VRegListT & IRTranslator::allocateVRegs(const Value &Val) { assert(!VMap.contains(Val) && "Value already allocated in VMap"); auto *Regs = VMap.getVRegs(Val); auto *Offsets = VMap.getOffsets(Val); SmallVector SplitTys; computeValueLLTs(*DL, *Val.getType(), SplitTys, Offsets->empty() ? Offsets : nullptr); for (unsigned i = 0; i < SplitTys.size(); ++i) Regs->push_back(0); return *Regs; } ArrayRef IRTranslator::getOrCreateVRegs(const Value &Val) { auto VRegsIt = VMap.findVRegs(Val); if (VRegsIt != VMap.vregs_end()) return *VRegsIt->second; if (Val.getType()->isVoidTy()) return *VMap.getVRegs(Val); // Create entry for this type. auto *VRegs = VMap.getVRegs(Val); auto *Offsets = VMap.getOffsets(Val); assert(Val.getType()->isSized() && "Don't know how to create an empty vreg"); SmallVector SplitTys; computeValueLLTs(*DL, *Val.getType(), SplitTys, Offsets->empty() ? Offsets : nullptr); if (!isa(Val)) { for (auto Ty : SplitTys) VRegs->push_back(MRI->createGenericVirtualRegister(Ty)); return *VRegs; } if (Val.getType()->isAggregateType()) { // UndefValue, ConstantAggregateZero auto &C = cast(Val); unsigned Idx = 0; while (auto Elt = C.getAggregateElement(Idx++)) { auto EltRegs = getOrCreateVRegs(*Elt); std::copy(EltRegs.begin(), EltRegs.end(), std::back_inserter(*VRegs)); } } else { assert(SplitTys.size() == 1 && "unexpectedly split LLT"); VRegs->push_back(MRI->createGenericVirtualRegister(SplitTys[0])); bool Success = translate(cast(Val), VRegs->front()); if (!Success) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", MF->getFunction().getSubprogram(), &MF->getFunction().getEntryBlock()); R << "unable to translate constant: " << ore::NV("Type", Val.getType()); reportTranslationError(*MF, *TPC, *ORE, R); return *VRegs; } } return *VRegs; } int IRTranslator::getOrCreateFrameIndex(const AllocaInst &AI) { if (FrameIndices.find(&AI) != FrameIndices.end()) return FrameIndices[&AI]; unsigned ElementSize = DL->getTypeStoreSize(AI.getAllocatedType()); unsigned Size = ElementSize * cast(AI.getArraySize())->getZExtValue(); // Always allocate at least one byte. Size = std::max(Size, 1u); unsigned Alignment = AI.getAlignment(); if (!Alignment) Alignment = DL->getABITypeAlignment(AI.getAllocatedType()); int &FI = FrameIndices[&AI]; FI = MF->getFrameInfo().CreateStackObject(Size, Alignment, false, &AI); return FI; } unsigned IRTranslator::getMemOpAlignment(const Instruction &I) { unsigned Alignment = 0; Type *ValTy = nullptr; if (const StoreInst *SI = dyn_cast(&I)) { Alignment = SI->getAlignment(); ValTy = SI->getValueOperand()->getType(); } else if (const LoadInst *LI = dyn_cast(&I)) { Alignment = LI->getAlignment(); ValTy = LI->getType(); } else if (const AtomicCmpXchgInst *AI = dyn_cast(&I)) { // TODO(PR27168): This instruction has no alignment attribute, but unlike // the default alignment for load/store, the default here is to assume // it has NATURAL alignment, not DataLayout-specified alignment. const DataLayout &DL = AI->getModule()->getDataLayout(); Alignment = DL.getTypeStoreSize(AI->getCompareOperand()->getType()); ValTy = AI->getCompareOperand()->getType(); } else if (const AtomicRMWInst *AI = dyn_cast(&I)) { // TODO(PR27168): This instruction has no alignment attribute, but unlike // the default alignment for load/store, the default here is to assume // it has NATURAL alignment, not DataLayout-specified alignment. const DataLayout &DL = AI->getModule()->getDataLayout(); Alignment = DL.getTypeStoreSize(AI->getValOperand()->getType()); ValTy = AI->getType(); } else { OptimizationRemarkMissed R("gisel-irtranslator", "", &I); R << "unable to translate memop: " << ore::NV("Opcode", &I); reportTranslationError(*MF, *TPC, *ORE, R); return 1; } return Alignment ? Alignment : DL->getABITypeAlignment(ValTy); } MachineBasicBlock &IRTranslator::getMBB(const BasicBlock &BB) { MachineBasicBlock *&MBB = BBToMBB[&BB]; assert(MBB && "BasicBlock was not encountered before"); return *MBB; } void IRTranslator::addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred) { assert(NewPred && "new predecessor must be a real MachineBasicBlock"); MachinePreds[Edge].push_back(NewPred); } bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U, MachineIRBuilder &MIRBuilder) { // FIXME: handle signed/unsigned wrapping flags. // Get or create a virtual register for each value. // Unless the value is a Constant => loadimm cst? // or inline constant each time? // Creation of a virtual register needs to have a size. unsigned Op0 = getOrCreateVReg(*U.getOperand(0)); unsigned Op1 = getOrCreateVReg(*U.getOperand(1)); unsigned Res = getOrCreateVReg(U); MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op0).addUse(Op1); return true; } bool IRTranslator::translateFSub(const User &U, MachineIRBuilder &MIRBuilder) { // -0.0 - X --> G_FNEG if (isa(U.getOperand(0)) && U.getOperand(0) == ConstantFP::getZeroValueForNegation(U.getType())) { MIRBuilder.buildInstr(TargetOpcode::G_FNEG) .addDef(getOrCreateVReg(U)) .addUse(getOrCreateVReg(*U.getOperand(1))); return true; } return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder); } bool IRTranslator::translateCompare(const User &U, MachineIRBuilder &MIRBuilder) { const CmpInst *CI = dyn_cast(&U); unsigned Op0 = getOrCreateVReg(*U.getOperand(0)); unsigned Op1 = getOrCreateVReg(*U.getOperand(1)); unsigned Res = getOrCreateVReg(U); CmpInst::Predicate Pred = CI ? CI->getPredicate() : static_cast( cast(U).getPredicate()); if (CmpInst::isIntPredicate(Pred)) MIRBuilder.buildICmp(Pred, Res, Op0, Op1); else if (Pred == CmpInst::FCMP_FALSE) MIRBuilder.buildCopy( Res, getOrCreateVReg(*Constant::getNullValue(CI->getType()))); else if (Pred == CmpInst::FCMP_TRUE) MIRBuilder.buildCopy( Res, getOrCreateVReg(*Constant::getAllOnesValue(CI->getType()))); else MIRBuilder.buildFCmp(Pred, Res, Op0, Op1); return true; } bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) { const ReturnInst &RI = cast(U); const Value *Ret = RI.getReturnValue(); if (Ret && DL->getTypeStoreSize(Ret->getType()) == 0) Ret = nullptr; // The target may mess up with the insertion point, but // this is not important as a return is the last instruction // of the block anyway. // FIXME: this interface should simplify when CallLowering gets adapted to // multiple VRegs per Value. unsigned VReg = Ret ? packRegs(*Ret, MIRBuilder) : 0; return CLI->lowerReturn(MIRBuilder, Ret, VReg); } bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) { const BranchInst &BrInst = cast(U); unsigned Succ = 0; if (!BrInst.isUnconditional()) { // We want a G_BRCOND to the true BB followed by an unconditional branch. unsigned Tst = getOrCreateVReg(*BrInst.getCondition()); const BasicBlock &TrueTgt = *cast(BrInst.getSuccessor(Succ++)); MachineBasicBlock &TrueBB = getMBB(TrueTgt); MIRBuilder.buildBrCond(Tst, TrueBB); } const BasicBlock &BrTgt = *cast(BrInst.getSuccessor(Succ)); MachineBasicBlock &TgtBB = getMBB(BrTgt); MachineBasicBlock &CurBB = MIRBuilder.getMBB(); // If the unconditional target is the layout successor, fallthrough. if (!CurBB.isLayoutSuccessor(&TgtBB)) MIRBuilder.buildBr(TgtBB); // Link successors. for (const BasicBlock *Succ : BrInst.successors()) CurBB.addSuccessor(&getMBB(*Succ)); return true; } bool IRTranslator::translateSwitch(const User &U, MachineIRBuilder &MIRBuilder) { // For now, just translate as a chain of conditional branches. // FIXME: could we share most of the logic/code in // SelectionDAGBuilder::visitSwitch between SelectionDAG and GlobalISel? // At first sight, it seems most of the logic in there is independent of // SelectionDAG-specifics and a lot of work went in to optimize switch // lowering in there. const SwitchInst &SwInst = cast(U); const unsigned SwCondValue = getOrCreateVReg(*SwInst.getCondition()); const BasicBlock *OrigBB = SwInst.getParent(); LLT LLTi1 = getLLTForType(*Type::getInt1Ty(U.getContext()), *DL); for (auto &CaseIt : SwInst.cases()) { const unsigned CaseValueReg = getOrCreateVReg(*CaseIt.getCaseValue()); const unsigned Tst = MRI->createGenericVirtualRegister(LLTi1); MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Tst, CaseValueReg, SwCondValue); MachineBasicBlock &CurMBB = MIRBuilder.getMBB(); const BasicBlock *TrueBB = CaseIt.getCaseSuccessor(); MachineBasicBlock &TrueMBB = getMBB(*TrueBB); MIRBuilder.buildBrCond(Tst, TrueMBB); CurMBB.addSuccessor(&TrueMBB); addMachineCFGPred({OrigBB, TrueBB}, &CurMBB); MachineBasicBlock *FalseMBB = MF->CreateMachineBasicBlock(SwInst.getParent()); // Insert the comparison blocks one after the other. MF->insert(std::next(CurMBB.getIterator()), FalseMBB); MIRBuilder.buildBr(*FalseMBB); CurMBB.addSuccessor(FalseMBB); MIRBuilder.setMBB(*FalseMBB); } // handle default case const BasicBlock *DefaultBB = SwInst.getDefaultDest(); MachineBasicBlock &DefaultMBB = getMBB(*DefaultBB); MIRBuilder.buildBr(DefaultMBB); MachineBasicBlock &CurMBB = MIRBuilder.getMBB(); CurMBB.addSuccessor(&DefaultMBB); addMachineCFGPred({OrigBB, DefaultBB}, &CurMBB); return true; } bool IRTranslator::translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder) { const IndirectBrInst &BrInst = cast(U); const unsigned Tgt = getOrCreateVReg(*BrInst.getAddress()); MIRBuilder.buildBrIndirect(Tgt); // Link successors. MachineBasicBlock &CurBB = MIRBuilder.getMBB(); for (const BasicBlock *Succ : BrInst.successors()) CurBB.addSuccessor(&getMBB(*Succ)); return true; } bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) { const LoadInst &LI = cast(U); auto Flags = LI.isVolatile() ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOLoad; if (DL->getTypeStoreSize(LI.getType()) == 0) return true; ArrayRef Regs = getOrCreateVRegs(LI); ArrayRef Offsets = *VMap.getOffsets(LI); unsigned Base = getOrCreateVReg(*LI.getPointerOperand()); for (unsigned i = 0; i < Regs.size(); ++i) { unsigned Addr = 0; MIRBuilder.materializeGEP(Addr, Base, LLT::scalar(64), Offsets[i] / 8); MachinePointerInfo Ptr(LI.getPointerOperand(), Offsets[i] / 8); unsigned BaseAlign = getMemOpAlignment(LI); auto MMO = MF->getMachineMemOperand( Ptr, Flags, (MRI->getType(Regs[i]).getSizeInBits() + 7) / 8, MinAlign(BaseAlign, Offsets[i] / 8), AAMDNodes(), nullptr, LI.getSyncScopeID(), LI.getOrdering()); MIRBuilder.buildLoad(Regs[i], Addr, *MMO); } return true; } bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) { const StoreInst &SI = cast(U); auto Flags = SI.isVolatile() ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOStore; if (DL->getTypeStoreSize(SI.getValueOperand()->getType()) == 0) return true; ArrayRef Vals = getOrCreateVRegs(*SI.getValueOperand()); ArrayRef Offsets = *VMap.getOffsets(*SI.getValueOperand()); unsigned Base = getOrCreateVReg(*SI.getPointerOperand()); for (unsigned i = 0; i < Vals.size(); ++i) { unsigned Addr = 0; MIRBuilder.materializeGEP(Addr, Base, LLT::scalar(64), Offsets[i] / 8); MachinePointerInfo Ptr(SI.getPointerOperand(), Offsets[i] / 8); unsigned BaseAlign = getMemOpAlignment(SI); auto MMO = MF->getMachineMemOperand( Ptr, Flags, (MRI->getType(Vals[i]).getSizeInBits() + 7) / 8, MinAlign(BaseAlign, Offsets[i] / 8), AAMDNodes(), nullptr, SI.getSyncScopeID(), SI.getOrdering()); MIRBuilder.buildStore(Vals[i], Addr, *MMO); } return true; } static uint64_t getOffsetFromIndices(const User &U, const DataLayout &DL) { const Value *Src = U.getOperand(0); Type *Int32Ty = Type::getInt32Ty(U.getContext()); // getIndexedOffsetInType is designed for GEPs, so the first index is the // usual array element rather than looking into the actual aggregate. SmallVector Indices; Indices.push_back(ConstantInt::get(Int32Ty, 0)); if (const ExtractValueInst *EVI = dyn_cast(&U)) { for (auto Idx : EVI->indices()) Indices.push_back(ConstantInt::get(Int32Ty, Idx)); } else if (const InsertValueInst *IVI = dyn_cast(&U)) { for (auto Idx : IVI->indices()) Indices.push_back(ConstantInt::get(Int32Ty, Idx)); } else { for (unsigned i = 1; i < U.getNumOperands(); ++i) Indices.push_back(U.getOperand(i)); } return 8 * static_cast( DL.getIndexedOffsetInType(Src->getType(), Indices)); } bool IRTranslator::translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder) { const Value *Src = U.getOperand(0); uint64_t Offset = getOffsetFromIndices(U, *DL); ArrayRef SrcRegs = getOrCreateVRegs(*Src); ArrayRef Offsets = *VMap.getOffsets(*Src); unsigned Idx = std::lower_bound(Offsets.begin(), Offsets.end(), Offset) - Offsets.begin(); auto &DstRegs = allocateVRegs(U); for (unsigned i = 0; i < DstRegs.size(); ++i) DstRegs[i] = SrcRegs[Idx++]; return true; } bool IRTranslator::translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder) { const Value *Src = U.getOperand(0); uint64_t Offset = getOffsetFromIndices(U, *DL); auto &DstRegs = allocateVRegs(U); ArrayRef DstOffsets = *VMap.getOffsets(U); ArrayRef SrcRegs = getOrCreateVRegs(*Src); ArrayRef InsertedRegs = getOrCreateVRegs(*U.getOperand(1)); auto InsertedIt = InsertedRegs.begin(); for (unsigned i = 0; i < DstRegs.size(); ++i) { if (DstOffsets[i] >= Offset && InsertedIt != InsertedRegs.end()) DstRegs[i] = *InsertedIt++; else DstRegs[i] = SrcRegs[i]; } return true; } bool IRTranslator::translateSelect(const User &U, MachineIRBuilder &MIRBuilder) { unsigned Tst = getOrCreateVReg(*U.getOperand(0)); ArrayRef ResRegs = getOrCreateVRegs(U); ArrayRef Op0Regs = getOrCreateVRegs(*U.getOperand(1)); ArrayRef Op1Regs = getOrCreateVRegs(*U.getOperand(2)); for (unsigned i = 0; i < ResRegs.size(); ++i) MIRBuilder.buildSelect(ResRegs[i], Tst, Op0Regs[i], Op1Regs[i]); return true; } bool IRTranslator::translateBitCast(const User &U, MachineIRBuilder &MIRBuilder) { // If we're bitcasting to the source type, we can reuse the source vreg. if (getLLTForType(*U.getOperand(0)->getType(), *DL) == getLLTForType(*U.getType(), *DL)) { unsigned SrcReg = getOrCreateVReg(*U.getOperand(0)); auto &Regs = *VMap.getVRegs(U); // If we already assigned a vreg for this bitcast, we can't change that. // Emit a copy to satisfy the users we already emitted. if (!Regs.empty()) MIRBuilder.buildCopy(Regs[0], SrcReg); else { Regs.push_back(SrcReg); VMap.getOffsets(U)->push_back(0); } return true; } return translateCast(TargetOpcode::G_BITCAST, U, MIRBuilder); } bool IRTranslator::translateCast(unsigned Opcode, const User &U, MachineIRBuilder &MIRBuilder) { unsigned Op = getOrCreateVReg(*U.getOperand(0)); unsigned Res = getOrCreateVReg(U); MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op); return true; } bool IRTranslator::translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder) { // FIXME: support vector GEPs. if (U.getType()->isVectorTy()) return false; Value &Op0 = *U.getOperand(0); unsigned BaseReg = getOrCreateVReg(Op0); Type *PtrIRTy = Op0.getType(); LLT PtrTy = getLLTForType(*PtrIRTy, *DL); Type *OffsetIRTy = DL->getIntPtrType(PtrIRTy); LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL); int64_t Offset = 0; for (gep_type_iterator GTI = gep_type_begin(&U), E = gep_type_end(&U); GTI != E; ++GTI) { const Value *Idx = GTI.getOperand(); if (StructType *StTy = GTI.getStructTypeOrNull()) { unsigned Field = cast(Idx)->getUniqueInteger().getZExtValue(); Offset += DL->getStructLayout(StTy)->getElementOffset(Field); continue; } else { uint64_t ElementSize = DL->getTypeAllocSize(GTI.getIndexedType()); // If this is a scalar constant or a splat vector of constants, // handle it quickly. if (const auto *CI = dyn_cast(Idx)) { Offset += ElementSize * CI->getSExtValue(); continue; } if (Offset != 0) { unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy); unsigned OffsetReg = getOrCreateVReg(*ConstantInt::get(OffsetIRTy, Offset)); MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg); BaseReg = NewBaseReg; Offset = 0; } unsigned IdxReg = getOrCreateVReg(*Idx); if (MRI->getType(IdxReg) != OffsetTy) { unsigned NewIdxReg = MRI->createGenericVirtualRegister(OffsetTy); MIRBuilder.buildSExtOrTrunc(NewIdxReg, IdxReg); IdxReg = NewIdxReg; } // N = N + Idx * ElementSize; // Avoid doing it for ElementSize of 1. unsigned GepOffsetReg; if (ElementSize != 1) { unsigned ElementSizeReg = getOrCreateVReg(*ConstantInt::get(OffsetIRTy, ElementSize)); GepOffsetReg = MRI->createGenericVirtualRegister(OffsetTy); MIRBuilder.buildMul(GepOffsetReg, ElementSizeReg, IdxReg); } else GepOffsetReg = IdxReg; unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy); MIRBuilder.buildGEP(NewBaseReg, BaseReg, GepOffsetReg); BaseReg = NewBaseReg; } } if (Offset != 0) { unsigned OffsetReg = getOrCreateVReg(*ConstantInt::get(OffsetIRTy, Offset)); MIRBuilder.buildGEP(getOrCreateVReg(U), BaseReg, OffsetReg); return true; } MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg); return true; } bool IRTranslator::translateMemfunc(const CallInst &CI, MachineIRBuilder &MIRBuilder, unsigned ID) { LLT SizeTy = getLLTForType(*CI.getArgOperand(2)->getType(), *DL); Type *DstTy = CI.getArgOperand(0)->getType(); if (cast(DstTy)->getAddressSpace() != 0 || SizeTy.getSizeInBits() != DL->getPointerSizeInBits(0)) return false; SmallVector Args; for (int i = 0; i < 3; ++i) { const auto &Arg = CI.getArgOperand(i); Args.emplace_back(getOrCreateVReg(*Arg), Arg->getType()); } const char *Callee; switch (ID) { case Intrinsic::memmove: case Intrinsic::memcpy: { Type *SrcTy = CI.getArgOperand(1)->getType(); if(cast(SrcTy)->getAddressSpace() != 0) return false; Callee = ID == Intrinsic::memcpy ? "memcpy" : "memmove"; break; } case Intrinsic::memset: Callee = "memset"; break; default: return false; } return CLI->lowerCall(MIRBuilder, CI.getCallingConv(), MachineOperand::CreateES(Callee), CallLowering::ArgInfo(0, CI.getType()), Args); } void IRTranslator::getStackGuard(unsigned DstReg, MachineIRBuilder &MIRBuilder) { const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); MRI->setRegClass(DstReg, TRI->getPointerRegClass(*MF)); auto MIB = MIRBuilder.buildInstr(TargetOpcode::LOAD_STACK_GUARD); MIB.addDef(DstReg); auto &TLI = *MF->getSubtarget().getTargetLowering(); Value *Global = TLI.getSDagStackGuard(*MF->getFunction().getParent()); if (!Global) return; MachinePointerInfo MPInfo(Global); MachineInstr::mmo_iterator MemRefs = MF->allocateMemRefsArray(1); auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant | MachineMemOperand::MODereferenceable; *MemRefs = MF->getMachineMemOperand(MPInfo, Flags, DL->getPointerSizeInBits() / 8, DL->getPointerABIAlignment(0)); MIB.setMemRefs(MemRefs, MemRefs + 1); } bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op, MachineIRBuilder &MIRBuilder) { ArrayRef ResRegs = getOrCreateVRegs(CI); auto MIB = MIRBuilder.buildInstr(Op) .addDef(ResRegs[0]) .addDef(ResRegs[1]) .addUse(getOrCreateVReg(*CI.getOperand(0))) .addUse(getOrCreateVReg(*CI.getOperand(1))); if (Op == TargetOpcode::G_UADDE || Op == TargetOpcode::G_USUBE) { unsigned Zero = getOrCreateVReg( *Constant::getNullValue(Type::getInt1Ty(CI.getContext()))); MIB.addUse(Zero); } return true; } bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder) { switch (ID) { default: break; case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: // Stack coloring is not enabled in O0 (which we care about now) so we can // drop these. Make sure someone notices when we start compiling at higher // opts though. if (MF->getTarget().getOptLevel() != CodeGenOpt::None) return false; return true; case Intrinsic::dbg_declare: { const DbgDeclareInst &DI = cast(CI); assert(DI.getVariable() && "Missing variable"); const Value *Address = DI.getAddress(); if (!Address || isa(Address)) { LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI << "\n"); return true; } assert(DI.getVariable()->isValidLocationForIntrinsic( MIRBuilder.getDebugLoc()) && "Expected inlined-at fields to agree"); auto AI = dyn_cast(Address); if (AI && AI->isStaticAlloca()) { // Static allocas are tracked at the MF level, no need for DBG_VALUE // instructions (in fact, they get ignored if they *do* exist). MF->setVariableDbgInfo(DI.getVariable(), DI.getExpression(), getOrCreateFrameIndex(*AI), DI.getDebugLoc()); } else MIRBuilder.buildDirectDbgValue(getOrCreateVReg(*Address), DI.getVariable(), DI.getExpression()); return true; } case Intrinsic::vaend: // No target I know of cares about va_end. Certainly no in-tree target // does. Simplest intrinsic ever! return true; case Intrinsic::vastart: { auto &TLI = *MF->getSubtarget().getTargetLowering(); Value *Ptr = CI.getArgOperand(0); unsigned ListSize = TLI.getVaListSizeInBits(*DL) / 8; MIRBuilder.buildInstr(TargetOpcode::G_VASTART) .addUse(getOrCreateVReg(*Ptr)) .addMemOperand(MF->getMachineMemOperand( MachinePointerInfo(Ptr), MachineMemOperand::MOStore, ListSize, 0)); return true; } case Intrinsic::dbg_value: { // This form of DBG_VALUE is target-independent. const DbgValueInst &DI = cast(CI); const Value *V = DI.getValue(); assert(DI.getVariable()->isValidLocationForIntrinsic( MIRBuilder.getDebugLoc()) && "Expected inlined-at fields to agree"); if (!V) { // Currently the optimizer can produce this; insert an undef to // help debugging. Probably the optimizer should not do this. MIRBuilder.buildIndirectDbgValue(0, DI.getVariable(), DI.getExpression()); } else if (const auto *CI = dyn_cast(V)) { MIRBuilder.buildConstDbgValue(*CI, DI.getVariable(), DI.getExpression()); } else { unsigned Reg = getOrCreateVReg(*V); // FIXME: This does not handle register-indirect values at offset 0. The // direct/indirect thing shouldn't really be handled by something as // implicit as reg+noreg vs reg+imm in the first palce, but it seems // pretty baked in right now. MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), DI.getExpression()); } return true; } case Intrinsic::uadd_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDE, MIRBuilder); case Intrinsic::sadd_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_SADDO, MIRBuilder); case Intrinsic::usub_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_USUBE, MIRBuilder); case Intrinsic::ssub_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_SSUBO, MIRBuilder); case Intrinsic::umul_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_UMULO, MIRBuilder); case Intrinsic::smul_with_overflow: return translateOverflowIntrinsic(CI, TargetOpcode::G_SMULO, MIRBuilder); case Intrinsic::pow: MIRBuilder.buildInstr(TargetOpcode::G_FPOW) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))) .addUse(getOrCreateVReg(*CI.getArgOperand(1))); return true; case Intrinsic::exp: MIRBuilder.buildInstr(TargetOpcode::G_FEXP) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))); return true; case Intrinsic::exp2: MIRBuilder.buildInstr(TargetOpcode::G_FEXP2) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))); return true; case Intrinsic::log: MIRBuilder.buildInstr(TargetOpcode::G_FLOG) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))); return true; case Intrinsic::log2: MIRBuilder.buildInstr(TargetOpcode::G_FLOG2) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))); return true; case Intrinsic::fabs: MIRBuilder.buildInstr(TargetOpcode::G_FABS) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))); return true; case Intrinsic::fma: MIRBuilder.buildInstr(TargetOpcode::G_FMA) .addDef(getOrCreateVReg(CI)) .addUse(getOrCreateVReg(*CI.getArgOperand(0))) .addUse(getOrCreateVReg(*CI.getArgOperand(1))) .addUse(getOrCreateVReg(*CI.getArgOperand(2))); return true; case Intrinsic::fmuladd: { const TargetMachine &TM = MF->getTarget(); const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering(); unsigned Dst = getOrCreateVReg(CI); unsigned Op0 = getOrCreateVReg(*CI.getArgOperand(0)); unsigned Op1 = getOrCreateVReg(*CI.getArgOperand(1)); unsigned Op2 = getOrCreateVReg(*CI.getArgOperand(2)); if (TM.Options.AllowFPOpFusion != FPOpFusion::Strict && TLI.isFMAFasterThanFMulAndFAdd(TLI.getValueType(*DL, CI.getType()))) { // TODO: Revisit this to see if we should move this part of the // lowering to the combiner. MIRBuilder.buildInstr(TargetOpcode::G_FMA, Dst, Op0, Op1, Op2); } else { LLT Ty = getLLTForType(*CI.getType(), *DL); auto FMul = MIRBuilder.buildInstr(TargetOpcode::G_FMUL, Ty, Op0, Op1); MIRBuilder.buildInstr(TargetOpcode::G_FADD, Dst, FMul, Op2); } return true; } case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: return translateMemfunc(CI, MIRBuilder, ID); case Intrinsic::eh_typeid_for: { GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0)); unsigned Reg = getOrCreateVReg(CI); unsigned TypeID = MF->getTypeIDFor(GV); MIRBuilder.buildConstant(Reg, TypeID); return true; } case Intrinsic::objectsize: { // If we don't know by now, we're never going to know. const ConstantInt *Min = cast(CI.getArgOperand(1)); MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0); return true; } case Intrinsic::stackguard: getStackGuard(getOrCreateVReg(CI), MIRBuilder); return true; case Intrinsic::stackprotector: { LLT PtrTy = getLLTForType(*CI.getArgOperand(0)->getType(), *DL); unsigned GuardVal = MRI->createGenericVirtualRegister(PtrTy); getStackGuard(GuardVal, MIRBuilder); AllocaInst *Slot = cast(CI.getArgOperand(1)); MIRBuilder.buildStore( GuardVal, getOrCreateVReg(*Slot), *MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(*MF, getOrCreateFrameIndex(*Slot)), MachineMemOperand::MOStore | MachineMemOperand::MOVolatile, PtrTy.getSizeInBits() / 8, 8)); return true; } } return false; } bool IRTranslator::translateInlineAsm(const CallInst &CI, MachineIRBuilder &MIRBuilder) { const InlineAsm &IA = cast(*CI.getCalledValue()); if (!IA.getConstraintString().empty()) return false; unsigned ExtraInfo = 0; if (IA.hasSideEffects()) ExtraInfo |= InlineAsm::Extra_HasSideEffects; if (IA.getDialect() == InlineAsm::AD_Intel) ExtraInfo |= InlineAsm::Extra_AsmDialect; MIRBuilder.buildInstr(TargetOpcode::INLINEASM) .addExternalSymbol(IA.getAsmString().c_str()) .addImm(ExtraInfo); return true; } unsigned IRTranslator::packRegs(const Value &V, MachineIRBuilder &MIRBuilder) { ArrayRef Regs = getOrCreateVRegs(V); ArrayRef Offsets = *VMap.getOffsets(V); LLT BigTy = getLLTForType(*V.getType(), *DL); if (Regs.size() == 1) return Regs[0]; unsigned Dst = MRI->createGenericVirtualRegister(BigTy); MIRBuilder.buildUndef(Dst); for (unsigned i = 0; i < Regs.size(); ++i) { unsigned NewDst = MRI->createGenericVirtualRegister(BigTy); MIRBuilder.buildInsert(NewDst, Dst, Regs[i], Offsets[i]); Dst = NewDst; } return Dst; } void IRTranslator::unpackRegs(const Value &V, unsigned Src, MachineIRBuilder &MIRBuilder) { ArrayRef Regs = getOrCreateVRegs(V); ArrayRef Offsets = *VMap.getOffsets(V); for (unsigned i = 0; i < Regs.size(); ++i) MIRBuilder.buildExtract(Regs[i], Src, Offsets[i]); } bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) { const CallInst &CI = cast(U); auto TII = MF->getTarget().getIntrinsicInfo(); const Function *F = CI.getCalledFunction(); // FIXME: support Windows dllimport function calls. if (F && F->hasDLLImportStorageClass()) return false; if (CI.isInlineAsm()) return translateInlineAsm(CI, MIRBuilder); Intrinsic::ID ID = Intrinsic::not_intrinsic; if (F && F->isIntrinsic()) { ID = F->getIntrinsicID(); if (TII && ID == Intrinsic::not_intrinsic) ID = static_cast(TII->getIntrinsicID(F)); } bool IsSplitType = valueIsSplit(CI); if (!F || !F->isIntrinsic() || ID == Intrinsic::not_intrinsic) { unsigned Res = IsSplitType ? MRI->createGenericVirtualRegister( getLLTForType(*CI.getType(), *DL)) : getOrCreateVReg(CI); SmallVector Args; for (auto &Arg: CI.arg_operands()) Args.push_back(packRegs(*Arg, MIRBuilder)); MF->getFrameInfo().setHasCalls(true); bool Success = CLI->lowerCall(MIRBuilder, &CI, Res, Args, [&]() { return getOrCreateVReg(*CI.getCalledValue()); }); if (IsSplitType) unpackRegs(CI, Res, MIRBuilder); return Success; } assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic"); if (translateKnownIntrinsic(CI, ID, MIRBuilder)) return true; unsigned Res = 0; if (!CI.getType()->isVoidTy()) { if (IsSplitType) Res = MRI->createGenericVirtualRegister(getLLTForType(*CI.getType(), *DL)); else Res = getOrCreateVReg(CI); } MachineInstrBuilder MIB = MIRBuilder.buildIntrinsic(ID, Res, !CI.doesNotAccessMemory()); for (auto &Arg : CI.arg_operands()) { // Some intrinsics take metadata parameters. Reject them. if (isa(Arg)) return false; MIB.addUse(packRegs(*Arg, MIRBuilder)); } if (IsSplitType) unpackRegs(CI, Res, MIRBuilder); // Add a MachineMemOperand if it is a target mem intrinsic. const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering(); TargetLowering::IntrinsicInfo Info; // TODO: Add a GlobalISel version of getTgtMemIntrinsic. if (TLI.getTgtMemIntrinsic(Info, CI, *MF, ID)) { uint64_t Size = Info.memVT.getStoreSize(); MIB.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Info.ptrVal), Info.flags, Size, Info.align)); } return true; } bool IRTranslator::translateInvoke(const User &U, MachineIRBuilder &MIRBuilder) { const InvokeInst &I = cast(U); MCContext &Context = MF->getContext(); const BasicBlock *ReturnBB = I.getSuccessor(0); const BasicBlock *EHPadBB = I.getSuccessor(1); const Value *Callee = I.getCalledValue(); const Function *Fn = dyn_cast(Callee); if (isa(Callee)) return false; // FIXME: support invoking patchpoint and statepoint intrinsics. if (Fn && Fn->isIntrinsic()) return false; // FIXME: support whatever these are. if (I.countOperandBundlesOfType(LLVMContext::OB_deopt)) return false; // FIXME: support Windows exception handling. if (!isa(EHPadBB->front())) return false; // Emit the actual call, bracketed by EH_LABELs so that the MF knows about // the region covered by the try. MCSymbol *BeginSymbol = Context.createTempSymbol(); MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol); unsigned Res = MRI->createGenericVirtualRegister(getLLTForType(*I.getType(), *DL)); SmallVector Args; for (auto &Arg: I.arg_operands()) Args.push_back(packRegs(*Arg, MIRBuilder)); if (!CLI->lowerCall(MIRBuilder, &I, Res, Args, [&]() { return getOrCreateVReg(*I.getCalledValue()); })) return false; unpackRegs(I, Res, MIRBuilder); MCSymbol *EndSymbol = Context.createTempSymbol(); MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol); // FIXME: track probabilities. MachineBasicBlock &EHPadMBB = getMBB(*EHPadBB), &ReturnMBB = getMBB(*ReturnBB); MF->addInvoke(&EHPadMBB, BeginSymbol, EndSymbol); MIRBuilder.getMBB().addSuccessor(&ReturnMBB); MIRBuilder.getMBB().addSuccessor(&EHPadMBB); MIRBuilder.buildBr(ReturnMBB); return true; } bool IRTranslator::translateLandingPad(const User &U, MachineIRBuilder &MIRBuilder) { const LandingPadInst &LP = cast(U); MachineBasicBlock &MBB = MIRBuilder.getMBB(); addLandingPadInfo(LP, MBB); MBB.setIsEHPad(); // If there aren't registers to copy the values into (e.g., during SjLj // exceptions), then don't bother. auto &TLI = *MF->getSubtarget().getTargetLowering(); const Constant *PersonalityFn = MF->getFunction().getPersonalityFn(); if (TLI.getExceptionPointerRegister(PersonalityFn) == 0 && TLI.getExceptionSelectorRegister(PersonalityFn) == 0) return true; // If landingpad's return type is token type, we don't create DAG nodes // for its exception pointer and selector value. The extraction of exception // pointer or selector value from token type landingpads is not currently // supported. if (LP.getType()->isTokenTy()) return true; // Add a label to mark the beginning of the landing pad. Deletion of the // landing pad can thus be detected via the MachineModuleInfo. MIRBuilder.buildInstr(TargetOpcode::EH_LABEL) .addSym(MF->addLandingPad(&MBB)); LLT Ty = getLLTForType(*LP.getType(), *DL); unsigned Undef = MRI->createGenericVirtualRegister(Ty); MIRBuilder.buildUndef(Undef); SmallVector Tys; for (Type *Ty : cast(LP.getType())->elements()) Tys.push_back(getLLTForType(*Ty, *DL)); assert(Tys.size() == 2 && "Only two-valued landingpads are supported"); // Mark exception register as live in. unsigned ExceptionReg = TLI.getExceptionPointerRegister(PersonalityFn); if (!ExceptionReg) return false; MBB.addLiveIn(ExceptionReg); ArrayRef ResRegs = getOrCreateVRegs(LP); MIRBuilder.buildCopy(ResRegs[0], ExceptionReg); unsigned SelectorReg = TLI.getExceptionSelectorRegister(PersonalityFn); if (!SelectorReg) return false; MBB.addLiveIn(SelectorReg); unsigned PtrVReg = MRI->createGenericVirtualRegister(Tys[0]); MIRBuilder.buildCopy(PtrVReg, SelectorReg); MIRBuilder.buildCast(ResRegs[1], PtrVReg); return true; } bool IRTranslator::translateAlloca(const User &U, MachineIRBuilder &MIRBuilder) { auto &AI = cast(U); if (AI.isSwiftError()) return false; if (AI.isStaticAlloca()) { unsigned Res = getOrCreateVReg(AI); int FI = getOrCreateFrameIndex(AI); MIRBuilder.buildFrameIndex(Res, FI); return true; } // FIXME: support stack probing for Windows. if (MF->getTarget().getTargetTriple().isOSWindows()) return false; // Now we're in the harder dynamic case. Type *Ty = AI.getAllocatedType(); unsigned Align = std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI.getAlignment()); unsigned NumElts = getOrCreateVReg(*AI.getArraySize()); Type *IntPtrIRTy = DL->getIntPtrType(AI.getType()); LLT IntPtrTy = getLLTForType(*IntPtrIRTy, *DL); if (MRI->getType(NumElts) != IntPtrTy) { unsigned ExtElts = MRI->createGenericVirtualRegister(IntPtrTy); MIRBuilder.buildZExtOrTrunc(ExtElts, NumElts); NumElts = ExtElts; } unsigned AllocSize = MRI->createGenericVirtualRegister(IntPtrTy); unsigned TySize = getOrCreateVReg(*ConstantInt::get(IntPtrIRTy, -DL->getTypeAllocSize(Ty))); MIRBuilder.buildMul(AllocSize, NumElts, TySize); LLT PtrTy = getLLTForType(*AI.getType(), *DL); auto &TLI = *MF->getSubtarget().getTargetLowering(); unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore(); unsigned SPTmp = MRI->createGenericVirtualRegister(PtrTy); MIRBuilder.buildCopy(SPTmp, SPReg); unsigned AllocTmp = MRI->createGenericVirtualRegister(PtrTy); MIRBuilder.buildGEP(AllocTmp, SPTmp, AllocSize); // Handle alignment. We have to realign if the allocation granule was smaller // than stack alignment, or the specific alloca requires more than stack // alignment. unsigned StackAlign = MF->getSubtarget().getFrameLowering()->getStackAlignment(); Align = std::max(Align, StackAlign); if (Align > StackAlign || DL->getTypeAllocSize(Ty) % StackAlign != 0) { // Round the size of the allocation up to the stack alignment size // by add SA-1 to the size. This doesn't overflow because we're computing // an address inside an alloca. unsigned AlignedAlloc = MRI->createGenericVirtualRegister(PtrTy); MIRBuilder.buildPtrMask(AlignedAlloc, AllocTmp, Log2_32(Align)); AllocTmp = AlignedAlloc; } MIRBuilder.buildCopy(SPReg, AllocTmp); MIRBuilder.buildCopy(getOrCreateVReg(AI), AllocTmp); MF->getFrameInfo().CreateVariableSizedObject(Align ? Align : 1, &AI); assert(MF->getFrameInfo().hasVarSizedObjects()); return true; } bool IRTranslator::translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) { // FIXME: We may need more info about the type. Because of how LLT works, // we're completely discarding the i64/double distinction here (amongst // others). Fortunately the ABIs I know of where that matters don't use va_arg // anyway but that's not guaranteed. MIRBuilder.buildInstr(TargetOpcode::G_VAARG) .addDef(getOrCreateVReg(U)) .addUse(getOrCreateVReg(*U.getOperand(0))) .addImm(DL->getABITypeAlignment(U.getType())); return true; } bool IRTranslator::translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder) { // If it is a <1 x Ty> vector, use the scalar as it is // not a legal vector type in LLT. if (U.getType()->getVectorNumElements() == 1) { unsigned Elt = getOrCreateVReg(*U.getOperand(1)); auto &Regs = *VMap.getVRegs(U); if (Regs.empty()) { Regs.push_back(Elt); VMap.getOffsets(U)->push_back(0); } else { MIRBuilder.buildCopy(Regs[0], Elt); } return true; } unsigned Res = getOrCreateVReg(U); unsigned Val = getOrCreateVReg(*U.getOperand(0)); unsigned Elt = getOrCreateVReg(*U.getOperand(1)); unsigned Idx = getOrCreateVReg(*U.getOperand(2)); MIRBuilder.buildInsertVectorElement(Res, Val, Elt, Idx); return true; } bool IRTranslator::translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder) { // If it is a <1 x Ty> vector, use the scalar as it is // not a legal vector type in LLT. if (U.getOperand(0)->getType()->getVectorNumElements() == 1) { unsigned Elt = getOrCreateVReg(*U.getOperand(0)); auto &Regs = *VMap.getVRegs(U); if (Regs.empty()) { Regs.push_back(Elt); VMap.getOffsets(U)->push_back(0); } else { MIRBuilder.buildCopy(Regs[0], Elt); } return true; } unsigned Res = getOrCreateVReg(U); unsigned Val = getOrCreateVReg(*U.getOperand(0)); unsigned Idx = getOrCreateVReg(*U.getOperand(1)); MIRBuilder.buildExtractVectorElement(Res, Val, Idx); return true; } bool IRTranslator::translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder) { MIRBuilder.buildInstr(TargetOpcode::G_SHUFFLE_VECTOR) .addDef(getOrCreateVReg(U)) .addUse(getOrCreateVReg(*U.getOperand(0))) .addUse(getOrCreateVReg(*U.getOperand(1))) .addUse(getOrCreateVReg(*U.getOperand(2))); return true; } bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) { const PHINode &PI = cast(U); SmallVector Insts; for (auto Reg : getOrCreateVRegs(PI)) { auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, Reg); Insts.push_back(MIB.getInstr()); } PendingPHIs.emplace_back(&PI, std::move(Insts)); return true; } bool IRTranslator::translateAtomicCmpXchg(const User &U, MachineIRBuilder &MIRBuilder) { const AtomicCmpXchgInst &I = cast(U); if (I.isWeak()) return false; auto Flags = I.isVolatile() ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore; Type *ResType = I.getType(); Type *ValType = ResType->Type::getStructElementType(0); auto Res = getOrCreateVRegs(I); unsigned OldValRes = Res[0]; unsigned SuccessRes = Res[1]; unsigned Addr = getOrCreateVReg(*I.getPointerOperand()); unsigned Cmp = getOrCreateVReg(*I.getCompareOperand()); unsigned NewVal = getOrCreateVReg(*I.getNewValOperand()); MIRBuilder.buildAtomicCmpXchgWithSuccess( OldValRes, SuccessRes, Addr, Cmp, NewVal, *MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()), Flags, DL->getTypeStoreSize(ValType), getMemOpAlignment(I), AAMDNodes(), nullptr, I.getSyncScopeID(), I.getSuccessOrdering(), I.getFailureOrdering())); return true; } bool IRTranslator::translateAtomicRMW(const User &U, MachineIRBuilder &MIRBuilder) { const AtomicRMWInst &I = cast(U); auto Flags = I.isVolatile() ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone; Flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore; Type *ResType = I.getType(); unsigned Res = getOrCreateVReg(I); unsigned Addr = getOrCreateVReg(*I.getPointerOperand()); unsigned Val = getOrCreateVReg(*I.getValOperand()); unsigned Opcode = 0; switch (I.getOperation()) { default: llvm_unreachable("Unknown atomicrmw op"); return false; case AtomicRMWInst::Xchg: Opcode = TargetOpcode::G_ATOMICRMW_XCHG; break; case AtomicRMWInst::Add: Opcode = TargetOpcode::G_ATOMICRMW_ADD; break; case AtomicRMWInst::Sub: Opcode = TargetOpcode::G_ATOMICRMW_SUB; break; case AtomicRMWInst::And: Opcode = TargetOpcode::G_ATOMICRMW_AND; break; case AtomicRMWInst::Nand: Opcode = TargetOpcode::G_ATOMICRMW_NAND; break; case AtomicRMWInst::Or: Opcode = TargetOpcode::G_ATOMICRMW_OR; break; case AtomicRMWInst::Xor: Opcode = TargetOpcode::G_ATOMICRMW_XOR; break; case AtomicRMWInst::Max: Opcode = TargetOpcode::G_ATOMICRMW_MAX; break; case AtomicRMWInst::Min: Opcode = TargetOpcode::G_ATOMICRMW_MIN; break; case AtomicRMWInst::UMax: Opcode = TargetOpcode::G_ATOMICRMW_UMAX; break; case AtomicRMWInst::UMin: Opcode = TargetOpcode::G_ATOMICRMW_UMIN; break; } MIRBuilder.buildAtomicRMW( Opcode, Res, Addr, Val, *MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()), Flags, DL->getTypeStoreSize(ResType), getMemOpAlignment(I), AAMDNodes(), nullptr, I.getSyncScopeID(), I.getOrdering())); return true; } void IRTranslator::finishPendingPhis() { for (auto &Phi : PendingPHIs) { const PHINode *PI = Phi.first; ArrayRef ComponentPHIs = Phi.second; // All MachineBasicBlocks exist, add them to the PHI. We assume IRTranslator // won't create extra control flow here, otherwise we need to find the // dominating predecessor here (or perhaps force the weirder IRTranslators // to provide a simple boundary). SmallSet HandledPreds; for (unsigned i = 0; i < PI->getNumIncomingValues(); ++i) { auto IRPred = PI->getIncomingBlock(i); if (HandledPreds.count(IRPred)) continue; HandledPreds.insert(IRPred); ArrayRef ValRegs = getOrCreateVRegs(*PI->getIncomingValue(i)); for (auto Pred : getMachinePredBBs({IRPred, PI->getParent()})) { assert(Pred->isSuccessor(ComponentPHIs[0]->getParent()) && "incorrect CFG at MachineBasicBlock level"); for (unsigned j = 0; j < ValRegs.size(); ++j) { MachineInstrBuilder MIB(*MF, ComponentPHIs[j]); MIB.addUse(ValRegs[j]); MIB.addMBB(Pred); } } } } } bool IRTranslator::valueIsSplit(const Value &V, SmallVectorImpl *Offsets) { SmallVector SplitTys; + if (Offsets && !Offsets->empty()) + Offsets->clear(); computeValueLLTs(*DL, *V.getType(), SplitTys, Offsets); return SplitTys.size() > 1; } bool IRTranslator::translate(const Instruction &Inst) { CurBuilder.setDebugLoc(Inst.getDebugLoc()); switch(Inst.getOpcode()) { #define HANDLE_INST(NUM, OPCODE, CLASS) \ case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder); #include "llvm/IR/Instruction.def" default: return false; } } bool IRTranslator::translate(const Constant &C, unsigned Reg) { if (auto CI = dyn_cast(&C)) EntryBuilder.buildConstant(Reg, *CI); else if (auto CF = dyn_cast(&C)) EntryBuilder.buildFConstant(Reg, *CF); else if (isa(C)) EntryBuilder.buildUndef(Reg); else if (isa(C)) { // As we are trying to build a constant val of 0 into a pointer, // insert a cast to make them correct with respect to types. unsigned NullSize = DL->getTypeSizeInBits(C.getType()); auto *ZeroTy = Type::getIntNTy(C.getContext(), NullSize); auto *ZeroVal = ConstantInt::get(ZeroTy, 0); unsigned ZeroReg = getOrCreateVReg(*ZeroVal); EntryBuilder.buildCast(Reg, ZeroReg); } else if (auto GV = dyn_cast(&C)) EntryBuilder.buildGlobalValue(Reg, GV); else if (auto CAZ = dyn_cast(&C)) { if (!CAZ->getType()->isVectorTy()) return false; // Return the scalar if it is a <1 x Ty> vector. if (CAZ->getNumElements() == 1) return translate(*CAZ->getElementValue(0u), Reg); std::vector Ops; for (unsigned i = 0; i < CAZ->getNumElements(); ++i) { Constant &Elt = *CAZ->getElementValue(i); Ops.push_back(getOrCreateVReg(Elt)); } EntryBuilder.buildMerge(Reg, Ops); } else if (auto CV = dyn_cast(&C)) { // Return the scalar if it is a <1 x Ty> vector. if (CV->getNumElements() == 1) return translate(*CV->getElementAsConstant(0), Reg); std::vector Ops; for (unsigned i = 0; i < CV->getNumElements(); ++i) { Constant &Elt = *CV->getElementAsConstant(i); Ops.push_back(getOrCreateVReg(Elt)); } EntryBuilder.buildMerge(Reg, Ops); } else if (auto CE = dyn_cast(&C)) { switch(CE->getOpcode()) { #define HANDLE_INST(NUM, OPCODE, CLASS) \ case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder); #include "llvm/IR/Instruction.def" default: return false; } } else if (auto CV = dyn_cast(&C)) { if (CV->getNumOperands() == 1) return translate(*CV->getOperand(0), Reg); SmallVector Ops; for (unsigned i = 0; i < CV->getNumOperands(); ++i) { Ops.push_back(getOrCreateVReg(*CV->getOperand(i))); } EntryBuilder.buildMerge(Reg, Ops); } else if (auto *BA = dyn_cast(&C)) { EntryBuilder.buildBlockAddress(Reg, BA); } else return false; return true; } void IRTranslator::finalizeFunction() { // Release the memory used by the different maps we // needed during the translation. PendingPHIs.clear(); VMap.reset(); FrameIndices.clear(); MachinePreds.clear(); // MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it // to avoid accessing free’d memory (in runOnMachineFunction) and to avoid // destroying it twice (in ~IRTranslator() and ~LLVMContext()) EntryBuilder = MachineIRBuilder(); CurBuilder = MachineIRBuilder(); } bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) { MF = &CurMF; const Function &F = MF->getFunction(); if (F.empty()) return false; CLI = MF->getSubtarget().getCallLowering(); CurBuilder.setMF(*MF); EntryBuilder.setMF(*MF); MRI = &MF->getRegInfo(); DL = &F.getParent()->getDataLayout(); TPC = &getAnalysis(); ORE = llvm::make_unique(&F); assert(PendingPHIs.empty() && "stale PHIs"); if (!DL->isLittleEndian()) { // Currently we don't properly handle big endian code. OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", F.getSubprogram(), &F.getEntryBlock()); R << "unable to translate in big endian mode"; reportTranslationError(*MF, *TPC, *ORE, R); } // Release the per-function state when we return, whether we succeeded or not. auto FinalizeOnReturn = make_scope_exit([this]() { finalizeFunction(); }); // Setup a separate basic-block for the arguments and constants MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock(); MF->push_back(EntryBB); EntryBuilder.setMBB(*EntryBB); // Create all blocks, in IR order, to preserve the layout. for (const BasicBlock &BB: F) { auto *&MBB = BBToMBB[&BB]; MBB = MF->CreateMachineBasicBlock(&BB); MF->push_back(MBB); if (BB.hasAddressTaken()) MBB->setHasAddressTaken(); } // Make our arguments/constants entry block fallthrough to the IR entry block. EntryBB->addSuccessor(&getMBB(F.front())); // Lower the actual args into this basic block. SmallVector VRegArgs; for (const Argument &Arg: F.args()) { if (DL->getTypeStoreSize(Arg.getType()) == 0) continue; // Don't handle zero sized types. VRegArgs.push_back( MRI->createGenericVirtualRegister(getLLTForType(*Arg.getType(), *DL))); } // We don't currently support translating swifterror or swiftself functions. for (auto &Arg : F.args()) { if (Arg.hasSwiftErrorAttr() || Arg.hasSwiftSelfAttr()) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", F.getSubprogram(), &F.getEntryBlock()); R << "unable to lower arguments due to swifterror/swiftself: " << ore::NV("Prototype", F.getType()); reportTranslationError(*MF, *TPC, *ORE, R); return false; } } if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) { OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", F.getSubprogram(), &F.getEntryBlock()); R << "unable to lower arguments: " << ore::NV("Prototype", F.getType()); reportTranslationError(*MF, *TPC, *ORE, R); return false; } auto ArgIt = F.arg_begin(); for (auto &VArg : VRegArgs) { // If the argument is an unsplit scalar then don't use unpackRegs to avoid // creating redundant copies. if (!valueIsSplit(*ArgIt, VMap.getOffsets(*ArgIt))) { auto &VRegs = *VMap.getVRegs(cast(*ArgIt)); assert(VRegs.empty() && "VRegs already populated?"); VRegs.push_back(VArg); } else { unpackRegs(*ArgIt, VArg, EntryBuilder); } ArgIt++; } // Need to visit defs before uses when translating instructions. ReversePostOrderTraversal RPOT(&F); for (const BasicBlock *BB : RPOT) { MachineBasicBlock &MBB = getMBB(*BB); // Set the insertion point of all the following translations to // the end of this basic block. CurBuilder.setMBB(MBB); for (const Instruction &Inst : *BB) { if (translate(Inst)) continue; OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure", Inst.getDebugLoc(), BB); R << "unable to translate instruction: " << ore::NV("Opcode", &Inst); if (ORE->allowExtraAnalysis("gisel-irtranslator")) { std::string InstStrStorage; raw_string_ostream InstStr(InstStrStorage); InstStr << Inst; R << ": '" << InstStr.str() << "'"; } reportTranslationError(*MF, *TPC, *ORE, R); return false; } } finishPendingPhis(); // Merge the argument lowering and constants block with its single // successor, the LLVM-IR entry block. We want the basic block to // be maximal. assert(EntryBB->succ_size() == 1 && "Custom BB used for lowering should have only one successor"); // Get the successor of the current entry block. MachineBasicBlock &NewEntryBB = **EntryBB->succ_begin(); assert(NewEntryBB.pred_size() == 1 && "LLVM-IR entry block has a predecessor!?"); // Move all the instruction from the current entry block to the // new entry block. NewEntryBB.splice(NewEntryBB.begin(), EntryBB, EntryBB->begin(), EntryBB->end()); // Update the live-in information for the new entry block. for (const MachineBasicBlock::RegisterMaskPair &LiveIn : EntryBB->liveins()) NewEntryBB.addLiveIn(LiveIn); NewEntryBB.sortUniqueLiveIns(); // Get rid of the now empty basic block. EntryBB->removeSuccessor(&NewEntryBB); MF->remove(EntryBB); MF->DeleteMachineBasicBlock(EntryBB); assert(&MF->front() == &NewEntryBB && "New entry wasn't next in the list of basic block!"); // Initialize stack protector information. StackProtector &SP = getAnalysis(); SP.copyToMachineFrameInfo(MF->getFrameInfo()); return false; } Index: vendor/llvm/dist-release_70/lib/IR/DebugInfo.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/IR/DebugInfo.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/IR/DebugInfo.cpp (revision 338378) @@ -1,1355 +1,1355 @@ //===- DebugInfo.cpp - Debug Information Helper Classes -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the helper classes used to build and interpret debug // information in LLVM IR form. // //===----------------------------------------------------------------------===// #include "llvm-c/DebugInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Support/Casting.h" #include #include #include using namespace llvm; using namespace llvm::dwarf; DISubprogram *llvm::getDISubprogram(const MDNode *Scope) { if (auto *LocalScope = dyn_cast_or_null(Scope)) return LocalScope->getSubprogram(); return nullptr; } //===----------------------------------------------------------------------===// // DebugInfoFinder implementations. //===----------------------------------------------------------------------===// void DebugInfoFinder::reset() { CUs.clear(); SPs.clear(); GVs.clear(); TYs.clear(); Scopes.clear(); NodesSeen.clear(); } void DebugInfoFinder::processModule(const Module &M) { for (auto *CU : M.debug_compile_units()) processCompileUnit(CU); for (auto &F : M.functions()) { if (auto *SP = cast_or_null(F.getSubprogram())) processSubprogram(SP); // There could be subprograms from inlined functions referenced from // instructions only. Walk the function to find them. for (const BasicBlock &BB : F) for (const Instruction &I : BB) processInstruction(M, I); } } void DebugInfoFinder::processCompileUnit(DICompileUnit *CU) { if (!addCompileUnit(CU)) return; for (auto DIG : CU->getGlobalVariables()) { if (!addGlobalVariable(DIG)) continue; auto *GV = DIG->getVariable(); processScope(GV->getScope()); processType(GV->getType().resolve()); } for (auto *ET : CU->getEnumTypes()) processType(ET); for (auto *RT : CU->getRetainedTypes()) if (auto *T = dyn_cast(RT)) processType(T); else processSubprogram(cast(RT)); for (auto *Import : CU->getImportedEntities()) { auto *Entity = Import->getEntity().resolve(); if (auto *T = dyn_cast(Entity)) processType(T); else if (auto *SP = dyn_cast(Entity)) processSubprogram(SP); else if (auto *NS = dyn_cast(Entity)) processScope(NS->getScope()); else if (auto *M = dyn_cast(Entity)) processScope(M->getScope()); } } void DebugInfoFinder::processInstruction(const Module &M, const Instruction &I) { if (auto *DDI = dyn_cast(&I)) processDeclare(M, DDI); else if (auto *DVI = dyn_cast(&I)) processValue(M, DVI); if (auto DbgLoc = I.getDebugLoc()) processLocation(M, DbgLoc.get()); } void DebugInfoFinder::processLocation(const Module &M, const DILocation *Loc) { if (!Loc) return; processScope(Loc->getScope()); processLocation(M, Loc->getInlinedAt()); } void DebugInfoFinder::processType(DIType *DT) { if (!addType(DT)) return; processScope(DT->getScope().resolve()); if (auto *ST = dyn_cast(DT)) { for (DITypeRef Ref : ST->getTypeArray()) processType(Ref.resolve()); return; } if (auto *DCT = dyn_cast(DT)) { processType(DCT->getBaseType().resolve()); for (Metadata *D : DCT->getElements()) { if (auto *T = dyn_cast(D)) processType(T); else if (auto *SP = dyn_cast(D)) processSubprogram(SP); } return; } if (auto *DDT = dyn_cast(DT)) { processType(DDT->getBaseType().resolve()); } } void DebugInfoFinder::processScope(DIScope *Scope) { if (!Scope) return; if (auto *Ty = dyn_cast(Scope)) { processType(Ty); return; } if (auto *CU = dyn_cast(Scope)) { addCompileUnit(CU); return; } if (auto *SP = dyn_cast(Scope)) { processSubprogram(SP); return; } if (!addScope(Scope)) return; if (auto *LB = dyn_cast(Scope)) { processScope(LB->getScope()); } else if (auto *NS = dyn_cast(Scope)) { processScope(NS->getScope()); } else if (auto *M = dyn_cast(Scope)) { processScope(M->getScope()); } } void DebugInfoFinder::processSubprogram(DISubprogram *SP) { if (!addSubprogram(SP)) return; processScope(SP->getScope().resolve()); // Some of the users, e.g. CloneFunctionInto / CloneModule, need to set up a // ValueMap containing identity mappings for all of the DICompileUnit's, not // just DISubprogram's, referenced from anywhere within the Function being // cloned prior to calling MapMetadata / RemapInstruction to avoid their // duplication later as DICompileUnit's are also directly referenced by // llvm.dbg.cu list. Thefore we need to collect DICompileUnit's here as well. // Also, DICompileUnit's may reference DISubprogram's too and therefore need // to be at least looked through. processCompileUnit(SP->getUnit()); processType(SP->getType()); for (auto *Element : SP->getTemplateParams()) { if (auto *TType = dyn_cast(Element)) { processType(TType->getType().resolve()); } else if (auto *TVal = dyn_cast(Element)) { processType(TVal->getType().resolve()); } } } void DebugInfoFinder::processDeclare(const Module &M, const DbgDeclareInst *DDI) { auto *N = dyn_cast(DDI->getVariable()); if (!N) return; auto *DV = dyn_cast(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve()); } void DebugInfoFinder::processValue(const Module &M, const DbgValueInst *DVI) { auto *N = dyn_cast(DVI->getVariable()); if (!N) return; auto *DV = dyn_cast(N); if (!DV) return; if (!NodesSeen.insert(DV).second) return; processScope(DV->getScope()); processType(DV->getType().resolve()); } bool DebugInfoFinder::addType(DIType *DT) { if (!DT) return false; if (!NodesSeen.insert(DT).second) return false; TYs.push_back(const_cast(DT)); return true; } bool DebugInfoFinder::addCompileUnit(DICompileUnit *CU) { if (!CU) return false; if (!NodesSeen.insert(CU).second) return false; CUs.push_back(CU); return true; } bool DebugInfoFinder::addGlobalVariable(DIGlobalVariableExpression *DIG) { if (!NodesSeen.insert(DIG).second) return false; GVs.push_back(DIG); return true; } bool DebugInfoFinder::addSubprogram(DISubprogram *SP) { if (!SP) return false; if (!NodesSeen.insert(SP).second) return false; SPs.push_back(SP); return true; } bool DebugInfoFinder::addScope(DIScope *Scope) { if (!Scope) return false; // FIXME: Ocaml binding generates a scope with no content, we treat it // as null for now. if (Scope->getNumOperands() == 0) return false; if (!NodesSeen.insert(Scope).second) return false; Scopes.push_back(Scope); return true; } static MDNode *stripDebugLocFromLoopID(MDNode *N) { assert(N->op_begin() != N->op_end() && "Missing self reference?"); // if there is no debug location, we do not have to rewrite this MDNode. if (std::none_of(N->op_begin() + 1, N->op_end(), [](const MDOperand &Op) { return isa(Op.get()); })) return N; // If there is only the debug location without any actual loop metadata, we // can remove the metadata. if (std::none_of(N->op_begin() + 1, N->op_end(), [](const MDOperand &Op) { return !isa(Op.get()); })) return nullptr; SmallVector Args; // Reserve operand 0 for loop id self reference. auto TempNode = MDNode::getTemporary(N->getContext(), None); Args.push_back(TempNode.get()); // Add all non-debug location operands back. for (auto Op = N->op_begin() + 1; Op != N->op_end(); Op++) { if (!isa(*Op)) Args.push_back(*Op); } // Set the first operand to itself. MDNode *LoopID = MDNode::get(N->getContext(), Args); LoopID->replaceOperandWith(0, LoopID); return LoopID; } bool llvm::stripDebugInfo(Function &F) { bool Changed = false; if (F.hasMetadata(LLVMContext::MD_dbg)) { Changed = true; F.setSubprogram(nullptr); } DenseMap LoopIDsMap; for (BasicBlock &BB : F) { for (auto II = BB.begin(), End = BB.end(); II != End;) { Instruction &I = *II++; // We may delete the instruction, increment now. if (isa(&I)) { I.eraseFromParent(); Changed = true; continue; } if (I.getDebugLoc()) { Changed = true; I.setDebugLoc(DebugLoc()); } } auto *TermInst = BB.getTerminator(); if (!TermInst) // This is invalid IR, but we may not have run the verifier yet continue; if (auto *LoopID = TermInst->getMetadata(LLVMContext::MD_loop)) { auto *NewLoopID = LoopIDsMap.lookup(LoopID); if (!NewLoopID) NewLoopID = LoopIDsMap[LoopID] = stripDebugLocFromLoopID(LoopID); if (NewLoopID != LoopID) TermInst->setMetadata(LLVMContext::MD_loop, NewLoopID); } } return Changed; } bool llvm::StripDebugInfo(Module &M) { bool Changed = false; for (Module::named_metadata_iterator NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = &*NMI; ++NMI; // We're stripping debug info, and without them, coverage information // doesn't quite make sense. if (NMD->getName().startswith("llvm.dbg.") || NMD->getName() == "llvm.gcov") { NMD->eraseFromParent(); Changed = true; } } for (Function &F : M) Changed |= stripDebugInfo(F); for (auto &GV : M.globals()) { Changed |= GV.eraseMetadata(LLVMContext::MD_dbg); } if (GVMaterializer *Materializer = M.getMaterializer()) Materializer->setStripDebugInfo(); return Changed; } namespace { /// Helper class to downgrade -g metadata to -gline-tables-only metadata. class DebugTypeInfoRemoval { DenseMap Replacements; public: /// The (void)() type. MDNode *EmptySubroutineType; private: /// Remember what linkage name we originally had before stripping. If we end /// up making two subprograms identical who originally had different linkage /// names, then we need to make one of them distinct, to avoid them getting /// uniqued. Maps the new node to the old linkage name. DenseMap NewToLinkageName; // TODO: Remember the distinct subprogram we created for a given linkage name, // so that we can continue to unique whenever possible. Map to the first (possibly distinct) mdsubprogram // created for that combination. This is not strictly needed for correctness, // but can cut down on the number of MDNodes and let us diff cleanly with the // output of -gline-tables-only. public: DebugTypeInfoRemoval(LLVMContext &C) : EmptySubroutineType(DISubroutineType::get(C, DINode::FlagZero, 0, MDNode::get(C, {}))) {} Metadata *map(Metadata *M) { if (!M) return nullptr; auto Replacement = Replacements.find(M); if (Replacement != Replacements.end()) return Replacement->second; return M; } MDNode *mapNode(Metadata *N) { return dyn_cast_or_null(map(N)); } /// Recursively remap N and all its referenced children. Does a DF post-order /// traversal, so as to remap bottoms up. void traverseAndRemap(MDNode *N) { traverse(N); } private: // Create a new DISubprogram, to replace the one given. DISubprogram *getReplacementSubprogram(DISubprogram *MDS) { auto *FileAndScope = cast_or_null(map(MDS->getFile())); StringRef LinkageName = MDS->getName().empty() ? MDS->getLinkageName() : ""; DISubprogram *Declaration = nullptr; auto *Type = cast_or_null(map(MDS->getType())); DITypeRef ContainingType(map(MDS->getContainingType())); auto *Unit = cast_or_null(map(MDS->getUnit())); auto Variables = nullptr; auto TemplateParams = nullptr; // Make a distinct DISubprogram, for situations that warrent it. auto distinctMDSubprogram = [&]() { return DISubprogram::getDistinct( MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), MDS->isDefinition(), MDS->getScopeLine(), ContainingType, MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration, Variables); }; if (MDS->isDistinct()) return distinctMDSubprogram(); auto *NewMDS = DISubprogram::get( MDS->getContext(), FileAndScope, MDS->getName(), LinkageName, FileAndScope, MDS->getLine(), Type, MDS->isLocalToUnit(), MDS->isDefinition(), MDS->getScopeLine(), ContainingType, MDS->getVirtuality(), MDS->getVirtualIndex(), MDS->getThisAdjustment(), MDS->getFlags(), MDS->isOptimized(), Unit, TemplateParams, Declaration, Variables); StringRef OldLinkageName = MDS->getLinkageName(); // See if we need to make a distinct one. auto OrigLinkage = NewToLinkageName.find(NewMDS); if (OrigLinkage != NewToLinkageName.end()) { if (OrigLinkage->second == OldLinkageName) // We're good. return NewMDS; // Otherwise, need to make a distinct one. // TODO: Query the map to see if we already have one. return distinctMDSubprogram(); } NewToLinkageName.insert({NewMDS, MDS->getLinkageName()}); return NewMDS; } /// Create a new compile unit, to replace the one given DICompileUnit *getReplacementCU(DICompileUnit *CU) { // Drop skeleton CUs. if (CU->getDWOId()) return nullptr; auto *File = cast_or_null(map(CU->getFile())); MDTuple *EnumTypes = nullptr; MDTuple *RetainedTypes = nullptr; MDTuple *GlobalVariables = nullptr; MDTuple *ImportedEntities = nullptr; return DICompileUnit::getDistinct( CU->getContext(), CU->getSourceLanguage(), File, CU->getProducer(), CU->isOptimized(), CU->getFlags(), CU->getRuntimeVersion(), CU->getSplitDebugFilename(), DICompileUnit::LineTablesOnly, EnumTypes, RetainedTypes, GlobalVariables, ImportedEntities, CU->getMacros(), CU->getDWOId(), CU->getSplitDebugInlining(), CU->getDebugInfoForProfiling(), CU->getGnuPubnames()); } DILocation *getReplacementMDLocation(DILocation *MLD) { auto *Scope = map(MLD->getScope()); auto *InlinedAt = map(MLD->getInlinedAt()); if (MLD->isDistinct()) return DILocation::getDistinct(MLD->getContext(), MLD->getLine(), MLD->getColumn(), Scope, InlinedAt); return DILocation::get(MLD->getContext(), MLD->getLine(), MLD->getColumn(), Scope, InlinedAt); } /// Create a new generic MDNode, to replace the one given MDNode *getReplacementMDNode(MDNode *N) { SmallVector Ops; Ops.reserve(N->getNumOperands()); for (auto &I : N->operands()) if (I) Ops.push_back(map(I)); auto *Ret = MDNode::get(N->getContext(), Ops); return Ret; } /// Attempt to re-map N to a newly created node. void remap(MDNode *N) { if (Replacements.count(N)) return; auto doRemap = [&](MDNode *N) -> MDNode * { if (!N) return nullptr; if (auto *MDSub = dyn_cast(N)) { remap(MDSub->getUnit()); return getReplacementSubprogram(MDSub); } if (isa(N)) return EmptySubroutineType; if (auto *CU = dyn_cast(N)) return getReplacementCU(CU); if (isa(N)) return N; if (auto *MDLB = dyn_cast(N)) // Remap to our referenced scope (recursively). return mapNode(MDLB->getScope()); if (auto *MLD = dyn_cast(N)) return getReplacementMDLocation(MLD); // Otherwise, if we see these, just drop them now. Not strictly necessary, // but this speeds things up a little. if (isa(N)) return nullptr; return getReplacementMDNode(N); }; Replacements[N] = doRemap(N); } /// Do the remapping traversal. void traverse(MDNode *); }; } // end anonymous namespace void DebugTypeInfoRemoval::traverse(MDNode *N) { if (!N || Replacements.count(N)) return; // To avoid cycles, as well as for efficiency sake, we will sometimes prune // parts of the graph. auto prune = [](MDNode *Parent, MDNode *Child) { if (auto *MDS = dyn_cast(Parent)) return Child == MDS->getRetainedNodes().get(); return false; }; SmallVector ToVisit; DenseSet Opened; // Visit each node starting at N in post order, and map them. ToVisit.push_back(N); while (!ToVisit.empty()) { auto *N = ToVisit.back(); if (!Opened.insert(N).second) { // Close it. remap(N); ToVisit.pop_back(); continue; } for (auto &I : N->operands()) if (auto *MDN = dyn_cast_or_null(I)) if (!Opened.count(MDN) && !Replacements.count(MDN) && !prune(N, MDN) && !isa(MDN)) ToVisit.push_back(MDN); } } bool llvm::stripNonLineTableDebugInfo(Module &M) { bool Changed = false; // First off, delete the debug intrinsics. auto RemoveUses = [&](StringRef Name) { if (auto *DbgVal = M.getFunction(Name)) { while (!DbgVal->use_empty()) cast(DbgVal->user_back())->eraseFromParent(); DbgVal->eraseFromParent(); Changed = true; } }; RemoveUses("llvm.dbg.declare"); RemoveUses("llvm.dbg.value"); // Delete non-CU debug info named metadata nodes. for (auto NMI = M.named_metadata_begin(), NME = M.named_metadata_end(); NMI != NME;) { NamedMDNode *NMD = &*NMI; ++NMI; // Specifically keep dbg.cu around. if (NMD->getName() == "llvm.dbg.cu") continue; } // Drop all dbg attachments from global variables. for (auto &GV : M.globals()) GV.eraseMetadata(LLVMContext::MD_dbg); DebugTypeInfoRemoval Mapper(M.getContext()); auto remap = [&](MDNode *Node) -> MDNode * { if (!Node) return nullptr; Mapper.traverseAndRemap(Node); auto *NewNode = Mapper.mapNode(Node); Changed |= Node != NewNode; Node = NewNode; return NewNode; }; // Rewrite the DebugLocs to be equivalent to what // -gline-tables-only would have created. for (auto &F : M) { if (auto *SP = F.getSubprogram()) { Mapper.traverseAndRemap(SP); auto *NewSP = cast(Mapper.mapNode(SP)); Changed |= SP != NewSP; F.setSubprogram(NewSP); } for (auto &BB : F) { for (auto &I : BB) { auto remapDebugLoc = [&](DebugLoc DL) -> DebugLoc { auto *Scope = DL.getScope(); MDNode *InlinedAt = DL.getInlinedAt(); Scope = remap(Scope); InlinedAt = remap(InlinedAt); return DebugLoc::get(DL.getLine(), DL.getCol(), Scope, InlinedAt); }; if (I.getDebugLoc() != DebugLoc()) I.setDebugLoc(remapDebugLoc(I.getDebugLoc())); // Remap DILocations in untyped MDNodes (e.g., llvm.loop). SmallVector, 2> MDs; I.getAllMetadata(MDs); for (auto Attachment : MDs) if (auto *T = dyn_cast_or_null(Attachment.second)) for (unsigned N = 0; N < T->getNumOperands(); ++N) if (auto *Loc = dyn_cast_or_null(T->getOperand(N))) if (Loc != DebugLoc()) T->replaceOperandWith(N, remapDebugLoc(Loc)); } } } // Create a new llvm.dbg.cu, which is equivalent to the one // -gline-tables-only would have created. for (auto &NMD : M.getNamedMDList()) { SmallVector Ops; for (MDNode *Op : NMD.operands()) Ops.push_back(remap(Op)); if (!Changed) continue; NMD.clearOperands(); for (auto *Op : Ops) if (Op) NMD.addOperand(Op); } return Changed; } unsigned llvm::getDebugMetadataVersionFromModule(const Module &M) { if (auto *Val = mdconst::dyn_extract_or_null( M.getModuleFlag("Debug Info Version"))) return Val->getZExtValue(); return 0; } void Instruction::applyMergedLocation(const DILocation *LocA, const DILocation *LocB) { setDebugLoc(DILocation::getMergedLocation(LocA, LocB, DILocation::WithGeneratedLocation)); } //===----------------------------------------------------------------------===// // LLVM C API implementations. //===----------------------------------------------------------------------===// static unsigned map_from_llvmDWARFsourcelanguage(LLVMDWARFSourceLanguage lang) { switch (lang) { #define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ case LLVMDWARFSourceLanguage##NAME: return ID; #include "llvm/BinaryFormat/Dwarf.def" #undef HANDLE_DW_LANG } llvm_unreachable("Unhandled Tag"); } template DIT *unwrapDI(LLVMMetadataRef Ref) { return (DIT *)(Ref ? unwrap(Ref) : nullptr); } static DINode::DIFlags map_from_llvmDIFlags(LLVMDIFlags Flags) { return static_cast(Flags); } static LLVMDIFlags map_to_llvmDIFlags(DINode::DIFlags Flags) { return static_cast(Flags); } unsigned LLVMDebugMetadataVersion() { return DEBUG_METADATA_VERSION; } LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M) { return wrap(new DIBuilder(*unwrap(M), false)); } LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M) { return wrap(new DIBuilder(*unwrap(M))); } unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef M) { return getDebugMetadataVersionFromModule(*unwrap(M)); } LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef M) { return StripDebugInfo(*unwrap(M)); } void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder) { delete unwrap(Builder); } void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder) { unwrap(Builder)->finalize(); } LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, LLVMBool isOptimized, const char *Flags, size_t FlagsLen, unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, LLVMBool DebugInfoForProfiling) { auto File = unwrapDI(FileRef); return wrap(unwrap(Builder)->createCompileUnit( map_from_llvmDWARFsourcelanguage(Lang), File, StringRef(Producer, ProducerLen), isOptimized, StringRef(Flags, FlagsLen), RuntimeVer, StringRef(SplitName, SplitNameLen), static_cast(Kind), DWOId, SplitDebugInlining, DebugInfoForProfiling)); } LLVMMetadataRef LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, size_t FilenameLen, const char *Directory, size_t DirectoryLen) { return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen), StringRef(Directory, DirectoryLen))); } LLVMMetadataRef LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, const char *ConfigMacros, size_t ConfigMacrosLen, const char *IncludePath, size_t IncludePathLen, const char *ISysRoot, size_t ISysRootLen) { return wrap(unwrap(Builder)->createModule( unwrapDI(ParentScope), StringRef(Name, NameLen), StringRef(ConfigMacros, ConfigMacrosLen), StringRef(IncludePath, IncludePathLen), StringRef(ISysRoot, ISysRootLen))); } LLVMMetadataRef LLVMDIBuilderCreateNameSpace(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, LLVMBool ExportSymbols) { return wrap(unwrap(Builder)->createNameSpace( unwrapDI(ParentScope), StringRef(Name, NameLen), ExportSymbols)); } LLVMMetadataRef LLVMDIBuilderCreateFunction( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *LinkageName, size_t LinkageNameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool IsLocalToUnit, LLVMBool IsDefinition, unsigned ScopeLine, LLVMDIFlags Flags, LLVMBool IsOptimized) { return wrap(unwrap(Builder)->createFunction( unwrapDI(Scope), {Name, NameLen}, {LinkageName, LinkageNameLen}, unwrapDI(File), LineNo, unwrapDI(Ty), IsLocalToUnit, IsDefinition, ScopeLine, map_from_llvmDIFlags(Flags), IsOptimized, nullptr, nullptr, nullptr)); } LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned Col) { return wrap(unwrap(Builder)->createLexicalBlock(unwrapDI(Scope), unwrapDI(File), Line, Col)); } LLVMMetadataRef LLVMDIBuilderCreateLexicalBlockFile(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Discriminator) { return wrap(unwrap(Builder)->createLexicalBlockFile(unwrapDI(Scope), unwrapDI(File), Discriminator)); } LLVMMetadataRef LLVMDIBuilderCreateImportedModuleFromNamespace(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef NS, LLVMMetadataRef File, unsigned Line) { return wrap(unwrap(Builder)->createImportedModule(unwrapDI(Scope), unwrapDI(NS), unwrapDI(File), Line)); } LLVMMetadataRef LLVMDIBuilderCreateImportedModuleFromAlias(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef ImportedEntity, LLVMMetadataRef File, unsigned Line) { return wrap(unwrap(Builder)->createImportedModule( unwrapDI(Scope), unwrapDI(ImportedEntity), unwrapDI(File), Line)); } LLVMMetadataRef LLVMDIBuilderCreateImportedModuleFromModule(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef M, LLVMMetadataRef File, unsigned Line) { return wrap(unwrap(Builder)->createImportedModule(unwrapDI(Scope), unwrapDI(M), unwrapDI(File), Line)); } LLVMMetadataRef LLVMDIBuilderCreateImportedDeclaration(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, LLVMMetadataRef Decl, LLVMMetadataRef File, unsigned Line, const char *Name, size_t NameLen) { return wrap(unwrap(Builder)->createImportedDeclaration( unwrapDI(Scope), unwrapDI(Decl), unwrapDI(File), Line, {Name, NameLen})); } LLVMMetadataRef LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, unsigned Column, LLVMMetadataRef Scope, LLVMMetadataRef InlinedAt) { return wrap(DILocation::get(*unwrap(Ctx), Line, Column, unwrap(Scope), unwrap(InlinedAt))); } unsigned LLVMDILocationGetLine(LLVMMetadataRef Location) { return unwrapDI(Location)->getLine(); } unsigned LLVMDILocationGetColumn(LLVMMetadataRef Location) { return unwrapDI(Location)->getColumn(); } LLVMMetadataRef LLVMDILocationGetScope(LLVMMetadataRef Location) { return wrap(unwrapDI(Location)->getScope()); } LLVMMetadataRef LLVMDIBuilderCreateEnumerationType( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMMetadataRef *Elements, unsigned NumElements, LLVMMetadataRef ClassTy) { auto Elts = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements}); return wrap(unwrap(Builder)->createEnumerationType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, Elts, unwrapDI(ClassTy))); } LLVMMetadataRef LLVMDIBuilderCreateUnionType( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, LLVMMetadataRef *Elements, unsigned NumElements, unsigned RunTimeLang, const char *UniqueId, size_t UniqueIdLen) { auto Elts = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements}); return wrap(unwrap(Builder)->createUnionType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, map_from_llvmDIFlags(Flags), Elts, RunTimeLang, {UniqueId, UniqueIdLen})); } LLVMMetadataRef LLVMDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, uint32_t AlignInBits, LLVMMetadataRef Ty, LLVMMetadataRef *Subscripts, unsigned NumSubscripts) { auto Subs = unwrap(Builder)->getOrCreateArray({unwrap(Subscripts), NumSubscripts}); return wrap(unwrap(Builder)->createArrayType(Size, AlignInBits, unwrapDI(Ty), Subs)); } LLVMMetadataRef LLVMDIBuilderCreateVectorType(LLVMDIBuilderRef Builder, uint64_t Size, uint32_t AlignInBits, LLVMMetadataRef Ty, LLVMMetadataRef *Subscripts, unsigned NumSubscripts) { auto Subs = unwrap(Builder)->getOrCreateArray({unwrap(Subscripts), NumSubscripts}); return wrap(unwrap(Builder)->createVectorType(Size, AlignInBits, unwrapDI(Ty), Subs)); } LLVMMetadataRef LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, uint64_t SizeInBits, LLVMDWARFTypeEncoding Encoding) { return wrap(unwrap(Builder)->createBasicType({Name, NameLen}, SizeInBits, Encoding)); } LLVMMetadataRef LLVMDIBuilderCreatePointerType( LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, const char *Name, size_t NameLen) { return wrap(unwrap(Builder)->createPointerType(unwrapDI(PointeeTy), SizeInBits, AlignInBits, AddressSpace, {Name, NameLen})); } LLVMMetadataRef LLVMDIBuilderCreateStructType( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, LLVMMetadataRef DerivedFrom, LLVMMetadataRef *Elements, unsigned NumElements, unsigned RunTimeLang, LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) { auto Elts = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements}); return wrap(unwrap(Builder)->createStructType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, map_from_llvmDIFlags(Flags), unwrapDI(DerivedFrom), Elts, RunTimeLang, unwrapDI(VTableHolder), {UniqueId, UniqueIdLen})); } LLVMMetadataRef LLVMDIBuilderCreateMemberType( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags, LLVMMetadataRef Ty) { return wrap(unwrap(Builder)->createMemberType(unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, map_from_llvmDIFlags(Flags), unwrapDI(Ty))); } LLVMMetadataRef LLVMDIBuilderCreateUnspecifiedType(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen) { return wrap(unwrap(Builder)->createUnspecifiedType({Name, NameLen})); } LLVMMetadataRef LLVMDIBuilderCreateStaticMemberType( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, LLVMMetadataRef Type, LLVMDIFlags Flags, LLVMValueRef ConstantVal, uint32_t AlignInBits) { return wrap(unwrap(Builder)->createStaticMemberType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, unwrapDI(Type), map_from_llvmDIFlags(Flags), unwrap(ConstantVal), AlignInBits)); } LLVMMetadataRef LLVMDIBuilderCreateObjCIVar(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags, LLVMMetadataRef Ty, LLVMMetadataRef PropertyNode) { return wrap(unwrap(Builder)->createObjCIVar( {Name, NameLen}, unwrapDI(File), LineNo, SizeInBits, AlignInBits, OffsetInBits, map_from_llvmDIFlags(Flags), unwrapDI(Ty), unwrapDI(PropertyNode))); } LLVMMetadataRef LLVMDIBuilderCreateObjCProperty(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, const char *GetterName, size_t GetterNameLen, const char *SetterName, size_t SetterNameLen, unsigned PropertyAttributes, LLVMMetadataRef Ty) { return wrap(unwrap(Builder)->createObjCProperty( {Name, NameLen}, unwrapDI(File), LineNo, {GetterName, GetterNameLen}, {SetterName, SetterNameLen}, PropertyAttributes, unwrapDI(Ty))); } LLVMMetadataRef LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, LLVMMetadataRef Type) { return wrap(unwrap(Builder)->createObjectPointerType(unwrapDI(Type))); } LLVMMetadataRef LLVMDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Scope) { return wrap(unwrap(Builder)->createTypedef( unwrapDI(Type), {Name, NameLen}, unwrapDI(File), LineNo, unwrapDI(Scope))); } LLVMMetadataRef LLVMDIBuilderCreateInheritance(LLVMDIBuilderRef Builder, LLVMMetadataRef Ty, LLVMMetadataRef BaseTy, uint64_t BaseOffset, uint32_t VBPtrOffset, LLVMDIFlags Flags) { return wrap(unwrap(Builder)->createInheritance( unwrapDI(Ty), unwrapDI(BaseTy), BaseOffset, VBPtrOffset, map_from_llvmDIFlags(Flags))); } LLVMMetadataRef LLVMDIBuilderCreateForwardDecl( LLVMDIBuilderRef Builder, unsigned Tag, const char *Name, size_t NameLen, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, const char *UniqueIdentifier, size_t UniqueIdentifierLen) { return wrap(unwrap(Builder)->createForwardDecl( Tag, {Name, NameLen}, unwrapDI(Scope), unwrapDI(File), Line, RuntimeLang, SizeInBits, AlignInBits, {UniqueIdentifier, UniqueIdentifierLen})); } LLVMMetadataRef LLVMDIBuilderCreateReplaceableCompositeType( LLVMDIBuilderRef Builder, unsigned Tag, const char *Name, size_t NameLen, LLVMMetadataRef Scope, LLVMMetadataRef File, unsigned Line, unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, const char *UniqueIdentifier, size_t UniqueIdentifierLen) { return wrap(unwrap(Builder)->createReplaceableCompositeType( Tag, {Name, NameLen}, unwrapDI(Scope), unwrapDI(File), Line, RuntimeLang, SizeInBits, AlignInBits, map_from_llvmDIFlags(Flags), {UniqueIdentifier, UniqueIdentifierLen})); } LLVMMetadataRef LLVMDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Type) { return wrap(unwrap(Builder)->createQualifiedType(Tag, unwrapDI(Type))); } LLVMMetadataRef LLVMDIBuilderCreateReferenceType(LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Type) { return wrap(unwrap(Builder)->createReferenceType(Tag, unwrapDI(Type))); } LLVMMetadataRef LLVMDIBuilderCreateNullPtrType(LLVMDIBuilderRef Builder) { return wrap(unwrap(Builder)->createNullPtrType()); } LLVMMetadataRef LLVMDIBuilderCreateMemberPointerType(LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeType, LLVMMetadataRef ClassType, uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags) { return wrap(unwrap(Builder)->createMemberPointerType( unwrapDI(PointeeType), unwrapDI(ClassType), AlignInBits, SizeInBits, map_from_llvmDIFlags(Flags))); } LLVMMetadataRef LLVMDIBuilderCreateBitFieldMemberType(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint64_t OffsetInBits, uint64_t StorageOffsetInBits, LLVMDIFlags Flags, LLVMMetadataRef Type) { return wrap(unwrap(Builder)->createBitFieldMemberType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, SizeInBits, OffsetInBits, StorageOffsetInBits, map_from_llvmDIFlags(Flags), unwrapDI(Type))); } LLVMMetadataRef LLVMDIBuilderCreateClassType(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, LLVMDIFlags Flags, LLVMMetadataRef DerivedFrom, LLVMMetadataRef *Elements, unsigned NumElements, LLVMMetadataRef VTableHolder, LLVMMetadataRef TemplateParamsNode, const char *UniqueIdentifier, size_t UniqueIdentifierLen) { auto Elts = unwrap(Builder)->getOrCreateArray({unwrap(Elements), NumElements}); return wrap(unwrap(Builder)->createClassType( unwrapDI(Scope), {Name, NameLen}, unwrapDI(File), LineNumber, SizeInBits, AlignInBits, OffsetInBits, map_from_llvmDIFlags(Flags), unwrapDI(DerivedFrom), Elts, unwrapDI(VTableHolder), unwrapDI(TemplateParamsNode), {UniqueIdentifier, UniqueIdentifierLen})); } LLVMMetadataRef LLVMDIBuilderCreateArtificialType(LLVMDIBuilderRef Builder, LLVMMetadataRef Type) { return wrap(unwrap(Builder)->createArtificialType(unwrapDI(Type))); } const char *LLVMDITypeGetName(LLVMMetadataRef DType, size_t *Length) { StringRef Str = unwrap(DType)->getName(); *Length = Str.size(); return Str.data(); } uint64_t LLVMDITypeGetSizeInBits(LLVMMetadataRef DType) { return unwrapDI(DType)->getSizeInBits(); } uint64_t LLVMDITypeGetOffsetInBits(LLVMMetadataRef DType) { return unwrapDI(DType)->getOffsetInBits(); } uint32_t LLVMDITypeGetAlignInBits(LLVMMetadataRef DType) { return unwrapDI(DType)->getAlignInBits(); } unsigned LLVMDITypeGetLine(LLVMMetadataRef DType) { return unwrapDI(DType)->getLine(); } LLVMDIFlags LLVMDITypeGetFlags(LLVMMetadataRef DType) { return map_to_llvmDIFlags(unwrapDI(DType)->getFlags()); } LLVMMetadataRef LLVMDIBuilderGetOrCreateTypeArray(LLVMDIBuilderRef Builder, LLVMMetadataRef *Types, size_t Length) { return wrap( unwrap(Builder)->getOrCreateTypeArray({unwrap(Types), Length}).get()); } LLVMMetadataRef LLVMDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder, LLVMMetadataRef File, LLVMMetadataRef *ParameterTypes, unsigned NumParameterTypes, LLVMDIFlags Flags) { auto Elts = unwrap(Builder)->getOrCreateTypeArray({unwrap(ParameterTypes), NumParameterTypes}); return wrap(unwrap(Builder)->createSubroutineType( Elts, map_from_llvmDIFlags(Flags))); } LLVMMetadataRef LLVMDIBuilderCreateExpression(LLVMDIBuilderRef Builder, int64_t *Addr, size_t Length) { return wrap(unwrap(Builder)->createExpression(ArrayRef(Addr, Length))); } LLVMMetadataRef LLVMDIBuilderCreateConstantValueExpression(LLVMDIBuilderRef Builder, int64_t Value) { return wrap(unwrap(Builder)->createConstantValueExpression(Value)); } LLVMMetadataRef LLVMDIBuilderCreateGlobalVariableExpression(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *Linkage, size_t LinkLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, LLVMMetadataRef Expr, LLVMMetadataRef Decl, uint32_t AlignInBits) { return wrap(unwrap(Builder)->createGlobalVariableExpression( unwrapDI(Scope), {Name, NameLen}, {Linkage, LinkLen}, unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, unwrap(Expr), unwrapDI(Decl), AlignInBits)); } LLVMMetadataRef LLVMTemporaryMDNode(LLVMContextRef Ctx, LLVMMetadataRef *Data, size_t Count) { return wrap( MDTuple::getTemporary(*unwrap(Ctx), {unwrap(Data), Count}).release()); } void LLVMDisposeTemporaryMDNode(LLVMMetadataRef TempNode) { MDNode::deleteTemporary(unwrapDI(TempNode)); } void LLVMMetadataReplaceAllUsesWith(LLVMMetadataRef TargetMetadata, LLVMMetadataRef Replacement) { auto *Node = unwrapDI(TargetMetadata); Node->replaceAllUsesWith(unwrap(Replacement)); MDNode::deleteTemporary(Node); } LLVMMetadataRef LLVMDIBuilderCreateTempGlobalVariableFwdDecl(LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *Linkage, size_t LnkLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool LocalToUnit, LLVMMetadataRef Decl, uint32_t AlignInBits) { return wrap(unwrap(Builder)->createTempGlobalVariableFwdDecl( unwrapDI(Scope), {Name, NameLen}, {Linkage, LnkLen}, unwrapDI(File), LineNo, unwrapDI(Ty), LocalToUnit, unwrapDI(Decl), AlignInBits)); } LLVMValueRef LLVMDIBuilderInsertDeclareBefore( LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo, LLVMMetadataRef Expr, LLVMMetadataRef DL, LLVMValueRef Instr) { return wrap(unwrap(Builder)->insertDeclare( unwrap(Storage), unwrap(VarInfo), unwrap(Expr), unwrap(DL), unwrap(Instr))); } LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd( LLVMDIBuilderRef Builder, LLVMValueRef Storage, LLVMMetadataRef VarInfo, LLVMMetadataRef Expr, LLVMMetadataRef DL, LLVMBasicBlockRef Block) { return wrap(unwrap(Builder)->insertDeclare( unwrap(Storage), unwrap(VarInfo), unwrap(Expr), unwrap(DL), unwrap(Block))); } LLVMValueRef LLVMDIBuilderInsertDbgValueBefore(LLVMDIBuilderRef Builder, LLVMValueRef Val, LLVMMetadataRef VarInfo, LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMValueRef Instr) { return wrap(unwrap(Builder)->insertDbgValueIntrinsic( unwrap(Val), unwrap(VarInfo), unwrap(Expr), unwrap(DebugLoc), unwrap(Instr))); } LLVMValueRef LLVMDIBuilderInsertDbgValueAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef Val, LLVMMetadataRef VarInfo, LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMBasicBlockRef Block) { return wrap(unwrap(Builder)->insertDbgValueIntrinsic( unwrap(Val), unwrap(VarInfo), unwrap(Expr), unwrap(DebugLoc), unwrap(Block))); } LLVMMetadataRef LLVMDIBuilderCreateAutoVariable( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, LLVMDIFlags Flags, uint32_t AlignInBits) { return wrap(unwrap(Builder)->createAutoVariable( unwrap(Scope), {Name, NameLen}, unwrap(File), LineNo, unwrap(Ty), AlwaysPreserve, map_from_llvmDIFlags(Flags), AlignInBits)); } LLVMMetadataRef LLVMDIBuilderCreateParameterVariable( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, unsigned ArgNo, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, LLVMDIFlags Flags) { return wrap(unwrap(Builder)->createParameterVariable( - unwrap(Scope), Name, ArgNo, unwrap(File), + unwrap(Scope), {Name, NameLen}, ArgNo, unwrap(File), LineNo, unwrap(Ty), AlwaysPreserve, map_from_llvmDIFlags(Flags))); } LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); } LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, LLVMMetadataRef *Data, size_t Length) { Metadata **DataValue = unwrap(Data); return wrap(unwrap(Builder)->getOrCreateArray({DataValue, Length}).get()); } LLVMMetadataRef LLVMGetSubprogram(LLVMValueRef Func) { return wrap(unwrap(Func)->getSubprogram()); } void LLVMSetSubprogram(LLVMValueRef Func, LLVMMetadataRef SP) { unwrap(Func)->setSubprogram(unwrap(SP)); } Index: vendor/llvm/dist-release_70/lib/MC/MCExpr.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/MC/MCExpr.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/MC/MCExpr.cpp (revision 338378) @@ -1,878 +1,892 @@ //===- MCExpr.cpp - Assembly Level Expression Implementation --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCExpr.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; #define DEBUG_TYPE "mcexpr" namespace { namespace stats { STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations"); } // end namespace stats } // end anonymous namespace void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const { switch (getKind()) { case MCExpr::Target: return cast(this)->printImpl(OS, MAI); case MCExpr::Constant: OS << cast(*this).getValue(); return; case MCExpr::SymbolRef: { const MCSymbolRefExpr &SRE = cast(*this); const MCSymbol &Sym = SRE.getSymbol(); // Parenthesize names that start with $ so that they don't look like // absolute names. bool UseParens = !InParens && !Sym.getName().empty() && Sym.getName()[0] == '$'; if (UseParens) { OS << '('; Sym.print(OS, MAI); OS << ')'; } else Sym.print(OS, MAI); if (SRE.getKind() != MCSymbolRefExpr::VK_None) SRE.printVariantKind(OS); return; } case MCExpr::Unary: { const MCUnaryExpr &UE = cast(*this); switch (UE.getOpcode()) { case MCUnaryExpr::LNot: OS << '!'; break; case MCUnaryExpr::Minus: OS << '-'; break; case MCUnaryExpr::Not: OS << '~'; break; case MCUnaryExpr::Plus: OS << '+'; break; } bool Binary = UE.getSubExpr()->getKind() == MCExpr::Binary; if (Binary) OS << "("; UE.getSubExpr()->print(OS, MAI); if (Binary) OS << ")"; return; } case MCExpr::Binary: { const MCBinaryExpr &BE = cast(*this); // Only print parens around the LHS if it is non-trivial. if (isa(BE.getLHS()) || isa(BE.getLHS())) { BE.getLHS()->print(OS, MAI); } else { OS << '('; BE.getLHS()->print(OS, MAI); OS << ')'; } switch (BE.getOpcode()) { case MCBinaryExpr::Add: // Print "X-42" instead of "X+-42". if (const MCConstantExpr *RHSC = dyn_cast(BE.getRHS())) { if (RHSC->getValue() < 0) { OS << RHSC->getValue(); return; } } OS << '+'; break; case MCBinaryExpr::AShr: OS << ">>"; break; case MCBinaryExpr::And: OS << '&'; break; case MCBinaryExpr::Div: OS << '/'; break; case MCBinaryExpr::EQ: OS << "=="; break; case MCBinaryExpr::GT: OS << '>'; break; case MCBinaryExpr::GTE: OS << ">="; break; case MCBinaryExpr::LAnd: OS << "&&"; break; case MCBinaryExpr::LOr: OS << "||"; break; case MCBinaryExpr::LShr: OS << ">>"; break; case MCBinaryExpr::LT: OS << '<'; break; case MCBinaryExpr::LTE: OS << "<="; break; case MCBinaryExpr::Mod: OS << '%'; break; case MCBinaryExpr::Mul: OS << '*'; break; case MCBinaryExpr::NE: OS << "!="; break; case MCBinaryExpr::Or: OS << '|'; break; case MCBinaryExpr::Shl: OS << "<<"; break; case MCBinaryExpr::Sub: OS << '-'; break; case MCBinaryExpr::Xor: OS << '^'; break; } // Only print parens around the LHS if it is non-trivial. if (isa(BE.getRHS()) || isa(BE.getRHS())) { BE.getRHS()->print(OS, MAI); } else { OS << '('; BE.getRHS()->print(OS, MAI); OS << ')'; } return; } } llvm_unreachable("Invalid expression kind!"); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void MCExpr::dump() const { dbgs() << *this; dbgs() << '\n'; } #endif /* *** */ const MCBinaryExpr *MCBinaryExpr::create(Opcode Opc, const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc) { return new (Ctx) MCBinaryExpr(Opc, LHS, RHS, Loc); } const MCUnaryExpr *MCUnaryExpr::create(Opcode Opc, const MCExpr *Expr, MCContext &Ctx, SMLoc Loc) { return new (Ctx) MCUnaryExpr(Opc, Expr, Loc); } const MCConstantExpr *MCConstantExpr::create(int64_t Value, MCContext &Ctx) { return new (Ctx) MCConstantExpr(Value); } /* *** */ MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind, const MCAsmInfo *MAI, SMLoc Loc) : MCExpr(MCExpr::SymbolRef, Loc), Kind(Kind), UseParensForSymbolVariant(MAI->useParensForSymbolVariant()), HasSubsectionsViaSymbols(MAI->hasSubsectionsViaSymbols()), Symbol(Symbol) { assert(Symbol); } const MCSymbolRefExpr *MCSymbolRefExpr::create(const MCSymbol *Sym, VariantKind Kind, MCContext &Ctx, SMLoc Loc) { return new (Ctx) MCSymbolRefExpr(Sym, Kind, Ctx.getAsmInfo(), Loc); } const MCSymbolRefExpr *MCSymbolRefExpr::create(StringRef Name, VariantKind Kind, MCContext &Ctx) { return create(Ctx.getOrCreateSymbol(Name), Kind, Ctx); } StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { switch (Kind) { case VK_Invalid: return "<>"; case VK_None: return "<>"; case VK_DTPOFF: return "DTPOFF"; case VK_DTPREL: return "DTPREL"; case VK_GOT: return "GOT"; case VK_GOTOFF: return "GOTOFF"; case VK_GOTREL: return "GOTREL"; case VK_GOTPCREL: return "GOTPCREL"; case VK_GOTTPOFF: return "GOTTPOFF"; case VK_INDNTPOFF: return "INDNTPOFF"; case VK_NTPOFF: return "NTPOFF"; case VK_GOTNTPOFF: return "GOTNTPOFF"; case VK_PLT: return "PLT"; case VK_TLSGD: return "TLSGD"; case VK_TLSLD: return "TLSLD"; case VK_TLSLDM: return "TLSLDM"; case VK_TPOFF: return "TPOFF"; case VK_TPREL: return "TPREL"; case VK_TLSCALL: return "tlscall"; case VK_TLSDESC: return "tlsdesc"; case VK_TLVP: return "TLVP"; case VK_TLVPPAGE: return "TLVPPAGE"; case VK_TLVPPAGEOFF: return "TLVPPAGEOFF"; case VK_PAGE: return "PAGE"; case VK_PAGEOFF: return "PAGEOFF"; case VK_GOTPAGE: return "GOTPAGE"; case VK_GOTPAGEOFF: return "GOTPAGEOFF"; case VK_SECREL: return "SECREL32"; case VK_SIZE: return "SIZE"; case VK_WEAKREF: return "WEAKREF"; case VK_X86_ABS8: return "ABS8"; case VK_ARM_NONE: return "none"; case VK_ARM_GOT_PREL: return "GOT_PREL"; case VK_ARM_TARGET1: return "target1"; case VK_ARM_TARGET2: return "target2"; case VK_ARM_PREL31: return "prel31"; case VK_ARM_SBREL: return "sbrel"; case VK_ARM_TLSLDO: return "tlsldo"; case VK_ARM_TLSDESCSEQ: return "tlsdescseq"; case VK_AVR_NONE: return "none"; case VK_AVR_LO8: return "lo8"; case VK_AVR_HI8: return "hi8"; case VK_AVR_HLO8: return "hlo8"; case VK_AVR_DIFF8: return "diff8"; case VK_AVR_DIFF16: return "diff16"; case VK_AVR_DIFF32: return "diff32"; case VK_PPC_LO: return "l"; case VK_PPC_HI: return "h"; case VK_PPC_HA: return "ha"; case VK_PPC_HIGH: return "high"; case VK_PPC_HIGHA: return "higha"; case VK_PPC_HIGHER: return "higher"; case VK_PPC_HIGHERA: return "highera"; case VK_PPC_HIGHEST: return "highest"; case VK_PPC_HIGHESTA: return "highesta"; case VK_PPC_GOT_LO: return "got@l"; case VK_PPC_GOT_HI: return "got@h"; case VK_PPC_GOT_HA: return "got@ha"; case VK_PPC_TOCBASE: return "tocbase"; case VK_PPC_TOC: return "toc"; case VK_PPC_TOC_LO: return "toc@l"; case VK_PPC_TOC_HI: return "toc@h"; case VK_PPC_TOC_HA: return "toc@ha"; case VK_PPC_DTPMOD: return "dtpmod"; case VK_PPC_TPREL_LO: return "tprel@l"; case VK_PPC_TPREL_HI: return "tprel@h"; case VK_PPC_TPREL_HA: return "tprel@ha"; case VK_PPC_TPREL_HIGH: return "tprel@high"; case VK_PPC_TPREL_HIGHA: return "tprel@higha"; case VK_PPC_TPREL_HIGHER: return "tprel@higher"; case VK_PPC_TPREL_HIGHERA: return "tprel@highera"; case VK_PPC_TPREL_HIGHEST: return "tprel@highest"; case VK_PPC_TPREL_HIGHESTA: return "tprel@highesta"; case VK_PPC_DTPREL_LO: return "dtprel@l"; case VK_PPC_DTPREL_HI: return "dtprel@h"; case VK_PPC_DTPREL_HA: return "dtprel@ha"; case VK_PPC_DTPREL_HIGH: return "dtprel@high"; case VK_PPC_DTPREL_HIGHA: return "dtprel@higha"; case VK_PPC_DTPREL_HIGHER: return "dtprel@higher"; case VK_PPC_DTPREL_HIGHERA: return "dtprel@highera"; case VK_PPC_DTPREL_HIGHEST: return "dtprel@highest"; case VK_PPC_DTPREL_HIGHESTA: return "dtprel@highesta"; case VK_PPC_GOT_TPREL: return "got@tprel"; case VK_PPC_GOT_TPREL_LO: return "got@tprel@l"; case VK_PPC_GOT_TPREL_HI: return "got@tprel@h"; case VK_PPC_GOT_TPREL_HA: return "got@tprel@ha"; case VK_PPC_GOT_DTPREL: return "got@dtprel"; case VK_PPC_GOT_DTPREL_LO: return "got@dtprel@l"; case VK_PPC_GOT_DTPREL_HI: return "got@dtprel@h"; case VK_PPC_GOT_DTPREL_HA: return "got@dtprel@ha"; case VK_PPC_TLS: return "tls"; case VK_PPC_GOT_TLSGD: return "got@tlsgd"; case VK_PPC_GOT_TLSGD_LO: return "got@tlsgd@l"; case VK_PPC_GOT_TLSGD_HI: return "got@tlsgd@h"; case VK_PPC_GOT_TLSGD_HA: return "got@tlsgd@ha"; case VK_PPC_TLSGD: return "tlsgd"; case VK_PPC_GOT_TLSLD: return "got@tlsld"; case VK_PPC_GOT_TLSLD_LO: return "got@tlsld@l"; case VK_PPC_GOT_TLSLD_HI: return "got@tlsld@h"; case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha"; case VK_PPC_TLSLD: return "tlsld"; case VK_PPC_LOCAL: return "local"; case VK_COFF_IMGREL32: return "IMGREL"; case VK_Hexagon_PCREL: return "PCREL"; case VK_Hexagon_LO16: return "LO16"; case VK_Hexagon_HI16: return "HI16"; case VK_Hexagon_GPREL: return "GPREL"; case VK_Hexagon_GD_GOT: return "GDGOT"; case VK_Hexagon_LD_GOT: return "LDGOT"; case VK_Hexagon_GD_PLT: return "GDPLT"; case VK_Hexagon_LD_PLT: return "LDPLT"; case VK_Hexagon_IE: return "IE"; case VK_Hexagon_IE_GOT: return "IEGOT"; case VK_WebAssembly_FUNCTION: return "FUNCTION"; case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX"; case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo"; case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi"; case VK_AMDGPU_REL32_LO: return "rel32@lo"; case VK_AMDGPU_REL32_HI: return "rel32@hi"; case VK_AMDGPU_REL64: return "rel64"; } llvm_unreachable("Invalid variant kind"); } MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch(Name.lower()) .Case("dtprel", VK_DTPREL) .Case("dtpoff", VK_DTPOFF) .Case("got", VK_GOT) .Case("gotoff", VK_GOTOFF) .Case("gotrel", VK_GOTREL) .Case("gotpcrel", VK_GOTPCREL) .Case("gottpoff", VK_GOTTPOFF) .Case("indntpoff", VK_INDNTPOFF) .Case("ntpoff", VK_NTPOFF) .Case("gotntpoff", VK_GOTNTPOFF) .Case("plt", VK_PLT) .Case("tlscall", VK_TLSCALL) .Case("tlsdesc", VK_TLSDESC) .Case("tlsgd", VK_TLSGD) .Case("tlsld", VK_TLSLD) .Case("tlsldm", VK_TLSLDM) .Case("tpoff", VK_TPOFF) .Case("tprel", VK_TPREL) .Case("tlvp", VK_TLVP) .Case("tlvppage", VK_TLVPPAGE) .Case("tlvppageoff", VK_TLVPPAGEOFF) .Case("page", VK_PAGE) .Case("pageoff", VK_PAGEOFF) .Case("gotpage", VK_GOTPAGE) .Case("gotpageoff", VK_GOTPAGEOFF) .Case("imgrel", VK_COFF_IMGREL32) .Case("secrel32", VK_SECREL) .Case("size", VK_SIZE) .Case("abs8", VK_X86_ABS8) .Case("l", VK_PPC_LO) .Case("h", VK_PPC_HI) .Case("ha", VK_PPC_HA) .Case("high", VK_PPC_HIGH) .Case("higha", VK_PPC_HIGHA) .Case("higher", VK_PPC_HIGHER) .Case("highera", VK_PPC_HIGHERA) .Case("highest", VK_PPC_HIGHEST) .Case("highesta", VK_PPC_HIGHESTA) .Case("got@l", VK_PPC_GOT_LO) .Case("got@h", VK_PPC_GOT_HI) .Case("got@ha", VK_PPC_GOT_HA) .Case("local", VK_PPC_LOCAL) .Case("tocbase", VK_PPC_TOCBASE) .Case("toc", VK_PPC_TOC) .Case("toc@l", VK_PPC_TOC_LO) .Case("toc@h", VK_PPC_TOC_HI) .Case("toc@ha", VK_PPC_TOC_HA) .Case("tls", VK_PPC_TLS) .Case("dtpmod", VK_PPC_DTPMOD) .Case("tprel@l", VK_PPC_TPREL_LO) .Case("tprel@h", VK_PPC_TPREL_HI) .Case("tprel@ha", VK_PPC_TPREL_HA) .Case("tprel@high", VK_PPC_TPREL_HIGH) .Case("tprel@higha", VK_PPC_TPREL_HIGHA) .Case("tprel@higher", VK_PPC_TPREL_HIGHER) .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) .Case("dtprel@l", VK_PPC_DTPREL_LO) .Case("dtprel@h", VK_PPC_DTPREL_HI) .Case("dtprel@ha", VK_PPC_DTPREL_HA) .Case("dtprel@high", VK_PPC_DTPREL_HIGH) .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) .Case("got@tprel", VK_PPC_GOT_TPREL) .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) .Case("got@dtprel", VK_PPC_GOT_DTPREL) .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) .Case("got@tlsgd", VK_PPC_GOT_TLSGD) .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) .Case("got@tlsld", VK_PPC_GOT_TLSLD) .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) .Case("gdgot", VK_Hexagon_GD_GOT) .Case("gdplt", VK_Hexagon_GD_PLT) .Case("iegot", VK_Hexagon_IE_GOT) .Case("ie", VK_Hexagon_IE) .Case("ldgot", VK_Hexagon_LD_GOT) .Case("ldplt", VK_Hexagon_LD_PLT) .Case("pcrel", VK_Hexagon_PCREL) .Case("none", VK_ARM_NONE) .Case("got_prel", VK_ARM_GOT_PREL) .Case("target1", VK_ARM_TARGET1) .Case("target2", VK_ARM_TARGET2) .Case("prel31", VK_ARM_PREL31) .Case("sbrel", VK_ARM_SBREL) .Case("tlsldo", VK_ARM_TLSLDO) .Case("lo8", VK_AVR_LO8) .Case("hi8", VK_AVR_HI8) .Case("hlo8", VK_AVR_HLO8) .Case("function", VK_WebAssembly_FUNCTION) .Case("typeindex", VK_WebAssembly_TYPEINDEX) .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) .Case("rel32@lo", VK_AMDGPU_REL32_LO) .Case("rel32@hi", VK_AMDGPU_REL32_HI) .Case("rel64", VK_AMDGPU_REL64) .Default(VK_Invalid); } void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const { if (UseParensForSymbolVariant) OS << '(' << MCSymbolRefExpr::getVariantKindName(getKind()) << ')'; else OS << '@' << MCSymbolRefExpr::getVariantKindName(getKind()); } /* *** */ void MCTargetExpr::anchor() {} /* *** */ bool MCExpr::evaluateAsAbsolute(int64_t &Res) const { return evaluateAsAbsolute(Res, nullptr, nullptr, nullptr); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const { return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout, const SectionAddrMap &Addrs) const { return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { return evaluateAsAbsolute(Res, Asm, nullptr, nullptr); } bool MCExpr::evaluateKnownAbsolute(int64_t &Res, const MCAsmLayout &Layout) const { return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, true); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs) const { // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us // absolutize differences across sections and that is what the MachO writer // uses Addrs for. return evaluateAsAbsolute(Res, Asm, Layout, Addrs, Addrs); } bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet) const { MCValue Value; // Fast path constants. if (const MCConstantExpr *CE = dyn_cast(this)) { Res = CE->getValue(); return true; } bool IsRelocatable = evaluateAsRelocatableImpl(Value, Asm, Layout, nullptr, Addrs, InSet); // Record the current value. Res = Value.getConstant(); return IsRelocatable && Value.isAbsolute(); } /// Helper method for \see EvaluateSymbolAdd(). static void AttemptToFoldSymbolOffsetDifference( const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet, const MCSymbolRefExpr *&A, const MCSymbolRefExpr *&B, int64_t &Addend) { if (!A || !B) return; const MCSymbol &SA = A->getSymbol(); const MCSymbol &SB = B->getSymbol(); if (SA.isUndefined() || SB.isUndefined()) return; if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) return; if (SA.getFragment() == SB.getFragment() && !SA.isVariable() && !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) { Addend += (SA.getOffset() - SB.getOffset()); // Pointers to Thumb symbols need to have their low-bit set to allow // for interworking. if (Asm->isThumbFunc(&SA)) Addend |= 1; // Clear the symbol expr pointers to indicate we have folded these // operands. A = B = nullptr; return; } if (!Layout) return; const MCSection &SecA = *SA.getFragment()->getParent(); const MCSection &SecB = *SB.getFragment()->getParent(); if ((&SecA != &SecB) && !Addrs) return; // Eagerly evaluate. Addend += Layout->getSymbolOffset(A->getSymbol()) - Layout->getSymbolOffset(B->getSymbol()); if (Addrs && (&SecA != &SecB)) Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB)); // Pointers to Thumb symbols need to have their low-bit set to allow // for interworking. if (Asm->isThumbFunc(&SA)) Addend |= 1; // Clear the symbol expr pointers to indicate we have folded these // operands. A = B = nullptr; } /// Evaluate the result of an add between (conceptually) two MCValues. /// /// This routine conceptually attempts to construct an MCValue: /// Result = (Result_A - Result_B + Result_Cst) /// from two MCValue's LHS and RHS where /// Result = LHS + RHS /// and /// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). /// /// This routine attempts to aggresively fold the operands such that the result /// is representable in an MCValue, but may not always succeed. /// /// \returns True on success, false if the result is not representable in an /// MCValue. /// NOTE: It is really important to have both the Asm and Layout arguments. /// They might look redundant, but this function can be used before layout /// is done (see the object streamer for example) and having the Asm argument /// lets us avoid relaxations early. static bool EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout, const SectionAddrMap *Addrs, bool InSet, const MCValue &LHS, const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy // about dealing with modifiers. This will ultimately bite us, one day. const MCSymbolRefExpr *LHS_A = LHS.getSymA(); const MCSymbolRefExpr *LHS_B = LHS.getSymB(); int64_t LHS_Cst = LHS.getConstant(); // Fold the result constant immediately. int64_t Result_Cst = LHS_Cst + RHS_Cst; assert((!Layout || Asm) && "Must have an assembler object if layout is given!"); // If we have a layout, we can fold resolved differences. Do not do this if // the backend requires this to be emitted as individual relocations, unless // the InSet flag is set to get the current difference anyway (used for // example to calculate symbol sizes). if (Asm && (InSet || !Asm->getBackend().requiresDiffExpressionRelocations())) { // First, fold out any differences which are fully resolved. By // reassociating terms in // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). // we have the four possible differences: // (LHS_A - LHS_B), // (LHS_A - RHS_B), // (RHS_A - LHS_B), // (RHS_A - RHS_B). // Since we are attempting to be as aggressive as possible about folding, we // attempt to evaluate each possible alternative. AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B, Result_Cst); AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B, Result_Cst); } // We can't represent the addition or subtraction of two symbols. if ((LHS_A && RHS_A) || (LHS_B && RHS_B)) return false; // At this point, we have at most one additive symbol and one subtractive // symbol -- find them. const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A; const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B; Res = MCValue::get(A, B, Result_Cst); return true; } bool MCExpr::evaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr; return evaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr, false); } bool MCExpr::evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const { MCAssembler *Assembler = &Layout.getAssembler(); return evaluateAsRelocatableImpl(Res, Assembler, &Layout, nullptr, nullptr, true); } static bool canExpand(const MCSymbol &Sym, bool InSet) { const MCExpr *Expr = Sym.getVariableValue(); const auto *Inner = dyn_cast(Expr); if (Inner) { if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) return false; } if (InSet) return true; return !Sym.isInSection(); } bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, const MCAsmLayout *Layout, const MCFixup *Fixup, const SectionAddrMap *Addrs, bool InSet) const { ++stats::MCExprEvaluate; switch (getKind()) { case Target: return cast(this)->evaluateAsRelocatableImpl(Res, Layout, Fixup); case Constant: Res = MCValue::get(cast(this)->getValue()); return true; case SymbolRef: { const MCSymbolRefExpr *SRE = cast(this); const MCSymbol &Sym = SRE->getSymbol(); // Evaluate recursively if this is a variable. if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None && canExpand(Sym, InSet)) { bool IsMachO = SRE->hasSubsectionsViaSymbols(); if (Sym.getVariableValue()->evaluateAsRelocatableImpl( Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO)) { if (!IsMachO) return true; const MCSymbolRefExpr *A = Res.getSymA(); const MCSymbolRefExpr *B = Res.getSymB(); // FIXME: This is small hack. Given // a = b + 4 // .long a // the OS X assembler will completely drop the 4. We should probably // include it in the relocation or produce an error if that is not // possible. // Allow constant expressions. if (!A && !B) return true; // Allows aliases with zero offset. if (Res.getConstant() == 0 && (!A || !B)) return true; } } Res = MCValue::get(SRE, nullptr, 0); return true; } case Unary: { const MCUnaryExpr *AUE = cast(this); MCValue Value; if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, Layout, Fixup, Addrs, InSet)) return false; switch (AUE->getOpcode()) { case MCUnaryExpr::LNot: if (!Value.isAbsolute()) return false; Res = MCValue::get(!Value.getConstant()); break; case MCUnaryExpr::Minus: /// -(a - b + const) ==> (b - a - const) if (Value.getSymA() && !Value.getSymB()) return false; // The cast avoids undefined behavior if the constant is INT64_MIN. Res = MCValue::get(Value.getSymB(), Value.getSymA(), -(uint64_t)Value.getConstant()); break; case MCUnaryExpr::Not: if (!Value.isAbsolute()) return false; Res = MCValue::get(~Value.getConstant()); break; case MCUnaryExpr::Plus: Res = Value; break; } return true; } case Binary: { const MCBinaryExpr *ABE = cast(this); MCValue LHSValue, RHSValue; if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup, Addrs, InSet) || !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup, - Addrs, InSet)) + Addrs, InSet)) { + // Check if both are Target Expressions, see if we can compare them. + if (const MCTargetExpr *L = dyn_cast(ABE->getLHS())) + if (const MCTargetExpr *R = cast(ABE->getRHS())) { + switch (ABE->getOpcode()) { + case MCBinaryExpr::EQ: + Res = MCValue::get((L->isEqualTo(R)) ? -1 : 0); + return true; + case MCBinaryExpr::NE: + Res = MCValue::get((R->isEqualTo(R)) ? 0 : -1); + return true; + default: {} + } + } return false; + } // We only support a few operations on non-constant expressions, handle // those first. if (!LHSValue.isAbsolute() || !RHSValue.isAbsolute()) { switch (ABE->getOpcode()) { default: return false; case MCBinaryExpr::Sub: // Negate RHS and add. // The cast avoids undefined behavior if the constant is INT64_MIN. return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymB(), RHSValue.getSymA(), -(uint64_t)RHSValue.getConstant(), Res); case MCBinaryExpr::Add: return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymA(), RHSValue.getSymB(), RHSValue.getConstant(), Res); } } // FIXME: We need target hooks for the evaluation. It may be limited in // width, and gas defines the result of comparisons differently from // Apple as. int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant(); int64_t Result = 0; auto Op = ABE->getOpcode(); switch (Op) { case MCBinaryExpr::AShr: Result = LHS >> RHS; break; case MCBinaryExpr::Add: Result = LHS + RHS; break; case MCBinaryExpr::And: Result = LHS & RHS; break; case MCBinaryExpr::Div: case MCBinaryExpr::Mod: // Handle division by zero. gas just emits a warning and keeps going, // we try to be stricter. // FIXME: Currently the caller of this function has no way to understand // we're bailing out because of 'division by zero'. Therefore, it will // emit a 'expected relocatable expression' error. It would be nice to // change this code to emit a better diagnostic. if (RHS == 0) return false; if (ABE->getOpcode() == MCBinaryExpr::Div) Result = LHS / RHS; else Result = LHS % RHS; break; case MCBinaryExpr::EQ: Result = LHS == RHS; break; case MCBinaryExpr::GT: Result = LHS > RHS; break; case MCBinaryExpr::GTE: Result = LHS >= RHS; break; case MCBinaryExpr::LAnd: Result = LHS && RHS; break; case MCBinaryExpr::LOr: Result = LHS || RHS; break; case MCBinaryExpr::LShr: Result = uint64_t(LHS) >> uint64_t(RHS); break; case MCBinaryExpr::LT: Result = LHS < RHS; break; case MCBinaryExpr::LTE: Result = LHS <= RHS; break; case MCBinaryExpr::Mul: Result = LHS * RHS; break; case MCBinaryExpr::NE: Result = LHS != RHS; break; case MCBinaryExpr::Or: Result = LHS | RHS; break; case MCBinaryExpr::Shl: Result = uint64_t(LHS) << uint64_t(RHS); break; case MCBinaryExpr::Sub: Result = LHS - RHS; break; case MCBinaryExpr::Xor: Result = LHS ^ RHS; break; } switch (Op) { default: Res = MCValue::get(Result); break; case MCBinaryExpr::EQ: case MCBinaryExpr::GT: case MCBinaryExpr::GTE: case MCBinaryExpr::LT: case MCBinaryExpr::LTE: case MCBinaryExpr::NE: // A comparison operator returns a -1 if true and 0 if false. Res = MCValue::get(Result ? -1 : 0); break; } return true; } } llvm_unreachable("Invalid assembly expression kind!"); } MCFragment *MCExpr::findAssociatedFragment() const { switch (getKind()) { case Target: // We never look through target specific expressions. return cast(this)->findAssociatedFragment(); case Constant: return MCSymbol::AbsolutePseudoFragment; case SymbolRef: { const MCSymbolRefExpr *SRE = cast(this); const MCSymbol &Sym = SRE->getSymbol(); return Sym.getFragment(); } case Unary: return cast(this)->getSubExpr()->findAssociatedFragment(); case Binary: { const MCBinaryExpr *BE = cast(this); MCFragment *LHS_F = BE->getLHS()->findAssociatedFragment(); MCFragment *RHS_F = BE->getRHS()->findAssociatedFragment(); // If either is absolute, return the other. if (LHS_F == MCSymbol::AbsolutePseudoFragment) return RHS_F; if (RHS_F == MCSymbol::AbsolutePseudoFragment) return LHS_F; // Not always correct, but probably the best we can do without more context. if (BE->getOpcode() == MCBinaryExpr::Sub) return MCSymbol::AbsolutePseudoFragment; // Otherwise, return the first non-null fragment. return LHS_F ? LHS_F : RHS_F; } } llvm_unreachable("Invalid assembly expression kind!"); } Index: vendor/llvm/dist-release_70/lib/MC/MCParser/AsmParser.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/MC/MCParser/AsmParser.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/MC/MCParser/AsmParser.cpp (revision 338378) @@ -1,5903 +1,5899 @@ //===- AsmParser.cpp - Parser for Assembly Files --------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class implements the parser for assembly files. // //===----------------------------------------------------------------------===// #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/AsmCond.h" #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCAsmParserExtension.h" #include "llvm/MC/MCParser/MCAsmParserUtils.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace llvm; MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default; static cl::opt AsmMacroMaxNestingDepth( "asm-macro-max-nesting-depth", cl::init(20), cl::Hidden, cl::desc("The maximum nesting depth allowed for assembly macros.")); namespace { /// Helper types for tracking macro definitions. typedef std::vector MCAsmMacroArgument; typedef std::vector MCAsmMacroArguments; /// Helper class for storing information about an active macro /// instantiation. struct MacroInstantiation { /// The location of the instantiation. SMLoc InstantiationLoc; /// The buffer where parsing should resume upon instantiation completion. int ExitBuffer; /// The location where parsing should resume upon instantiation completion. SMLoc ExitLoc; /// The depth of TheCondStack at the start of the instantiation. size_t CondStackDepth; public: MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth); }; struct ParseStatementInfo { /// The parsed operands from the last parsed statement. SmallVector, 8> ParsedOperands; /// The opcode from the last parsed instruction. unsigned Opcode = ~0U; /// Was there an error parsing the inline assembly? bool ParseError = false; SmallVectorImpl *AsmRewrites = nullptr; ParseStatementInfo() = delete; ParseStatementInfo(SmallVectorImpl *rewrites) : AsmRewrites(rewrites) {} }; /// The concrete assembly parser instance. class AsmParser : public MCAsmParser { private: AsmLexer Lexer; MCContext &Ctx; MCStreamer &Out; const MCAsmInfo &MAI; SourceMgr &SrcMgr; SourceMgr::DiagHandlerTy SavedDiagHandler; void *SavedDiagContext; std::unique_ptr PlatformParser; /// This is the current buffer index we're lexing from as managed by the /// SourceMgr object. unsigned CurBuffer; AsmCond TheCondState; std::vector TheCondStack; /// maps directive names to handler methods in parser /// extensions. Extensions register themselves in this map by calling /// addDirectiveHandler. StringMap ExtensionDirectiveMap; /// Stack of active macro instantiations. std::vector ActiveMacros; /// List of bodies of anonymous macros. std::deque MacroLikeBodies; /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabledFlag : 1; /// Keeps track of how many .macro's have been instantiated. unsigned NumOfMacroInstantiations; /// The values from the last parsed cpp hash file line comment if any. struct CppHashInfoTy { StringRef Filename; int64_t LineNumber = 0; SMLoc Loc; unsigned Buf = 0; }; CppHashInfoTy CppHashInfo; /// List of forward directional labels for diagnosis at the end. SmallVector, 4> DirLabels; /// AssemblerDialect. ~OU means unset value and use value provided by MAI. unsigned AssemblerDialect = ~0U; /// is Darwin compatibility enabled? bool IsDarwin = false; /// Are we parsing ms-style inline assembly? bool ParsingInlineAsm = false; /// Did we already inform the user about inconsistent MD5 usage? bool ReportedInconsistentMD5 = false; public: AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB); AsmParser(const AsmParser &) = delete; AsmParser &operator=(const AsmParser &) = delete; ~AsmParser() override; bool Run(bool NoInitialTextSection, bool NoFinalize = false) override; void addDirectiveHandler(StringRef Directive, ExtensionDirectiveHandler Handler) override { ExtensionDirectiveMap[Directive] = Handler; } void addAliasForDirective(StringRef Directive, StringRef Alias) override { DirectiveKindMap[Directive] = DirectiveKindMap[Alias]; } /// @name MCAsmParser Interface /// { SourceMgr &getSourceManager() override { return SrcMgr; } MCAsmLexer &getLexer() override { return Lexer; } MCContext &getContext() override { return Ctx; } MCStreamer &getStreamer() override { return Out; } CodeViewContext &getCVContext() { return Ctx.getCVContext(); } unsigned getAssemblerDialect() override { if (AssemblerDialect == ~0U) return MAI.getAssemblerDialect(); else return AssemblerDialect; } void setAssemblerDialect(unsigned i) override { AssemblerDialect = i; } void Note(SMLoc L, const Twine &Msg, SMRange Range = None) override; bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) override; bool printError(SMLoc L, const Twine &Msg, SMRange Range = None) override; const AsmToken &Lex() override; void setParsingInlineAsm(bool V) override { ParsingInlineAsm = V; Lexer.setParsingMSInlineAsm(V); } bool isParsingInlineAsm() override { return ParsingInlineAsm; } bool parseMSInlineAsm(void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, SmallVectorImpl> &OpDecls, SmallVectorImpl &Constraints, SmallVectorImpl &Clobbers, const MCInstrInfo *MII, const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) override; bool parseExpression(const MCExpr *&Res); bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override; bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override; bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override; bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res, SMLoc &EndLoc) override; bool parseAbsoluteExpression(int64_t &Res) override; /// Parse a floating point expression using the float \p Semantics /// and set \p Res to the value. bool parseRealValue(const fltSemantics &Semantics, APInt &Res); /// Parse an identifier or string (as a quoted identifier) /// and set \p Res to the identifier contents. bool parseIdentifier(StringRef &Res) override; void eatToEndOfStatement() override; bool checkForValidSection() override; /// } private: bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc); void altMacroString(StringRef AltMacroStr, std::string &Res); bool parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI); bool parseCurlyBlockScope(SmallVectorImpl& AsmStrRewrites); bool parseCppHashLineFilenameComment(SMLoc L); void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body, ArrayRef Parameters); bool expandMacro(raw_svector_ostream &OS, StringRef Body, ArrayRef Parameters, ArrayRef A, bool EnableAtPseudoVariable, SMLoc L); /// Are macros enabled in the parser? bool areMacrosEnabled() {return MacrosEnabledFlag;} /// Control a flag in the parser that enables or disables macros. void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;} /// Are we inside a macro instantiation? bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} /// Handle entry to macro instantiation. /// /// \param M The macro. /// \param NameLoc Instantiation location. bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc); /// Handle exit from macro instantiation. void handleMacroExit(); /// Extract AsmTokens for a macro argument. bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg); /// Parse all macro arguments for a given macro. bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A); void printMacroInstantiations(); void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg, SMRange Range = None) const { ArrayRef Ranges(Range); SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); } static void DiagHandler(const SMDiagnostic &Diag, void *Context); /// Should we emit DWARF describing this assembler source? (Returns false if /// the source has .file directives, which means we don't want to generate /// info describing the assembler source itself.) bool enabledGenDwarfForAssembly(); /// Enter the specified file. This returns true on failure. bool enterIncludeFile(const std::string &Filename); /// Process the specified file for the .incbin directive. /// This returns true on failure. bool processIncbinFile(const std::string &Filename, int64_t Skip = 0, const MCExpr *Count = nullptr, SMLoc Loc = SMLoc()); /// Reset the current lexer position to that given by \p Loc. The /// current token is not set; clients should ensure Lex() is called /// subsequently. /// /// \param InBuffer If not 0, should be the known buffer id that contains the /// location. void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0); /// Parse up to the end of statement and a return the contents from the /// current token until the end of the statement; the current token on exit /// will be either the EndOfStatement or EOF. StringRef parseStringToEndOfStatement() override; /// Parse until the end of a statement or a comma is encountered, /// return the contents from the current token up to the end or comma. StringRef parseStringToComma(); bool parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip = false, bool AllowExtendedExpr = false); + bool NoDeadStrip = false); unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind); bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc); bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc); bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName); bool parseCVFileId(int64_t &FileId, StringRef DirectiveName); // Generic (target and platform independent) directive parsing. enum DirectiveKind { DK_NO_DIRECTIVE, // Placeholder DK_SET, DK_EQU, DK_EQUIV, DK_ASCII, DK_ASCIZ, DK_STRING, DK_BYTE, DK_SHORT, DK_RELOC, DK_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, DK_OCTA, DK_DC, DK_DC_A, DK_DC_B, DK_DC_D, DK_DC_L, DK_DC_S, DK_DC_W, DK_DC_X, DK_DCB, DK_DCB_B, DK_DCB_D, DK_DCB_L, DK_DCB_S, DK_DCB_W, DK_DCB_X, DK_DS, DK_DS_B, DK_DS_D, DK_DS_L, DK_DS_P, DK_DS_S, DK_DS_W, DK_DS_X, DK_SINGLE, DK_FLOAT, DK_DOUBLE, DK_ALIGN, DK_ALIGN32, DK_BALIGN, DK_BALIGNW, DK_BALIGNL, DK_P2ALIGN, DK_P2ALIGNW, DK_P2ALIGNL, DK_ORG, DK_FILL, DK_ENDR, DK_BUNDLE_ALIGN_MODE, DK_BUNDLE_LOCK, DK_BUNDLE_UNLOCK, DK_ZERO, DK_EXTERN, DK_GLOBL, DK_GLOBAL, DK_LAZY_REFERENCE, DK_NO_DEAD_STRIP, DK_SYMBOL_RESOLVER, DK_PRIVATE_EXTERN, DK_REFERENCE, DK_WEAK_DEFINITION, DK_WEAK_REFERENCE, DK_WEAK_DEF_CAN_BE_HIDDEN, DK_COMM, DK_COMMON, DK_LCOMM, DK_ABORT, DK_INCLUDE, DK_INCBIN, DK_CODE16, DK_CODE16GCC, DK_REPT, DK_IRP, DK_IRPC, DK_IF, DK_IFEQ, DK_IFGE, DK_IFGT, DK_IFLE, DK_IFLT, DK_IFNE, DK_IFB, DK_IFNB, DK_IFC, DK_IFEQS, DK_IFNC, DK_IFNES, DK_IFDEF, DK_IFNDEF, DK_IFNOTDEF, DK_ELSEIF, DK_ELSE, DK_ENDIF, DK_SPACE, DK_SKIP, DK_FILE, DK_LINE, DK_LOC, DK_STABS, DK_CV_FILE, DK_CV_FUNC_ID, DK_CV_INLINE_SITE_ID, DK_CV_LOC, DK_CV_LINETABLE, DK_CV_INLINE_LINETABLE, DK_CV_DEF_RANGE, DK_CV_STRINGTABLE, DK_CV_FILECHECKSUMS, DK_CV_FILECHECKSUM_OFFSET, DK_CV_FPO_DATA, DK_CFI_SECTIONS, DK_CFI_STARTPROC, DK_CFI_ENDPROC, DK_CFI_DEF_CFA, DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER, DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, DK_CFI_LSDA, DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE, DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_RETURN_COLUMN, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED, DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, DK_NOALTMACRO, DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM, DK_SLEB128, DK_ULEB128, DK_ERR, DK_ERROR, DK_WARNING, DK_PRINT, DK_ADDRSIG, DK_ADDRSIG_SYM, DK_END }; /// Maps directive name --> DirectiveKind enum, for /// directives parsed by this class. StringMap DirectiveKindMap; // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc" bool parseDirectiveValue(StringRef IDVal, unsigned Size); // ".byte", ".long", ... bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ... bool parseDirectiveRealValue(StringRef IDVal, const fltSemantics &); // ".single", ... bool parseDirectiveFill(); // ".fill" bool parseDirectiveZero(); // ".zero" // ".set", ".equ", ".equiv" bool parseDirectiveSet(StringRef IDVal, bool allow_redef); bool parseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize); // ".file", ".line", ".loc", ".stabs" bool parseDirectiveFile(SMLoc DirectiveLoc); bool parseDirectiveLine(); bool parseDirectiveLoc(); bool parseDirectiveStabs(); // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable", // ".cv_inline_linetable", ".cv_def_range" bool parseDirectiveCVFile(); bool parseDirectiveCVFuncId(); bool parseDirectiveCVInlineSiteId(); bool parseDirectiveCVLoc(); bool parseDirectiveCVLinetable(); bool parseDirectiveCVInlineLinetable(); bool parseDirectiveCVDefRange(); bool parseDirectiveCVStringTable(); bool parseDirectiveCVFileChecksums(); bool parseDirectiveCVFileChecksumOffset(); bool parseDirectiveCVFPOData(); // .cfi directives bool parseDirectiveCFIRegister(SMLoc DirectiveLoc); bool parseDirectiveCFIWindowSave(); bool parseDirectiveCFISections(); bool parseDirectiveCFIStartProc(); bool parseDirectiveCFIEndProc(); bool parseDirectiveCFIDefCfaOffset(); bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc); bool parseDirectiveCFIAdjustCfaOffset(); bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc); bool parseDirectiveCFIOffset(SMLoc DirectiveLoc); bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc); bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality); bool parseDirectiveCFIRememberState(); bool parseDirectiveCFIRestoreState(); bool parseDirectiveCFISameValue(SMLoc DirectiveLoc); bool parseDirectiveCFIRestore(SMLoc DirectiveLoc); bool parseDirectiveCFIEscape(); bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc); bool parseDirectiveCFISignalFrame(); bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc); // macro directives bool parseDirectivePurgeMacro(SMLoc DirectiveLoc); bool parseDirectiveExitMacro(StringRef Directive); bool parseDirectiveEndMacro(StringRef Directive); bool parseDirectiveMacro(SMLoc DirectiveLoc); bool parseDirectiveMacrosOnOff(StringRef Directive); // alternate macro mode directives bool parseDirectiveAltmacro(StringRef Directive); // ".bundle_align_mode" bool parseDirectiveBundleAlignMode(); // ".bundle_lock" bool parseDirectiveBundleLock(); // ".bundle_unlock" bool parseDirectiveBundleUnlock(); // ".space", ".skip" bool parseDirectiveSpace(StringRef IDVal); // ".dcb" bool parseDirectiveDCB(StringRef IDVal, unsigned Size); bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &); // ".ds" bool parseDirectiveDS(StringRef IDVal, unsigned Size); // .sleb128 (Signed=true) and .uleb128 (Signed=false) bool parseDirectiveLEB128(bool Signed); /// Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr); bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm" bool parseDirectiveAbort(); // ".abort" bool parseDirectiveInclude(); // ".include" bool parseDirectiveIncbin(); // ".incbin" // ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne" bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind); // ".ifb" or ".ifnb", depending on ExpectBlank. bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank); // ".ifc" or ".ifnc", depending on ExpectEqual. bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual); // ".ifeqs" or ".ifnes", depending on ExpectEqual. bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual); // ".ifdef" or ".ifndef", depending on expect_defined bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else" bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif bool parseEscapedString(std::string &Data) override; const MCExpr *applyModifierToExpr(const MCExpr *E, MCSymbolRefExpr::VariantKind Variant); // Macro-like directives MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc); void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, raw_svector_ostream &OS); bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive); bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp" bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc" bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr" // "_emit" or "__emit" bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info, size_t Len); // "align" bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info); // "end" bool parseDirectiveEnd(SMLoc DirectiveLoc); // ".err" or ".error" bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage); // ".warning" bool parseDirectiveWarning(SMLoc DirectiveLoc); // .print bool parseDirectivePrint(SMLoc DirectiveLoc); // Directives to support address-significance tables. bool parseDirectiveAddrsig(); bool parseDirectiveAddrsigSym(); void initializeDirectiveKindMap(); }; } // end anonymous namespace namespace llvm { extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); extern MCAsmParserExtension *createCOFFAsmParser(); } // end namespace llvm enum { DEFAULT_ADDRSPACE = 0 }; AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB = 0) : Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM), CurBuffer(CB ? CB : SM.getMainFileID()), MacrosEnabledFlag(true) { HadError = false; // Save the old handler. SavedDiagHandler = SrcMgr.getDiagHandler(); SavedDiagContext = SrcMgr.getDiagContext(); // Set our own handler which calls the saved handler. SrcMgr.setDiagHandler(DiagHandler, this); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); // Initialize the platform / file format parser. switch (Ctx.getObjectFileInfo()->getObjectFileType()) { case MCObjectFileInfo::IsCOFF: PlatformParser.reset(createCOFFAsmParser()); break; case MCObjectFileInfo::IsMachO: PlatformParser.reset(createDarwinAsmParser()); IsDarwin = true; break; case MCObjectFileInfo::IsELF: PlatformParser.reset(createELFAsmParser()); break; case MCObjectFileInfo::IsWasm: // TODO: WASM will need its own MCAsmParserExtension implementation, but // for now we can re-use the ELF one, since the directives can be the // same for now. PlatformParser.reset(createELFAsmParser()); break; } PlatformParser->Initialize(*this); initializeDirectiveKindMap(); NumOfMacroInstantiations = 0; } AsmParser::~AsmParser() { assert((HadError || ActiveMacros.empty()) && "Unexpected active macro instantiation!"); // Restore the saved diagnostics handler and context for use during // finalization. SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext); } void AsmParser::printMacroInstantiations() { // Print the active macro instantiation stack. for (std::vector::const_reverse_iterator it = ActiveMacros.rbegin(), ie = ActiveMacros.rend(); it != ie; ++it) printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note, "while in macro instantiation"); } void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) { printPendingErrors(); printMessage(L, SourceMgr::DK_Note, Msg, Range); printMacroInstantiations(); } bool AsmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) { if(getTargetParser().getTargetOptions().MCNoWarn) return false; if (getTargetParser().getTargetOptions().MCFatalWarnings) return Error(L, Msg, Range); printMessage(L, SourceMgr::DK_Warning, Msg, Range); printMacroInstantiations(); return false; } bool AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) { HadError = true; printMessage(L, SourceMgr::DK_Error, Msg, Range); printMacroInstantiations(); return true; } bool AsmParser::enterIncludeFile(const std::string &Filename) { std::string IncludedFile; unsigned NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); if (!NewBuf) return true; CurBuffer = NewBuf; Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); return false; } /// Process the specified .incbin file by searching for it in the include paths /// then just emitting the byte contents of the file to the streamer. This /// returns true on failure. bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip, const MCExpr *Count, SMLoc Loc) { std::string IncludedFile; unsigned NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); if (!NewBuf) return true; // Pick up the bytes from the file and emit them. StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer(); Bytes = Bytes.drop_front(Skip); if (Count) { int64_t Res; if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(Loc, "expected absolute expression"); if (Res < 0) return Warning(Loc, "negative count has no effect"); Bytes = Bytes.take_front(Res); } getStreamer().EmitBytes(Bytes); return false; } void AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) { CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), Loc.getPointer()); } const AsmToken &AsmParser::Lex() { if (Lexer.getTok().is(AsmToken::Error)) Error(Lexer.getErrLoc(), Lexer.getErr()); // if it's a end of statement with a comment in it if (getTok().is(AsmToken::EndOfStatement)) { // if this is a line comment output it. if (!getTok().getString().empty() && getTok().getString().front() != '\n' && getTok().getString().front() != '\r' && MAI.preserveAsmComments()) Out.addExplicitComment(Twine(getTok().getString())); } const AsmToken *tok = &Lexer.Lex(); // Parse comments here to be deferred until end of next statement. while (tok->is(AsmToken::Comment)) { if (MAI.preserveAsmComments()) Out.addExplicitComment(Twine(tok->getString())); tok = &Lexer.Lex(); } if (tok->is(AsmToken::Eof)) { // If this is the end of an included file, pop the parent file off the // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); if (ParentIncludeLoc != SMLoc()) { jumpToLoc(ParentIncludeLoc); return Lex(); } } return *tok; } bool AsmParser::enabledGenDwarfForAssembly() { // Check whether the user specified -g. if (!getContext().getGenDwarfForAssembly()) return false; // If we haven't encountered any .file directives (which would imply that // the assembler source was produced with debug info already) then emit one // describing the assembler source file itself. if (getContext().getGenDwarfFileNumber() == 0) getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( 0, StringRef(), getContext().getMainFileName())); return true; } bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Create the initial section, if requested. if (!NoInitialTextSection) Out.InitSections(false); // Prime the lexer. Lex(); HadError = false; AsmCond StartingCondState = TheCondState; SmallVector AsmStrRewrites; // If we are generating dwarf for assembly source files save the initial text // section. (Don't use enabledGenDwarfForAssembly() here, as we aren't // emitting any actual debug info yet and haven't had a chance to parse any // embedded .file directives.) if (getContext().getGenDwarfForAssembly()) { MCSection *Sec = getStreamer().getCurrentSectionOnly(); if (!Sec->getBeginSymbol()) { MCSymbol *SectionStartSym = getContext().createTempSymbol(); getStreamer().EmitLabel(SectionStartSym); Sec->setBeginSymbol(SectionStartSym); } bool InsertResult = getContext().addGenDwarfSection(Sec); assert(InsertResult && ".text section should not have debug info yet"); (void)InsertResult; } // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { ParseStatementInfo Info(&AsmStrRewrites); if (!parseStatement(Info, nullptr)) continue; // If we have a Lexer Error we are on an Error Token. Load in Lexer Error // for printing ErrMsg via Lex() only if no (presumably better) parser error // exists. if (!hasPendingError() && Lexer.getTok().is(AsmToken::Error)) { Lex(); } // parseStatement returned true so may need to emit an error. printPendingErrors(); // Skipping to the next line if needed. if (!getLexer().isAtStartOfStatement()) eatToEndOfStatement(); } // All errors should have been emitted. assert(!hasPendingError() && "unexpected error from parseStatement"); getTargetParser().flushPendingInstructions(getStreamer()); if (TheCondState.TheCond != StartingCondState.TheCond || TheCondState.Ignore != StartingCondState.Ignore) printError(getTok().getLoc(), "unmatched .ifs or .elses"); // Check to see there are no empty DwarfFile slots. const auto &LineTables = getContext().getMCDwarfLineTables(); if (!LineTables.empty()) { unsigned Index = 0; for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) { if (File.Name.empty() && Index != 0) printError(getTok().getLoc(), "unassigned file number: " + Twine(Index) + " for .file directives"); ++Index; } } // Check to see that all assembler local symbols were actually defined. // Targets that don't do subsections via symbols may not want this, though, // so conservatively exclude them. Only do this if we're finalizing, though, // as otherwise we won't necessarilly have seen everything yet. if (!NoFinalize) { if (MAI.hasSubsectionsViaSymbols()) { for (const auto &TableEntry : getContext().getSymbols()) { MCSymbol *Sym = TableEntry.getValue(); // Variable symbols may not be marked as defined, so check those // explicitly. If we know it's a variable, we have a definition for // the purposes of this check. if (Sym->isTemporary() && !Sym->isVariable() && !Sym->isDefined()) // FIXME: We would really like to refer back to where the symbol was // first referenced for a source location. We need to add something // to track that. Currently, we just point to the end of the file. printError(getTok().getLoc(), "assembler local symbol '" + Sym->getName() + "' not defined"); } } // Temporary symbols like the ones for directional jumps don't go in the // symbol table. They also need to be diagnosed in all (final) cases. for (std::tuple &LocSym : DirLabels) { if (std::get<2>(LocSym)->isUndefined()) { // Reset the state of any "# line file" directives we've seen to the // context as it was at the diagnostic site. CppHashInfo = std::get<1>(LocSym); printError(std::get<0>(LocSym), "directional label undefined"); } } } // Finalize the output stream if there are no errors and if the client wants // us to. if (!HadError && !NoFinalize) Out.Finish(); return HadError || getContext().hadError(); } bool AsmParser::checkForValidSection() { if (!ParsingInlineAsm && !getStreamer().getCurrentSectionOnly()) { Out.InitSections(false); return Error(getTok().getLoc(), "expected section directive before assembly directive"); } return false; } /// Throw away the rest of the line for testing purposes. void AsmParser::eatToEndOfStatement() { while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); // Eat EOL. if (Lexer.is(AsmToken::EndOfStatement)) Lexer.Lex(); } StringRef AsmParser::parseStringToEndOfStatement() { const char *Start = getTok().getLoc().getPointer(); while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); const char *End = getTok().getLoc().getPointer(); return StringRef(Start, End - Start); } StringRef AsmParser::parseStringToComma() { const char *Start = getTok().getLoc().getPointer(); while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Comma) && Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); const char *End = getTok().getLoc().getPointer(); return StringRef(Start, End - Start); } /// Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. /// /// parenexpr ::= expr) /// bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { if (parseExpression(Res)) return true; if (Lexer.isNot(AsmToken::RParen)) return TokError("expected ')' in parentheses expression"); EndLoc = Lexer.getTok().getEndLoc(); Lex(); return false; } /// Parse a bracket expression and return it. /// NOTE: This assumes the leading '[' has already been consumed. /// /// bracketexpr ::= expr] /// bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { if (parseExpression(Res)) return true; EndLoc = getTok().getEndLoc(); if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression")) return true; return false; } /// Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol /// primaryexpr ::= number /// primaryexpr ::= '.' /// primaryexpr ::= ~,+,- primaryexpr bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { SMLoc FirstTokenLoc = getLexer().getLoc(); AsmToken::TokenKind FirstTokenKind = Lexer.getKind(); switch (FirstTokenKind) { default: return TokError("unknown token in expression"); // If we have an error assume that we've already handled it. case AsmToken::Error: return true; case AsmToken::Exclaim: Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc)) return true; Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Dollar: case AsmToken::At: case AsmToken::String: case AsmToken::Identifier: { StringRef Identifier; if (parseIdentifier(Identifier)) { // We may have failed but $ may be a valid token. if (getTok().is(AsmToken::Dollar)) { if (Lexer.getMAI().getDollarIsPC()) { Lex(); // This is a '$' reference, which references the current PC. Emit a // temporary label to the streamer and refer to it. MCSymbol *Sym = Ctx.createTempSymbol(); Out.EmitLabel(Sym); Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); EndLoc = FirstTokenLoc; return false; } return Error(FirstTokenLoc, "invalid token in expression"); } } // Parse symbol variant std::pair Split; if (!MAI.useParensForSymbolVariant()) { if (FirstTokenKind == AsmToken::String) { if (Lexer.is(AsmToken::At)) { Lex(); // eat @ SMLoc AtLoc = getLexer().getLoc(); StringRef VName; if (parseIdentifier(VName)) return Error(AtLoc, "expected symbol variant after '@'"); Split = std::make_pair(Identifier, VName); } } else { Split = Identifier.split('@'); } } else if (Lexer.is(AsmToken::LParen)) { Lex(); // eat '('. StringRef VName; parseIdentifier(VName); // eat ')'. if (parseToken(AsmToken::RParen, "unexpected token in variant, expected ')'")) return true; Split = std::make_pair(Identifier, VName); } EndLoc = SMLoc::getFromPointer(Identifier.end()); // This is a symbol reference. StringRef SymbolName = Identifier; if (SymbolName.empty()) return true; MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; // Lookup the symbol variant if used. if (!Split.second.empty()) { Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); if (Variant != MCSymbolRefExpr::VK_Invalid) { SymbolName = Split.first; } else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) { Variant = MCSymbolRefExpr::VK_None; } else { return Error(SMLoc::getFromPointer(Split.second.begin()), "invalid variant '" + Split.second + "'"); } } MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->isVariable()) { auto V = Sym->getVariableValue(/*SetUsed*/ false); bool DoInline = isa(V); if (auto TV = dyn_cast(V)) DoInline = TV->inlineAssignedExpr(); if (DoInline) { if (Variant) return Error(EndLoc, "unexpected modifier on variable reference"); Res = Sym->getVariableValue(/*SetUsed*/ false); return false; } } // Otherwise create a symbol ref. Res = MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc); return false; } case AsmToken::BigNum: return TokError("literal value out of range for directive"); case AsmToken::Integer: { SMLoc Loc = getTok().getLoc(); int64_t IntVal = getTok().getIntVal(); Res = MCConstantExpr::create(IntVal, getContext()); EndLoc = Lexer.getTok().getEndLoc(); Lex(); // Eat token. // Look for 'b' or 'f' following an Integer as a directional label if (Lexer.getKind() == AsmToken::Identifier) { StringRef IDVal = getTok().getString(); // Lookup the symbol variant if used. std::pair Split = IDVal.split('@'); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; if (Split.first.size() != IDVal.size()) { Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); if (Variant == MCSymbolRefExpr::VK_Invalid) return TokError("invalid variant '" + Split.second + "'"); IDVal = Split.first; } if (IDVal == "f" || IDVal == "b") { MCSymbol *Sym = Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b"); Res = MCSymbolRefExpr::create(Sym, Variant, getContext()); if (IDVal == "b" && Sym->isUndefined()) return Error(Loc, "directional label undefined"); DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym)); EndLoc = Lexer.getTok().getEndLoc(); Lex(); // Eat identifier. } } return false; } case AsmToken::Real: { APFloat RealVal(APFloat::IEEEdouble(), getTok().getString()); uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); Res = MCConstantExpr::create(IntVal, getContext()); EndLoc = Lexer.getTok().getEndLoc(); Lex(); // Eat token. return false; } case AsmToken::Dot: { // This is a '.' reference, which references the current PC. Emit a // temporary label to the streamer and refer to it. MCSymbol *Sym = Ctx.createTempSymbol(); Out.EmitLabel(Sym); Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); EndLoc = Lexer.getTok().getEndLoc(); Lex(); // Eat identifier. return false; } case AsmToken::LParen: Lex(); // Eat the '('. return parseParenExpr(Res, EndLoc); case AsmToken::LBrac: if (!PlatformParser->HasBracketExpressions()) return TokError("brackets expression not supported on this target"); Lex(); // Eat the '['. return parseBracketExpr(Res, EndLoc); case AsmToken::Minus: Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc)) return true; Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Plus: Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc)) return true; Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc); return false; case AsmToken::Tilde: Lex(); // Eat the operator. if (parsePrimaryExpr(Res, EndLoc)) return true; Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc); return false; // MIPS unary expression operators. The lexer won't generate these tokens if // MCAsmInfo::HasMipsExpressions is false for the target. case AsmToken::PercentCall16: case AsmToken::PercentCall_Hi: case AsmToken::PercentCall_Lo: case AsmToken::PercentDtprel_Hi: case AsmToken::PercentDtprel_Lo: case AsmToken::PercentGot: case AsmToken::PercentGot_Disp: case AsmToken::PercentGot_Hi: case AsmToken::PercentGot_Lo: case AsmToken::PercentGot_Ofst: case AsmToken::PercentGot_Page: case AsmToken::PercentGottprel: case AsmToken::PercentGp_Rel: case AsmToken::PercentHi: case AsmToken::PercentHigher: case AsmToken::PercentHighest: case AsmToken::PercentLo: case AsmToken::PercentNeg: case AsmToken::PercentPcrel_Hi: case AsmToken::PercentPcrel_Lo: case AsmToken::PercentTlsgd: case AsmToken::PercentTlsldm: case AsmToken::PercentTprel_Hi: case AsmToken::PercentTprel_Lo: Lex(); // Eat the operator. if (Lexer.isNot(AsmToken::LParen)) return TokError("expected '(' after operator"); Lex(); // Eat the operator. if (parseExpression(Res, EndLoc)) return true; if (Lexer.isNot(AsmToken::RParen)) return TokError("expected ')'"); Lex(); // Eat the operator. Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx); return !Res; } } bool AsmParser::parseExpression(const MCExpr *&Res) { SMLoc EndLoc; return parseExpression(Res, EndLoc); } const MCExpr * AsmParser::applyModifierToExpr(const MCExpr *E, MCSymbolRefExpr::VariantKind Variant) { // Ask the target implementation about this expression first. const MCExpr *NewE = getTargetParser().applyModifierToExpr(E, Variant, Ctx); if (NewE) return NewE; // Recurse over the given expression, rebuilding it to apply the given variant // if there is exactly one symbol. switch (E->getKind()) { case MCExpr::Target: case MCExpr::Constant: return nullptr; case MCExpr::SymbolRef: { const MCSymbolRefExpr *SRE = cast(E); if (SRE->getKind() != MCSymbolRefExpr::VK_None) { TokError("invalid variant on expression '" + getTok().getIdentifier() + "' (already modified)"); return E; } return MCSymbolRefExpr::create(&SRE->getSymbol(), Variant, getContext()); } case MCExpr::Unary: { const MCUnaryExpr *UE = cast(E); const MCExpr *Sub = applyModifierToExpr(UE->getSubExpr(), Variant); if (!Sub) return nullptr; return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext()); } case MCExpr::Binary: { const MCBinaryExpr *BE = cast(E); const MCExpr *LHS = applyModifierToExpr(BE->getLHS(), Variant); const MCExpr *RHS = applyModifierToExpr(BE->getRHS(), Variant); if (!LHS && !RHS) return nullptr; if (!LHS) LHS = BE->getLHS(); if (!RHS) RHS = BE->getRHS(); return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext()); } } llvm_unreachable("Invalid expression kind!"); } /// This function checks if the next token is type or arithmetic. /// string that begin with character '<' must end with character '>'. /// otherwise it is arithmetics. /// If the function returns a 'true' value, /// the End argument will be filled with the last location pointed to the '>' /// character. /// There is a gap between the AltMacro's documentation and the single quote implementation. /// GCC does not fully support this feature and so we will not support it. /// TODO: Adding single quote as a string. bool AsmParser::isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) { assert((StrLoc.getPointer() != NULL) && "Argument to the function cannot be a NULL value"); const char *CharPtr = StrLoc.getPointer(); while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') && (*CharPtr != '\0')) { if (*CharPtr == '!') CharPtr++; CharPtr++; } if (*CharPtr == '>') { EndLoc = StrLoc.getFromPointer(CharPtr + 1); return true; } return false; } /// creating a string without the escape characters '!'. void AsmParser::altMacroString(StringRef AltMacroStr,std::string &Res) { for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) { if (AltMacroStr[Pos] == '!') Pos++; Res += AltMacroStr[Pos]; } } /// Parse an expression and return it. /// /// expr ::= expr &&,|| expr -> lowest. /// expr ::= expr |,^,&,! expr /// expr ::= expr ==,!=,<>,<,<=,>,>= expr /// expr ::= expr <<,>> expr /// expr ::= expr +,- expr /// expr ::= expr *,/,% expr -> highest. /// expr ::= primaryexpr /// bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) { // Parse the expression. Res = nullptr; - if (parsePrimaryExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc)) + if (getTargetParser().parsePrimaryExpr(Res, EndLoc) || + parseBinOpRHS(1, Res, EndLoc)) return true; // As a special case, we support 'a op b @ modifier' by rewriting the // expression to include the modifier. This is inefficient, but in general we // expect users to use 'a@modifier op b'. if (Lexer.getKind() == AsmToken::At) { Lex(); if (Lexer.isNot(AsmToken::Identifier)) return TokError("unexpected symbol modifier following '@'"); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier()); if (Variant == MCSymbolRefExpr::VK_Invalid) return TokError("invalid variant '" + getTok().getIdentifier() + "'"); const MCExpr *ModifiedRes = applyModifierToExpr(Res, Variant); if (!ModifiedRes) { return TokError("invalid modifier '" + getTok().getIdentifier() + "' (no symbols present)"); } Res = ModifiedRes; Lex(); } // Try to constant fold it up front, if possible. Do not exploit // assembler here. int64_t Value; if (Res->evaluateAsAbsolute(Value)) Res = MCConstantExpr::create(Value, getContext()); return false; } bool AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { Res = nullptr; return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc); } bool AsmParser::parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res, SMLoc &EndLoc) { if (parseParenExpr(Res, EndLoc)) return true; for (; ParenDepth > 0; --ParenDepth) { if (parseBinOpRHS(1, Res, EndLoc)) return true; // We don't Lex() the last RParen. // This is the same behavior as parseParenExpression(). if (ParenDepth - 1 > 0) { EndLoc = getTok().getEndLoc(); if (parseToken(AsmToken::RParen, "expected ')' in parentheses expression")) return true; } } return false; } bool AsmParser::parseAbsoluteExpression(int64_t &Res) { const MCExpr *Expr; SMLoc StartLoc = Lexer.getLoc(); if (parseExpression(Expr)) return true; if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr())) return Error(StartLoc, "expected absolute expression"); return false; } static unsigned getDarwinBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind, bool ShouldUseLogicalShr) { switch (K) { default: return 0; // not a binop. // Lowest Precedence: &&, || case AsmToken::AmpAmp: Kind = MCBinaryExpr::LAnd; return 1; case AsmToken::PipePipe: Kind = MCBinaryExpr::LOr; return 1; // Low Precedence: |, &, ^ // // FIXME: gas seems to support '!' as an infix operator? case AsmToken::Pipe: Kind = MCBinaryExpr::Or; return 2; case AsmToken::Caret: Kind = MCBinaryExpr::Xor; return 2; case AsmToken::Amp: Kind = MCBinaryExpr::And; return 2; // Low Intermediate Precedence: ==, !=, <>, <, <=, >, >= case AsmToken::EqualEqual: Kind = MCBinaryExpr::EQ; return 3; case AsmToken::ExclaimEqual: case AsmToken::LessGreater: Kind = MCBinaryExpr::NE; return 3; case AsmToken::Less: Kind = MCBinaryExpr::LT; return 3; case AsmToken::LessEqual: Kind = MCBinaryExpr::LTE; return 3; case AsmToken::Greater: Kind = MCBinaryExpr::GT; return 3; case AsmToken::GreaterEqual: Kind = MCBinaryExpr::GTE; return 3; // Intermediate Precedence: <<, >> case AsmToken::LessLess: Kind = MCBinaryExpr::Shl; return 4; case AsmToken::GreaterGreater: Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr; return 4; // High Intermediate Precedence: +, - case AsmToken::Plus: Kind = MCBinaryExpr::Add; return 5; case AsmToken::Minus: Kind = MCBinaryExpr::Sub; return 5; // Highest Precedence: *, /, % case AsmToken::Star: Kind = MCBinaryExpr::Mul; return 6; case AsmToken::Slash: Kind = MCBinaryExpr::Div; return 6; case AsmToken::Percent: Kind = MCBinaryExpr::Mod; return 6; } } static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind, bool ShouldUseLogicalShr) { switch (K) { default: return 0; // not a binop. // Lowest Precedence: &&, || case AsmToken::AmpAmp: Kind = MCBinaryExpr::LAnd; return 2; case AsmToken::PipePipe: Kind = MCBinaryExpr::LOr; return 1; // Low Precedence: ==, !=, <>, <, <=, >, >= case AsmToken::EqualEqual: Kind = MCBinaryExpr::EQ; return 3; case AsmToken::ExclaimEqual: case AsmToken::LessGreater: Kind = MCBinaryExpr::NE; return 3; case AsmToken::Less: Kind = MCBinaryExpr::LT; return 3; case AsmToken::LessEqual: Kind = MCBinaryExpr::LTE; return 3; case AsmToken::Greater: Kind = MCBinaryExpr::GT; return 3; case AsmToken::GreaterEqual: Kind = MCBinaryExpr::GTE; return 3; // Low Intermediate Precedence: +, - case AsmToken::Plus: Kind = MCBinaryExpr::Add; return 4; case AsmToken::Minus: Kind = MCBinaryExpr::Sub; return 4; // High Intermediate Precedence: |, &, ^ // // FIXME: gas seems to support '!' as an infix operator? case AsmToken::Pipe: Kind = MCBinaryExpr::Or; return 5; case AsmToken::Caret: Kind = MCBinaryExpr::Xor; return 5; case AsmToken::Amp: Kind = MCBinaryExpr::And; return 5; // Highest Precedence: *, /, %, <<, >> case AsmToken::Star: Kind = MCBinaryExpr::Mul; return 6; case AsmToken::Slash: Kind = MCBinaryExpr::Div; return 6; case AsmToken::Percent: Kind = MCBinaryExpr::Mod; return 6; case AsmToken::LessLess: Kind = MCBinaryExpr::Shl; return 6; case AsmToken::GreaterGreater: Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr; return 6; } } unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind) { bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr(); return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr) : getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr); } /// Parse all binary operators with precedence >= 'Precedence'. /// Res contains the LHS of the expression on input. bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc) { SMLoc StartLoc = Lexer.getLoc(); while (true) { MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); // If the next token is lower precedence than we are allowed to eat, return // successfully with what we ate already. if (TokPrec < Precedence) return false; Lex(); // Eat the next primary expression. const MCExpr *RHS; - if (parsePrimaryExpr(RHS, EndLoc)) + if (getTargetParser().parsePrimaryExpr(RHS, EndLoc)) return true; // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. MCBinaryExpr::Opcode Dummy; unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy); if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc)) return true; // Merge LHS and RHS according to operator. Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc); } } /// ParseStatement: /// ::= EndOfStatement /// ::= Label* Directive ...Operands... EndOfStatement /// ::= Label* Identifier OperandList* EndOfStatement bool AsmParser::parseStatement(ParseStatementInfo &Info, MCAsmParserSemaCallback *SI) { assert(!hasPendingError() && "parseStatement started with pending error"); // Eat initial spaces and comments while (Lexer.is(AsmToken::Space)) Lex(); if (Lexer.is(AsmToken::EndOfStatement)) { // if this is a line comment we can drop it safely if (getTok().getString().empty() || getTok().getString().front() == '\r' || getTok().getString().front() == '\n') Out.AddBlankLine(); Lex(); return false; } // Statements always start with an identifier. AsmToken ID = getTok(); SMLoc IDLoc = ID.getLoc(); StringRef IDVal; int64_t LocalLabelVal = -1; if (Lexer.is(AsmToken::HashDirective)) return parseCppHashLineFilenameComment(IDLoc); // Allow an integer followed by a ':' as a directional local label. if (Lexer.is(AsmToken::Integer)) { LocalLabelVal = getTok().getIntVal(); if (LocalLabelVal < 0) { if (!TheCondState.Ignore) { Lex(); // always eat a token return Error(IDLoc, "unexpected token at start of statement"); } IDVal = ""; } else { IDVal = getTok().getString(); Lex(); // Consume the integer token to be used as an identifier token. if (Lexer.getKind() != AsmToken::Colon) { if (!TheCondState.Ignore) { Lex(); // always eat a token return Error(IDLoc, "unexpected token at start of statement"); } } } } else if (Lexer.is(AsmToken::Dot)) { // Treat '.' as a valid identifier in this context. Lex(); IDVal = "."; } else if (Lexer.is(AsmToken::LCurly)) { // Treat '{' as a valid identifier in this context. Lex(); IDVal = "{"; } else if (Lexer.is(AsmToken::RCurly)) { // Treat '}' as a valid identifier in this context. Lex(); IDVal = "}"; } else if (Lexer.is(AsmToken::Star) && getTargetParser().starIsStartOfStatement()) { // Accept '*' as a valid start of statement. Lex(); IDVal = "*"; } else if (parseIdentifier(IDVal)) { if (!TheCondState.Ignore) { Lex(); // always eat a token return Error(IDLoc, "unexpected token at start of statement"); } IDVal = ""; } // Handle conditional assembly here before checking for skipping. We // have to do this so that .endif isn't skipped in a ".if 0" block for // example. StringMap::const_iterator DirKindIt = DirectiveKindMap.find(IDVal); DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end()) ? DK_NO_DIRECTIVE : DirKindIt->getValue(); switch (DirKind) { default: break; case DK_IF: case DK_IFEQ: case DK_IFGE: case DK_IFGT: case DK_IFLE: case DK_IFLT: case DK_IFNE: return parseDirectiveIf(IDLoc, DirKind); case DK_IFB: return parseDirectiveIfb(IDLoc, true); case DK_IFNB: return parseDirectiveIfb(IDLoc, false); case DK_IFC: return parseDirectiveIfc(IDLoc, true); case DK_IFEQS: return parseDirectiveIfeqs(IDLoc, true); case DK_IFNC: return parseDirectiveIfc(IDLoc, false); case DK_IFNES: return parseDirectiveIfeqs(IDLoc, false); case DK_IFDEF: return parseDirectiveIfdef(IDLoc, true); case DK_IFNDEF: case DK_IFNOTDEF: return parseDirectiveIfdef(IDLoc, false); case DK_ELSEIF: return parseDirectiveElseIf(IDLoc); case DK_ELSE: return parseDirectiveElse(IDLoc); case DK_ENDIF: return parseDirectiveEndIf(IDLoc); } // Ignore the statement if in the middle of inactive conditional // (e.g. ".if 0"). if (TheCondState.Ignore) { eatToEndOfStatement(); return false; } // FIXME: Recurse on local labels? // See what kind of statement we have. switch (Lexer.getKind()) { case AsmToken::Colon: { if (!getTargetParser().isLabel(ID)) break; if (checkForValidSection()) return true; // identifier ':' -> Label. Lex(); // Diagnose attempt to use '.' as a label. if (IDVal == ".") return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label"); // Diagnose attempt to use a variable as a label. // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: This doesn't diagnose assignment to a symbol which has been // implicitly marked as external. MCSymbol *Sym; if (LocalLabelVal == -1) { if (ParsingInlineAsm && SI) { StringRef RewrittenLabel = SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true); assert(!RewrittenLabel.empty() && "We should have an internal name here."); Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(), RewrittenLabel); IDVal = RewrittenLabel; } Sym = getContext().getOrCreateSymbol(IDVal); } else Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal); // End of Labels should be treated as end of line for lexing // purposes but that information is not available to the Lexer who // does not understand Labels. This may cause us to see a Hash // here instead of a preprocessor line comment. if (getTok().is(AsmToken::Hash)) { StringRef CommentStr = parseStringToEndOfStatement(); Lexer.Lex(); Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr)); } // Consume any end of statement token, if present, to avoid spurious // AddBlankLine calls(). if (getTok().is(AsmToken::EndOfStatement)) { Lex(); } // Emit the label. if (!getTargetParser().isParsingInlineAsm()) Out.EmitLabel(Sym, IDLoc); // If we are generating dwarf for assembly source files then gather the // info to make a dwarf label entry for this label if needed. if (enabledGenDwarfForAssembly()) MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(), IDLoc); getTargetParser().onLabelParsed(Sym); return false; } case AsmToken::Equal: if (!getTargetParser().equalIsAsmAssignment()) break; // identifier '=' ... -> assignment statement Lex(); - return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true); + return parseAssignment(IDVal, true); default: // Normal instruction or directive. break; } // If macros are enabled, check to see if this is a macro instantiation. if (areMacrosEnabled()) if (const MCAsmMacro *M = getContext().lookupMacro(IDVal)) { return handleMacroEntry(M, IDLoc); } // Otherwise, we have a normal instruction or directive. // Directives start with "." if (IDVal[0] == '.' && IDVal != ".") { // There are several entities interested in parsing directives: // // 1. The target-specific assembly parser. Some directives are target // specific or may potentially behave differently on certain targets. // 2. Asm parser extensions. For example, platform-specific parsers // (like the ELF parser) register themselves as extensions. // 3. The generic directive parser implemented by this class. These are // all the directives that behave in a target and platform independent // manner, or at least have a default behavior that's shared between // all targets and platforms. getTargetParser().flushPendingInstructions(getStreamer()); SMLoc StartTokLoc = getTok().getLoc(); bool TPDirectiveReturn = getTargetParser().ParseDirective(ID); if (hasPendingError()) return true; // Currently the return value should be true if we are // uninterested but as this is at odds with the standard parsing // convention (return true = error) we have instances of a parsed // directive that fails returning true as an error. Catch these // cases as best as possible errors here. if (TPDirectiveReturn && StartTokLoc != getTok().getLoc()) return true; // Return if we did some parsing or believe we succeeded. if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc()) return false; // Next, check the extension directive map to see if any extension has // registered itself to parse this directive. std::pair Handler = ExtensionDirectiveMap.lookup(IDVal); if (Handler.first) return (*Handler.second)(Handler.first, IDVal, IDLoc); // Finally, if no one else is interested in this directive, it must be // generic and familiar to this class. switch (DirKind) { default: break; case DK_SET: case DK_EQU: return parseDirectiveSet(IDVal, true); case DK_EQUIV: return parseDirectiveSet(IDVal, false); case DK_ASCII: return parseDirectiveAscii(IDVal, false); case DK_ASCIZ: case DK_STRING: return parseDirectiveAscii(IDVal, true); case DK_BYTE: case DK_DC_B: return parseDirectiveValue(IDVal, 1); case DK_DC: case DK_DC_W: case DK_SHORT: case DK_VALUE: case DK_2BYTE: return parseDirectiveValue(IDVal, 2); case DK_LONG: case DK_INT: case DK_4BYTE: case DK_DC_L: return parseDirectiveValue(IDVal, 4); case DK_QUAD: case DK_8BYTE: return parseDirectiveValue(IDVal, 8); case DK_DC_A: return parseDirectiveValue( IDVal, getContext().getAsmInfo()->getCodePointerSize()); case DK_OCTA: return parseDirectiveOctaValue(IDVal); case DK_SINGLE: case DK_FLOAT: case DK_DC_S: return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle()); case DK_DOUBLE: case DK_DC_D: return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble()); case DK_ALIGN: { bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); return parseDirectiveAlign(IsPow2, /*ExprSize=*/1); } case DK_ALIGN32: { bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes(); return parseDirectiveAlign(IsPow2, /*ExprSize=*/4); } case DK_BALIGN: return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); case DK_BALIGNW: return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); case DK_BALIGNL: return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); case DK_P2ALIGN: return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); case DK_P2ALIGNW: return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); case DK_P2ALIGNL: return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); case DK_ORG: return parseDirectiveOrg(); case DK_FILL: return parseDirectiveFill(); case DK_ZERO: return parseDirectiveZero(); case DK_EXTERN: eatToEndOfStatement(); // .extern is the default, ignore it. return false; case DK_GLOBL: case DK_GLOBAL: return parseDirectiveSymbolAttribute(MCSA_Global); case DK_LAZY_REFERENCE: return parseDirectiveSymbolAttribute(MCSA_LazyReference); case DK_NO_DEAD_STRIP: return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip); case DK_SYMBOL_RESOLVER: return parseDirectiveSymbolAttribute(MCSA_SymbolResolver); case DK_PRIVATE_EXTERN: return parseDirectiveSymbolAttribute(MCSA_PrivateExtern); case DK_REFERENCE: return parseDirectiveSymbolAttribute(MCSA_Reference); case DK_WEAK_DEFINITION: return parseDirectiveSymbolAttribute(MCSA_WeakDefinition); case DK_WEAK_REFERENCE: return parseDirectiveSymbolAttribute(MCSA_WeakReference); case DK_WEAK_DEF_CAN_BE_HIDDEN: return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate); case DK_COMM: case DK_COMMON: return parseDirectiveComm(/*IsLocal=*/false); case DK_LCOMM: return parseDirectiveComm(/*IsLocal=*/true); case DK_ABORT: return parseDirectiveAbort(); case DK_INCLUDE: return parseDirectiveInclude(); case DK_INCBIN: return parseDirectiveIncbin(); case DK_CODE16: case DK_CODE16GCC: return TokError(Twine(IDVal) + " not currently supported for this target"); case DK_REPT: return parseDirectiveRept(IDLoc, IDVal); case DK_IRP: return parseDirectiveIrp(IDLoc); case DK_IRPC: return parseDirectiveIrpc(IDLoc); case DK_ENDR: return parseDirectiveEndr(IDLoc); case DK_BUNDLE_ALIGN_MODE: return parseDirectiveBundleAlignMode(); case DK_BUNDLE_LOCK: return parseDirectiveBundleLock(); case DK_BUNDLE_UNLOCK: return parseDirectiveBundleUnlock(); case DK_SLEB128: return parseDirectiveLEB128(true); case DK_ULEB128: return parseDirectiveLEB128(false); case DK_SPACE: case DK_SKIP: return parseDirectiveSpace(IDVal); case DK_FILE: return parseDirectiveFile(IDLoc); case DK_LINE: return parseDirectiveLine(); case DK_LOC: return parseDirectiveLoc(); case DK_STABS: return parseDirectiveStabs(); case DK_CV_FILE: return parseDirectiveCVFile(); case DK_CV_FUNC_ID: return parseDirectiveCVFuncId(); case DK_CV_INLINE_SITE_ID: return parseDirectiveCVInlineSiteId(); case DK_CV_LOC: return parseDirectiveCVLoc(); case DK_CV_LINETABLE: return parseDirectiveCVLinetable(); case DK_CV_INLINE_LINETABLE: return parseDirectiveCVInlineLinetable(); case DK_CV_DEF_RANGE: return parseDirectiveCVDefRange(); case DK_CV_STRINGTABLE: return parseDirectiveCVStringTable(); case DK_CV_FILECHECKSUMS: return parseDirectiveCVFileChecksums(); case DK_CV_FILECHECKSUM_OFFSET: return parseDirectiveCVFileChecksumOffset(); case DK_CV_FPO_DATA: return parseDirectiveCVFPOData(); case DK_CFI_SECTIONS: return parseDirectiveCFISections(); case DK_CFI_STARTPROC: return parseDirectiveCFIStartProc(); case DK_CFI_ENDPROC: return parseDirectiveCFIEndProc(); case DK_CFI_DEF_CFA: return parseDirectiveCFIDefCfa(IDLoc); case DK_CFI_DEF_CFA_OFFSET: return parseDirectiveCFIDefCfaOffset(); case DK_CFI_ADJUST_CFA_OFFSET: return parseDirectiveCFIAdjustCfaOffset(); case DK_CFI_DEF_CFA_REGISTER: return parseDirectiveCFIDefCfaRegister(IDLoc); case DK_CFI_OFFSET: return parseDirectiveCFIOffset(IDLoc); case DK_CFI_REL_OFFSET: return parseDirectiveCFIRelOffset(IDLoc); case DK_CFI_PERSONALITY: return parseDirectiveCFIPersonalityOrLsda(true); case DK_CFI_LSDA: return parseDirectiveCFIPersonalityOrLsda(false); case DK_CFI_REMEMBER_STATE: return parseDirectiveCFIRememberState(); case DK_CFI_RESTORE_STATE: return parseDirectiveCFIRestoreState(); case DK_CFI_SAME_VALUE: return parseDirectiveCFISameValue(IDLoc); case DK_CFI_RESTORE: return parseDirectiveCFIRestore(IDLoc); case DK_CFI_ESCAPE: return parseDirectiveCFIEscape(); case DK_CFI_RETURN_COLUMN: return parseDirectiveCFIReturnColumn(IDLoc); case DK_CFI_SIGNAL_FRAME: return parseDirectiveCFISignalFrame(); case DK_CFI_UNDEFINED: return parseDirectiveCFIUndefined(IDLoc); case DK_CFI_REGISTER: return parseDirectiveCFIRegister(IDLoc); case DK_CFI_WINDOW_SAVE: return parseDirectiveCFIWindowSave(); case DK_MACROS_ON: case DK_MACROS_OFF: return parseDirectiveMacrosOnOff(IDVal); case DK_MACRO: return parseDirectiveMacro(IDLoc); case DK_ALTMACRO: case DK_NOALTMACRO: return parseDirectiveAltmacro(IDVal); case DK_EXITM: return parseDirectiveExitMacro(IDVal); case DK_ENDM: case DK_ENDMACRO: return parseDirectiveEndMacro(IDVal); case DK_PURGEM: return parseDirectivePurgeMacro(IDLoc); case DK_END: return parseDirectiveEnd(IDLoc); case DK_ERR: return parseDirectiveError(IDLoc, false); case DK_ERROR: return parseDirectiveError(IDLoc, true); case DK_WARNING: return parseDirectiveWarning(IDLoc); case DK_RELOC: return parseDirectiveReloc(IDLoc); case DK_DCB: case DK_DCB_W: return parseDirectiveDCB(IDVal, 2); case DK_DCB_B: return parseDirectiveDCB(IDVal, 1); case DK_DCB_D: return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble()); case DK_DCB_L: return parseDirectiveDCB(IDVal, 4); case DK_DCB_S: return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle()); case DK_DC_X: case DK_DCB_X: return TokError(Twine(IDVal) + " not currently supported for this target"); case DK_DS: case DK_DS_W: return parseDirectiveDS(IDVal, 2); case DK_DS_B: return parseDirectiveDS(IDVal, 1); case DK_DS_D: return parseDirectiveDS(IDVal, 8); case DK_DS_L: case DK_DS_S: return parseDirectiveDS(IDVal, 4); case DK_DS_P: case DK_DS_X: return parseDirectiveDS(IDVal, 12); case DK_PRINT: return parseDirectivePrint(IDLoc); case DK_ADDRSIG: return parseDirectiveAddrsig(); case DK_ADDRSIG_SYM: return parseDirectiveAddrsigSym(); } return Error(IDLoc, "unknown directive"); } // __asm _emit or __asm __emit if (ParsingInlineAsm && (IDVal == "_emit" || IDVal == "__emit" || IDVal == "_EMIT" || IDVal == "__EMIT")) return parseDirectiveMSEmit(IDLoc, Info, IDVal.size()); // __asm align if (ParsingInlineAsm && (IDVal == "align" || IDVal == "ALIGN")) return parseDirectiveMSAlign(IDLoc, Info); if (ParsingInlineAsm && (IDVal == "even" || IDVal == "EVEN")) Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4); if (checkForValidSection()) return true; // Canonicalize the opcode to lower case. std::string OpcodeStr = IDVal.lower(); ParseInstructionInfo IInfo(Info.AsmRewrites); bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID, Info.ParsedOperands); Info.ParseError = ParseHadError; // Dump the parsed representation, if requested. if (getShowParsedOperands()) { SmallString<256> Str; raw_svector_ostream OS(Str); OS << "parsed instruction: ["; for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) { if (i != 0) OS << ", "; Info.ParsedOperands[i]->print(OS); } OS << "]"; printMessage(IDLoc, SourceMgr::DK_Note, OS.str()); } // Fail even if ParseInstruction erroneously returns false. if (hasPendingError() || ParseHadError) return true; // If we are generating dwarf for the current section then generate a .loc // directive for the instruction. if (!ParseHadError && enabledGenDwarfForAssembly() && getContext().getGenDwarfSectionSyms().count( getStreamer().getCurrentSectionOnly())) { unsigned Line; if (ActiveMacros.empty()) Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); else Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc, ActiveMacros.front()->ExitBuffer); // If we previously parsed a cpp hash file line comment then make sure the // current Dwarf File is for the CppHashFilename if not then emit the // Dwarf File table for it and adjust the line number for the .loc. if (!CppHashInfo.Filename.empty()) { unsigned FileNumber = getStreamer().EmitDwarfFileDirective( 0, StringRef(), CppHashInfo.Filename); getContext().setGenDwarfFileNumber(FileNumber); unsigned CppHashLocLineNo = SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf); Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo); } getStreamer().EmitDwarfLocDirective( getContext().getGenDwarfFileNumber(), Line, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0, StringRef()); } // If parsing succeeded, match the instruction. if (!ParseHadError) { uint64_t ErrorInfo; if (getTargetParser().MatchAndEmitInstruction( IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, getTargetParser().isParsingInlineAsm())) return true; } return false; } // Parse and erase curly braces marking block start/end bool AsmParser::parseCurlyBlockScope(SmallVectorImpl &AsmStrRewrites) { // Identify curly brace marking block start/end if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly)) return false; SMLoc StartLoc = Lexer.getLoc(); Lex(); // Eat the brace if (Lexer.is(AsmToken::EndOfStatement)) Lex(); // Eat EndOfStatement following the brace // Erase the block start/end brace from the output asm string AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() - StartLoc.getPointer()); return true; } /// parseCppHashLineFilenameComment as this: /// ::= # number "filename" bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) { Lex(); // Eat the hash token. // Lexer only ever emits HashDirective if it fully formed if it's // done the checking already so this is an internal error. assert(getTok().is(AsmToken::Integer) && "Lexing Cpp line comment: Expected Integer"); int64_t LineNumber = getTok().getIntVal(); Lex(); assert(getTok().is(AsmToken::String) && "Lexing Cpp line comment: Expected String"); StringRef Filename = getTok().getString(); Lex(); // Get rid of the enclosing quotes. Filename = Filename.substr(1, Filename.size() - 2); // Save the SMLoc, Filename and LineNumber for later use by diagnostics. CppHashInfo.Loc = L; CppHashInfo.Filename = Filename; CppHashInfo.LineNumber = LineNumber; CppHashInfo.Buf = CurBuffer; return false; } /// will use the last parsed cpp hash line filename comment /// for the Filename and LineNo if any in the diagnostic. void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) { const AsmParser *Parser = static_cast(Context); raw_ostream &OS = errs(); const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr(); SMLoc DiagLoc = Diag.getLoc(); unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc); unsigned CppHashBuf = Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc); // Like SourceMgr::printMessage() we need to print the include stack if any // before printing the message. unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc); if (!Parser->SavedDiagHandler && DiagCurBuffer && DiagCurBuffer != DiagSrcMgr.getMainFileID()) { SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer); DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS); } // If we have not parsed a cpp hash line filename comment or the source // manager changed or buffer changed (like in a nested include) then just // print the normal diagnostic using its Filename and LineNo. if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr || DiagBuf != CppHashBuf) { if (Parser->SavedDiagHandler) Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext); else Diag.print(nullptr, OS); return; } // Use the CppHashFilename and calculate a line number based on the // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc // for the diagnostic. const std::string &Filename = Parser->CppHashInfo.Filename; int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf); int CppHashLocLineNo = Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf); int LineNo = Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo); SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo, Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(), Diag.getLineContents(), Diag.getRanges()); if (Parser->SavedDiagHandler) Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext); else NewDiag.print(nullptr, OS); } // FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The // difference being that that function accepts '@' as part of identifiers and // we can't do that. AsmLexer.cpp should probably be changed to handle // '@' as a special case when needed. static bool isIdentifierChar(char c) { return isalnum(static_cast(c)) || c == '_' || c == '$' || c == '.'; } bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, ArrayRef Parameters, ArrayRef A, bool EnableAtPseudoVariable, SMLoc L) { unsigned NParameters = Parameters.size(); bool HasVararg = NParameters ? Parameters.back().Vararg : false; if ((!IsDarwin || NParameters != 0) && NParameters != A.size()) return Error(L, "Wrong number of arguments"); // A macro without parameters is handled differently on Darwin: // gas accepts no arguments and does no substitutions while (!Body.empty()) { // Scan for the next substitution. std::size_t End = Body.size(), Pos = 0; for (; Pos != End; ++Pos) { // Check for a substitution or escape. if (IsDarwin && !NParameters) { // This macro has no parameters, look for $0, $1, etc. if (Body[Pos] != '$' || Pos + 1 == End) continue; char Next = Body[Pos + 1]; if (Next == '$' || Next == 'n' || isdigit(static_cast(Next))) break; } else { // This macro has parameters, look for \foo, \bar, etc. if (Body[Pos] == '\\' && Pos + 1 != End) break; } } // Add the prefix. OS << Body.slice(0, Pos); // Check if we reached the end. if (Pos == End) break; if (IsDarwin && !NParameters) { switch (Body[Pos + 1]) { // $$ => $ case '$': OS << '$'; break; // $n => number of arguments case 'n': OS << A.size(); break; // $[0-9] => argument default: { // Missing arguments are ignored. unsigned Index = Body[Pos + 1] - '0'; if (Index >= A.size()) break; // Otherwise substitute with the token values, with spaces eliminated. for (const AsmToken &Token : A[Index]) OS << Token.getString(); break; } } Pos += 2; } else { unsigned I = Pos + 1; // Check for the \@ pseudo-variable. if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End) ++I; else while (isIdentifierChar(Body[I]) && I + 1 != End) ++I; const char *Begin = Body.data() + Pos + 1; StringRef Argument(Begin, I - (Pos + 1)); unsigned Index = 0; if (Argument == "@") { OS << NumOfMacroInstantiations; Pos += 2; } else { for (; Index < NParameters; ++Index) if (Parameters[Index].Name == Argument) break; if (Index == NParameters) { if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') Pos += 3; else { OS << '\\' << Argument; Pos = I; } } else { bool VarargParameter = HasVararg && Index == (NParameters - 1); for (const AsmToken &Token : A[Index]) // For altmacro mode, you can write '%expr'. // The prefix '%' evaluates the expression 'expr' // and uses the result as a string (e.g. replace %(1+2) with the string "3"). // Here, we identify the integer token which is the result of the // absolute expression evaluation and replace it with its string representation. if ((Lexer.IsaAltMacroMode()) && (*(Token.getString().begin()) == '%') && Token.is(AsmToken::Integer)) // Emit an integer value to the buffer. OS << Token.getIntVal(); // Only Token that was validated as a string and begins with '<' // is considered altMacroString!!! else if ((Lexer.IsaAltMacroMode()) && (*(Token.getString().begin()) == '<') && Token.is(AsmToken::String)) { std::string Res; altMacroString(Token.getStringContents(), Res); OS << Res; } // We expect no quotes around the string's contents when // parsing for varargs. else if (Token.isNot(AsmToken::String) || VarargParameter) OS << Token.getString(); else OS << Token.getStringContents(); Pos += 1 + Argument.size(); } } } // Update the scan point. Body = Body.substr(Pos); } return false; } MacroInstantiation::MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth) : InstantiationLoc(IL), ExitBuffer(EB), ExitLoc(EL), CondStackDepth(CondStackDepth) {} static bool isOperator(AsmToken::TokenKind kind) { switch (kind) { default: return false; case AsmToken::Plus: case AsmToken::Minus: case AsmToken::Tilde: case AsmToken::Slash: case AsmToken::Star: case AsmToken::Dot: case AsmToken::Equal: case AsmToken::EqualEqual: case AsmToken::Pipe: case AsmToken::PipePipe: case AsmToken::Caret: case AsmToken::Amp: case AsmToken::AmpAmp: case AsmToken::Exclaim: case AsmToken::ExclaimEqual: case AsmToken::Less: case AsmToken::LessEqual: case AsmToken::LessLess: case AsmToken::LessGreater: case AsmToken::Greater: case AsmToken::GreaterEqual: case AsmToken::GreaterGreater: return true; } } namespace { class AsmLexerSkipSpaceRAII { public: AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) { Lexer.setSkipSpace(SkipSpace); } ~AsmLexerSkipSpaceRAII() { Lexer.setSkipSpace(true); } private: AsmLexer &Lexer; }; } // end anonymous namespace bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) { if (Vararg) { if (Lexer.isNot(AsmToken::EndOfStatement)) { StringRef Str = parseStringToEndOfStatement(); MA.emplace_back(AsmToken::String, Str); } return false; } unsigned ParenLevel = 0; // Darwin doesn't use spaces to delmit arguments. AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin); bool SpaceEaten; while (true) { SpaceEaten = false; if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) return TokError("unexpected token in macro instantiation"); if (ParenLevel == 0) { if (Lexer.is(AsmToken::Comma)) break; if (Lexer.is(AsmToken::Space)) { SpaceEaten = true; Lexer.Lex(); // Eat spaces } // Spaces can delimit parameters, but could also be part an expression. // If the token after a space is an operator, add the token and the next // one into this argument if (!IsDarwin) { if (isOperator(Lexer.getKind())) { MA.push_back(getTok()); Lexer.Lex(); // Whitespace after an operator can be ignored. if (Lexer.is(AsmToken::Space)) Lexer.Lex(); continue; } } if (SpaceEaten) break; } // handleMacroEntry relies on not advancing the lexer here // to be able to fill in the remaining default parameter values if (Lexer.is(AsmToken::EndOfStatement)) break; // Adjust the current parentheses level. if (Lexer.is(AsmToken::LParen)) ++ParenLevel; else if (Lexer.is(AsmToken::RParen) && ParenLevel) --ParenLevel; // Append the token to the current argument list. MA.push_back(getTok()); Lexer.Lex(); } if (ParenLevel != 0) return TokError("unbalanced parentheses in macro argument"); return false; } // Parse the macro instantiation arguments. bool AsmParser::parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A) { const unsigned NParameters = M ? M->Parameters.size() : 0; bool NamedParametersFound = false; SmallVector FALocs; A.resize(NParameters); FALocs.resize(NParameters); // Parse two kinds of macro invocations: // - macros defined without any parameters accept an arbitrary number of them // - macros defined with parameters accept at most that many of them bool HasVararg = NParameters ? M->Parameters.back().Vararg : false; for (unsigned Parameter = 0; !NParameters || Parameter < NParameters; ++Parameter) { SMLoc IDLoc = Lexer.getLoc(); MCAsmMacroParameter FA; if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) { if (parseIdentifier(FA.Name)) return Error(IDLoc, "invalid argument identifier for formal argument"); if (Lexer.isNot(AsmToken::Equal)) return TokError("expected '=' after formal parameter identifier"); Lex(); NamedParametersFound = true; } bool Vararg = HasVararg && Parameter == (NParameters - 1); if (NamedParametersFound && FA.Name.empty()) return Error(IDLoc, "cannot mix positional and keyword arguments"); SMLoc StrLoc = Lexer.getLoc(); SMLoc EndLoc; if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Percent)) { const MCExpr *AbsoluteExp; int64_t Value; /// Eat '%' Lex(); if (parseExpression(AbsoluteExp, EndLoc)) return false; if (!AbsoluteExp->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) return Error(StrLoc, "expected absolute expression"); const char *StrChar = StrLoc.getPointer(); const char *EndChar = EndLoc.getPointer(); AsmToken newToken(AsmToken::Integer, StringRef(StrChar , EndChar - StrChar), Value); FA.Value.push_back(newToken); } else if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Less) && isAltmacroString(StrLoc, EndLoc)) { const char *StrChar = StrLoc.getPointer(); const char *EndChar = EndLoc.getPointer(); jumpToLoc(EndLoc, CurBuffer); /// Eat from '<' to '>' Lex(); AsmToken newToken(AsmToken::String, StringRef(StrChar, EndChar - StrChar)); FA.Value.push_back(newToken); } else if(parseMacroArgument(FA.Value, Vararg)) return true; unsigned PI = Parameter; if (!FA.Name.empty()) { unsigned FAI = 0; for (FAI = 0; FAI < NParameters; ++FAI) if (M->Parameters[FAI].Name == FA.Name) break; if (FAI >= NParameters) { assert(M && "expected macro to be defined"); return Error(IDLoc, "parameter named '" + FA.Name + "' does not exist for macro '" + M->Name + "'"); } PI = FAI; } if (!FA.Value.empty()) { if (A.size() <= PI) A.resize(PI + 1); A[PI] = FA.Value; if (FALocs.size() <= PI) FALocs.resize(PI + 1); FALocs[PI] = Lexer.getLoc(); } // At the end of the statement, fill in remaining arguments that have // default values. If there aren't any, then the next argument is // required but missing if (Lexer.is(AsmToken::EndOfStatement)) { bool Failure = false; for (unsigned FAI = 0; FAI < NParameters; ++FAI) { if (A[FAI].empty()) { if (M->Parameters[FAI].Required) { Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(), "missing value for required parameter " "'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'"); Failure = true; } if (!M->Parameters[FAI].Value.empty()) A[FAI] = M->Parameters[FAI].Value; } } return Failure; } if (Lexer.is(AsmToken::Comma)) Lex(); } return TokError("too many positional arguments"); } bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { // Arbitrarily limit macro nesting depth (default matches 'as'). We can // eliminate this, although we should protect against infinite loops. unsigned MaxNestingDepth = AsmMacroMaxNestingDepth; if (ActiveMacros.size() == MaxNestingDepth) { std::ostringstream MaxNestingDepthError; MaxNestingDepthError << "macros cannot be nested more than " << MaxNestingDepth << " levels deep." << " Use -asm-macro-max-nesting-depth to increase " "this limit."; return TokError(MaxNestingDepthError.str()); } MCAsmMacroArguments A; if (parseMacroArguments(M, A)) return true; // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. SmallString<256> Buf; StringRef Body = M->Body; raw_svector_ostream OS(Buf); if (expandMacro(OS, Body, M->Parameters, A, true, getTok().getLoc())) return true; // We include the .endmacro in the buffer as our cue to exit the macro // instantiation. OS << ".endmacro\n"; std::unique_ptr Instantiation = MemoryBuffer::getMemBufferCopy(OS.str(), ""); // Create the macro instantiation object and add to the current macro // instantiation stack. MacroInstantiation *MI = new MacroInstantiation( NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()); ActiveMacros.push_back(MI); ++NumOfMacroInstantiations; // Jump to the macro instantiation and prime the lexer. CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc()); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); Lex(); return false; } void AsmParser::handleMacroExit() { // Jump to the EndOfStatement we should return to, and consume it. jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer); Lex(); // Pop the instantiation entry. delete ActiveMacros.back(); ActiveMacros.pop_back(); } bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, - bool NoDeadStrip, bool AllowExtendedExpr) { + bool NoDeadStrip) { MCSymbol *Sym; const MCExpr *Value; if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym, - Value, AllowExtendedExpr)) + Value)) return true; if (!Sym) { // In the case where we parse an expression starting with a '.', we will // not generate an error, nor will we create a symbol. In this case we // should just return out. return false; } // Do the assignment. Out.EmitAssignment(Sym, Value); if (NoDeadStrip) Out.EmitSymbolAttribute(Sym, MCSA_NoDeadStrip); return false; } /// parseIdentifier: /// ::= identifier /// ::= string bool AsmParser::parseIdentifier(StringRef &Res) { // The assembler has relaxed rules for accepting identifiers, in particular we // allow things like '.globl $foo' and '.def @feat.00', which would normally be // separate tokens. At this level, we have already lexed so we cannot (currently) // handle this as a context dependent token, instead we detect adjacent tokens // and return the combined identifier. if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) { SMLoc PrefixLoc = getLexer().getLoc(); // Consume the prefix character, and check for a following identifier. AsmToken Buf[1]; Lexer.peekTokens(Buf, false); if (Buf[0].isNot(AsmToken::Identifier)) return true; // We have a '$' or '@' followed by an identifier, make sure they are adjacent. if (PrefixLoc.getPointer() + 1 != Buf[0].getLoc().getPointer()) return true; // eat $ or @ Lexer.Lex(); // Lexer's Lex guarantees consecutive token. // Construct the joined identifier and consume the token. Res = StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1); Lex(); // Parser Lex to maintain invariants. return false; } if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String)) return true; Res = getTok().getIdentifier(); Lex(); // Consume the identifier token. return false; } /// parseDirectiveSet: /// ::= .equ identifier ',' expression /// ::= .equiv identifier ',' expression /// ::= .set identifier ',' expression bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) { StringRef Name; if (check(parseIdentifier(Name), "expected identifier") || parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } bool AsmParser::parseEscapedString(std::string &Data) { if (check(getTok().isNot(AsmToken::String), "expected string")) return true; Data = ""; StringRef Str = getTok().getStringContents(); for (unsigned i = 0, e = Str.size(); i != e; ++i) { if (Str[i] != '\\') { Data += Str[i]; continue; } // Recognize escaped characters. Note that this escape semantics currently // loosely follows Darwin 'as'. Notably, it doesn't support hex escapes. ++i; if (i == e) return TokError("unexpected backslash at end of string"); // Recognize octal sequences. if ((unsigned)(Str[i] - '0') <= 7) { // Consume up to three octal characters. unsigned Value = Str[i] - '0'; if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) { ++i; Value = Value * 8 + (Str[i] - '0'); if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) { ++i; Value = Value * 8 + (Str[i] - '0'); } } if (Value > 255) return TokError("invalid octal escape sequence (out of range)"); Data += (unsigned char)Value; continue; } // Otherwise recognize individual escapes. switch (Str[i]) { default: // Just reject invalid escape sequences for now. return TokError("invalid escape sequence (unrecognized character)"); case 'b': Data += '\b'; break; case 'f': Data += '\f'; break; case 'n': Data += '\n'; break; case 'r': Data += '\r'; break; case 't': Data += '\t'; break; case '"': Data += '"'; break; case '\\': Data += '\\'; break; } } Lex(); return false; } /// parseDirectiveAscii: /// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ] bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { auto parseOp = [&]() -> bool { std::string Data; if (checkForValidSection() || parseEscapedString(Data)) return true; getStreamer().EmitBytes(Data); if (ZeroTerminated) getStreamer().EmitBytes(StringRef("\0", 1)); return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } /// parseDirectiveReloc /// ::= .reloc expression , identifier [ , expression ] bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) { const MCExpr *Offset; const MCExpr *Expr = nullptr; SMLoc OffsetLoc = Lexer.getTok().getLoc(); int64_t OffsetValue; // We can only deal with constant expressions at the moment. if (parseExpression(Offset)) return true; if (check(!Offset->evaluateAsAbsolute(OffsetValue, getStreamer().getAssemblerPtr()), OffsetLoc, "expression is not a constant value") || check(OffsetValue < 0, OffsetLoc, "expression is negative") || parseToken(AsmToken::Comma, "expected comma") || check(getTok().isNot(AsmToken::Identifier), "expected relocation name")) return true; SMLoc NameLoc = Lexer.getTok().getLoc(); StringRef Name = Lexer.getTok().getIdentifier(); Lex(); if (Lexer.is(AsmToken::Comma)) { Lex(); SMLoc ExprLoc = Lexer.getLoc(); if (parseExpression(Expr)) return true; MCValue Value; if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr)) return Error(ExprLoc, "expression must be relocatable"); } if (parseToken(AsmToken::EndOfStatement, "unexpected token in .reloc directive")) return true; const MCTargetAsmParser &MCT = getTargetParser(); const MCSubtargetInfo &STI = MCT.getSTI(); if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc, STI)) return Error(NameLoc, "unknown relocation name"); return false; } /// parseDirectiveValue /// ::= (.byte | .short | ... ) [ expression (, expression)* ] bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) { auto parseOp = [&]() -> bool { const MCExpr *Value; SMLoc ExprLoc = getLexer().getLoc(); if (checkForValidSection() || parseExpression(Value)) return true; // Special case constant expressions to match code generator. if (const MCConstantExpr *MCE = dyn_cast(Value)) { assert(Size <= 8 && "Invalid size"); uint64_t IntValue = MCE->getValue(); if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) return Error(ExprLoc, "out of range literal value"); getStreamer().EmitIntValue(IntValue, Size); } else getStreamer().EmitValue(Value, Size, ExprLoc); return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) { if (Asm.getTok().isNot(AsmToken::Integer) && Asm.getTok().isNot(AsmToken::BigNum)) return Asm.TokError("unknown token in expression"); SMLoc ExprLoc = Asm.getTok().getLoc(); APInt IntValue = Asm.getTok().getAPIntVal(); Asm.Lex(); if (!IntValue.isIntN(128)) return Asm.Error(ExprLoc, "out of range literal value"); if (!IntValue.isIntN(64)) { hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue(); lo = IntValue.getLoBits(64).getZExtValue(); } else { hi = 0; lo = IntValue.getZExtValue(); } return false; } /// ParseDirectiveOctaValue /// ::= .octa [ hexconstant (, hexconstant)* ] bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) { auto parseOp = [&]() -> bool { if (checkForValidSection()) return true; uint64_t hi, lo; if (parseHexOcta(*this, hi, lo)) return true; if (MAI.isLittleEndian()) { getStreamer().EmitIntValue(lo, 8); getStreamer().EmitIntValue(hi, 8); } else { getStreamer().EmitIntValue(hi, 8); getStreamer().EmitIntValue(lo, 8); } return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) { // We don't truly support arithmetic on floating point expressions, so we // have to manually parse unary prefixes. bool IsNeg = false; if (getLexer().is(AsmToken::Minus)) { Lexer.Lex(); IsNeg = true; } else if (getLexer().is(AsmToken::Plus)) Lexer.Lex(); if (Lexer.is(AsmToken::Error)) return TokError(Lexer.getErr()); if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) && Lexer.isNot(AsmToken::Identifier)) return TokError("unexpected token in directive"); // Convert to an APFloat. APFloat Value(Semantics); StringRef IDVal = getTok().getString(); if (getLexer().is(AsmToken::Identifier)) { if (!IDVal.compare_lower("infinity") || !IDVal.compare_lower("inf")) Value = APFloat::getInf(Semantics); else if (!IDVal.compare_lower("nan")) Value = APFloat::getNaN(Semantics, false, ~0); else return TokError("invalid floating point literal"); } else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) == APFloat::opInvalidOp) return TokError("invalid floating point literal"); if (IsNeg) Value.changeSign(); // Consume the numeric token. Lex(); Res = Value.bitcastToAPInt(); return false; } /// parseDirectiveRealValue /// ::= (.single | .double) [ expression (, expression)* ] bool AsmParser::parseDirectiveRealValue(StringRef IDVal, const fltSemantics &Semantics) { auto parseOp = [&]() -> bool { APInt AsInt; if (checkForValidSection() || parseRealValue(Semantics, AsInt)) return true; getStreamer().EmitIntValue(AsInt.getLimitedValue(), AsInt.getBitWidth() / 8); return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); return false; } /// parseDirectiveZero /// ::= .zero expression bool AsmParser::parseDirectiveZero() { SMLoc NumBytesLoc = Lexer.getLoc(); const MCExpr *NumBytes; if (checkForValidSection() || parseExpression(NumBytes)) return true; int64_t Val = 0; if (getLexer().is(AsmToken::Comma)) { Lex(); if (parseAbsoluteExpression(Val)) return true; } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.zero' directive")) return true; getStreamer().emitFill(*NumBytes, Val, NumBytesLoc); return false; } /// parseDirectiveFill /// ::= .fill expression [ , expression [ , expression ] ] bool AsmParser::parseDirectiveFill() { SMLoc NumValuesLoc = Lexer.getLoc(); const MCExpr *NumValues; if (checkForValidSection() || parseExpression(NumValues)) return true; int64_t FillSize = 1; int64_t FillExpr = 0; SMLoc SizeLoc, ExprLoc; if (parseOptionalToken(AsmToken::Comma)) { SizeLoc = getTok().getLoc(); if (parseAbsoluteExpression(FillSize)) return true; if (parseOptionalToken(AsmToken::Comma)) { ExprLoc = getTok().getLoc(); if (parseAbsoluteExpression(FillExpr)) return true; } } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.fill' directive")) return true; if (FillSize < 0) { Warning(SizeLoc, "'.fill' directive with negative size has no effect"); return false; } if (FillSize > 8) { Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8"); FillSize = 8; } if (!isUInt<32>(FillExpr) && FillSize > 4) Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits"); getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc); return false; } /// parseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::parseDirectiveOrg() { const MCExpr *Offset; SMLoc OffsetLoc = Lexer.getLoc(); if (checkForValidSection() || parseExpression(Offset)) return true; // Parse optional fill expression. int64_t FillExpr = 0; if (parseOptionalToken(AsmToken::Comma)) if (parseAbsoluteExpression(FillExpr)) return addErrorSuffix(" in '.org' directive"); if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.org' directive"); getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc); return false; } /// parseDirectiveAlign /// ::= {.align, ...} expression [ , expression [ , expression ]] bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { SMLoc AlignmentLoc = getLexer().getLoc(); int64_t Alignment; SMLoc MaxBytesLoc; bool HasFillExpr = false; int64_t FillExpr = 0; int64_t MaxBytesToFill = 0; auto parseAlign = [&]() -> bool { if (parseAbsoluteExpression(Alignment)) return true; if (parseOptionalToken(AsmToken::Comma)) { // The fill expression can be omitted while specifying a maximum number of // alignment bytes, e.g: // .align 3,,4 if (getTok().isNot(AsmToken::Comma)) { HasFillExpr = true; if (parseAbsoluteExpression(FillExpr)) return true; } if (parseOptionalToken(AsmToken::Comma)) if (parseTokenLoc(MaxBytesLoc) || parseAbsoluteExpression(MaxBytesToFill)) return true; } return parseToken(AsmToken::EndOfStatement); }; if (checkForValidSection()) return addErrorSuffix(" in directive"); // Ignore empty '.p2align' directives for GNU-as compatibility if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) { Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored"); return parseToken(AsmToken::EndOfStatement); } if (parseAlign()) return addErrorSuffix(" in directive"); // Always emit an alignment here even if we thrown an error. bool ReturnVal = false; // Compute alignment in bytes. if (IsPow2) { // FIXME: Diagnose overflow. if (Alignment >= 32) { ReturnVal |= Error(AlignmentLoc, "invalid alignment value"); Alignment = 31; } Alignment = 1ULL << Alignment; } else { // Reject alignments that aren't either a power of two or zero, // for gas compatibility. Alignment of zero is silently rounded // up to one. if (Alignment == 0) Alignment = 1; if (!isPowerOf2_64(Alignment)) ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2"); } // Diagnose non-sensical max bytes to align. if (MaxBytesLoc.isValid()) { if (MaxBytesToFill < 1) { ReturnVal |= Error(MaxBytesLoc, "alignment directive can never be satisfied in this " "many bytes, ignoring maximum bytes expression"); MaxBytesToFill = 0; } if (MaxBytesToFill >= Alignment) { Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and " "has no effect"); MaxBytesToFill = 0; } } // Check whether we should use optimal code alignment for this .align // directive. const MCSection *Section = getStreamer().getCurrentSectionOnly(); assert(Section && "must have section to emit alignment"); bool UseCodeAlign = Section->UseCodeAlign(); if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && ValueSize == 1 && UseCodeAlign) { getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill); } else { // FIXME: Target specific behavior about how the "extra" bytes are filled. getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); } return ReturnVal; } /// parseDirectiveFile /// ::= .file filename /// ::= .file number [directory] filename [md5 checksum] [source source-text] bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { // FIXME: I'm not sure what this is. int64_t FileNumber = -1; if (getLexer().is(AsmToken::Integer)) { FileNumber = getTok().getIntVal(); Lex(); if (FileNumber < 0) return TokError("negative file number"); } std::string Path; // Usually the directory and filename together, otherwise just the directory. // Allow the strings to have escaped octal character sequence. if (check(getTok().isNot(AsmToken::String), "unexpected token in '.file' directive") || parseEscapedString(Path)) return true; StringRef Directory; StringRef Filename; std::string FilenameData; if (getLexer().is(AsmToken::String)) { if (check(FileNumber == -1, "explicit path specified, but no file number") || parseEscapedString(FilenameData)) return true; Filename = FilenameData; Directory = Path; } else { Filename = Path; } uint64_t MD5Hi, MD5Lo; bool HasMD5 = false; Optional Source; bool HasSource = false; std::string SourceString; while (!parseOptionalToken(AsmToken::EndOfStatement)) { StringRef Keyword; if (check(getTok().isNot(AsmToken::Identifier), "unexpected token in '.file' directive") || parseIdentifier(Keyword)) return true; if (Keyword == "md5") { HasMD5 = true; if (check(FileNumber == -1, "MD5 checksum specified, but no file number") || parseHexOcta(*this, MD5Hi, MD5Lo)) return true; } else if (Keyword == "source") { HasSource = true; if (check(FileNumber == -1, "source specified, but no file number") || check(getTok().isNot(AsmToken::String), "unexpected token in '.file' directive") || parseEscapedString(SourceString)) return true; } else { return TokError("unexpected token in '.file' directive"); } } // In case there is a -g option as well as debug info from directive .file, // we turn off the -g option, directly use the existing debug info instead. // Also reset any implicit ".file 0" for the assembler source. if (Ctx.getGenDwarfForAssembly()) { Ctx.getMCDwarfLineTable(0).resetRootFile(); Ctx.setGenDwarfForAssembly(false); } if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { MD5::MD5Result *CKMem = nullptr; if (HasMD5) { CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); for (unsigned i = 0; i != 8; ++i) { CKMem->Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8)); CKMem->Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8)); } } if (HasSource) { char *SourceBuf = static_cast(Ctx.allocate(SourceString.size())); memcpy(SourceBuf, SourceString.data(), SourceString.size()); Source = StringRef(SourceBuf, SourceString.size()); } if (FileNumber == 0) { if (Ctx.getDwarfVersion() < 5) return Warning(DirectiveLoc, "file 0 not supported prior to DWARF-5"); getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source); } else { Expected FileNumOrErr = getStreamer().tryEmitDwarfFileDirective( FileNumber, Directory, Filename, CKMem, Source); if (!FileNumOrErr) return Error(DirectiveLoc, toString(FileNumOrErr.takeError())); FileNumber = FileNumOrErr.get(); } // Alert the user if there are some .file directives with MD5 and some not. // But only do that once. if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) { ReportedInconsistentMD5 = true; return Warning(DirectiveLoc, "inconsistent use of MD5 checksums"); } } return false; } /// parseDirectiveLine /// ::= .line [number] bool AsmParser::parseDirectiveLine() { int64_t LineNumber; if (getLexer().is(AsmToken::Integer)) { if (parseIntToken(LineNumber, "unexpected token in '.line' directive")) return true; (void)LineNumber; // FIXME: Do something with the .line. } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.line' directive")) return true; return false; } /// parseDirectiveLoc /// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end] /// [epilogue_begin] [is_stmt VALUE] [isa VALUE] /// The first number is a file number, must have been previously assigned with /// a .file directive, the second number is the line number and optionally the /// third number is a column position (zero if not specified). The remaining /// optional items are .loc sub-directives. bool AsmParser::parseDirectiveLoc() { int64_t FileNumber = 0, LineNumber = 0; SMLoc Loc = getTok().getLoc(); if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") || check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc, "file number less than one in '.loc' directive") || check(!getContext().isValidDwarfFileNumber(FileNumber), Loc, "unassigned file number in '.loc' directive")) return true; // optional if (getLexer().is(AsmToken::Integer)) { LineNumber = getTok().getIntVal(); if (LineNumber < 0) return TokError("line number less than zero in '.loc' directive"); Lex(); } int64_t ColumnPos = 0; if (getLexer().is(AsmToken::Integer)) { ColumnPos = getTok().getIntVal(); if (ColumnPos < 0) return TokError("column position less than zero in '.loc' directive"); Lex(); } unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; unsigned Isa = 0; int64_t Discriminator = 0; auto parseLocOp = [&]() -> bool { StringRef Name; SMLoc Loc = getTok().getLoc(); if (parseIdentifier(Name)) return TokError("unexpected token in '.loc' directive"); if (Name == "basic_block") Flags |= DWARF2_FLAG_BASIC_BLOCK; else if (Name == "prologue_end") Flags |= DWARF2_FLAG_PROLOGUE_END; else if (Name == "epilogue_begin") Flags |= DWARF2_FLAG_EPILOGUE_BEGIN; else if (Name == "is_stmt") { Loc = getTok().getLoc(); const MCExpr *Value; if (parseExpression(Value)) return true; // The expression must be the constant 0 or 1. if (const MCConstantExpr *MCE = dyn_cast(Value)) { int Value = MCE->getValue(); if (Value == 0) Flags &= ~DWARF2_FLAG_IS_STMT; else if (Value == 1) Flags |= DWARF2_FLAG_IS_STMT; else return Error(Loc, "is_stmt value not 0 or 1"); } else { return Error(Loc, "is_stmt value not the constant value of 0 or 1"); } } else if (Name == "isa") { Loc = getTok().getLoc(); const MCExpr *Value; if (parseExpression(Value)) return true; // The expression must be a constant greater or equal to 0. if (const MCConstantExpr *MCE = dyn_cast(Value)) { int Value = MCE->getValue(); if (Value < 0) return Error(Loc, "isa number less than zero"); Isa = Value; } else { return Error(Loc, "isa number not a constant value"); } } else if (Name == "discriminator") { if (parseAbsoluteExpression(Discriminator)) return true; } else { return Error(Loc, "unknown sub-directive in '.loc' directive"); } return false; }; if (parseMany(parseLocOp, false /*hasComma*/)) return true; getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags, Isa, Discriminator, StringRef()); return false; } /// parseDirectiveStabs /// ::= .stabs string, number, number, number bool AsmParser::parseDirectiveStabs() { return TokError("unsupported directive '.stabs'"); } /// parseDirectiveCVFile /// ::= .cv_file number filename [checksum] [checksumkind] bool AsmParser::parseDirectiveCVFile() { SMLoc FileNumberLoc = getTok().getLoc(); int64_t FileNumber; std::string Filename; std::string Checksum; int64_t ChecksumKind = 0; if (parseIntToken(FileNumber, "expected file number in '.cv_file' directive") || check(FileNumber < 1, FileNumberLoc, "file number less than one") || check(getTok().isNot(AsmToken::String), "unexpected token in '.cv_file' directive") || parseEscapedString(Filename)) return true; if (!parseOptionalToken(AsmToken::EndOfStatement)) { if (check(getTok().isNot(AsmToken::String), "unexpected token in '.cv_file' directive") || parseEscapedString(Checksum) || parseIntToken(ChecksumKind, "expected checksum kind in '.cv_file' directive") || parseToken(AsmToken::EndOfStatement, "unexpected token in '.cv_file' directive")) return true; } Checksum = fromHex(Checksum); void *CKMem = Ctx.allocate(Checksum.size(), 1); memcpy(CKMem, Checksum.data(), Checksum.size()); ArrayRef ChecksumAsBytes(reinterpret_cast(CKMem), Checksum.size()); if (!getStreamer().EmitCVFileDirective(FileNumber, Filename, ChecksumAsBytes, static_cast(ChecksumKind))) return Error(FileNumberLoc, "file number already allocated"); return false; } bool AsmParser::parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName) { SMLoc Loc; return parseTokenLoc(Loc) || parseIntToken(FunctionId, "expected function id in '" + DirectiveName + "' directive") || check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc, "expected function id within range [0, UINT_MAX)"); } bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) { SMLoc Loc; return parseTokenLoc(Loc) || parseIntToken(FileNumber, "expected integer in '" + DirectiveName + "' directive") || check(FileNumber < 1, Loc, "file number less than one in '" + DirectiveName + "' directive") || check(!getCVContext().isValidFileNumber(FileNumber), Loc, "unassigned file number in '" + DirectiveName + "' directive"); } /// parseDirectiveCVFuncId /// ::= .cv_func_id FunctionId /// /// Introduces a function ID that can be used with .cv_loc. bool AsmParser::parseDirectiveCVFuncId() { SMLoc FunctionIdLoc = getTok().getLoc(); int64_t FunctionId; if (parseCVFunctionId(FunctionId, ".cv_func_id") || parseToken(AsmToken::EndOfStatement, "unexpected token in '.cv_func_id' directive")) return true; if (!getStreamer().EmitCVFuncIdDirective(FunctionId)) return Error(FunctionIdLoc, "function id already allocated"); return false; } /// parseDirectiveCVInlineSiteId /// ::= .cv_inline_site_id FunctionId /// "within" IAFunc /// "inlined_at" IAFile IALine [IACol] /// /// Introduces a function ID that can be used with .cv_loc. Includes "inlined /// at" source location information for use in the line table of the caller, /// whether the caller is a real function or another inlined call site. bool AsmParser::parseDirectiveCVInlineSiteId() { SMLoc FunctionIdLoc = getTok().getLoc(); int64_t FunctionId; int64_t IAFunc; int64_t IAFile; int64_t IALine; int64_t IACol = 0; // FunctionId if (parseCVFunctionId(FunctionId, ".cv_inline_site_id")) return true; // "within" if (check((getLexer().isNot(AsmToken::Identifier) || getTok().getIdentifier() != "within"), "expected 'within' identifier in '.cv_inline_site_id' directive")) return true; Lex(); // IAFunc if (parseCVFunctionId(IAFunc, ".cv_inline_site_id")) return true; // "inlined_at" if (check((getLexer().isNot(AsmToken::Identifier) || getTok().getIdentifier() != "inlined_at"), "expected 'inlined_at' identifier in '.cv_inline_site_id' " "directive") ) return true; Lex(); // IAFile IALine if (parseCVFileId(IAFile, ".cv_inline_site_id") || parseIntToken(IALine, "expected line number after 'inlined_at'")) return true; // [IACol] if (getLexer().is(AsmToken::Integer)) { IACol = getTok().getIntVal(); Lex(); } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.cv_inline_site_id' directive")) return true; if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile, IALine, IACol, FunctionIdLoc)) return Error(FunctionIdLoc, "function id already allocated"); return false; } /// parseDirectiveCVLoc /// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end] /// [is_stmt VALUE] /// The first number is a file number, must have been previously assigned with /// a .file directive, the second number is the line number and optionally the /// third number is a column position (zero if not specified). The remaining /// optional items are .loc sub-directives. bool AsmParser::parseDirectiveCVLoc() { SMLoc DirectiveLoc = getTok().getLoc(); int64_t FunctionId, FileNumber; if (parseCVFunctionId(FunctionId, ".cv_loc") || parseCVFileId(FileNumber, ".cv_loc")) return true; int64_t LineNumber = 0; if (getLexer().is(AsmToken::Integer)) { LineNumber = getTok().getIntVal(); if (LineNumber < 0) return TokError("line number less than zero in '.cv_loc' directive"); Lex(); } int64_t ColumnPos = 0; if (getLexer().is(AsmToken::Integer)) { ColumnPos = getTok().getIntVal(); if (ColumnPos < 0) return TokError("column position less than zero in '.cv_loc' directive"); Lex(); } bool PrologueEnd = false; uint64_t IsStmt = 0; auto parseOp = [&]() -> bool { StringRef Name; SMLoc Loc = getTok().getLoc(); if (parseIdentifier(Name)) return TokError("unexpected token in '.cv_loc' directive"); if (Name == "prologue_end") PrologueEnd = true; else if (Name == "is_stmt") { Loc = getTok().getLoc(); const MCExpr *Value; if (parseExpression(Value)) return true; // The expression must be the constant 0 or 1. IsStmt = ~0ULL; if (const auto *MCE = dyn_cast(Value)) IsStmt = MCE->getValue(); if (IsStmt > 1) return Error(Loc, "is_stmt value not 0 or 1"); } else { return Error(Loc, "unknown sub-directive in '.cv_loc' directive"); } return false; }; if (parseMany(parseOp, false /*hasComma*/)) return true; getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber, ColumnPos, PrologueEnd, IsStmt, StringRef(), DirectiveLoc); return false; } /// parseDirectiveCVLinetable /// ::= .cv_linetable FunctionId, FnStart, FnEnd bool AsmParser::parseDirectiveCVLinetable() { int64_t FunctionId; StringRef FnStartName, FnEndName; SMLoc Loc = getTok().getLoc(); if (parseCVFunctionId(FunctionId, ".cv_linetable") || parseToken(AsmToken::Comma, "unexpected token in '.cv_linetable' directive") || parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, "expected identifier in directive") || parseToken(AsmToken::Comma, "unexpected token in '.cv_linetable' directive") || parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, "expected identifier in directive")) return true; MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName); MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName); getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym); return false; } /// parseDirectiveCVInlineLinetable /// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd bool AsmParser::parseDirectiveCVInlineLinetable() { int64_t PrimaryFunctionId, SourceFileId, SourceLineNum; StringRef FnStartName, FnEndName; SMLoc Loc = getTok().getLoc(); if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") || parseTokenLoc(Loc) || parseIntToken( SourceFileId, "expected SourceField in '.cv_inline_linetable' directive") || check(SourceFileId <= 0, Loc, "File id less than zero in '.cv_inline_linetable' directive") || parseTokenLoc(Loc) || parseIntToken( SourceLineNum, "expected SourceLineNum in '.cv_inline_linetable' directive") || check(SourceLineNum < 0, Loc, "Line number less than zero in '.cv_inline_linetable' directive") || parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc, "expected identifier in directive") || parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc, "expected identifier in directive")) return true; if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement")) return true; MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName); MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName); getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym); return false; } /// parseDirectiveCVDefRange /// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes* bool AsmParser::parseDirectiveCVDefRange() { SMLoc Loc; std::vector> Ranges; while (getLexer().is(AsmToken::Identifier)) { Loc = getLexer().getLoc(); StringRef GapStartName; if (parseIdentifier(GapStartName)) return Error(Loc, "expected identifier in directive"); MCSymbol *GapStartSym = getContext().getOrCreateSymbol(GapStartName); Loc = getLexer().getLoc(); StringRef GapEndName; if (parseIdentifier(GapEndName)) return Error(Loc, "expected identifier in directive"); MCSymbol *GapEndSym = getContext().getOrCreateSymbol(GapEndName); Ranges.push_back({GapStartSym, GapEndSym}); } std::string FixedSizePortion; if (parseToken(AsmToken::Comma, "unexpected token in directive") || parseEscapedString(FixedSizePortion)) return true; getStreamer().EmitCVDefRangeDirective(Ranges, FixedSizePortion); return false; } /// parseDirectiveCVStringTable /// ::= .cv_stringtable bool AsmParser::parseDirectiveCVStringTable() { getStreamer().EmitCVStringTableDirective(); return false; } /// parseDirectiveCVFileChecksums /// ::= .cv_filechecksums bool AsmParser::parseDirectiveCVFileChecksums() { getStreamer().EmitCVFileChecksumsDirective(); return false; } /// parseDirectiveCVFileChecksumOffset /// ::= .cv_filechecksumoffset fileno bool AsmParser::parseDirectiveCVFileChecksumOffset() { int64_t FileNo; if (parseIntToken(FileNo, "expected identifier in directive")) return true; if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement")) return true; getStreamer().EmitCVFileChecksumOffsetDirective(FileNo); return false; } /// parseDirectiveCVFPOData /// ::= .cv_fpo_data procsym bool AsmParser::parseDirectiveCVFPOData() { SMLoc DirLoc = getLexer().getLoc(); StringRef ProcName; if (parseIdentifier(ProcName)) return TokError("expected symbol name"); if (parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_data' directive"); MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName); getStreamer().EmitCVFPOData(ProcSym, DirLoc); return false; } /// parseDirectiveCFISections /// ::= .cfi_sections section [, section] bool AsmParser::parseDirectiveCFISections() { StringRef Name; bool EH = false; bool Debug = false; if (parseIdentifier(Name)) return TokError("Expected an identifier"); if (Name == ".eh_frame") EH = true; else if (Name == ".debug_frame") Debug = true; if (getLexer().is(AsmToken::Comma)) { Lex(); if (parseIdentifier(Name)) return TokError("Expected an identifier"); if (Name == ".eh_frame") EH = true; else if (Name == ".debug_frame") Debug = true; } getStreamer().EmitCFISections(EH, Debug); return false; } /// parseDirectiveCFIStartProc /// ::= .cfi_startproc [simple] bool AsmParser::parseDirectiveCFIStartProc() { StringRef Simple; if (!parseOptionalToken(AsmToken::EndOfStatement)) { if (check(parseIdentifier(Simple) || Simple != "simple", "unexpected token") || parseToken(AsmToken::EndOfStatement)) return addErrorSuffix(" in '.cfi_startproc' directive"); } getStreamer().EmitCFIStartProc(!Simple.empty()); return false; } /// parseDirectiveCFIEndProc /// ::= .cfi_endproc bool AsmParser::parseDirectiveCFIEndProc() { getStreamer().EmitCFIEndProc(); return false; } /// parse register name or number. bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc) { unsigned RegNo; if (getLexer().isNot(AsmToken::Integer)) { if (getTargetParser().ParseRegister(RegNo, DirectiveLoc, DirectiveLoc)) return true; Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo, true); } else return parseAbsoluteExpression(Register); return false; } /// parseDirectiveCFIDefCfa /// ::= .cfi_def_cfa register, offset bool AsmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) { int64_t Register = 0, Offset = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseToken(AsmToken::Comma, "unexpected token in directive") || parseAbsoluteExpression(Offset)) return true; getStreamer().EmitCFIDefCfa(Register, Offset); return false; } /// parseDirectiveCFIDefCfaOffset /// ::= .cfi_def_cfa_offset offset bool AsmParser::parseDirectiveCFIDefCfaOffset() { int64_t Offset = 0; if (parseAbsoluteExpression(Offset)) return true; getStreamer().EmitCFIDefCfaOffset(Offset); return false; } /// parseDirectiveCFIRegister /// ::= .cfi_register register, register bool AsmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) { int64_t Register1 = 0, Register2 = 0; if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) || parseToken(AsmToken::Comma, "unexpected token in directive") || parseRegisterOrRegisterNumber(Register2, DirectiveLoc)) return true; getStreamer().EmitCFIRegister(Register1, Register2); return false; } /// parseDirectiveCFIWindowSave /// ::= .cfi_window_save bool AsmParser::parseDirectiveCFIWindowSave() { getStreamer().EmitCFIWindowSave(); return false; } /// parseDirectiveCFIAdjustCfaOffset /// ::= .cfi_adjust_cfa_offset adjustment bool AsmParser::parseDirectiveCFIAdjustCfaOffset() { int64_t Adjustment = 0; if (parseAbsoluteExpression(Adjustment)) return true; getStreamer().EmitCFIAdjustCfaOffset(Adjustment); return false; } /// parseDirectiveCFIDefCfaRegister /// ::= .cfi_def_cfa_register register bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) { int64_t Register = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; getStreamer().EmitCFIDefCfaRegister(Register); return false; } /// parseDirectiveCFIOffset /// ::= .cfi_offset register, offset bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) { int64_t Register = 0; int64_t Offset = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseToken(AsmToken::Comma, "unexpected token in directive") || parseAbsoluteExpression(Offset)) return true; getStreamer().EmitCFIOffset(Register, Offset); return false; } /// parseDirectiveCFIRelOffset /// ::= .cfi_rel_offset register, offset bool AsmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) { int64_t Register = 0, Offset = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseToken(AsmToken::Comma, "unexpected token in directive") || parseAbsoluteExpression(Offset)) return true; getStreamer().EmitCFIRelOffset(Register, Offset); return false; } static bool isValidEncoding(int64_t Encoding) { if (Encoding & ~0xff) return false; if (Encoding == dwarf::DW_EH_PE_omit) return true; const unsigned Format = Encoding & 0xf; if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 && Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 && Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 && Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed) return false; const unsigned Application = Encoding & 0x70; if (Application != dwarf::DW_EH_PE_absptr && Application != dwarf::DW_EH_PE_pcrel) return false; return true; } /// parseDirectiveCFIPersonalityOrLsda /// IsPersonality true for cfi_personality, false for cfi_lsda /// ::= .cfi_personality encoding, [symbol_name] /// ::= .cfi_lsda encoding, [symbol_name] bool AsmParser::parseDirectiveCFIPersonalityOrLsda(bool IsPersonality) { int64_t Encoding = 0; if (parseAbsoluteExpression(Encoding)) return true; if (Encoding == dwarf::DW_EH_PE_omit) return false; StringRef Name; if (check(!isValidEncoding(Encoding), "unsupported encoding.") || parseToken(AsmToken::Comma, "unexpected token in directive") || check(parseIdentifier(Name), "expected identifier in directive")) return true; MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (IsPersonality) getStreamer().EmitCFIPersonality(Sym, Encoding); else getStreamer().EmitCFILsda(Sym, Encoding); return false; } /// parseDirectiveCFIRememberState /// ::= .cfi_remember_state bool AsmParser::parseDirectiveCFIRememberState() { getStreamer().EmitCFIRememberState(); return false; } /// parseDirectiveCFIRestoreState /// ::= .cfi_remember_state bool AsmParser::parseDirectiveCFIRestoreState() { getStreamer().EmitCFIRestoreState(); return false; } /// parseDirectiveCFISameValue /// ::= .cfi_same_value register bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) { int64_t Register = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; getStreamer().EmitCFISameValue(Register); return false; } /// parseDirectiveCFIRestore /// ::= .cfi_restore register bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) { int64_t Register = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; getStreamer().EmitCFIRestore(Register); return false; } /// parseDirectiveCFIEscape /// ::= .cfi_escape expression[,...] bool AsmParser::parseDirectiveCFIEscape() { std::string Values; int64_t CurrValue; if (parseAbsoluteExpression(CurrValue)) return true; Values.push_back((uint8_t)CurrValue); while (getLexer().is(AsmToken::Comma)) { Lex(); if (parseAbsoluteExpression(CurrValue)) return true; Values.push_back((uint8_t)CurrValue); } getStreamer().EmitCFIEscape(Values); return false; } /// parseDirectiveCFIReturnColumn /// ::= .cfi_return_column register bool AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) { int64_t Register = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; getStreamer().EmitCFIReturnColumn(Register); return false; } /// parseDirectiveCFISignalFrame /// ::= .cfi_signal_frame bool AsmParser::parseDirectiveCFISignalFrame() { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.cfi_signal_frame'")) return true; getStreamer().EmitCFISignalFrame(); return false; } /// parseDirectiveCFIUndefined /// ::= .cfi_undefined register bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) { int64_t Register = 0; if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) return true; getStreamer().EmitCFIUndefined(Register); return false; } /// parseDirectiveAltmacro /// ::= .altmacro /// ::= .noaltmacro bool AsmParser::parseDirectiveAltmacro(StringRef Directive) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); if (Directive == ".altmacro") getLexer().SetAltMacroMode(true); else getLexer().SetAltMacroMode(false); return false; } /// parseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off bool AsmParser::parseDirectiveMacrosOnOff(StringRef Directive) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Directive + "' directive")) return true; setMacrosEnabled(Directive == ".macros_on"); return false; } /// parseDirectiveMacro /// ::= .macro name[,] [parameters] bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) { StringRef Name; if (parseIdentifier(Name)) return TokError("expected identifier in '.macro' directive"); if (getLexer().is(AsmToken::Comma)) Lex(); MCAsmMacroParameters Parameters; while (getLexer().isNot(AsmToken::EndOfStatement)) { if (!Parameters.empty() && Parameters.back().Vararg) return Error(Lexer.getLoc(), "Vararg parameter '" + Parameters.back().Name + "' should be last one in the list of parameters."); MCAsmMacroParameter Parameter; if (parseIdentifier(Parameter.Name)) return TokError("expected identifier in '.macro' directive"); // Emit an error if two (or more) named parameters share the same name for (const MCAsmMacroParameter& CurrParam : Parameters) if (CurrParam.Name.equals(Parameter.Name)) return TokError("macro '" + Name + "' has multiple parameters" " named '" + Parameter.Name + "'"); if (Lexer.is(AsmToken::Colon)) { Lex(); // consume ':' SMLoc QualLoc; StringRef Qualifier; QualLoc = Lexer.getLoc(); if (parseIdentifier(Qualifier)) return Error(QualLoc, "missing parameter qualifier for " "'" + Parameter.Name + "' in macro '" + Name + "'"); if (Qualifier == "req") Parameter.Required = true; else if (Qualifier == "vararg") Parameter.Vararg = true; else return Error(QualLoc, Qualifier + " is not a valid parameter qualifier " "for '" + Parameter.Name + "' in macro '" + Name + "'"); } if (getLexer().is(AsmToken::Equal)) { Lex(); SMLoc ParamLoc; ParamLoc = Lexer.getLoc(); if (parseMacroArgument(Parameter.Value, /*Vararg=*/false )) return true; if (Parameter.Required) Warning(ParamLoc, "pointless default value for required parameter " "'" + Parameter.Name + "' in macro '" + Name + "'"); } Parameters.push_back(std::move(Parameter)); if (getLexer().is(AsmToken::Comma)) Lex(); } // Eat just the end of statement. Lexer.Lex(); // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors AsmToken EndToken, StartToken = getTok(); unsigned MacroDepth = 0; // Lex the macro definition. while (true) { // Ignore Lexing errors in macros. while (Lexer.is(AsmToken::Error)) { Lexer.Lex(); } // Check whether we have reached the end of the file. if (getLexer().is(AsmToken::Eof)) return Error(DirectiveLoc, "no matching '.endmacro' in definition"); // Otherwise, check whether we have reach the .endmacro. if (getLexer().is(AsmToken::Identifier)) { if (getTok().getIdentifier() == ".endm" || getTok().getIdentifier() == ".endmacro") { if (MacroDepth == 0) { // Outermost macro. EndToken = getTok(); Lexer.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + EndToken.getIdentifier() + "' directive"); break; } else { // Otherwise we just found the end of an inner macro. --MacroDepth; } } else if (getTok().getIdentifier() == ".macro") { // We allow nested macros. Those aren't instantiated until the outermost // macro is expanded so just ignore them for now. ++MacroDepth; } } // Otherwise, scan til the end of the statement. eatToEndOfStatement(); } if (getContext().lookupMacro(Name)) { return Error(DirectiveLoc, "macro '" + Name + "' is already defined"); } const char *BodyStart = StartToken.getLoc().getPointer(); const char *BodyEnd = EndToken.getLoc().getPointer(); StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); checkForBadMacro(DirectiveLoc, Name, Body, Parameters); MCAsmMacro Macro(Name, Body, std::move(Parameters)); DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n"; Macro.dump()); getContext().defineMacro(Name, std::move(Macro)); return false; } /// checkForBadMacro /// /// With the support added for named parameters there may be code out there that /// is transitioning from positional parameters. In versions of gas that did /// not support named parameters they would be ignored on the macro definition. /// But to support both styles of parameters this is not possible so if a macro /// definition has named parameters but does not use them and has what appears /// to be positional parameters, strings like $1, $2, ... and $n, then issue a /// warning that the positional parameter found in body which have no effect. /// Hoping the developer will either remove the named parameters from the macro /// definition so the positional parameters get used if that was what was /// intended or change the macro to use the named parameters. It is possible /// this warning will trigger when the none of the named parameters are used /// and the strings like $1 are infact to simply to be passed trough unchanged. void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body, ArrayRef Parameters) { // If this macro is not defined with named parameters the warning we are // checking for here doesn't apply. unsigned NParameters = Parameters.size(); if (NParameters == 0) return; bool NamedParametersFound = false; bool PositionalParametersFound = false; // Look at the body of the macro for use of both the named parameters and what // are likely to be positional parameters. This is what expandMacro() is // doing when it finds the parameters in the body. while (!Body.empty()) { // Scan for the next possible parameter. std::size_t End = Body.size(), Pos = 0; for (; Pos != End; ++Pos) { // Check for a substitution or escape. // This macro is defined with parameters, look for \foo, \bar, etc. if (Body[Pos] == '\\' && Pos + 1 != End) break; // This macro should have parameters, but look for $0, $1, ..., $n too. if (Body[Pos] != '$' || Pos + 1 == End) continue; char Next = Body[Pos + 1]; if (Next == '$' || Next == 'n' || isdigit(static_cast(Next))) break; } // Check if we reached the end. if (Pos == End) break; if (Body[Pos] == '$') { switch (Body[Pos + 1]) { // $$ => $ case '$': break; // $n => number of arguments case 'n': PositionalParametersFound = true; break; // $[0-9] => argument default: { PositionalParametersFound = true; break; } } Pos += 2; } else { unsigned I = Pos + 1; while (isIdentifierChar(Body[I]) && I + 1 != End) ++I; const char *Begin = Body.data() + Pos + 1; StringRef Argument(Begin, I - (Pos + 1)); unsigned Index = 0; for (; Index < NParameters; ++Index) if (Parameters[Index].Name == Argument) break; if (Index == NParameters) { if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') Pos += 3; else { Pos = I; } } else { NamedParametersFound = true; Pos += 1 + Argument.size(); } } // Update the scan point. Body = Body.substr(Pos); } if (!NamedParametersFound && PositionalParametersFound) Warning(DirectiveLoc, "macro defined with named parameters which are not " "used in macro body, possible positional parameter " "found in body which will have no effect"); } /// parseDirectiveExitMacro /// ::= .exitm bool AsmParser::parseDirectiveExitMacro(StringRef Directive) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Directive + "' directive")) return true; if (!isInsideMacroInstantiation()) return TokError("unexpected '" + Directive + "' in file, " "no current macro definition"); // Exit all conditionals that are active in the current macro. while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) { TheCondState = TheCondStack.back(); TheCondStack.pop_back(); } handleMacroExit(); return false; } /// parseDirectiveEndMacro /// ::= .endm /// ::= .endmacro bool AsmParser::parseDirectiveEndMacro(StringRef Directive) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); // If we are inside a macro instantiation, terminate the current // instantiation. if (isInsideMacroInstantiation()) { handleMacroExit(); return false; } // Otherwise, this .endmacro is a stray entry in the file; well formed // .endmacro directives are handled during the macro definition parsing. return TokError("unexpected '" + Directive + "' in file, " "no current macro definition"); } /// parseDirectivePurgeMacro /// ::= .purgem bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) { StringRef Name; SMLoc Loc; if (parseTokenLoc(Loc) || check(parseIdentifier(Name), Loc, "expected identifier in '.purgem' directive") || parseToken(AsmToken::EndOfStatement, "unexpected token in '.purgem' directive")) return true; if (!getContext().lookupMacro(Name)) return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); getContext().undefineMacro(Name); DEBUG_WITH_TYPE("asm-macros", dbgs() << "Un-defining macro: " << Name << "\n"); return false; } /// parseDirectiveBundleAlignMode /// ::= {.bundle_align_mode} expression bool AsmParser::parseDirectiveBundleAlignMode() { // Expect a single argument: an expression that evaluates to a constant // in the inclusive range 0-30. SMLoc ExprLoc = getLexer().getLoc(); int64_t AlignSizePow2; if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) || parseToken(AsmToken::EndOfStatement, "unexpected token after expression " "in '.bundle_align_mode' " "directive") || check(AlignSizePow2 < 0 || AlignSizePow2 > 30, ExprLoc, "invalid bundle alignment size (expected between 0 and 30)")) return true; // Because of AlignSizePow2's verified range we can safely truncate it to // unsigned. getStreamer().EmitBundleAlignMode(static_cast(AlignSizePow2)); return false; } /// parseDirectiveBundleLock /// ::= {.bundle_lock} [align_to_end] bool AsmParser::parseDirectiveBundleLock() { if (checkForValidSection()) return true; bool AlignToEnd = false; StringRef Option; SMLoc Loc = getTok().getLoc(); const char *kInvalidOptionError = "invalid option for '.bundle_lock' directive"; if (!parseOptionalToken(AsmToken::EndOfStatement)) { if (check(parseIdentifier(Option), Loc, kInvalidOptionError) || check(Option != "align_to_end", Loc, kInvalidOptionError) || parseToken(AsmToken::EndOfStatement, "unexpected token after '.bundle_lock' directive option")) return true; AlignToEnd = true; } getStreamer().EmitBundleLock(AlignToEnd); return false; } /// parseDirectiveBundleLock /// ::= {.bundle_lock} bool AsmParser::parseDirectiveBundleUnlock() { if (checkForValidSection() || parseToken(AsmToken::EndOfStatement, "unexpected token in '.bundle_unlock' directive")) return true; getStreamer().EmitBundleUnlock(); return false; } /// parseDirectiveSpace /// ::= (.skip | .space) expression [ , expression ] bool AsmParser::parseDirectiveSpace(StringRef IDVal) { SMLoc NumBytesLoc = Lexer.getLoc(); const MCExpr *NumBytes; if (checkForValidSection() || parseExpression(NumBytes)) return true; int64_t FillExpr = 0; if (parseOptionalToken(AsmToken::Comma)) if (parseAbsoluteExpression(FillExpr)) return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); if (parseToken(AsmToken::EndOfStatement)) return addErrorSuffix("in '" + Twine(IDVal) + "' directive"); // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc); return false; } /// parseDirectiveDCB /// ::= .dcb.{b, l, w} expression, expression bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) { SMLoc NumValuesLoc = Lexer.getLoc(); int64_t NumValues; if (checkForValidSection() || parseAbsoluteExpression(NumValues)) return true; if (NumValues < 0) { Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); return false; } if (parseToken(AsmToken::Comma, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; const MCExpr *Value; SMLoc ExprLoc = getLexer().getLoc(); if (parseExpression(Value)) return true; // Special case constant expressions to match code generator. if (const MCConstantExpr *MCE = dyn_cast(Value)) { assert(Size <= 8 && "Invalid size"); uint64_t IntValue = MCE->getValue(); if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue)) return Error(ExprLoc, "literal value out of range for directive"); for (uint64_t i = 0, e = NumValues; i != e; ++i) getStreamer().EmitIntValue(IntValue, Size); } else { for (uint64_t i = 0, e = NumValues; i != e; ++i) getStreamer().EmitValue(Value, Size, ExprLoc); } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; return false; } /// parseDirectiveRealDCB /// ::= .dcb.{d, s} expression, expression bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) { SMLoc NumValuesLoc = Lexer.getLoc(); int64_t NumValues; if (checkForValidSection() || parseAbsoluteExpression(NumValues)) return true; if (NumValues < 0) { Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); return false; } if (parseToken(AsmToken::Comma, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; APInt AsInt; if (parseRealValue(Semantics, AsInt)) return true; if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; for (uint64_t i = 0, e = NumValues; i != e; ++i) getStreamer().EmitIntValue(AsInt.getLimitedValue(), AsInt.getBitWidth() / 8); return false; } /// parseDirectiveDS /// ::= .ds.{b, d, l, p, s, w, x} expression bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) { SMLoc NumValuesLoc = Lexer.getLoc(); int64_t NumValues; if (checkForValidSection() || parseAbsoluteExpression(NumValues)) return true; if (NumValues < 0) { Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect"); return false; } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Twine(IDVal) + "' directive")) return true; for (uint64_t i = 0, e = NumValues; i != e; ++i) getStreamer().emitFill(Size, 0); return false; } /// parseDirectiveLEB128 /// ::= (.sleb128 | .uleb128) [ expression (, expression)* ] bool AsmParser::parseDirectiveLEB128(bool Signed) { if (checkForValidSection()) return true; auto parseOp = [&]() -> bool { const MCExpr *Value; if (parseExpression(Value)) return true; if (Signed) getStreamer().EmitSLEB128Value(Value); else getStreamer().EmitULEB128Value(Value); return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in directive"); return false; } /// parseDirectiveSymbolAttribute /// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) { auto parseOp = [&]() -> bool { StringRef Name; SMLoc Loc = getTok().getLoc(); if (parseIdentifier(Name)) return Error(Loc, "expected identifier"); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); // Assembler local symbols don't make any sense here. Complain loudly. if (Sym->isTemporary()) return Error(Loc, "non-local symbol required"); if (!getStreamer().EmitSymbolAttribute(Sym, Attr)) return Error(Loc, "unable to emit symbol attribute"); return false; }; if (parseMany(parseOp)) return addErrorSuffix(" in directive"); return false; } /// parseDirectiveComm /// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] bool AsmParser::parseDirectiveComm(bool IsLocal) { if (checkForValidSection()) return true; SMLoc IDLoc = getLexer().getLoc(); StringRef Name; if (parseIdentifier(Name)) return TokError("expected identifier in directive"); // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().getOrCreateSymbol(Name); if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); Lex(); int64_t Size; SMLoc SizeLoc = getLexer().getLoc(); if (parseAbsoluteExpression(Size)) return true; int64_t Pow2Alignment = 0; SMLoc Pow2AlignmentLoc; if (getLexer().is(AsmToken::Comma)) { Lex(); Pow2AlignmentLoc = getLexer().getLoc(); if (parseAbsoluteExpression(Pow2Alignment)) return true; LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType(); if (IsLocal && LCOMM == LCOMM::NoAlignment) return Error(Pow2AlignmentLoc, "alignment not supported on this target"); // If this target takes alignments in bytes (not log) validate and convert. if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) || (IsLocal && LCOMM == LCOMM::ByteAlignment)) { if (!isPowerOf2_64(Pow2Alignment)) return Error(Pow2AlignmentLoc, "alignment must be a power of 2"); Pow2Alignment = Log2_64(Pow2Alignment); } } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.comm' or '.lcomm' directive")) return true; // NOTE: a size of zero for a .comm should create a undefined symbol // but a size of .lcomm creates a bss symbol of size zero. if (Size < 0) return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't " "be less than zero"); // NOTE: The alignment in the directive is a power of 2 value, the assembler // may internally end up wanting an alignment in bytes. // FIXME: Diagnose overflow. if (Pow2Alignment < 0) return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive " "alignment, can't be less than zero"); Sym->redefineIfPossible(); if (!Sym->isUndefined()) return Error(IDLoc, "invalid symbol redefinition"); // Create the Symbol as a common or local common with Size and Pow2Alignment if (IsLocal) { getStreamer().EmitLocalCommonSymbol(Sym, Size, 1 << Pow2Alignment); return false; } getStreamer().EmitCommonSymbol(Sym, Size, 1 << Pow2Alignment); return false; } /// parseDirectiveAbort /// ::= .abort [... message ...] bool AsmParser::parseDirectiveAbort() { // FIXME: Use loc from directive. SMLoc Loc = getLexer().getLoc(); StringRef Str = parseStringToEndOfStatement(); if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.abort' directive")) return true; if (Str.empty()) return Error(Loc, ".abort detected. Assembly stopping."); else return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); // FIXME: Actually abort assembly here. return false; } /// parseDirectiveInclude /// ::= .include "filename" bool AsmParser::parseDirectiveInclude() { // Allow the strings to have escaped octal character sequence. std::string Filename; SMLoc IncludeLoc = getTok().getLoc(); if (check(getTok().isNot(AsmToken::String), "expected string in '.include' directive") || parseEscapedString(Filename) || check(getTok().isNot(AsmToken::EndOfStatement), "unexpected token in '.include' directive") || // Attempt to switch the lexer to the included file before consuming the // end of statement to avoid losing it when we switch. check(enterIncludeFile(Filename), IncludeLoc, "Could not find include file '" + Filename + "'")) return true; return false; } /// parseDirectiveIncbin /// ::= .incbin "filename" [ , skip [ , count ] ] bool AsmParser::parseDirectiveIncbin() { // Allow the strings to have escaped octal character sequence. std::string Filename; SMLoc IncbinLoc = getTok().getLoc(); if (check(getTok().isNot(AsmToken::String), "expected string in '.incbin' directive") || parseEscapedString(Filename)) return true; int64_t Skip = 0; const MCExpr *Count = nullptr; SMLoc SkipLoc, CountLoc; if (parseOptionalToken(AsmToken::Comma)) { // The skip expression can be omitted while specifying the count, e.g: // .incbin "filename",,4 if (getTok().isNot(AsmToken::Comma)) { if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip)) return true; } if (parseOptionalToken(AsmToken::Comma)) { CountLoc = getTok().getLoc(); if (parseExpression(Count)) return true; } } if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.incbin' directive")) return true; if (check(Skip < 0, SkipLoc, "skip is negative")) return true; // Attempt to process the included file. if (processIncbinFile(Filename, Skip, Count, CountLoc)) return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); return false; } /// parseDirectiveIf /// ::= .if{,eq,ge,gt,le,lt,ne} expression bool AsmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) { TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; if (TheCondState.Ignore) { eatToEndOfStatement(); } else { int64_t ExprValue; if (parseAbsoluteExpression(ExprValue) || parseToken(AsmToken::EndOfStatement, "unexpected token in '.if' directive")) return true; switch (DirKind) { default: llvm_unreachable("unsupported directive"); case DK_IF: case DK_IFNE: break; case DK_IFEQ: ExprValue = ExprValue == 0; break; case DK_IFGE: ExprValue = ExprValue >= 0; break; case DK_IFGT: ExprValue = ExprValue > 0; break; case DK_IFLE: ExprValue = ExprValue <= 0; break; case DK_IFLT: ExprValue = ExprValue < 0; break; } TheCondState.CondMet = ExprValue; TheCondState.Ignore = !TheCondState.CondMet; } return false; } /// parseDirectiveIfb /// ::= .ifb string bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) { TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; if (TheCondState.Ignore) { eatToEndOfStatement(); } else { StringRef Str = parseStringToEndOfStatement(); if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifb' directive")) return true; TheCondState.CondMet = ExpectBlank == Str.empty(); TheCondState.Ignore = !TheCondState.CondMet; } return false; } /// parseDirectiveIfc /// ::= .ifc string1, string2 /// ::= .ifnc string1, string2 bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) { TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; if (TheCondState.Ignore) { eatToEndOfStatement(); } else { StringRef Str1 = parseStringToComma(); if (parseToken(AsmToken::Comma, "unexpected token in '.ifc' directive")) return true; StringRef Str2 = parseStringToEndOfStatement(); if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifc' directive")) return true; TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim()); TheCondState.Ignore = !TheCondState.CondMet; } return false; } /// parseDirectiveIfeqs /// ::= .ifeqs string1, string2 bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) { if (Lexer.isNot(AsmToken::String)) { if (ExpectEqual) return TokError("expected string parameter for '.ifeqs' directive"); return TokError("expected string parameter for '.ifnes' directive"); } StringRef String1 = getTok().getStringContents(); Lex(); if (Lexer.isNot(AsmToken::Comma)) { if (ExpectEqual) return TokError( "expected comma after first string for '.ifeqs' directive"); return TokError("expected comma after first string for '.ifnes' directive"); } Lex(); if (Lexer.isNot(AsmToken::String)) { if (ExpectEqual) return TokError("expected string parameter for '.ifeqs' directive"); return TokError("expected string parameter for '.ifnes' directive"); } StringRef String2 = getTok().getStringContents(); Lex(); TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; TheCondState.CondMet = ExpectEqual == (String1 == String2); TheCondState.Ignore = !TheCondState.CondMet; return false; } /// parseDirectiveIfdef /// ::= .ifdef symbol bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { StringRef Name; TheCondStack.push_back(TheCondState); TheCondState.TheCond = AsmCond::IfCond; if (TheCondState.Ignore) { eatToEndOfStatement(); } else { if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") || parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifdef'")) return true; MCSymbol *Sym = getContext().lookupSymbol(Name); if (expect_defined) TheCondState.CondMet = (Sym && !Sym->isUndefined()); else TheCondState.CondMet = (!Sym || Sym->isUndefined()); TheCondState.Ignore = !TheCondState.CondMet; } return false; } /// parseDirectiveElseIf /// ::= .elseif expression bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) { if (TheCondState.TheCond != AsmCond::IfCond && TheCondState.TheCond != AsmCond::ElseIfCond) return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an" " .if or an .elseif"); TheCondState.TheCond = AsmCond::ElseIfCond; bool LastIgnoreState = false; if (!TheCondStack.empty()) LastIgnoreState = TheCondStack.back().Ignore; if (LastIgnoreState || TheCondState.CondMet) { TheCondState.Ignore = true; eatToEndOfStatement(); } else { int64_t ExprValue; if (parseAbsoluteExpression(ExprValue)) return true; if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.elseif' directive")) return true; TheCondState.CondMet = ExprValue; TheCondState.Ignore = !TheCondState.CondMet; } return false; } /// parseDirectiveElse /// ::= .else bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.else' directive")) return true; if (TheCondState.TheCond != AsmCond::IfCond && TheCondState.TheCond != AsmCond::ElseIfCond) return Error(DirectiveLoc, "Encountered a .else that doesn't follow " " an .if or an .elseif"); TheCondState.TheCond = AsmCond::ElseCond; bool LastIgnoreState = false; if (!TheCondStack.empty()) LastIgnoreState = TheCondStack.back().Ignore; if (LastIgnoreState || TheCondState.CondMet) TheCondState.Ignore = true; else TheCondState.Ignore = false; return false; } /// parseDirectiveEnd /// ::= .end bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.end' directive")) return true; while (Lexer.isNot(AsmToken::Eof)) Lexer.Lex(); return false; } /// parseDirectiveError /// ::= .err /// ::= .error [string] bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) { if (!TheCondStack.empty()) { if (TheCondStack.back().Ignore) { eatToEndOfStatement(); return false; } } if (!WithMessage) return Error(L, ".err encountered"); StringRef Message = ".error directive invoked in source file"; if (Lexer.isNot(AsmToken::EndOfStatement)) { if (Lexer.isNot(AsmToken::String)) return TokError(".error argument must be a string"); Message = getTok().getStringContents(); Lex(); } return Error(L, Message); } /// parseDirectiveWarning /// ::= .warning [string] bool AsmParser::parseDirectiveWarning(SMLoc L) { if (!TheCondStack.empty()) { if (TheCondStack.back().Ignore) { eatToEndOfStatement(); return false; } } StringRef Message = ".warning directive invoked in source file"; if (!parseOptionalToken(AsmToken::EndOfStatement)) { if (Lexer.isNot(AsmToken::String)) return TokError(".warning argument must be a string"); Message = getTok().getStringContents(); Lex(); if (parseToken(AsmToken::EndOfStatement, "expected end of statement in '.warning' directive")) return true; } return Warning(L, Message); } /// parseDirectiveEndIf /// ::= .endif bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in '.endif' directive")) return true; if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty()) return Error(DirectiveLoc, "Encountered a .endif that doesn't follow " "an .if or .else"); if (!TheCondStack.empty()) { TheCondState = TheCondStack.back(); TheCondStack.pop_back(); } return false; } void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".set"] = DK_SET; DirectiveKindMap[".equ"] = DK_EQU; DirectiveKindMap[".equiv"] = DK_EQUIV; DirectiveKindMap[".ascii"] = DK_ASCII; DirectiveKindMap[".asciz"] = DK_ASCIZ; DirectiveKindMap[".string"] = DK_STRING; DirectiveKindMap[".byte"] = DK_BYTE; DirectiveKindMap[".short"] = DK_SHORT; DirectiveKindMap[".value"] = DK_VALUE; DirectiveKindMap[".2byte"] = DK_2BYTE; DirectiveKindMap[".long"] = DK_LONG; DirectiveKindMap[".int"] = DK_INT; DirectiveKindMap[".4byte"] = DK_4BYTE; DirectiveKindMap[".quad"] = DK_QUAD; DirectiveKindMap[".8byte"] = DK_8BYTE; DirectiveKindMap[".octa"] = DK_OCTA; DirectiveKindMap[".single"] = DK_SINGLE; DirectiveKindMap[".float"] = DK_FLOAT; DirectiveKindMap[".double"] = DK_DOUBLE; DirectiveKindMap[".align"] = DK_ALIGN; DirectiveKindMap[".align32"] = DK_ALIGN32; DirectiveKindMap[".balign"] = DK_BALIGN; DirectiveKindMap[".balignw"] = DK_BALIGNW; DirectiveKindMap[".balignl"] = DK_BALIGNL; DirectiveKindMap[".p2align"] = DK_P2ALIGN; DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW; DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL; DirectiveKindMap[".org"] = DK_ORG; DirectiveKindMap[".fill"] = DK_FILL; DirectiveKindMap[".zero"] = DK_ZERO; DirectiveKindMap[".extern"] = DK_EXTERN; DirectiveKindMap[".globl"] = DK_GLOBL; DirectiveKindMap[".global"] = DK_GLOBAL; DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE; DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP; DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER; DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN; DirectiveKindMap[".reference"] = DK_REFERENCE; DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION; DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE; DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN; DirectiveKindMap[".comm"] = DK_COMM; DirectiveKindMap[".common"] = DK_COMMON; DirectiveKindMap[".lcomm"] = DK_LCOMM; DirectiveKindMap[".abort"] = DK_ABORT; DirectiveKindMap[".include"] = DK_INCLUDE; DirectiveKindMap[".incbin"] = DK_INCBIN; DirectiveKindMap[".code16"] = DK_CODE16; DirectiveKindMap[".code16gcc"] = DK_CODE16GCC; DirectiveKindMap[".rept"] = DK_REPT; DirectiveKindMap[".rep"] = DK_REPT; DirectiveKindMap[".irp"] = DK_IRP; DirectiveKindMap[".irpc"] = DK_IRPC; DirectiveKindMap[".endr"] = DK_ENDR; DirectiveKindMap[".bundle_align_mode"] = DK_BUNDLE_ALIGN_MODE; DirectiveKindMap[".bundle_lock"] = DK_BUNDLE_LOCK; DirectiveKindMap[".bundle_unlock"] = DK_BUNDLE_UNLOCK; DirectiveKindMap[".if"] = DK_IF; DirectiveKindMap[".ifeq"] = DK_IFEQ; DirectiveKindMap[".ifge"] = DK_IFGE; DirectiveKindMap[".ifgt"] = DK_IFGT; DirectiveKindMap[".ifle"] = DK_IFLE; DirectiveKindMap[".iflt"] = DK_IFLT; DirectiveKindMap[".ifne"] = DK_IFNE; DirectiveKindMap[".ifb"] = DK_IFB; DirectiveKindMap[".ifnb"] = DK_IFNB; DirectiveKindMap[".ifc"] = DK_IFC; DirectiveKindMap[".ifeqs"] = DK_IFEQS; DirectiveKindMap[".ifnc"] = DK_IFNC; DirectiveKindMap[".ifnes"] = DK_IFNES; DirectiveKindMap[".ifdef"] = DK_IFDEF; DirectiveKindMap[".ifndef"] = DK_IFNDEF; DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF; DirectiveKindMap[".elseif"] = DK_ELSEIF; DirectiveKindMap[".else"] = DK_ELSE; DirectiveKindMap[".end"] = DK_END; DirectiveKindMap[".endif"] = DK_ENDIF; DirectiveKindMap[".skip"] = DK_SKIP; DirectiveKindMap[".space"] = DK_SPACE; DirectiveKindMap[".file"] = DK_FILE; DirectiveKindMap[".line"] = DK_LINE; DirectiveKindMap[".loc"] = DK_LOC; DirectiveKindMap[".stabs"] = DK_STABS; DirectiveKindMap[".cv_file"] = DK_CV_FILE; DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID; DirectiveKindMap[".cv_loc"] = DK_CV_LOC; DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE; DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE; DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID; DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE; DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE; DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS; DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET; DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA; DirectiveKindMap[".sleb128"] = DK_SLEB128; DirectiveKindMap[".uleb128"] = DK_ULEB128; DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS; DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC; DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC; DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA; DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET; DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET; DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER; DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET; DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET; DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY; DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA; DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE; DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE; DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE; DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE; DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE; DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN; DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME; DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED; DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER; DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE; DirectiveKindMap[".macros_on"] = DK_MACROS_ON; DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; DirectiveKindMap[".macro"] = DK_MACRO; DirectiveKindMap[".exitm"] = DK_EXITM; DirectiveKindMap[".endm"] = DK_ENDM; DirectiveKindMap[".endmacro"] = DK_ENDMACRO; DirectiveKindMap[".purgem"] = DK_PURGEM; DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; DirectiveKindMap[".altmacro"] = DK_ALTMACRO; DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO; DirectiveKindMap[".reloc"] = DK_RELOC; DirectiveKindMap[".dc"] = DK_DC; DirectiveKindMap[".dc.a"] = DK_DC_A; DirectiveKindMap[".dc.b"] = DK_DC_B; DirectiveKindMap[".dc.d"] = DK_DC_D; DirectiveKindMap[".dc.l"] = DK_DC_L; DirectiveKindMap[".dc.s"] = DK_DC_S; DirectiveKindMap[".dc.w"] = DK_DC_W; DirectiveKindMap[".dc.x"] = DK_DC_X; DirectiveKindMap[".dcb"] = DK_DCB; DirectiveKindMap[".dcb.b"] = DK_DCB_B; DirectiveKindMap[".dcb.d"] = DK_DCB_D; DirectiveKindMap[".dcb.l"] = DK_DCB_L; DirectiveKindMap[".dcb.s"] = DK_DCB_S; DirectiveKindMap[".dcb.w"] = DK_DCB_W; DirectiveKindMap[".dcb.x"] = DK_DCB_X; DirectiveKindMap[".ds"] = DK_DS; DirectiveKindMap[".ds.b"] = DK_DS_B; DirectiveKindMap[".ds.d"] = DK_DS_D; DirectiveKindMap[".ds.l"] = DK_DS_L; DirectiveKindMap[".ds.p"] = DK_DS_P; DirectiveKindMap[".ds.s"] = DK_DS_S; DirectiveKindMap[".ds.w"] = DK_DS_W; DirectiveKindMap[".ds.x"] = DK_DS_X; DirectiveKindMap[".print"] = DK_PRINT; DirectiveKindMap[".addrsig"] = DK_ADDRSIG; DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM; } MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { AsmToken EndToken, StartToken = getTok(); unsigned NestLevel = 0; while (true) { // Check whether we have reached the end of the file. if (getLexer().is(AsmToken::Eof)) { printError(DirectiveLoc, "no matching '.endr' in definition"); return nullptr; } if (Lexer.is(AsmToken::Identifier) && (getTok().getIdentifier() == ".rep" || getTok().getIdentifier() == ".rept" || getTok().getIdentifier() == ".irp" || getTok().getIdentifier() == ".irpc")) { ++NestLevel; } // Otherwise, check whether we have reached the .endr. if (Lexer.is(AsmToken::Identifier) && getTok().getIdentifier() == ".endr") { if (NestLevel == 0) { EndToken = getTok(); Lex(); if (Lexer.isNot(AsmToken::EndOfStatement)) { printError(getTok().getLoc(), "unexpected token in '.endr' directive"); return nullptr; } break; } --NestLevel; } // Otherwise, scan till the end of the statement. eatToEndOfStatement(); } const char *BodyStart = StartToken.getLoc().getPointer(); const char *BodyEnd = EndToken.getLoc().getPointer(); StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); // We Are Anonymous. MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters()); return &MacroLikeBodies.back(); } void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, raw_svector_ostream &OS) { OS << ".endr\n"; std::unique_ptr Instantiation = MemoryBuffer::getMemBufferCopy(OS.str(), ""); // Create the macro instantiation object and add to the current macro // instantiation stack. MacroInstantiation *MI = new MacroInstantiation( DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()); ActiveMacros.push_back(MI); // Jump to the macro instantiation and prime the lexer. CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc()); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); Lex(); } /// parseDirectiveRept /// ::= .rep | .rept count bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) { const MCExpr *CountExpr; SMLoc CountLoc = getTok().getLoc(); if (parseExpression(CountExpr)) return true; int64_t Count; if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) { return Error(CountLoc, "unexpected token in '" + Dir + "' directive"); } if (check(Count < 0, CountLoc, "Count is negative") || parseToken(AsmToken::EndOfStatement, "unexpected token in '" + Dir + "' directive")) return true; // Lex the rept definition. MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc); if (!M) return true; // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. SmallString<256> Buf; raw_svector_ostream OS(Buf); while (Count--) { // Note that the AtPseudoVariable is disabled for instantiations of .rep(t). if (expandMacro(OS, M->Body, None, None, false, getTok().getLoc())) return true; } instantiateMacroLikeBody(M, DirectiveLoc, OS); return false; } /// parseDirectiveIrp /// ::= .irp symbol,values bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) { MCAsmMacroParameter Parameter; MCAsmMacroArguments A; if (check(parseIdentifier(Parameter.Name), "expected identifier in '.irp' directive") || parseToken(AsmToken::Comma, "expected comma in '.irp' directive") || parseMacroArguments(nullptr, A) || parseToken(AsmToken::EndOfStatement, "expected End of Statement")) return true; // Lex the irp definition. MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc); if (!M) return true; // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. SmallString<256> Buf; raw_svector_ostream OS(Buf); for (const MCAsmMacroArgument &Arg : A) { // Note that the AtPseudoVariable is enabled for instantiations of .irp. // This is undocumented, but GAS seems to support it. if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc())) return true; } instantiateMacroLikeBody(M, DirectiveLoc, OS); return false; } /// parseDirectiveIrpc /// ::= .irpc symbol,values bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) { MCAsmMacroParameter Parameter; MCAsmMacroArguments A; if (check(parseIdentifier(Parameter.Name), "expected identifier in '.irpc' directive") || parseToken(AsmToken::Comma, "expected comma in '.irpc' directive") || parseMacroArguments(nullptr, A)) return true; if (A.size() != 1 || A.front().size() != 1) return TokError("unexpected token in '.irpc' directive"); // Eat the end of statement. if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) return true; // Lex the irpc definition. MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc); if (!M) return true; // Macro instantiation is lexical, unfortunately. We construct a new buffer // to hold the macro body with substitutions. SmallString<256> Buf; raw_svector_ostream OS(Buf); StringRef Values = A.front().front().getString(); for (std::size_t I = 0, End = Values.size(); I != End; ++I) { MCAsmMacroArgument Arg; Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1)); // Note that the AtPseudoVariable is enabled for instantiations of .irpc. // This is undocumented, but GAS seems to support it. if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc())) return true; } instantiateMacroLikeBody(M, DirectiveLoc, OS); return false; } bool AsmParser::parseDirectiveEndr(SMLoc DirectiveLoc) { if (ActiveMacros.empty()) return TokError("unmatched '.endr' directive"); // The only .repl that should get here are the ones created by // instantiateMacroLikeBody. assert(getLexer().is(AsmToken::EndOfStatement)); handleMacroExit(); return false; } bool AsmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info, size_t Len) { const MCExpr *Value; SMLoc ExprLoc = getLexer().getLoc(); if (parseExpression(Value)) return true; const MCConstantExpr *MCE = dyn_cast(Value); if (!MCE) return Error(ExprLoc, "unexpected expression in _emit"); uint64_t IntValue = MCE->getValue(); if (!isUInt<8>(IntValue) && !isInt<8>(IntValue)) return Error(ExprLoc, "literal value out of range for directive"); Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len); return false; } bool AsmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) { const MCExpr *Value; SMLoc ExprLoc = getLexer().getLoc(); if (parseExpression(Value)) return true; const MCConstantExpr *MCE = dyn_cast(Value); if (!MCE) return Error(ExprLoc, "unexpected expression in align"); uint64_t IntValue = MCE->getValue(); if (!isPowerOf2_64(IntValue)) return Error(ExprLoc, "literal value not a power of two greater then zero"); Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue)); return false; } bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) { const AsmToken StrTok = getTok(); Lex(); if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"') return Error(DirectiveLoc, "expected double quoted string after .print"); if (parseToken(AsmToken::EndOfStatement, "expected end of statement")) return true; llvm::outs() << StrTok.getStringContents() << '\n'; return false; } bool AsmParser::parseDirectiveAddrsig() { getStreamer().EmitAddrsig(); return false; } bool AsmParser::parseDirectiveAddrsigSym() { StringRef Name; if (check(parseIdentifier(Name), "expected identifier in '.addrsig_sym' directive")) return true; MCSymbol *Sym = getContext().getOrCreateSymbol(Name); getStreamer().EmitAddrsigSym(Sym); return false; } // We are comparing pointers, but the pointers are relative to a single string. // Thus, this should always be deterministic. static int rewritesSort(const AsmRewrite *AsmRewriteA, const AsmRewrite *AsmRewriteB) { if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer()) return -1; if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer()) return 1; // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output // rewrite to the same location. Make sure the SizeDirective rewrite is // performed first, then the Imm/ImmPrefix and finally the Input/Output. This // ensures the sort algorithm is stable. if (AsmRewritePrecedence[AsmRewriteA->Kind] > AsmRewritePrecedence[AsmRewriteB->Kind]) return -1; if (AsmRewritePrecedence[AsmRewriteA->Kind] < AsmRewritePrecedence[AsmRewriteB->Kind]) return 1; llvm_unreachable("Unstable rewrite sort."); } bool AsmParser::parseMSInlineAsm( void *AsmLoc, std::string &AsmString, unsigned &NumOutputs, unsigned &NumInputs, SmallVectorImpl> &OpDecls, SmallVectorImpl &Constraints, SmallVectorImpl &Clobbers, const MCInstrInfo *MII, const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) { SmallVector InputDecls; SmallVector OutputDecls; SmallVector InputDeclsAddressOf; SmallVector OutputDeclsAddressOf; SmallVector InputConstraints; SmallVector OutputConstraints; SmallVector ClobberRegs; SmallVector AsmStrRewrites; // Prime the lexer. Lex(); // While we have input, parse each statement. unsigned InputIdx = 0; unsigned OutputIdx = 0; while (getLexer().isNot(AsmToken::Eof)) { // Parse curly braces marking block start/end if (parseCurlyBlockScope(AsmStrRewrites)) continue; ParseStatementInfo Info(&AsmStrRewrites); bool StatementErr = parseStatement(Info, &SI); if (StatementErr || Info.ParseError) { // Emit pending errors if any exist. printPendingErrors(); return true; } // No pending error should exist here. assert(!hasPendingError() && "unexpected error from parseStatement"); if (Info.Opcode == ~0U) continue; const MCInstrDesc &Desc = MII->get(Info.Opcode); // Build the list of clobbers, outputs and inputs. for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) { MCParsedAsmOperand &Operand = *Info.ParsedOperands[i]; // Immediate. if (Operand.isImm()) continue; // Register operand. if (Operand.isReg() && !Operand.needAddressOf() && !getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) { unsigned NumDefs = Desc.getNumDefs(); // Clobber. if (NumDefs && Operand.getMCOperandNum() < NumDefs) ClobberRegs.push_back(Operand.getReg()); continue; } // Expr/Input or Output. StringRef SymName = Operand.getSymName(); if (SymName.empty()) continue; void *OpDecl = Operand.getOpDecl(); if (!OpDecl) continue; bool isOutput = (i == 1) && Desc.mayStore(); SMLoc Start = SMLoc::getFromPointer(SymName.data()); if (isOutput) { ++InputIdx; OutputDecls.push_back(OpDecl); OutputDeclsAddressOf.push_back(Operand.needAddressOf()); OutputConstraints.push_back(("=" + Operand.getConstraint()).str()); AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size()); } else { InputDecls.push_back(OpDecl); InputDeclsAddressOf.push_back(Operand.needAddressOf()); InputConstraints.push_back(Operand.getConstraint().str()); AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size()); } } // Consider implicit defs to be clobbers. Think of cpuid and push. ArrayRef ImpDefs(Desc.getImplicitDefs(), Desc.getNumImplicitDefs()); ClobberRegs.insert(ClobberRegs.end(), ImpDefs.begin(), ImpDefs.end()); } // Set the number of Outputs and Inputs. NumOutputs = OutputDecls.size(); NumInputs = InputDecls.size(); // Set the unique clobbers. array_pod_sort(ClobberRegs.begin(), ClobberRegs.end()); ClobberRegs.erase(std::unique(ClobberRegs.begin(), ClobberRegs.end()), ClobberRegs.end()); Clobbers.assign(ClobberRegs.size(), std::string()); for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) { raw_string_ostream OS(Clobbers[I]); IP->printRegName(OS, ClobberRegs[I]); } // Merge the various outputs and inputs. Output are expected first. if (NumOutputs || NumInputs) { unsigned NumExprs = NumOutputs + NumInputs; OpDecls.resize(NumExprs); Constraints.resize(NumExprs); for (unsigned i = 0; i < NumOutputs; ++i) { OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]); Constraints[i] = OutputConstraints[i]; } for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) { OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]); Constraints[j] = InputConstraints[i]; } } // Build the IR assembly string. std::string AsmStringIR; raw_string_ostream OS(AsmStringIR); StringRef ASMString = SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer(); const char *AsmStart = ASMString.begin(); const char *AsmEnd = ASMString.end(); array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort); for (const AsmRewrite &AR : AsmStrRewrites) { AsmRewriteKind Kind = AR.Kind; const char *Loc = AR.Loc.getPointer(); assert(Loc >= AsmStart && "Expected Loc to be at or after Start!"); // Emit everything up to the immediate/expression. if (unsigned Len = Loc - AsmStart) OS << StringRef(AsmStart, Len); // Skip the original expression. if (Kind == AOK_Skip) { AsmStart = Loc + AR.Len; continue; } unsigned AdditionalSkip = 0; // Rewrite expressions in $N notation. switch (Kind) { default: break; case AOK_IntelExpr: assert(AR.IntelExp.isValid() && "cannot write invalid intel expression"); if (AR.IntelExp.NeedBracs) OS << "["; if (AR.IntelExp.hasBaseReg()) OS << AR.IntelExp.BaseReg; if (AR.IntelExp.hasIndexReg()) OS << (AR.IntelExp.hasBaseReg() ? " + " : "") << AR.IntelExp.IndexReg; if (AR.IntelExp.Scale > 1) OS << " * $$" << AR.IntelExp.Scale; if (AR.IntelExp.Imm || !AR.IntelExp.hasRegs()) OS << (AR.IntelExp.hasRegs() ? " + $$" : "$$") << AR.IntelExp.Imm; if (AR.IntelExp.NeedBracs) OS << "]"; break; case AOK_Label: OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label; break; case AOK_Input: OS << '$' << InputIdx++; break; case AOK_Output: OS << '$' << OutputIdx++; break; case AOK_SizeDirective: switch (AR.Val) { default: break; case 8: OS << "byte ptr "; break; case 16: OS << "word ptr "; break; case 32: OS << "dword ptr "; break; case 64: OS << "qword ptr "; break; case 80: OS << "xword ptr "; break; case 128: OS << "xmmword ptr "; break; case 256: OS << "ymmword ptr "; break; } break; case AOK_Emit: OS << ".byte"; break; case AOK_Align: { // MS alignment directives are measured in bytes. If the native assembler // measures alignment in bytes, we can pass it straight through. OS << ".align"; if (getContext().getAsmInfo()->getAlignmentIsInBytes()) break; // Alignment is in log2 form, so print that instead and skip the original // immediate. unsigned Val = AR.Val; OS << ' ' << Val; assert(Val < 10 && "Expected alignment less then 2^10."); AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4; break; } case AOK_EVEN: OS << ".even"; break; case AOK_EndOfStatement: OS << "\n\t"; break; } // Skip the original expression. AsmStart = Loc + AR.Len + AdditionalSkip; } // Emit the remainder of the asm string. if (AsmStart != AsmEnd) OS << StringRef(AsmStart, AsmEnd - AsmStart); AsmString = OS.str(); return false; } namespace llvm { namespace MCParserUtils { /// Returns whether the given symbol is used anywhere in the given expression, /// or subexpressions. static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) { switch (Value->getKind()) { case MCExpr::Binary: { const MCBinaryExpr *BE = static_cast(Value); return isSymbolUsedInExpression(Sym, BE->getLHS()) || isSymbolUsedInExpression(Sym, BE->getRHS()); } case MCExpr::Target: case MCExpr::Constant: return false; case MCExpr::SymbolRef: { const MCSymbol &S = static_cast(Value)->getSymbol(); if (S.isVariable()) return isSymbolUsedInExpression(Sym, S.getVariableValue()); return &S == Sym; } case MCExpr::Unary: return isSymbolUsedInExpression( Sym, static_cast(Value)->getSubExpr()); } llvm_unreachable("Unknown expr kind!"); } bool parseAssignmentExpression(StringRef Name, bool allow_redef, MCAsmParser &Parser, MCSymbol *&Sym, - const MCExpr *&Value, bool AllowExtendedExpr) { + const MCExpr *&Value) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Parser.getTok().getLoc(); - SMLoc EndLoc; - if (AllowExtendedExpr) { - if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) { - return Parser.TokError("missing expression"); - } - } else if (Parser.parseExpression(Value, EndLoc)) - return Parser.TokError("missing expression"); + if (Parser.parseExpression(Value)) + return Parser.TokError("missing expression"); // Note: we don't count b as used in "a = b". This is to allow // a = b // b = c if (Parser.parseToken(AsmToken::EndOfStatement)) return true; // Validate that the LHS is allowed to be a variable (either it has not been // used as a symbol, or it is an absolute symbol). Sym = Parser.getContext().lookupSymbol(Name); if (Sym) { // Diagnose assignment to a label. // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: Diagnose assignment to protected identifier (e.g., register name). if (isSymbolUsedInExpression(Sym, Value)) return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'"); else if (Sym->isUndefined(/*SetUsed*/ false) && !Sym->isUsed() && !Sym->isVariable()) ; // Allow redefinitions of undefined symbols only used in directives. else if (Sym->isVariable() && !Sym->isUsed() && allow_redef) ; // Allow redefinitions of variables that haven't yet been used. else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef)) return Parser.Error(EqualLoc, "redefinition of '" + Name + "'"); else if (!Sym->isVariable()) return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'"); else if (!isa(Sym->getVariableValue())) return Parser.Error(EqualLoc, "invalid reassignment of non-absolute variable '" + Name + "'"); } else if (Name == ".") { Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc); return false; } else Sym = Parser.getContext().getOrCreateSymbol(Name); Sym->setRedefinable(allow_redef); return false; } } // end namespace MCParserUtils } // end namespace llvm /// Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, unsigned CB) { return new AsmParser(SM, C, Out, MAI, CB); } Index: vendor/llvm/dist-release_70/lib/Support/Path.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/Support/Path.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/Support/Path.cpp (revision 338378) @@ -1,1238 +1,1246 @@ //===-- Path.cpp - Implement OS Path Concept ------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the operating system Path API. // //===----------------------------------------------------------------------===// #include "llvm/Support/Path.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include #include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include #else #include #endif using namespace llvm; using namespace llvm::support::endian; namespace { using llvm::StringRef; using llvm::sys::path::is_separator; using llvm::sys::path::Style; inline Style real_style(Style style) { #ifdef _WIN32 return (style == Style::posix) ? Style::posix : Style::windows; #else return (style == Style::windows) ? Style::windows : Style::posix; #endif } inline const char *separators(Style style) { if (real_style(style) == Style::windows) return "\\/"; return "/"; } inline char preferred_separator(Style style) { if (real_style(style) == Style::windows) return '\\'; return '/'; } StringRef find_first_component(StringRef path, Style style) { // Look for this first component in the following order. // * empty (in this case we return an empty string) // * either C: or {//,\\}net. // * {/,\} // * {file,directory}name if (path.empty()) return path; if (real_style(style) == Style::windows) { // C: if (path.size() >= 2 && std::isalpha(static_cast(path[0])) && path[1] == ':') return path.substr(0, 2); } // //net if ((path.size() > 2) && is_separator(path[0], style) && path[0] == path[1] && !is_separator(path[2], style)) { // Find the next directory separator. size_t end = path.find_first_of(separators(style), 2); return path.substr(0, end); } // {/,\} if (is_separator(path[0], style)) return path.substr(0, 1); // * {file,directory}name size_t end = path.find_first_of(separators(style)); return path.substr(0, end); } // Returns the first character of the filename in str. For paths ending in // '/', it returns the position of the '/'. size_t filename_pos(StringRef str, Style style) { if (str.size() > 0 && is_separator(str[str.size() - 1], style)) return str.size() - 1; size_t pos = str.find_last_of(separators(style), str.size() - 1); if (real_style(style) == Style::windows) { if (pos == StringRef::npos) pos = str.find_last_of(':', str.size() - 2); } if (pos == StringRef::npos || (pos == 1 && is_separator(str[0], style))) return 0; return pos + 1; } // Returns the position of the root directory in str. If there is no root // directory in str, it returns StringRef::npos. size_t root_dir_start(StringRef str, Style style) { // case "c:/" if (real_style(style) == Style::windows) { if (str.size() > 2 && str[1] == ':' && is_separator(str[2], style)) return 2; } // case "//net" if (str.size() > 3 && is_separator(str[0], style) && str[0] == str[1] && !is_separator(str[2], style)) { return str.find_first_of(separators(style), 2); } // case "/" if (str.size() > 0 && is_separator(str[0], style)) return 0; return StringRef::npos; } // Returns the position past the end of the "parent path" of path. The parent // path will not end in '/', unless the parent is the root directory. If the // path has no parent, 0 is returned. size_t parent_path_end(StringRef path, Style style) { size_t end_pos = filename_pos(path, style); bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos], style); // Skip separators until we reach root dir (or the start of the string). size_t root_dir_pos = root_dir_start(path, style); while (end_pos > 0 && (root_dir_pos == StringRef::npos || end_pos > root_dir_pos) && is_separator(path[end_pos - 1], style)) --end_pos; if (end_pos == root_dir_pos && !filename_was_sep) { // We've reached the root dir and the input path was *not* ending in a // sequence of slashes. Include the root dir in the parent path. return root_dir_pos + 1; } // Otherwise, just include before the last slash. return end_pos; } } // end unnamed namespace enum FSEntity { FS_Dir, FS_File, FS_Name }; static std::error_code createUniqueEntity(const Twine &Model, int &ResultFD, SmallVectorImpl &ResultPath, bool MakeAbsolute, unsigned Mode, FSEntity Type, sys::fs::OpenFlags Flags = sys::fs::OF_None) { SmallString<128> ModelStorage; Model.toVector(ModelStorage); if (MakeAbsolute) { // Make model absolute by prepending a temp directory if it's not already. if (!sys::path::is_absolute(Twine(ModelStorage))) { SmallString<128> TDir; sys::path::system_temp_directory(true, TDir); sys::path::append(TDir, Twine(ModelStorage)); ModelStorage.swap(TDir); } } // From here on, DO NOT modify model. It may be needed if the randomly chosen // path already exists. ResultPath = ModelStorage; // Null terminate. ResultPath.push_back(0); ResultPath.pop_back(); retry_random_path: // Replace '%' with random chars. for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { if (ModelStorage[i] == '%') ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; } // Try to open + create the file. switch (Type) { case FS_File: { if (std::error_code EC = sys::fs::openFileForReadWrite(Twine(ResultPath.begin()), ResultFD, sys::fs::CD_CreateNew, Flags, Mode)) { if (EC == errc::file_exists) goto retry_random_path; return EC; } return std::error_code(); } case FS_Name: { std::error_code EC = sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist); if (EC == errc::no_such_file_or_directory) return std::error_code(); if (EC) return EC; goto retry_random_path; } case FS_Dir: { if (std::error_code EC = sys::fs::create_directory(ResultPath.begin(), false)) { if (EC == errc::file_exists) goto retry_random_path; return EC; } return std::error_code(); } } llvm_unreachable("Invalid Type"); } namespace llvm { namespace sys { namespace path { const_iterator begin(StringRef path, Style style) { const_iterator i; i.Path = path; i.Component = find_first_component(path, style); i.Position = 0; i.S = style; return i; } const_iterator end(StringRef path) { const_iterator i; i.Path = path; i.Position = path.size(); return i; } const_iterator &const_iterator::operator++() { assert(Position < Path.size() && "Tried to increment past end!"); // Increment Position to past the current component Position += Component.size(); // Check for end. if (Position == Path.size()) { Component = StringRef(); return *this; } // Both POSIX and Windows treat paths that begin with exactly two separators // specially. bool was_net = Component.size() > 2 && is_separator(Component[0], S) && Component[1] == Component[0] && !is_separator(Component[2], S); // Handle separators. if (is_separator(Path[Position], S)) { // Root dir. if (was_net || // c:/ (real_style(S) == Style::windows && Component.endswith(":"))) { Component = Path.substr(Position, 1); return *this; } // Skip extra separators. while (Position != Path.size() && is_separator(Path[Position], S)) { ++Position; } // Treat trailing '/' as a '.', unless it is the root dir. if (Position == Path.size() && Component != "/") { --Position; Component = "."; return *this; } } // Find next component. size_t end_pos = Path.find_first_of(separators(S), Position); Component = Path.slice(Position, end_pos); return *this; } bool const_iterator::operator==(const const_iterator &RHS) const { return Path.begin() == RHS.Path.begin() && Position == RHS.Position; } ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { return Position - RHS.Position; } reverse_iterator rbegin(StringRef Path, Style style) { reverse_iterator I; I.Path = Path; I.Position = Path.size(); I.S = style; return ++I; } reverse_iterator rend(StringRef Path) { reverse_iterator I; I.Path = Path; I.Component = Path.substr(0, 0); I.Position = 0; return I; } reverse_iterator &reverse_iterator::operator++() { size_t root_dir_pos = root_dir_start(Path, S); // Skip separators unless it's the root directory. size_t end_pos = Position; while (end_pos > 0 && (end_pos - 1) != root_dir_pos && is_separator(Path[end_pos - 1], S)) --end_pos; // Treat trailing '/' as a '.', unless it is the root dir. if (Position == Path.size() && !Path.empty() && is_separator(Path.back(), S) && (root_dir_pos == StringRef::npos || end_pos - 1 > root_dir_pos)) { --Position; Component = "."; return *this; } // Find next separator. size_t start_pos = filename_pos(Path.substr(0, end_pos), S); Component = Path.slice(start_pos, end_pos); Position = start_pos; return *this; } bool reverse_iterator::operator==(const reverse_iterator &RHS) const { return Path.begin() == RHS.Path.begin() && Component == RHS.Component && Position == RHS.Position; } ptrdiff_t reverse_iterator::operator-(const reverse_iterator &RHS) const { return Position - RHS.Position; } StringRef root_path(StringRef path, Style style) { const_iterator b = begin(path, style), pos = b, e = end(path); if (b != e) { bool has_net = b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if (has_net || has_drive) { if ((++pos != e) && is_separator((*pos)[0], style)) { // {C:/,//net/}, so get the first two components. return path.substr(0, b->size() + pos->size()); } else { // just {C:,//net}, return the first component. return *b; } } // POSIX style root directory. if (is_separator((*b)[0], style)) { return *b; } } return StringRef(); } StringRef root_name(StringRef path, Style style) { const_iterator b = begin(path, style), e = end(path); if (b != e) { bool has_net = b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if (has_net || has_drive) { // just {C:,//net}, return the first component. return *b; } } // No path or no name. return StringRef(); } StringRef root_directory(StringRef path, Style style) { const_iterator b = begin(path, style), pos = b, e = end(path); if (b != e) { bool has_net = b->size() > 2 && is_separator((*b)[0], style) && (*b)[1] == (*b)[0]; bool has_drive = (real_style(style) == Style::windows) && b->endswith(":"); if ((has_net || has_drive) && // {C:,//net}, skip to the next component. (++pos != e) && is_separator((*pos)[0], style)) { return *pos; } // POSIX style root directory. if (!has_net && is_separator((*b)[0], style)) { return *b; } } // No path or no root. return StringRef(); } StringRef relative_path(StringRef path, Style style) { StringRef root = root_path(path, style); return path.substr(root.size()); } void append(SmallVectorImpl &path, Style style, const Twine &a, const Twine &b, const Twine &c, const Twine &d) { SmallString<32> a_storage; SmallString<32> b_storage; SmallString<32> c_storage; SmallString<32> d_storage; SmallVector components; if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); for (auto &component : components) { bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1], style); if (path_has_sep) { // Strip separators from beginning of component. size_t loc = component.find_first_not_of(separators(style)); StringRef c = component.substr(loc); // Append it. path.append(c.begin(), c.end()); continue; } bool component_has_sep = !component.empty() && is_separator(component[0], style); if (!component_has_sep && !(path.empty() || has_root_name(component, style))) { // Add a separator. path.push_back(preferred_separator(style)); } path.append(component.begin(), component.end()); } } void append(SmallVectorImpl &path, const Twine &a, const Twine &b, const Twine &c, const Twine &d) { append(path, Style::native, a, b, c, d); } void append(SmallVectorImpl &path, const_iterator begin, const_iterator end, Style style) { for (; begin != end; ++begin) path::append(path, style, *begin); } StringRef parent_path(StringRef path, Style style) { size_t end_pos = parent_path_end(path, style); if (end_pos == StringRef::npos) return StringRef(); else return path.substr(0, end_pos); } void remove_filename(SmallVectorImpl &path, Style style) { size_t end_pos = parent_path_end(StringRef(path.begin(), path.size()), style); if (end_pos != StringRef::npos) path.set_size(end_pos); } void replace_extension(SmallVectorImpl &path, const Twine &extension, Style style) { StringRef p(path.begin(), path.size()); SmallString<32> ext_storage; StringRef ext = extension.toStringRef(ext_storage); // Erase existing extension. size_t pos = p.find_last_of('.'); if (pos != StringRef::npos && pos >= filename_pos(p, style)) path.set_size(pos); // Append '.' if needed. if (ext.size() > 0 && ext[0] != '.') path.push_back('.'); // Append extension. path.append(ext.begin(), ext.end()); } void replace_path_prefix(SmallVectorImpl &Path, const StringRef &OldPrefix, const StringRef &NewPrefix, Style style) { if (OldPrefix.empty() && NewPrefix.empty()) return; StringRef OrigPath(Path.begin(), Path.size()); if (!OrigPath.startswith(OldPrefix)) return; // If prefixes have the same size we can simply copy the new one over. if (OldPrefix.size() == NewPrefix.size()) { std::copy(NewPrefix.begin(), NewPrefix.end(), Path.begin()); return; } StringRef RelPath = OrigPath.substr(OldPrefix.size()); SmallString<256> NewPath; path::append(NewPath, style, NewPrefix); path::append(NewPath, style, RelPath); Path.swap(NewPath); } void native(const Twine &path, SmallVectorImpl &result, Style style) { assert((!path.isSingleStringRef() || path.getSingleStringRef().data() != result.data()) && "path and result are not allowed to overlap!"); // Clear result. result.clear(); path.toVector(result); native(result, style); } void native(SmallVectorImpl &Path, Style style) { if (Path.empty()) return; if (real_style(style) == Style::windows) { std::replace(Path.begin(), Path.end(), '/', '\\'); if (Path[0] == '~' && (Path.size() == 1 || is_separator(Path[1], style))) { SmallString<128> PathHome; home_directory(PathHome); PathHome.append(Path.begin() + 1, Path.end()); Path = PathHome; } } else { for (auto PI = Path.begin(), PE = Path.end(); PI < PE; ++PI) { if (*PI == '\\') { auto PN = PI + 1; if (PN < PE && *PN == '\\') ++PI; // increment once, the for loop will move over the escaped slash else *PI = '/'; } } } } std::string convert_to_slash(StringRef path, Style style) { if (real_style(style) != Style::windows) return path; std::string s = path.str(); std::replace(s.begin(), s.end(), '\\', '/'); return s; } StringRef filename(StringRef path, Style style) { return *rbegin(path, style); } StringRef stem(StringRef path, Style style) { StringRef fname = filename(path, style); size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return fname; else if ((fname.size() == 1 && fname == ".") || (fname.size() == 2 && fname == "..")) return fname; else return fname.substr(0, pos); } StringRef extension(StringRef path, Style style) { StringRef fname = filename(path, style); size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return StringRef(); else if ((fname.size() == 1 && fname == ".") || (fname.size() == 2 && fname == "..")) return StringRef(); else return fname.substr(pos); } bool is_separator(char value, Style style) { if (value == '/') return true; if (real_style(style) == Style::windows) return value == '\\'; return false; } StringRef get_separator(Style style) { if (real_style(style) == Style::windows) return "\\"; return "/"; } bool has_root_name(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !root_name(p, style).empty(); } bool has_root_directory(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !root_directory(p, style).empty(); } bool has_root_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !root_path(p, style).empty(); } bool has_relative_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !relative_path(p, style).empty(); } bool has_filename(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !filename(p, style).empty(); } bool has_parent_path(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !parent_path(p, style).empty(); } bool has_stem(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !stem(p, style).empty(); } bool has_extension(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); return !extension(p, style).empty(); } bool is_absolute(const Twine &path, Style style) { SmallString<128> path_storage; StringRef p = path.toStringRef(path_storage); bool rootDir = has_root_directory(p, style); bool rootName = (real_style(style) != Style::windows) || has_root_name(p, style); return rootDir && rootName; } bool is_relative(const Twine &path, Style style) { return !is_absolute(path, style); } StringRef remove_leading_dotslash(StringRef Path, Style style) { // Remove leading "./" (or ".//" or "././" etc.) while (Path.size() > 2 && Path[0] == '.' && is_separator(Path[1], style)) { Path = Path.substr(2); while (Path.size() > 0 && is_separator(Path[0], style)) Path = Path.substr(1); } return Path; } static SmallString<256> remove_dots(StringRef path, bool remove_dot_dot, Style style) { SmallVector components; // Skip the root path, then look for traversal in the components. StringRef rel = path::relative_path(path, style); for (StringRef C : llvm::make_range(path::begin(rel, style), path::end(rel))) { if (C == ".") continue; // Leading ".." will remain in the path unless it's at the root. if (remove_dot_dot && C == "..") { if (!components.empty() && components.back() != "..") { components.pop_back(); continue; } if (path::is_absolute(path, style)) continue; } components.push_back(C); } SmallString<256> buffer = path::root_path(path, style); for (StringRef C : components) path::append(buffer, style, C); return buffer; } bool remove_dots(SmallVectorImpl &path, bool remove_dot_dot, Style style) { StringRef p(path.data(), path.size()); SmallString<256> result = remove_dots(p, remove_dot_dot, style); if (result == path) return false; path.swap(result); return true; } } // end namespace path namespace fs { std::error_code getUniqueID(const Twine Path, UniqueID &Result) { file_status Status; std::error_code EC = status(Path, Status); if (EC) return EC; Result = Status.getUniqueID(); return std::error_code(); } std::error_code createUniqueFile(const Twine &Model, int &ResultFd, SmallVectorImpl &ResultPath, unsigned Mode) { return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File); } static std::error_code createUniqueFile(const Twine &Model, int &ResultFd, SmallVectorImpl &ResultPath, unsigned Mode, OpenFlags Flags) { return createUniqueEntity(Model, ResultFd, ResultPath, false, Mode, FS_File, Flags); } std::error_code createUniqueFile(const Twine &Model, SmallVectorImpl &ResultPath, unsigned Mode) { int FD; auto EC = createUniqueFile(Model, FD, ResultPath, Mode); if (EC) return EC; // FD is only needed to avoid race conditions. Close it right away. close(FD); return EC; } static std::error_code createTemporaryFile(const Twine &Model, int &ResultFD, llvm::SmallVectorImpl &ResultPath, FSEntity Type) { SmallString<128> Storage; StringRef P = Model.toNullTerminatedStringRef(Storage); assert(P.find_first_of(separators(Style::native)) == StringRef::npos && "Model must be a simple filename."); // Use P.begin() so that createUniqueEntity doesn't need to recreate Storage. return createUniqueEntity(P.begin(), ResultFD, ResultPath, true, owner_read | owner_write, Type); } static std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, llvm::SmallVectorImpl &ResultPath, FSEntity Type) { const char *Middle = Suffix.empty() ? "-%%%%%%" : "-%%%%%%."; return createTemporaryFile(Prefix + Middle + Suffix, ResultFD, ResultPath, Type); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, int &ResultFD, SmallVectorImpl &ResultPath) { return createTemporaryFile(Prefix, Suffix, ResultFD, ResultPath, FS_File); } std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, SmallVectorImpl &ResultPath) { int FD; auto EC = createTemporaryFile(Prefix, Suffix, FD, ResultPath); if (EC) return EC; // FD is only needed to avoid race conditions. Close it right away. close(FD); return EC; } // This is a mkdtemp with a different pattern. We use createUniqueEntity mostly // for consistency. We should try using mkdtemp. std::error_code createUniqueDirectory(const Twine &Prefix, SmallVectorImpl &ResultPath) { int Dummy; return createUniqueEntity(Prefix + "-%%%%%%", Dummy, ResultPath, true, 0, FS_Dir); } std::error_code getPotentiallyUniqueFileName(const Twine &Model, SmallVectorImpl &ResultPath) { int Dummy; return createUniqueEntity(Model, Dummy, ResultPath, false, 0, FS_Name); } std::error_code getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix, SmallVectorImpl &ResultPath) { int Dummy; return createTemporaryFile(Prefix, Suffix, Dummy, ResultPath, FS_Name); } static std::error_code make_absolute(const Twine ¤t_directory, SmallVectorImpl &path, bool use_current_directory) { StringRef p(path.data(), path.size()); bool rootDirectory = path::has_root_directory(p); bool rootName = (real_style(Style::native) != Style::windows) || path::has_root_name(p); // Already absolute. if (rootName && rootDirectory) return std::error_code(); // All of the following conditions will need the current directory. SmallString<128> current_dir; if (use_current_directory) current_directory.toVector(current_dir); else if (std::error_code ec = current_path(current_dir)) return ec; // Relative path. Prepend the current directory. if (!rootName && !rootDirectory) { // Append path to the current directory. path::append(current_dir, p); // Set path to the result. path.swap(current_dir); return std::error_code(); } if (!rootName && rootDirectory) { StringRef cdrn = path::root_name(current_dir); SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); path::append(curDirRootName, p); // Set path to the result. path.swap(curDirRootName); return std::error_code(); } if (rootName && !rootDirectory) { StringRef pRootName = path::root_name(p); StringRef bRootDirectory = path::root_directory(current_dir); StringRef bRelativePath = path::relative_path(current_dir); StringRef pRelativePath = path::relative_path(p); SmallString<128> res; path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); path.swap(res); return std::error_code(); } llvm_unreachable("All rootName and rootDirectory combinations should have " "occurred above!"); } std::error_code make_absolute(const Twine ¤t_directory, SmallVectorImpl &path) { return make_absolute(current_directory, path, true); } std::error_code make_absolute(SmallVectorImpl &path) { return make_absolute(Twine(), path, false); } std::error_code create_directories(const Twine &Path, bool IgnoreExisting, perms Perms) { SmallString<128> PathStorage; StringRef P = Path.toStringRef(PathStorage); // Be optimistic and try to create the directory std::error_code EC = create_directory(P, IgnoreExisting, Perms); // If we succeeded, or had any error other than the parent not existing, just // return it. if (EC != errc::no_such_file_or_directory) return EC; // We failed because of a no_such_file_or_directory, try to create the // parent. StringRef Parent = path::parent_path(P); if (Parent.empty()) return EC; if ((EC = create_directories(Parent, IgnoreExisting, Perms))) return EC; return create_directory(P, IgnoreExisting, Perms); } static std::error_code copy_file_internal(int ReadFD, int WriteFD) { const size_t BufSize = 4096; char *Buf = new char[BufSize]; int BytesRead = 0, BytesWritten = 0; for (;;) { BytesRead = read(ReadFD, Buf, BufSize); if (BytesRead <= 0) break; while (BytesRead) { BytesWritten = write(WriteFD, Buf, BytesRead); if (BytesWritten < 0) break; BytesRead -= BytesWritten; } if (BytesWritten < 0) break; } delete[] Buf; if (BytesRead < 0 || BytesWritten < 0) return std::error_code(errno, std::generic_category()); return std::error_code(); } std::error_code copy_file(const Twine &From, const Twine &To) { int ReadFD, WriteFD; if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) return EC; if (std::error_code EC = openFileForWrite(To, WriteFD, CD_CreateAlways, OF_None)) { close(ReadFD); return EC; } std::error_code EC = copy_file_internal(ReadFD, WriteFD); close(ReadFD); close(WriteFD); return EC; } std::error_code copy_file(const Twine &From, int ToFD) { int ReadFD; if (std::error_code EC = openFileForRead(From, ReadFD, OF_None)) return EC; std::error_code EC = copy_file_internal(ReadFD, ToFD); close(ReadFD); return EC; } ErrorOr md5_contents(int FD) { MD5 Hash; constexpr size_t BufSize = 4096; std::vector Buf(BufSize); int BytesRead = 0; for (;;) { BytesRead = read(FD, Buf.data(), BufSize); if (BytesRead <= 0) break; Hash.update(makeArrayRef(Buf.data(), BytesRead)); } if (BytesRead < 0) return std::error_code(errno, std::generic_category()); MD5::MD5Result Result; Hash.final(Result); return Result; } ErrorOr md5_contents(const Twine &Path) { int FD; if (auto EC = openFileForRead(Path, FD, OF_None)) return EC; auto Result = md5_contents(FD); close(FD); return Result; } bool exists(const basic_file_status &status) { return status_known(status) && status.type() != file_type::file_not_found; } bool status_known(const basic_file_status &s) { return s.type() != file_type::status_error; } file_type get_file_type(const Twine &Path, bool Follow) { file_status st; if (status(Path, st, Follow)) return file_type::status_error; return st.type(); } bool is_directory(const basic_file_status &status) { return status.type() == file_type::directory_file; } std::error_code is_directory(const Twine &path, bool &result) { file_status st; if (std::error_code ec = status(path, st)) return ec; result = is_directory(st); return std::error_code(); } bool is_regular_file(const basic_file_status &status) { return status.type() == file_type::regular_file; } std::error_code is_regular_file(const Twine &path, bool &result) { file_status st; if (std::error_code ec = status(path, st)) return ec; result = is_regular_file(st); return std::error_code(); } bool is_symlink_file(const basic_file_status &status) { return status.type() == file_type::symlink_file; } std::error_code is_symlink_file(const Twine &path, bool &result) { file_status st; if (std::error_code ec = status(path, st, false)) return ec; result = is_symlink_file(st); return std::error_code(); } bool is_other(const basic_file_status &status) { return exists(status) && !is_regular_file(status) && !is_directory(status); } std::error_code is_other(const Twine &Path, bool &Result) { file_status FileStatus; if (std::error_code EC = status(Path, FileStatus)) return EC; Result = is_other(FileStatus); return std::error_code(); } void directory_entry::replace_filename(const Twine &filename, basic_file_status st) { SmallString<128> path = path::parent_path(Path); path::append(path, filename); Path = path.str(); Status = st; } ErrorOr getPermissions(const Twine &Path) { file_status Status; if (std::error_code EC = status(Path, Status)) return EC; return Status.permissions(); } } // end namespace fs } // end namespace sys } // end namespace llvm // Include the truly platform-specific parts. #if defined(LLVM_ON_UNIX) #include "Unix/Path.inc" #endif #if defined(_WIN32) #include "Windows/Path.inc" #endif namespace llvm { namespace sys { namespace fs { TempFile::TempFile(StringRef Name, int FD) : TmpName(Name), FD(FD) {} TempFile::TempFile(TempFile &&Other) { *this = std::move(Other); } TempFile &TempFile::operator=(TempFile &&Other) { TmpName = std::move(Other.TmpName); FD = Other.FD; Other.Done = true; return *this; } TempFile::~TempFile() { assert(Done); } Error TempFile::discard() { Done = true; std::error_code RemoveEC; // On windows closing will remove the file. #ifndef _WIN32 // Always try to close and remove. if (!TmpName.empty()) { RemoveEC = fs::remove(TmpName); sys::DontRemoveFileOnSignal(TmpName); } #endif if (!RemoveEC) TmpName = ""; if (FD != -1 && close(FD) == -1) { std::error_code EC = std::error_code(errno, std::generic_category()); return errorCodeToError(EC); } FD = -1; return errorCodeToError(RemoveEC); } Error TempFile::keep(const Twine &Name) { assert(!Done); Done = true; // Always try to close and rename. #ifdef _WIN32 // If we can't cancel the delete don't rename. auto H = reinterpret_cast(_get_osfhandle(FD)); std::error_code RenameEC = setDeleteDisposition(H, false); - if (!RenameEC) + if (!RenameEC) { RenameEC = rename_fd(FD, Name); + // If rename failed because it's cross-device, copy instead + if (RenameEC == + std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) { + RenameEC = copy_file(TmpName, Name); + setDeleteDisposition(H, true); + } + } + // If we can't rename, discard the temporary file. if (RenameEC) setDeleteDisposition(H, true); #else std::error_code RenameEC = fs::rename(TmpName, Name); if (RenameEC) { // If we can't rename, try to copy to work around cross-device link issues. RenameEC = sys::fs::copy_file(TmpName, Name); // If we can't rename or copy, discard the temporary file. if (RenameEC) remove(TmpName); } sys::DontRemoveFileOnSignal(TmpName); #endif if (!RenameEC) TmpName = ""; if (close(FD) == -1) { std::error_code EC(errno, std::generic_category()); return errorCodeToError(EC); } FD = -1; return errorCodeToError(RenameEC); } Error TempFile::keep() { assert(!Done); Done = true; #ifdef _WIN32 auto H = reinterpret_cast(_get_osfhandle(FD)); if (std::error_code EC = setDeleteDisposition(H, false)) return errorCodeToError(EC); #else sys::DontRemoveFileOnSignal(TmpName); #endif TmpName = ""; if (close(FD) == -1) { std::error_code EC(errno, std::generic_category()); return errorCodeToError(EC); } FD = -1; return Error::success(); } Expected TempFile::create(const Twine &Model, unsigned Mode) { int FD; SmallString<128> ResultPath; if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode, OF_Delete)) return errorCodeToError(EC); TempFile Ret(ResultPath, FD); #ifndef _WIN32 if (sys::RemoveFileOnSignal(ResultPath)) { // Make sure we delete the file when RemoveFileOnSignal fails. consumeError(Ret.discard()); std::error_code EC(errc::operation_not_permitted); return errorCodeToError(EC); } #endif return std::move(Ret); } } namespace path { bool user_cache_directory(SmallVectorImpl &Result, const Twine &Path1, const Twine &Path2, const Twine &Path3) { if (getUserCacheDir(Result)) { append(Result, Path1, Path2, Path3); return true; } return false; } } // end namespace path } // end namsspace sys } // end namespace llvm Index: vendor/llvm/dist-release_70/lib/Support/Windows/Path.inc =================================================================== --- vendor/llvm/dist-release_70/lib/Support/Windows/Path.inc (revision 338377) +++ vendor/llvm/dist-release_70/lib/Support/Windows/Path.inc (revision 338378) @@ -1,1405 +1,1405 @@ //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Windows specific implementation of the Path API. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// //=== WARNING: Implementation here must contain only generic Windows code that //=== is guaranteed to work on *all* Windows variants. //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/WindowsError.h" #include #include #include #include // These two headers must be included last, and make sure shlobj is required // after Windows.h to make sure it picks up our definition of _WIN32_WINNT #include "WindowsSupport.h" #include #include #undef max // MinGW doesn't define this. #ifndef _ERRNO_T_DEFINED #define _ERRNO_T_DEFINED typedef int errno_t; #endif #ifdef _MSC_VER # pragma comment(lib, "advapi32.lib") // This provides CryptAcquireContextW. # pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree #endif using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::CurCPToUTF16; using llvm::sys::windows::UTF16ToUTF8; using llvm::sys::path::widenPath; static bool is_separator(const wchar_t value) { switch (value) { case L'\\': case L'/': return true; default: return false; } } namespace llvm { namespace sys { namespace path { // Convert a UTF-8 path to UTF-16. Also, if the absolute equivalent of the // path is longer than CreateDirectory can tolerate, make it absolute and // prefixed by '\\?\'. std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16) { const size_t MaxDirLen = MAX_PATH - 12; // Must leave room for 8.3 filename. // Several operations would convert Path8 to SmallString; more efficient to // do it once up front. SmallString<128> Path8Str; Path8.toVector(Path8Str); // If we made this path absolute, how much longer would it get? size_t CurPathLen; if (llvm::sys::path::is_absolute(Twine(Path8Str))) CurPathLen = 0; // No contribution from current_path needed. else { CurPathLen = ::GetCurrentDirectoryW(0, NULL); if (CurPathLen == 0) return mapWindowsError(::GetLastError()); } // Would the absolute path be longer than our limit? if ((Path8Str.size() + CurPathLen) >= MaxDirLen && !Path8Str.startswith("\\\\?\\")) { SmallString<2*MAX_PATH> FullPath("\\\\?\\"); if (CurPathLen) { SmallString<80> CurPath; if (std::error_code EC = llvm::sys::fs::current_path(CurPath)) return EC; FullPath.append(CurPath); } // Traverse the requested path, canonicalizing . and .. (because the \\?\ // prefix is documented to treat them as real components). Ignore // separators, which can be returned from the iterator if the path has a // drive name. We don't need to call native() on the result since append() // always attaches preferred_separator. for (llvm::sys::path::const_iterator I = llvm::sys::path::begin(Path8Str), E = llvm::sys::path::end(Path8Str); I != E; ++I) { if (I->size() == 1 && is_separator((*I)[0])) continue; if (I->size() == 1 && *I == ".") continue; if (I->size() == 2 && *I == "..") llvm::sys::path::remove_filename(FullPath); else llvm::sys::path::append(FullPath, *I); } return UTF8ToUTF16(FullPath, Path16); } // Just use the caller's original path. return UTF8ToUTF16(Path8Str, Path16); } } // end namespace path namespace fs { const file_t kInvalidFile = INVALID_HANDLE_VALUE; std::string getMainExecutable(const char *argv0, void *MainExecAddr) { SmallVector PathName; DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); // A zero return value indicates a failure other than insufficient space. if (Size == 0) return ""; // Insufficient space is determined by a return value equal to the size of // the buffer passed in. if (Size == PathName.capacity()) return ""; // On success, GetModuleFileNameW returns the number of characters written to // the buffer not including the NULL terminator. PathName.set_size(Size); // Convert the result from UTF-16 to UTF-8. SmallVector PathNameUTF8; if (UTF16ToUTF8(PathName.data(), PathName.size(), PathNameUTF8)) return ""; return std::string(PathNameUTF8.data()); } UniqueID file_status::getUniqueID() const { // The file is uniquely identified by the volume serial number along // with the 64-bit file identifier. uint64_t FileID = (static_cast(FileIndexHigh) << 32ULL) | static_cast(FileIndexLow); return UniqueID(VolumeSerialNumber, FileID); } ErrorOr disk_space(const Twine &Path) { ULARGE_INTEGER Avail, Total, Free; if (!::GetDiskFreeSpaceExA(Path.str().c_str(), &Avail, &Total, &Free)) return mapWindowsError(::GetLastError()); space_info SpaceInfo; SpaceInfo.capacity = (static_cast(Total.HighPart) << 32) + Total.LowPart; SpaceInfo.free = (static_cast(Free.HighPart) << 32) + Free.LowPart; SpaceInfo.available = (static_cast(Avail.HighPart) << 32) + Avail.LowPart; return SpaceInfo; } TimePoint<> basic_file_status::getLastAccessedTime() const { FILETIME Time; Time.dwLowDateTime = LastAccessedTimeLow; Time.dwHighDateTime = LastAccessedTimeHigh; return toTimePoint(Time); } TimePoint<> basic_file_status::getLastModificationTime() const { FILETIME Time; Time.dwLowDateTime = LastWriteTimeLow; Time.dwHighDateTime = LastWriteTimeHigh; return toTimePoint(Time); } uint32_t file_status::getLinkCount() const { return NumLinks; } std::error_code current_path(SmallVectorImpl &result) { SmallVector cur_path; DWORD len = MAX_PATH; do { cur_path.reserve(len); len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); // A zero return value indicates a failure other than insufficient space. if (len == 0) return mapWindowsError(::GetLastError()); // If there's insufficient space, the len returned is larger than the len // given. } while (len > cur_path.capacity()); // On success, GetCurrentDirectoryW returns the number of characters not // including the null-terminator. cur_path.set_size(len); return UTF16ToUTF8(cur_path.begin(), cur_path.size(), result); } std::error_code set_current_path(const Twine &path) { // Convert to utf-16. SmallVector wide_path; if (std::error_code ec = widenPath(path, wide_path)) return ec; if (!::SetCurrentDirectoryW(wide_path.begin())) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code create_directory(const Twine &path, bool IgnoreExisting, perms Perms) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) return ec; if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { DWORD LastError = ::GetLastError(); if (LastError != ERROR_ALREADY_EXISTS || !IgnoreExisting) return mapWindowsError(LastError); } return std::error_code(); } // We can't use symbolic links for windows. std::error_code create_link(const Twine &to, const Twine &from) { // Convert to utf-16. SmallVector wide_from; SmallVector wide_to; if (std::error_code ec = widenPath(from, wide_from)) return ec; if (std::error_code ec = widenPath(to, wide_to)) return ec; if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code create_hard_link(const Twine &to, const Twine &from) { return create_link(to, from); } std::error_code remove(const Twine &path, bool IgnoreNonExisting) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) return ec; // We don't know whether this is a file or a directory, and remove() can // accept both. The usual way to delete a file or directory is to use one of // the DeleteFile or RemoveDirectory functions, but that requires you to know // which one it is. We could stat() the file to determine that, but that would // cost us additional system calls, which can be slow in a directory // containing a large number of files. So instead we call CreateFile directly. // The important part is the FILE_FLAG_DELETE_ON_CLOSE flag, which causes the // file to be deleted once it is closed. We also use the flags // FILE_FLAG_BACKUP_SEMANTICS (which allows us to open directories), and // FILE_FLAG_OPEN_REPARSE_POINT (don't follow symlinks). ScopedFileHandle h(::CreateFileW( c_str(path_utf16), DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_DELETE_ON_CLOSE, NULL)); if (!h) { std::error_code EC = mapWindowsError(::GetLastError()); if (EC != errc::no_such_file_or_directory || !IgnoreNonExisting) return EC; } return std::error_code(); } static std::error_code is_local_internal(SmallVectorImpl &Path, bool &Result) { SmallVector VolumePath; size_t Len = 128; while (true) { VolumePath.resize(Len); BOOL Success = ::GetVolumePathNameW(Path.data(), VolumePath.data(), VolumePath.size()); if (Success) break; DWORD Err = ::GetLastError(); if (Err != ERROR_INSUFFICIENT_BUFFER) return mapWindowsError(Err); Len *= 2; } // If the output buffer has exactly enough space for the path name, but not // the null terminator, it will leave the output unterminated. Push a null // terminator onto the end to ensure that this never happens. VolumePath.push_back(L'\0'); VolumePath.set_size(wcslen(VolumePath.data())); const wchar_t *P = VolumePath.data(); UINT Type = ::GetDriveTypeW(P); switch (Type) { case DRIVE_FIXED: Result = true; return std::error_code(); case DRIVE_REMOTE: case DRIVE_CDROM: case DRIVE_RAMDISK: case DRIVE_REMOVABLE: Result = false; return std::error_code(); default: return make_error_code(errc::no_such_file_or_directory); } llvm_unreachable("Unreachable!"); } std::error_code is_local(const Twine &path, bool &result) { if (!llvm::sys::fs::exists(path) || !llvm::sys::path::has_root_path(path)) return make_error_code(errc::no_such_file_or_directory); SmallString<128> Storage; StringRef P = path.toStringRef(Storage); // Convert to utf-16. SmallVector WidePath; if (std::error_code ec = widenPath(P, WidePath)) return ec; return is_local_internal(WidePath, result); } static std::error_code realPathFromHandle(HANDLE H, SmallVectorImpl &Buffer) { DWORD CountChars = ::GetFinalPathNameByHandleW( H, Buffer.begin(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); if (CountChars > Buffer.capacity()) { // The buffer wasn't big enough, try again. In this case the return value // *does* indicate the size of the null terminator. Buffer.reserve(CountChars); CountChars = ::GetFinalPathNameByHandleW( H, Buffer.data(), Buffer.capacity() - 1, FILE_NAME_NORMALIZED); } if (CountChars == 0) return mapWindowsError(GetLastError()); Buffer.set_size(CountChars); return std::error_code(); } static std::error_code realPathFromHandle(HANDLE H, SmallVectorImpl &RealPath) { RealPath.clear(); SmallVector Buffer; if (std::error_code EC = realPathFromHandle(H, Buffer)) return EC; const wchar_t *Data = Buffer.data(); DWORD CountChars = Buffer.size(); if (CountChars >= 4) { if (0 == ::memcmp(Data, L"\\\\?\\", 8)) { CountChars -= 4; Data += 4; } } // Convert the result from UTF-16 to UTF-8. return UTF16ToUTF8(Data, CountChars, RealPath); } std::error_code is_local(int FD, bool &Result) { SmallVector FinalPath; HANDLE Handle = reinterpret_cast(_get_osfhandle(FD)); if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) return EC; return is_local_internal(FinalPath, Result); } static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { FILE_DISPOSITION_INFO Disposition; Disposition.DeleteFile = Delete; if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, sizeof(Disposition))) return mapWindowsError(::GetLastError()); return std::error_code(); } static std::error_code rename_internal(HANDLE FromHandle, const Twine &To, bool ReplaceIfExists) { SmallVector ToWide; if (auto EC = widenPath(To, ToWide)) return EC; std::vector RenameInfoBuf(sizeof(FILE_RENAME_INFO) - sizeof(wchar_t) + (ToWide.size() * sizeof(wchar_t))); FILE_RENAME_INFO &RenameInfo = *reinterpret_cast(RenameInfoBuf.data()); RenameInfo.ReplaceIfExists = ReplaceIfExists; RenameInfo.RootDirectory = 0; RenameInfo.FileNameLength = ToWide.size(); std::copy(ToWide.begin(), ToWide.end(), &RenameInfo.FileName[0]); SetLastError(ERROR_SUCCESS); if (!SetFileInformationByHandle(FromHandle, FileRenameInfo, &RenameInfo, RenameInfoBuf.size())) { unsigned Error = GetLastError(); if (Error == ERROR_SUCCESS) Error = ERROR_CALL_NOT_IMPLEMENTED; // Wine doesn't always set error code. return mapWindowsError(Error); } return std::error_code(); } static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) { SmallVector WideTo; if (std::error_code EC = widenPath(To, WideTo)) return EC; // We normally expect this loop to succeed after a few iterations. If it // requires more than 200 tries, it's more likely that the failures are due to // a true error, so stop trying. for (unsigned Retry = 0; Retry != 200; ++Retry) { auto EC = rename_internal(FromHandle, To, true); if (EC == std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category())) { // Wine doesn't support SetFileInformationByHandle in rename_internal. // Fall back to MoveFileEx. SmallVector WideFrom; if (std::error_code EC2 = realPathFromHandle(FromHandle, WideFrom)) return EC2; if (::MoveFileExW(WideFrom.begin(), WideTo.begin(), - MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED)) + MOVEFILE_REPLACE_EXISTING)) return std::error_code(); return mapWindowsError(GetLastError()); } if (!EC || EC != errc::permission_denied) return EC; // The destination file probably exists and is currently open in another // process, either because the file was opened without FILE_SHARE_DELETE or // it is mapped into memory (e.g. using MemoryBuffer). Rename it in order to // move it out of the way of the source file. Use FILE_FLAG_DELETE_ON_CLOSE // to arrange for the destination file to be deleted when the other process // closes it. ScopedFileHandle ToHandle( ::CreateFileW(WideTo.begin(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)); if (!ToHandle) { auto EC = mapWindowsError(GetLastError()); // Another process might have raced with us and moved the existing file // out of the way before we had a chance to open it. If that happens, try // to rename the source file again. if (EC == errc::no_such_file_or_directory) continue; return EC; } BY_HANDLE_FILE_INFORMATION FI; if (!GetFileInformationByHandle(ToHandle, &FI)) return mapWindowsError(GetLastError()); // Try to find a unique new name for the destination file. for (unsigned UniqueId = 0; UniqueId != 200; ++UniqueId) { std::string TmpFilename = (To + ".tmp" + utostr(UniqueId)).str(); if (auto EC = rename_internal(ToHandle, TmpFilename, false)) { if (EC == errc::file_exists || EC == errc::permission_denied) { // Again, another process might have raced with us and moved the file // before we could move it. Check whether this is the case, as it // might have caused the permission denied error. If that was the // case, we don't need to move it ourselves. ScopedFileHandle ToHandle2(::CreateFileW( WideTo.begin(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)); if (!ToHandle2) { auto EC = mapWindowsError(GetLastError()); if (EC == errc::no_such_file_or_directory) break; return EC; } BY_HANDLE_FILE_INFORMATION FI2; if (!GetFileInformationByHandle(ToHandle2, &FI2)) return mapWindowsError(GetLastError()); if (FI.nFileIndexHigh != FI2.nFileIndexHigh || FI.nFileIndexLow != FI2.nFileIndexLow || FI.dwVolumeSerialNumber != FI2.dwVolumeSerialNumber) break; continue; } return EC; } break; } // Okay, the old destination file has probably been moved out of the way at // this point, so try to rename the source file again. Still, another // process might have raced with us to create and open the destination // file, so we need to keep doing this until we succeed. } // The most likely root cause. return errc::permission_denied; } static std::error_code rename_fd(int FromFD, const Twine &To) { HANDLE FromHandle = reinterpret_cast(_get_osfhandle(FromFD)); return rename_handle(FromHandle, To); } std::error_code rename(const Twine &From, const Twine &To) { // Convert to utf-16. SmallVector WideFrom; if (std::error_code EC = widenPath(From, WideFrom)) return EC; ScopedFileHandle FromHandle; // Retry this a few times to defeat badly behaved file system scanners. for (unsigned Retry = 0; Retry != 200; ++Retry) { if (Retry != 0) ::Sleep(10); FromHandle = ::CreateFileW(WideFrom.begin(), GENERIC_READ | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (FromHandle) break; } if (!FromHandle) return mapWindowsError(GetLastError()); return rename_handle(FromHandle, To); } std::error_code resize_file(int FD, uint64_t Size) { #ifdef HAVE__CHSIZE_S errno_t error = ::_chsize_s(FD, Size); #else errno_t error = ::_chsize(FD, Size); #endif return std::error_code(error, std::generic_category()); } std::error_code access(const Twine &Path, AccessMode Mode) { SmallVector PathUtf16; if (std::error_code EC = widenPath(Path, PathUtf16)) return EC; DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin()); if (Attributes == INVALID_FILE_ATTRIBUTES) { // See if the file didn't actually exist. DWORD LastError = ::GetLastError(); if (LastError != ERROR_FILE_NOT_FOUND && LastError != ERROR_PATH_NOT_FOUND) return mapWindowsError(LastError); return errc::no_such_file_or_directory; } if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY)) return errc::permission_denied; return std::error_code(); } bool can_execute(const Twine &Path) { return !access(Path, AccessMode::Execute) || !access(Path + ".exe", AccessMode::Execute); } bool equivalent(file_status A, file_status B) { assert(status_known(A) && status_known(B)); return A.FileIndexHigh == B.FileIndexHigh && A.FileIndexLow == B.FileIndexLow && A.FileSizeHigh == B.FileSizeHigh && A.FileSizeLow == B.FileSizeLow && A.LastAccessedTimeHigh == B.LastAccessedTimeHigh && A.LastAccessedTimeLow == B.LastAccessedTimeLow && A.LastWriteTimeHigh == B.LastWriteTimeHigh && A.LastWriteTimeLow == B.LastWriteTimeLow && A.VolumeSerialNumber == B.VolumeSerialNumber; } std::error_code equivalent(const Twine &A, const Twine &B, bool &result) { file_status fsA, fsB; if (std::error_code ec = status(A, fsA)) return ec; if (std::error_code ec = status(B, fsB)) return ec; result = equivalent(fsA, fsB); return std::error_code(); } static bool isReservedName(StringRef path) { // This list of reserved names comes from MSDN, at: // http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx static const char *const sReservedNames[] = { "nul", "con", "prn", "aux", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; // First, check to see if this is a device namespace, which always // starts with \\.\, since device namespaces are not legal file paths. if (path.startswith("\\\\.\\")) return true; // Then compare against the list of ancient reserved names. for (size_t i = 0; i < array_lengthof(sReservedNames); ++i) { if (path.equals_lower(sReservedNames[i])) return true; } // The path isn't what we consider reserved. return false; } static file_type file_type_from_attrs(DWORD Attrs) { return (Attrs & FILE_ATTRIBUTE_DIRECTORY) ? file_type::directory_file : file_type::regular_file; } static perms perms_from_attrs(DWORD Attrs) { return (Attrs & FILE_ATTRIBUTE_READONLY) ? (all_read | all_exe) : all_all; } static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { if (FileHandle == INVALID_HANDLE_VALUE) goto handle_status_error; switch (::GetFileType(FileHandle)) { default: llvm_unreachable("Don't know anything about this file type"); case FILE_TYPE_UNKNOWN: { DWORD Err = ::GetLastError(); if (Err != NO_ERROR) return mapWindowsError(Err); Result = file_status(file_type::type_unknown); return std::error_code(); } case FILE_TYPE_DISK: break; case FILE_TYPE_CHAR: Result = file_status(file_type::character_file); return std::error_code(); case FILE_TYPE_PIPE: Result = file_status(file_type::fifo_file); return std::error_code(); } BY_HANDLE_FILE_INFORMATION Info; if (!::GetFileInformationByHandle(FileHandle, &Info)) goto handle_status_error; Result = file_status( file_type_from_attrs(Info.dwFileAttributes), perms_from_attrs(Info.dwFileAttributes), Info.nNumberOfLinks, Info.ftLastAccessTime.dwHighDateTime, Info.ftLastAccessTime.dwLowDateTime, Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime, Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow); return std::error_code(); handle_status_error: DWORD LastError = ::GetLastError(); if (LastError == ERROR_FILE_NOT_FOUND || LastError == ERROR_PATH_NOT_FOUND) Result = file_status(file_type::file_not_found); else if (LastError == ERROR_SHARING_VIOLATION) Result = file_status(file_type::type_unknown); else Result = file_status(file_type::status_error); return mapWindowsError(LastError); } std::error_code status(const Twine &path, file_status &result, bool Follow) { SmallString<128> path_storage; SmallVector path_utf16; StringRef path8 = path.toStringRef(path_storage); if (isReservedName(path8)) { result = file_status(file_type::character_file); return std::error_code(); } if (std::error_code ec = widenPath(path8, path_utf16)) return ec; DWORD attr = ::GetFileAttributesW(path_utf16.begin()); if (attr == INVALID_FILE_ATTRIBUTES) return getStatus(INVALID_HANDLE_VALUE, result); DWORD Flags = FILE_FLAG_BACKUP_SEMANTICS; // Handle reparse points. if (!Follow && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) Flags |= FILE_FLAG_OPEN_REPARSE_POINT; ScopedFileHandle h( ::CreateFileW(path_utf16.begin(), 0, // Attributes only. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, Flags, 0)); if (!h) return getStatus(INVALID_HANDLE_VALUE, result); return getStatus(h, result); } std::error_code status(int FD, file_status &Result) { HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); return getStatus(FileHandle, Result); } std::error_code setPermissions(const Twine &Path, perms Permissions) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Path, PathUTF16)) return EC; DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin()); if (Attributes == INVALID_FILE_ATTRIBUTES) return mapWindowsError(GetLastError()); // There are many Windows file attributes that are not to do with the file // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve // them. if (Permissions & all_write) { Attributes &= ~FILE_ATTRIBUTE_READONLY; if (Attributes == 0) // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set. Attributes |= FILE_ATTRIBUTE_NORMAL; } else { Attributes |= FILE_ATTRIBUTE_READONLY; // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so // remove it, if it is present. Attributes &= ~FILE_ATTRIBUTE_NORMAL; } if (!::SetFileAttributesW(PathUTF16.begin(), Attributes)) return mapWindowsError(GetLastError()); return std::error_code(); } std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { FILETIME FT = toFILETIME(Time); HANDLE FileHandle = reinterpret_cast(_get_osfhandle(FD)); if (!SetFileTime(FileHandle, NULL, &FT, &FT)) return mapWindowsError(::GetLastError()); return std::error_code(); } std::error_code mapped_file_region::init(int FD, uint64_t Offset, mapmode Mode) { this->Mode = Mode; HANDLE OrigFileHandle = reinterpret_cast(_get_osfhandle(FD)); if (OrigFileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); DWORD flprotect; switch (Mode) { case readonly: flprotect = PAGE_READONLY; break; case readwrite: flprotect = PAGE_READWRITE; break; case priv: flprotect = PAGE_WRITECOPY; break; } HANDLE FileMappingHandle = ::CreateFileMappingW(OrigFileHandle, 0, flprotect, Hi_32(Size), Lo_32(Size), 0); if (FileMappingHandle == NULL) { std::error_code ec = mapWindowsError(GetLastError()); return ec; } DWORD dwDesiredAccess; switch (Mode) { case readonly: dwDesiredAccess = FILE_MAP_READ; break; case readwrite: dwDesiredAccess = FILE_MAP_WRITE; break; case priv: dwDesiredAccess = FILE_MAP_COPY; break; } Mapping = ::MapViewOfFile(FileMappingHandle, dwDesiredAccess, Offset >> 32, Offset & 0xffffffff, Size); if (Mapping == NULL) { std::error_code ec = mapWindowsError(GetLastError()); ::CloseHandle(FileMappingHandle); return ec; } if (Size == 0) { MEMORY_BASIC_INFORMATION mbi; SIZE_T Result = VirtualQuery(Mapping, &mbi, sizeof(mbi)); if (Result == 0) { std::error_code ec = mapWindowsError(GetLastError()); ::UnmapViewOfFile(Mapping); ::CloseHandle(FileMappingHandle); return ec; } Size = mbi.RegionSize; } // Close the file mapping handle, as it's kept alive by the file mapping. But // neither the file mapping nor the file mapping handle keep the file handle // alive, so we need to keep a reference to the file in case all other handles // are closed and the file is deleted, which may cause invalid data to be read // from the file. ::CloseHandle(FileMappingHandle); if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle, ::GetCurrentProcess(), &FileHandle, 0, 0, DUPLICATE_SAME_ACCESS)) { std::error_code ec = mapWindowsError(GetLastError()); ::UnmapViewOfFile(Mapping); return ec; } return std::error_code(); } mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, std::error_code &ec) : Size(length), Mapping() { ec = init(fd, offset, mode); if (ec) Mapping = 0; } mapped_file_region::~mapped_file_region() { if (Mapping) { ::UnmapViewOfFile(Mapping); if (Mode == mapmode::readwrite) { // There is a Windows kernel bug, the exact trigger conditions of which // are not well understood. When triggered, dirty pages are not properly // flushed and subsequent process's attempts to read a file can return // invalid data. Calling FlushFileBuffers on the write handle is // sufficient to ensure that this bug is not triggered. ::FlushFileBuffers(FileHandle); } ::CloseHandle(FileHandle); } } size_t mapped_file_region::size() const { assert(Mapping && "Mapping failed but used anyway!"); return Size; } char *mapped_file_region::data() const { assert(Mapping && "Mapping failed but used anyway!"); return reinterpret_cast(Mapping); } const char *mapped_file_region::const_data() const { assert(Mapping && "Mapping failed but used anyway!"); return reinterpret_cast(Mapping); } int mapped_file_region::alignment() { SYSTEM_INFO SysInfo; ::GetSystemInfo(&SysInfo); return SysInfo.dwAllocationGranularity; } static basic_file_status status_from_find_data(WIN32_FIND_DATAW *FindData) { return basic_file_status(file_type_from_attrs(FindData->dwFileAttributes), perms_from_attrs(FindData->dwFileAttributes), FindData->ftLastAccessTime.dwHighDateTime, FindData->ftLastAccessTime.dwLowDateTime, FindData->ftLastWriteTime.dwHighDateTime, FindData->ftLastWriteTime.dwLowDateTime, FindData->nFileSizeHigh, FindData->nFileSizeLow); } std::error_code detail::directory_iterator_construct(detail::DirIterState &it, StringRef path, bool follow_symlinks) { SmallVector path_utf16; if (std::error_code ec = widenPath(path, path_utf16)) return ec; // Convert path to the format that Windows is happy with. if (path_utf16.size() > 0 && !is_separator(path_utf16[path.size() - 1]) && path_utf16[path.size() - 1] != L':') { path_utf16.push_back(L'\\'); path_utf16.push_back(L'*'); } else { path_utf16.push_back(L'*'); } // Get the first directory entry. WIN32_FIND_DATAW FirstFind; ScopedFindHandle FindHandle(::FindFirstFileExW( c_str(path_utf16), FindExInfoBasic, &FirstFind, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH)); if (!FindHandle) return mapWindowsError(::GetLastError()); size_t FilenameLen = ::wcslen(FirstFind.cFileName); while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && FirstFind.cFileName[1] == L'.')) if (!::FindNextFileW(FindHandle, &FirstFind)) { DWORD LastError = ::GetLastError(); // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); return mapWindowsError(LastError); } else FilenameLen = ::wcslen(FirstFind.cFileName); // Construct the current directory entry. SmallString<128> directory_entry_name_utf8; if (std::error_code ec = UTF16ToUTF8(FirstFind.cFileName, ::wcslen(FirstFind.cFileName), directory_entry_name_utf8)) return ec; it.IterationHandle = intptr_t(FindHandle.take()); SmallString<128> directory_entry_path(path); path::append(directory_entry_path, directory_entry_name_utf8); it.CurrentEntry = directory_entry(directory_entry_path, follow_symlinks, status_from_find_data(&FirstFind)); return std::error_code(); } std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) { if (it.IterationHandle != 0) // Closes the handle if it's valid. ScopedFindHandle close(HANDLE(it.IterationHandle)); it.IterationHandle = 0; it.CurrentEntry = directory_entry(); return std::error_code(); } std::error_code detail::directory_iterator_increment(detail::DirIterState &it) { WIN32_FIND_DATAW FindData; if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { DWORD LastError = ::GetLastError(); // Check for end. if (LastError == ERROR_NO_MORE_FILES) return detail::directory_iterator_destruct(it); return mapWindowsError(LastError); } size_t FilenameLen = ::wcslen(FindData.cFileName); if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || (FilenameLen == 2 && FindData.cFileName[0] == L'.' && FindData.cFileName[1] == L'.')) return directory_iterator_increment(it); SmallString<128> directory_entry_path_utf8; if (std::error_code ec = UTF16ToUTF8(FindData.cFileName, ::wcslen(FindData.cFileName), directory_entry_path_utf8)) return ec; it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8), status_from_find_data(&FindData)); return std::error_code(); } ErrorOr directory_entry::status() const { return Status; } static std::error_code nativeFileToFd(Expected H, int &ResultFD, OpenFlags Flags) { int CrtOpenFlags = 0; if (Flags & OF_Append) CrtOpenFlags |= _O_APPEND; if (Flags & OF_Text) CrtOpenFlags |= _O_TEXT; ResultFD = -1; if (!H) return errorToErrorCode(H.takeError()); ResultFD = ::_open_osfhandle(intptr_t(*H), CrtOpenFlags); if (ResultFD == -1) { ::CloseHandle(*H); return mapWindowsError(ERROR_INVALID_HANDLE); } return std::error_code(); } static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) { // This is a compatibility hack. Really we should respect the creation // disposition, but a lot of old code relied on the implicit assumption that // OF_Append implied it would open an existing file. Since the disposition is // now explicit and defaults to CD_CreateAlways, this assumption would cause // any usage of OF_Append to append to a new file, even if the file already // existed. A better solution might have two new creation dispositions: // CD_AppendAlways and CD_AppendNew. This would also address the problem of // OF_Append being used on a read-only descriptor, which doesn't make sense. if (Flags & OF_Append) return OPEN_ALWAYS; switch (Disp) { case CD_CreateAlways: return CREATE_ALWAYS; case CD_CreateNew: return CREATE_NEW; case CD_OpenAlways: return OPEN_ALWAYS; case CD_OpenExisting: return OPEN_EXISTING; } llvm_unreachable("unreachable!"); } static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { DWORD Result = 0; if (Access & FA_Read) Result |= GENERIC_READ; if (Access & FA_Write) Result |= GENERIC_WRITE; if (Flags & OF_Delete) Result |= DELETE; if (Flags & OF_UpdateAtime) Result |= FILE_WRITE_ATTRIBUTES; return Result; } static std::error_code openNativeFileInternal(const Twine &Name, file_t &ResultFile, DWORD Disp, DWORD Access, DWORD Flags, bool Inherit = false) { SmallVector PathUTF16; if (std::error_code EC = widenPath(Name, PathUTF16)) return EC; SECURITY_ATTRIBUTES SA; SA.nLength = sizeof(SA); SA.lpSecurityDescriptor = nullptr; SA.bInheritHandle = Inherit; HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, &SA, Disp, Flags, NULL); if (H == INVALID_HANDLE_VALUE) { DWORD LastError = ::GetLastError(); std::error_code EC = mapWindowsError(LastError); // Provide a better error message when trying to open directories. // This only runs if we failed to open the file, so there is probably // no performances issues. if (LastError != ERROR_ACCESS_DENIED) return EC; if (is_directory(Name)) return make_error_code(errc::is_a_directory); return EC; } ResultFile = H; return std::error_code(); } Expected openNativeFile(const Twine &Name, CreationDisposition Disp, FileAccess Access, OpenFlags Flags, unsigned Mode) { // Verify that we don't have both "append" and "excl". assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) && "Cannot specify both 'CreateNew' and 'Append' file creation flags!"); DWORD NativeDisp = nativeDisposition(Disp, Flags); DWORD NativeAccess = nativeAccess(Access, Flags); bool Inherit = false; if (Flags & OF_ChildInherit) Inherit = true; file_t Result; std::error_code EC = openNativeFileInternal( Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit); if (EC) return errorCodeToError(EC); if (Flags & OF_UpdateAtime) { FILETIME FileTime; SYSTEMTIME SystemTime; GetSystemTime(&SystemTime); if (SystemTimeToFileTime(&SystemTime, &FileTime) == 0 || SetFileTime(Result, NULL, &FileTime, NULL) == 0) { DWORD LastError = ::GetLastError(); ::CloseHandle(Result); return errorCodeToError(mapWindowsError(LastError)); } } if (Flags & OF_Delete) { if ((EC = setDeleteDisposition(Result, true))) { ::CloseHandle(Result); return errorCodeToError(EC); } } return Result; } std::error_code openFile(const Twine &Name, int &ResultFD, CreationDisposition Disp, FileAccess Access, OpenFlags Flags, unsigned int Mode) { Expected Result = openNativeFile(Name, Disp, Access, Flags); if (!Result) return errorToErrorCode(Result.takeError()); return nativeFileToFd(*Result, ResultFD, Flags); } static std::error_code directoryRealPath(const Twine &Name, SmallVectorImpl &RealPath) { file_t File; std::error_code EC = openNativeFileInternal( Name, File, OPEN_EXISTING, GENERIC_READ, FILE_FLAG_BACKUP_SEMANTICS); if (EC) return EC; EC = realPathFromHandle(File, RealPath); ::CloseHandle(File); return EC; } std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags, SmallVectorImpl *RealPath) { Expected NativeFile = openNativeFileForRead(Name, Flags, RealPath); return nativeFileToFd(std::move(NativeFile), ResultFD, OF_None); } Expected openNativeFileForRead(const Twine &Name, OpenFlags Flags, SmallVectorImpl *RealPath) { Expected Result = openNativeFile(Name, CD_OpenExisting, FA_Read, Flags); // Fetch the real name of the file, if the user asked if (Result && RealPath) realPathFromHandle(*Result, *RealPath); return Result; } void closeFile(file_t &F) { ::CloseHandle(F); F = kInvalidFile; } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { // Convert to utf-16. SmallVector Path16; std::error_code EC = widenPath(path, Path16); if (EC && !IgnoreErrors) return EC; // SHFileOperation() accepts a list of paths, and so must be double null- // terminated to indicate the end of the list. The buffer is already null // terminated, but since that null character is not considered part of the // vector's size, pushing another one will just consume that byte. So we // need to push 2 null terminators. Path16.push_back(0); Path16.push_back(0); SHFILEOPSTRUCTW shfos = {}; shfos.wFunc = FO_DELETE; shfos.pFrom = Path16.data(); shfos.fFlags = FOF_NO_UI; int result = ::SHFileOperationW(&shfos); if (result != 0 && !IgnoreErrors) return mapWindowsError(result); return std::error_code(); } static void expandTildeExpr(SmallVectorImpl &Path) { // Path does not begin with a tilde expression. if (Path.empty() || Path[0] != '~') return; StringRef PathStr(Path.begin(), Path.size()); PathStr = PathStr.drop_front(); StringRef Expr = PathStr.take_until([](char c) { return path::is_separator(c); }); if (!Expr.empty()) { // This is probably a ~username/ expression. Don't support this on Windows. return; } SmallString<128> HomeDir; if (!path::home_directory(HomeDir)) { // For some reason we couldn't get the home directory. Just exit. return; } // Overwrite the first character and insert the rest. Path[0] = HomeDir[0]; Path.insert(Path.begin() + 1, HomeDir.begin() + 1, HomeDir.end()); } std::error_code real_path(const Twine &path, SmallVectorImpl &dest, bool expand_tilde) { dest.clear(); if (path.isTriviallyEmpty()) return std::error_code(); if (expand_tilde) { SmallString<128> Storage; path.toVector(Storage); expandTildeExpr(Storage); return real_path(Storage, dest, false); } if (is_directory(path)) return directoryRealPath(path, dest); int fd; if (std::error_code EC = llvm::sys::fs::openFileForRead(path, fd, OF_None, &dest)) return EC; ::close(fd); return std::error_code(); } } // end namespace fs namespace path { static bool getKnownFolderPath(KNOWNFOLDERID folderId, SmallVectorImpl &result) { wchar_t *path = nullptr; if (::SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, nullptr, &path) != S_OK) return false; bool ok = !UTF16ToUTF8(path, ::wcslen(path), result); ::CoTaskMemFree(path); return ok; } bool getUserCacheDir(SmallVectorImpl &Result) { return getKnownFolderPath(FOLDERID_LocalAppData, Result); } bool home_directory(SmallVectorImpl &result) { return getKnownFolderPath(FOLDERID_Profile, result); } static bool getTempDirEnvVar(const wchar_t *Var, SmallVectorImpl &Res) { SmallVector Buf; size_t Size = 1024; do { Buf.reserve(Size); Size = GetEnvironmentVariableW(Var, Buf.data(), Buf.capacity()); if (Size == 0) return false; // Try again with larger buffer. } while (Size > Buf.capacity()); Buf.set_size(Size); return !windows::UTF16ToUTF8(Buf.data(), Size, Res); } static bool getTempDirEnvVar(SmallVectorImpl &Res) { const wchar_t *EnvironmentVariables[] = {L"TMP", L"TEMP", L"USERPROFILE"}; for (auto *Env : EnvironmentVariables) { if (getTempDirEnvVar(Env, Res)) return true; } return false; } void system_temp_directory(bool ErasedOnReboot, SmallVectorImpl &Result) { (void)ErasedOnReboot; Result.clear(); // Check whether the temporary directory is specified by an environment var. // This matches GetTempPath logic to some degree. GetTempPath is not used // directly as it cannot handle evn var longer than 130 chars on Windows 7 // (fixed on Windows 8). if (getTempDirEnvVar(Result)) { assert(!Result.empty() && "Unexpected empty path"); native(Result); // Some Unix-like shells use Unix path separator in $TMP. fs::make_absolute(Result); // Make it absolute if not already. return; } // Fall back to a system default. const char *DefaultResult = "C:\\Temp"; Result.append(DefaultResult, DefaultResult + strlen(DefaultResult)); } } // end namespace path namespace windows { std::error_code CodePageToUTF16(unsigned codepage, llvm::StringRef original, llvm::SmallVectorImpl &utf16) { if (!original.empty()) { int len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), original.size(), utf16.begin(), 0); if (len == 0) { return mapWindowsError(::GetLastError()); } utf16.reserve(len + 1); utf16.set_size(len); len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.begin(), original.size(), utf16.begin(), utf16.size()); if (len == 0) { return mapWindowsError(::GetLastError()); } } // Make utf16 null terminated. utf16.push_back(0); utf16.pop_back(); return std::error_code(); } std::error_code UTF8ToUTF16(llvm::StringRef utf8, llvm::SmallVectorImpl &utf16) { return CodePageToUTF16(CP_UTF8, utf8, utf16); } std::error_code CurCPToUTF16(llvm::StringRef curcp, llvm::SmallVectorImpl &utf16) { return CodePageToUTF16(CP_ACP, curcp, utf16); } static std::error_code UTF16ToCodePage(unsigned codepage, const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &converted) { if (utf16_len) { // Get length. int len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.begin(), 0, NULL, NULL); if (len == 0) { return mapWindowsError(::GetLastError()); } converted.reserve(len); converted.set_size(len); // Now do the actual conversion. len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(), converted.size(), NULL, NULL); if (len == 0) { return mapWindowsError(::GetLastError()); } } // Make the new string null terminated. converted.push_back(0); converted.pop_back(); return std::error_code(); } std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &utf8) { return UTF16ToCodePage(CP_UTF8, utf16, utf16_len, utf8); } std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len, llvm::SmallVectorImpl &curcp) { return UTF16ToCodePage(CP_ACP, utf16, utf16_len, curcp); } } // end namespace windows } // end namespace sys } // end namespace llvm Index: vendor/llvm/dist-release_70/lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- vendor/llvm/dist-release_70/lib/Target/AArch64/AArch64SystemOperands.td (revision 338377) +++ vendor/llvm/dist-release_70/lib/Target/AArch64/AArch64SystemOperands.td (revision 338378) @@ -1,1317 +1,1332 @@ //===- AArch64SystemOperands.td ----------------------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the symbolic operands permitted for various kinds of // AArch64 system instruction. // //===----------------------------------------------------------------------===// include "llvm/TableGen/SearchableTable.td" //===----------------------------------------------------------------------===// // AT (address translate) instruction options. //===----------------------------------------------------------------------===// class AT op1, bits<4> crn, bits<4> crm, bits<3> op2> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<14> Encoding; let Encoding{13-11} = op1; let Encoding{10-7} = crn; let Encoding{6-3} = crm; let Encoding{2-0} = op2; code Requires = [{ {} }]; } def : AT<"S1E1R", 0b000, 0b0111, 0b1000, 0b000>; def : AT<"S1E2R", 0b100, 0b0111, 0b1000, 0b000>; def : AT<"S1E3R", 0b110, 0b0111, 0b1000, 0b000>; def : AT<"S1E1W", 0b000, 0b0111, 0b1000, 0b001>; def : AT<"S1E2W", 0b100, 0b0111, 0b1000, 0b001>; def : AT<"S1E3W", 0b110, 0b0111, 0b1000, 0b001>; def : AT<"S1E0R", 0b000, 0b0111, 0b1000, 0b010>; def : AT<"S1E0W", 0b000, 0b0111, 0b1000, 0b011>; def : AT<"S12E1R", 0b100, 0b0111, 0b1000, 0b100>; def : AT<"S12E1W", 0b100, 0b0111, 0b1000, 0b101>; def : AT<"S12E0R", 0b100, 0b0111, 0b1000, 0b110>; def : AT<"S12E0W", 0b100, 0b0111, 0b1000, 0b111>; let Requires = [{ {AArch64::HasV8_2aOps} }] in { def : AT<"S1E1RP", 0b000, 0b0111, 0b1001, 0b000>; def : AT<"S1E1WP", 0b000, 0b0111, 0b1001, 0b001>; } //===----------------------------------------------------------------------===// // DMB/DSB (data barrier) instruction options. //===----------------------------------------------------------------------===// class DB encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<4> Encoding = encoding; } def : DB<"oshld", 0x1>; def : DB<"oshst", 0x2>; def : DB<"osh", 0x3>; def : DB<"nshld", 0x5>; def : DB<"nshst", 0x6>; def : DB<"nsh", 0x7>; def : DB<"ishld", 0x9>; def : DB<"ishst", 0xa>; def : DB<"ish", 0xb>; def : DB<"ld", 0xd>; def : DB<"st", 0xe>; def : DB<"sy", 0xf>; //===----------------------------------------------------------------------===// // DC (data cache maintenance) instruction options. //===----------------------------------------------------------------------===// class DC op1, bits<4> crn, bits<4> crm, bits<3> op2> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<14> Encoding; let Encoding{13-11} = op1; let Encoding{10-7} = crn; let Encoding{6-3} = crm; let Encoding{2-0} = op2; code Requires = [{ {} }]; } def : DC<"ZVA", 0b011, 0b0111, 0b0100, 0b001>; def : DC<"IVAC", 0b000, 0b0111, 0b0110, 0b001>; def : DC<"ISW", 0b000, 0b0111, 0b0110, 0b010>; def : DC<"CVAC", 0b011, 0b0111, 0b1010, 0b001>; def : DC<"CSW", 0b000, 0b0111, 0b1010, 0b010>; def : DC<"CVAU", 0b011, 0b0111, 0b1011, 0b001>; def : DC<"CIVAC", 0b011, 0b0111, 0b1110, 0b001>; def : DC<"CISW", 0b000, 0b0111, 0b1110, 0b010>; let Requires = [{ {AArch64::HasV8_2aOps} }] in def : DC<"CVAP", 0b011, 0b0111, 0b1100, 0b001>; //===----------------------------------------------------------------------===// // IC (instruction cache maintenance) instruction options. //===----------------------------------------------------------------------===// class IC op1, bits<4> crn, bits<4> crm, bits<3> op2, bit needsreg> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<14> Encoding; let Encoding{13-11} = op1; let Encoding{10-7} = crn; let Encoding{6-3} = crm; let Encoding{2-0} = op2; bit NeedsReg = needsreg; } def : IC<"IALLUIS", 0b000, 0b0111, 0b0001, 0b000, 0>; def : IC<"IALLU", 0b000, 0b0111, 0b0101, 0b000, 0>; def : IC<"IVAU", 0b011, 0b0111, 0b0101, 0b001, 1>; //===----------------------------------------------------------------------===// // ISB (instruction-fetch barrier) instruction options. //===----------------------------------------------------------------------===// class ISB encoding> : SearchableTable{ let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<4> Encoding; let Encoding = encoding; } def : ISB<"sy", 0xf>; //===----------------------------------------------------------------------===// // TSB (Trace synchronization barrier) instruction options. //===----------------------------------------------------------------------===// class TSB encoding> : SearchableTable{ let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<4> Encoding; let Encoding = encoding; code Requires = [{ {AArch64::HasV8_4aOps} }]; } def : TSB<"csync", 0>; //===----------------------------------------------------------------------===// // PRFM (prefetch) instruction options. //===----------------------------------------------------------------------===// class PRFM encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<5> Encoding; let Encoding = encoding; } def : PRFM<"pldl1keep", 0x00>; def : PRFM<"pldl1strm", 0x01>; def : PRFM<"pldl2keep", 0x02>; def : PRFM<"pldl2strm", 0x03>; def : PRFM<"pldl3keep", 0x04>; def : PRFM<"pldl3strm", 0x05>; def : PRFM<"plil1keep", 0x08>; def : PRFM<"plil1strm", 0x09>; def : PRFM<"plil2keep", 0x0a>; def : PRFM<"plil2strm", 0x0b>; def : PRFM<"plil3keep", 0x0c>; def : PRFM<"plil3strm", 0x0d>; def : PRFM<"pstl1keep", 0x10>; def : PRFM<"pstl1strm", 0x11>; def : PRFM<"pstl2keep", 0x12>; def : PRFM<"pstl2strm", 0x13>; def : PRFM<"pstl3keep", 0x14>; def : PRFM<"pstl3strm", 0x15>; //===----------------------------------------------------------------------===// // SVE Prefetch instruction options. //===----------------------------------------------------------------------===// class SVEPRFM encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<4> Encoding; let Encoding = encoding; code Requires = [{ {} }]; } let Requires = [{ {AArch64::FeatureSVE} }] in { def : SVEPRFM<"pldl1keep", 0x00>; def : SVEPRFM<"pldl1strm", 0x01>; def : SVEPRFM<"pldl2keep", 0x02>; def : SVEPRFM<"pldl2strm", 0x03>; def : SVEPRFM<"pldl3keep", 0x04>; def : SVEPRFM<"pldl3strm", 0x05>; def : SVEPRFM<"pstl1keep", 0x08>; def : SVEPRFM<"pstl1strm", 0x09>; def : SVEPRFM<"pstl2keep", 0x0a>; def : SVEPRFM<"pstl2strm", 0x0b>; def : SVEPRFM<"pstl3keep", 0x0c>; def : SVEPRFM<"pstl3strm", 0x0d>; } //===----------------------------------------------------------------------===// // SVE Predicate patterns //===----------------------------------------------------------------------===// class SVEPREDPAT encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<5> Encoding; let Encoding = encoding; } def : SVEPREDPAT<"pow2", 0x00>; def : SVEPREDPAT<"vl1", 0x01>; def : SVEPREDPAT<"vl2", 0x02>; def : SVEPREDPAT<"vl3", 0x03>; def : SVEPREDPAT<"vl4", 0x04>; def : SVEPREDPAT<"vl5", 0x05>; def : SVEPREDPAT<"vl6", 0x06>; def : SVEPREDPAT<"vl7", 0x07>; def : SVEPREDPAT<"vl8", 0x08>; def : SVEPREDPAT<"vl16", 0x09>; def : SVEPREDPAT<"vl32", 0x0a>; def : SVEPREDPAT<"vl64", 0x0b>; def : SVEPREDPAT<"vl128", 0x0c>; def : SVEPREDPAT<"vl256", 0x0d>; def : SVEPREDPAT<"mul4", 0x1d>; def : SVEPREDPAT<"mul3", 0x1e>; def : SVEPREDPAT<"all", 0x1f>; //===----------------------------------------------------------------------===// // Exact FP Immediates. // // These definitions are used to create a lookup table with FP Immediates that // is used for a few instructions that only accept a limited set of exact FP // immediates values. //===----------------------------------------------------------------------===// class ExactFPImm enum > : SearchableTable { let SearchableFields = ["Enum", "Repr"]; let EnumValueField = "Enum"; string Name = name; bits<4> Enum = enum; string Repr = repr; } def : ExactFPImm<"zero", "0.0", 0x0>; def : ExactFPImm<"half", "0.5", 0x1>; def : ExactFPImm<"one", "1.0", 0x2>; def : ExactFPImm<"two", "2.0", 0x3>; //===----------------------------------------------------------------------===// // PState instruction options. //===----------------------------------------------------------------------===// class PState encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<5> Encoding; let Encoding = encoding; code Requires = [{ {} }]; } def : PState<"SPSel", 0b00101>; def : PState<"DAIFSet", 0b11110>; def : PState<"DAIFClr", 0b11111>; // v8.1a "Privileged Access Never" extension-specific PStates let Requires = [{ {AArch64::HasV8_1aOps} }] in def : PState<"PAN", 0b00100>; // v8.2a "User Access Override" extension-specific PStates let Requires = [{ {AArch64::HasV8_2aOps} }] in def : PState<"UAO", 0b00011>; // v8.4a timining insensitivity of data processing instructions let Requires = [{ {AArch64::HasV8_4aOps} }] in def : PState<"DIT", 0b11010>; //===----------------------------------------------------------------------===// // PSB instruction options. //===----------------------------------------------------------------------===// class PSB encoding> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<5> Encoding; let Encoding = encoding; } def : PSB<"csync", 0x11>; //===----------------------------------------------------------------------===// // TLBI (translation lookaside buffer invalidate) instruction options. //===----------------------------------------------------------------------===// class TLBI op1, bits<4> crn, bits<4> crm, bits<3> op2, bit needsreg = 1> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<14> Encoding; let Encoding{13-11} = op1; let Encoding{10-7} = crn; let Encoding{6-3} = crm; let Encoding{2-0} = op2; bit NeedsReg = needsreg; code Requires = [{ {} }]; } def : TLBI<"IPAS2E1IS", 0b100, 0b1000, 0b0000, 0b001>; def : TLBI<"IPAS2LE1IS", 0b100, 0b1000, 0b0000, 0b101>; def : TLBI<"VMALLE1IS", 0b000, 0b1000, 0b0011, 0b000, 0>; def : TLBI<"ALLE2IS", 0b100, 0b1000, 0b0011, 0b000, 0>; def : TLBI<"ALLE3IS", 0b110, 0b1000, 0b0011, 0b000, 0>; def : TLBI<"VAE1IS", 0b000, 0b1000, 0b0011, 0b001>; def : TLBI<"VAE2IS", 0b100, 0b1000, 0b0011, 0b001>; def : TLBI<"VAE3IS", 0b110, 0b1000, 0b0011, 0b001>; def : TLBI<"ASIDE1IS", 0b000, 0b1000, 0b0011, 0b010>; def : TLBI<"VAAE1IS", 0b000, 0b1000, 0b0011, 0b011>; def : TLBI<"ALLE1IS", 0b100, 0b1000, 0b0011, 0b100, 0>; def : TLBI<"VALE1IS", 0b000, 0b1000, 0b0011, 0b101>; def : TLBI<"VALE2IS", 0b100, 0b1000, 0b0011, 0b101>; def : TLBI<"VALE3IS", 0b110, 0b1000, 0b0011, 0b101>; def : TLBI<"VMALLS12E1IS", 0b100, 0b1000, 0b0011, 0b110, 0>; def : TLBI<"VAALE1IS", 0b000, 0b1000, 0b0011, 0b111>; def : TLBI<"IPAS2E1", 0b100, 0b1000, 0b0100, 0b001>; def : TLBI<"IPAS2LE1", 0b100, 0b1000, 0b0100, 0b101>; def : TLBI<"VMALLE1", 0b000, 0b1000, 0b0111, 0b000, 0>; def : TLBI<"ALLE2", 0b100, 0b1000, 0b0111, 0b000, 0>; def : TLBI<"ALLE3", 0b110, 0b1000, 0b0111, 0b000, 0>; def : TLBI<"VAE1", 0b000, 0b1000, 0b0111, 0b001>; def : TLBI<"VAE2", 0b100, 0b1000, 0b0111, 0b001>; def : TLBI<"VAE3", 0b110, 0b1000, 0b0111, 0b001>; def : TLBI<"ASIDE1", 0b000, 0b1000, 0b0111, 0b010>; def : TLBI<"VAAE1", 0b000, 0b1000, 0b0111, 0b011>; def : TLBI<"ALLE1", 0b100, 0b1000, 0b0111, 0b100, 0>; def : TLBI<"VALE1", 0b000, 0b1000, 0b0111, 0b101>; def : TLBI<"VALE2", 0b100, 0b1000, 0b0111, 0b101>; def : TLBI<"VALE3", 0b110, 0b1000, 0b0111, 0b101>; def : TLBI<"VMALLS12E1", 0b100, 0b1000, 0b0111, 0b110, 0>; def : TLBI<"VAALE1", 0b000, 0b1000, 0b0111, 0b111>; // Armv8.4-A Outer Sharable TLB Maintenance instructions: let Requires = [{ {AArch64::HasV8_4aOps} }] in { // op1 CRn CRm op2 def : TLBI<"VMALLE1OS", 0b000, 0b1000, 0b0001, 0b000, 0>; def : TLBI<"VAE1OS", 0b000, 0b1000, 0b0001, 0b001>; def : TLBI<"ASIDE1OS", 0b000, 0b1000, 0b0001, 0b010>; def : TLBI<"VAAE1OS", 0b000, 0b1000, 0b0001, 0b011>; def : TLBI<"VALE1OS", 0b000, 0b1000, 0b0001, 0b101>; def : TLBI<"VAALE1OS", 0b000, 0b1000, 0b0001, 0b111>; def : TLBI<"IPAS2E1OS", 0b100, 0b1000, 0b0100, 0b000>; def : TLBI<"IPAS2LE1OS", 0b100, 0b1000, 0b0100, 0b100>; def : TLBI<"VAE2OS", 0b100, 0b1000, 0b0001, 0b001>; def : TLBI<"VALE2OS", 0b100, 0b1000, 0b0001, 0b101>; def : TLBI<"VMALLS12E1OS", 0b100, 0b1000, 0b0001, 0b110, 0>; def : TLBI<"VAE3OS", 0b110, 0b1000, 0b0001, 0b001>; def : TLBI<"VALE3OS", 0b110, 0b1000, 0b0001, 0b101>; def : TLBI<"ALLE2OS", 0b100, 0b1000, 0b0001, 0b000, 0>; def : TLBI<"ALLE1OS", 0b100, 0b1000, 0b0001, 0b100, 0>; def : TLBI<"ALLE3OS", 0b110, 0b1000, 0b0001, 0b000, 0>; // Armv8.4-A TLB Range Maintenance instructions: // op1 CRn CRm op2 def : TLBI<"RVAE1", 0b000, 0b1000, 0b0110, 0b001>; def : TLBI<"RVAAE1", 0b000, 0b1000, 0b0110, 0b011>; def : TLBI<"RVALE1", 0b000, 0b1000, 0b0110, 0b101>; def : TLBI<"RVAALE1", 0b000, 0b1000, 0b0110, 0b111>; def : TLBI<"RVAE1IS", 0b000, 0b1000, 0b0010, 0b001>; def : TLBI<"RVAAE1IS", 0b000, 0b1000, 0b0010, 0b011>; def : TLBI<"RVALE1IS", 0b000, 0b1000, 0b0010, 0b101>; def : TLBI<"RVAALE1IS", 0b000, 0b1000, 0b0010, 0b111>; def : TLBI<"RVAE1OS", 0b000, 0b1000, 0b0101, 0b001>; def : TLBI<"RVAAE1OS", 0b000, 0b1000, 0b0101, 0b011>; def : TLBI<"RVALE1OS", 0b000, 0b1000, 0b0101, 0b101>; def : TLBI<"RVAALE1OS", 0b000, 0b1000, 0b0101, 0b111>; def : TLBI<"RIPAS2E1IS", 0b100, 0b1000, 0b0000, 0b010>; def : TLBI<"RIPAS2LE1IS", 0b100, 0b1000, 0b0000, 0b110>; def : TLBI<"RIPAS2E1", 0b100, 0b1000, 0b0100, 0b010>; def : TLBI<"RIPAS2LE1", 0b100, 0b1000, 0b0100, 0b110>; def : TLBI<"RIPAS2E1OS", 0b100, 0b1000, 0b0100, 0b011>; def : TLBI<"RIPAS2LE1OS", 0b100, 0b1000, 0b0100, 0b111>; def : TLBI<"RVAE2", 0b100, 0b1000, 0b0110, 0b001>; def : TLBI<"RVALE2", 0b100, 0b1000, 0b0110, 0b101>; def : TLBI<"RVAE2IS", 0b100, 0b1000, 0b0010, 0b001>; def : TLBI<"RVALE2IS", 0b100, 0b1000, 0b0010, 0b101>; def : TLBI<"RVAE2OS", 0b100, 0b1000, 0b0101, 0b001>; def : TLBI<"RVALE2OS", 0b100, 0b1000, 0b0101, 0b101>; def : TLBI<"RVAE3", 0b110, 0b1000, 0b0110, 0b001>; def : TLBI<"RVALE3", 0b110, 0b1000, 0b0110, 0b101>; def : TLBI<"RVAE3IS", 0b110, 0b1000, 0b0010, 0b001>; def : TLBI<"RVALE3IS", 0b110, 0b1000, 0b0010, 0b101>; def : TLBI<"RVAE3OS", 0b110, 0b1000, 0b0101, 0b001>; def : TLBI<"RVALE3OS", 0b110, 0b1000, 0b0101, 0b101>; } //===----------------------------------------------------------------------===// // MRS/MSR (system register read/write) instruction options. //===----------------------------------------------------------------------===// class SysReg op0, bits<3> op1, bits<4> crn, bits<4> crm, bits<3> op2> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; bits<16> Encoding; let Encoding{15-14} = op0; let Encoding{13-11} = op1; let Encoding{10-7} = crn; let Encoding{6-3} = crm; let Encoding{2-0} = op2; bit Readable = ?; bit Writeable = ?; code Requires = [{ {} }]; } class RWSysReg op0, bits<3> op1, bits<4> crn, bits<4> crm, bits<3> op2> : SysReg { let Readable = 1; let Writeable = 1; } class ROSysReg op0, bits<3> op1, bits<4> crn, bits<4> crm, bits<3> op2> : SysReg { let Readable = 1; let Writeable = 0; } class WOSysReg op0, bits<3> op1, bits<4> crn, bits<4> crm, bits<3> op2> : SysReg { let Readable = 0; let Writeable = 1; } //===---------------------- // Read-only regs //===---------------------- // Op0 Op1 CRn CRm Op2 def : ROSysReg<"MDCCSR_EL0", 0b10, 0b011, 0b0000, 0b0001, 0b000>; def : ROSysReg<"DBGDTRRX_EL0", 0b10, 0b011, 0b0000, 0b0101, 0b000>; def : ROSysReg<"MDRAR_EL1", 0b10, 0b000, 0b0001, 0b0000, 0b000>; def : ROSysReg<"OSLSR_EL1", 0b10, 0b000, 0b0001, 0b0001, 0b100>; def : ROSysReg<"DBGAUTHSTATUS_EL1", 0b10, 0b000, 0b0111, 0b1110, 0b110>; def : ROSysReg<"PMCEID0_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b110>; def : ROSysReg<"PMCEID1_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b111>; def : ROSysReg<"MIDR_EL1", 0b11, 0b000, 0b0000, 0b0000, 0b000>; def : ROSysReg<"CCSIDR_EL1", 0b11, 0b001, 0b0000, 0b0000, 0b000>; def : ROSysReg<"CCSIDR2_EL1", 0b11, 0b001, 0b0000, 0b0000, 0b010> { let Requires = [{ {AArch64::HasV8_3aOps} }]; } def : ROSysReg<"CLIDR_EL1", 0b11, 0b001, 0b0000, 0b0000, 0b001>; def : ROSysReg<"CTR_EL0", 0b11, 0b011, 0b0000, 0b0000, 0b001>; def : ROSysReg<"MPIDR_EL1", 0b11, 0b000, 0b0000, 0b0000, 0b101>; def : ROSysReg<"REVIDR_EL1", 0b11, 0b000, 0b0000, 0b0000, 0b110>; def : ROSysReg<"AIDR_EL1", 0b11, 0b001, 0b0000, 0b0000, 0b111>; def : ROSysReg<"DCZID_EL0", 0b11, 0b011, 0b0000, 0b0000, 0b111>; def : ROSysReg<"ID_PFR0_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b000>; def : ROSysReg<"ID_PFR1_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b001>; def : ROSysReg<"ID_DFR0_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b010>; def : ROSysReg<"ID_AFR0_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b011>; def : ROSysReg<"ID_MMFR0_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b100>; def : ROSysReg<"ID_MMFR1_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b101>; def : ROSysReg<"ID_MMFR2_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b110>; def : ROSysReg<"ID_MMFR3_EL1", 0b11, 0b000, 0b0000, 0b0001, 0b111>; def : ROSysReg<"ID_ISAR0_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b000>; def : ROSysReg<"ID_ISAR1_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b001>; def : ROSysReg<"ID_ISAR2_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b010>; def : ROSysReg<"ID_ISAR3_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b011>; def : ROSysReg<"ID_ISAR4_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b100>; def : ROSysReg<"ID_ISAR5_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b101>; def : ROSysReg<"ID_ISAR6_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b111> { let Requires = [{ {AArch64::HasV8_2aOps} }]; } def : ROSysReg<"ID_AA64PFR0_EL1", 0b11, 0b000, 0b0000, 0b0100, 0b000>; def : ROSysReg<"ID_AA64PFR1_EL1", 0b11, 0b000, 0b0000, 0b0100, 0b001>; def : ROSysReg<"ID_AA64DFR0_EL1", 0b11, 0b000, 0b0000, 0b0101, 0b000>; def : ROSysReg<"ID_AA64DFR1_EL1", 0b11, 0b000, 0b0000, 0b0101, 0b001>; def : ROSysReg<"ID_AA64AFR0_EL1", 0b11, 0b000, 0b0000, 0b0101, 0b100>; def : ROSysReg<"ID_AA64AFR1_EL1", 0b11, 0b000, 0b0000, 0b0101, 0b101>; def : ROSysReg<"ID_AA64ISAR0_EL1", 0b11, 0b000, 0b0000, 0b0110, 0b000>; def : ROSysReg<"ID_AA64ISAR1_EL1", 0b11, 0b000, 0b0000, 0b0110, 0b001>; def : ROSysReg<"ID_AA64MMFR0_EL1", 0b11, 0b000, 0b0000, 0b0111, 0b000>; def : ROSysReg<"ID_AA64MMFR1_EL1", 0b11, 0b000, 0b0000, 0b0111, 0b001>; def : ROSysReg<"ID_AA64MMFR2_EL1", 0b11, 0b000, 0b0000, 0b0111, 0b010> { let Requires = [{ {AArch64::HasV8_2aOps} }]; } def : ROSysReg<"MVFR0_EL1", 0b11, 0b000, 0b0000, 0b0011, 0b000>; def : ROSysReg<"MVFR1_EL1", 0b11, 0b000, 0b0000, 0b0011, 0b001>; def : ROSysReg<"MVFR2_EL1", 0b11, 0b000, 0b0000, 0b0011, 0b010>; def : ROSysReg<"RVBAR_EL1", 0b11, 0b000, 0b1100, 0b0000, 0b001>; def : ROSysReg<"RVBAR_EL2", 0b11, 0b100, 0b1100, 0b0000, 0b001>; def : ROSysReg<"RVBAR_EL3", 0b11, 0b110, 0b1100, 0b0000, 0b001>; def : ROSysReg<"ISR_EL1", 0b11, 0b000, 0b1100, 0b0001, 0b000>; def : ROSysReg<"CNTPCT_EL0", 0b11, 0b011, 0b1110, 0b0000, 0b001>; def : ROSysReg<"CNTVCT_EL0", 0b11, 0b011, 0b1110, 0b0000, 0b010>; def : ROSysReg<"ID_MMFR4_EL1", 0b11, 0b000, 0b0000, 0b0010, 0b110>; // Trace registers // Op0 Op1 CRn CRm Op2 def : ROSysReg<"TRCSTATR", 0b10, 0b001, 0b0000, 0b0011, 0b000>; def : ROSysReg<"TRCIDR8", 0b10, 0b001, 0b0000, 0b0000, 0b110>; def : ROSysReg<"TRCIDR9", 0b10, 0b001, 0b0000, 0b0001, 0b110>; def : ROSysReg<"TRCIDR10", 0b10, 0b001, 0b0000, 0b0010, 0b110>; def : ROSysReg<"TRCIDR11", 0b10, 0b001, 0b0000, 0b0011, 0b110>; def : ROSysReg<"TRCIDR12", 0b10, 0b001, 0b0000, 0b0100, 0b110>; def : ROSysReg<"TRCIDR13", 0b10, 0b001, 0b0000, 0b0101, 0b110>; def : ROSysReg<"TRCIDR0", 0b10, 0b001, 0b0000, 0b1000, 0b111>; def : ROSysReg<"TRCIDR1", 0b10, 0b001, 0b0000, 0b1001, 0b111>; def : ROSysReg<"TRCIDR2", 0b10, 0b001, 0b0000, 0b1010, 0b111>; def : ROSysReg<"TRCIDR3", 0b10, 0b001, 0b0000, 0b1011, 0b111>; def : ROSysReg<"TRCIDR4", 0b10, 0b001, 0b0000, 0b1100, 0b111>; def : ROSysReg<"TRCIDR5", 0b10, 0b001, 0b0000, 0b1101, 0b111>; def : ROSysReg<"TRCIDR6", 0b10, 0b001, 0b0000, 0b1110, 0b111>; def : ROSysReg<"TRCIDR7", 0b10, 0b001, 0b0000, 0b1111, 0b111>; def : ROSysReg<"TRCOSLSR", 0b10, 0b001, 0b0001, 0b0001, 0b100>; def : ROSysReg<"TRCPDSR", 0b10, 0b001, 0b0001, 0b0101, 0b100>; def : ROSysReg<"TRCDEVAFF0", 0b10, 0b001, 0b0111, 0b1010, 0b110>; def : ROSysReg<"TRCDEVAFF1", 0b10, 0b001, 0b0111, 0b1011, 0b110>; def : ROSysReg<"TRCLSR", 0b10, 0b001, 0b0111, 0b1101, 0b110>; def : ROSysReg<"TRCAUTHSTATUS", 0b10, 0b001, 0b0111, 0b1110, 0b110>; def : ROSysReg<"TRCDEVARCH", 0b10, 0b001, 0b0111, 0b1111, 0b110>; def : ROSysReg<"TRCDEVID", 0b10, 0b001, 0b0111, 0b0010, 0b111>; def : ROSysReg<"TRCDEVTYPE", 0b10, 0b001, 0b0111, 0b0011, 0b111>; def : ROSysReg<"TRCPIDR4", 0b10, 0b001, 0b0111, 0b0100, 0b111>; def : ROSysReg<"TRCPIDR5", 0b10, 0b001, 0b0111, 0b0101, 0b111>; def : ROSysReg<"TRCPIDR6", 0b10, 0b001, 0b0111, 0b0110, 0b111>; def : ROSysReg<"TRCPIDR7", 0b10, 0b001, 0b0111, 0b0111, 0b111>; def : ROSysReg<"TRCPIDR0", 0b10, 0b001, 0b0111, 0b1000, 0b111>; def : ROSysReg<"TRCPIDR1", 0b10, 0b001, 0b0111, 0b1001, 0b111>; def : ROSysReg<"TRCPIDR2", 0b10, 0b001, 0b0111, 0b1010, 0b111>; def : ROSysReg<"TRCPIDR3", 0b10, 0b001, 0b0111, 0b1011, 0b111>; def : ROSysReg<"TRCCIDR0", 0b10, 0b001, 0b0111, 0b1100, 0b111>; def : ROSysReg<"TRCCIDR1", 0b10, 0b001, 0b0111, 0b1101, 0b111>; def : ROSysReg<"TRCCIDR2", 0b10, 0b001, 0b0111, 0b1110, 0b111>; def : ROSysReg<"TRCCIDR3", 0b10, 0b001, 0b0111, 0b1111, 0b111>; // GICv3 registers // Op0 Op1 CRn CRm Op2 def : ROSysReg<"ICC_IAR1_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b000>; def : ROSysReg<"ICC_IAR0_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b000>; def : ROSysReg<"ICC_HPPIR1_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b010>; def : ROSysReg<"ICC_HPPIR0_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b010>; def : ROSysReg<"ICC_RPR_EL1", 0b11, 0b000, 0b1100, 0b1011, 0b011>; def : ROSysReg<"ICH_VTR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b001>; def : ROSysReg<"ICH_EISR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b011>; def : ROSysReg<"ICH_ELRSR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b101>; +// SVE control registers +// Op0 Op1 CRn CRm Op2 +let Requires = [{ {AArch64::FeatureSVE} }] in { +def : ROSysReg<"ID_AA64ZFR0_EL1", 0b11, 0b000, 0b0000, 0b0100, 0b100>; +} + // v8.1a "Limited Ordering Regions" extension-specific system register // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::HasV8_1aOps} }] in def : ROSysReg<"LORID_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b111>; // v8.2a "RAS extension" registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::FeatureRAS} }] in { def : ROSysReg<"ERRIDR_EL1", 0b11, 0b000, 0b0101, 0b0011, 0b000>; def : ROSysReg<"ERXFR_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b000>; } //===---------------------- // Write-only regs //===---------------------- // Op0 Op1 CRn CRm Op2 def : WOSysReg<"DBGDTRTX_EL0", 0b10, 0b011, 0b0000, 0b0101, 0b000>; def : WOSysReg<"OSLAR_EL1", 0b10, 0b000, 0b0001, 0b0000, 0b100>; def : WOSysReg<"PMSWINC_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b100>; // Trace Registers // Op0 Op1 CRn CRm Op2 def : WOSysReg<"TRCOSLAR", 0b10, 0b001, 0b0001, 0b0000, 0b100>; def : WOSysReg<"TRCLAR", 0b10, 0b001, 0b0111, 0b1100, 0b110>; // GICv3 registers // Op0 Op1 CRn CRm Op2 def : WOSysReg<"ICC_EOIR1_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b001>; def : WOSysReg<"ICC_EOIR0_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b001>; def : WOSysReg<"ICC_DIR_EL1", 0b11, 0b000, 0b1100, 0b1011, 0b001>; def : WOSysReg<"ICC_SGI1R_EL1", 0b11, 0b000, 0b1100, 0b1011, 0b101>; def : WOSysReg<"ICC_ASGI1R_EL1", 0b11, 0b000, 0b1100, 0b1011, 0b110>; def : WOSysReg<"ICC_SGI0R_EL1", 0b11, 0b000, 0b1100, 0b1011, 0b111>; //===---------------------- // Read-write regs //===---------------------- // Op0 Op1 CRn CRm Op2 def : RWSysReg<"OSDTRRX_EL1", 0b10, 0b000, 0b0000, 0b0000, 0b010>; def : RWSysReg<"OSDTRTX_EL1", 0b10, 0b000, 0b0000, 0b0011, 0b010>; def : RWSysReg<"TEECR32_EL1", 0b10, 0b010, 0b0000, 0b0000, 0b000>; def : RWSysReg<"MDCCINT_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b000>; def : RWSysReg<"MDSCR_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b010>; def : RWSysReg<"DBGDTR_EL0", 0b10, 0b011, 0b0000, 0b0100, 0b000>; def : RWSysReg<"OSECCR_EL1", 0b10, 0b000, 0b0000, 0b0110, 0b010>; def : RWSysReg<"DBGVCR32_EL2", 0b10, 0b100, 0b0000, 0b0111, 0b000>; def : RWSysReg<"DBGBVR0_EL1", 0b10, 0b000, 0b0000, 0b0000, 0b100>; def : RWSysReg<"DBGBVR1_EL1", 0b10, 0b000, 0b0000, 0b0001, 0b100>; def : RWSysReg<"DBGBVR2_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b100>; def : RWSysReg<"DBGBVR3_EL1", 0b10, 0b000, 0b0000, 0b0011, 0b100>; def : RWSysReg<"DBGBVR4_EL1", 0b10, 0b000, 0b0000, 0b0100, 0b100>; def : RWSysReg<"DBGBVR5_EL1", 0b10, 0b000, 0b0000, 0b0101, 0b100>; def : RWSysReg<"DBGBVR6_EL1", 0b10, 0b000, 0b0000, 0b0110, 0b100>; def : RWSysReg<"DBGBVR7_EL1", 0b10, 0b000, 0b0000, 0b0111, 0b100>; def : RWSysReg<"DBGBVR8_EL1", 0b10, 0b000, 0b0000, 0b1000, 0b100>; def : RWSysReg<"DBGBVR9_EL1", 0b10, 0b000, 0b0000, 0b1001, 0b100>; def : RWSysReg<"DBGBVR10_EL1", 0b10, 0b000, 0b0000, 0b1010, 0b100>; def : RWSysReg<"DBGBVR11_EL1", 0b10, 0b000, 0b0000, 0b1011, 0b100>; def : RWSysReg<"DBGBVR12_EL1", 0b10, 0b000, 0b0000, 0b1100, 0b100>; def : RWSysReg<"DBGBVR13_EL1", 0b10, 0b000, 0b0000, 0b1101, 0b100>; def : RWSysReg<"DBGBVR14_EL1", 0b10, 0b000, 0b0000, 0b1110, 0b100>; def : RWSysReg<"DBGBVR15_EL1", 0b10, 0b000, 0b0000, 0b1111, 0b100>; def : RWSysReg<"DBGBCR0_EL1", 0b10, 0b000, 0b0000, 0b0000, 0b101>; def : RWSysReg<"DBGBCR1_EL1", 0b10, 0b000, 0b0000, 0b0001, 0b101>; def : RWSysReg<"DBGBCR2_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b101>; def : RWSysReg<"DBGBCR3_EL1", 0b10, 0b000, 0b0000, 0b0011, 0b101>; def : RWSysReg<"DBGBCR4_EL1", 0b10, 0b000, 0b0000, 0b0100, 0b101>; def : RWSysReg<"DBGBCR5_EL1", 0b10, 0b000, 0b0000, 0b0101, 0b101>; def : RWSysReg<"DBGBCR6_EL1", 0b10, 0b000, 0b0000, 0b0110, 0b101>; def : RWSysReg<"DBGBCR7_EL1", 0b10, 0b000, 0b0000, 0b0111, 0b101>; def : RWSysReg<"DBGBCR8_EL1", 0b10, 0b000, 0b0000, 0b1000, 0b101>; def : RWSysReg<"DBGBCR9_EL1", 0b10, 0b000, 0b0000, 0b1001, 0b101>; def : RWSysReg<"DBGBCR10_EL1", 0b10, 0b000, 0b0000, 0b1010, 0b101>; def : RWSysReg<"DBGBCR11_EL1", 0b10, 0b000, 0b0000, 0b1011, 0b101>; def : RWSysReg<"DBGBCR12_EL1", 0b10, 0b000, 0b0000, 0b1100, 0b101>; def : RWSysReg<"DBGBCR13_EL1", 0b10, 0b000, 0b0000, 0b1101, 0b101>; def : RWSysReg<"DBGBCR14_EL1", 0b10, 0b000, 0b0000, 0b1110, 0b101>; def : RWSysReg<"DBGBCR15_EL1", 0b10, 0b000, 0b0000, 0b1111, 0b101>; def : RWSysReg<"DBGWVR0_EL1", 0b10, 0b000, 0b0000, 0b0000, 0b110>; def : RWSysReg<"DBGWVR1_EL1", 0b10, 0b000, 0b0000, 0b0001, 0b110>; def : RWSysReg<"DBGWVR2_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b110>; def : RWSysReg<"DBGWVR3_EL1", 0b10, 0b000, 0b0000, 0b0011, 0b110>; def : RWSysReg<"DBGWVR4_EL1", 0b10, 0b000, 0b0000, 0b0100, 0b110>; def : RWSysReg<"DBGWVR5_EL1", 0b10, 0b000, 0b0000, 0b0101, 0b110>; def : RWSysReg<"DBGWVR6_EL1", 0b10, 0b000, 0b0000, 0b0110, 0b110>; def : RWSysReg<"DBGWVR7_EL1", 0b10, 0b000, 0b0000, 0b0111, 0b110>; def : RWSysReg<"DBGWVR8_EL1", 0b10, 0b000, 0b0000, 0b1000, 0b110>; def : RWSysReg<"DBGWVR9_EL1", 0b10, 0b000, 0b0000, 0b1001, 0b110>; def : RWSysReg<"DBGWVR10_EL1", 0b10, 0b000, 0b0000, 0b1010, 0b110>; def : RWSysReg<"DBGWVR11_EL1", 0b10, 0b000, 0b0000, 0b1011, 0b110>; def : RWSysReg<"DBGWVR12_EL1", 0b10, 0b000, 0b0000, 0b1100, 0b110>; def : RWSysReg<"DBGWVR13_EL1", 0b10, 0b000, 0b0000, 0b1101, 0b110>; def : RWSysReg<"DBGWVR14_EL1", 0b10, 0b000, 0b0000, 0b1110, 0b110>; def : RWSysReg<"DBGWVR15_EL1", 0b10, 0b000, 0b0000, 0b1111, 0b110>; def : RWSysReg<"DBGWCR0_EL1", 0b10, 0b000, 0b0000, 0b0000, 0b111>; def : RWSysReg<"DBGWCR1_EL1", 0b10, 0b000, 0b0000, 0b0001, 0b111>; def : RWSysReg<"DBGWCR2_EL1", 0b10, 0b000, 0b0000, 0b0010, 0b111>; def : RWSysReg<"DBGWCR3_EL1", 0b10, 0b000, 0b0000, 0b0011, 0b111>; def : RWSysReg<"DBGWCR4_EL1", 0b10, 0b000, 0b0000, 0b0100, 0b111>; def : RWSysReg<"DBGWCR5_EL1", 0b10, 0b000, 0b0000, 0b0101, 0b111>; def : RWSysReg<"DBGWCR6_EL1", 0b10, 0b000, 0b0000, 0b0110, 0b111>; def : RWSysReg<"DBGWCR7_EL1", 0b10, 0b000, 0b0000, 0b0111, 0b111>; def : RWSysReg<"DBGWCR8_EL1", 0b10, 0b000, 0b0000, 0b1000, 0b111>; def : RWSysReg<"DBGWCR9_EL1", 0b10, 0b000, 0b0000, 0b1001, 0b111>; def : RWSysReg<"DBGWCR10_EL1", 0b10, 0b000, 0b0000, 0b1010, 0b111>; def : RWSysReg<"DBGWCR11_EL1", 0b10, 0b000, 0b0000, 0b1011, 0b111>; def : RWSysReg<"DBGWCR12_EL1", 0b10, 0b000, 0b0000, 0b1100, 0b111>; def : RWSysReg<"DBGWCR13_EL1", 0b10, 0b000, 0b0000, 0b1101, 0b111>; def : RWSysReg<"DBGWCR14_EL1", 0b10, 0b000, 0b0000, 0b1110, 0b111>; def : RWSysReg<"DBGWCR15_EL1", 0b10, 0b000, 0b0000, 0b1111, 0b111>; def : RWSysReg<"TEEHBR32_EL1", 0b10, 0b010, 0b0001, 0b0000, 0b000>; def : RWSysReg<"OSDLR_EL1", 0b10, 0b000, 0b0001, 0b0011, 0b100>; def : RWSysReg<"DBGPRCR_EL1", 0b10, 0b000, 0b0001, 0b0100, 0b100>; def : RWSysReg<"DBGCLAIMSET_EL1", 0b10, 0b000, 0b0111, 0b1000, 0b110>; def : RWSysReg<"DBGCLAIMCLR_EL1", 0b10, 0b000, 0b0111, 0b1001, 0b110>; def : RWSysReg<"CSSELR_EL1", 0b11, 0b010, 0b0000, 0b0000, 0b000>; def : RWSysReg<"VPIDR_EL2", 0b11, 0b100, 0b0000, 0b0000, 0b000>; def : RWSysReg<"VMPIDR_EL2", 0b11, 0b100, 0b0000, 0b0000, 0b101>; def : RWSysReg<"CPACR_EL1", 0b11, 0b000, 0b0001, 0b0000, 0b010>; def : RWSysReg<"SCTLR_EL1", 0b11, 0b000, 0b0001, 0b0000, 0b000>; def : RWSysReg<"SCTLR_EL2", 0b11, 0b100, 0b0001, 0b0000, 0b000>; def : RWSysReg<"SCTLR_EL3", 0b11, 0b110, 0b0001, 0b0000, 0b000>; def : RWSysReg<"ACTLR_EL1", 0b11, 0b000, 0b0001, 0b0000, 0b001>; def : RWSysReg<"ACTLR_EL2", 0b11, 0b100, 0b0001, 0b0000, 0b001>; def : RWSysReg<"ACTLR_EL3", 0b11, 0b110, 0b0001, 0b0000, 0b001>; def : RWSysReg<"HCR_EL2", 0b11, 0b100, 0b0001, 0b0001, 0b000>; def : RWSysReg<"SCR_EL3", 0b11, 0b110, 0b0001, 0b0001, 0b000>; def : RWSysReg<"MDCR_EL2", 0b11, 0b100, 0b0001, 0b0001, 0b001>; def : RWSysReg<"SDER32_EL3", 0b11, 0b110, 0b0001, 0b0001, 0b001>; def : RWSysReg<"CPTR_EL2", 0b11, 0b100, 0b0001, 0b0001, 0b010>; def : RWSysReg<"CPTR_EL3", 0b11, 0b110, 0b0001, 0b0001, 0b010>; def : RWSysReg<"HSTR_EL2", 0b11, 0b100, 0b0001, 0b0001, 0b011>; def : RWSysReg<"HACR_EL2", 0b11, 0b100, 0b0001, 0b0001, 0b111>; def : RWSysReg<"MDCR_EL3", 0b11, 0b110, 0b0001, 0b0011, 0b001>; def : RWSysReg<"TTBR0_EL1", 0b11, 0b000, 0b0010, 0b0000, 0b000>; def : RWSysReg<"TTBR0_EL2", 0b11, 0b100, 0b0010, 0b0000, 0b000>; def : RWSysReg<"TTBR0_EL3", 0b11, 0b110, 0b0010, 0b0000, 0b000>; def : RWSysReg<"TTBR1_EL1", 0b11, 0b000, 0b0010, 0b0000, 0b001>; def : RWSysReg<"TCR_EL1", 0b11, 0b000, 0b0010, 0b0000, 0b010>; def : RWSysReg<"TCR_EL2", 0b11, 0b100, 0b0010, 0b0000, 0b010>; def : RWSysReg<"TCR_EL3", 0b11, 0b110, 0b0010, 0b0000, 0b010>; def : RWSysReg<"VTTBR_EL2", 0b11, 0b100, 0b0010, 0b0001, 0b000>; def : RWSysReg<"VTCR_EL2", 0b11, 0b100, 0b0010, 0b0001, 0b010>; def : RWSysReg<"DACR32_EL2", 0b11, 0b100, 0b0011, 0b0000, 0b000>; def : RWSysReg<"SPSR_EL1", 0b11, 0b000, 0b0100, 0b0000, 0b000>; def : RWSysReg<"SPSR_EL2", 0b11, 0b100, 0b0100, 0b0000, 0b000>; def : RWSysReg<"SPSR_EL3", 0b11, 0b110, 0b0100, 0b0000, 0b000>; def : RWSysReg<"ELR_EL1", 0b11, 0b000, 0b0100, 0b0000, 0b001>; def : RWSysReg<"ELR_EL2", 0b11, 0b100, 0b0100, 0b0000, 0b001>; def : RWSysReg<"ELR_EL3", 0b11, 0b110, 0b0100, 0b0000, 0b001>; def : RWSysReg<"SP_EL0", 0b11, 0b000, 0b0100, 0b0001, 0b000>; def : RWSysReg<"SP_EL1", 0b11, 0b100, 0b0100, 0b0001, 0b000>; def : RWSysReg<"SP_EL2", 0b11, 0b110, 0b0100, 0b0001, 0b000>; def : RWSysReg<"SPSel", 0b11, 0b000, 0b0100, 0b0010, 0b000>; def : RWSysReg<"NZCV", 0b11, 0b011, 0b0100, 0b0010, 0b000>; def : RWSysReg<"DAIF", 0b11, 0b011, 0b0100, 0b0010, 0b001>; def : RWSysReg<"CurrentEL", 0b11, 0b000, 0b0100, 0b0010, 0b010>; def : RWSysReg<"SPSR_irq", 0b11, 0b100, 0b0100, 0b0011, 0b000>; def : RWSysReg<"SPSR_abt", 0b11, 0b100, 0b0100, 0b0011, 0b001>; def : RWSysReg<"SPSR_und", 0b11, 0b100, 0b0100, 0b0011, 0b010>; def : RWSysReg<"SPSR_fiq", 0b11, 0b100, 0b0100, 0b0011, 0b011>; def : RWSysReg<"FPCR", 0b11, 0b011, 0b0100, 0b0100, 0b000>; def : RWSysReg<"FPSR", 0b11, 0b011, 0b0100, 0b0100, 0b001>; def : RWSysReg<"DSPSR_EL0", 0b11, 0b011, 0b0100, 0b0101, 0b000>; def : RWSysReg<"DLR_EL0", 0b11, 0b011, 0b0100, 0b0101, 0b001>; def : RWSysReg<"IFSR32_EL2", 0b11, 0b100, 0b0101, 0b0000, 0b001>; def : RWSysReg<"AFSR0_EL1", 0b11, 0b000, 0b0101, 0b0001, 0b000>; def : RWSysReg<"AFSR0_EL2", 0b11, 0b100, 0b0101, 0b0001, 0b000>; def : RWSysReg<"AFSR0_EL3", 0b11, 0b110, 0b0101, 0b0001, 0b000>; def : RWSysReg<"AFSR1_EL1", 0b11, 0b000, 0b0101, 0b0001, 0b001>; def : RWSysReg<"AFSR1_EL2", 0b11, 0b100, 0b0101, 0b0001, 0b001>; def : RWSysReg<"AFSR1_EL3", 0b11, 0b110, 0b0101, 0b0001, 0b001>; def : RWSysReg<"ESR_EL1", 0b11, 0b000, 0b0101, 0b0010, 0b000>; def : RWSysReg<"ESR_EL2", 0b11, 0b100, 0b0101, 0b0010, 0b000>; def : RWSysReg<"ESR_EL3", 0b11, 0b110, 0b0101, 0b0010, 0b000>; def : RWSysReg<"FPEXC32_EL2", 0b11, 0b100, 0b0101, 0b0011, 0b000>; def : RWSysReg<"FAR_EL1", 0b11, 0b000, 0b0110, 0b0000, 0b000>; def : RWSysReg<"FAR_EL2", 0b11, 0b100, 0b0110, 0b0000, 0b000>; def : RWSysReg<"FAR_EL3", 0b11, 0b110, 0b0110, 0b0000, 0b000>; def : RWSysReg<"HPFAR_EL2", 0b11, 0b100, 0b0110, 0b0000, 0b100>; def : RWSysReg<"PAR_EL1", 0b11, 0b000, 0b0111, 0b0100, 0b000>; def : RWSysReg<"PMCR_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b000>; def : RWSysReg<"PMCNTENSET_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b001>; def : RWSysReg<"PMCNTENCLR_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b010>; def : RWSysReg<"PMOVSCLR_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b011>; def : RWSysReg<"PMSELR_EL0", 0b11, 0b011, 0b1001, 0b1100, 0b101>; def : RWSysReg<"PMCCNTR_EL0", 0b11, 0b011, 0b1001, 0b1101, 0b000>; def : RWSysReg<"PMXEVTYPER_EL0", 0b11, 0b011, 0b1001, 0b1101, 0b001>; def : RWSysReg<"PMXEVCNTR_EL0", 0b11, 0b011, 0b1001, 0b1101, 0b010>; def : RWSysReg<"PMUSERENR_EL0", 0b11, 0b011, 0b1001, 0b1110, 0b000>; def : RWSysReg<"PMINTENSET_EL1", 0b11, 0b000, 0b1001, 0b1110, 0b001>; def : RWSysReg<"PMINTENCLR_EL1", 0b11, 0b000, 0b1001, 0b1110, 0b010>; def : RWSysReg<"PMOVSSET_EL0", 0b11, 0b011, 0b1001, 0b1110, 0b011>; def : RWSysReg<"MAIR_EL1", 0b11, 0b000, 0b1010, 0b0010, 0b000>; def : RWSysReg<"MAIR_EL2", 0b11, 0b100, 0b1010, 0b0010, 0b000>; def : RWSysReg<"MAIR_EL3", 0b11, 0b110, 0b1010, 0b0010, 0b000>; def : RWSysReg<"AMAIR_EL1", 0b11, 0b000, 0b1010, 0b0011, 0b000>; def : RWSysReg<"AMAIR_EL2", 0b11, 0b100, 0b1010, 0b0011, 0b000>; def : RWSysReg<"AMAIR_EL3", 0b11, 0b110, 0b1010, 0b0011, 0b000>; def : RWSysReg<"VBAR_EL1", 0b11, 0b000, 0b1100, 0b0000, 0b000>; def : RWSysReg<"VBAR_EL2", 0b11, 0b100, 0b1100, 0b0000, 0b000>; def : RWSysReg<"VBAR_EL3", 0b11, 0b110, 0b1100, 0b0000, 0b000>; def : RWSysReg<"RMR_EL1", 0b11, 0b000, 0b1100, 0b0000, 0b010>; def : RWSysReg<"RMR_EL2", 0b11, 0b100, 0b1100, 0b0000, 0b010>; def : RWSysReg<"RMR_EL3", 0b11, 0b110, 0b1100, 0b0000, 0b010>; def : RWSysReg<"CONTEXTIDR_EL1", 0b11, 0b000, 0b1101, 0b0000, 0b001>; def : RWSysReg<"TPIDR_EL0", 0b11, 0b011, 0b1101, 0b0000, 0b010>; def : RWSysReg<"TPIDR_EL2", 0b11, 0b100, 0b1101, 0b0000, 0b010>; def : RWSysReg<"TPIDR_EL3", 0b11, 0b110, 0b1101, 0b0000, 0b010>; def : RWSysReg<"TPIDRRO_EL0", 0b11, 0b011, 0b1101, 0b0000, 0b011>; def : RWSysReg<"TPIDR_EL1", 0b11, 0b000, 0b1101, 0b0000, 0b100>; def : RWSysReg<"CNTFRQ_EL0", 0b11, 0b011, 0b1110, 0b0000, 0b000>; def : RWSysReg<"CNTVOFF_EL2", 0b11, 0b100, 0b1110, 0b0000, 0b011>; def : RWSysReg<"CNTKCTL_EL1", 0b11, 0b000, 0b1110, 0b0001, 0b000>; def : RWSysReg<"CNTHCTL_EL2", 0b11, 0b100, 0b1110, 0b0001, 0b000>; def : RWSysReg<"CNTP_TVAL_EL0", 0b11, 0b011, 0b1110, 0b0010, 0b000>; def : RWSysReg<"CNTHP_TVAL_EL2", 0b11, 0b100, 0b1110, 0b0010, 0b000>; def : RWSysReg<"CNTPS_TVAL_EL1", 0b11, 0b111, 0b1110, 0b0010, 0b000>; def : RWSysReg<"CNTP_CTL_EL0", 0b11, 0b011, 0b1110, 0b0010, 0b001>; def : RWSysReg<"CNTHP_CTL_EL2", 0b11, 0b100, 0b1110, 0b0010, 0b001>; def : RWSysReg<"CNTPS_CTL_EL1", 0b11, 0b111, 0b1110, 0b0010, 0b001>; def : RWSysReg<"CNTP_CVAL_EL0", 0b11, 0b011, 0b1110, 0b0010, 0b010>; def : RWSysReg<"CNTHP_CVAL_EL2", 0b11, 0b100, 0b1110, 0b0010, 0b010>; def : RWSysReg<"CNTPS_CVAL_EL1", 0b11, 0b111, 0b1110, 0b0010, 0b010>; def : RWSysReg<"CNTV_TVAL_EL0", 0b11, 0b011, 0b1110, 0b0011, 0b000>; def : RWSysReg<"CNTV_CTL_EL0", 0b11, 0b011, 0b1110, 0b0011, 0b001>; def : RWSysReg<"CNTV_CVAL_EL0", 0b11, 0b011, 0b1110, 0b0011, 0b010>; def : RWSysReg<"PMEVCNTR0_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b000>; def : RWSysReg<"PMEVCNTR1_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b001>; def : RWSysReg<"PMEVCNTR2_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b010>; def : RWSysReg<"PMEVCNTR3_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b011>; def : RWSysReg<"PMEVCNTR4_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b100>; def : RWSysReg<"PMEVCNTR5_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b101>; def : RWSysReg<"PMEVCNTR6_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b110>; def : RWSysReg<"PMEVCNTR7_EL0", 0b11, 0b011, 0b1110, 0b1000, 0b111>; def : RWSysReg<"PMEVCNTR8_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b000>; def : RWSysReg<"PMEVCNTR9_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b001>; def : RWSysReg<"PMEVCNTR10_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b010>; def : RWSysReg<"PMEVCNTR11_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b011>; def : RWSysReg<"PMEVCNTR12_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b100>; def : RWSysReg<"PMEVCNTR13_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b101>; def : RWSysReg<"PMEVCNTR14_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b110>; def : RWSysReg<"PMEVCNTR15_EL0", 0b11, 0b011, 0b1110, 0b1001, 0b111>; def : RWSysReg<"PMEVCNTR16_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b000>; def : RWSysReg<"PMEVCNTR17_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b001>; def : RWSysReg<"PMEVCNTR18_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b010>; def : RWSysReg<"PMEVCNTR19_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b011>; def : RWSysReg<"PMEVCNTR20_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b100>; def : RWSysReg<"PMEVCNTR21_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b101>; def : RWSysReg<"PMEVCNTR22_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b110>; def : RWSysReg<"PMEVCNTR23_EL0", 0b11, 0b011, 0b1110, 0b1010, 0b111>; def : RWSysReg<"PMEVCNTR24_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b000>; def : RWSysReg<"PMEVCNTR25_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b001>; def : RWSysReg<"PMEVCNTR26_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b010>; def : RWSysReg<"PMEVCNTR27_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b011>; def : RWSysReg<"PMEVCNTR28_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b100>; def : RWSysReg<"PMEVCNTR29_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b101>; def : RWSysReg<"PMEVCNTR30_EL0", 0b11, 0b011, 0b1110, 0b1011, 0b110>; def : RWSysReg<"PMCCFILTR_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b111>; def : RWSysReg<"PMEVTYPER0_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b000>; def : RWSysReg<"PMEVTYPER1_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b001>; def : RWSysReg<"PMEVTYPER2_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b010>; def : RWSysReg<"PMEVTYPER3_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b011>; def : RWSysReg<"PMEVTYPER4_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b100>; def : RWSysReg<"PMEVTYPER5_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b101>; def : RWSysReg<"PMEVTYPER6_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b110>; def : RWSysReg<"PMEVTYPER7_EL0", 0b11, 0b011, 0b1110, 0b1100, 0b111>; def : RWSysReg<"PMEVTYPER8_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b000>; def : RWSysReg<"PMEVTYPER9_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b001>; def : RWSysReg<"PMEVTYPER10_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b010>; def : RWSysReg<"PMEVTYPER11_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b011>; def : RWSysReg<"PMEVTYPER12_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b100>; def : RWSysReg<"PMEVTYPER13_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b101>; def : RWSysReg<"PMEVTYPER14_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b110>; def : RWSysReg<"PMEVTYPER15_EL0", 0b11, 0b011, 0b1110, 0b1101, 0b111>; def : RWSysReg<"PMEVTYPER16_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b000>; def : RWSysReg<"PMEVTYPER17_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b001>; def : RWSysReg<"PMEVTYPER18_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b010>; def : RWSysReg<"PMEVTYPER19_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b011>; def : RWSysReg<"PMEVTYPER20_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b100>; def : RWSysReg<"PMEVTYPER21_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b101>; def : RWSysReg<"PMEVTYPER22_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b110>; def : RWSysReg<"PMEVTYPER23_EL0", 0b11, 0b011, 0b1110, 0b1110, 0b111>; def : RWSysReg<"PMEVTYPER24_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b000>; def : RWSysReg<"PMEVTYPER25_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b001>; def : RWSysReg<"PMEVTYPER26_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b010>; def : RWSysReg<"PMEVTYPER27_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b011>; def : RWSysReg<"PMEVTYPER28_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b100>; def : RWSysReg<"PMEVTYPER29_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b101>; def : RWSysReg<"PMEVTYPER30_EL0", 0b11, 0b011, 0b1110, 0b1111, 0b110>; // Trace registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"TRCPRGCTLR", 0b10, 0b001, 0b0000, 0b0001, 0b000>; def : RWSysReg<"TRCPROCSELR", 0b10, 0b001, 0b0000, 0b0010, 0b000>; def : RWSysReg<"TRCCONFIGR", 0b10, 0b001, 0b0000, 0b0100, 0b000>; def : RWSysReg<"TRCAUXCTLR", 0b10, 0b001, 0b0000, 0b0110, 0b000>; def : RWSysReg<"TRCEVENTCTL0R", 0b10, 0b001, 0b0000, 0b1000, 0b000>; def : RWSysReg<"TRCEVENTCTL1R", 0b10, 0b001, 0b0000, 0b1001, 0b000>; def : RWSysReg<"TRCSTALLCTLR", 0b10, 0b001, 0b0000, 0b1011, 0b000>; def : RWSysReg<"TRCTSCTLR", 0b10, 0b001, 0b0000, 0b1100, 0b000>; def : RWSysReg<"TRCSYNCPR", 0b10, 0b001, 0b0000, 0b1101, 0b000>; def : RWSysReg<"TRCCCCTLR", 0b10, 0b001, 0b0000, 0b1110, 0b000>; def : RWSysReg<"TRCBBCTLR", 0b10, 0b001, 0b0000, 0b1111, 0b000>; def : RWSysReg<"TRCTRACEIDR", 0b10, 0b001, 0b0000, 0b0000, 0b001>; def : RWSysReg<"TRCQCTLR", 0b10, 0b001, 0b0000, 0b0001, 0b001>; def : RWSysReg<"TRCVICTLR", 0b10, 0b001, 0b0000, 0b0000, 0b010>; def : RWSysReg<"TRCVIIECTLR", 0b10, 0b001, 0b0000, 0b0001, 0b010>; def : RWSysReg<"TRCVISSCTLR", 0b10, 0b001, 0b0000, 0b0010, 0b010>; def : RWSysReg<"TRCVIPCSSCTLR", 0b10, 0b001, 0b0000, 0b0011, 0b010>; def : RWSysReg<"TRCVDCTLR", 0b10, 0b001, 0b0000, 0b1000, 0b010>; def : RWSysReg<"TRCVDSACCTLR", 0b10, 0b001, 0b0000, 0b1001, 0b010>; def : RWSysReg<"TRCVDARCCTLR", 0b10, 0b001, 0b0000, 0b1010, 0b010>; def : RWSysReg<"TRCSEQEVR0", 0b10, 0b001, 0b0000, 0b0000, 0b100>; def : RWSysReg<"TRCSEQEVR1", 0b10, 0b001, 0b0000, 0b0001, 0b100>; def : RWSysReg<"TRCSEQEVR2", 0b10, 0b001, 0b0000, 0b0010, 0b100>; def : RWSysReg<"TRCSEQRSTEVR", 0b10, 0b001, 0b0000, 0b0110, 0b100>; def : RWSysReg<"TRCSEQSTR", 0b10, 0b001, 0b0000, 0b0111, 0b100>; def : RWSysReg<"TRCEXTINSELR", 0b10, 0b001, 0b0000, 0b1000, 0b100>; def : RWSysReg<"TRCCNTRLDVR0", 0b10, 0b001, 0b0000, 0b0000, 0b101>; def : RWSysReg<"TRCCNTRLDVR1", 0b10, 0b001, 0b0000, 0b0001, 0b101>; def : RWSysReg<"TRCCNTRLDVR2", 0b10, 0b001, 0b0000, 0b0010, 0b101>; def : RWSysReg<"TRCCNTRLDVR3", 0b10, 0b001, 0b0000, 0b0011, 0b101>; def : RWSysReg<"TRCCNTCTLR0", 0b10, 0b001, 0b0000, 0b0100, 0b101>; def : RWSysReg<"TRCCNTCTLR1", 0b10, 0b001, 0b0000, 0b0101, 0b101>; def : RWSysReg<"TRCCNTCTLR2", 0b10, 0b001, 0b0000, 0b0110, 0b101>; def : RWSysReg<"TRCCNTCTLR3", 0b10, 0b001, 0b0000, 0b0111, 0b101>; def : RWSysReg<"TRCCNTVR0", 0b10, 0b001, 0b0000, 0b1000, 0b101>; def : RWSysReg<"TRCCNTVR1", 0b10, 0b001, 0b0000, 0b1001, 0b101>; def : RWSysReg<"TRCCNTVR2", 0b10, 0b001, 0b0000, 0b1010, 0b101>; def : RWSysReg<"TRCCNTVR3", 0b10, 0b001, 0b0000, 0b1011, 0b101>; def : RWSysReg<"TRCIMSPEC0", 0b10, 0b001, 0b0000, 0b0000, 0b111>; def : RWSysReg<"TRCIMSPEC1", 0b10, 0b001, 0b0000, 0b0001, 0b111>; def : RWSysReg<"TRCIMSPEC2", 0b10, 0b001, 0b0000, 0b0010, 0b111>; def : RWSysReg<"TRCIMSPEC3", 0b10, 0b001, 0b0000, 0b0011, 0b111>; def : RWSysReg<"TRCIMSPEC4", 0b10, 0b001, 0b0000, 0b0100, 0b111>; def : RWSysReg<"TRCIMSPEC5", 0b10, 0b001, 0b0000, 0b0101, 0b111>; def : RWSysReg<"TRCIMSPEC6", 0b10, 0b001, 0b0000, 0b0110, 0b111>; def : RWSysReg<"TRCIMSPEC7", 0b10, 0b001, 0b0000, 0b0111, 0b111>; def : RWSysReg<"TRCRSCTLR2", 0b10, 0b001, 0b0001, 0b0010, 0b000>; def : RWSysReg<"TRCRSCTLR3", 0b10, 0b001, 0b0001, 0b0011, 0b000>; def : RWSysReg<"TRCRSCTLR4", 0b10, 0b001, 0b0001, 0b0100, 0b000>; def : RWSysReg<"TRCRSCTLR5", 0b10, 0b001, 0b0001, 0b0101, 0b000>; def : RWSysReg<"TRCRSCTLR6", 0b10, 0b001, 0b0001, 0b0110, 0b000>; def : RWSysReg<"TRCRSCTLR7", 0b10, 0b001, 0b0001, 0b0111, 0b000>; def : RWSysReg<"TRCRSCTLR8", 0b10, 0b001, 0b0001, 0b1000, 0b000>; def : RWSysReg<"TRCRSCTLR9", 0b10, 0b001, 0b0001, 0b1001, 0b000>; def : RWSysReg<"TRCRSCTLR10", 0b10, 0b001, 0b0001, 0b1010, 0b000>; def : RWSysReg<"TRCRSCTLR11", 0b10, 0b001, 0b0001, 0b1011, 0b000>; def : RWSysReg<"TRCRSCTLR12", 0b10, 0b001, 0b0001, 0b1100, 0b000>; def : RWSysReg<"TRCRSCTLR13", 0b10, 0b001, 0b0001, 0b1101, 0b000>; def : RWSysReg<"TRCRSCTLR14", 0b10, 0b001, 0b0001, 0b1110, 0b000>; def : RWSysReg<"TRCRSCTLR15", 0b10, 0b001, 0b0001, 0b1111, 0b000>; def : RWSysReg<"TRCRSCTLR16", 0b10, 0b001, 0b0001, 0b0000, 0b001>; def : RWSysReg<"TRCRSCTLR17", 0b10, 0b001, 0b0001, 0b0001, 0b001>; def : RWSysReg<"TRCRSCTLR18", 0b10, 0b001, 0b0001, 0b0010, 0b001>; def : RWSysReg<"TRCRSCTLR19", 0b10, 0b001, 0b0001, 0b0011, 0b001>; def : RWSysReg<"TRCRSCTLR20", 0b10, 0b001, 0b0001, 0b0100, 0b001>; def : RWSysReg<"TRCRSCTLR21", 0b10, 0b001, 0b0001, 0b0101, 0b001>; def : RWSysReg<"TRCRSCTLR22", 0b10, 0b001, 0b0001, 0b0110, 0b001>; def : RWSysReg<"TRCRSCTLR23", 0b10, 0b001, 0b0001, 0b0111, 0b001>; def : RWSysReg<"TRCRSCTLR24", 0b10, 0b001, 0b0001, 0b1000, 0b001>; def : RWSysReg<"TRCRSCTLR25", 0b10, 0b001, 0b0001, 0b1001, 0b001>; def : RWSysReg<"TRCRSCTLR26", 0b10, 0b001, 0b0001, 0b1010, 0b001>; def : RWSysReg<"TRCRSCTLR27", 0b10, 0b001, 0b0001, 0b1011, 0b001>; def : RWSysReg<"TRCRSCTLR28", 0b10, 0b001, 0b0001, 0b1100, 0b001>; def : RWSysReg<"TRCRSCTLR29", 0b10, 0b001, 0b0001, 0b1101, 0b001>; def : RWSysReg<"TRCRSCTLR30", 0b10, 0b001, 0b0001, 0b1110, 0b001>; def : RWSysReg<"TRCRSCTLR31", 0b10, 0b001, 0b0001, 0b1111, 0b001>; def : RWSysReg<"TRCSSCCR0", 0b10, 0b001, 0b0001, 0b0000, 0b010>; def : RWSysReg<"TRCSSCCR1", 0b10, 0b001, 0b0001, 0b0001, 0b010>; def : RWSysReg<"TRCSSCCR2", 0b10, 0b001, 0b0001, 0b0010, 0b010>; def : RWSysReg<"TRCSSCCR3", 0b10, 0b001, 0b0001, 0b0011, 0b010>; def : RWSysReg<"TRCSSCCR4", 0b10, 0b001, 0b0001, 0b0100, 0b010>; def : RWSysReg<"TRCSSCCR5", 0b10, 0b001, 0b0001, 0b0101, 0b010>; def : RWSysReg<"TRCSSCCR6", 0b10, 0b001, 0b0001, 0b0110, 0b010>; def : RWSysReg<"TRCSSCCR7", 0b10, 0b001, 0b0001, 0b0111, 0b010>; def : RWSysReg<"TRCSSCSR0", 0b10, 0b001, 0b0001, 0b1000, 0b010>; def : RWSysReg<"TRCSSCSR1", 0b10, 0b001, 0b0001, 0b1001, 0b010>; def : RWSysReg<"TRCSSCSR2", 0b10, 0b001, 0b0001, 0b1010, 0b010>; def : RWSysReg<"TRCSSCSR3", 0b10, 0b001, 0b0001, 0b1011, 0b010>; def : RWSysReg<"TRCSSCSR4", 0b10, 0b001, 0b0001, 0b1100, 0b010>; def : RWSysReg<"TRCSSCSR5", 0b10, 0b001, 0b0001, 0b1101, 0b010>; def : RWSysReg<"TRCSSCSR6", 0b10, 0b001, 0b0001, 0b1110, 0b010>; def : RWSysReg<"TRCSSCSR7", 0b10, 0b001, 0b0001, 0b1111, 0b010>; def : RWSysReg<"TRCSSPCICR0", 0b10, 0b001, 0b0001, 0b0000, 0b011>; def : RWSysReg<"TRCSSPCICR1", 0b10, 0b001, 0b0001, 0b0001, 0b011>; def : RWSysReg<"TRCSSPCICR2", 0b10, 0b001, 0b0001, 0b0010, 0b011>; def : RWSysReg<"TRCSSPCICR3", 0b10, 0b001, 0b0001, 0b0011, 0b011>; def : RWSysReg<"TRCSSPCICR4", 0b10, 0b001, 0b0001, 0b0100, 0b011>; def : RWSysReg<"TRCSSPCICR5", 0b10, 0b001, 0b0001, 0b0101, 0b011>; def : RWSysReg<"TRCSSPCICR6", 0b10, 0b001, 0b0001, 0b0110, 0b011>; def : RWSysReg<"TRCSSPCICR7", 0b10, 0b001, 0b0001, 0b0111, 0b011>; def : RWSysReg<"TRCPDCR", 0b10, 0b001, 0b0001, 0b0100, 0b100>; def : RWSysReg<"TRCACVR0", 0b10, 0b001, 0b0010, 0b0000, 0b000>; def : RWSysReg<"TRCACVR1", 0b10, 0b001, 0b0010, 0b0010, 0b000>; def : RWSysReg<"TRCACVR2", 0b10, 0b001, 0b0010, 0b0100, 0b000>; def : RWSysReg<"TRCACVR3", 0b10, 0b001, 0b0010, 0b0110, 0b000>; def : RWSysReg<"TRCACVR4", 0b10, 0b001, 0b0010, 0b1000, 0b000>; def : RWSysReg<"TRCACVR5", 0b10, 0b001, 0b0010, 0b1010, 0b000>; def : RWSysReg<"TRCACVR6", 0b10, 0b001, 0b0010, 0b1100, 0b000>; def : RWSysReg<"TRCACVR7", 0b10, 0b001, 0b0010, 0b1110, 0b000>; def : RWSysReg<"TRCACVR8", 0b10, 0b001, 0b0010, 0b0000, 0b001>; def : RWSysReg<"TRCACVR9", 0b10, 0b001, 0b0010, 0b0010, 0b001>; def : RWSysReg<"TRCACVR10", 0b10, 0b001, 0b0010, 0b0100, 0b001>; def : RWSysReg<"TRCACVR11", 0b10, 0b001, 0b0010, 0b0110, 0b001>; def : RWSysReg<"TRCACVR12", 0b10, 0b001, 0b0010, 0b1000, 0b001>; def : RWSysReg<"TRCACVR13", 0b10, 0b001, 0b0010, 0b1010, 0b001>; def : RWSysReg<"TRCACVR14", 0b10, 0b001, 0b0010, 0b1100, 0b001>; def : RWSysReg<"TRCACVR15", 0b10, 0b001, 0b0010, 0b1110, 0b001>; def : RWSysReg<"TRCACATR0", 0b10, 0b001, 0b0010, 0b0000, 0b010>; def : RWSysReg<"TRCACATR1", 0b10, 0b001, 0b0010, 0b0010, 0b010>; def : RWSysReg<"TRCACATR2", 0b10, 0b001, 0b0010, 0b0100, 0b010>; def : RWSysReg<"TRCACATR3", 0b10, 0b001, 0b0010, 0b0110, 0b010>; def : RWSysReg<"TRCACATR4", 0b10, 0b001, 0b0010, 0b1000, 0b010>; def : RWSysReg<"TRCACATR5", 0b10, 0b001, 0b0010, 0b1010, 0b010>; def : RWSysReg<"TRCACATR6", 0b10, 0b001, 0b0010, 0b1100, 0b010>; def : RWSysReg<"TRCACATR7", 0b10, 0b001, 0b0010, 0b1110, 0b010>; def : RWSysReg<"TRCACATR8", 0b10, 0b001, 0b0010, 0b0000, 0b011>; def : RWSysReg<"TRCACATR9", 0b10, 0b001, 0b0010, 0b0010, 0b011>; def : RWSysReg<"TRCACATR10", 0b10, 0b001, 0b0010, 0b0100, 0b011>; def : RWSysReg<"TRCACATR11", 0b10, 0b001, 0b0010, 0b0110, 0b011>; def : RWSysReg<"TRCACATR12", 0b10, 0b001, 0b0010, 0b1000, 0b011>; def : RWSysReg<"TRCACATR13", 0b10, 0b001, 0b0010, 0b1010, 0b011>; def : RWSysReg<"TRCACATR14", 0b10, 0b001, 0b0010, 0b1100, 0b011>; def : RWSysReg<"TRCACATR15", 0b10, 0b001, 0b0010, 0b1110, 0b011>; def : RWSysReg<"TRCDVCVR0", 0b10, 0b001, 0b0010, 0b0000, 0b100>; def : RWSysReg<"TRCDVCVR1", 0b10, 0b001, 0b0010, 0b0100, 0b100>; def : RWSysReg<"TRCDVCVR2", 0b10, 0b001, 0b0010, 0b1000, 0b100>; def : RWSysReg<"TRCDVCVR3", 0b10, 0b001, 0b0010, 0b1100, 0b100>; def : RWSysReg<"TRCDVCVR4", 0b10, 0b001, 0b0010, 0b0000, 0b101>; def : RWSysReg<"TRCDVCVR5", 0b10, 0b001, 0b0010, 0b0100, 0b101>; def : RWSysReg<"TRCDVCVR6", 0b10, 0b001, 0b0010, 0b1000, 0b101>; def : RWSysReg<"TRCDVCVR7", 0b10, 0b001, 0b0010, 0b1100, 0b101>; def : RWSysReg<"TRCDVCMR0", 0b10, 0b001, 0b0010, 0b0000, 0b110>; def : RWSysReg<"TRCDVCMR1", 0b10, 0b001, 0b0010, 0b0100, 0b110>; def : RWSysReg<"TRCDVCMR2", 0b10, 0b001, 0b0010, 0b1000, 0b110>; def : RWSysReg<"TRCDVCMR3", 0b10, 0b001, 0b0010, 0b1100, 0b110>; def : RWSysReg<"TRCDVCMR4", 0b10, 0b001, 0b0010, 0b0000, 0b111>; def : RWSysReg<"TRCDVCMR5", 0b10, 0b001, 0b0010, 0b0100, 0b111>; def : RWSysReg<"TRCDVCMR6", 0b10, 0b001, 0b0010, 0b1000, 0b111>; def : RWSysReg<"TRCDVCMR7", 0b10, 0b001, 0b0010, 0b1100, 0b111>; def : RWSysReg<"TRCCIDCVR0", 0b10, 0b001, 0b0011, 0b0000, 0b000>; def : RWSysReg<"TRCCIDCVR1", 0b10, 0b001, 0b0011, 0b0010, 0b000>; def : RWSysReg<"TRCCIDCVR2", 0b10, 0b001, 0b0011, 0b0100, 0b000>; def : RWSysReg<"TRCCIDCVR3", 0b10, 0b001, 0b0011, 0b0110, 0b000>; def : RWSysReg<"TRCCIDCVR4", 0b10, 0b001, 0b0011, 0b1000, 0b000>; def : RWSysReg<"TRCCIDCVR5", 0b10, 0b001, 0b0011, 0b1010, 0b000>; def : RWSysReg<"TRCCIDCVR6", 0b10, 0b001, 0b0011, 0b1100, 0b000>; def : RWSysReg<"TRCCIDCVR7", 0b10, 0b001, 0b0011, 0b1110, 0b000>; def : RWSysReg<"TRCVMIDCVR0", 0b10, 0b001, 0b0011, 0b0000, 0b001>; def : RWSysReg<"TRCVMIDCVR1", 0b10, 0b001, 0b0011, 0b0010, 0b001>; def : RWSysReg<"TRCVMIDCVR2", 0b10, 0b001, 0b0011, 0b0100, 0b001>; def : RWSysReg<"TRCVMIDCVR3", 0b10, 0b001, 0b0011, 0b0110, 0b001>; def : RWSysReg<"TRCVMIDCVR4", 0b10, 0b001, 0b0011, 0b1000, 0b001>; def : RWSysReg<"TRCVMIDCVR5", 0b10, 0b001, 0b0011, 0b1010, 0b001>; def : RWSysReg<"TRCVMIDCVR6", 0b10, 0b001, 0b0011, 0b1100, 0b001>; def : RWSysReg<"TRCVMIDCVR7", 0b10, 0b001, 0b0011, 0b1110, 0b001>; def : RWSysReg<"TRCCIDCCTLR0", 0b10, 0b001, 0b0011, 0b0000, 0b010>; def : RWSysReg<"TRCCIDCCTLR1", 0b10, 0b001, 0b0011, 0b0001, 0b010>; def : RWSysReg<"TRCVMIDCCTLR0", 0b10, 0b001, 0b0011, 0b0010, 0b010>; def : RWSysReg<"TRCVMIDCCTLR1", 0b10, 0b001, 0b0011, 0b0011, 0b010>; def : RWSysReg<"TRCITCTRL", 0b10, 0b001, 0b0111, 0b0000, 0b100>; def : RWSysReg<"TRCCLAIMSET", 0b10, 0b001, 0b0111, 0b1000, 0b110>; def : RWSysReg<"TRCCLAIMCLR", 0b10, 0b001, 0b0111, 0b1001, 0b110>; // GICv3 registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"ICC_BPR1_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b011>; def : RWSysReg<"ICC_BPR0_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b011>; def : RWSysReg<"ICC_PMR_EL1", 0b11, 0b000, 0b0100, 0b0110, 0b000>; def : RWSysReg<"ICC_CTLR_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b100>; def : RWSysReg<"ICC_CTLR_EL3", 0b11, 0b110, 0b1100, 0b1100, 0b100>; def : RWSysReg<"ICC_SRE_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b101>; def : RWSysReg<"ICC_SRE_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b101>; def : RWSysReg<"ICC_SRE_EL3", 0b11, 0b110, 0b1100, 0b1100, 0b101>; def : RWSysReg<"ICC_IGRPEN0_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b110>; def : RWSysReg<"ICC_IGRPEN1_EL1", 0b11, 0b000, 0b1100, 0b1100, 0b111>; def : RWSysReg<"ICC_IGRPEN1_EL3", 0b11, 0b110, 0b1100, 0b1100, 0b111>; def : RWSysReg<"ICC_SEIEN_EL1", 0b11, 0b000, 0b1100, 0b1101, 0b000>; def : RWSysReg<"ICC_AP0R0_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b100>; def : RWSysReg<"ICC_AP0R1_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b101>; def : RWSysReg<"ICC_AP0R2_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b110>; def : RWSysReg<"ICC_AP0R3_EL1", 0b11, 0b000, 0b1100, 0b1000, 0b111>; def : RWSysReg<"ICC_AP1R0_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b000>; def : RWSysReg<"ICC_AP1R1_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b001>; def : RWSysReg<"ICC_AP1R2_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b010>; def : RWSysReg<"ICC_AP1R3_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b011>; def : RWSysReg<"ICH_AP0R0_EL2", 0b11, 0b100, 0b1100, 0b1000, 0b000>; def : RWSysReg<"ICH_AP0R1_EL2", 0b11, 0b100, 0b1100, 0b1000, 0b001>; def : RWSysReg<"ICH_AP0R2_EL2", 0b11, 0b100, 0b1100, 0b1000, 0b010>; def : RWSysReg<"ICH_AP0R3_EL2", 0b11, 0b100, 0b1100, 0b1000, 0b011>; def : RWSysReg<"ICH_AP1R0_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b000>; def : RWSysReg<"ICH_AP1R1_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b001>; def : RWSysReg<"ICH_AP1R2_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b010>; def : RWSysReg<"ICH_AP1R3_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b011>; def : RWSysReg<"ICH_HCR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b000>; def : RWSysReg<"ICH_MISR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b010>; def : RWSysReg<"ICH_VMCR_EL2", 0b11, 0b100, 0b1100, 0b1011, 0b111>; def : RWSysReg<"ICH_VSEIR_EL2", 0b11, 0b100, 0b1100, 0b1001, 0b100>; def : RWSysReg<"ICH_LR0_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b000>; def : RWSysReg<"ICH_LR1_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b001>; def : RWSysReg<"ICH_LR2_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b010>; def : RWSysReg<"ICH_LR3_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b011>; def : RWSysReg<"ICH_LR4_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b100>; def : RWSysReg<"ICH_LR5_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b101>; def : RWSysReg<"ICH_LR6_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b110>; def : RWSysReg<"ICH_LR7_EL2", 0b11, 0b100, 0b1100, 0b1100, 0b111>; def : RWSysReg<"ICH_LR8_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b000>; def : RWSysReg<"ICH_LR9_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b001>; def : RWSysReg<"ICH_LR10_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b010>; def : RWSysReg<"ICH_LR11_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b011>; def : RWSysReg<"ICH_LR12_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b100>; def : RWSysReg<"ICH_LR13_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b101>; def : RWSysReg<"ICH_LR14_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b110>; def : RWSysReg<"ICH_LR15_EL2", 0b11, 0b100, 0b1100, 0b1101, 0b111>; // v8.1a "Privileged Access Never" extension-specific system registers let Requires = [{ {AArch64::HasV8_1aOps} }] in def : RWSysReg<"PAN", 0b11, 0b000, 0b0100, 0b0010, 0b011>; // v8.1a "Limited Ordering Regions" extension-specific system registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::HasV8_1aOps} }] in { def : RWSysReg<"LORSA_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b000>; def : RWSysReg<"LOREA_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b001>; def : RWSysReg<"LORN_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b010>; def : RWSysReg<"LORC_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b011>; } // v8.1a "Virtualization hos extensions" system registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::HasV8_1aOps} }] in { def : RWSysReg<"TTBR1_EL2", 0b11, 0b100, 0b0010, 0b0000, 0b001>; def : RWSysReg<"CONTEXTIDR_EL2", 0b11, 0b100, 0b1101, 0b0000, 0b001>; def : RWSysReg<"CNTHV_TVAL_EL2", 0b11, 0b100, 0b1110, 0b0011, 0b000>; def : RWSysReg<"CNTHV_CVAL_EL2", 0b11, 0b100, 0b1110, 0b0011, 0b010>; def : RWSysReg<"CNTHV_CTL_EL2", 0b11, 0b100, 0b1110, 0b0011, 0b001>; def : RWSysReg<"SCTLR_EL12", 0b11, 0b101, 0b0001, 0b0000, 0b000>; def : RWSysReg<"CPACR_EL12", 0b11, 0b101, 0b0001, 0b0000, 0b010>; def : RWSysReg<"TTBR0_EL12", 0b11, 0b101, 0b0010, 0b0000, 0b000>; def : RWSysReg<"TTBR1_EL12", 0b11, 0b101, 0b0010, 0b0000, 0b001>; def : RWSysReg<"TCR_EL12", 0b11, 0b101, 0b0010, 0b0000, 0b010>; def : RWSysReg<"AFSR0_EL12", 0b11, 0b101, 0b0101, 0b0001, 0b000>; def : RWSysReg<"AFSR1_EL12", 0b11, 0b101, 0b0101, 0b0001, 0b001>; def : RWSysReg<"ESR_EL12", 0b11, 0b101, 0b0101, 0b0010, 0b000>; def : RWSysReg<"FAR_EL12", 0b11, 0b101, 0b0110, 0b0000, 0b000>; def : RWSysReg<"MAIR_EL12", 0b11, 0b101, 0b1010, 0b0010, 0b000>; def : RWSysReg<"AMAIR_EL12", 0b11, 0b101, 0b1010, 0b0011, 0b000>; def : RWSysReg<"VBAR_EL12", 0b11, 0b101, 0b1100, 0b0000, 0b000>; def : RWSysReg<"CONTEXTIDR_EL12", 0b11, 0b101, 0b1101, 0b0000, 0b001>; def : RWSysReg<"CNTKCTL_EL12", 0b11, 0b101, 0b1110, 0b0001, 0b000>; def : RWSysReg<"CNTP_TVAL_EL02", 0b11, 0b101, 0b1110, 0b0010, 0b000>; def : RWSysReg<"CNTP_CTL_EL02", 0b11, 0b101, 0b1110, 0b0010, 0b001>; def : RWSysReg<"CNTP_CVAL_EL02", 0b11, 0b101, 0b1110, 0b0010, 0b010>; def : RWSysReg<"CNTV_TVAL_EL02", 0b11, 0b101, 0b1110, 0b0011, 0b000>; def : RWSysReg<"CNTV_CTL_EL02", 0b11, 0b101, 0b1110, 0b0011, 0b001>; def : RWSysReg<"CNTV_CVAL_EL02", 0b11, 0b101, 0b1110, 0b0011, 0b010>; def : RWSysReg<"SPSR_EL12", 0b11, 0b101, 0b0100, 0b0000, 0b000>; def : RWSysReg<"ELR_EL12", 0b11, 0b101, 0b0100, 0b0000, 0b001>; } // v8.2a registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::HasV8_2aOps} }] in def : RWSysReg<"UAO", 0b11, 0b000, 0b0100, 0b0010, 0b100>; // v8.2a "Statistical Profiling extension" registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::FeatureSPE} }] in { def : RWSysReg<"PMBLIMITR_EL1", 0b11, 0b000, 0b1001, 0b1010, 0b000>; def : RWSysReg<"PMBPTR_EL1", 0b11, 0b000, 0b1001, 0b1010, 0b001>; def : RWSysReg<"PMBSR_EL1", 0b11, 0b000, 0b1001, 0b1010, 0b011>; def : RWSysReg<"PMBIDR_EL1", 0b11, 0b000, 0b1001, 0b1010, 0b111>; def : RWSysReg<"PMSCR_EL2", 0b11, 0b100, 0b1001, 0b1001, 0b000>; def : RWSysReg<"PMSCR_EL12", 0b11, 0b101, 0b1001, 0b1001, 0b000>; def : RWSysReg<"PMSCR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b000>; def : RWSysReg<"PMSICR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b010>; def : RWSysReg<"PMSIRR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b011>; def : RWSysReg<"PMSFCR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b100>; def : RWSysReg<"PMSEVFR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b101>; def : RWSysReg<"PMSLATFR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b110>; def : RWSysReg<"PMSIDR_EL1", 0b11, 0b000, 0b1001, 0b1001, 0b111>; } // v8.2a "RAS extension" registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::FeatureRAS} }] in { def : RWSysReg<"ERRSELR_EL1", 0b11, 0b000, 0b0101, 0b0011, 0b001>; def : RWSysReg<"ERXCTLR_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b001>; def : RWSysReg<"ERXSTATUS_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b010>; def : RWSysReg<"ERXADDR_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b011>; def : RWSysReg<"ERXMISC0_EL1", 0b11, 0b000, 0b0101, 0b0101, 0b000>; def : RWSysReg<"ERXMISC1_EL1", 0b11, 0b000, 0b0101, 0b0101, 0b001>; def : RWSysReg<"DISR_EL1", 0b11, 0b000, 0b1100, 0b0001, 0b001>; def : RWSysReg<"VDISR_EL2", 0b11, 0b100, 0b1100, 0b0001, 0b001>; def : RWSysReg<"VSESR_EL2", 0b11, 0b100, 0b0101, 0b0010, 0b011>; } // v8.3a "Pointer authentication extension" registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::HasV8_3aOps} }] in { def : RWSysReg<"APIAKeyLo_EL1", 0b11, 0b000, 0b0010, 0b0001, 0b000>; def : RWSysReg<"APIAKeyHi_EL1", 0b11, 0b000, 0b0010, 0b0001, 0b001>; def : RWSysReg<"APIBKeyLo_EL1", 0b11, 0b000, 0b0010, 0b0001, 0b010>; def : RWSysReg<"APIBKeyHi_EL1", 0b11, 0b000, 0b0010, 0b0001, 0b011>; def : RWSysReg<"APDAKeyLo_EL1", 0b11, 0b000, 0b0010, 0b0010, 0b000>; def : RWSysReg<"APDAKeyHi_EL1", 0b11, 0b000, 0b0010, 0b0010, 0b001>; def : RWSysReg<"APDBKeyLo_EL1", 0b11, 0b000, 0b0010, 0b0010, 0b010>; def : RWSysReg<"APDBKeyHi_EL1", 0b11, 0b000, 0b0010, 0b0010, 0b011>; def : RWSysReg<"APGAKeyLo_EL1", 0b11, 0b000, 0b0010, 0b0011, 0b000>; def : RWSysReg<"APGAKeyHi_EL1", 0b11, 0b000, 0b0010, 0b0011, 0b001>; } let Requires = [{ {AArch64::HasV8_4aOps} }] in { // v8.4a "Virtualization secure second stage translation" registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"VSTCR_EL2" , 0b11, 0b100, 0b0010, 0b0110, 0b010>; def : RWSysReg<"VSTTBR_EL2", 0b11, 0b100, 0b0010, 0b0110, 0b000>; // v8.4a "Virtualization timer" registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"CNTHVS_TVAL_EL2", 0b11, 0b100, 0b1110, 0b0100, 0b000>; def : RWSysReg<"CNTHVS_CVAL_EL2", 0b11, 0b100, 0b1110, 0b0100, 0b010>; def : RWSysReg<"CNTHVS_CTL_EL2", 0b11, 0b100, 0b1110, 0b0100, 0b001>; def : RWSysReg<"CNTHPS_TVAL_EL2", 0b11, 0b100, 0b1110, 0b0101, 0b000>; def : RWSysReg<"CNTHPS_CVAL_EL2", 0b11, 0b100, 0b1110, 0b0101, 0b010>; def : RWSysReg<"CNTHPS_CTL_EL2", 0b11, 0b100, 0b1110, 0b0101, 0b001>; // v8.4a "Virtualization debug state" registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"SDER32_EL2", 0b11, 0b100, 0b0001, 0b0011, 0b001>; // v8.4a RAS registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"ERXPFGCTL_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b101>; def : RWSysReg<"ERXPFGCDN_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b110>; def : RWSysReg<"ERXTS_EL1", 0b11, 0b000, 0b0101, 0b0101, 0b111>; def : RWSysReg<"ERXMISC2_EL1", 0b11, 0b000, 0b0101, 0b0101, 0b010>; def : RWSysReg<"ERXMISC3_EL1", 0b11, 0b000, 0b0101, 0b0101, 0b011>; def : ROSysReg<"ERXPFGF_EL1", 0b11, 0b000, 0b0101, 0b0100, 0b100>; // v8.4a MPAM registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"MPAM0_EL1", 0b11, 0b000, 0b1010, 0b0101, 0b001>; def : RWSysReg<"MPAM1_EL1", 0b11, 0b000, 0b1010, 0b0101, 0b000>; def : RWSysReg<"MPAM2_EL2", 0b11, 0b100, 0b1010, 0b0101, 0b000>; def : RWSysReg<"MPAM3_EL3", 0b11, 0b110, 0b1010, 0b0101, 0b000>; def : RWSysReg<"MPAM1_EL12", 0b11, 0b101, 0b1010, 0b0101, 0b000>; def : RWSysReg<"MPAMHCR_EL2", 0b11, 0b100, 0b1010, 0b0100, 0b000>; def : RWSysReg<"MPAMVPMV_EL2", 0b11, 0b100, 0b1010, 0b0100, 0b001>; def : RWSysReg<"MPAMVPM0_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b000>; def : RWSysReg<"MPAMVPM1_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b001>; def : RWSysReg<"MPAMVPM2_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b010>; def : RWSysReg<"MPAMVPM3_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b011>; def : RWSysReg<"MPAMVPM4_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b100>; def : RWSysReg<"MPAMVPM5_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b101>; def : RWSysReg<"MPAMVPM6_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b110>; def : RWSysReg<"MPAMVPM7_EL2", 0b11, 0b100, 0b1010, 0b0110, 0b111>; def : ROSysReg<"MPAMIDR_EL1", 0b11, 0b000, 0b1010, 0b0100, 0b100>; // v8.4a Activitiy monitor registers // Op0 Op1 CRn CRm Op2 def : RWSysReg<"AMCR_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b000>; def : ROSysReg<"AMCFGR_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b001>; def : ROSysReg<"AMCGCR_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b010>; def : RWSysReg<"AMUSERENR_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b011>; def : RWSysReg<"AMCNTENCLR0_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b100>; def : RWSysReg<"AMCNTENSET0_EL0", 0b11, 0b011, 0b1101, 0b0010, 0b101>; def : RWSysReg<"AMEVCNTR00_EL0", 0b11, 0b011, 0b1101, 0b0100, 0b000>; def : RWSysReg<"AMEVCNTR01_EL0", 0b11, 0b011, 0b1101, 0b0100, 0b001>; def : RWSysReg<"AMEVCNTR02_EL0", 0b11, 0b011, 0b1101, 0b0100, 0b010>; def : RWSysReg<"AMEVCNTR03_EL0", 0b11, 0b011, 0b1101, 0b0100, 0b011>; def : ROSysReg<"AMEVTYPER00_EL0", 0b11, 0b011, 0b1101, 0b0110, 0b000>; def : ROSysReg<"AMEVTYPER01_EL0", 0b11, 0b011, 0b1101, 0b0110, 0b001>; def : ROSysReg<"AMEVTYPER02_EL0", 0b11, 0b011, 0b1101, 0b0110, 0b010>; def : ROSysReg<"AMEVTYPER03_EL0", 0b11, 0b011, 0b1101, 0b0110, 0b011>; def : RWSysReg<"AMCNTENCLR1_EL0", 0b11, 0b011, 0b1101, 0b0011, 0b000>; def : RWSysReg<"AMCNTENSET1_EL0", 0b11, 0b011, 0b1101, 0b0011, 0b001>; def : RWSysReg<"AMEVCNTR10_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b000>; def : RWSysReg<"AMEVCNTR11_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b001>; def : RWSysReg<"AMEVCNTR12_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b010>; def : RWSysReg<"AMEVCNTR13_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b011>; def : RWSysReg<"AMEVCNTR14_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b100>; def : RWSysReg<"AMEVCNTR15_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b101>; def : RWSysReg<"AMEVCNTR16_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b110>; def : RWSysReg<"AMEVCNTR17_EL0", 0b11, 0b011, 0b1101, 0b1100, 0b111>; def : RWSysReg<"AMEVCNTR18_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b000>; def : RWSysReg<"AMEVCNTR19_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b001>; def : RWSysReg<"AMEVCNTR110_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b010>; def : RWSysReg<"AMEVCNTR111_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b011>; def : RWSysReg<"AMEVCNTR112_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b100>; def : RWSysReg<"AMEVCNTR113_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b101>; def : RWSysReg<"AMEVCNTR114_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b110>; def : RWSysReg<"AMEVCNTR115_EL0", 0b11, 0b011, 0b1101, 0b1101, 0b111>; def : RWSysReg<"AMEVTYPER10_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b000>; def : RWSysReg<"AMEVTYPER11_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b001>; def : RWSysReg<"AMEVTYPER12_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b010>; def : RWSysReg<"AMEVTYPER13_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b011>; def : RWSysReg<"AMEVTYPER14_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b100>; def : RWSysReg<"AMEVTYPER15_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b101>; def : RWSysReg<"AMEVTYPER16_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b110>; def : RWSysReg<"AMEVTYPER17_EL0", 0b11, 0b011, 0b1101, 0b1110, 0b111>; def : RWSysReg<"AMEVTYPER18_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b000>; def : RWSysReg<"AMEVTYPER19_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b001>; def : RWSysReg<"AMEVTYPER110_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b010>; def : RWSysReg<"AMEVTYPER111_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b011>; def : RWSysReg<"AMEVTYPER112_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b100>; def : RWSysReg<"AMEVTYPER113_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b101>; def : RWSysReg<"AMEVTYPER114_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b110>; def : RWSysReg<"AMEVTYPER115_EL0", 0b11, 0b011, 0b1101, 0b1111, 0b111>; // v8.4a Trace Extension registers // // Please note that the 8.4 spec also defines these registers: // TRCIDR1, ID_DFR0_EL1, ID_AA64DFR0_EL1, MDSCR_EL1, MDCR_EL2, and MDCR_EL3, // but they are already defined above. // // Op0 Op1 CRn CRm Op2 def : RWSysReg<"TRFCR_EL1", 0b11, 0b000, 0b0001, 0b0010, 0b001>; def : RWSysReg<"TRFCR_EL2", 0b11, 0b100, 0b0001, 0b0010, 0b001>; def : RWSysReg<"TRFCR_EL12", 0b11, 0b101, 0b0001, 0b0010, 0b001>; // v8.4a Timining insensitivity of data processing instructions // Op0 Op1 CRn CRm Op2 def : RWSysReg<"DIT", 0b11, 0b011, 0b0100, 0b0010, 0b101>; // v8.4a Enhanced Support for Nested Virtualization // Op0 Op1 CRn CRm Op2 def : RWSysReg<"VNCR_EL2", 0b11, 0b100, 0b0010, 0b0010, 0b000>; } // HasV8_4aOps + +// SVE control registers +// Op0 Op1 CRn CRm Op2 +let Requires = [{ {AArch64::FeatureSVE} }] in { +def : RWSysReg<"ZCR_EL1", 0b11, 0b000, 0b0001, 0b0010, 0b000>; +def : RWSysReg<"ZCR_EL2", 0b11, 0b100, 0b0001, 0b0010, 0b000>; +def : RWSysReg<"ZCR_EL3", 0b11, 0b110, 0b0001, 0b0010, 0b000>; +def : RWSysReg<"ZCR_EL12", 0b11, 0b101, 0b0001, 0b0010, 0b000>; +} // Cyclone specific system registers // Op0 Op1 CRn CRm Op2 let Requires = [{ {AArch64::ProcCyclone} }] in def : RWSysReg<"CPM_IOACC_CTL_EL3", 0b11, 0b111, 0b1111, 0b0010, 0b000>; Index: vendor/llvm/dist-release_70/lib/Target/X86/AsmParser/X86AsmParser.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/Target/X86/AsmParser/X86AsmParser.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/Target/X86/AsmParser/X86AsmParser.cpp (revision 338378) @@ -1,3455 +1,3457 @@ //===-- X86AsmParser.cpp - Parse X86 assembly to MCInst instructions ------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InstPrinter/X86IntelInstPrinter.h" #include "MCTargetDesc/X86BaseInfo.h" #include "MCTargetDesc/X86MCExpr.h" #include "MCTargetDesc/X86TargetStreamer.h" #include "X86AsmInstrumentation.h" #include "X86AsmParserCommon.h" #include "X86Operand.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include #include using namespace llvm; static bool checkScale(unsigned Scale, StringRef &ErrMsg) { if (Scale != 1 && Scale != 2 && Scale != 4 && Scale != 8) { ErrMsg = "scale factor in address must be 1, 2, 4 or 8"; return true; } return false; } namespace { static const char OpPrecedence[] = { 0, // IC_OR 1, // IC_XOR 2, // IC_AND 3, // IC_LSHIFT 3, // IC_RSHIFT 4, // IC_PLUS 4, // IC_MINUS 5, // IC_MULTIPLY 5, // IC_DIVIDE 5, // IC_MOD 6, // IC_NOT 7, // IC_NEG 8, // IC_RPAREN 9, // IC_LPAREN 0, // IC_IMM 0 // IC_REGISTER }; class X86AsmParser : public MCTargetAsmParser { ParseInstructionInfo *InstInfo; std::unique_ptr Instrumentation; bool Code16GCC; private: SMLoc consumeToken() { MCAsmParser &Parser = getParser(); SMLoc Result = Parser.getTok().getLoc(); Parser.Lex(); return Result; } X86TargetStreamer &getTargetStreamer() { assert(getParser().getStreamer().getTargetStreamer() && "do not have a target streamer"); MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast(TS); } unsigned MatchInstruction(const OperandVector &Operands, MCInst &Inst, uint64_t &ErrorInfo, bool matchingInlineAsm, unsigned VariantID = 0) { // In Code16GCC mode, match as 32-bit. if (Code16GCC) SwitchMode(X86::Mode32Bit); unsigned rv = MatchInstructionImpl(Operands, Inst, ErrorInfo, matchingInlineAsm, VariantID); if (Code16GCC) SwitchMode(X86::Mode16Bit); return rv; } enum InfixCalculatorTok { IC_OR = 0, IC_XOR, IC_AND, IC_LSHIFT, IC_RSHIFT, IC_PLUS, IC_MINUS, IC_MULTIPLY, IC_DIVIDE, IC_MOD, IC_NOT, IC_NEG, IC_RPAREN, IC_LPAREN, IC_IMM, IC_REGISTER }; enum IntelOperatorKind { IOK_INVALID = 0, IOK_LENGTH, IOK_SIZE, IOK_TYPE, IOK_OFFSET }; class InfixCalculator { typedef std::pair< InfixCalculatorTok, int64_t > ICToken; SmallVector InfixOperatorStack; SmallVector PostfixStack; bool isUnaryOperator(const InfixCalculatorTok Op) { return Op == IC_NEG || Op == IC_NOT; } public: int64_t popOperand() { assert (!PostfixStack.empty() && "Poped an empty stack!"); ICToken Op = PostfixStack.pop_back_val(); if (!(Op.first == IC_IMM || Op.first == IC_REGISTER)) return -1; // The invalid Scale value will be caught later by checkScale return Op.second; } void pushOperand(InfixCalculatorTok Op, int64_t Val = 0) { assert ((Op == IC_IMM || Op == IC_REGISTER) && "Unexpected operand!"); PostfixStack.push_back(std::make_pair(Op, Val)); } void popOperator() { InfixOperatorStack.pop_back(); } void pushOperator(InfixCalculatorTok Op) { // Push the new operator if the stack is empty. if (InfixOperatorStack.empty()) { InfixOperatorStack.push_back(Op); return; } // Push the new operator if it has a higher precedence than the operator // on the top of the stack or the operator on the top of the stack is a // left parentheses. unsigned Idx = InfixOperatorStack.size() - 1; InfixCalculatorTok StackOp = InfixOperatorStack[Idx]; if (OpPrecedence[Op] > OpPrecedence[StackOp] || StackOp == IC_LPAREN) { InfixOperatorStack.push_back(Op); return; } // The operator on the top of the stack has higher precedence than the // new operator. unsigned ParenCount = 0; while (1) { // Nothing to process. if (InfixOperatorStack.empty()) break; Idx = InfixOperatorStack.size() - 1; StackOp = InfixOperatorStack[Idx]; if (!(OpPrecedence[StackOp] >= OpPrecedence[Op] || ParenCount)) break; // If we have an even parentheses count and we see a left parentheses, // then stop processing. if (!ParenCount && StackOp == IC_LPAREN) break; if (StackOp == IC_RPAREN) { ++ParenCount; InfixOperatorStack.pop_back(); } else if (StackOp == IC_LPAREN) { --ParenCount; InfixOperatorStack.pop_back(); } else { InfixOperatorStack.pop_back(); PostfixStack.push_back(std::make_pair(StackOp, 0)); } } // Push the new operator. InfixOperatorStack.push_back(Op); } int64_t execute() { // Push any remaining operators onto the postfix stack. while (!InfixOperatorStack.empty()) { InfixCalculatorTok StackOp = InfixOperatorStack.pop_back_val(); if (StackOp != IC_LPAREN && StackOp != IC_RPAREN) PostfixStack.push_back(std::make_pair(StackOp, 0)); } if (PostfixStack.empty()) return 0; SmallVector OperandStack; for (unsigned i = 0, e = PostfixStack.size(); i != e; ++i) { ICToken Op = PostfixStack[i]; if (Op.first == IC_IMM || Op.first == IC_REGISTER) { OperandStack.push_back(Op); } else if (isUnaryOperator(Op.first)) { assert (OperandStack.size() > 0 && "Too few operands."); ICToken Operand = OperandStack.pop_back_val(); assert (Operand.first == IC_IMM && "Unary operation with a register!"); switch (Op.first) { default: report_fatal_error("Unexpected operator!"); break; case IC_NEG: OperandStack.push_back(std::make_pair(IC_IMM, -Operand.second)); break; case IC_NOT: OperandStack.push_back(std::make_pair(IC_IMM, ~Operand.second)); break; } } else { assert (OperandStack.size() > 1 && "Too few operands."); int64_t Val; ICToken Op2 = OperandStack.pop_back_val(); ICToken Op1 = OperandStack.pop_back_val(); switch (Op.first) { default: report_fatal_error("Unexpected operator!"); break; case IC_PLUS: Val = Op1.second + Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_MINUS: Val = Op1.second - Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_MULTIPLY: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Multiply operation with an immediate and a register!"); Val = Op1.second * Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_DIVIDE: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Divide operation with an immediate and a register!"); assert (Op2.second != 0 && "Division by zero!"); Val = Op1.second / Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_MOD: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Modulo operation with an immediate and a register!"); Val = Op1.second % Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_OR: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Or operation with an immediate and a register!"); Val = Op1.second | Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_XOR: assert(Op1.first == IC_IMM && Op2.first == IC_IMM && "Xor operation with an immediate and a register!"); Val = Op1.second ^ Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_AND: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "And operation with an immediate and a register!"); Val = Op1.second & Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_LSHIFT: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Left shift operation with an immediate and a register!"); Val = Op1.second << Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; case IC_RSHIFT: assert (Op1.first == IC_IMM && Op2.first == IC_IMM && "Right shift operation with an immediate and a register!"); Val = Op1.second >> Op2.second; OperandStack.push_back(std::make_pair(IC_IMM, Val)); break; } } } assert (OperandStack.size() == 1 && "Expected a single result."); return OperandStack.pop_back_val().second; } }; enum IntelExprState { IES_INIT, IES_OR, IES_XOR, IES_AND, IES_LSHIFT, IES_RSHIFT, IES_PLUS, IES_MINUS, IES_NOT, IES_MULTIPLY, IES_DIVIDE, IES_MOD, IES_LBRAC, IES_RBRAC, IES_LPAREN, IES_RPAREN, IES_REGISTER, IES_INTEGER, IES_IDENTIFIER, IES_ERROR }; class IntelExprStateMachine { IntelExprState State, PrevState; unsigned BaseReg, IndexReg, TmpReg, Scale; int64_t Imm; const MCExpr *Sym; StringRef SymName; InfixCalculator IC; InlineAsmIdentifierInfo Info; short BracCount; bool MemExpr; public: IntelExprStateMachine() : State(IES_INIT), PrevState(IES_ERROR), BaseReg(0), IndexReg(0), TmpReg(0), Scale(0), Imm(0), Sym(nullptr), BracCount(0), MemExpr(false) {} void addImm(int64_t imm) { Imm += imm; } short getBracCount() { return BracCount; } bool isMemExpr() { return MemExpr; } unsigned getBaseReg() { return BaseReg; } unsigned getIndexReg() { return IndexReg; } unsigned getScale() { return Scale; } const MCExpr *getSym() { return Sym; } StringRef getSymName() { return SymName; } int64_t getImm() { return Imm + IC.execute(); } bool isValidEndState() { return State == IES_RBRAC || State == IES_INTEGER; } bool hadError() { return State == IES_ERROR; } InlineAsmIdentifierInfo &getIdentifierInfo() { return Info; } void onOr() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_OR; IC.pushOperator(IC_OR); break; } PrevState = CurrState; } void onXor() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_XOR; IC.pushOperator(IC_XOR); break; } PrevState = CurrState; } void onAnd() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_AND; IC.pushOperator(IC_AND); break; } PrevState = CurrState; } void onLShift() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_LSHIFT; IC.pushOperator(IC_LSHIFT); break; } PrevState = CurrState; } void onRShift() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_RSHIFT; IC.pushOperator(IC_RSHIFT); break; } PrevState = CurrState; } bool onPlus(StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: case IES_REGISTER: State = IES_PLUS; IC.pushOperator(IC_PLUS); if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) { // If we already have a BaseReg, then assume this is the IndexReg with // no explicit scale. if (!BaseReg) { BaseReg = TmpReg; } else { if (IndexReg) { ErrMsg = "BaseReg/IndexReg already set!"; return true; } IndexReg = TmpReg; Scale = 0; } } break; } PrevState = CurrState; return false; } bool onMinus(StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_OR: case IES_XOR: case IES_AND: case IES_LSHIFT: case IES_RSHIFT: case IES_PLUS: case IES_NOT: case IES_MULTIPLY: case IES_DIVIDE: case IES_MOD: case IES_LPAREN: case IES_RPAREN: case IES_LBRAC: case IES_RBRAC: case IES_INTEGER: case IES_REGISTER: case IES_INIT: State = IES_MINUS; // push minus operator if it is not a negate operator if (CurrState == IES_REGISTER || CurrState == IES_RPAREN || CurrState == IES_INTEGER || CurrState == IES_RBRAC) IC.pushOperator(IC_MINUS); else if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) { // We have negate operator for Scale: it's illegal ErrMsg = "Scale can't be negative"; return true; } else IC.pushOperator(IC_NEG); if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) { // If we already have a BaseReg, then assume this is the IndexReg with // no explicit scale. if (!BaseReg) { BaseReg = TmpReg; } else { if (IndexReg) { ErrMsg = "BaseReg/IndexReg already set!"; return true; } IndexReg = TmpReg; Scale = 0; } } break; } PrevState = CurrState; return false; } void onNot() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_OR: case IES_XOR: case IES_AND: case IES_LSHIFT: case IES_RSHIFT: case IES_PLUS: case IES_MINUS: case IES_NOT: case IES_MULTIPLY: case IES_DIVIDE: case IES_MOD: case IES_LPAREN: case IES_LBRAC: case IES_INIT: State = IES_NOT; IC.pushOperator(IC_NOT); break; } PrevState = CurrState; } bool onRegister(unsigned Reg, StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_PLUS: case IES_LPAREN: case IES_LBRAC: State = IES_REGISTER; TmpReg = Reg; IC.pushOperand(IC_REGISTER); break; case IES_MULTIPLY: // Index Register - Scale * Register if (PrevState == IES_INTEGER) { if (IndexReg) { ErrMsg = "BaseReg/IndexReg already set!"; return true; } State = IES_REGISTER; IndexReg = Reg; // Get the scale and replace the 'Scale * Register' with '0'. Scale = IC.popOperand(); if (checkScale(Scale, ErrMsg)) return true; IC.pushOperand(IC_IMM); IC.popOperator(); } else { State = IES_ERROR; } break; } PrevState = CurrState; return false; } bool onIdentifierExpr(const MCExpr *SymRef, StringRef SymRefName, const InlineAsmIdentifierInfo &IDInfo, bool ParsingInlineAsm, StringRef &ErrMsg) { // InlineAsm: Treat an enum value as an integer if (ParsingInlineAsm) if (IDInfo.isKind(InlineAsmIdentifierInfo::IK_EnumVal)) return onInteger(IDInfo.Enum.EnumVal, ErrMsg); // Treat a symbolic constant like an integer if (auto *CE = dyn_cast(SymRef)) return onInteger(CE->getValue(), ErrMsg); PrevState = State; bool HasSymbol = Sym != nullptr; switch (State) { default: State = IES_ERROR; break; case IES_PLUS: case IES_MINUS: case IES_NOT: case IES_INIT: case IES_LBRAC: MemExpr = true; State = IES_INTEGER; Sym = SymRef; SymName = SymRefName; IC.pushOperand(IC_IMM); if (ParsingInlineAsm) Info = IDInfo; break; } if (HasSymbol) ErrMsg = "cannot use more than one symbol in memory operand"; return HasSymbol; } bool onInteger(int64_t TmpInt, StringRef &ErrMsg) { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_PLUS: case IES_MINUS: case IES_NOT: case IES_OR: case IES_XOR: case IES_AND: case IES_LSHIFT: case IES_RSHIFT: case IES_DIVIDE: case IES_MOD: case IES_MULTIPLY: case IES_LPAREN: case IES_INIT: case IES_LBRAC: State = IES_INTEGER; if (PrevState == IES_REGISTER && CurrState == IES_MULTIPLY) { // Index Register - Register * Scale if (IndexReg) { ErrMsg = "BaseReg/IndexReg already set!"; return true; } IndexReg = TmpReg; Scale = TmpInt; if (checkScale(Scale, ErrMsg)) return true; // Get the scale and replace the 'Register * Scale' with '0'. IC.popOperator(); } else { IC.pushOperand(IC_IMM, TmpInt); } break; } PrevState = CurrState; return false; } void onStar() { PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_REGISTER: case IES_RPAREN: State = IES_MULTIPLY; IC.pushOperator(IC_MULTIPLY); break; } } void onDivide() { PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: State = IES_DIVIDE; IC.pushOperator(IC_DIVIDE); break; } } void onMod() { PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_RPAREN: State = IES_MOD; IC.pushOperator(IC_MOD); break; } } bool onLBrac() { if (BracCount) return true; PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_RBRAC: case IES_INTEGER: case IES_RPAREN: State = IES_PLUS; IC.pushOperator(IC_PLUS); break; case IES_INIT: assert(!BracCount && "BracCount should be zero on parsing's start"); State = IES_LBRAC; break; } MemExpr = true; BracCount++; return false; } bool onRBrac() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_REGISTER: case IES_RPAREN: if (BracCount-- != 1) return true; State = IES_RBRAC; if (CurrState == IES_REGISTER && PrevState != IES_MULTIPLY) { // If we already have a BaseReg, then assume this is the IndexReg with // no explicit scale. if (!BaseReg) { BaseReg = TmpReg; } else { assert (!IndexReg && "BaseReg/IndexReg already set!"); IndexReg = TmpReg; Scale = 0; } } break; } PrevState = CurrState; return false; } void onLParen() { IntelExprState CurrState = State; switch (State) { default: State = IES_ERROR; break; case IES_PLUS: case IES_MINUS: case IES_NOT: case IES_OR: case IES_XOR: case IES_AND: case IES_LSHIFT: case IES_RSHIFT: case IES_MULTIPLY: case IES_DIVIDE: case IES_MOD: case IES_LPAREN: case IES_INIT: case IES_LBRAC: State = IES_LPAREN; IC.pushOperator(IC_LPAREN); break; } PrevState = CurrState; } void onRParen() { PrevState = State; switch (State) { default: State = IES_ERROR; break; case IES_INTEGER: case IES_REGISTER: case IES_RPAREN: State = IES_RPAREN; IC.pushOperator(IC_RPAREN); break; } } }; bool Error(SMLoc L, const Twine &Msg, SMRange Range = None, bool MatchingInlineAsm = false) { MCAsmParser &Parser = getParser(); if (MatchingInlineAsm) { if (!getLexer().isAtStartOfStatement()) Parser.eatToEndOfStatement(); return false; } return Parser.Error(L, Msg, Range); } std::nullptr_t ErrorOperand(SMLoc Loc, StringRef Msg) { Error(Loc, Msg); return nullptr; } std::unique_ptr DefaultMemSIOperand(SMLoc Loc); std::unique_ptr DefaultMemDIOperand(SMLoc Loc); bool IsSIReg(unsigned Reg); unsigned GetSIDIForRegClass(unsigned RegClassID, unsigned Reg, bool IsSIReg); void AddDefaultSrcDestOperands(OperandVector &Operands, std::unique_ptr &&Src, std::unique_ptr &&Dst); bool VerifyAndAdjustOperands(OperandVector &OrigOperands, OperandVector &FinalOperands); std::unique_ptr ParseOperand(); std::unique_ptr ParseATTOperand(); std::unique_ptr ParseIntelOperand(); std::unique_ptr ParseIntelOffsetOfOperator(); bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End); unsigned IdentifyIntelInlineAsmOperator(StringRef Name); unsigned ParseIntelInlineAsmOperator(unsigned OpKind); std::unique_ptr ParseRoundingModeOp(SMLoc Start); bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM); void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start, SMLoc End); bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End); bool ParseIntelInlineAsmIdentifier(const MCExpr *&Val, StringRef &Identifier, InlineAsmIdentifierInfo &Info, bool IsUnevaluatedOperand, SMLoc &End); std::unique_ptr ParseMemOperand(unsigned SegReg, SMLoc MemStart); bool ParseIntelMemoryOperandSize(unsigned &Size); std::unique_ptr CreateMemForInlineAsm(unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier, const InlineAsmIdentifierInfo &Info); bool parseDirectiveEven(SMLoc L); bool ParseDirectiveCode(StringRef IDVal, SMLoc L); /// CodeView FPO data directives. bool parseDirectiveFPOProc(SMLoc L); bool parseDirectiveFPOSetFrame(SMLoc L); bool parseDirectiveFPOPushReg(SMLoc L); bool parseDirectiveFPOStackAlloc(SMLoc L); bool parseDirectiveFPOEndPrologue(SMLoc L); bool parseDirectiveFPOEndProc(SMLoc L); bool parseDirectiveFPOData(SMLoc L); bool validateInstruction(MCInst &Inst, const OperandVector &Ops); bool processInstruction(MCInst &Inst, const OperandVector &Ops); /// Wrapper around MCStreamer::EmitInstruction(). Possibly adds /// instrumentation around Inst. void EmitInstruction(MCInst &Inst, OperandVector &Operands, MCStreamer &Out); bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override; void MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op, OperandVector &Operands, MCStreamer &Out, bool MatchingInlineAsm); bool ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo, bool MatchingInlineAsm); bool MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm); bool MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm); bool OmitRegisterFromClobberLists(unsigned RegNo) override; /// Parses AVX512 specific operand primitives: masked registers ({%k}, {z}) /// and memory broadcasting ({1to}) primitives, updating Operands vector if required. /// return false if no parsing errors occurred, true otherwise. bool HandleAVX512Operand(OperandVector &Operands, const MCParsedAsmOperand &Op); bool ParseZ(std::unique_ptr &Z, const SMLoc &StartLoc); bool is64BitMode() const { // FIXME: Can tablegen auto-generate this? return getSTI().getFeatureBits()[X86::Mode64Bit]; } bool is32BitMode() const { // FIXME: Can tablegen auto-generate this? return getSTI().getFeatureBits()[X86::Mode32Bit]; } bool is16BitMode() const { // FIXME: Can tablegen auto-generate this? return getSTI().getFeatureBits()[X86::Mode16Bit]; } void SwitchMode(unsigned mode) { MCSubtargetInfo &STI = copySTI(); FeatureBitset AllModes({X86::Mode64Bit, X86::Mode32Bit, X86::Mode16Bit}); FeatureBitset OldMode = STI.getFeatureBits() & AllModes; uint64_t FB = ComputeAvailableFeatures( STI.ToggleFeature(OldMode.flip(mode))); setAvailableFeatures(FB); assert(FeatureBitset({mode}) == (STI.getFeatureBits() & AllModes)); } unsigned getPointerWidth() { if (is16BitMode()) return 16; if (is32BitMode()) return 32; if (is64BitMode()) return 64; llvm_unreachable("invalid mode"); } bool isParsingIntelSyntax() { return getParser().getAssemblerDialect(); } /// @name Auto-generated Matcher Functions /// { #define GET_ASSEMBLER_HEADER #include "X86GenAsmMatcher.inc" /// } public: X86AsmParser(const MCSubtargetInfo &sti, MCAsmParser &Parser, const MCInstrInfo &mii, const MCTargetOptions &Options) : MCTargetAsmParser(Options, sti, mii), InstInfo(nullptr), Code16GCC(false) { Parser.addAliasForDirective(".word", ".2byte"); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); Instrumentation.reset( CreateX86AsmInstrumentation(Options, Parser.getContext(), STI)); } bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; void SetFrameRegister(unsigned RegNo) override; - bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) override; + bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override; bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; }; } // end anonymous namespace /// @name Auto-generated Match Functions /// { static unsigned MatchRegisterName(StringRef Name); /// } static bool CheckBaseRegAndIndexRegAndScale(unsigned BaseReg, unsigned IndexReg, unsigned Scale, bool Is64BitMode, StringRef &ErrMsg) { // If we have both a base register and an index register make sure they are // both 64-bit or 32-bit registers. // To support VSIB, IndexReg can be 128-bit or 256-bit registers. if (BaseReg != 0 && !(BaseReg == X86::RIP || BaseReg == X86::EIP || X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) || X86MCRegisterClasses[X86::GR32RegClassID].contains(BaseReg) || X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg))) { ErrMsg = "invalid base+index expression"; return true; } if (IndexReg != 0 && !(IndexReg == X86::EIZ || IndexReg == X86::RIZ || X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::VR128XRegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::VR256XRegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::VR512RegClassID].contains(IndexReg))) { ErrMsg = "invalid base+index expression"; return true; } if (((BaseReg == X86::RIP || BaseReg == X86::EIP) && IndexReg != 0) || IndexReg == X86::EIP || IndexReg == X86::RIP || IndexReg == X86::ESP || IndexReg == X86::RSP) { ErrMsg = "invalid base+index expression"; return true; } // Check for use of invalid 16-bit registers. Only BX/BP/SI/DI are allowed, // and then only in non-64-bit modes. if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) && (Is64BitMode || (BaseReg != X86::BX && BaseReg != X86::BP && BaseReg != X86::SI && BaseReg != X86::DI)) && BaseReg != X86::DX) { ErrMsg = "invalid 16-bit base register"; return true; } if (BaseReg == 0 && X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg)) { ErrMsg = "16-bit memory operand may not include only index register"; return true; } if (BaseReg != 0 && IndexReg != 0) { if (X86MCRegisterClasses[X86::GR64RegClassID].contains(BaseReg) && (X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg) || IndexReg == X86::EIZ)) { ErrMsg = "base register is 64-bit, but index register is not"; return true; } if (X86MCRegisterClasses[X86::GR32RegClassID].contains(BaseReg) && (X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg) || IndexReg == X86::RIZ)) { ErrMsg = "base register is 32-bit, but index register is not"; return true; } if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg)) { if (X86MCRegisterClasses[X86::GR32RegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::GR64RegClassID].contains(IndexReg)) { ErrMsg = "base register is 16-bit, but index register is not"; return true; } if ((BaseReg != X86::BX && BaseReg != X86::BP) || (IndexReg != X86::SI && IndexReg != X86::DI)) { ErrMsg = "invalid 16-bit base/index register combination"; return true; } } } // RIP/EIP-relative addressing is only supported in 64-bit mode. if (!Is64BitMode && BaseReg != 0 && (BaseReg == X86::RIP || BaseReg == X86::EIP)) { ErrMsg = "RIP-relative addressing requires 64-bit mode"; return true; } return checkScale(Scale, ErrMsg); } bool X86AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { MCAsmParser &Parser = getParser(); RegNo = 0; const AsmToken &PercentTok = Parser.getTok(); StartLoc = PercentTok.getLoc(); // If we encounter a %, ignore it. This code handles registers with and // without the prefix, unprefixed registers can occur in cfi directives. if (!isParsingIntelSyntax() && PercentTok.is(AsmToken::Percent)) Parser.Lex(); // Eat percent token. const AsmToken &Tok = Parser.getTok(); EndLoc = Tok.getEndLoc(); if (Tok.isNot(AsmToken::Identifier)) { if (isParsingIntelSyntax()) return true; return Error(StartLoc, "invalid register name", SMRange(StartLoc, EndLoc)); } RegNo = MatchRegisterName(Tok.getString()); // If the match failed, try the register name as lowercase. if (RegNo == 0) RegNo = MatchRegisterName(Tok.getString().lower()); // The "flags" register cannot be referenced directly. // Treat it as an identifier instead. if (isParsingInlineAsm() && isParsingIntelSyntax() && RegNo == X86::EFLAGS) RegNo = 0; if (!is64BitMode()) { // FIXME: This should be done using Requires and // Requires so "eiz" usage in 64-bit instructions can be also // checked. // FIXME: Check AH, CH, DH, BH cannot be used in an instruction requiring a // REX prefix. if (RegNo == X86::RIZ || RegNo == X86::RIP || RegNo == X86::EIP || X86MCRegisterClasses[X86::GR64RegClassID].contains(RegNo) || X86II::isX86_64NonExtLowByteReg(RegNo) || X86II::isX86_64ExtendedReg(RegNo)) return Error(StartLoc, "register %" + Tok.getString() + " is only available in 64-bit mode", SMRange(StartLoc, EndLoc)); } // Parse "%st" as "%st(0)" and "%st(1)", which is multiple tokens. if (RegNo == 0 && (Tok.getString() == "st" || Tok.getString() == "ST")) { RegNo = X86::ST0; Parser.Lex(); // Eat 'st' // Check to see if we have '(4)' after %st. if (getLexer().isNot(AsmToken::LParen)) return false; // Lex the paren. getParser().Lex(); const AsmToken &IntTok = Parser.getTok(); if (IntTok.isNot(AsmToken::Integer)) return Error(IntTok.getLoc(), "expected stack index"); switch (IntTok.getIntVal()) { case 0: RegNo = X86::ST0; break; case 1: RegNo = X86::ST1; break; case 2: RegNo = X86::ST2; break; case 3: RegNo = X86::ST3; break; case 4: RegNo = X86::ST4; break; case 5: RegNo = X86::ST5; break; case 6: RegNo = X86::ST6; break; case 7: RegNo = X86::ST7; break; default: return Error(IntTok.getLoc(), "invalid stack index"); } if (getParser().Lex().isNot(AsmToken::RParen)) return Error(Parser.getTok().getLoc(), "expected ')'"); EndLoc = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat ')' return false; } EndLoc = Parser.getTok().getEndLoc(); // If this is "db[0-15]", match it as an alias // for dr[0-15]. if (RegNo == 0 && Tok.getString().startswith("db")) { if (Tok.getString().size() == 3) { switch (Tok.getString()[2]) { case '0': RegNo = X86::DR0; break; case '1': RegNo = X86::DR1; break; case '2': RegNo = X86::DR2; break; case '3': RegNo = X86::DR3; break; case '4': RegNo = X86::DR4; break; case '5': RegNo = X86::DR5; break; case '6': RegNo = X86::DR6; break; case '7': RegNo = X86::DR7; break; case '8': RegNo = X86::DR8; break; case '9': RegNo = X86::DR9; break; } } else if (Tok.getString().size() == 4 && Tok.getString()[2] == '1') { switch (Tok.getString()[3]) { case '0': RegNo = X86::DR10; break; case '1': RegNo = X86::DR11; break; case '2': RegNo = X86::DR12; break; case '3': RegNo = X86::DR13; break; case '4': RegNo = X86::DR14; break; case '5': RegNo = X86::DR15; break; } } if (RegNo != 0) { EndLoc = Parser.getTok().getEndLoc(); Parser.Lex(); // Eat it. return false; } } if (RegNo == 0) { if (isParsingIntelSyntax()) return true; return Error(StartLoc, "invalid register name", SMRange(StartLoc, EndLoc)); } Parser.Lex(); // Eat identifier token. return false; } void X86AsmParser::SetFrameRegister(unsigned RegNo) { Instrumentation->SetInitialFrameRegister(RegNo); } std::unique_ptr X86AsmParser::DefaultMemSIOperand(SMLoc Loc) { bool Parse32 = is32BitMode() || Code16GCC; unsigned Basereg = is64BitMode() ? X86::RSI : (Parse32 ? X86::ESI : X86::SI); const MCExpr *Disp = MCConstantExpr::create(0, getContext()); return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp, /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); } std::unique_ptr X86AsmParser::DefaultMemDIOperand(SMLoc Loc) { bool Parse32 = is32BitMode() || Code16GCC; unsigned Basereg = is64BitMode() ? X86::RDI : (Parse32 ? X86::EDI : X86::DI); const MCExpr *Disp = MCConstantExpr::create(0, getContext()); return X86Operand::CreateMem(getPointerWidth(), /*SegReg=*/0, Disp, /*BaseReg=*/Basereg, /*IndexReg=*/0, /*Scale=*/1, Loc, Loc, 0); } bool X86AsmParser::IsSIReg(unsigned Reg) { switch (Reg) { default: llvm_unreachable("Only (R|E)SI and (R|E)DI are expected!"); case X86::RSI: case X86::ESI: case X86::SI: return true; case X86::RDI: case X86::EDI: case X86::DI: return false; } } unsigned X86AsmParser::GetSIDIForRegClass(unsigned RegClassID, unsigned Reg, bool IsSIReg) { switch (RegClassID) { default: llvm_unreachable("Unexpected register class"); case X86::GR64RegClassID: return IsSIReg ? X86::RSI : X86::RDI; case X86::GR32RegClassID: return IsSIReg ? X86::ESI : X86::EDI; case X86::GR16RegClassID: return IsSIReg ? X86::SI : X86::DI; } } void X86AsmParser::AddDefaultSrcDestOperands( OperandVector& Operands, std::unique_ptr &&Src, std::unique_ptr &&Dst) { if (isParsingIntelSyntax()) { Operands.push_back(std::move(Dst)); Operands.push_back(std::move(Src)); } else { Operands.push_back(std::move(Src)); Operands.push_back(std::move(Dst)); } } bool X86AsmParser::VerifyAndAdjustOperands(OperandVector &OrigOperands, OperandVector &FinalOperands) { if (OrigOperands.size() > 1) { // Check if sizes match, OrigOperands also contains the instruction name assert(OrigOperands.size() == FinalOperands.size() + 1 && "Operand size mismatch"); SmallVector, 2> Warnings; // Verify types match int RegClassID = -1; for (unsigned int i = 0; i < FinalOperands.size(); ++i) { X86Operand &OrigOp = static_cast(*OrigOperands[i + 1]); X86Operand &FinalOp = static_cast(*FinalOperands[i]); if (FinalOp.isReg() && (!OrigOp.isReg() || FinalOp.getReg() != OrigOp.getReg())) // Return false and let a normal complaint about bogus operands happen return false; if (FinalOp.isMem()) { if (!OrigOp.isMem()) // Return false and let a normal complaint about bogus operands happen return false; unsigned OrigReg = OrigOp.Mem.BaseReg; unsigned FinalReg = FinalOp.Mem.BaseReg; // If we've already encounterd a register class, make sure all register // bases are of the same register class if (RegClassID != -1 && !X86MCRegisterClasses[RegClassID].contains(OrigReg)) { return Error(OrigOp.getStartLoc(), "mismatching source and destination index registers"); } if (X86MCRegisterClasses[X86::GR64RegClassID].contains(OrigReg)) RegClassID = X86::GR64RegClassID; else if (X86MCRegisterClasses[X86::GR32RegClassID].contains(OrigReg)) RegClassID = X86::GR32RegClassID; else if (X86MCRegisterClasses[X86::GR16RegClassID].contains(OrigReg)) RegClassID = X86::GR16RegClassID; else // Unexpected register class type // Return false and let a normal complaint about bogus operands happen return false; bool IsSI = IsSIReg(FinalReg); FinalReg = GetSIDIForRegClass(RegClassID, FinalReg, IsSI); if (FinalReg != OrigReg) { std::string RegName = IsSI ? "ES:(R|E)SI" : "ES:(R|E)DI"; Warnings.push_back(std::make_pair( OrigOp.getStartLoc(), "memory operand is only for determining the size, " + RegName + " will be used for the location")); } FinalOp.Mem.Size = OrigOp.Mem.Size; FinalOp.Mem.SegReg = OrigOp.Mem.SegReg; FinalOp.Mem.BaseReg = FinalReg; } } // Produce warnings only if all the operands passed the adjustment - prevent // legal cases like "movsd (%rax), %xmm0" mistakenly produce warnings for (auto &WarningMsg : Warnings) { Warning(WarningMsg.first, WarningMsg.second); } // Remove old operands for (unsigned int i = 0; i < FinalOperands.size(); ++i) OrigOperands.pop_back(); } // OrigOperands.append(FinalOperands.begin(), FinalOperands.end()); for (unsigned int i = 0; i < FinalOperands.size(); ++i) OrigOperands.push_back(std::move(FinalOperands[i])); return false; } std::unique_ptr X86AsmParser::ParseOperand() { if (isParsingIntelSyntax()) return ParseIntelOperand(); return ParseATTOperand(); } std::unique_ptr X86AsmParser::CreateMemForInlineAsm( unsigned SegReg, const MCExpr *Disp, unsigned BaseReg, unsigned IndexReg, unsigned Scale, SMLoc Start, SMLoc End, unsigned Size, StringRef Identifier, const InlineAsmIdentifierInfo &Info) { // If we found a decl other than a VarDecl, then assume it is a FuncDecl or // some other label reference. if (Info.isKind(InlineAsmIdentifierInfo::IK_Label)) { // Insert an explicit size if the user didn't have one. if (!Size) { Size = getPointerWidth(); InstInfo->AsmRewrites->emplace_back(AOK_SizeDirective, Start, /*Len=*/0, Size); } // Create an absolute memory reference in order to match against // instructions taking a PC relative operand. return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size, Identifier, Info.Label.Decl); } // We either have a direct symbol reference, or an offset from a symbol. The // parser always puts the symbol on the LHS, so look there for size // calculation purposes. unsigned FrontendSize = 0; void *Decl = nullptr; bool IsGlobalLV = false; if (Info.isKind(InlineAsmIdentifierInfo::IK_Var)) { // Size is in terms of bits in this context. FrontendSize = Info.Var.Type * 8; Decl = Info.Var.Decl; IsGlobalLV = Info.Var.IsGlobalLV; } // It is widely common for MS InlineAsm to use a global variable and one/two // registers in a mmory expression, and though unaccessible via rip/eip. if (IsGlobalLV && (BaseReg || IndexReg)) { return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End); // Otherwise, we set the base register to a non-zero value // if we don't know the actual value at this time. This is necessary to // get the matching correct in some cases. } else { BaseReg = BaseReg ? BaseReg : 1; return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg, IndexReg, Scale, Start, End, Size, Identifier, Decl, FrontendSize); } } // Some binary bitwise operators have a named synonymous // Query a candidate string for being such a named operator // and if so - invoke the appropriate handler bool X86AsmParser::ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM) { // A named operator should be either lower or upper case, but not a mix if (Name.compare(Name.lower()) && Name.compare(Name.upper())) return false; if (Name.equals_lower("not")) SM.onNot(); else if (Name.equals_lower("or")) SM.onOr(); else if (Name.equals_lower("shl")) SM.onLShift(); else if (Name.equals_lower("shr")) SM.onRShift(); else if (Name.equals_lower("xor")) SM.onXor(); else if (Name.equals_lower("and")) SM.onAnd(); else if (Name.equals_lower("mod")) SM.onMod(); else return false; return true; } bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); StringRef ErrMsg; AsmToken::TokenKind PrevTK = AsmToken::Error; bool Done = false; while (!Done) { bool UpdateLocLex = true; AsmToken::TokenKind TK = getLexer().getKind(); switch (TK) { default: if ((Done = SM.isValidEndState())) break; return Error(Tok.getLoc(), "unknown token in expression"); case AsmToken::EndOfStatement: Done = true; break; case AsmToken::Real: // DotOperator: [ebx].0 UpdateLocLex = false; if (ParseIntelDotOperator(SM, End)) return true; break; case AsmToken::At: case AsmToken::String: case AsmToken::Identifier: { SMLoc IdentLoc = Tok.getLoc(); StringRef Identifier = Tok.getString(); UpdateLocLex = false; // Register unsigned Reg; if (Tok.is(AsmToken::Identifier) && !ParseRegister(Reg, IdentLoc, End)) { if (SM.onRegister(Reg, ErrMsg)) return Error(Tok.getLoc(), ErrMsg); break; } // Operator synonymous ("not", "or" etc.) if ((UpdateLocLex = ParseIntelNamedOperator(Identifier, SM))) break; // Symbol reference, when parsing assembly content InlineAsmIdentifierInfo Info; const MCExpr *Val; if (!isParsingInlineAsm()) { if (getParser().parsePrimaryExpr(Val, End)) { return Error(Tok.getLoc(), "Unexpected identifier!"); } else if (SM.onIdentifierExpr(Val, Identifier, Info, false, ErrMsg)) { return Error(IdentLoc, ErrMsg); } else break; } // MS InlineAsm operators (TYPE/LENGTH/SIZE) if (unsigned OpKind = IdentifyIntelInlineAsmOperator(Identifier)) { if (OpKind == IOK_OFFSET) return Error(IdentLoc, "Dealing OFFSET operator as part of" "a compound immediate expression is yet to be supported"); if (int64_t Val = ParseIntelInlineAsmOperator(OpKind)) { if (SM.onInteger(Val, ErrMsg)) return Error(IdentLoc, ErrMsg); } else return true; break; } // MS Dot Operator expression if (Identifier.count('.') && PrevTK == AsmToken::RBrac) { if (ParseIntelDotOperator(SM, End)) return true; break; } // MS InlineAsm identifier // Call parseIdentifier() to combine @ with the identifier behind it. if (TK == AsmToken::At && Parser.parseIdentifier(Identifier)) return Error(IdentLoc, "expected identifier"); if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, false, End)) return true; else if (SM.onIdentifierExpr(Val, Identifier, Info, true, ErrMsg)) return Error(IdentLoc, ErrMsg); break; } case AsmToken::Integer: { // Look for 'b' or 'f' following an Integer as a directional label SMLoc Loc = getTok().getLoc(); int64_t IntVal = getTok().getIntVal(); End = consumeToken(); UpdateLocLex = false; if (getLexer().getKind() == AsmToken::Identifier) { StringRef IDVal = getTok().getString(); if (IDVal == "f" || IDVal == "b") { MCSymbol *Sym = getContext().getDirectionalLocalSymbol(IntVal, IDVal == "b"); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; const MCExpr *Val = MCSymbolRefExpr::create(Sym, Variant, getContext()); if (IDVal == "b" && Sym->isUndefined()) return Error(Loc, "invalid reference to undefined symbol"); StringRef Identifier = Sym->getName(); InlineAsmIdentifierInfo Info; if (SM.onIdentifierExpr(Val, Identifier, Info, isParsingInlineAsm(), ErrMsg)) return Error(Loc, ErrMsg); End = consumeToken(); } else { if (SM.onInteger(IntVal, ErrMsg)) return Error(Loc, ErrMsg); } } else { if (SM.onInteger(IntVal, ErrMsg)) return Error(Loc, ErrMsg); } break; } case AsmToken::Plus: if (SM.onPlus(ErrMsg)) return Error(getTok().getLoc(), ErrMsg); break; case AsmToken::Minus: if (SM.onMinus(ErrMsg)) return Error(getTok().getLoc(), ErrMsg); break; case AsmToken::Tilde: SM.onNot(); break; case AsmToken::Star: SM.onStar(); break; case AsmToken::Slash: SM.onDivide(); break; case AsmToken::Percent: SM.onMod(); break; case AsmToken::Pipe: SM.onOr(); break; case AsmToken::Caret: SM.onXor(); break; case AsmToken::Amp: SM.onAnd(); break; case AsmToken::LessLess: SM.onLShift(); break; case AsmToken::GreaterGreater: SM.onRShift(); break; case AsmToken::LBrac: if (SM.onLBrac()) return Error(Tok.getLoc(), "unexpected bracket encountered"); break; case AsmToken::RBrac: if (SM.onRBrac()) return Error(Tok.getLoc(), "unexpected bracket encountered"); break; case AsmToken::LParen: SM.onLParen(); break; case AsmToken::RParen: SM.onRParen(); break; } if (SM.hadError()) return Error(Tok.getLoc(), "unknown token in expression"); if (!Done && UpdateLocLex) End = consumeToken(); PrevTK = TK; } return false; } void X86AsmParser::RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start, SMLoc End) { SMLoc Loc = Start; unsigned ExprLen = End.getPointer() - Start.getPointer(); // Skip everything before a symbol displacement (if we have one) if (SM.getSym()) { StringRef SymName = SM.getSymName(); if (unsigned Len = SymName.data() - Start.getPointer()) InstInfo->AsmRewrites->emplace_back(AOK_Skip, Start, Len); Loc = SMLoc::getFromPointer(SymName.data() + SymName.size()); ExprLen = End.getPointer() - (SymName.data() + SymName.size()); // If we have only a symbol than there's no need for complex rewrite, // simply skip everything after it if (!(SM.getBaseReg() || SM.getIndexReg() || SM.getImm())) { if (ExprLen) InstInfo->AsmRewrites->emplace_back(AOK_Skip, Loc, ExprLen); return; } } // Build an Intel Expression rewrite StringRef BaseRegStr; StringRef IndexRegStr; if (SM.getBaseReg()) BaseRegStr = X86IntelInstPrinter::getRegisterName(SM.getBaseReg()); if (SM.getIndexReg()) IndexRegStr = X86IntelInstPrinter::getRegisterName(SM.getIndexReg()); // Emit it IntelExpr Expr(BaseRegStr, IndexRegStr, SM.getScale(), SM.getImm(), SM.isMemExpr()); InstInfo->AsmRewrites->emplace_back(Loc, ExprLen, Expr); } // Inline assembly may use variable names with namespace alias qualifiers. bool X86AsmParser::ParseIntelInlineAsmIdentifier(const MCExpr *&Val, StringRef &Identifier, InlineAsmIdentifierInfo &Info, bool IsUnevaluatedOperand, SMLoc &End) { MCAsmParser &Parser = getParser(); assert(isParsingInlineAsm() && "Expected to be parsing inline assembly."); Val = nullptr; StringRef LineBuf(Identifier.data()); SemaCallback->LookupInlineAsmIdentifier(LineBuf, Info, IsUnevaluatedOperand); const AsmToken &Tok = Parser.getTok(); SMLoc Loc = Tok.getLoc(); // Advance the token stream until the end of the current token is // after the end of what the frontend claimed. const char *EndPtr = Tok.getLoc().getPointer() + LineBuf.size(); do { End = Tok.getEndLoc(); getLexer().Lex(); } while (End.getPointer() < EndPtr); Identifier = LineBuf; // The frontend should end parsing on an assembler token boundary, unless it // failed parsing. assert((End.getPointer() == EndPtr || Info.isKind(InlineAsmIdentifierInfo::IK_Invalid)) && "frontend claimed part of a token?"); // If the identifier lookup was unsuccessful, assume that we are dealing with // a label. if (Info.isKind(InlineAsmIdentifierInfo::IK_Invalid)) { StringRef InternalName = SemaCallback->LookupInlineAsmLabel(Identifier, getSourceManager(), Loc, false); assert(InternalName.size() && "We should have an internal name here."); // Push a rewrite for replacing the identifier name with the internal name. InstInfo->AsmRewrites->emplace_back(AOK_Label, Loc, Identifier.size(), InternalName); } else if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal)) return false; // Create the symbol reference. MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; Val = MCSymbolRefExpr::create(Sym, Variant, getParser().getContext()); return false; } //ParseRoundingModeOp - Parse AVX-512 rounding mode operand std::unique_ptr X86AsmParser::ParseRoundingModeOp(SMLoc Start) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); // Eat "{" and mark the current place. const SMLoc consumedToken = consumeToken(); if (Tok.getIdentifier().startswith("r")){ int rndMode = StringSwitch(Tok.getIdentifier()) .Case("rn", X86::STATIC_ROUNDING::TO_NEAREST_INT) .Case("rd", X86::STATIC_ROUNDING::TO_NEG_INF) .Case("ru", X86::STATIC_ROUNDING::TO_POS_INF) .Case("rz", X86::STATIC_ROUNDING::TO_ZERO) .Default(-1); if (-1 == rndMode) return ErrorOperand(Tok.getLoc(), "Invalid rounding mode."); Parser.Lex(); // Eat "r*" of r*-sae if (!getLexer().is(AsmToken::Minus)) return ErrorOperand(Tok.getLoc(), "Expected - at this point"); Parser.Lex(); // Eat "-" Parser.Lex(); // Eat the sae if (!getLexer().is(AsmToken::RCurly)) return ErrorOperand(Tok.getLoc(), "Expected } at this point"); SMLoc End = Tok.getEndLoc(); Parser.Lex(); // Eat "}" const MCExpr *RndModeOp = MCConstantExpr::create(rndMode, Parser.getContext()); return X86Operand::CreateImm(RndModeOp, Start, End); } if(Tok.getIdentifier().equals("sae")){ Parser.Lex(); // Eat the sae if (!getLexer().is(AsmToken::RCurly)) return ErrorOperand(Tok.getLoc(), "Expected } at this point"); Parser.Lex(); // Eat "}" return X86Operand::CreateToken("{sae}", consumedToken); } return ErrorOperand(Tok.getLoc(), "unknown token in expression"); } /// Parse the '.' operator. bool X86AsmParser::ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End) { const AsmToken &Tok = getTok(); unsigned Offset; // Drop the optional '.'. StringRef DotDispStr = Tok.getString(); if (DotDispStr.startswith(".")) DotDispStr = DotDispStr.drop_front(1); // .Imm gets lexed as a real. if (Tok.is(AsmToken::Real)) { APInt DotDisp; DotDispStr.getAsInteger(10, DotDisp); Offset = DotDisp.getZExtValue(); } else if (isParsingInlineAsm() && Tok.is(AsmToken::Identifier)) { std::pair BaseMember = DotDispStr.split('.'); if (SemaCallback->LookupInlineAsmField(BaseMember.first, BaseMember.second, Offset)) return Error(Tok.getLoc(), "Unable to lookup field reference!"); } else return Error(Tok.getLoc(), "Unexpected token type!"); // Eat the DotExpression and update End End = SMLoc::getFromPointer(DotDispStr.data()); const char *DotExprEndLoc = DotDispStr.data() + DotDispStr.size(); while (Tok.getLoc().getPointer() < DotExprEndLoc) Lex(); SM.addImm(Offset); return false; } /// Parse the 'offset' operator. This operator is used to specify the /// location rather then the content of a variable. std::unique_ptr X86AsmParser::ParseIntelOffsetOfOperator() { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc OffsetOfLoc = Tok.getLoc(); Parser.Lex(); // Eat offset. const MCExpr *Val; InlineAsmIdentifierInfo Info; SMLoc Start = Tok.getLoc(), End; StringRef Identifier = Tok.getString(); if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, /*Unevaluated=*/false, End)) return nullptr; void *Decl = nullptr; // FIXME: MS evaluates "offset " to the underlying integral if (Info.isKind(InlineAsmIdentifierInfo::IK_EnumVal)) return ErrorOperand(Start, "offset operator cannot yet handle constants"); else if (Info.isKind(InlineAsmIdentifierInfo::IK_Var)) Decl = Info.Var.Decl; // Don't emit the offset operator. InstInfo->AsmRewrites->emplace_back(AOK_Skip, OffsetOfLoc, 7); // The offset operator will have an 'r' constraint, thus we need to create // register operand to ensure proper matching. Just pick a GPR based on // the size of a pointer. bool Parse32 = is32BitMode() || Code16GCC; unsigned RegNo = is64BitMode() ? X86::RBX : (Parse32 ? X86::EBX : X86::BX); return X86Operand::CreateReg(RegNo, Start, End, /*GetAddress=*/true, OffsetOfLoc, Identifier, Decl); } // Query a candidate string for being an Intel assembly operator // Report back its kind, or IOK_INVALID if does not evaluated as a known one unsigned X86AsmParser::IdentifyIntelInlineAsmOperator(StringRef Name) { return StringSwitch(Name) .Cases("TYPE","type",IOK_TYPE) .Cases("SIZE","size",IOK_SIZE) .Cases("LENGTH","length",IOK_LENGTH) .Cases("OFFSET","offset",IOK_OFFSET) .Default(IOK_INVALID); } /// Parse the 'LENGTH', 'TYPE' and 'SIZE' operators. The LENGTH operator /// returns the number of elements in an array. It returns the value 1 for /// non-array variables. The SIZE operator returns the size of a C or C++ /// variable. A variable's size is the product of its LENGTH and TYPE. The /// TYPE operator returns the size of a C or C++ type or variable. If the /// variable is an array, TYPE returns the size of a single element. unsigned X86AsmParser::ParseIntelInlineAsmOperator(unsigned OpKind) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); Parser.Lex(); // Eat operator. const MCExpr *Val = nullptr; InlineAsmIdentifierInfo Info; SMLoc Start = Tok.getLoc(), End; StringRef Identifier = Tok.getString(); if (ParseIntelInlineAsmIdentifier(Val, Identifier, Info, /*Unevaluated=*/true, End)) return 0; if (!Info.isKind(InlineAsmIdentifierInfo::IK_Var)) { Error(Start, "unable to lookup expression"); return 0; } unsigned CVal = 0; switch(OpKind) { default: llvm_unreachable("Unexpected operand kind!"); case IOK_LENGTH: CVal = Info.Var.Length; break; case IOK_SIZE: CVal = Info.Var.Size; break; case IOK_TYPE: CVal = Info.Var.Type; break; } return CVal; } bool X86AsmParser::ParseIntelMemoryOperandSize(unsigned &Size) { Size = StringSwitch(getTok().getString()) .Cases("BYTE", "byte", 8) .Cases("WORD", "word", 16) .Cases("DWORD", "dword", 32) .Cases("FLOAT", "float", 32) .Cases("LONG", "long", 32) .Cases("FWORD", "fword", 48) .Cases("DOUBLE", "double", 64) .Cases("QWORD", "qword", 64) .Cases("MMWORD","mmword", 64) .Cases("XWORD", "xword", 80) .Cases("TBYTE", "tbyte", 80) .Cases("XMMWORD", "xmmword", 128) .Cases("YMMWORD", "ymmword", 256) .Cases("ZMMWORD", "zmmword", 512) .Default(0); if (Size) { const AsmToken &Tok = Lex(); // Eat operand size (e.g., byte, word). if (!(Tok.getString().equals("PTR") || Tok.getString().equals("ptr"))) return Error(Tok.getLoc(), "Expected 'PTR' or 'ptr' token!"); Lex(); // Eat ptr. } return false; } std::unique_ptr X86AsmParser::ParseIntelOperand() { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); SMLoc Start, End; // FIXME: Offset operator // Should be handled as part of immediate expression, as other operators // Currently, only supported as a stand-alone operand if (isParsingInlineAsm()) if (IdentifyIntelInlineAsmOperator(Tok.getString()) == IOK_OFFSET) return ParseIntelOffsetOfOperator(); // Parse optional Size directive. unsigned Size; if (ParseIntelMemoryOperandSize(Size)) return nullptr; bool PtrInOperand = bool(Size); Start = Tok.getLoc(); // Rounding mode operand. if (getLexer().is(AsmToken::LCurly)) return ParseRoundingModeOp(Start); // Register operand. unsigned RegNo = 0; if (Tok.is(AsmToken::Identifier) && !ParseRegister(RegNo, Start, End)) { if (RegNo == X86::RIP) return ErrorOperand(Start, "rip can only be used as a base register"); // A Register followed by ':' is considered a segment override if (Tok.isNot(AsmToken::Colon)) return !PtrInOperand ? X86Operand::CreateReg(RegNo, Start, End) : ErrorOperand(Start, "expected memory operand after 'ptr', " "found register operand instead"); // An alleged segment override. check if we have a valid segment register if (!X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo)) return ErrorOperand(Start, "invalid segment register"); // Eat ':' and update Start location Start = Lex().getLoc(); } // Immediates and Memory IntelExprStateMachine SM; if (ParseIntelExpression(SM, End)) return nullptr; if (isParsingInlineAsm()) RewriteIntelExpression(SM, Start, Tok.getLoc()); int64_t Imm = SM.getImm(); const MCExpr *Disp = SM.getSym(); const MCExpr *ImmDisp = MCConstantExpr::create(Imm, getContext()); if (Disp && Imm) Disp = MCBinaryExpr::createAdd(Disp, ImmDisp, getContext()); if (!Disp) Disp = ImmDisp; // RegNo != 0 specifies a valid segment register, // and we are parsing a segment override if (!SM.isMemExpr() && !RegNo) return X86Operand::CreateImm(Disp, Start, End); StringRef ErrMsg; unsigned BaseReg = SM.getBaseReg(); unsigned IndexReg = SM.getIndexReg(); unsigned Scale = SM.getScale(); if (Scale == 0 && BaseReg != X86::ESP && BaseReg != X86::RSP && (IndexReg == X86::ESP || IndexReg == X86::RSP)) std::swap(BaseReg, IndexReg); // If BaseReg is a vector register and IndexReg is not, swap them unless // Scale was specified in which case it would be an error. if (Scale == 0 && !(X86MCRegisterClasses[X86::VR128XRegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::VR256XRegClassID].contains(IndexReg) || X86MCRegisterClasses[X86::VR512RegClassID].contains(IndexReg)) && (X86MCRegisterClasses[X86::VR128XRegClassID].contains(BaseReg) || X86MCRegisterClasses[X86::VR256XRegClassID].contains(BaseReg) || X86MCRegisterClasses[X86::VR512RegClassID].contains(BaseReg))) std::swap(BaseReg, IndexReg); if (Scale != 0 && X86MCRegisterClasses[X86::GR16RegClassID].contains(IndexReg)) return ErrorOperand(Start, "16-bit addresses cannot have a scale"); // If there was no explicit scale specified, change it to 1. if (Scale == 0) Scale = 1; // If this is a 16-bit addressing mode with the base and index in the wrong // order, swap them so CheckBaseRegAndIndexRegAndScale doesn't fail. It is // shared with att syntax where order matters. if ((BaseReg == X86::SI || BaseReg == X86::DI) && (IndexReg == X86::BX || IndexReg == X86::BP)) std::swap(BaseReg, IndexReg); if ((BaseReg || IndexReg) && CheckBaseRegAndIndexRegAndScale(BaseReg, IndexReg, Scale, is64BitMode(), ErrMsg)) return ErrorOperand(Start, ErrMsg); if (isParsingInlineAsm()) return CreateMemForInlineAsm(RegNo, Disp, BaseReg, IndexReg, Scale, Start, End, Size, SM.getSymName(), SM.getIdentifierInfo()); if (!(BaseReg || IndexReg || RegNo)) return X86Operand::CreateMem(getPointerWidth(), Disp, Start, End, Size); return X86Operand::CreateMem(getPointerWidth(), RegNo, Disp, BaseReg, IndexReg, Scale, Start, End, Size); } std::unique_ptr X86AsmParser::ParseATTOperand() { MCAsmParser &Parser = getParser(); switch (getLexer().getKind()) { default: // Parse a memory operand with no segment register. return ParseMemOperand(0, Parser.getTok().getLoc()); case AsmToken::Percent: { // Read the register. unsigned RegNo; SMLoc Start, End; if (ParseRegister(RegNo, Start, End)) return nullptr; if (RegNo == X86::EIZ || RegNo == X86::RIZ) { Error(Start, "%eiz and %riz can only be used as index registers", SMRange(Start, End)); return nullptr; } if (RegNo == X86::RIP) { Error(Start, "%rip can only be used as a base register", SMRange(Start, End)); return nullptr; } // If this is a segment register followed by a ':', then this is the start // of a memory reference, otherwise this is a normal register reference. if (getLexer().isNot(AsmToken::Colon)) return X86Operand::CreateReg(RegNo, Start, End); if (!X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo)) return ErrorOperand(Start, "invalid segment register"); getParser().Lex(); // Eat the colon. return ParseMemOperand(RegNo, Start); } case AsmToken::Dollar: { // $42 -> immediate. SMLoc Start = Parser.getTok().getLoc(), End; Parser.Lex(); const MCExpr *Val; if (getParser().parseExpression(Val, End)) return nullptr; return X86Operand::CreateImm(Val, Start, End); } case AsmToken::LCurly:{ SMLoc Start = Parser.getTok().getLoc(); return ParseRoundingModeOp(Start); } } } // true on failure, false otherwise // If no {z} mark was found - Parser doesn't advance bool X86AsmParser::ParseZ(std::unique_ptr &Z, const SMLoc &StartLoc) { MCAsmParser &Parser = getParser(); // Assuming we are just pass the '{' mark, quering the next token // Searched for {z}, but none was found. Return false, as no parsing error was // encountered if (!(getLexer().is(AsmToken::Identifier) && (getLexer().getTok().getIdentifier() == "z"))) return false; Parser.Lex(); // Eat z // Query and eat the '}' mark if (!getLexer().is(AsmToken::RCurly)) return Error(getLexer().getLoc(), "Expected } at this point"); Parser.Lex(); // Eat '}' // Assign Z with the {z} mark opernad Z = X86Operand::CreateToken("{z}", StartLoc); return false; } // true on failure, false otherwise bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands, const MCParsedAsmOperand &Op) { MCAsmParser &Parser = getParser(); if (getLexer().is(AsmToken::LCurly)) { // Eat "{" and mark the current place. const SMLoc consumedToken = consumeToken(); // Distinguish {1to} from {%k}. if(getLexer().is(AsmToken::Integer)) { // Parse memory broadcasting ({1to}). if (getLexer().getTok().getIntVal() != 1) return TokError("Expected 1to at this point"); Parser.Lex(); // Eat "1" of 1to8 if (!getLexer().is(AsmToken::Identifier) || !getLexer().getTok().getIdentifier().startswith("to")) return TokError("Expected 1to at this point"); // Recognize only reasonable suffixes. const char *BroadcastPrimitive = StringSwitch(getLexer().getTok().getIdentifier()) .Case("to2", "{1to2}") .Case("to4", "{1to4}") .Case("to8", "{1to8}") .Case("to16", "{1to16}") .Default(nullptr); if (!BroadcastPrimitive) return TokError("Invalid memory broadcast primitive."); Parser.Lex(); // Eat "toN" of 1toN if (!getLexer().is(AsmToken::RCurly)) return TokError("Expected } at this point"); Parser.Lex(); // Eat "}" Operands.push_back(X86Operand::CreateToken(BroadcastPrimitive, consumedToken)); // No AVX512 specific primitives can pass // after memory broadcasting, so return. return false; } else { // Parse either {k}{z}, {z}{k}, {k} or {z} // last one have no meaning, but GCC accepts it // Currently, we're just pass a '{' mark std::unique_ptr Z; if (ParseZ(Z, consumedToken)) return true; // Reaching here means that parsing of the allegadly '{z}' mark yielded // no errors. // Query for the need of further parsing for a {%k} mark if (!Z || getLexer().is(AsmToken::LCurly)) { SMLoc StartLoc = Z ? consumeToken() : consumedToken; // Parse an op-mask register mark ({%k}), which is now to be // expected unsigned RegNo; SMLoc RegLoc; if (!ParseRegister(RegNo, RegLoc, StartLoc) && X86MCRegisterClasses[X86::VK1RegClassID].contains(RegNo)) { if (RegNo == X86::K0) return Error(RegLoc, "Register k0 can't be used as write mask"); if (!getLexer().is(AsmToken::RCurly)) return Error(getLexer().getLoc(), "Expected } at this point"); Operands.push_back(X86Operand::CreateToken("{", StartLoc)); Operands.push_back( X86Operand::CreateReg(RegNo, StartLoc, StartLoc)); Operands.push_back(X86Operand::CreateToken("}", consumeToken())); } else return Error(getLexer().getLoc(), "Expected an op-mask register at this point"); // {%k} mark is found, inquire for {z} if (getLexer().is(AsmToken::LCurly) && !Z) { // Have we've found a parsing error, or found no (expected) {z} mark // - report an error if (ParseZ(Z, consumeToken()) || !Z) return Error(getLexer().getLoc(), "Expected a {z} mark at this point"); } // '{z}' on its own is meaningless, hence should be ignored. // on the contrary - have it been accompanied by a K register, // allow it. if (Z) Operands.push_back(std::move(Z)); } } } return false; } /// ParseMemOperand: segment: disp(basereg, indexreg, scale). The '%ds:' prefix /// has already been parsed if present. std::unique_ptr X86AsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { MCAsmParser &Parser = getParser(); // We have to disambiguate a parenthesized expression "(4+5)" from the start // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)". The // only way to do this without lookahead is to eat the '(' and see what is // after it. const MCExpr *Disp = MCConstantExpr::create(0, getParser().getContext()); if (getLexer().isNot(AsmToken::LParen)) { SMLoc ExprEnd; if (getParser().parseExpression(Disp, ExprEnd)) return nullptr; // Disp may be a variable, handle register values. if (auto *RE = dyn_cast(Disp)) return X86Operand::CreateReg(RE->getRegNo(), MemStart, ExprEnd); // After parsing the base expression we could either have a parenthesized // memory address or not. If not, return now. If so, eat the (. if (getLexer().isNot(AsmToken::LParen)) { // Unless we have a segment register, treat this as an immediate. if (SegReg == 0) return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, ExprEnd); return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, 0, 0, 1, MemStart, ExprEnd); } // Eat the '('. Parser.Lex(); } else { // Okay, we have a '('. We don't know if this is an expression or not, but // so we have to eat the ( to see beyond it. SMLoc LParenLoc = Parser.getTok().getLoc(); Parser.Lex(); // Eat the '('. if (getLexer().is(AsmToken::Percent) || getLexer().is(AsmToken::Comma)) { // Nothing to do here, fall into the code below with the '(' part of the // memory operand consumed. } else { SMLoc ExprEnd; getLexer().UnLex(AsmToken(AsmToken::LParen, "(")); // It must be either an parenthesized expression, or an expression that // begins from a parenthesized expression, parse it now. Example: (1+2) or // (1+2)+3 if (getParser().parseExpression(Disp, ExprEnd)) return nullptr; // After parsing the base expression we could either have a parenthesized // memory address or not. If not, return now. If so, eat the (. if (getLexer().isNot(AsmToken::LParen)) { // Unless we have a segment register, treat this as an immediate. if (SegReg == 0) return X86Operand::CreateMem(getPointerWidth(), Disp, LParenLoc, ExprEnd); return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, 0, 0, 1, MemStart, ExprEnd); } // Eat the '('. Parser.Lex(); } } // If we reached here, then we just ate the ( of the memory operand. Process // the rest of the memory operand. unsigned BaseReg = 0, IndexReg = 0, Scale = 1; SMLoc IndexLoc, BaseLoc; if (getLexer().is(AsmToken::Percent)) { SMLoc StartLoc, EndLoc; BaseLoc = Parser.getTok().getLoc(); if (ParseRegister(BaseReg, StartLoc, EndLoc)) return nullptr; if (BaseReg == X86::EIZ || BaseReg == X86::RIZ) { Error(StartLoc, "eiz and riz can only be used as index registers", SMRange(StartLoc, EndLoc)); return nullptr; } } if (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. IndexLoc = Parser.getTok().getLoc(); // Following the comma we should have either an index register, or a scale // value. We don't support the later form, but we want to parse it // correctly. // // Not that even though it would be completely consistent to support syntax // like "1(%eax,,1)", the assembler doesn't. Use "eiz" or "riz" for this. if (getLexer().is(AsmToken::Percent)) { SMLoc L; if (ParseRegister(IndexReg, L, L)) return nullptr; if (BaseReg == X86::RIP) { Error(IndexLoc, "%rip as base register can not have an index register"); return nullptr; } if (IndexReg == X86::RIP) { Error(IndexLoc, "%rip is not allowed as an index register"); return nullptr; } if (getLexer().isNot(AsmToken::RParen)) { // Parse the scale amount: // ::= ',' [scale-expression] if (parseToken(AsmToken::Comma, "expected comma in scale expression")) return nullptr; if (getLexer().isNot(AsmToken::RParen)) { SMLoc Loc = Parser.getTok().getLoc(); int64_t ScaleVal; if (getParser().parseAbsoluteExpression(ScaleVal)){ Error(Loc, "expected scale expression"); return nullptr; } // Validate the scale amount. if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) && ScaleVal != 1) { Error(Loc, "scale factor in 16-bit address must be 1"); return nullptr; } if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8) { Error(Loc, "scale factor in address must be 1, 2, 4 or 8"); return nullptr; } Scale = (unsigned)ScaleVal; } } } else if (getLexer().isNot(AsmToken::RParen)) { // A scale amount without an index is ignored. // index. SMLoc Loc = Parser.getTok().getLoc(); int64_t Value; if (getParser().parseAbsoluteExpression(Value)) return nullptr; if (Value != 1) Warning(Loc, "scale factor without index register is ignored"); Scale = 1; } } // Ok, we've eaten the memory operand, verify we have a ')' and eat it too. SMLoc MemEnd = Parser.getTok().getEndLoc(); if (parseToken(AsmToken::RParen, "unexpected token in memory operand")) return nullptr; // This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" -> // "outb %al, %dx". Out doesn't take a memory form, but this is a widely // documented form in various unofficial manuals, so a lot of code uses it. if (BaseReg == X86::DX && IndexReg == 0 && Scale == 1 && SegReg == 0 && isa(Disp) && cast(Disp)->getValue() == 0) return X86Operand::CreateDXReg(BaseLoc, BaseLoc); StringRef ErrMsg; if (CheckBaseRegAndIndexRegAndScale(BaseReg, IndexReg, Scale, is64BitMode(), ErrMsg)) { Error(BaseLoc, ErrMsg); return nullptr; } if (SegReg || BaseReg || IndexReg) return X86Operand::CreateMem(getPointerWidth(), SegReg, Disp, BaseReg, IndexReg, Scale, MemStart, MemEnd); return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, MemEnd); } -// Parse either a standard expression or a register. -bool X86AsmParser::parseAssignmentExpression(const MCExpr *&Res, - SMLoc &EndLoc) { +// Parse either a standard primary expression or a register. +bool X86AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { MCAsmParser &Parser = getParser(); - if (Parser.parseExpression(Res, EndLoc)) { + if (Parser.parsePrimaryExpr(Res, EndLoc)) { SMLoc StartLoc = Parser.getTok().getLoc(); // Normal Expression parse fails, check if it could be a register. unsigned RegNo; - if (Parser.getTargetParser().ParseRegister(RegNo, StartLoc, EndLoc)) + bool TryRegParse = + getTok().is(AsmToken::Percent) || + (isParsingIntelSyntax() && getTok().is(AsmToken::Identifier)); + if (!TryRegParse || ParseRegister(RegNo, StartLoc, EndLoc)) return true; // Clear previous parse error and return correct expression. Parser.clearPendingErrors(); Res = X86MCExpr::create(RegNo, Parser.getContext()); return false; } return false; } bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { MCAsmParser &Parser = getParser(); InstInfo = &Info; StringRef PatchedName = Name; if ((Name.equals("jmp") || Name.equals("jc") || Name.equals("jz")) && isParsingIntelSyntax() && isParsingInlineAsm()) { StringRef NextTok = Parser.getTok().getString(); if (NextTok == "short") { SMLoc NameEndLoc = NameLoc.getFromPointer(NameLoc.getPointer() + Name.size()); // Eat the short keyword Parser.Lex(); // MS ignores the short keyword, it determines the jmp type based // on the distance of the label InstInfo->AsmRewrites->emplace_back(AOK_Skip, NameEndLoc, NextTok.size() + 1); } } // FIXME: Hack to recognize setneb as setne. if (PatchedName.startswith("set") && PatchedName.endswith("b") && PatchedName != "setb" && PatchedName != "setnb") PatchedName = PatchedName.substr(0, Name.size()-1); // FIXME: Hack to recognize cmp{ss,sd,ps,pd}. if ((PatchedName.startswith("cmp") || PatchedName.startswith("vcmp")) && (PatchedName.endswith("ss") || PatchedName.endswith("sd") || PatchedName.endswith("ps") || PatchedName.endswith("pd"))) { bool IsVCMP = PatchedName[0] == 'v'; unsigned CCIdx = IsVCMP ? 4 : 3; unsigned ComparisonCode = StringSwitch( PatchedName.slice(CCIdx, PatchedName.size() - 2)) .Case("eq", 0x00) .Case("eq_oq", 0x00) .Case("lt", 0x01) .Case("lt_os", 0x01) .Case("le", 0x02) .Case("le_os", 0x02) .Case("unord", 0x03) .Case("unord_q", 0x03) .Case("neq", 0x04) .Case("neq_uq", 0x04) .Case("nlt", 0x05) .Case("nlt_us", 0x05) .Case("nle", 0x06) .Case("nle_us", 0x06) .Case("ord", 0x07) .Case("ord_q", 0x07) /* AVX only from here */ .Case("eq_uq", 0x08) .Case("nge", 0x09) .Case("nge_us", 0x09) .Case("ngt", 0x0A) .Case("ngt_us", 0x0A) .Case("false", 0x0B) .Case("false_oq", 0x0B) .Case("neq_oq", 0x0C) .Case("ge", 0x0D) .Case("ge_os", 0x0D) .Case("gt", 0x0E) .Case("gt_os", 0x0E) .Case("true", 0x0F) .Case("true_uq", 0x0F) .Case("eq_os", 0x10) .Case("lt_oq", 0x11) .Case("le_oq", 0x12) .Case("unord_s", 0x13) .Case("neq_us", 0x14) .Case("nlt_uq", 0x15) .Case("nle_uq", 0x16) .Case("ord_s", 0x17) .Case("eq_us", 0x18) .Case("nge_uq", 0x19) .Case("ngt_uq", 0x1A) .Case("false_os", 0x1B) .Case("neq_os", 0x1C) .Case("ge_oq", 0x1D) .Case("gt_oq", 0x1E) .Case("true_us", 0x1F) .Default(~0U); if (ComparisonCode != ~0U && (IsVCMP || ComparisonCode < 8)) { Operands.push_back(X86Operand::CreateToken(PatchedName.slice(0, CCIdx), NameLoc)); const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode, getParser().getContext()); Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc)); PatchedName = PatchedName.substr(PatchedName.size() - 2); } } // FIXME: Hack to recognize vpcmp{ub,uw,ud,uq,b,w,d,q}. if (PatchedName.startswith("vpcmp") && (PatchedName.endswith("b") || PatchedName.endswith("w") || PatchedName.endswith("d") || PatchedName.endswith("q"))) { unsigned CCIdx = PatchedName.drop_back().back() == 'u' ? 2 : 1; unsigned ComparisonCode = StringSwitch( PatchedName.slice(5, PatchedName.size() - CCIdx)) .Case("eq", 0x0) // Only allowed on unsigned. Checked below. .Case("lt", 0x1) .Case("le", 0x2) //.Case("false", 0x3) // Not a documented alias. .Case("neq", 0x4) .Case("nlt", 0x5) .Case("nle", 0x6) //.Case("true", 0x7) // Not a documented alias. .Default(~0U); if (ComparisonCode != ~0U && (ComparisonCode != 0 || CCIdx == 2)) { Operands.push_back(X86Operand::CreateToken("vpcmp", NameLoc)); const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode, getParser().getContext()); Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc)); PatchedName = PatchedName.substr(PatchedName.size() - CCIdx); } } // FIXME: Hack to recognize vpcom{ub,uw,ud,uq,b,w,d,q}. if (PatchedName.startswith("vpcom") && (PatchedName.endswith("b") || PatchedName.endswith("w") || PatchedName.endswith("d") || PatchedName.endswith("q"))) { unsigned CCIdx = PatchedName.drop_back().back() == 'u' ? 2 : 1; unsigned ComparisonCode = StringSwitch( PatchedName.slice(5, PatchedName.size() - CCIdx)) .Case("lt", 0x0) .Case("le", 0x1) .Case("gt", 0x2) .Case("ge", 0x3) .Case("eq", 0x4) .Case("neq", 0x5) .Case("false", 0x6) .Case("true", 0x7) .Default(~0U); if (ComparisonCode != ~0U) { Operands.push_back(X86Operand::CreateToken("vpcom", NameLoc)); const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode, getParser().getContext()); Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc)); PatchedName = PatchedName.substr(PatchedName.size() - CCIdx); } } // Determine whether this is an instruction prefix. // FIXME: // Enhance prefixes integrity robustness. for example, following forms // are currently tolerated: // repz repnz ; GAS errors for the use of two similar prefixes // lock addq %rax, %rbx ; Destination operand must be of memory type // xacquire ; xacquire must be accompanied by 'lock' bool isPrefix = StringSwitch(Name) .Cases("rex64", "data32", "data16", true) .Cases("xacquire", "xrelease", true) .Cases("acquire", "release", isParsingIntelSyntax()) .Default(false); auto isLockRepeatNtPrefix = [](StringRef N) { return StringSwitch(N) .Cases("lock", "rep", "repe", "repz", "repne", "repnz", "notrack", true) .Default(false); }; bool CurlyAsEndOfStatement = false; unsigned Flags = X86::IP_NO_PREFIX; while (isLockRepeatNtPrefix(Name.lower())) { unsigned Prefix = StringSwitch(Name) .Cases("lock", "lock", X86::IP_HAS_LOCK) .Cases("rep", "repe", "repz", X86::IP_HAS_REPEAT) .Cases("repne", "repnz", X86::IP_HAS_REPEAT_NE) .Cases("notrack", "notrack", X86::IP_HAS_NOTRACK) .Default(X86::IP_NO_PREFIX); // Invalid prefix (impossible) Flags |= Prefix; if (getLexer().is(AsmToken::EndOfStatement)) { // We don't have real instr with the given prefix // let's use the prefix as the instr. // TODO: there could be several prefixes one after another Flags = X86::IP_NO_PREFIX; break; } Name = Parser.getTok().getString(); Parser.Lex(); // eat the prefix // Hack: we could have something like "rep # some comment" or // "lock; cmpxchg16b $1" or "lock\0A\09incl" or "lock/incl" while (Name.startswith(";") || Name.startswith("\n") || Name.startswith("#") || Name.startswith("\t") || Name.startswith("/")) { Name = Parser.getTok().getString(); Parser.Lex(); // go to next prefix or instr } } if (Flags) PatchedName = Name; // Hacks to handle 'data16' and 'data32' if (PatchedName == "data16" && is16BitMode()) { return Error(NameLoc, "redundant data16 prefix"); } if (PatchedName == "data32") { if (is32BitMode()) return Error(NameLoc, "redundant data32 prefix"); if (is64BitMode()) return Error(NameLoc, "'data32' is not supported in 64-bit mode"); // Hack to 'data16' for the table lookup. PatchedName = "data16"; } Operands.push_back(X86Operand::CreateToken(PatchedName, NameLoc)); // This does the actual operand parsing. Don't parse any more if we have a // prefix juxtaposed with an operation like "lock incl 4(%rax)", because we // just want to parse the "lock" as the first instruction and the "incl" as // the next one. if (getLexer().isNot(AsmToken::EndOfStatement) && !isPrefix) { // Parse '*' modifier. if (getLexer().is(AsmToken::Star)) Operands.push_back(X86Operand::CreateToken("*", consumeToken())); // Read the operands. while(1) { if (std::unique_ptr Op = ParseOperand()) { Operands.push_back(std::move(Op)); if (HandleAVX512Operand(Operands, *Operands.back())) return true; } else { return true; } // check for comma and eat it if (getLexer().is(AsmToken::Comma)) Parser.Lex(); else break; } // In MS inline asm curly braces mark the beginning/end of a block, // therefore they should be interepreted as end of statement CurlyAsEndOfStatement = isParsingIntelSyntax() && isParsingInlineAsm() && (getLexer().is(AsmToken::LCurly) || getLexer().is(AsmToken::RCurly)); if (getLexer().isNot(AsmToken::EndOfStatement) && !CurlyAsEndOfStatement) return TokError("unexpected token in argument list"); } // Consume the EndOfStatement or the prefix separator Slash if (getLexer().is(AsmToken::EndOfStatement) || (isPrefix && getLexer().is(AsmToken::Slash))) Parser.Lex(); else if (CurlyAsEndOfStatement) // Add an actual EndOfStatement before the curly brace Info.AsmRewrites->emplace_back(AOK_EndOfStatement, getLexer().getTok().getLoc(), 0); // This is for gas compatibility and cannot be done in td. // Adding "p" for some floating point with no argument. // For example: fsub --> fsubp bool IsFp = Name == "fsub" || Name == "fdiv" || Name == "fsubr" || Name == "fdivr"; if (IsFp && Operands.size() == 1) { const char *Repl = StringSwitch(Name) .Case("fsub", "fsubp") .Case("fdiv", "fdivp") .Case("fsubr", "fsubrp") .Case("fdivr", "fdivrp"); static_cast(*Operands[0]).setTokenValue(Repl); } // Moving a 32 or 16 bit value into a segment register has the same // behavior. Modify such instructions to always take shorter form. if ((Name == "mov" || Name == "movw" || Name == "movl") && (Operands.size() == 3)) { X86Operand &Op1 = (X86Operand &)*Operands[1]; X86Operand &Op2 = (X86Operand &)*Operands[2]; SMLoc Loc = Op1.getEndLoc(); if (Op1.isReg() && Op2.isReg() && X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains( Op2.getReg()) && (X86MCRegisterClasses[X86::GR16RegClassID].contains(Op1.getReg()) || X86MCRegisterClasses[X86::GR32RegClassID].contains(Op1.getReg()))) { // Change instruction name to match new instruction. if (Name != "mov" && Name[3] == (is16BitMode() ? 'l' : 'w')) { Name = is16BitMode() ? "movw" : "movl"; Operands[0] = X86Operand::CreateToken(Name, NameLoc); } // Select the correct equivalent 16-/32-bit source register. unsigned Reg = getX86SubSuperRegisterOrZero(Op1.getReg(), is16BitMode() ? 16 : 32); Operands[1] = X86Operand::CreateReg(Reg, Loc, Loc); } } // This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" -> // "outb %al, %dx". Out doesn't take a memory form, but this is a widely // documented form in various unofficial manuals, so a lot of code uses it. if ((Name == "outb" || Name == "outsb" || Name == "outw" || Name == "outsw" || Name == "outl" || Name == "outsl" || Name == "out" || Name == "outs") && Operands.size() == 3) { X86Operand &Op = (X86Operand &)*Operands.back(); if (Op.isDXReg()) Operands.back() = X86Operand::CreateReg(X86::DX, Op.getStartLoc(), Op.getEndLoc()); } // Same hack for "in[s]?[bwl]? (%dx), %al" -> "inb %dx, %al". if ((Name == "inb" || Name == "insb" || Name == "inw" || Name == "insw" || Name == "inl" || Name == "insl" || Name == "in" || Name == "ins") && Operands.size() == 3) { X86Operand &Op = (X86Operand &)*Operands[1]; if (Op.isDXReg()) Operands[1] = X86Operand::CreateReg(X86::DX, Op.getStartLoc(), Op.getEndLoc()); } SmallVector, 2> TmpOperands; bool HadVerifyError = false; // Append default arguments to "ins[bwld]" if (Name.startswith("ins") && (Operands.size() == 1 || Operands.size() == 3) && (Name == "insb" || Name == "insw" || Name == "insl" || Name == "insd" || Name == "ins")) { AddDefaultSrcDestOperands(TmpOperands, X86Operand::CreateReg(X86::DX, NameLoc, NameLoc), DefaultMemDIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Append default arguments to "outs[bwld]" if (Name.startswith("outs") && (Operands.size() == 1 || Operands.size() == 3) && (Name == "outsb" || Name == "outsw" || Name == "outsl" || Name == "outsd" || Name == "outs")) { AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc), X86Operand::CreateReg(X86::DX, NameLoc, NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Transform "lods[bwlq]" into "lods[bwlq] ($SIREG)" for appropriate // values of $SIREG according to the mode. It would be nice if this // could be achieved with InstAlias in the tables. if (Name.startswith("lods") && (Operands.size() == 1 || Operands.size() == 2) && (Name == "lods" || Name == "lodsb" || Name == "lodsw" || Name == "lodsl" || Name == "lodsd" || Name == "lodsq")) { TmpOperands.push_back(DefaultMemSIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Transform "stos[bwlq]" into "stos[bwlq] ($DIREG)" for appropriate // values of $DIREG according to the mode. It would be nice if this // could be achieved with InstAlias in the tables. if (Name.startswith("stos") && (Operands.size() == 1 || Operands.size() == 2) && (Name == "stos" || Name == "stosb" || Name == "stosw" || Name == "stosl" || Name == "stosd" || Name == "stosq")) { TmpOperands.push_back(DefaultMemDIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Transform "scas[bwlq]" into "scas[bwlq] ($DIREG)" for appropriate // values of $DIREG according to the mode. It would be nice if this // could be achieved with InstAlias in the tables. if (Name.startswith("scas") && (Operands.size() == 1 || Operands.size() == 2) && (Name == "scas" || Name == "scasb" || Name == "scasw" || Name == "scasl" || Name == "scasd" || Name == "scasq")) { TmpOperands.push_back(DefaultMemDIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Add default SI and DI operands to "cmps[bwlq]". if (Name.startswith("cmps") && (Operands.size() == 1 || Operands.size() == 3) && (Name == "cmps" || Name == "cmpsb" || Name == "cmpsw" || Name == "cmpsl" || Name == "cmpsd" || Name == "cmpsq")) { AddDefaultSrcDestOperands(TmpOperands, DefaultMemDIOperand(NameLoc), DefaultMemSIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Add default SI and DI operands to "movs[bwlq]". if (((Name.startswith("movs") && (Name == "movs" || Name == "movsb" || Name == "movsw" || Name == "movsl" || Name == "movsd" || Name == "movsq")) || (Name.startswith("smov") && (Name == "smov" || Name == "smovb" || Name == "smovw" || Name == "smovl" || Name == "smovd" || Name == "smovq"))) && (Operands.size() == 1 || Operands.size() == 3)) { if (Name == "movsd" && Operands.size() == 1 && !isParsingIntelSyntax()) Operands.back() = X86Operand::CreateToken("movsl", NameLoc); AddDefaultSrcDestOperands(TmpOperands, DefaultMemSIOperand(NameLoc), DefaultMemDIOperand(NameLoc)); HadVerifyError = VerifyAndAdjustOperands(Operands, TmpOperands); } // Check if we encountered an error for one the string insturctions if (HadVerifyError) { return HadVerifyError; } // FIXME: Hack to handle recognize s{hr,ar,hl} $1, . Canonicalize to // "shift ". if ((Name.startswith("shr") || Name.startswith("sar") || Name.startswith("shl") || Name.startswith("sal") || Name.startswith("rcl") || Name.startswith("rcr") || Name.startswith("rol") || Name.startswith("ror")) && Operands.size() == 3) { if (isParsingIntelSyntax()) { // Intel syntax X86Operand &Op1 = static_cast(*Operands[2]); if (Op1.isImm() && isa(Op1.getImm()) && cast(Op1.getImm())->getValue() == 1) Operands.pop_back(); } else { X86Operand &Op1 = static_cast(*Operands[1]); if (Op1.isImm() && isa(Op1.getImm()) && cast(Op1.getImm())->getValue() == 1) Operands.erase(Operands.begin() + 1); } } // Transforms "int $3" into "int3" as a size optimization. We can't write an // instalias with an immediate operand yet. if (Name == "int" && Operands.size() == 2) { X86Operand &Op1 = static_cast(*Operands[1]); if (Op1.isImm()) if (auto *CE = dyn_cast(Op1.getImm())) if (CE->getValue() == 3) { Operands.erase(Operands.begin() + 1); static_cast(*Operands[0]).setTokenValue("int3"); } } // Transforms "xlat mem8" into "xlatb" if ((Name == "xlat" || Name == "xlatb") && Operands.size() == 2) { X86Operand &Op1 = static_cast(*Operands[1]); if (Op1.isMem8()) { Warning(Op1.getStartLoc(), "memory operand is only for determining the " "size, (R|E)BX will be used for the location"); Operands.pop_back(); static_cast(*Operands[0]).setTokenValue("xlatb"); } } if (Flags) Operands.push_back(X86Operand::CreatePrefix(Flags, NameLoc, NameLoc)); return false; } bool X86AsmParser::processInstruction(MCInst &Inst, const OperandVector &Ops) { return false; } bool X86AsmParser::validateInstruction(MCInst &Inst, const OperandVector &Ops) { const MCRegisterInfo *MRI = getContext().getRegisterInfo(); switch (Inst.getOpcode()) { case X86::VGATHERDPDYrm: case X86::VGATHERDPDrm: case X86::VGATHERDPSYrm: case X86::VGATHERDPSrm: case X86::VGATHERQPDYrm: case X86::VGATHERQPDrm: case X86::VGATHERQPSYrm: case X86::VGATHERQPSrm: case X86::VPGATHERDDYrm: case X86::VPGATHERDDrm: case X86::VPGATHERDQYrm: case X86::VPGATHERDQrm: case X86::VPGATHERQDYrm: case X86::VPGATHERQDrm: case X86::VPGATHERQQYrm: case X86::VPGATHERQQrm: { unsigned Dest = MRI->getEncodingValue(Inst.getOperand(0).getReg()); unsigned Mask = MRI->getEncodingValue(Inst.getOperand(1).getReg()); unsigned Index = MRI->getEncodingValue(Inst.getOperand(3 + X86::AddrIndexReg).getReg()); if (Dest == Mask || Dest == Index || Mask == Index) return Warning(Ops[0]->getStartLoc(), "mask, index, and destination " "registers should be distinct"); break; } case X86::VGATHERDPDZ128rm: case X86::VGATHERDPDZ256rm: case X86::VGATHERDPDZrm: case X86::VGATHERDPSZ128rm: case X86::VGATHERDPSZ256rm: case X86::VGATHERDPSZrm: case X86::VGATHERQPDZ128rm: case X86::VGATHERQPDZ256rm: case X86::VGATHERQPDZrm: case X86::VGATHERQPSZ128rm: case X86::VGATHERQPSZ256rm: case X86::VGATHERQPSZrm: case X86::VPGATHERDDZ128rm: case X86::VPGATHERDDZ256rm: case X86::VPGATHERDDZrm: case X86::VPGATHERDQZ128rm: case X86::VPGATHERDQZ256rm: case X86::VPGATHERDQZrm: case X86::VPGATHERQDZ128rm: case X86::VPGATHERQDZ256rm: case X86::VPGATHERQDZrm: case X86::VPGATHERQQZ128rm: case X86::VPGATHERQQZ256rm: case X86::VPGATHERQQZrm: { unsigned Dest = MRI->getEncodingValue(Inst.getOperand(0).getReg()); unsigned Index = MRI->getEncodingValue(Inst.getOperand(4 + X86::AddrIndexReg).getReg()); if (Dest == Index) return Warning(Ops[0]->getStartLoc(), "index and destination registers " "should be distinct"); break; } case X86::V4FMADDPSrm: case X86::V4FMADDPSrmk: case X86::V4FMADDPSrmkz: case X86::V4FMADDSSrm: case X86::V4FMADDSSrmk: case X86::V4FMADDSSrmkz: case X86::V4FNMADDPSrm: case X86::V4FNMADDPSrmk: case X86::V4FNMADDPSrmkz: case X86::V4FNMADDSSrm: case X86::V4FNMADDSSrmk: case X86::V4FNMADDSSrmkz: case X86::VP4DPWSSDSrm: case X86::VP4DPWSSDSrmk: case X86::VP4DPWSSDSrmkz: case X86::VP4DPWSSDrm: case X86::VP4DPWSSDrmk: case X86::VP4DPWSSDrmkz: { unsigned Src2 = Inst.getOperand(Inst.getNumOperands() - X86::AddrNumOperands - 1).getReg(); unsigned Src2Enc = MRI->getEncodingValue(Src2); if (Src2Enc % 4 != 0) { StringRef RegName = X86IntelInstPrinter::getRegisterName(Src2); unsigned GroupStart = (Src2Enc / 4) * 4; unsigned GroupEnd = GroupStart + 3; return Warning(Ops[0]->getStartLoc(), "source register '" + RegName + "' implicitly denotes '" + RegName.take_front(3) + Twine(GroupStart) + "' to '" + RegName.take_front(3) + Twine(GroupEnd) + "' source group"); } break; } } return false; } static const char *getSubtargetFeatureName(uint64_t Val); void X86AsmParser::EmitInstruction(MCInst &Inst, OperandVector &Operands, MCStreamer &Out) { Instrumentation->InstrumentAndEmitInstruction( Inst, Operands, getContext(), MII, Out, getParser().shouldPrintSchedInfo()); } bool X86AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { if (isParsingIntelSyntax()) return MatchAndEmitIntelInstruction(IDLoc, Opcode, Operands, Out, ErrorInfo, MatchingInlineAsm); return MatchAndEmitATTInstruction(IDLoc, Opcode, Operands, Out, ErrorInfo, MatchingInlineAsm); } void X86AsmParser::MatchFPUWaitAlias(SMLoc IDLoc, X86Operand &Op, OperandVector &Operands, MCStreamer &Out, bool MatchingInlineAsm) { // FIXME: This should be replaced with a real .td file alias mechanism. // Also, MatchInstructionImpl should actually *do* the EmitInstruction // call. const char *Repl = StringSwitch(Op.getToken()) .Case("finit", "fninit") .Case("fsave", "fnsave") .Case("fstcw", "fnstcw") .Case("fstcww", "fnstcw") .Case("fstenv", "fnstenv") .Case("fstsw", "fnstsw") .Case("fstsww", "fnstsw") .Case("fclex", "fnclex") .Default(nullptr); if (Repl) { MCInst Inst; Inst.setOpcode(X86::WAIT); Inst.setLoc(IDLoc); if (!MatchingInlineAsm) EmitInstruction(Inst, Operands, Out); Operands[0] = X86Operand::CreateToken(Repl, IDLoc); } } bool X86AsmParser::ErrorMissingFeature(SMLoc IDLoc, uint64_t ErrorInfo, bool MatchingInlineAsm) { assert(ErrorInfo && "Unknown missing feature!"); SmallString<126> Msg; raw_svector_ostream OS(Msg); OS << "instruction requires:"; uint64_t Mask = 1; for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) { if (ErrorInfo & Mask) OS << ' ' << getSubtargetFeatureName(ErrorInfo & Mask); Mask <<= 1; } return Error(IDLoc, OS.str(), SMRange(), MatchingInlineAsm); } static unsigned getPrefixes(OperandVector &Operands) { unsigned Result = 0; X86Operand &Prefix = static_cast(*Operands.back()); if (Prefix.isPrefix()) { Result = Prefix.getPrefix(); Operands.pop_back(); } return Result; } bool X86AsmParser::MatchAndEmitATTInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { assert(!Operands.empty() && "Unexpect empty operand list!"); X86Operand &Op = static_cast(*Operands[0]); assert(Op.isToken() && "Leading operand should always be a mnemonic!"); SMRange EmptyRange = None; // First, handle aliases that expand to multiple instructions. MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm); bool WasOriginallyInvalidOperand = false; unsigned Prefixes = getPrefixes(Operands); MCInst Inst; if (Prefixes) Inst.setFlags(Prefixes); // First, try a direct match. switch (MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax())) { default: llvm_unreachable("Unexpected match result!"); case Match_Success: if (!MatchingInlineAsm && validateInstruction(Inst, Operands)) return true; // Some instructions need post-processing to, for example, tweak which // encoding is selected. Loop on it while changes happen so the // individual transformations can chain off each other. if (!MatchingInlineAsm) while (processInstruction(Inst, Operands)) ; Inst.setLoc(IDLoc); if (!MatchingInlineAsm) EmitInstruction(Inst, Operands, Out); Opcode = Inst.getOpcode(); return false; case Match_MissingFeature: return ErrorMissingFeature(IDLoc, ErrorInfo, MatchingInlineAsm); case Match_InvalidOperand: WasOriginallyInvalidOperand = true; break; case Match_MnemonicFail: break; } // FIXME: Ideally, we would only attempt suffix matches for things which are // valid prefixes, and we could just infer the right unambiguous // type. However, that requires substantially more matcher support than the // following hack. // Change the operand to point to a temporary token. StringRef Base = Op.getToken(); SmallString<16> Tmp; Tmp += Base; Tmp += ' '; Op.setTokenValue(Tmp); // If this instruction starts with an 'f', then it is a floating point stack // instruction. These come in up to three forms for 32-bit, 64-bit, and // 80-bit floating point, which use the suffixes s,l,t respectively. // // Otherwise, we assume that this may be an integer instruction, which comes // in 8/16/32/64-bit forms using the b,w,l,q suffixes respectively. const char *Suffixes = Base[0] != 'f' ? "bwlq" : "slt\0"; // Check for the various suffix matches. uint64_t ErrorInfoIgnore; uint64_t ErrorInfoMissingFeature = 0; // Init suppresses compiler warnings. unsigned Match[4]; for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) { Tmp.back() = Suffixes[I]; Match[I] = MatchInstruction(Operands, Inst, ErrorInfoIgnore, MatchingInlineAsm, isParsingIntelSyntax()); // If this returned as a missing feature failure, remember that. if (Match[I] == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; } // Restore the old token. Op.setTokenValue(Base); // If exactly one matched, then we treat that as a successful match (and the // instruction will already have been filled in correctly, since the failing // matches won't have modified it). unsigned NumSuccessfulMatches = std::count(std::begin(Match), std::end(Match), Match_Success); if (NumSuccessfulMatches == 1) { Inst.setLoc(IDLoc); if (!MatchingInlineAsm) EmitInstruction(Inst, Operands, Out); Opcode = Inst.getOpcode(); return false; } // Otherwise, the match failed, try to produce a decent error message. // If we had multiple suffix matches, then identify this as an ambiguous // match. if (NumSuccessfulMatches > 1) { char MatchChars[4]; unsigned NumMatches = 0; for (unsigned I = 0, E = array_lengthof(Match); I != E; ++I) if (Match[I] == Match_Success) MatchChars[NumMatches++] = Suffixes[I]; SmallString<126> Msg; raw_svector_ostream OS(Msg); OS << "ambiguous instructions require an explicit suffix (could be "; for (unsigned i = 0; i != NumMatches; ++i) { if (i != 0) OS << ", "; if (i + 1 == NumMatches) OS << "or "; OS << "'" << Base << MatchChars[i] << "'"; } OS << ")"; Error(IDLoc, OS.str(), EmptyRange, MatchingInlineAsm); return true; } // Okay, we know that none of the variants matched successfully. // If all of the instructions reported an invalid mnemonic, then the original // mnemonic was invalid. if (std::count(std::begin(Match), std::end(Match), Match_MnemonicFail) == 4) { if (!WasOriginallyInvalidOperand) { return Error(IDLoc, "invalid instruction mnemonic '" + Base + "'", Op.getLocRange(), MatchingInlineAsm); } // Recover location info for the operand if we know which was the problem. if (ErrorInfo != ~0ULL) { if (ErrorInfo >= Operands.size()) return Error(IDLoc, "too few operands for instruction", EmptyRange, MatchingInlineAsm); X86Operand &Operand = (X86Operand &)*Operands[ErrorInfo]; if (Operand.getStartLoc().isValid()) { SMRange OperandRange = Operand.getLocRange(); return Error(Operand.getStartLoc(), "invalid operand for instruction", OperandRange, MatchingInlineAsm); } } return Error(IDLoc, "invalid operand for instruction", EmptyRange, MatchingInlineAsm); } // If one instruction matched with a missing feature, report this as a // missing feature. if (std::count(std::begin(Match), std::end(Match), Match_MissingFeature) == 1) { ErrorInfo = ErrorInfoMissingFeature; return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature, MatchingInlineAsm); } // If one instruction matched with an invalid operand, report this as an // operand failure. if (std::count(std::begin(Match), std::end(Match), Match_InvalidOperand) == 1) { return Error(IDLoc, "invalid operand for instruction", EmptyRange, MatchingInlineAsm); } // If all of these were an outright failure, report it in a useless way. Error(IDLoc, "unknown use of instruction mnemonic without a size suffix", EmptyRange, MatchingInlineAsm); return true; } bool X86AsmParser::MatchAndEmitIntelInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { assert(!Operands.empty() && "Unexpect empty operand list!"); X86Operand &Op = static_cast(*Operands[0]); assert(Op.isToken() && "Leading operand should always be a mnemonic!"); StringRef Mnemonic = Op.getToken(); SMRange EmptyRange = None; StringRef Base = Op.getToken(); unsigned Prefixes = getPrefixes(Operands); // First, handle aliases that expand to multiple instructions. MatchFPUWaitAlias(IDLoc, Op, Operands, Out, MatchingInlineAsm); MCInst Inst; if (Prefixes) Inst.setFlags(Prefixes); // Find one unsized memory operand, if present. X86Operand *UnsizedMemOp = nullptr; for (const auto &Op : Operands) { X86Operand *X86Op = static_cast(Op.get()); if (X86Op->isMemUnsized()) { UnsizedMemOp = X86Op; // Have we found an unqualified memory operand, // break. IA allows only one memory operand. break; } } // Allow some instructions to have implicitly pointer-sized operands. This is // compatible with gas. if (UnsizedMemOp) { static const char *const PtrSizedInstrs[] = {"call", "jmp", "push"}; for (const char *Instr : PtrSizedInstrs) { if (Mnemonic == Instr) { UnsizedMemOp->Mem.Size = getPointerWidth(); break; } } } SmallVector Match; uint64_t ErrorInfoMissingFeature = 0; // If unsized push has immediate operand we should default the default pointer // size for the size. if (Mnemonic == "push" && Operands.size() == 2) { auto *X86Op = static_cast(Operands[1].get()); if (X86Op->isImm()) { // If it's not a constant fall through and let remainder take care of it. const auto *CE = dyn_cast(X86Op->getImm()); unsigned Size = getPointerWidth(); if (CE && (isIntN(Size, CE->getValue()) || isUIntN(Size, CE->getValue()))) { SmallString<16> Tmp; Tmp += Base; Tmp += (is64BitMode()) ? "q" : (is32BitMode()) ? "l" : (is16BitMode()) ? "w" : " "; Op.setTokenValue(Tmp); // Do match in ATT mode to allow explicit suffix usage. Match.push_back(MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm, false /*isParsingIntelSyntax()*/)); Op.setTokenValue(Base); } } } // If an unsized memory operand is present, try to match with each memory // operand size. In Intel assembly, the size is not part of the instruction // mnemonic. if (UnsizedMemOp && UnsizedMemOp->isMemUnsized()) { static const unsigned MopSizes[] = {8, 16, 32, 64, 80, 128, 256, 512}; for (unsigned Size : MopSizes) { UnsizedMemOp->Mem.Size = Size; uint64_t ErrorInfoIgnore; unsigned LastOpcode = Inst.getOpcode(); unsigned M = MatchInstruction(Operands, Inst, ErrorInfoIgnore, MatchingInlineAsm, isParsingIntelSyntax()); if (Match.empty() || LastOpcode != Inst.getOpcode()) Match.push_back(M); // If this returned as a missing feature failure, remember that. if (Match.back() == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfoIgnore; } // Restore the size of the unsized memory operand if we modified it. UnsizedMemOp->Mem.Size = 0; } // If we haven't matched anything yet, this is not a basic integer or FPU // operation. There shouldn't be any ambiguity in our mnemonic table, so try // matching with the unsized operand. if (Match.empty()) { Match.push_back(MatchInstruction( Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax())); // If this returned as a missing feature failure, remember that. if (Match.back() == Match_MissingFeature) ErrorInfoMissingFeature = ErrorInfo; } // Restore the size of the unsized memory operand if we modified it. if (UnsizedMemOp) UnsizedMemOp->Mem.Size = 0; // If it's a bad mnemonic, all results will be the same. if (Match.back() == Match_MnemonicFail) { return Error(IDLoc, "invalid instruction mnemonic '" + Mnemonic + "'", Op.getLocRange(), MatchingInlineAsm); } unsigned NumSuccessfulMatches = std::count(std::begin(Match), std::end(Match), Match_Success); // If matching was ambiguous and we had size information from the frontend, // try again with that. This handles cases like "movxz eax, m8/m16". if (UnsizedMemOp && NumSuccessfulMatches > 1 && UnsizedMemOp->getMemFrontendSize()) { UnsizedMemOp->Mem.Size = UnsizedMemOp->getMemFrontendSize(); unsigned M = MatchInstruction( Operands, Inst, ErrorInfo, MatchingInlineAsm, isParsingIntelSyntax()); if (M == Match_Success) NumSuccessfulMatches = 1; // Add a rewrite that encodes the size information we used from the // frontend. InstInfo->AsmRewrites->emplace_back( AOK_SizeDirective, UnsizedMemOp->getStartLoc(), /*Len=*/0, UnsizedMemOp->getMemFrontendSize()); } // If exactly one matched, then we treat that as a successful match (and the // instruction will already have been filled in correctly, since the failing // matches won't have modified it). if (NumSuccessfulMatches == 1) { if (!MatchingInlineAsm && validateInstruction(Inst, Operands)) return true; // Some instructions need post-processing to, for example, tweak which // encoding is selected. Loop on it while changes happen so the individual // transformations can chain off each other. if (!MatchingInlineAsm) while (processInstruction(Inst, Operands)) ; Inst.setLoc(IDLoc); if (!MatchingInlineAsm) EmitInstruction(Inst, Operands, Out); Opcode = Inst.getOpcode(); return false; } else if (NumSuccessfulMatches > 1) { assert(UnsizedMemOp && "multiple matches only possible with unsized memory operands"); return Error(UnsizedMemOp->getStartLoc(), "ambiguous operand size for instruction '" + Mnemonic + "\'", UnsizedMemOp->getLocRange()); } // If one instruction matched with a missing feature, report this as a // missing feature. if (std::count(std::begin(Match), std::end(Match), Match_MissingFeature) == 1) { ErrorInfo = ErrorInfoMissingFeature; return ErrorMissingFeature(IDLoc, ErrorInfoMissingFeature, MatchingInlineAsm); } // If one instruction matched with an invalid operand, report this as an // operand failure. if (std::count(std::begin(Match), std::end(Match), Match_InvalidOperand) == 1) { return Error(IDLoc, "invalid operand for instruction", EmptyRange, MatchingInlineAsm); } // If all of these were an outright failure, report it in a useless way. return Error(IDLoc, "unknown instruction mnemonic", EmptyRange, MatchingInlineAsm); } bool X86AsmParser::OmitRegisterFromClobberLists(unsigned RegNo) { return X86MCRegisterClasses[X86::SEGMENT_REGRegClassID].contains(RegNo); } bool X86AsmParser::ParseDirective(AsmToken DirectiveID) { MCAsmParser &Parser = getParser(); StringRef IDVal = DirectiveID.getIdentifier(); if (IDVal.startswith(".code")) return ParseDirectiveCode(IDVal, DirectiveID.getLoc()); else if (IDVal.startswith(".att_syntax")) { getParser().setParsingInlineAsm(false); if (getLexer().isNot(AsmToken::EndOfStatement)) { if (Parser.getTok().getString() == "prefix") Parser.Lex(); else if (Parser.getTok().getString() == "noprefix") return Error(DirectiveID.getLoc(), "'.att_syntax noprefix' is not " "supported: registers must have a " "'%' prefix in .att_syntax"); } getParser().setAssemblerDialect(0); return false; } else if (IDVal.startswith(".intel_syntax")) { getParser().setAssemblerDialect(1); getParser().setParsingInlineAsm(true); if (getLexer().isNot(AsmToken::EndOfStatement)) { if (Parser.getTok().getString() == "noprefix") Parser.Lex(); else if (Parser.getTok().getString() == "prefix") return Error(DirectiveID.getLoc(), "'.intel_syntax prefix' is not " "supported: registers must not have " "a '%' prefix in .intel_syntax"); } return false; } else if (IDVal == ".even") return parseDirectiveEven(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_proc") return parseDirectiveFPOProc(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_setframe") return parseDirectiveFPOSetFrame(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_pushreg") return parseDirectiveFPOPushReg(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_stackalloc") return parseDirectiveFPOStackAlloc(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_endprologue") return parseDirectiveFPOEndPrologue(DirectiveID.getLoc()); else if (IDVal == ".cv_fpo_endproc") return parseDirectiveFPOEndProc(DirectiveID.getLoc()); return true; } /// parseDirectiveEven /// ::= .even bool X86AsmParser::parseDirectiveEven(SMLoc L) { if (parseToken(AsmToken::EndOfStatement, "unexpected token in directive")) return false; const MCSection *Section = getStreamer().getCurrentSectionOnly(); if (!Section) { getStreamer().InitSections(false); Section = getStreamer().getCurrentSectionOnly(); } if (Section->UseCodeAlign()) getStreamer().EmitCodeAlignment(2, 0); else getStreamer().EmitValueToAlignment(2, 0, 1, 0); return false; } /// ParseDirectiveCode /// ::= .code16 | .code32 | .code64 bool X86AsmParser::ParseDirectiveCode(StringRef IDVal, SMLoc L) { MCAsmParser &Parser = getParser(); Code16GCC = false; if (IDVal == ".code16") { Parser.Lex(); if (!is16BitMode()) { SwitchMode(X86::Mode16Bit); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); } } else if (IDVal == ".code16gcc") { // .code16gcc parses as if in 32-bit mode, but emits code in 16-bit mode. Parser.Lex(); Code16GCC = true; if (!is16BitMode()) { SwitchMode(X86::Mode16Bit); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16); } } else if (IDVal == ".code32") { Parser.Lex(); if (!is32BitMode()) { SwitchMode(X86::Mode32Bit); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32); } } else if (IDVal == ".code64") { Parser.Lex(); if (!is64BitMode()) { SwitchMode(X86::Mode64Bit); getParser().getStreamer().EmitAssemblerFlag(MCAF_Code64); } } else { Error(L, "unknown directive " + IDVal); return false; } return false; } // .cv_fpo_proc foo bool X86AsmParser::parseDirectiveFPOProc(SMLoc L) { MCAsmParser &Parser = getParser(); StringRef ProcName; int64_t ParamsSize; if (Parser.parseIdentifier(ProcName)) return Parser.TokError("expected symbol name"); if (Parser.parseIntToken(ParamsSize, "expected parameter byte count")) return true; if (!isUIntN(32, ParamsSize)) return Parser.TokError("parameters size out of range"); if (Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_proc' directive"); MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName); return getTargetStreamer().emitFPOProc(ProcSym, ParamsSize, L); } // .cv_fpo_setframe ebp bool X86AsmParser::parseDirectiveFPOSetFrame(SMLoc L) { MCAsmParser &Parser = getParser(); unsigned Reg; SMLoc DummyLoc; if (ParseRegister(Reg, DummyLoc, DummyLoc) || Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_setframe' directive"); return getTargetStreamer().emitFPOSetFrame(Reg, L); } // .cv_fpo_pushreg ebx bool X86AsmParser::parseDirectiveFPOPushReg(SMLoc L) { MCAsmParser &Parser = getParser(); unsigned Reg; SMLoc DummyLoc; if (ParseRegister(Reg, DummyLoc, DummyLoc) || Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_pushreg' directive"); return getTargetStreamer().emitFPOPushReg(Reg, L); } // .cv_fpo_stackalloc 20 bool X86AsmParser::parseDirectiveFPOStackAlloc(SMLoc L) { MCAsmParser &Parser = getParser(); int64_t Offset; if (Parser.parseIntToken(Offset, "expected offset") || Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_stackalloc' directive"); return getTargetStreamer().emitFPOStackAlloc(Offset, L); } // .cv_fpo_endprologue bool X86AsmParser::parseDirectiveFPOEndPrologue(SMLoc L) { MCAsmParser &Parser = getParser(); if (Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_endprologue' directive"); return getTargetStreamer().emitFPOEndPrologue(L); } // .cv_fpo_endproc bool X86AsmParser::parseDirectiveFPOEndProc(SMLoc L) { MCAsmParser &Parser = getParser(); if (Parser.parseEOL("unexpected tokens")) return addErrorSuffix(" in '.cv_fpo_endproc' directive"); return getTargetStreamer().emitFPOEndProc(L); } // Force static initialization. extern "C" void LLVMInitializeX86AsmParser() { RegisterMCAsmParser X(getTheX86_32Target()); RegisterMCAsmParser Y(getTheX86_64Target()); } #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION #define GET_SUBTARGET_FEATURE_NAME #include "X86GenAsmMatcher.inc" Index: vendor/llvm/dist-release_70/lib/Target/X86/MCTargetDesc/X86MCExpr.h =================================================================== --- vendor/llvm/dist-release_70/lib/Target/X86/MCTargetDesc/X86MCExpr.h (revision 338377) +++ vendor/llvm/dist-release_70/lib/Target/X86/MCTargetDesc/X86MCExpr.h (revision 338378) @@ -1,75 +1,80 @@ //=--- X86MCExpr.h - X86 specific MC expression classes ---*- C++ -*-=// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes X86-specific MCExprs, i.e, registers used for // extended variable assignments. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_X86_MCTARGETDESC_X86MCEXPR_H #define LLVM_LIB_TARGET_X86_MCTARGETDESC_X86MCEXPR_H #include "InstPrinter/X86ATTInstPrinter.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { class X86MCExpr : public MCTargetExpr { private: const int64_t RegNo; // All explicit X86MCExpr(int64_t R) : RegNo(R) {} public: /// @name Construction /// @{ static const X86MCExpr *create(int64_t RegNo, MCContext &Ctx) { return new (Ctx) X86MCExpr(RegNo); } /// @} /// @name Accessors /// @{ /// getSubExpr - Get the child of this expression. int64_t getRegNo() const { return RegNo; } /// @} void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override { - if (MAI->getAssemblerDialect() == 0) + if (!MAI || MAI->getAssemblerDialect() == 0) OS << '%'; OS << X86ATTInstPrinter::getRegisterName(RegNo); } bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const override { return false; } // Register values should be inlined as they are not valid .set expressions. bool inlineAssignedExpr() const override { return true; } + bool isEqualTo(const MCExpr *X) const override { + if (auto *E = dyn_cast(X)) + return getRegNo() == E->getRegNo(); + return false; + } void visitUsedExpr(MCStreamer &Streamer) const override{}; MCFragment *findAssociatedFragment() const override { return nullptr; } // There are no TLS X86MCExprs at the moment. void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; } }; } // end namespace llvm #endif Index: vendor/llvm/dist-release_70/lib/Transforms/Utils/BypassSlowDivision.cpp =================================================================== --- vendor/llvm/dist-release_70/lib/Transforms/Utils/BypassSlowDivision.cpp (revision 338377) +++ vendor/llvm/dist-release_70/lib/Transforms/Utils/BypassSlowDivision.cpp (revision 338378) @@ -1,466 +1,475 @@ //===- BypassSlowDivision.cpp - Bypass slow division ----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains an optimization for div and rem on architectures that // execute short instructions significantly faster than longer instructions. // For example, on Intel Atom 32-bit divides are slow enough that during // runtime it is profitable to check the value of the operands, and if they are // positive and less than 256 use an unsigned 8-bit divide. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/BypassSlowDivision.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/KnownBits.h" #include #include using namespace llvm; #define DEBUG_TYPE "bypass-slow-division" namespace { struct QuotRemPair { Value *Quotient; Value *Remainder; QuotRemPair(Value *InQuotient, Value *InRemainder) : Quotient(InQuotient), Remainder(InRemainder) {} }; /// A quotient and remainder, plus a BB from which they logically "originate". /// If you use Quotient or Remainder in a Phi node, you should use BB as its /// corresponding predecessor. struct QuotRemWithBB { BasicBlock *BB = nullptr; Value *Quotient = nullptr; Value *Remainder = nullptr; }; using DivCacheTy = DenseMap; using BypassWidthsTy = DenseMap; using VisitedSetTy = SmallPtrSet; enum ValueRange { /// Operand definitely fits into BypassType. No runtime checks are needed. VALRNG_KNOWN_SHORT, /// A runtime check is required, as value range is unknown. VALRNG_UNKNOWN, /// Operand is unlikely to fit into BypassType. The bypassing should be /// disabled. VALRNG_LIKELY_LONG }; class FastDivInsertionTask { bool IsValidTask = false; Instruction *SlowDivOrRem = nullptr; IntegerType *BypassType = nullptr; BasicBlock *MainBB = nullptr; bool isHashLikeValue(Value *V, VisitedSetTy &Visited); ValueRange getValueRange(Value *Op, VisitedSetTy &Visited); QuotRemWithBB createSlowBB(BasicBlock *Successor); QuotRemWithBB createFastBB(BasicBlock *Successor); QuotRemPair createDivRemPhiNodes(QuotRemWithBB &LHS, QuotRemWithBB &RHS, BasicBlock *PhiBB); Value *insertOperandRuntimeCheck(Value *Op1, Value *Op2); Optional insertFastDivAndRem(); bool isSignedOp() { return SlowDivOrRem->getOpcode() == Instruction::SDiv || SlowDivOrRem->getOpcode() == Instruction::SRem; } bool isDivisionOp() { return SlowDivOrRem->getOpcode() == Instruction::SDiv || SlowDivOrRem->getOpcode() == Instruction::UDiv; } Type *getSlowType() { return SlowDivOrRem->getType(); } public: FastDivInsertionTask(Instruction *I, const BypassWidthsTy &BypassWidths); Value *getReplacement(DivCacheTy &Cache); }; } // end anonymous namespace FastDivInsertionTask::FastDivInsertionTask(Instruction *I, const BypassWidthsTy &BypassWidths) { switch (I->getOpcode()) { case Instruction::UDiv: case Instruction::SDiv: case Instruction::URem: case Instruction::SRem: SlowDivOrRem = I; break; default: // I is not a div/rem operation. return; } // Skip division on vector types. Only optimize integer instructions. IntegerType *SlowType = dyn_cast(SlowDivOrRem->getType()); if (!SlowType) return; // Skip if this bitwidth is not bypassed. auto BI = BypassWidths.find(SlowType->getBitWidth()); if (BI == BypassWidths.end()) return; // Get type for div/rem instruction with bypass bitwidth. IntegerType *BT = IntegerType::get(I->getContext(), BI->second); BypassType = BT; // The original basic block. MainBB = I->getParent(); // The instruction is indeed a slow div or rem operation. IsValidTask = true; } /// Reuses previously-computed dividend or remainder from the current BB if /// operands and operation are identical. Otherwise calls insertFastDivAndRem to /// perform the optimization and caches the resulting dividend and remainder. /// If no replacement can be generated, nullptr is returned. Value *FastDivInsertionTask::getReplacement(DivCacheTy &Cache) { // First, make sure that the task is valid. if (!IsValidTask) return nullptr; // Then, look for a value in Cache. Value *Dividend = SlowDivOrRem->getOperand(0); Value *Divisor = SlowDivOrRem->getOperand(1); DivRemMapKey Key(isSignedOp(), Dividend, Divisor); auto CacheI = Cache.find(Key); if (CacheI == Cache.end()) { // If previous instance does not exist, try to insert fast div. Optional OptResult = insertFastDivAndRem(); // Bail out if insertFastDivAndRem has failed. if (!OptResult) return nullptr; CacheI = Cache.insert({Key, *OptResult}).first; } QuotRemPair &Value = CacheI->second; return isDivisionOp() ? Value.Quotient : Value.Remainder; } /// Check if a value looks like a hash. /// /// The routine is expected to detect values computed using the most common hash /// algorithms. Typically, hash computations end with one of the following /// instructions: /// /// 1) MUL with a constant wider than BypassType /// 2) XOR instruction /// /// And even if we are wrong and the value is not a hash, it is still quite /// unlikely that such values will fit into BypassType. /// /// To detect string hash algorithms like FNV we have to look through PHI-nodes. /// It is implemented as a depth-first search for values that look neither long /// nor hash-like. bool FastDivInsertionTask::isHashLikeValue(Value *V, VisitedSetTy &Visited) { Instruction *I = dyn_cast(V); if (!I) return false; switch (I->getOpcode()) { case Instruction::Xor: return true; case Instruction::Mul: { // After Constant Hoisting pass, long constants may be represented as // bitcast instructions. As a result, some constants may look like an // instruction at first, and an additional check is necessary to find out if // an operand is actually a constant. Value *Op1 = I->getOperand(1); ConstantInt *C = dyn_cast(Op1); if (!C && isa(Op1)) C = dyn_cast(cast(Op1)->getOperand(0)); return C && C->getValue().getMinSignedBits() > BypassType->getBitWidth(); } case Instruction::PHI: // Stop IR traversal in case of a crazy input code. This limits recursion // depth. if (Visited.size() >= 16) return false; // Do not visit nodes that have been visited already. We return true because // it means that we couldn't find any value that doesn't look hash-like. if (Visited.find(I) != Visited.end()) return true; Visited.insert(I); return llvm::all_of(cast(I)->incoming_values(), [&](Value *V) { // Ignore undef values as they probably don't affect the division // operands. return getValueRange(V, Visited) == VALRNG_LIKELY_LONG || isa(V); }); default: return false; } } /// Check if an integer value fits into our bypass type. ValueRange FastDivInsertionTask::getValueRange(Value *V, VisitedSetTy &Visited) { unsigned ShortLen = BypassType->getBitWidth(); unsigned LongLen = V->getType()->getIntegerBitWidth(); assert(LongLen > ShortLen && "Value type must be wider than BypassType"); unsigned HiBits = LongLen - ShortLen; const DataLayout &DL = SlowDivOrRem->getModule()->getDataLayout(); KnownBits Known(LongLen); computeKnownBits(V, Known, DL); if (Known.countMinLeadingZeros() >= HiBits) return VALRNG_KNOWN_SHORT; if (Known.countMaxLeadingZeros() < HiBits) return VALRNG_LIKELY_LONG; // Long integer divisions are often used in hashtable implementations. It's // not worth bypassing such divisions because hash values are extremely // unlikely to have enough leading zeros. The call below tries to detect // values that are unlikely to fit BypassType (including hashes). if (isHashLikeValue(V, Visited)) return VALRNG_LIKELY_LONG; return VALRNG_UNKNOWN; } /// Add new basic block for slow div and rem operations and put it before /// SuccessorBB. QuotRemWithBB FastDivInsertionTask::createSlowBB(BasicBlock *SuccessorBB) { QuotRemWithBB DivRemPair; DivRemPair.BB = BasicBlock::Create(MainBB->getParent()->getContext(), "", MainBB->getParent(), SuccessorBB); IRBuilder<> Builder(DivRemPair.BB, DivRemPair.BB->begin()); Value *Dividend = SlowDivOrRem->getOperand(0); Value *Divisor = SlowDivOrRem->getOperand(1); if (isSignedOp()) { DivRemPair.Quotient = Builder.CreateSDiv(Dividend, Divisor); DivRemPair.Remainder = Builder.CreateSRem(Dividend, Divisor); } else { DivRemPair.Quotient = Builder.CreateUDiv(Dividend, Divisor); DivRemPair.Remainder = Builder.CreateURem(Dividend, Divisor); } Builder.CreateBr(SuccessorBB); return DivRemPair; } /// Add new basic block for fast div and rem operations and put it before /// SuccessorBB. QuotRemWithBB FastDivInsertionTask::createFastBB(BasicBlock *SuccessorBB) { QuotRemWithBB DivRemPair; DivRemPair.BB = BasicBlock::Create(MainBB->getParent()->getContext(), "", MainBB->getParent(), SuccessorBB); IRBuilder<> Builder(DivRemPair.BB, DivRemPair.BB->begin()); Value *Dividend = SlowDivOrRem->getOperand(0); Value *Divisor = SlowDivOrRem->getOperand(1); Value *ShortDivisorV = Builder.CreateCast(Instruction::Trunc, Divisor, BypassType); Value *ShortDividendV = Builder.CreateCast(Instruction::Trunc, Dividend, BypassType); // udiv/urem because this optimization only handles positive numbers. Value *ShortQV = Builder.CreateUDiv(ShortDividendV, ShortDivisorV); Value *ShortRV = Builder.CreateURem(ShortDividendV, ShortDivisorV); DivRemPair.Quotient = Builder.CreateCast(Instruction::ZExt, ShortQV, getSlowType()); DivRemPair.Remainder = Builder.CreateCast(Instruction::ZExt, ShortRV, getSlowType()); Builder.CreateBr(SuccessorBB); return DivRemPair; } /// Creates Phi nodes for result of Div and Rem. QuotRemPair FastDivInsertionTask::createDivRemPhiNodes(QuotRemWithBB &LHS, QuotRemWithBB &RHS, BasicBlock *PhiBB) { IRBuilder<> Builder(PhiBB, PhiBB->begin()); PHINode *QuoPhi = Builder.CreatePHI(getSlowType(), 2); QuoPhi->addIncoming(LHS.Quotient, LHS.BB); QuoPhi->addIncoming(RHS.Quotient, RHS.BB); PHINode *RemPhi = Builder.CreatePHI(getSlowType(), 2); RemPhi->addIncoming(LHS.Remainder, LHS.BB); RemPhi->addIncoming(RHS.Remainder, RHS.BB); return QuotRemPair(QuoPhi, RemPhi); } /// Creates a runtime check to test whether both the divisor and dividend fit /// into BypassType. The check is inserted at the end of MainBB. True return /// value means that the operands fit. Either of the operands may be NULL if it /// doesn't need a runtime check. Value *FastDivInsertionTask::insertOperandRuntimeCheck(Value *Op1, Value *Op2) { assert((Op1 || Op2) && "Nothing to check"); IRBuilder<> Builder(MainBB, MainBB->end()); Value *OrV; if (Op1 && Op2) OrV = Builder.CreateOr(Op1, Op2); else OrV = Op1 ? Op1 : Op2; // BitMask is inverted to check if the operands are // larger than the bypass type uint64_t BitMask = ~BypassType->getBitMask(); Value *AndV = Builder.CreateAnd(OrV, BitMask); // Compare operand values Value *ZeroV = ConstantInt::getSigned(getSlowType(), 0); return Builder.CreateICmpEQ(AndV, ZeroV); } /// Substitutes the div/rem instruction with code that checks the value of the /// operands and uses a shorter-faster div/rem instruction when possible. Optional FastDivInsertionTask::insertFastDivAndRem() { Value *Dividend = SlowDivOrRem->getOperand(0); Value *Divisor = SlowDivOrRem->getOperand(1); VisitedSetTy SetL; ValueRange DividendRange = getValueRange(Dividend, SetL); if (DividendRange == VALRNG_LIKELY_LONG) return None; VisitedSetTy SetR; ValueRange DivisorRange = getValueRange(Divisor, SetR); if (DivisorRange == VALRNG_LIKELY_LONG) return None; bool DividendShort = (DividendRange == VALRNG_KNOWN_SHORT); bool DivisorShort = (DivisorRange == VALRNG_KNOWN_SHORT); if (DividendShort && DivisorShort) { // If both operands are known to be short then just replace the long // division with a short one in-place. Since we're not introducing control // flow in this case, narrowing the division is always a win, even if the // divisor is a constant (and will later get replaced by a multiplication). IRBuilder<> Builder(SlowDivOrRem); Value *TruncDividend = Builder.CreateTrunc(Dividend, BypassType); Value *TruncDivisor = Builder.CreateTrunc(Divisor, BypassType); Value *TruncDiv = Builder.CreateUDiv(TruncDividend, TruncDivisor); Value *TruncRem = Builder.CreateURem(TruncDividend, TruncDivisor); Value *ExtDiv = Builder.CreateZExt(TruncDiv, getSlowType()); Value *ExtRem = Builder.CreateZExt(TruncRem, getSlowType()); return QuotRemPair(ExtDiv, ExtRem); } if (isa(Divisor)) { // If the divisor is not a constant, DAGCombiner will convert it to a // multiplication by a magic constant. It isn't clear if it is worth // introducing control flow to get a narrower multiply. return None; } + // After Constant Hoisting pass, long constants may be represented as + // bitcast instructions. As a result, some constants may look like an + // instruction at first, and an additional check is necessary to find out if + // an operand is actually a constant. + if (auto *BCI = dyn_cast(Divisor)) + if (BCI->getParent() == SlowDivOrRem->getParent() && + isa(BCI->getOperand(0))) + return None; + if (DividendShort && !isSignedOp()) { // If the division is unsigned and Dividend is known to be short, then // either // 1) Divisor is less or equal to Dividend, and the result can be computed // with a short division. // 2) Divisor is greater than Dividend. In this case, no division is needed // at all: The quotient is 0 and the remainder is equal to Dividend. // // So instead of checking at runtime whether Divisor fits into BypassType, // we emit a runtime check to differentiate between these two cases. This // lets us entirely avoid a long div. // Split the basic block before the div/rem. BasicBlock *SuccessorBB = MainBB->splitBasicBlock(SlowDivOrRem); // Remove the unconditional branch from MainBB to SuccessorBB. MainBB->getInstList().back().eraseFromParent(); QuotRemWithBB Long; Long.BB = MainBB; Long.Quotient = ConstantInt::get(getSlowType(), 0); Long.Remainder = Dividend; QuotRemWithBB Fast = createFastBB(SuccessorBB); QuotRemPair Result = createDivRemPhiNodes(Fast, Long, SuccessorBB); IRBuilder<> Builder(MainBB, MainBB->end()); Value *CmpV = Builder.CreateICmpUGE(Dividend, Divisor); Builder.CreateCondBr(CmpV, Fast.BB, SuccessorBB); return Result; } else { // General case. Create both slow and fast div/rem pairs and choose one of // them at runtime. // Split the basic block before the div/rem. BasicBlock *SuccessorBB = MainBB->splitBasicBlock(SlowDivOrRem); // Remove the unconditional branch from MainBB to SuccessorBB. MainBB->getInstList().back().eraseFromParent(); QuotRemWithBB Fast = createFastBB(SuccessorBB); QuotRemWithBB Slow = createSlowBB(SuccessorBB); QuotRemPair Result = createDivRemPhiNodes(Fast, Slow, SuccessorBB); Value *CmpV = insertOperandRuntimeCheck(DividendShort ? nullptr : Dividend, DivisorShort ? nullptr : Divisor); IRBuilder<> Builder(MainBB, MainBB->end()); Builder.CreateCondBr(CmpV, Fast.BB, Slow.BB); return Result; } } /// This optimization identifies DIV/REM instructions in a BB that can be /// profitably bypassed and carried out with a shorter, faster divide. bool llvm::bypassSlowDivision(BasicBlock *BB, const BypassWidthsTy &BypassWidths) { DivCacheTy PerBBDivCache; bool MadeChange = false; Instruction* Next = &*BB->begin(); while (Next != nullptr) { // We may add instructions immediately after I, but we want to skip over // them. Instruction* I = Next; Next = Next->getNextNode(); FastDivInsertionTask Task(I, BypassWidths); if (Value *Replacement = Task.getReplacement(PerBBDivCache)) { I->replaceAllUsesWith(Replacement); I->eraseFromParent(); MadeChange = true; } } // Above we eagerly create divs and rems, as pairs, so that we can efficiently // create divrem machine instructions. Now erase any unused divs / rems so we // don't leave extra instructions sitting around. for (auto &KV : PerBBDivCache) for (Value *V : {KV.second.Quotient, KV.second.Remainder}) RecursivelyDeleteTriviallyDeadInstructions(V); return MadeChange; } Index: vendor/llvm/dist-release_70/test/CodeGen/AArch64/GlobalISel/irtranslator-duplicate-types-param.ll =================================================================== --- vendor/llvm/dist-release_70/test/CodeGen/AArch64/GlobalISel/irtranslator-duplicate-types-param.ll (nonexistent) +++ vendor/llvm/dist-release_70/test/CodeGen/AArch64/GlobalISel/irtranslator-duplicate-types-param.ll (revision 338378) @@ -0,0 +1,15 @@ +; RUN: llc -O0 -o - -verify-machineinstrs %s | FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux-gnu" + +; Check we don't crash due to encountering the same struct param type twice. +; CHECK-LABEL: param_two_struct +; CHECK: add +; CHECK: ret +define i64 @param_two_struct([2 x i64] %t.coerce, [2 x i64] %s.coerce) { +entry: + %t.coerce.fca.0.extract = extractvalue [2 x i64] %t.coerce, 0 + %s.coerce.fca.1.extract = extractvalue [2 x i64] %s.coerce, 1 + %add = add nsw i64 %s.coerce.fca.1.extract, %t.coerce.fca.0.extract + ret i64 %add +} Index: vendor/llvm/dist-release_70/test/CodeGen/PowerPC/uwtables.ll =================================================================== --- vendor/llvm/dist-release_70/test/CodeGen/PowerPC/uwtables.ll (nonexistent) +++ vendor/llvm/dist-release_70/test/CodeGen/PowerPC/uwtables.ll (revision 338378) @@ -0,0 +1,51 @@ +; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown \ +; RUN: -verify-machineinstrs -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr < %s | FileCheck %s +; RUN: llc -mcpu=pwr8 -mtriple=powerpc64le-unknown-unknown \ +; RUN: -verify-machineinstrs -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr < %s | FileCheck %s +; RUN: llc -mtriple=powerpc64-unknown-unknown \ +; RUN: -verify-machineinstrs -ppc-asm-full-reg-names \ +; RUN: -ppc-vsr-nums-as-vr < %s | FileCheck %s + + +@_ZTIi = external constant i8* + +; Function is marked as nounwind but it still throws with __cxa_throw and +; calls __cxa_call_unexpected. +; Need to make sure that we do not only have a debug frame. +; Function Attrs: noreturn nounwind +define void @_Z4funcv() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %exception = tail call i8* @__cxa_allocate_exception(i64 4) + %0 = bitcast i8* %exception to i32* + store i32 100, i32* %0, align 16 + invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) + to label %unreachable unwind label %lpad + +lpad: ; preds = %entry + %1 = landingpad { i8*, i32 } + filter [0 x i8*] zeroinitializer + %2 = extractvalue { i8*, i32 } %1, 0 + tail call void @__cxa_call_unexpected(i8* %2) + unreachable + +unreachable: ; preds = %entry + unreachable +; CHECK-LABEL: _Z4funcv +; CHECK-NOT: .debug_frame +; CHECK: .cfi_personality +; CHECK: .cfi_endproc +} + +declare i8* @__cxa_allocate_exception(i64) local_unnamed_addr + +declare void @__cxa_throw(i8*, i8*, i8*) local_unnamed_addr + +declare i32 @__gxx_personality_v0(...) + +declare void @__cxa_call_unexpected(i8*) local_unnamed_addr + + +attributes #0 = { noreturn nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="ppc64le" "target-features"="+altivec,+bpermd,+crypto,+direct-move,+extdiv,+htm,+power8-vector,+vsx,-power9-vector,-qpx" "unsafe-fp-math"="false" "use-soft-float"="false" } + Index: vendor/llvm/dist-release_70/test/CodeGen/X86/divide-by-constant.ll =================================================================== --- vendor/llvm/dist-release_70/test/CodeGen/X86/divide-by-constant.ll (revision 338377) +++ vendor/llvm/dist-release_70/test/CodeGen/X86/divide-by-constant.ll (revision 338378) @@ -1,332 +1,442 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=i686-pc-linux-gnu | FileCheck %s --check-prefix=X32 ; RUN: llc < %s -mtriple=x86_64-pc-linux-gnu | FileCheck %s --check-prefix=X64 define zeroext i16 @test1(i16 zeroext %x) nounwind { ; X32-LABEL: test1: ; X32: # %bb.0: # %entry ; X32-NEXT: movzwl {{[0-9]+}}(%esp), %eax ; X32-NEXT: imull $63551, %eax, %eax # imm = 0xF83F ; X32-NEXT: shrl $21, %eax ; X32-NEXT: # kill: def $ax killed $ax killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test1: ; X64: # %bb.0: # %entry ; X64-NEXT: imull $63551, %edi, %eax # imm = 0xF83F ; X64-NEXT: shrl $21, %eax ; X64-NEXT: # kill: def $ax killed $ax killed $eax ; X64-NEXT: retq entry: %div = udiv i16 %x, 33 ret i16 %div } define zeroext i16 @test2(i8 signext %x, i16 zeroext %c) nounwind readnone ssp noredzone { ; X32-LABEL: test2: ; X32: # %bb.0: # %entry ; X32-NEXT: movzwl {{[0-9]+}}(%esp), %eax ; X32-NEXT: imull $43691, %eax, %eax # imm = 0xAAAB ; X32-NEXT: shrl $17, %eax ; X32-NEXT: # kill: def $ax killed $ax killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test2: ; X64: # %bb.0: # %entry ; X64-NEXT: imull $43691, %esi, %eax # imm = 0xAAAB ; X64-NEXT: shrl $17, %eax ; X64-NEXT: # kill: def $ax killed $ax killed $eax ; X64-NEXT: retq entry: %div = udiv i16 %c, 3 ret i16 %div } define zeroext i8 @test3(i8 zeroext %x, i8 zeroext %c) nounwind readnone ssp noredzone { ; X32-LABEL: test3: ; X32: # %bb.0: # %entry ; X32-NEXT: movzbl {{[0-9]+}}(%esp), %eax ; X32-NEXT: imull $171, %eax, %eax ; X32-NEXT: shrl $9, %eax ; X32-NEXT: # kill: def $al killed $al killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test3: ; X64: # %bb.0: # %entry ; X64-NEXT: imull $171, %esi, %eax ; X64-NEXT: shrl $9, %eax ; X64-NEXT: # kill: def $al killed $al killed $eax ; X64-NEXT: retq entry: %div = udiv i8 %c, 3 ret i8 %div } define signext i16 @test4(i16 signext %x) nounwind { ; X32-LABEL: test4: ; X32: # %bb.0: # %entry ; X32-NEXT: movswl {{[0-9]+}}(%esp), %eax ; X32-NEXT: imull $1986, %eax, %eax # imm = 0x7C2 ; X32-NEXT: movl %eax, %ecx ; X32-NEXT: shrl $31, %ecx ; X32-NEXT: shrl $16, %eax ; X32-NEXT: addl %ecx, %eax ; X32-NEXT: # kill: def $ax killed $ax killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test4: ; X64: # %bb.0: # %entry ; X64-NEXT: imull $1986, %edi, %eax # imm = 0x7C2 ; X64-NEXT: movl %eax, %ecx ; X64-NEXT: shrl $31, %ecx ; X64-NEXT: shrl $16, %eax ; X64-NEXT: addl %ecx, %eax ; X64-NEXT: # kill: def $ax killed $ax killed $eax ; X64-NEXT: retq entry: %div = sdiv i16 %x, 33 ; [#uses=1] ret i16 %div } define i32 @test5(i32 %A) nounwind { ; X32-LABEL: test5: ; X32: # %bb.0: ; X32-NEXT: movl $365384439, %eax # imm = 0x15C752F7 ; X32-NEXT: mull {{[0-9]+}}(%esp) ; X32-NEXT: shrl $27, %edx ; X32-NEXT: movl %edx, %eax ; X32-NEXT: retl ; ; X64-LABEL: test5: ; X64: # %bb.0: ; X64-NEXT: movl %edi, %eax ; X64-NEXT: imulq $365384439, %rax, %rax # imm = 0x15C752F7 ; X64-NEXT: shrq $59, %rax ; X64-NEXT: # kill: def $eax killed $eax killed $rax ; X64-NEXT: retq %tmp1 = udiv i32 %A, 1577682821 ; [#uses=1] ret i32 %tmp1 } define signext i16 @test6(i16 signext %x) nounwind { ; X32-LABEL: test6: ; X32: # %bb.0: # %entry ; X32-NEXT: movswl {{[0-9]+}}(%esp), %eax ; X32-NEXT: imull $26215, %eax, %eax # imm = 0x6667 ; X32-NEXT: movl %eax, %ecx ; X32-NEXT: shrl $31, %ecx ; X32-NEXT: sarl $18, %eax ; X32-NEXT: addl %ecx, %eax ; X32-NEXT: # kill: def $ax killed $ax killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test6: ; X64: # %bb.0: # %entry ; X64-NEXT: imull $26215, %edi, %eax # imm = 0x6667 ; X64-NEXT: movl %eax, %ecx ; X64-NEXT: shrl $31, %ecx ; X64-NEXT: sarl $18, %eax ; X64-NEXT: addl %ecx, %eax ; X64-NEXT: # kill: def $ax killed $ax killed $eax ; X64-NEXT: retq entry: %div = sdiv i16 %x, 10 ret i16 %div } define i32 @test7(i32 %x) nounwind { ; X32-LABEL: test7: ; X32: # %bb.0: ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: shrl $2, %eax ; X32-NEXT: movl $613566757, %ecx # imm = 0x24924925 ; X32-NEXT: mull %ecx ; X32-NEXT: movl %edx, %eax ; X32-NEXT: retl ; ; X64-LABEL: test7: ; X64: # %bb.0: ; X64-NEXT: # kill: def $edi killed $edi def $rdi ; X64-NEXT: shrl $2, %edi ; X64-NEXT: imulq $613566757, %rdi, %rax # imm = 0x24924925 ; X64-NEXT: shrq $32, %rax ; X64-NEXT: # kill: def $eax killed $eax killed $rax ; X64-NEXT: retq %div = udiv i32 %x, 28 ret i32 %div } ; PR13326 define i8 @test8(i8 %x) nounwind { ; X32-LABEL: test8: ; X32: # %bb.0: ; X32-NEXT: movb {{[0-9]+}}(%esp), %al ; X32-NEXT: shrb %al ; X32-NEXT: movzbl %al, %eax ; X32-NEXT: imull $211, %eax, %eax ; X32-NEXT: shrl $13, %eax ; X32-NEXT: # kill: def $al killed $al killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test8: ; X64: # %bb.0: ; X64-NEXT: shrb %dil ; X64-NEXT: movzbl %dil, %eax ; X64-NEXT: imull $211, %eax, %eax ; X64-NEXT: shrl $13, %eax ; X64-NEXT: # kill: def $al killed $al killed $eax ; X64-NEXT: retq %div = udiv i8 %x, 78 ret i8 %div } define i8 @test9(i8 %x) nounwind { ; X32-LABEL: test9: ; X32: # %bb.0: ; X32-NEXT: movb {{[0-9]+}}(%esp), %al ; X32-NEXT: shrb $2, %al ; X32-NEXT: movzbl %al, %eax ; X32-NEXT: imull $71, %eax, %eax ; X32-NEXT: shrl $11, %eax ; X32-NEXT: # kill: def $al killed $al killed $eax ; X32-NEXT: retl ; ; X64-LABEL: test9: ; X64: # %bb.0: ; X64-NEXT: shrb $2, %dil ; X64-NEXT: movzbl %dil, %eax ; X64-NEXT: imull $71, %eax, %eax ; X64-NEXT: shrl $11, %eax ; X64-NEXT: # kill: def $al killed $al killed $eax ; X64-NEXT: retq %div = udiv i8 %x, 116 ret i8 %div } define i32 @testsize1(i32 %x) minsize nounwind { ; X32-LABEL: testsize1: ; X32: # %bb.0: # %entry ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: pushl $32 ; X32-NEXT: popl %ecx ; X32-NEXT: cltd ; X32-NEXT: idivl %ecx ; X32-NEXT: retl ; ; X64-LABEL: testsize1: ; X64: # %bb.0: # %entry ; X64-NEXT: pushq $32 ; X64-NEXT: popq %rcx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: cltd ; X64-NEXT: idivl %ecx ; X64-NEXT: retq entry: %div = sdiv i32 %x, 32 ret i32 %div } define i32 @testsize2(i32 %x) minsize nounwind { ; X32-LABEL: testsize2: ; X32: # %bb.0: # %entry ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: pushl $33 ; X32-NEXT: popl %ecx ; X32-NEXT: cltd ; X32-NEXT: idivl %ecx ; X32-NEXT: retl ; ; X64-LABEL: testsize2: ; X64: # %bb.0: # %entry ; X64-NEXT: pushq $33 ; X64-NEXT: popq %rcx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: cltd ; X64-NEXT: idivl %ecx ; X64-NEXT: retq entry: %div = sdiv i32 %x, 33 ret i32 %div } define i32 @testsize3(i32 %x) minsize nounwind { ; X32-LABEL: testsize3: ; X32: # %bb.0: # %entry ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: shrl $5, %eax ; X32-NEXT: retl ; ; X64-LABEL: testsize3: ; X64: # %bb.0: # %entry ; X64-NEXT: shrl $5, %edi ; X64-NEXT: movl %edi, %eax ; X64-NEXT: retq entry: %div = udiv i32 %x, 32 ret i32 %div } define i32 @testsize4(i32 %x) minsize nounwind { ; X32-LABEL: testsize4: ; X32: # %bb.0: # %entry ; X32-NEXT: movl {{[0-9]+}}(%esp), %eax ; X32-NEXT: pushl $33 ; X32-NEXT: popl %ecx ; X32-NEXT: xorl %edx, %edx ; X32-NEXT: divl %ecx ; X32-NEXT: retl ; ; X64-LABEL: testsize4: ; X64: # %bb.0: # %entry ; X64-NEXT: pushq $33 ; X64-NEXT: popq %rcx ; X64-NEXT: xorl %edx, %edx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: divl %ecx ; X64-NEXT: retq entry: %div = udiv i32 %x, 33 ret i32 %div } define i64 @PR23590(i64 %x) nounwind { ; X32-LABEL: PR23590: ; X32: # %bb.0: # %entry ; X32-NEXT: subl $12, %esp ; X32-NEXT: pushl $0 ; X32-NEXT: pushl $12345 # imm = 0x3039 ; X32-NEXT: pushl {{[0-9]+}}(%esp) ; X32-NEXT: pushl {{[0-9]+}}(%esp) ; X32-NEXT: calll __umoddi3 ; X32-NEXT: addl $16, %esp ; X32-NEXT: pushl $0 ; X32-NEXT: pushl $7 ; X32-NEXT: pushl %edx ; X32-NEXT: pushl %eax ; X32-NEXT: calll __udivdi3 ; X32-NEXT: addl $28, %esp ; X32-NEXT: retl ; ; X64-LABEL: PR23590: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rdi, %rcx ; X64-NEXT: movabsq $6120523590596543007, %rdx # imm = 0x54F077C718E7C21F ; X64-NEXT: movq %rdi, %rax ; X64-NEXT: mulq %rdx ; X64-NEXT: shrq $12, %rdx ; X64-NEXT: imulq $12345, %rdx, %rax # imm = 0x3039 ; X64-NEXT: subq %rax, %rcx ; X64-NEXT: movabsq $2635249153387078803, %rdx # imm = 0x2492492492492493 ; X64-NEXT: movq %rcx, %rax ; X64-NEXT: mulq %rdx ; X64-NEXT: subq %rdx, %rcx ; X64-NEXT: shrq %rcx ; X64-NEXT: leaq (%rcx,%rdx), %rax ; X64-NEXT: shrq $2, %rax ; X64-NEXT: retq entry: %rem = urem i64 %x, 12345 %div = udiv i64 %rem, 7 ret i64 %div } + +define { i64, i32 } @PR38622(i64) nounwind { +; X32-LABEL: PR38622: +; X32: # %bb.0: +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: pushl %edi +; X32-NEXT: pushl %esi +; X32-NEXT: subl $12, %esp +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebx +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebp +; X32-NEXT: pushl $0 +; X32-NEXT: pushl $-294967296 # imm = 0xEE6B2800 +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: calll __udivdi3 +; X32-NEXT: addl $16, %esp +; X32-NEXT: movl %eax, %esi +; X32-NEXT: movl %edx, %edi +; X32-NEXT: pushl $0 +; X32-NEXT: pushl $-294967296 # imm = 0xEE6B2800 +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: calll __umoddi3 +; X32-NEXT: addl $16, %esp +; X32-NEXT: movl %eax, %ecx +; X32-NEXT: movl %esi, %eax +; X32-NEXT: movl %edi, %edx +; X32-NEXT: addl $12, %esp +; X32-NEXT: popl %esi +; X32-NEXT: popl %edi +; X32-NEXT: popl %ebx +; X32-NEXT: popl %ebp +; X32-NEXT: retl +; +; X64-LABEL: PR38622: +; X64: # %bb.0: +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: shrq $11, %rax +; X64-NEXT: movabsq $4835703278458517, %rcx # imm = 0x112E0BE826D695 +; X64-NEXT: mulq %rcx +; X64-NEXT: shrq $9, %rdx +; X64-NEXT: imull $-294967296, %edx, %eax # imm = 0xEE6B2800 +; X64-NEXT: subl %eax, %edi +; X64-NEXT: movq %rdx, %rax +; X64-NEXT: movl %edi, %edx +; X64-NEXT: retq + %2 = udiv i64 %0, 4000000000 + %3 = urem i64 %0, 4000000000 + %4 = trunc i64 %3 to i32 + %5 = insertvalue { i64, i32 } undef, i64 %2, 0 + %6 = insertvalue { i64, i32 } %5, i32 %4, 1 + ret { i64, i32 } %6 +} + +define { i64, i32 } @PR38622_signed(i64) nounwind { +; X32-LABEL: PR38622_signed: +; X32: # %bb.0: +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: pushl %edi +; X32-NEXT: pushl %esi +; X32-NEXT: subl $12, %esp +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebx +; X32-NEXT: movl {{[0-9]+}}(%esp), %ebp +; X32-NEXT: pushl $0 +; X32-NEXT: pushl $-294967296 # imm = 0xEE6B2800 +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: calll __divdi3 +; X32-NEXT: addl $16, %esp +; X32-NEXT: movl %eax, %esi +; X32-NEXT: movl %edx, %edi +; X32-NEXT: pushl $0 +; X32-NEXT: pushl $-294967296 # imm = 0xEE6B2800 +; X32-NEXT: pushl %ebp +; X32-NEXT: pushl %ebx +; X32-NEXT: calll __moddi3 +; X32-NEXT: addl $16, %esp +; X32-NEXT: movl %eax, %ecx +; X32-NEXT: movl %esi, %eax +; X32-NEXT: movl %edi, %edx +; X32-NEXT: addl $12, %esp +; X32-NEXT: popl %esi +; X32-NEXT: popl %edi +; X32-NEXT: popl %ebx +; X32-NEXT: popl %ebp +; X32-NEXT: retl +; +; X64-LABEL: PR38622_signed: +; X64: # %bb.0: +; X64-NEXT: movabsq $1237940039285380275, %rcx # imm = 0x112E0BE826D694B3 +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: imulq %rcx +; X64-NEXT: movq %rdx, %rcx +; X64-NEXT: shrq $63, %rcx +; X64-NEXT: sarq $28, %rdx +; X64-NEXT: leaq (%rdx,%rcx), %rax +; X64-NEXT: addl %ecx, %edx +; X64-NEXT: imull $-294967296, %edx, %ecx # imm = 0xEE6B2800 +; X64-NEXT: subl %ecx, %edi +; X64-NEXT: movl %edi, %edx +; X64-NEXT: retq + %2 = sdiv i64 %0, 4000000000 + %3 = srem i64 %0, 4000000000 + %4 = trunc i64 %3 to i32 + %5 = insertvalue { i64, i32 } undef, i64 %2, 0 + %6 = insertvalue { i64, i32 } %5, i32 %4, 1 + ret { i64, i32 } %6 +} Index: vendor/llvm/dist-release_70/test/CodeGen/X86/uwtables.ll =================================================================== --- vendor/llvm/dist-release_70/test/CodeGen/X86/uwtables.ll (nonexistent) +++ vendor/llvm/dist-release_70/test/CodeGen/X86/uwtables.ll (revision 338378) @@ -0,0 +1,43 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s + + +@_ZTIi = external constant i8* + +; Function is marked as nounwind but it still throws with __cxa_throw and +; calls __cxa_call_unexpected. +; Need to make sure that we do not only have a debug frame. +; Function Attrs: noreturn nounwind +define void @_Z4funcv() local_unnamed_addr #0 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %exception = tail call i8* @__cxa_allocate_exception(i64 4) + %0 = bitcast i8* %exception to i32* + store i32 100, i32* %0, align 16 + invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) + to label %unreachable unwind label %lpad + +lpad: ; preds = %entry + %1 = landingpad { i8*, i32 } + filter [0 x i8*] zeroinitializer + %2 = extractvalue { i8*, i32 } %1, 0 + tail call void @__cxa_call_unexpected(i8* %2) + unreachable + +unreachable: ; preds = %entry + unreachable +; CHECK-LABEL: _Z4funcv +; CHECK-NOT: .debug_frame +; CHECK: .cfi_personality +; CHECK: .cfi_endproc +} + +declare i8* @__cxa_allocate_exception(i64) local_unnamed_addr + +declare void @__cxa_throw(i8*, i8*, i8*) local_unnamed_addr + +declare i32 @__gxx_personality_v0(...) + +declare void @__cxa_call_unexpected(i8*) local_unnamed_addr + + +attributes #0 = { noreturn nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="ppc64le" "target-features"="+altivec,+bpermd,+crypto,+direct-move,+extdiv,+htm,+power8-vector,+vsx,-power9-vector,-qpx" "unsafe-fp-math"="false" "use-soft-float"="false" } + Index: vendor/llvm/dist-release_70/test/CodeGen/X86/x86-shrink-wrap-unwind.ll =================================================================== --- vendor/llvm/dist-release_70/test/CodeGen/X86/x86-shrink-wrap-unwind.ll (revision 338377) +++ vendor/llvm/dist-release_70/test/CodeGen/X86/x86-shrink-wrap-unwind.ll (revision 338378) @@ -1,326 +1,327 @@ ; RUN: llc %s -o - | FileCheck %s ; ; Note: This test cannot be merged with the shrink-wrapping tests ; because the booleans set on the command line take precedence on ; the target logic that disable shrink-wrapping. target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "x86_64-apple-macosx" ; This test checks that we do not use shrink-wrapping when ; the function does not have any frame pointer and may unwind. ; This is a workaround for a limitation in the emission of ; the CFI directives, that are not correct in such case. ; PR25614 ; ; No shrink-wrapping should occur here, until the CFI information are fixed. ; CHECK-LABEL: framelessUnwind: ; ; Prologue code. ; (What we push does not matter. It should be some random sratch register.) ; CHECK: pushq ; ; Compare the arguments and jump to exit. ; After the prologue is set. ; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] ; CHECK-NEXT: cmpl %esi, %edi ; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] ; ; Store %a in the alloca. ; CHECK: movl [[ARG0CPY]], 4(%rsp) ; Set the alloca address in the second argument. ; CHECK-NEXT: leaq 4(%rsp), %rsi ; Set the first argument to zero. ; CHECK-NEXT: xorl %edi, %edi ; CHECK-NEXT: callq _doSomething ; ; CHECK: [[EXIT_LABEL]]: ; ; Without shrink-wrapping, epilogue is in the exit block. ; Epilogue code. (What we pop does not matter.) ; CHECK-NEXT: popq ; ; CHECK-NEXT: retq define i32 @framelessUnwind(i32 %a, i32 %b) #0 { %tmp = alloca i32, align 4 %tmp2 = icmp slt i32 %a, %b br i1 %tmp2, label %true, label %false true: store i32 %a, i32* %tmp, align 4 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) br label %false false: %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] ret i32 %tmp.0 } declare i32 @doSomething(i32, i32*) attributes #0 = { "no-frame-pointer-elim"="false" } ; Shrink-wrapping should occur here. We have a frame pointer. ; CHECK-LABEL: frameUnwind: ; ; Compare the arguments and jump to exit. ; No prologue needed. ; ; Compare the arguments and jump to exit. ; After the prologue is set. ; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] ; CHECK-NEXT: cmpl %esi, %edi ; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] ; ; Prologue code. ; CHECK: pushq %rbp ; CHECK: movq %rsp, %rbp ; ; Store %a in the alloca. ; CHECK: movl [[ARG0CPY]], -4(%rbp) ; Set the alloca address in the second argument. ; CHECK-NEXT: leaq -4(%rbp), %rsi ; Set the first argument to zero. ; CHECK-NEXT: xorl %edi, %edi ; CHECK-NEXT: callq _doSomething ; ; Epilogue code. (What we pop does not matter.) ; CHECK: popq %rbp ; ; CHECK: [[EXIT_LABEL]]: ; CHECK-NEXT: retq define i32 @frameUnwind(i32 %a, i32 %b) #1 { %tmp = alloca i32, align 4 %tmp2 = icmp slt i32 %a, %b br i1 %tmp2, label %true, label %false true: store i32 %a, i32* %tmp, align 4 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) br label %false false: %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] ret i32 %tmp.0 } attributes #1 = { "no-frame-pointer-elim"="true" } ; Shrink-wrapping should occur here. We do not have to unwind. ; CHECK-LABEL: framelessnoUnwind: ; ; Compare the arguments and jump to exit. ; No prologue needed. ; ; Compare the arguments and jump to exit. ; After the prologue is set. ; CHECK: movl %edi, [[ARG0CPY:%e[a-z]+]] ; CHECK-NEXT: cmpl %esi, %edi ; CHECK-NEXT: jge [[EXIT_LABEL:LBB[0-9_]+]] ; ; Prologue code. ; (What we push does not matter. It should be some random sratch register.) ; CHECK: pushq ; ; Store %a in the alloca. ; CHECK: movl [[ARG0CPY]], 4(%rsp) ; Set the alloca address in the second argument. ; CHECK-NEXT: leaq 4(%rsp), %rsi ; Set the first argument to zero. ; CHECK-NEXT: xorl %edi, %edi ; CHECK-NEXT: callq _doSomething ; ; Epilogue code. ; CHECK-NEXT: addq ; ; CHECK: [[EXIT_LABEL]]: ; CHECK-NEXT: retq define i32 @framelessnoUnwind(i32 %a, i32 %b) #2 { %tmp = alloca i32, align 4 %tmp2 = icmp slt i32 %a, %b br i1 %tmp2, label %true, label %false true: store i32 %a, i32* %tmp, align 4 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp) br label %false false: %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ] ret i32 %tmp.0 } attributes #2 = { "no-frame-pointer-elim"="false" nounwind } ; Check that we generate correct code for segmented stack. ; We used to emit the code at the entry point of the function ; instead of just before the prologue. ; For now, shrink-wrapping is disabled on segmented stack functions: PR26107. ; ; CHECK-LABEL: segmentedStack: ; CHECK: cmpq ; CHECK-NEXT: ja [[ENTRY_LABEL:LBB[0-9_]+]] ; ; CHECK: callq ___morestack ; CHECK-NEXT: retq ; ; CHECK: [[ENTRY_LABEL]]: ; Prologue ; CHECK: push ; ; In PR26107, we use to drop these two basic blocks, because ; the segmentedStack entry block was jumping directly to ; the place where the prologue is actually needed, which is ; the call to memcmp. ; Then, those two basic blocks did not have any predecessors ; anymore and were removed. ; ; Check if vk1 is null ; CHECK: testq %rdi, %rdi ; CHECK-NEXT: je [[STRINGS_EQUAL:LBB[0-9_]+]] ; ; Check if vk2 is null ; CHECK: testq %rsi, %rsi ; CHECK-NEXT: je [[STRINGS_EQUAL]] ; ; CHECK: [[STRINGS_EQUAL]] ; CHECK: popq define zeroext i1 @segmentedStack(i8* readonly %vk1, i8* readonly %vk2, i64 %key_size) #5 { entry: %cmp.i = icmp eq i8* %vk1, null %cmp1.i = icmp eq i8* %vk2, null %brmerge.i = or i1 %cmp.i, %cmp1.i %cmp1.mux.i = and i1 %cmp.i, %cmp1.i br i1 %brmerge.i, label %__go_ptr_strings_equal.exit, label %if.end4.i if.end4.i: ; preds = %entry %tmp = getelementptr inbounds i8, i8* %vk1, i64 8 %tmp1 = bitcast i8* %tmp to i64* %tmp2 = load i64, i64* %tmp1, align 8 %tmp3 = getelementptr inbounds i8, i8* %vk2, i64 8 %tmp4 = bitcast i8* %tmp3 to i64* %tmp5 = load i64, i64* %tmp4, align 8 %cmp.i.i = icmp eq i64 %tmp2, %tmp5 br i1 %cmp.i.i, label %land.rhs.i.i, label %__go_ptr_strings_equal.exit land.rhs.i.i: ; preds = %if.end4.i %tmp6 = bitcast i8* %vk2 to i8** %tmp7 = load i8*, i8** %tmp6, align 8 %tmp8 = bitcast i8* %vk1 to i8** %tmp9 = load i8*, i8** %tmp8, align 8 %call.i.i = tail call i32 @memcmp(i8* %tmp9, i8* %tmp7, i64 %tmp2) #5 %cmp4.i.i = icmp eq i32 %call.i.i, 0 br label %__go_ptr_strings_equal.exit __go_ptr_strings_equal.exit: ; preds = %land.rhs.i.i, %if.end4.i, %entry %retval.0.i = phi i1 [ %cmp1.mux.i, %entry ], [ false, %if.end4.i ], [ %cmp4.i.i, %land.rhs.i.i ] ret i1 %retval.0.i } ; Function Attrs: nounwind readonly declare i32 @memcmp(i8* nocapture, i8* nocapture, i64) #5 attributes #5 = { nounwind readonly ssp uwtable "split-stack" } ; Check that correctly take into account the jumps to landing pad. ; We used to consider function that may throw like regular ; function calls. ; Therefore, in this example, we were happily inserting the epilogue ; right after the call to throw_exception. Because of that we would not ; execute the epilogue when an execption occur and bad things will ; happen. ; PR36513 ; ; CHECK-LABEL: with_nounwind: ; Prologue ; CHECK: push ; ; Jump to throw_exception: +; CHECK-NEXT: .cfi_def_cfa_offset ; CHECK-NEXT: testb $1, %dil ; CHECK-NEXT: jne [[THROW_LABEL:LBB[0-9_]+]] ; Else return exit ; CHECK: popq ; CHECK-NEXT: retq ; ; CHECK-NEXT: [[THROW_LABEL]]: ; CHECK: callq _throw_exception ; Unreachable block... ; ; Epilogue must be after the landing pad. ; CHECK-NOT: popq ; ; Look for the landing pad label. ; CHECK: LBB{{[0-9_]+}}: ; Epilogue on the landing pad ; CHECK: popq ; CHECK-NEXT: retq define void @with_nounwind(i1 %cond) nounwind personality i32 (...)* @my_personality { entry: br i1 %cond, label %throw, label %return throw: invoke void @throw_exception() to label %unreachable unwind label %landing unreachable: unreachable landing: %pad = landingpad { i8*, i32 } catch i8* null ret void return: ret void } ; Check landing pad again. ; This time checks that we can shrink-wrap when the epilogue does not ; span accross several blocks. ; ; CHECK-LABEL: with_nounwind_same_succ: ; ; Jump to throw_exception: ; CHECK: testb $1, %dil ; CHECK-NEXT: je [[RET_LABEL:LBB[0-9_]+]] ; ; Prologue ; CHECK: push ; CHECK: callq _throw_exception ; ; Fallthrough label ; CHECK: [[FALLTHROUGH_LABEL:LBB[0-9_]+]] ; CHECK: nop ; CHECK: popq ; ; CHECK: [[RET_LABEL]] ; CHECK: retq ; ; Look for the landing pad label. ; CHECK: LBB{{[0-9_]+}}: ; Landing pad jumps to fallthrough ; CHECK: jmp [[FALLTHROUGH_LABEL]] define void @with_nounwind_same_succ(i1 %cond) nounwind personality i32 (...)* @my_personality2 { entry: br i1 %cond, label %throw, label %return throw: invoke void @throw_exception() to label %fallthrough unwind label %landing landing: %pad = landingpad { i8*, i32 } catch i8* null br label %fallthrough fallthrough: tail call void asm "nop", ""() br label %return return: ret void } declare void @throw_exception() declare i32 @my_personality(...) declare i32 @my_personality2(...) Index: vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs-diagnostics.s =================================================================== --- vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs-diagnostics.s (nonexistent) +++ vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs-diagnostics.s (revision 338378) @@ -0,0 +1,51 @@ +// RUN: not llvm-mc -triple aarch64 -mattr=+sve -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-SVE +// RUN: not llvm-mc -triple aarch64 -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSVE + + +// --------------------------------------------------------------------------// +// ID_AA64ZFR0_EL1 is read-only + +msr ID_AA64ZFR0_EL1, x3 +// CHECK-SVE: error: expected writable system register or pstate +// CHECK-SVE-NEXT: msr ID_AA64ZFR0_EL1, x3 + + +// --------------------------------------------------------------------------// +// Check that the other SVE registers are only readable/writable when +// the +sve attribute is set. + +mrs x3, ID_AA64ZFR0_EL1 +// CHECK-NOSVE: error: expected readable system register +// CHECK-NOSVE: mrs x3, ID_AA64ZFR0_EL1 + +mrs x3, ZCR_EL1 +// CHECK-NOSVE: error: expected readable system register +// CHECK-NOSVE-NEXT: mrs x3, ZCR_EL1 + +mrs x3, ZCR_EL2 +// CHECK-NOSVE: error: expected readable system register +// CHECK-NOSVE-NEXT: mrs x3, ZCR_EL2 + +mrs x3, ZCR_EL3 +// CHECK-NOSVE: error: expected readable system register +// CHECK-NOSVE-NEXT: mrs x3, ZCR_EL3 + +mrs x3, ZCR_EL12 +// CHECK-NOSVE: error: expected readable system register +// CHECK-NOSVE-NEXT: mrs x3, ZCR_EL12 + +msr ZCR_EL1, x3 +// CHECK-NOSVE: error: expected writable system register or pstate +// CHECK-NOSVE-NEXT: msr ZCR_EL1, x3 + +msr ZCR_EL2, x3 +// CHECK-NOSVE: error: expected writable system register or pstate +// CHECK-NOSVE-NEXT: msr ZCR_EL2, x3 + +msr ZCR_EL3, x3 +// CHECK-NOSVE: error: expected writable system register or pstate +// CHECK-NOSVE-NEXT: msr ZCR_EL3, x3 + +msr ZCR_EL12, x3 +// CHECK-NOSVE: error: expected writable system register or pstate +// CHECK-NOSVE-NEXT: msr ZCR_EL12, x3 Property changes on: vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs-diagnostics.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs.s =================================================================== --- vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs.s (nonexistent) +++ vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs.s (revision 338378) @@ -0,0 +1,62 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \ +// RUN: | llvm-objdump -d -mattr=+sve - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \ +// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN + +mrs x3, ID_AA64ZFR0_EL1 +// CHECK-INST: mrs x3, ID_AA64ZFR0_EL1 +// CHECK-ENCODING: [0x83,0x04,0x38,0xd5] +// CHECK-ERROR: expected readable system register +// CHECK-UNKNOWN: 83 04 38 d5 mrs x3, S3_0_C0_C4_4 + +mrs x3, ZCR_EL1 +// CHECK-INST: mrs x3, ZCR_EL1 +// CHECK-ENCODING: [0x03,0x12,0x38,0xd5] +// CHECK-ERROR: expected readable system register +// CHECK-UNKNOWN: 03 12 38 d5 mrs x3, S3_0_C1_C2_0 + +mrs x3, ZCR_EL2 +// CHECK-INST: mrs x3, ZCR_EL2 +// CHECK-ENCODING: [0x03,0x12,0x3c,0xd5] +// CHECK-ERROR: expected readable system register +// CHECK-UNKNOWN: 03 12 3c d5 mrs x3, S3_4_C1_C2_0 + +mrs x3, ZCR_EL3 +// CHECK-INST: mrs x3, ZCR_EL3 +// CHECK-ENCODING: [0x03,0x12,0x3e,0xd5] +// CHECK-ERROR: expected readable system register +// CHECK-UNKNOWN: 03 12 3e d5 mrs x3, S3_6_C1_C2_0 + +mrs x3, ZCR_EL12 +// CHECK-INST: mrs x3, ZCR_EL12 +// CHECK-ENCODING: [0x03,0x12,0x3d,0xd5] +// CHECK-ERROR: expected readable system register +// CHECK-UNKNOWN: 03 12 3d d5 mrs x3, S3_5_C1_C2_0 + +msr ZCR_EL1, x3 +// CHECK-INST: msr ZCR_EL1, x3 +// CHECK-ENCODING: [0x03,0x12,0x18,0xd5] +// CHECK-ERROR: expected writable system register or pstate +// CHECK-UNKNOWN: 03 12 18 d5 msr S3_0_C1_C2_0, x3 + +msr ZCR_EL2, x3 +// CHECK-INST: msr ZCR_EL2, x3 +// CHECK-ENCODING: [0x03,0x12,0x1c,0xd5] +// CHECK-ERROR: expected writable system register or pstate +// CHECK-UNKNOWN: 03 12 1c d5 msr S3_4_C1_C2_0, x3 + +msr ZCR_EL3, x3 +// CHECK-INST: msr ZCR_EL3, x3 +// CHECK-ENCODING: [0x03,0x12,0x1e,0xd5] +// CHECK-ERROR: expected writable system register or pstate +// CHECK-UNKNOWN: 03 12 1e d5 msr S3_6_C1_C2_0, x3 + +msr ZCR_EL12, x3 +// CHECK-INST: msr ZCR_EL12, x3 +// CHECK-ENCODING: [0x03,0x12,0x1d,0xd5] +// CHECK-ERROR: expected writable system register or pstate +// CHECK-UNKNOWN: 03 12 1d d5 msr S3_5_C1_C2_0, x3 Property changes on: vendor/llvm/dist-release_70/test/MC/AArch64/SVE/system-regs.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/llvm/dist-release_70/test/MC/X86/pr37425.s =================================================================== --- vendor/llvm/dist-release_70/test/MC/X86/pr37425.s (revision 338377) +++ vendor/llvm/dist-release_70/test/MC/X86/pr37425.s (revision 338378) @@ -1,16 +1,20 @@ -// RUN: llvm-mc -triple x86_64-unknown-unknown -defsym=ERR=0 %s -o - | FileCheck %s -// RUN: not llvm-mc -triple x86_64-unknown-unknown -defsym=ERR=1 %s -o - 2>&1 | FileCheck --check-prefix=ERR %s +// RUN: llvm-mc -triple x86_64-unknown-unknown %s -o - | FileCheck %s // CHECK-NOT: .set var_xdata var_xdata = %rcx // CHECK: xorq %rcx, %rcx xorq var_xdata, var_xdata -.if (ERR==1) -// ERR: [[@LINE+2]]:15: error: unknown token in expression in '.set' directive -// ERR: [[@LINE+1]]:15: error: missing expression in '.set' directive -.set err_var, %rcx -.endif +// CHECK: .data +// CHECK-NEXT: .byte 1 +.data +.if var_xdata == %rax + .byte 0 +.elseif var_xdata == %rcx + .byte 1 +.else + .byte 2 +.endif Index: vendor/llvm/dist-release_70/test/Transforms/CodeGenPrepare/X86/multi-extension.ll =================================================================== --- vendor/llvm/dist-release_70/test/Transforms/CodeGenPrepare/X86/multi-extension.ll (nonexistent) +++ vendor/llvm/dist-release_70/test/Transforms/CodeGenPrepare/X86/multi-extension.ll (revision 338378) @@ -0,0 +1,25 @@ +; RUN: opt < %s -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.13.0" + +declare void @bar(i64) + +@b = global i16 0, align 2 + +; This test case is extracted from PR38125. +; %or is reachable by both a sext and zext that are going to be promoted. +; It ensures correct operation on PromotedInsts. + +; CHECK: %promoted = trunc i32 %or to i16 +; CHECK-NEXT: %c = sext i16 %promoted to i64 +define i32 @foo(i16 %kkk) { +entry: + %t4 = load i16, i16* @b, align 2 + %conv4 = zext i16 %t4 to i32 + %or = or i16 %kkk, %t4 + %c = sext i16 %or to i64 + call void @bar(i64 %c) + %t5 = and i16 %or, 5 + %z = zext i16 %t5 to i32 + ret i32 %z +} Index: vendor/llvm/dist-release_70/utils/lit/tests/Inputs/shtest-format/lit.cfg =================================================================== --- vendor/llvm/dist-release_70/utils/lit/tests/Inputs/shtest-format/lit.cfg (revision 338377) +++ vendor/llvm/dist-release_70/utils/lit/tests/Inputs/shtest-format/lit.cfg (revision 338378) @@ -1,9 +1,9 @@ import lit.formats config.name = 'shtest-format' config.suffixes = ['.txt'] config.test_format = lit.formats.ShTest() config.test_source_root = None config.test_exec_root = None config.target_triple = 'x86_64-unknown-unknown' config.available_features.add('a-present-feature') -config.substitutions.append(('%{python}', "'%s'" % (sys.executable))) +config.substitutions.append(('%{python}', '"%s"' % (sys.executable)))