Index: vendor/llvm/dist/cmake/modules/DetermineGCCCompatible.cmake =================================================================== --- vendor/llvm/dist/cmake/modules/DetermineGCCCompatible.cmake (revision 313055) +++ vendor/llvm/dist/cmake/modules/DetermineGCCCompatible.cmake (revision 313056) @@ -1,11 +1,13 @@ # Determine if the compiler has GCC-compatible command-line syntax. if(NOT DEFINED LLVM_COMPILER_IS_GCC_COMPATIBLE) if(CMAKE_COMPILER_IS_GNUCXX) set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) elseif( MSVC ) set(LLVM_COMPILER_IS_GCC_COMPATIBLE OFF) elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) + elseif( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel" ) + set(LLVM_COMPILER_IS_GCC_COMPATIBLE ON) endif() endif() Index: vendor/llvm/dist/include/llvm/CodeGen/AsmPrinter.h =================================================================== --- vendor/llvm/dist/include/llvm/CodeGen/AsmPrinter.h (revision 313055) +++ vendor/llvm/dist/include/llvm/CodeGen/AsmPrinter.h (revision 313056) @@ -1,595 +1,601 @@ //===-- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework --------*- 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 a class to be used as the base class for target specific // asm writers. This class primarily handles common functionality used by // all asm writers. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_ASMPRINTER_H #define LLVM_CODEGEN_ASMPRINTER_H #include "llvm/ADT/MapVector.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/DwarfStringPoolEntry.h" #include "llvm/IR/InlineAsm.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { class AsmPrinterHandler; class BlockAddress; class ByteStreamer; class GCStrategy; class Constant; class ConstantArray; class DIE; class DIEAbbrev; class GCMetadataPrinter; class GlobalIndirectSymbol; class GlobalValue; class GlobalVariable; class MachineBasicBlock; class MachineFunction; class MachineInstr; class MachineLocation; class MachineLoopInfo; class MachineLoop; class MachineConstantPoolValue; class MachineJumpTableInfo; class MachineModuleInfo; class MCAsmInfo; class MCCFIInstruction; class MCContext; class MCExpr; class MCInst; class MCSection; class MCStreamer; class MCSubtargetInfo; class MCSymbol; class MCTargetOptions; class MDNode; class DwarfDebug; class Mangler; class TargetLoweringObjectFile; class DataLayout; class TargetMachine; /// This class is intended to be used as a driving class for all asm writers. class AsmPrinter : public MachineFunctionPass { public: /// Target machine description. /// TargetMachine &TM; /// Target Asm Printer information. /// const MCAsmInfo *MAI; /// This is the context for the output file that we are streaming. This owns /// all of the global MC-related objects for the generated translation unit. MCContext &OutContext; /// This is the MCStreamer object for the file we are generating. This /// contains the transient state for the current translation unit that we are /// generating (such as the current section etc). std::unique_ptr OutStreamer; /// The current machine function. const MachineFunction *MF; /// This is a pointer to the current MachineModuleInfo. MachineModuleInfo *MMI; /// The symbol for the current function. This is recalculated at the beginning /// of each call to runOnMachineFunction(). /// MCSymbol *CurrentFnSym; /// The symbol used to represent the start of the current function for the /// purpose of calculating its size (e.g. using the .size directive). By /// default, this is equal to CurrentFnSym. MCSymbol *CurrentFnSymForSize; /// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of /// its number of uses by other globals. typedef std::pair GOTEquivUsePair; MapVector GlobalGOTEquivs; private: MCSymbol *CurrentFnBegin; MCSymbol *CurrentFnEnd; MCSymbol *CurExceptionSym; // The garbage collection metadata printer table. void *GCMetadataPrinters; // Really a DenseMap. /// Emit comments in assembly output if this is true. /// bool VerboseAsm; static char ID; /// If VerboseAsm is set, a pointer to the loop info for this function. MachineLoopInfo *LI; struct HandlerInfo { AsmPrinterHandler *Handler; const char *TimerName; const char *TimerDescription; const char *TimerGroupName; const char *TimerGroupDescription; HandlerInfo(AsmPrinterHandler *Handler, const char *TimerName, const char *TimerDescription, const char *TimerGroupName, const char *TimerGroupDescription) : Handler(Handler), TimerName(TimerName), TimerDescription(TimerDescription), TimerGroupName(TimerGroupName), TimerGroupDescription(TimerGroupDescription) {} }; /// A vector of all debug/EH info emitters we should use. This vector /// maintains ownership of the emitters. SmallVector Handlers; /// If the target supports dwarf debug info, this pointer is non-null. DwarfDebug *DD; /// If the current module uses dwarf CFI annotations strictly for debugging. bool isCFIMoveForDebugging; protected: explicit AsmPrinter(TargetMachine &TM, std::unique_ptr Streamer); public: ~AsmPrinter() override; DwarfDebug *getDwarfDebug() { return DD; } DwarfDebug *getDwarfDebug() const { return DD; } uint16_t getDwarfVersion() const; void setDwarfVersion(uint16_t Version); bool isPositionIndependent() const; /// Return true if assembly output should contain comments. /// bool isVerbose() const { return VerboseAsm; } /// Return a unique ID for the current function. /// unsigned getFunctionNumber() const; MCSymbol *getFunctionBegin() const { return CurrentFnBegin; } MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } MCSymbol *getCurExceptionSym(); /// Return information about object file lowering. const TargetLoweringObjectFile &getObjFileLowering() const; /// Return information about data layout. const DataLayout &getDataLayout() const; /// Return the pointer size from the TargetMachine unsigned getPointerSize() const; /// Return information about subtarget. const MCSubtargetInfo &getSubtargetInfo() const; void EmitToStreamer(MCStreamer &S, const MCInst &Inst); /// Return the current section we are emitting to. const MCSection *getCurrentSection() const; void getNameWithPrefix(SmallVectorImpl &Name, const GlobalValue *GV) const; MCSymbol *getSymbol(const GlobalValue *GV) const; //===------------------------------------------------------------------===// // XRay instrumentation implementation. //===------------------------------------------------------------------===// public: // This describes the kind of sled we're storing in the XRay table. enum class SledKind : uint8_t { FUNCTION_ENTER = 0, FUNCTION_EXIT = 1, TAIL_CALL = 2, }; // The table will contain these structs that point to the sled, the function // containing the sled, and what kind of sled (and whether they should always // be instrumented). struct XRayFunctionEntry { const MCSymbol *Sled; const MCSymbol *Function; SledKind Kind; bool AlwaysInstrument; const class Function *Fn; void emit(int, MCStreamer *, const MCSymbol *) const; }; // All the sleds to be emitted. std::vector Sleds; // Helper function to record a given XRay sled. void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind); /// Emit a table with all XRay instrumentation points. void emitXRayTable(); //===------------------------------------------------------------------===// // MachineFunctionPass Implementation. //===------------------------------------------------------------------===// /// Record analysis usage. /// void getAnalysisUsage(AnalysisUsage &AU) const override; /// Set up the AsmPrinter when we are working on a new module. If your pass /// overrides this, it must make sure to explicitly call this implementation. bool doInitialization(Module &M) override; /// Shut down the asmprinter. If you override this in your pass, you must make /// sure to call it explicitly. bool doFinalization(Module &M) override; /// Emit the specified function out to the OutStreamer. bool runOnMachineFunction(MachineFunction &MF) override { SetupMachineFunction(MF); EmitFunctionBody(); return false; } //===------------------------------------------------------------------===// // Coarse grained IR lowering routines. //===------------------------------------------------------------------===// /// This should be called when a new MachineFunction is being processed from /// runOnMachineFunction. void SetupMachineFunction(MachineFunction &MF); /// This method emits the body and trailer for a function. void EmitFunctionBody(); void emitCFIInstruction(const MachineInstr &MI); void emitFrameAlloc(const MachineInstr &MI); enum CFIMoveType { CFI_M_None, CFI_M_EH, CFI_M_Debug }; CFIMoveType needsCFIMoves(); /// Returns false if needsCFIMoves() == CFI_M_EH for any function /// in the module. bool needsOnlyDebugCFIMoves() const { return isCFIMoveForDebugging; } bool needsSEHMoves(); /// Print to the current output stream assembly representations of the /// constants in the constant pool MCP. This is used to print out constants /// which have been "spilled to memory" by the code generator. /// virtual void EmitConstantPool(); /// Print assembly representations of the jump tables used by the current /// function to the current output stream. /// virtual void EmitJumpTableInfo(); /// Emit the specified global variable to the .s file. virtual void EmitGlobalVariable(const GlobalVariable *GV); /// Check to see if the specified global is a special global used by LLVM. If /// so, emit it and return true, otherwise do nothing and return false. bool EmitSpecialLLVMGlobal(const GlobalVariable *GV); /// Emit an alignment directive to the specified power of two boundary. For /// example, if you pass in 3 here, you will get an 8 byte alignment. If a /// global value is specified, and if that global has an explicit alignment /// requested, it will override the alignment request if required for /// correctness. /// void EmitAlignment(unsigned NumBits, const GlobalObject *GO = nullptr) const; /// Lower the specified LLVM Constant to an MCExpr. virtual const MCExpr *lowerConstant(const Constant *CV); /// \brief Print a general LLVM constant to the .s file. void EmitGlobalConstant(const DataLayout &DL, const Constant *CV); /// \brief Unnamed constant global variables solely contaning a pointer to /// another globals variable act like a global variable "proxy", or GOT /// equivalents, i.e., it's only used to hold the address of the latter. One /// optimization is to replace accesses to these proxies by using the GOT /// entry for the final global instead. Hence, we select GOT equivalent /// candidates among all the module global variables, avoid emitting them /// unnecessarily and finally replace references to them by pc relative /// accesses to GOT entries. void computeGlobalGOTEquivs(Module &M); /// \brief Constant expressions using GOT equivalent globals may not be /// eligible for PC relative GOT entry conversion, in such cases we need to /// emit the proxies we previously omitted in EmitGlobalVariable. void emitGlobalGOTEquivs(); //===------------------------------------------------------------------===// // Overridable Hooks //===------------------------------------------------------------------===// // Targets can, or in the case of EmitInstruction, must implement these to // customize output. /// This virtual method can be overridden by targets that want to emit /// something at the start of their file. virtual void EmitStartOfAsmFile(Module &) {} /// This virtual method can be overridden by targets that want to emit /// something at the end of their file. virtual void EmitEndOfAsmFile(Module &) {} /// Targets can override this to emit stuff before the first basic block in /// the function. virtual void EmitFunctionBodyStart() {} /// Targets can override this to emit stuff after the last basic block in the /// function. virtual void EmitFunctionBodyEnd() {} /// Targets can override this to emit stuff at the start of a basic block. /// By default, this method prints the label for the specified /// MachineBasicBlock, an alignment (if present) and a comment describing it /// if appropriate. virtual void EmitBasicBlockStart(const MachineBasicBlock &MBB) const; /// Targets can override this to emit stuff at the end of a basic block. virtual void EmitBasicBlockEnd(const MachineBasicBlock &MBB) {} /// Targets should implement this to emit instructions. virtual void EmitInstruction(const MachineInstr *) { llvm_unreachable("EmitInstruction not implemented"); } /// Return the symbol for the specified constant pool entry. virtual MCSymbol *GetCPISymbol(unsigned CPID) const; virtual void EmitFunctionEntryLabel(); virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV); /// Targets can override this to change how global constants that are part of /// a C++ static/global constructor list are emitted. virtual void EmitXXStructor(const DataLayout &DL, const Constant *CV) { EmitGlobalConstant(DL, CV); } /// Return true if the basic block has exactly one predecessor and the control /// transfer mechanism between the predecessor and this block is a /// fall-through. virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const; /// Targets can override this to customize the output of IMPLICIT_DEF /// instructions in verbose mode. virtual void emitImplicitDef(const MachineInstr *MI) const; //===------------------------------------------------------------------===// // Symbol Lowering Routines. //===------------------------------------------------------------------===// public: MCSymbol *createTempSymbol(const Twine &Name) const; /// Return the MCSymbol for a private symbol with global value name as its /// base, with the specified suffix. MCSymbol *getSymbolWithGlobalValueBase(const GlobalValue *GV, StringRef Suffix) const; /// Return the MCSymbol for the specified ExternalSymbol. MCSymbol *GetExternalSymbolSymbol(StringRef Sym) const; /// Return the symbol for the specified jump table entry. MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const; /// Return the symbol for the specified jump table .set /// FIXME: privatize to AsmPrinter. MCSymbol *GetJTSetSymbol(unsigned UID, unsigned MBBID) const; /// Return the MCSymbol used to satisfy BlockAddress uses of the specified /// basic block. MCSymbol *GetBlockAddressSymbol(const BlockAddress *BA) const; MCSymbol *GetBlockAddressSymbol(const BasicBlock *BB) const; //===------------------------------------------------------------------===// // Emission Helper Routines. //===------------------------------------------------------------------===// public: /// This is just convenient handler for printing offsets. void printOffset(int64_t Offset, raw_ostream &OS) const; /// Emit a byte directive and value. /// void EmitInt8(int Value) const; /// Emit a short directive and value. /// void EmitInt16(int Value) const; /// Emit a long directive and value. /// void EmitInt32(int Value) const; /// Emit something like ".long Hi-Lo" where the size in bytes of the directive /// is specified by Size and Hi/Lo specify the labels. This implicitly uses /// .set if it is available. void EmitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) const; /// Emit something like ".long Label+Offset" where the size in bytes of the /// directive is specified by Size and Label specifies the label. This /// implicitly uses .set if it is available. void EmitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset, unsigned Size, bool IsSectionRelative = false) const; /// Emit something like ".long Label" where the size in bytes of the directive /// is specified by Size and Label specifies the label. void EmitLabelReference(const MCSymbol *Label, unsigned Size, bool IsSectionRelative = false) const { EmitLabelPlusOffset(Label, 0, Size, IsSectionRelative); } //===------------------------------------------------------------------===// // Dwarf Emission Helper Routines //===------------------------------------------------------------------===// /// Emit the specified signed leb128 value. void EmitSLEB128(int64_t Value, const char *Desc = nullptr) const; /// Emit the specified unsigned leb128 value. void EmitULEB128(uint64_t Value, const char *Desc = nullptr, unsigned PadTo = 0) const; /// Emit a .byte 42 directive that corresponds to an encoding. If verbose /// assembly output is enabled, we output comments describing the encoding. /// Desc is a string saying what the encoding is specifying (e.g. "LSDA"). void EmitEncodingByte(unsigned Val, const char *Desc = nullptr) const; /// Return the size of the encoding in bytes. unsigned GetSizeOfEncodedValue(unsigned Encoding) const; /// Emit reference to a ttype global with a specified encoding. void EmitTTypeReference(const GlobalValue *GV, unsigned Encoding) const; /// Emit a reference to a symbol for use in dwarf. Different object formats /// represent this in different ways. Some use a relocation others encode /// the label offset in its section. void emitDwarfSymbolReference(const MCSymbol *Label, bool ForceOffset = false) const; /// Emit the 4-byte offset of a string from the start of its section. /// /// When possible, emit a DwarfStringPool section offset without any /// relocations, and without using the symbol. Otherwise, defers to \a /// emitDwarfSymbolReference(). void emitDwarfStringOffset(DwarfStringPoolEntryRef S) const; /// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified. virtual unsigned getISAEncoding() { return 0; } + /// Emit the directive and value for debug thread local expression + /// + /// \p Value - The value to emit. + /// \p Size - The size of the integer (in bytes) to emit. + virtual void EmitDebugValue(const MCExpr *Value, unsigned Size) const; + //===------------------------------------------------------------------===// // Dwarf Lowering Routines //===------------------------------------------------------------------===// /// \brief Emit frame instruction to describe the layout of the frame. void emitCFIInstruction(const MCCFIInstruction &Inst) const; /// \brief Emit Dwarf abbreviation table. template void emitDwarfAbbrevs(const T &Abbrevs) const { // For each abbreviation. for (const auto &Abbrev : Abbrevs) emitDwarfAbbrev(*Abbrev); // Mark end of abbreviations. EmitULEB128(0, "EOM(3)"); } void emitDwarfAbbrev(const DIEAbbrev &Abbrev) const; /// \brief Recursively emit Dwarf DIE tree. void emitDwarfDIE(const DIE &Die) const; //===------------------------------------------------------------------===// // Inline Asm Support //===------------------------------------------------------------------===// public: // These are hooks that targets can override to implement inline asm // support. These should probably be moved out of AsmPrinter someday. /// Print information related to the specified machine instr that is /// independent of the operand, and may be independent of the instr itself. /// This can be useful for portably encoding the comment character or other /// bits of target-specific knowledge into the asmstrings. The syntax used is /// ${:comment}. Targets can override this to add support for their own /// strange codes. virtual void PrintSpecial(const MachineInstr *MI, raw_ostream &OS, const char *Code) const; /// Print the specified operand of MI, an INLINEASM instruction, using the /// specified assembler variant. Targets should override this to format as /// appropriate. This method can return true if the operand is erroneous. virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS); /// Print the specified operand of MI, an INLINEASM instruction, using the /// specified assembler variant as an address. Targets should override this to /// format as appropriate. This method can return true if the operand is /// erroneous. virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &OS); /// Let the target do anything it needs to do before emitting inlineasm. /// \p StartInfo - the subtarget info before parsing inline asm virtual void emitInlineAsmStart() const; /// Let the target do anything it needs to do after emitting inlineasm. /// This callback can be used restore the original mode in case the /// inlineasm contains directives to switch modes. /// \p StartInfo - the original subtarget info before inline asm /// \p EndInfo - the final subtarget info after parsing the inline asm, /// or NULL if the value is unknown. virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, const MCSubtargetInfo *EndInfo) const; private: /// Private state for PrintSpecial() // Assign a unique ID to this machine instruction. mutable const MachineInstr *LastMI; mutable unsigned LastFn; mutable unsigned Counter; /// This method emits the header for the current function. virtual void EmitFunctionHeader(); /// Emit a blob of inline asm to the output streamer. void EmitInlineAsm(StringRef Str, const MCSubtargetInfo &STI, const MCTargetOptions &MCOptions, const MDNode *LocMDNode = nullptr, InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const; /// This method formats and emits the specified machine instruction that is an /// inline asm. void EmitInlineAsm(const MachineInstr *MI) const; //===------------------------------------------------------------------===// // Internal Implementation Details //===------------------------------------------------------------------===// /// This emits visibility information about symbol, if this is suported by the /// target. void EmitVisibility(MCSymbol *Sym, unsigned Visibility, bool IsDefinition = true) const; void EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; void EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, unsigned uid) const; void EmitLLVMUsedList(const ConstantArray *InitList); /// Emit llvm.ident metadata in an '.ident' directive. void EmitModuleIdents(Module &M); void EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor); GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &C); /// Emit GlobalAlias or GlobalIFunc. void emitGlobalIndirectSymbol(Module &M, const GlobalIndirectSymbol& GIS); }; } #endif Index: vendor/llvm/dist/include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- vendor/llvm/dist/include/llvm/CodeGen/SelectionDAGISel.h (revision 313055) +++ vendor/llvm/dist/include/llvm/CodeGen/SelectionDAGISel.h (revision 313056) @@ -1,314 +1,314 @@ //===-- llvm/CodeGen/SelectionDAGISel.h - Common Base Class------*- 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 SelectionDAGISel class, which is used as the common // base class for SelectionDAG-based instruction selectors. // //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_SELECTIONDAGISEL_H #define LLVM_CODEGEN_SELECTIONDAGISEL_H #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/IR/BasicBlock.h" #include "llvm/Pass.h" #include "llvm/Target/TargetSubtargetInfo.h" namespace llvm { class FastISel; class SelectionDAGBuilder; class SDValue; class MachineRegisterInfo; class MachineBasicBlock; class MachineFunction; class MachineInstr; class TargetLowering; class TargetLibraryInfo; class FunctionLoweringInfo; class ScheduleHazardRecognizer; class GCFunctionInfo; class ScheduleDAGSDNodes; class LoadInst; /// SelectionDAGISel - This is the common base class used for SelectionDAG-based /// pattern-matching instruction selectors. class SelectionDAGISel : public MachineFunctionPass { public: TargetMachine &TM; const TargetLibraryInfo *LibInfo; FunctionLoweringInfo *FuncInfo; MachineFunction *MF; MachineRegisterInfo *RegInfo; SelectionDAG *CurDAG; SelectionDAGBuilder *SDB; AliasAnalysis *AA; GCFunctionInfo *GFI; CodeGenOpt::Level OptLevel; const TargetInstrInfo *TII; const TargetLowering *TLI; static char ID; explicit SelectionDAGISel(TargetMachine &tm, CodeGenOpt::Level OL = CodeGenOpt::Default); ~SelectionDAGISel() override; const TargetLowering *getTargetLowering() const { return TLI; } void getAnalysisUsage(AnalysisUsage &AU) const override; bool runOnMachineFunction(MachineFunction &MF) override; virtual void EmitFunctionEntryCode() {} /// PreprocessISelDAG - This hook allows targets to hack on the graph before /// instruction selection starts. virtual void PreprocessISelDAG() {} /// PostprocessISelDAG() - This hook allows the target to hack on the graph /// right after selection. virtual void PostprocessISelDAG() {} /// Main hook for targets to transform nodes into machine nodes. virtual void Select(SDNode *N) = 0; /// SelectInlineAsmMemoryOperand - Select the specified address as a target /// addressing mode, according to the specified constraint. If this does /// not match or is not implemented, return true. The resultant operands /// (which will appear in the machine instruction) should be added to the /// OutOps vector. virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { return true; } /// IsProfitableToFold - Returns true if it's profitable to fold the specific /// operand node N of U during instruction selection that starts at Root. virtual bool IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const; /// IsLegalToFold - Returns true if the specific operand node N of /// U can be folded during instruction selection that starts at Root. /// FIXME: This is a static member function because the MSP430/X86 /// targets, which uses it during isel. This could become a proper member. static bool IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, CodeGenOpt::Level OptLevel, bool IgnoreChains = false); // Opcodes used by the DAG state machine: enum BuiltinOpcodes { OPC_Scope, OPC_RecordNode, OPC_RecordChild0, OPC_RecordChild1, OPC_RecordChild2, OPC_RecordChild3, OPC_RecordChild4, OPC_RecordChild5, OPC_RecordChild6, OPC_RecordChild7, OPC_RecordMemRef, OPC_CaptureGlueInput, OPC_MoveChild, OPC_MoveChild0, OPC_MoveChild1, OPC_MoveChild2, OPC_MoveChild3, OPC_MoveChild4, OPC_MoveChild5, OPC_MoveChild6, OPC_MoveChild7, OPC_MoveParent, OPC_CheckSame, OPC_CheckChild0Same, OPC_CheckChild1Same, OPC_CheckChild2Same, OPC_CheckChild3Same, OPC_CheckPatternPredicate, OPC_CheckPredicate, OPC_CheckOpcode, OPC_SwitchOpcode, OPC_CheckType, OPC_SwitchType, OPC_CheckChild0Type, OPC_CheckChild1Type, OPC_CheckChild2Type, OPC_CheckChild3Type, OPC_CheckChild4Type, OPC_CheckChild5Type, OPC_CheckChild6Type, OPC_CheckChild7Type, OPC_CheckInteger, OPC_CheckChild0Integer, OPC_CheckChild1Integer, OPC_CheckChild2Integer, OPC_CheckChild3Integer, OPC_CheckChild4Integer, OPC_CheckCondCode, OPC_CheckValueType, OPC_CheckComplexPat, OPC_CheckAndImm, OPC_CheckOrImm, OPC_CheckFoldableChainNode, OPC_EmitInteger, OPC_EmitRegister, OPC_EmitRegister2, OPC_EmitConvertToTarget, OPC_EmitMergeInputChains, OPC_EmitMergeInputChains1_0, OPC_EmitMergeInputChains1_1, OPC_EmitMergeInputChains1_2, OPC_EmitCopyToReg, OPC_EmitNodeXForm, OPC_EmitNode, // Space-optimized forms that implicitly encode number of result VTs. OPC_EmitNode0, OPC_EmitNode1, OPC_EmitNode2, OPC_MorphNodeTo, // Space-optimized forms that implicitly encode number of result VTs. OPC_MorphNodeTo0, OPC_MorphNodeTo1, OPC_MorphNodeTo2, OPC_CompleteMatch }; enum { OPFL_None = 0, // Node has no chain or glue input and isn't variadic. OPFL_Chain = 1, // Node has a chain input. OPFL_GlueInput = 2, // Node has a glue input. OPFL_GlueOutput = 4, // Node has a glue output. OPFL_MemRefs = 8, // Node gets accumulated MemRefs. OPFL_Variadic0 = 1<<4, // Node is variadic, root has 0 fixed inputs. OPFL_Variadic1 = 2<<4, // Node is variadic, root has 1 fixed inputs. OPFL_Variadic2 = 3<<4, // Node is variadic, root has 2 fixed inputs. OPFL_Variadic3 = 4<<4, // Node is variadic, root has 3 fixed inputs. OPFL_Variadic4 = 5<<4, // Node is variadic, root has 4 fixed inputs. OPFL_Variadic5 = 6<<4, // Node is variadic, root has 5 fixed inputs. OPFL_Variadic6 = 7<<4, // Node is variadic, root has 6 fixed inputs. OPFL_VariadicInfo = OPFL_Variadic6 }; /// getNumFixedFromVariadicInfo - Transform an EmitNode flags word into the /// number of fixed arity values that should be skipped when copying from the /// root. static inline int getNumFixedFromVariadicInfo(unsigned Flags) { return ((Flags&OPFL_VariadicInfo) >> 4)-1; } protected: /// DAGSize - Size of DAG being instruction selected. /// unsigned DAGSize; /// ReplaceUses - replace all uses of the old node F with the use /// of the new node T. void ReplaceUses(SDValue F, SDValue T) { CurDAG->ReplaceAllUsesOfValueWith(F, T); } /// ReplaceUses - replace all uses of the old nodes F with the use /// of the new nodes T. void ReplaceUses(const SDValue *F, const SDValue *T, unsigned Num) { CurDAG->ReplaceAllUsesOfValuesWith(F, T, Num); } /// ReplaceUses - replace all uses of the old node F with the use /// of the new node T. void ReplaceUses(SDNode *F, SDNode *T) { CurDAG->ReplaceAllUsesWith(F, T); } /// Replace all uses of \c F with \c T, then remove \c F from the DAG. void ReplaceNode(SDNode *F, SDNode *T) { CurDAG->ReplaceAllUsesWith(F, T); CurDAG->RemoveDeadNode(F); } /// SelectInlineAsmMemoryOperands - Calls to this are automatically generated /// by tblgen. Others should not call it. void SelectInlineAsmMemoryOperands(std::vector &Ops, const SDLoc &DL); public: // Calls to these predicates are generated by tblgen. bool CheckAndMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const; bool CheckOrMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const; /// CheckPatternPredicate - This function is generated by tblgen in the /// target. It runs the specified pattern predicate and returns true if it /// succeeds or false if it fails. The number is a private implementation /// detail to the code tblgen produces. virtual bool CheckPatternPredicate(unsigned PredNo) const { llvm_unreachable("Tblgen should generate the implementation of this!"); } /// CheckNodePredicate - This function is generated by tblgen in the target. /// It runs node predicate number PredNo and returns true if it succeeds or /// false if it fails. The number is a private implementation /// detail to the code tblgen produces. virtual bool CheckNodePredicate(SDNode *N, unsigned PredNo) const { llvm_unreachable("Tblgen should generate the implementation of this!"); } virtual bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N, unsigned PatternNo, SmallVectorImpl > &Result) { llvm_unreachable("Tblgen should generate the implementation of this!"); } virtual SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) { llvm_unreachable("Tblgen should generate this!"); } void SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned TableSize); /// \brief Return true if complex patterns for this target can mutate the /// DAG. virtual bool ComplexPatternFuncMutatesDAG() const { return false; } private: // Calls to these functions are generated by tblgen. void Select_INLINEASM(SDNode *N); void Select_READ_REGISTER(SDNode *N); void Select_WRITE_REGISTER(SDNode *N); void Select_UNDEF(SDNode *N); void CannotYetSelect(SDNode *N); private: void DoInstructionSelection(); SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTs, ArrayRef Ops, unsigned EmitNodeInfo); /// Prepares the landing pad to take incoming values or do other EH /// personality specific tasks. Returns true if the block should be /// instruction selected, false if no code should be emitted for it. bool PrepareEHLandingPad(); /// \brief Perform instruction selection on all basic blocks in the function. void SelectAllBasicBlocks(const Function &Fn); /// \brief Perform instruction selection on a single basic block, for /// instructions between \p Begin and \p End. \p HadTailCall will be set /// to true if a call in the block was translated as a tail call. void SelectBasicBlock(BasicBlock::const_iterator Begin, BasicBlock::const_iterator End, bool &HadTailCall); void FinishBasicBlock(); void CodeGenAndEmitDAG(); /// \brief Generate instructions for lowering the incoming arguments of the /// given function. void LowerArguments(const Function &F); void ComputeLiveOutVRegInfo(); /// Create the scheduler. If a specific scheduler was specified /// via the SchedulerRegistry, use it, otherwise select the /// one preferred by the target. /// ScheduleDAGSDNodes *CreateScheduler(); /// OpcodeOffset - This is a cache used to dispatch efficiently into isel /// state machines that start with a OPC_SwitchOpcode node. std::vector OpcodeOffset; void UpdateChains(SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl &ChainNodesMatched, + SmallVectorImpl &ChainNodesMatched, bool isMorphNodeTo); }; } #endif /* LLVM_CODEGEN_SELECTIONDAGISEL_H */ Index: vendor/llvm/dist/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- vendor/llvm/dist/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (revision 313055) +++ vendor/llvm/dist/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (revision 313056) @@ -1,2708 +1,2717 @@ //===-- AsmPrinter.cpp - Common AsmPrinter code ---------------------------===// // // 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 AsmPrinter class. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/AsmPrinter.h" #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" #include "WinException.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/GCMetadataPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; #define DEBUG_TYPE "asm-printer" static const char *const DWARFGroupName = "dwarf"; static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "emit"; static const char *const DbgTimerDescription = "Debug Info Emission"; static const char *const EHTimerName = "write_exception"; static const char *const EHTimerDescription = "DWARF Exception Writer"; static const char *const CodeViewLineTablesGroupName = "linetables"; static const char *const CodeViewLineTablesGroupDescription = "CodeView Line Tables"; STATISTIC(EmittedInsts, "Number of machine instrs printed"); char AsmPrinter::ID = 0; typedef DenseMap> gcp_map_type; static gcp_map_type &getGCMap(void *&P) { if (!P) P = new gcp_map_type(); return *(gcp_map_type*)P; } /// getGVAlignmentLog2 - Return the alignment to use for the specified global /// value in log2 form. This rounds up to the preferred alignment if possible /// and legal. static unsigned getGVAlignmentLog2(const GlobalValue *GV, const DataLayout &DL, unsigned InBits = 0) { unsigned NumBits = 0; if (const GlobalVariable *GVar = dyn_cast(GV)) NumBits = DL.getPreferredAlignmentLog(GVar); // If InBits is specified, round it to it. if (InBits > NumBits) NumBits = InBits; // If the GV has a specified alignment, take it into account. if (GV->getAlignment() == 0) return NumBits; unsigned GVAlign = Log2_32(GV->getAlignment()); // If the GVAlign is larger than NumBits, or if we are required to obey // NumBits because the GV has an assigned section, obey it. if (GVAlign > NumBits || GV->hasSection()) NumBits = GVAlign; return NumBits; } AsmPrinter::AsmPrinter(TargetMachine &tm, std::unique_ptr Streamer) : MachineFunctionPass(ID), TM(tm), MAI(tm.getMCAsmInfo()), OutContext(Streamer->getContext()), OutStreamer(std::move(Streamer)), isCFIMoveForDebugging(false), LastMI(nullptr), LastFn(0), Counter(~0U) { DD = nullptr; MMI = nullptr; LI = nullptr; MF = nullptr; CurExceptionSym = CurrentFnSym = CurrentFnSymForSize = nullptr; CurrentFnBegin = nullptr; CurrentFnEnd = nullptr; GCMetadataPrinters = nullptr; VerboseAsm = OutStreamer->isVerboseAsm(); } AsmPrinter::~AsmPrinter() { assert(!DD && Handlers.empty() && "Debug/EH info didn't get finalized"); if (GCMetadataPrinters) { gcp_map_type &GCMap = getGCMap(GCMetadataPrinters); delete &GCMap; GCMetadataPrinters = nullptr; } } bool AsmPrinter::isPositionIndependent() const { return TM.isPositionIndependent(); } /// getFunctionNumber - Return a unique ID for the current function. /// unsigned AsmPrinter::getFunctionNumber() const { return MF->getFunctionNumber(); } const TargetLoweringObjectFile &AsmPrinter::getObjFileLowering() const { return *TM.getObjFileLowering(); } const DataLayout &AsmPrinter::getDataLayout() const { return MMI->getModule()->getDataLayout(); } // Do not use the cached DataLayout because some client use it without a Module // (llvm-dsymutil, llvm-dwarfdump). unsigned AsmPrinter::getPointerSize() const { return TM.getPointerSize(); } const MCSubtargetInfo &AsmPrinter::getSubtargetInfo() const { assert(MF && "getSubtargetInfo requires a valid MachineFunction!"); return MF->getSubtarget(); } void AsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { S.EmitInstruction(Inst, getSubtargetInfo()); } /// getCurrentSection() - Return the current section we are emitting to. const MCSection *AsmPrinter::getCurrentSection() const { return OutStreamer->getCurrentSectionOnly(); } void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); MachineFunctionPass::getAnalysisUsage(AU); AU.addRequired(); AU.addRequired(); if (isVerbose()) AU.addRequired(); } bool AsmPrinter::doInitialization(Module &M) { MMI = getAnalysisIfAvailable(); // Initialize TargetLoweringObjectFile. const_cast(getObjFileLowering()) .Initialize(OutContext, TM); OutStreamer->InitSections(false); // Emit the version-min deplyment target directive if needed. // // FIXME: If we end up with a collection of these sorts of Darwin-specific // or ELF-specific things, it may make sense to have a platform helper class // that will work with the target helper class. For now keep it here, as the // alternative is duplicated code in each of the target asm printers that // use the directive, where it would need the same conditionalization // anyway. const Triple &TT = TM.getTargetTriple(); // If there is a version specified, Major will be non-zero. if (TT.isOSDarwin() && TT.getOSMajorVersion() != 0) { unsigned Major, Minor, Update; MCVersionMinType VersionType; if (TT.isWatchOS()) { VersionType = MCVM_WatchOSVersionMin; TT.getWatchOSVersion(Major, Minor, Update); } else if (TT.isTvOS()) { VersionType = MCVM_TvOSVersionMin; TT.getiOSVersion(Major, Minor, Update); } else if (TT.isMacOSX()) { VersionType = MCVM_OSXVersionMin; if (!TT.getMacOSXVersion(Major, Minor, Update)) Major = 0; } else { VersionType = MCVM_IOSVersionMin; TT.getiOSVersion(Major, Minor, Update); } if (Major != 0) OutStreamer->EmitVersionMin(VersionType, Major, Minor, Update); } // Allow the target to emit any magic that it wants at the start of the file. EmitStartOfAsmFile(M); // Very minimal debug info. It is ignored if we emit actual debug info. If we // don't, this at least helps the user find where a global came from. if (MAI->hasSingleParameterDotFile()) { // .file "foo.c" OutStreamer->EmitFileDirective(M.getModuleIdentifier()); } GCModuleInfo *MI = getAnalysisIfAvailable(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); for (auto &I : *MI) if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(*I)) MP->beginAssembly(M, *MI, *this); // Emit module-level inline asm if it exists. if (!M.getModuleInlineAsm().empty()) { // We're at the module level. Construct MCSubtarget from the default CPU // and target triple. std::unique_ptr STI(TM.getTarget().createMCSubtargetInfo( TM.getTargetTriple().str(), TM.getTargetCPU(), TM.getTargetFeatureString())); OutStreamer->AddComment("Start of file scope inline assembly"); OutStreamer->AddBlankLine(); EmitInlineAsm(M.getModuleInlineAsm()+"\n", OutContext.getSubtargetCopy(*STI), TM.Options.MCOptions); OutStreamer->AddComment("End of file scope inline assembly"); OutStreamer->AddBlankLine(); } if (MAI->doesSupportDebugInformation()) { bool EmitCodeView = MMI->getModule()->getCodeViewFlag(); if (EmitCodeView && (TM.getTargetTriple().isKnownWindowsMSVCEnvironment() || TM.getTargetTriple().isWindowsItaniumEnvironment())) { Handlers.push_back(HandlerInfo(new CodeViewDebug(this), DbgTimerName, DbgTimerDescription, CodeViewLineTablesGroupName, CodeViewLineTablesGroupDescription)); } if (!EmitCodeView || MMI->getModule()->getDwarfVersion()) { DD = new DwarfDebug(this, &M); DD->beginModule(); Handlers.push_back(HandlerInfo(DD, DbgTimerName, DbgTimerDescription, DWARFGroupName, DWARFGroupDescription)); } } switch (MAI->getExceptionHandlingType()) { case ExceptionHandling::SjLj: case ExceptionHandling::DwarfCFI: case ExceptionHandling::ARM: isCFIMoveForDebugging = true; if (MAI->getExceptionHandlingType() != ExceptionHandling::DwarfCFI) break; for (auto &F: M.getFunctionList()) { // If the module contains any function with unwind data, // .eh_frame has to be emitted. // Ignore functions that won't get emitted. if (!F.isDeclarationForLinker() && F.needsUnwindTableEntry()) { isCFIMoveForDebugging = false; break; } } break; default: isCFIMoveForDebugging = false; break; } EHStreamer *ES = nullptr; switch (MAI->getExceptionHandlingType()) { case ExceptionHandling::None: break; case ExceptionHandling::SjLj: case ExceptionHandling::DwarfCFI: ES = new DwarfCFIException(this); break; case ExceptionHandling::ARM: ES = new ARMException(this); break; case ExceptionHandling::WinEH: switch (MAI->getWinEHEncodingType()) { default: llvm_unreachable("unsupported unwinding information encoding"); case WinEH::EncodingType::Invalid: break; case WinEH::EncodingType::X86: case WinEH::EncodingType::Itanium: ES = new WinException(this); break; } break; } if (ES) Handlers.push_back(HandlerInfo(ES, EHTimerName, EHTimerDescription, DWARFGroupName, DWARFGroupDescription)); return false; } static bool canBeHidden(const GlobalValue *GV, const MCAsmInfo &MAI) { if (!MAI.hasWeakDefCanBeHiddenDirective()) return false; return canBeOmittedFromSymbolTable(GV); } void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const { GlobalValue::LinkageTypes Linkage = GV->getLinkage(); switch (Linkage) { case GlobalValue::CommonLinkage: case GlobalValue::LinkOnceAnyLinkage: case GlobalValue::LinkOnceODRLinkage: case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: if (MAI->hasWeakDefDirective()) { // .globl _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); if (!canBeHidden(GV, *MAI)) // .weak_definition _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_WeakDefinition); else OutStreamer->EmitSymbolAttribute(GVSym, MCSA_WeakDefAutoPrivate); } else if (MAI->hasLinkOnceDirective()) { // .globl _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); //NOTE: linkonce is handled by the section the symbol was assigned to. } else { // .weak _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Weak); } return; case GlobalValue::ExternalLinkage: // If external, declare as a global symbol: .globl _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global); return; case GlobalValue::PrivateLinkage: case GlobalValue::InternalLinkage: return; case GlobalValue::AppendingLinkage: case GlobalValue::AvailableExternallyLinkage: case GlobalValue::ExternalWeakLinkage: llvm_unreachable("Should never emit this"); } llvm_unreachable("Unknown linkage type!"); } void AsmPrinter::getNameWithPrefix(SmallVectorImpl &Name, const GlobalValue *GV) const { TM.getNameWithPrefix(Name, GV, getObjFileLowering().getMangler()); } MCSymbol *AsmPrinter::getSymbol(const GlobalValue *GV) const { return TM.getSymbol(GV); } /// EmitGlobalVariable - Emit the specified global variable to the .s file. void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { bool IsEmuTLSVar = TM.Options.EmulatedTLS && GV->isThreadLocal(); assert(!(IsEmuTLSVar && GV->hasCommonLinkage()) && "No emulated TLS variables in the common section"); // Never emit TLS variable xyz in emulated TLS model. // The initialization value is in __emutls_t.xyz instead of xyz. if (IsEmuTLSVar) return; if (GV->hasInitializer()) { // Check to see if this is a special global used by LLVM, if so, emit it. if (EmitSpecialLLVMGlobal(GV)) return; // Skip the emission of global equivalents. The symbol can be emitted later // on by emitGlobalGOTEquivs in case it turns out to be needed. if (GlobalGOTEquivs.count(getSymbol(GV))) return; if (isVerbose()) { // When printing the control variable __emutls_v.*, // we don't need to print the original TLS variable name. GV->printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, GV->getParent()); OutStreamer->GetCommentOS() << '\n'; } } MCSymbol *GVSym = getSymbol(GV); MCSymbol *EmittedSym = GVSym; // getOrCreateEmuTLSControlSym only creates the symbol with name and default // attributes. // GV's or GVSym's attributes will be used for the EmittedSym. EmitVisibility(EmittedSym, GV->getVisibility(), !GV->isDeclaration()); if (!GV->hasInitializer()) // External globals require no extra code. return; GVSym->redefineIfPossible(); if (GVSym->isDefined() || GVSym->isVariable()) report_fatal_error("symbol '" + Twine(GVSym->getName()) + "' is already defined"); if (MAI->hasDotTypeDotSizeDirective()) OutStreamer->EmitSymbolAttribute(EmittedSym, MCSA_ELF_TypeObject); SectionKind GVKind = TargetLoweringObjectFile::getKindForGlobal(GV, TM); const DataLayout &DL = GV->getParent()->getDataLayout(); uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); // If the alignment is specified, we *must* obey it. Overaligning a global // with a specified alignment is a prompt way to break globals emitted to // sections and expected to be contiguous (e.g. ObjC metadata). unsigned AlignLog = getGVAlignmentLog2(GV, DL); for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->setSymbolSize(GVSym, Size); } // Handle common symbols if (GVKind.isCommon()) { if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. unsigned Align = 1 << AlignLog; if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) Align = 0; // .comm _foo, 42, 4 OutStreamer->EmitCommonSymbol(GVSym, Size, Align); return; } // Determine to which section this global should be emitted. MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, TM); // If we have a bss global going to a section that supports the // zerofill directive, do so here. if (GVKind.isBSS() && MAI->hasMachoZeroFillDirective() && TheSection->isVirtualSection()) { if (Size == 0) Size = 1; // zerofill of 0 bytes is undefined. unsigned Align = 1 << AlignLog; EmitLinkage(GV, GVSym); // .zerofill __DATA, __bss, _foo, 400, 5 OutStreamer->EmitZerofill(TheSection, GVSym, Size, Align); return; } // If this is a BSS local symbol and we are emitting in the BSS // section use .lcomm/.comm directive. if (GVKind.isBSSLocal() && getObjFileLowering().getBSSSection() == TheSection) { if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. unsigned Align = 1 << AlignLog; // Use .lcomm only if it supports user-specified alignment. // Otherwise, while it would still be correct to use .lcomm in some // cases (e.g. when Align == 1), the external assembler might enfore // some -unknown- default alignment behavior, which could cause // spurious differences between external and integrated assembler. // Prefer to simply fall back to .local / .comm in this case. if (MAI->getLCOMMDirectiveAlignmentType() != LCOMM::NoAlignment) { // .lcomm _foo, 42 OutStreamer->EmitLocalCommonSymbol(GVSym, Size, Align); return; } if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) Align = 0; // .local _foo OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Local); // .comm _foo, 42, 4 OutStreamer->EmitCommonSymbol(GVSym, Size, Align); return; } // Handle thread local data for mach-o which requires us to output an // additional structure of data and mangle the original symbol so that we // can reference it later. // // TODO: This should become an "emit thread local global" method on TLOF. // All of this macho specific stuff should be sunk down into TLOFMachO and // stuff like "TLSExtraDataSection" should no longer be part of the parent // TLOF class. This will also make it more obvious that stuff like // MCStreamer::EmitTBSSSymbol is macho specific and only called from macho // specific code. if (GVKind.isThreadLocal() && MAI->hasMachoTBSSDirective()) { // Emit the .tbss symbol MCSymbol *MangSym = OutContext.getOrCreateSymbol(GVSym->getName() + Twine("$tlv$init")); if (GVKind.isThreadBSS()) { TheSection = getObjFileLowering().getTLSBSSSection(); OutStreamer->EmitTBSSSymbol(TheSection, MangSym, Size, 1 << AlignLog); } else if (GVKind.isThreadData()) { OutStreamer->SwitchSection(TheSection); EmitAlignment(AlignLog, GV); OutStreamer->EmitLabel(MangSym); EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); } OutStreamer->AddBlankLine(); // Emit the variable struct for the runtime. MCSection *TLVSect = getObjFileLowering().getTLSExtraDataSection(); OutStreamer->SwitchSection(TLVSect); // Emit the linkage here. EmitLinkage(GV, GVSym); OutStreamer->EmitLabel(GVSym); // Three pointers in size: // - __tlv_bootstrap - used to make sure support exists // - spare pointer, used when mapped by the runtime // - pointer to mangled symbol above with initializer unsigned PtrSize = DL.getPointerTypeSize(GV->getType()); OutStreamer->EmitSymbolValue(GetExternalSymbolSymbol("_tlv_bootstrap"), PtrSize); OutStreamer->EmitIntValue(0, PtrSize); OutStreamer->EmitSymbolValue(MangSym, PtrSize); OutStreamer->AddBlankLine(); return; } MCSymbol *EmittedInitSym = GVSym; OutStreamer->SwitchSection(TheSection); EmitLinkage(GV, EmittedInitSym); EmitAlignment(AlignLog, GV); OutStreamer->EmitLabel(EmittedInitSym); EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); if (MAI->hasDotTypeDotSizeDirective()) // .size foo, 42 OutStreamer->emitELFSize(EmittedInitSym, MCConstantExpr::create(Size, OutContext)); OutStreamer->AddBlankLine(); } +/// Emit the directive and value for debug thread local expression +/// +/// \p Value - The value to emit. +/// \p Size - The size of the integer (in bytes) to emit. +void AsmPrinter::EmitDebugValue(const MCExpr *Value, + unsigned Size) const { + OutStreamer->EmitValue(Value, Size); +} + /// EmitFunctionHeader - This method emits the header for the current /// function. void AsmPrinter::EmitFunctionHeader() { // Print out constants referenced by the function EmitConstantPool(); // Print the 'header' of function. const Function *F = MF->getFunction(); OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(F, TM)); EmitVisibility(CurrentFnSym, F->getVisibility()); EmitLinkage(F, CurrentFnSym); if (MAI->hasFunctionAlignment()) EmitAlignment(MF->getAlignment(), F); if (MAI->hasDotTypeDotSizeDirective()) OutStreamer->EmitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction); if (isVerbose()) { F->printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, F->getParent()); OutStreamer->GetCommentOS() << '\n'; } // Emit the prefix data. if (F->hasPrefixData()) EmitGlobalConstant(F->getParent()->getDataLayout(), F->getPrefixData()); // Emit the CurrentFnSym. This is a virtual function to allow targets to // do their wild and crazy things as required. EmitFunctionEntryLabel(); // If the function had address-taken blocks that got deleted, then we have // references to the dangling symbols. Emit them at the start of the function // so that we don't get references to undefined symbols. std::vector DeadBlockSyms; MMI->takeDeletedSymbolsForFunction(F, DeadBlockSyms); for (unsigned i = 0, e = DeadBlockSyms.size(); i != e; ++i) { OutStreamer->AddComment("Address taken block that was later removed"); OutStreamer->EmitLabel(DeadBlockSyms[i]); } if (CurrentFnBegin) { if (MAI->useAssignmentForEHBegin()) { MCSymbol *CurPos = OutContext.createTempSymbol(); OutStreamer->EmitLabel(CurPos); OutStreamer->EmitAssignment(CurrentFnBegin, MCSymbolRefExpr::create(CurPos, OutContext)); } else { OutStreamer->EmitLabel(CurrentFnBegin); } } // Emit pre-function debug and/or EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->beginFunction(MF); } // Emit the prologue data. if (F->hasPrologueData()) EmitGlobalConstant(F->getParent()->getDataLayout(), F->getPrologueData()); } /// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the /// function. This can be overridden by targets as required to do custom stuff. void AsmPrinter::EmitFunctionEntryLabel() { CurrentFnSym->redefineIfPossible(); // The function label could have already been emitted if two symbols end up // conflicting due to asm renaming. Detect this and emit an error. if (CurrentFnSym->isVariable()) report_fatal_error("'" + Twine(CurrentFnSym->getName()) + "' is a protected alias"); if (CurrentFnSym->isDefined()) report_fatal_error("'" + Twine(CurrentFnSym->getName()) + "' label emitted multiple times to assembly file"); return OutStreamer->EmitLabel(CurrentFnSym); } /// emitComments - Pretty-print comments for instructions. static void emitComments(const MachineInstr &MI, raw_ostream &CommentOS) { const MachineFunction *MF = MI.getParent()->getParent(); const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); // Check for spills and reloads int FI; const MachineFrameInfo &MFI = MF->getFrameInfo(); // We assume a single instruction only has a spill or reload, not // both. const MachineMemOperand *MMO; if (TII->isLoadFromStackSlotPostFE(MI, FI)) { if (MFI.isSpillSlotObjectIndex(FI)) { MMO = *MI.memoperands_begin(); CommentOS << MMO->getSize() << "-byte Reload\n"; } } else if (TII->hasLoadFromStackSlot(MI, MMO, FI)) { if (MFI.isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Reload\n"; } else if (TII->isStoreToStackSlotPostFE(MI, FI)) { if (MFI.isSpillSlotObjectIndex(FI)) { MMO = *MI.memoperands_begin(); CommentOS << MMO->getSize() << "-byte Spill\n"; } } else if (TII->hasStoreToStackSlot(MI, MMO, FI)) { if (MFI.isSpillSlotObjectIndex(FI)) CommentOS << MMO->getSize() << "-byte Folded Spill\n"; } // Check for spill-induced copies if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse)) CommentOS << " Reload Reuse\n"; } /// emitImplicitDef - This method emits the specified machine instruction /// that is an implicit def. void AsmPrinter::emitImplicitDef(const MachineInstr *MI) const { unsigned RegNo = MI->getOperand(0).getReg(); SmallString<128> Str; raw_svector_ostream OS(Str); OS << "implicit-def: " << PrintReg(RegNo, MF->getSubtarget().getRegisterInfo()); OutStreamer->AddComment(OS.str()); OutStreamer->AddBlankLine(); } static void emitKill(const MachineInstr *MI, AsmPrinter &AP) { std::string Str; raw_string_ostream OS(Str); OS << "kill:"; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &Op = MI->getOperand(i); assert(Op.isReg() && "KILL instruction must have only register operands"); OS << ' ' << PrintReg(Op.getReg(), AP.MF->getSubtarget().getRegisterInfo()) << (Op.isDef() ? "" : ""); } AP.OutStreamer->AddComment(OS.str()); AP.OutStreamer->AddBlankLine(); } /// emitDebugValueComment - This method handles the target-independent form /// of DBG_VALUE, returning true if it was able to do so. A false return /// means the target will need to handle MI in EmitInstruction. static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) { // This code handles only the 4-operand target-independent form. if (MI->getNumOperands() != 4) return false; SmallString<128> Str; raw_svector_ostream OS(Str); OS << "DEBUG_VALUE: "; const DILocalVariable *V = MI->getDebugVariable(); if (auto *SP = dyn_cast(V->getScope())) { StringRef Name = SP->getDisplayName(); if (!Name.empty()) OS << Name << ":"; } OS << V->getName(); const DIExpression *Expr = MI->getDebugExpression(); auto Fragment = Expr->getFragmentInfo(); if (Fragment) OS << " [fragment offset=" << Fragment->OffsetInBits << " size=" << Fragment->SizeInBits << "]"; OS << " <- "; // The second operand is only an offset if it's an immediate. bool Deref = MI->getOperand(0).isReg() && MI->getOperand(1).isImm(); int64_t Offset = Deref ? MI->getOperand(1).getImm() : 0; for (unsigned i = 0; i < Expr->getNumElements(); ++i) { uint64_t Op = Expr->getElement(i); if (Op == dwarf::DW_OP_LLVM_fragment) { // There can't be any operands after this in a valid expression break; } else if (Deref) { // We currently don't support extra Offsets or derefs after the first // one. Bail out early instead of emitting an incorrect comment OS << " [complex expression]"; AP.OutStreamer->emitRawComment(OS.str()); return true; } else if (Op == dwarf::DW_OP_deref) { Deref = true; continue; } uint64_t ExtraOffset = Expr->getElement(i++); if (Op == dwarf::DW_OP_plus) Offset += ExtraOffset; else { assert(Op == dwarf::DW_OP_minus); Offset -= ExtraOffset; } } // Register or immediate value. Register 0 means undef. if (MI->getOperand(0).isFPImm()) { APFloat APF = APFloat(MI->getOperand(0).getFPImm()->getValueAPF()); if (MI->getOperand(0).getFPImm()->getType()->isFloatTy()) { OS << (double)APF.convertToFloat(); } else if (MI->getOperand(0).getFPImm()->getType()->isDoubleTy()) { OS << APF.convertToDouble(); } else { // There is no good way to print long double. Convert a copy to // double. Ah well, it's only a comment. bool ignored; APF.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, &ignored); OS << "(long double) " << APF.convertToDouble(); } } else if (MI->getOperand(0).isImm()) { OS << MI->getOperand(0).getImm(); } else if (MI->getOperand(0).isCImm()) { MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/); } else { unsigned Reg; if (MI->getOperand(0).isReg()) { Reg = MI->getOperand(0).getReg(); } else { assert(MI->getOperand(0).isFI() && "Unknown operand type"); const TargetFrameLowering *TFI = AP.MF->getSubtarget().getFrameLowering(); Offset += TFI->getFrameIndexReference(*AP.MF, MI->getOperand(0).getIndex(), Reg); Deref = true; } if (Reg == 0) { // Suppress offset, it is not meaningful here. OS << "undef"; // NOTE: Want this comment at start of line, don't emit with AddComment. AP.OutStreamer->emitRawComment(OS.str()); return true; } if (Deref) OS << '['; OS << PrintReg(Reg, AP.MF->getSubtarget().getRegisterInfo()); } if (Deref) OS << '+' << Offset << ']'; // NOTE: Want this comment at start of line, don't emit with AddComment. AP.OutStreamer->emitRawComment(OS.str()); return true; } AsmPrinter::CFIMoveType AsmPrinter::needsCFIMoves() { if (MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI && MF->getFunction()->needsUnwindTableEntry()) return CFI_M_EH; if (MMI->hasDebugInfo()) return CFI_M_Debug; return CFI_M_None; } bool AsmPrinter::needsSEHMoves() { return MAI->usesWindowsCFI() && MF->getFunction()->needsUnwindTableEntry(); } void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && ExceptionHandlingType != ExceptionHandling::ARM) return; if (needsCFIMoves() == CFI_M_None) return; const std::vector &Instrs = MF->getFrameInstructions(); unsigned CFIIndex = MI.getOperand(0).getCFIIndex(); const MCCFIInstruction &CFI = Instrs[CFIIndex]; emitCFIInstruction(CFI); } void AsmPrinter::emitFrameAlloc(const MachineInstr &MI) { // The operands are the MCSymbol and the frame offset of the allocation. MCSymbol *FrameAllocSym = MI.getOperand(0).getMCSymbol(); int FrameOffset = MI.getOperand(1).getImm(); // Emit a symbol assignment. OutStreamer->EmitAssignment(FrameAllocSym, MCConstantExpr::create(FrameOffset, OutContext)); } /// EmitFunctionBody - This method emits the body and trailer for a /// function. void AsmPrinter::EmitFunctionBody() { EmitFunctionHeader(); // Emit target-specific gunk before the function body. EmitFunctionBodyStart(); bool ShouldPrintDebugScopes = MMI->hasDebugInfo(); // Print out code for the function. bool HasAnyRealCode = false; for (auto &MBB : *MF) { // Print a label for the basic block. EmitBasicBlockStart(MBB); for (auto &MI : MBB) { // Print the assembly for the instruction. if (!MI.isPosition() && !MI.isImplicitDef() && !MI.isKill() && !MI.isDebugValue()) { HasAnyRealCode = true; ++EmittedInsts; } if (ShouldPrintDebugScopes) { for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->beginInstruction(&MI); } } if (isVerbose()) emitComments(MI, OutStreamer->GetCommentOS()); switch (MI.getOpcode()) { case TargetOpcode::CFI_INSTRUCTION: emitCFIInstruction(MI); break; case TargetOpcode::LOCAL_ESCAPE: emitFrameAlloc(MI); break; case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer->EmitLabel(MI.getOperand(0).getMCSymbol()); break; case TargetOpcode::INLINEASM: EmitInlineAsm(&MI); break; case TargetOpcode::DBG_VALUE: if (isVerbose()) { if (!emitDebugValueComment(&MI, *this)) EmitInstruction(&MI); } break; case TargetOpcode::IMPLICIT_DEF: if (isVerbose()) emitImplicitDef(&MI); break; case TargetOpcode::KILL: if (isVerbose()) emitKill(&MI, *this); break; default: EmitInstruction(&MI); break; } if (ShouldPrintDebugScopes) { for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->endInstruction(); } } } EmitBasicBlockEnd(MBB); } // If the function is empty and the object file uses .subsections_via_symbols, // then we need to emit *something* to the function body to prevent the // labels from collapsing together. Just emit a noop. if ((MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode)) { MCInst Noop; MF->getSubtarget().getInstrInfo()->getNoopForMachoTarget(Noop); OutStreamer->AddComment("avoids zero-length function"); // Targets can opt-out of emitting the noop here by leaving the opcode // unspecified. if (Noop.getOpcode()) OutStreamer->EmitInstruction(Noop, getSubtargetInfo()); } const Function *F = MF->getFunction(); for (const auto &BB : *F) { if (!BB.hasAddressTaken()) continue; MCSymbol *Sym = GetBlockAddressSymbol(&BB); if (Sym->isDefined()) continue; OutStreamer->AddComment("Address of block that was removed by CodeGen"); OutStreamer->EmitLabel(Sym); } // Emit target-specific gunk after the function body. EmitFunctionBodyEnd(); if (!MF->getLandingPads().empty() || MMI->hasDebugInfo() || MF->hasEHFunclets() || MAI->hasDotTypeDotSizeDirective()) { // Create a symbol for the end of function. CurrentFnEnd = createTempSymbol("func_end"); OutStreamer->EmitLabel(CurrentFnEnd); } // If the target wants a .size directive for the size of the function, emit // it. if (MAI->hasDotTypeDotSizeDirective()) { // We can get the size as difference between the function label and the // temp label. const MCExpr *SizeExp = MCBinaryExpr::createSub( MCSymbolRefExpr::create(CurrentFnEnd, OutContext), MCSymbolRefExpr::create(CurrentFnSymForSize, OutContext), OutContext); OutStreamer->emitELFSize(CurrentFnSym, SizeExp); } for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->markFunctionEnd(); } // Print out jump tables referenced by the function. EmitJumpTableInfo(); // Emit post-function debug and/or EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->endFunction(MF); } OutStreamer->AddBlankLine(); } /// \brief Compute the number of Global Variables that uses a Constant. static unsigned getNumGlobalVariableUses(const Constant *C) { if (!C) return 0; if (isa(C)) return 1; unsigned NumUses = 0; for (auto *CU : C->users()) NumUses += getNumGlobalVariableUses(dyn_cast(CU)); return NumUses; } /// \brief Only consider global GOT equivalents if at least one user is a /// cstexpr inside an initializer of another global variables. Also, don't /// handle cstexpr inside instructions. During global variable emission, /// candidates are skipped and are emitted later in case at least one cstexpr /// isn't replaced by a PC relative GOT entry access. static bool isGOTEquivalentCandidate(const GlobalVariable *GV, unsigned &NumGOTEquivUsers) { // Global GOT equivalents are unnamed private globals with a constant // pointer initializer to another global symbol. They must point to a // GlobalVariable or Function, i.e., as GlobalValue. if (!GV->hasGlobalUnnamedAddr() || !GV->hasInitializer() || !GV->isConstant() || !GV->isDiscardableIfUnused() || !dyn_cast(GV->getOperand(0))) return false; // To be a got equivalent, at least one of its users need to be a constant // expression used by another global variable. for (auto *U : GV->users()) NumGOTEquivUsers += getNumGlobalVariableUses(dyn_cast(U)); return NumGOTEquivUsers > 0; } /// \brief Unnamed constant global variables solely contaning a pointer to /// another globals variable is equivalent to a GOT table entry; it contains the /// the address of another symbol. Optimize it and replace accesses to these /// "GOT equivalents" by using the GOT entry for the final global instead. /// Compute GOT equivalent candidates among all global variables to avoid /// emitting them if possible later on, after it use is replaced by a GOT entry /// access. void AsmPrinter::computeGlobalGOTEquivs(Module &M) { if (!getObjFileLowering().supportIndirectSymViaGOTPCRel()) return; for (const auto &G : M.globals()) { unsigned NumGOTEquivUsers = 0; if (!isGOTEquivalentCandidate(&G, NumGOTEquivUsers)) continue; const MCSymbol *GOTEquivSym = getSymbol(&G); GlobalGOTEquivs[GOTEquivSym] = std::make_pair(&G, NumGOTEquivUsers); } } /// \brief Constant expressions using GOT equivalent globals may not be eligible /// for PC relative GOT entry conversion, in such cases we need to emit such /// globals we previously omitted in EmitGlobalVariable. void AsmPrinter::emitGlobalGOTEquivs() { if (!getObjFileLowering().supportIndirectSymViaGOTPCRel()) return; SmallVector FailedCandidates; for (auto &I : GlobalGOTEquivs) { const GlobalVariable *GV = I.second.first; unsigned Cnt = I.second.second; if (Cnt) FailedCandidates.push_back(GV); } GlobalGOTEquivs.clear(); for (auto *GV : FailedCandidates) EmitGlobalVariable(GV); } void AsmPrinter::emitGlobalIndirectSymbol(Module &M, const GlobalIndirectSymbol& GIS) { MCSymbol *Name = getSymbol(&GIS); if (GIS.hasExternalLinkage() || !MAI->getWeakRefDirective()) OutStreamer->EmitSymbolAttribute(Name, MCSA_Global); else if (GIS.hasWeakLinkage() || GIS.hasLinkOnceLinkage()) OutStreamer->EmitSymbolAttribute(Name, MCSA_WeakReference); else assert(GIS.hasLocalLinkage() && "Invalid alias or ifunc linkage"); // Set the symbol type to function if the alias has a function type. // This affects codegen when the aliasee is not a function. if (GIS.getType()->getPointerElementType()->isFunctionTy()) { OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); if (isa(GIS)) OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); } EmitVisibility(Name, GIS.getVisibility()); const MCExpr *Expr = lowerConstant(GIS.getIndirectSymbol()); if (isa(&GIS) && MAI->hasAltEntry() && isa(Expr)) OutStreamer->EmitSymbolAttribute(Name, MCSA_AltEntry); // Emit the directives as assignments aka .set: OutStreamer->EmitAssignment(Name, Expr); if (auto *GA = dyn_cast(&GIS)) { // If the aliasee does not correspond to a symbol in the output, i.e. the // alias is not of an object or the aliased object is private, then set the // size of the alias symbol from the type of the alias. We don't do this in // other situations as the alias and aliasee having differing types but same // size may be intentional. const GlobalObject *BaseObject = GA->getBaseObject(); if (MAI->hasDotTypeDotSizeDirective() && GA->getValueType()->isSized() && (!BaseObject || BaseObject->hasPrivateLinkage())) { const DataLayout &DL = M.getDataLayout(); uint64_t Size = DL.getTypeAllocSize(GA->getValueType()); OutStreamer->emitELFSize(Name, MCConstantExpr::create(Size, OutContext)); } } } bool AsmPrinter::doFinalization(Module &M) { // Set the MachineFunction to nullptr so that we can catch attempted // accesses to MF specific features at the module level and so that // we can conditionalize accesses based on whether or not it is nullptr. MF = nullptr; // Gather all GOT equivalent globals in the module. We really need two // passes over the globals: one to compute and another to avoid its emission // in EmitGlobalVariable, otherwise we would not be able to handle cases // where the got equivalent shows up before its use. computeGlobalGOTEquivs(M); // Emit global variables. for (const auto &G : M.globals()) EmitGlobalVariable(&G); // Emit remaining GOT equivalent globals. emitGlobalGOTEquivs(); // Emit visibility info for declarations for (const Function &F : M) { if (!F.isDeclarationForLinker()) continue; GlobalValue::VisibilityTypes V = F.getVisibility(); if (V == GlobalValue::DefaultVisibility) continue; MCSymbol *Name = getSymbol(&F); EmitVisibility(Name, V, false); } const TargetLoweringObjectFile &TLOF = getObjFileLowering(); // Emit module flags. SmallVector ModuleFlags; M.getModuleFlagsMetadata(ModuleFlags); if (!ModuleFlags.empty()) TLOF.emitModuleFlags(*OutStreamer, ModuleFlags, TM); if (TM.getTargetTriple().isOSBinFormatELF()) { MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); // Output stubs for external and common global variables. MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); if (!Stubs.empty()) { OutStreamer->SwitchSection(TLOF.getDataSection()); const DataLayout &DL = M.getDataLayout(); for (const auto &Stub : Stubs) { OutStreamer->EmitLabel(Stub.first); OutStreamer->EmitSymbolValue(Stub.second.getPointer(), DL.getPointerSize()); } } } // Finalize debug and EH information. for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); HI.Handler->endModule(); delete HI.Handler; } Handlers.clear(); DD = nullptr; // If the target wants to know about weak references, print them all. if (MAI->getWeakRefDirective()) { // FIXME: This is not lazy, it would be nice to only print weak references // to stuff that is actually used. Note that doing so would require targets // to notice uses in operands (due to constant exprs etc). This should // happen with the MC stuff eventually. // Print out module-level global objects here. for (const auto &GO : M.global_objects()) { if (!GO.hasExternalWeakLinkage()) continue; OutStreamer->EmitSymbolAttribute(getSymbol(&GO), MCSA_WeakReference); } } OutStreamer->AddBlankLine(); // Print aliases in topological order, that is, for each alias a = b, // b must be printed before a. // This is because on some targets (e.g. PowerPC) linker expects aliases in // such an order to generate correct TOC information. SmallVector AliasStack; SmallPtrSet AliasVisited; for (const auto &Alias : M.aliases()) { for (const GlobalAlias *Cur = &Alias; Cur; Cur = dyn_cast(Cur->getAliasee())) { if (!AliasVisited.insert(Cur).second) break; AliasStack.push_back(Cur); } for (const GlobalAlias *AncestorAlias : reverse(AliasStack)) emitGlobalIndirectSymbol(M, *AncestorAlias); AliasStack.clear(); } for (const auto &IFunc : M.ifuncs()) emitGlobalIndirectSymbol(M, IFunc); GCModuleInfo *MI = getAnalysisIfAvailable(); assert(MI && "AsmPrinter didn't require GCModuleInfo?"); for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; ) if (GCMetadataPrinter *MP = GetOrCreateGCPrinter(**--I)) MP->finishAssembly(M, *MI, *this); // Emit llvm.ident metadata in an '.ident' directive. EmitModuleIdents(M); // Emit __morestack address if needed for indirect calls. if (MMI->usesMorestackAddr()) { unsigned Align = 1; MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant( getDataLayout(), SectionKind::getReadOnly(), /*C=*/nullptr, Align); OutStreamer->SwitchSection(ReadOnlySection); MCSymbol *AddrSymbol = OutContext.getOrCreateSymbol(StringRef("__morestack_addr")); OutStreamer->EmitLabel(AddrSymbol); unsigned PtrSize = M.getDataLayout().getPointerSize(0); OutStreamer->EmitSymbolValue(GetExternalSymbolSymbol("__morestack"), PtrSize); } // If we don't have any trampolines, then we don't require stack memory // to be executable. Some targets have a directive to declare this. Function *InitTrampolineIntrinsic = M.getFunction("llvm.init.trampoline"); if (!InitTrampolineIntrinsic || InitTrampolineIntrinsic->use_empty()) if (MCSection *S = MAI->getNonexecutableStackSection(OutContext)) OutStreamer->SwitchSection(S); // Allow the target to emit any magic that it wants at the end of the file, // after everything else has gone out. EmitEndOfAsmFile(M); MMI = nullptr; OutStreamer->Finish(); OutStreamer->reset(); return false; } MCSymbol *AsmPrinter::getCurExceptionSym() { if (!CurExceptionSym) CurExceptionSym = createTempSymbol("exception"); return CurExceptionSym; } void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { this->MF = &MF; // Get the function symbol. CurrentFnSym = getSymbol(MF.getFunction()); CurrentFnSymForSize = CurrentFnSym; CurrentFnBegin = nullptr; CurExceptionSym = nullptr; bool NeedsLocalForSize = MAI->needsLocalForSize(); if (!MF.getLandingPads().empty() || MMI->hasDebugInfo() || MF.hasEHFunclets() || NeedsLocalForSize) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; } if (isVerbose()) LI = &getAnalysis(); } namespace { // Keep track the alignment, constpool entries per Section. struct SectionCPs { MCSection *S; unsigned Alignment; SmallVector CPEs; SectionCPs(MCSection *s, unsigned a) : S(s), Alignment(a) {} }; } /// EmitConstantPool - Print to the current output stream assembly /// representations of the constants in the constant pool MCP. This is /// used to print out constants which have been "spilled to memory" by /// the code generator. /// void AsmPrinter::EmitConstantPool() { const MachineConstantPool *MCP = MF->getConstantPool(); const std::vector &CP = MCP->getConstants(); if (CP.empty()) return; // Calculate sections for constant pool entries. We collect entries to go into // the same section together to reduce amount of section switch statements. SmallVector CPSections; for (unsigned i = 0, e = CP.size(); i != e; ++i) { const MachineConstantPoolEntry &CPE = CP[i]; unsigned Align = CPE.getAlignment(); SectionKind Kind = CPE.getSectionKind(&getDataLayout()); const Constant *C = nullptr; if (!CPE.isMachineConstantPoolEntry()) C = CPE.Val.ConstVal; MCSection *S = getObjFileLowering().getSectionForConstant(getDataLayout(), Kind, C, Align); // The number of sections are small, just do a linear search from the // last section to the first. bool Found = false; unsigned SecIdx = CPSections.size(); while (SecIdx != 0) { if (CPSections[--SecIdx].S == S) { Found = true; break; } } if (!Found) { SecIdx = CPSections.size(); CPSections.push_back(SectionCPs(S, Align)); } if (Align > CPSections[SecIdx].Alignment) CPSections[SecIdx].Alignment = Align; CPSections[SecIdx].CPEs.push_back(i); } // Now print stuff into the calculated sections. const MCSection *CurSection = nullptr; unsigned Offset = 0; for (unsigned i = 0, e = CPSections.size(); i != e; ++i) { for (unsigned j = 0, ee = CPSections[i].CPEs.size(); j != ee; ++j) { unsigned CPI = CPSections[i].CPEs[j]; MCSymbol *Sym = GetCPISymbol(CPI); if (!Sym->isUndefined()) continue; if (CurSection != CPSections[i].S) { OutStreamer->SwitchSection(CPSections[i].S); EmitAlignment(Log2_32(CPSections[i].Alignment)); CurSection = CPSections[i].S; Offset = 0; } MachineConstantPoolEntry CPE = CP[CPI]; // Emit inter-object padding for alignment. unsigned AlignMask = CPE.getAlignment() - 1; unsigned NewOffset = (Offset + AlignMask) & ~AlignMask; OutStreamer->EmitZeros(NewOffset - Offset); Type *Ty = CPE.getType(); Offset = NewOffset + getDataLayout().getTypeAllocSize(Ty); OutStreamer->EmitLabel(Sym); if (CPE.isMachineConstantPoolEntry()) EmitMachineConstantPoolValue(CPE.Val.MachineCPVal); else EmitGlobalConstant(getDataLayout(), CPE.Val.ConstVal); } } } /// EmitJumpTableInfo - Print assembly representations of the jump tables used /// by the current function to the current output stream. /// void AsmPrinter::EmitJumpTableInfo() { const DataLayout &DL = MF->getDataLayout(); const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); if (!MJTI) return; if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_Inline) return; const std::vector &JT = MJTI->getJumpTables(); if (JT.empty()) return; // Pick the directive to use to print the jump table entries, and switch to // the appropriate section. const Function *F = MF->getFunction(); const TargetLoweringObjectFile &TLOF = getObjFileLowering(); bool JTInDiffSection = !TLOF.shouldPutJumpTableInFunctionSection( MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32, *F); if (JTInDiffSection) { // Drop it in the readonly section. MCSection *ReadOnlySection = TLOF.getSectionForJumpTable(*F, TM); OutStreamer->SwitchSection(ReadOnlySection); } EmitAlignment(Log2_32(MJTI->getEntryAlignment(DL))); // Jump tables in code sections are marked with a data_region directive // where that's supported. if (!JTInDiffSection) OutStreamer->EmitDataRegion(MCDR_DataRegionJT32); for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) { const std::vector &JTBBs = JT[JTI].MBBs; // If this jump table was deleted, ignore it. if (JTBBs.empty()) continue; // For the EK_LabelDifference32 entry, if using .set avoids a relocation, /// emit a .set directive for each unique entry. if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 && MAI->doesSetDirectiveSuppressReloc()) { SmallPtrSet EmittedSets; const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF,JTI,OutContext); for (unsigned ii = 0, ee = JTBBs.size(); ii != ee; ++ii) { const MachineBasicBlock *MBB = JTBBs[ii]; if (!EmittedSets.insert(MBB).second) continue; // .set LJTSet, LBB32-base const MCExpr *LHS = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); OutStreamer->EmitAssignment(GetJTSetSymbol(JTI, MBB->getNumber()), MCBinaryExpr::createSub(LHS, Base, OutContext)); } } // On some targets (e.g. Darwin) we want to emit two consecutive labels // before each jump table. The first label is never referenced, but tells // the assembler and linker the extents of the jump table object. The // second label is actually referenced by the code. if (JTInDiffSection && DL.hasLinkerPrivateGlobalPrefix()) // FIXME: This doesn't have to have any specific name, just any randomly // named and numbered 'l' label would work. Simplify GetJTISymbol. OutStreamer->EmitLabel(GetJTISymbol(JTI, true)); OutStreamer->EmitLabel(GetJTISymbol(JTI)); for (unsigned ii = 0, ee = JTBBs.size(); ii != ee; ++ii) EmitJumpTableEntry(MJTI, JTBBs[ii], JTI); } if (!JTInDiffSection) OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); } /// EmitJumpTableEntry - Emit a jump table entry for the specified MBB to the /// current stream. void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, unsigned UID) const { assert(MBB && MBB->getNumber() >= 0 && "Invalid basic block"); const MCExpr *Value = nullptr; switch (MJTI->getEntryKind()) { case MachineJumpTableInfo::EK_Inline: llvm_unreachable("Cannot emit EK_Inline jump table entry"); case MachineJumpTableInfo::EK_Custom32: Value = MF->getSubtarget().getTargetLowering()->LowerCustomJumpTableEntry( MJTI, MBB, UID, OutContext); break; case MachineJumpTableInfo::EK_BlockAddress: // EK_BlockAddress - Each entry is a plain address of block, e.g.: // .word LBB123 Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); break; case MachineJumpTableInfo::EK_GPRel32BlockAddress: { // EK_GPRel32BlockAddress - Each entry is an address of block, encoded // with a relocation as gp-relative, e.g.: // .gprel32 LBB123 MCSymbol *MBBSym = MBB->getSymbol(); OutStreamer->EmitGPRel32Value(MCSymbolRefExpr::create(MBBSym, OutContext)); return; } case MachineJumpTableInfo::EK_GPRel64BlockAddress: { // EK_GPRel64BlockAddress - Each entry is an address of block, encoded // with a relocation as gp-relative, e.g.: // .gpdword LBB123 MCSymbol *MBBSym = MBB->getSymbol(); OutStreamer->EmitGPRel64Value(MCSymbolRefExpr::create(MBBSym, OutContext)); return; } case MachineJumpTableInfo::EK_LabelDifference32: { // Each entry is the address of the block minus the address of the jump // table. This is used for PIC jump tables where gprel32 is not supported. // e.g.: // .word LBB123 - LJTI1_2 // If the .set directive avoids relocations, this is emitted as: // .set L4_5_set_123, LBB123 - LJTI1_2 // .word L4_5_set_123 if (MAI->doesSetDirectiveSuppressReloc()) { Value = MCSymbolRefExpr::create(GetJTSetSymbol(UID, MBB->getNumber()), OutContext); break; } Value = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); const TargetLowering *TLI = MF->getSubtarget().getTargetLowering(); const MCExpr *Base = TLI->getPICJumpTableRelocBaseExpr(MF, UID, OutContext); Value = MCBinaryExpr::createSub(Value, Base, OutContext); break; } } assert(Value && "Unknown entry kind!"); unsigned EntrySize = MJTI->getEntrySize(getDataLayout()); OutStreamer->EmitValue(Value, EntrySize); } /// EmitSpecialLLVMGlobal - Check to see if the specified global is a /// special global used by LLVM. If so, emit it and return true, otherwise /// do nothing and return false. bool AsmPrinter::EmitSpecialLLVMGlobal(const GlobalVariable *GV) { if (GV->getName() == "llvm.used") { if (MAI->hasNoDeadStrip()) // No need to emit this at all. EmitLLVMUsedList(cast(GV->getInitializer())); return true; } // Ignore debug and non-emitted data. This handles llvm.compiler.used. if (GV->getSection() == "llvm.metadata" || GV->hasAvailableExternallyLinkage()) return true; if (!GV->hasAppendingLinkage()) return false; assert(GV->hasInitializer() && "Not a special LLVM global!"); if (GV->getName() == "llvm.global_ctors") { EmitXXStructorList(GV->getParent()->getDataLayout(), GV->getInitializer(), /* isCtor */ true); return true; } if (GV->getName() == "llvm.global_dtors") { EmitXXStructorList(GV->getParent()->getDataLayout(), GV->getInitializer(), /* isCtor */ false); return true; } report_fatal_error("unknown special variable"); } /// EmitLLVMUsedList - For targets that define a MAI::UsedDirective, mark each /// global in the specified llvm.used list for which emitUsedDirectiveFor /// is true, as being used with this directive. void AsmPrinter::EmitLLVMUsedList(const ConstantArray *InitList) { // Should be an array of 'i8*'. for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { const GlobalValue *GV = dyn_cast(InitList->getOperand(i)->stripPointerCasts()); if (GV) OutStreamer->EmitSymbolAttribute(getSymbol(GV), MCSA_NoDeadStrip); } } namespace { struct Structor { Structor() : Priority(0), Func(nullptr), ComdatKey(nullptr) {} int Priority; llvm::Constant *Func; llvm::GlobalValue *ComdatKey; }; } // end namespace /// EmitXXStructorList - Emit the ctor or dtor list taking into account the init /// priority. void AsmPrinter::EmitXXStructorList(const DataLayout &DL, const Constant *List, bool isCtor) { // Should be an array of '{ int, void ()* }' structs. The first value is the // init priority. if (!isa(List)) return; // Sanity check the structors list. const ConstantArray *InitList = dyn_cast(List); if (!InitList) return; // Not an array! StructType *ETy = dyn_cast(InitList->getType()->getElementType()); // FIXME: Only allow the 3-field form in LLVM 4.0. if (!ETy || ETy->getNumElements() < 2 || ETy->getNumElements() > 3) return; // Not an array of two or three elements! if (!isa(ETy->getTypeAtIndex(0U)) || !isa(ETy->getTypeAtIndex(1U))) return; // Not (int, ptr). if (ETy->getNumElements() == 3 && !isa(ETy->getTypeAtIndex(2U))) return; // Not (int, ptr, ptr). // Gather the structors in a form that's convenient for sorting by priority. SmallVector Structors; for (Value *O : InitList->operands()) { ConstantStruct *CS = dyn_cast(O); if (!CS) continue; // Malformed. if (CS->getOperand(1)->isNullValue()) break; // Found a null terminator, skip the rest. ConstantInt *Priority = dyn_cast(CS->getOperand(0)); if (!Priority) continue; // Malformed. Structors.push_back(Structor()); Structor &S = Structors.back(); S.Priority = Priority->getLimitedValue(65535); S.Func = CS->getOperand(1); if (ETy->getNumElements() == 3 && !CS->getOperand(2)->isNullValue()) S.ComdatKey = dyn_cast(CS->getOperand(2)->stripPointerCasts()); } // Emit the function pointers in the target-specific order unsigned Align = Log2_32(DL.getPointerPrefAlignment()); std::stable_sort(Structors.begin(), Structors.end(), [](const Structor &L, const Structor &R) { return L.Priority < R.Priority; }); for (Structor &S : Structors) { const TargetLoweringObjectFile &Obj = getObjFileLowering(); const MCSymbol *KeySym = nullptr; if (GlobalValue *GV = S.ComdatKey) { if (GV->hasAvailableExternallyLinkage()) // If the associated variable is available_externally, some other TU // will provide its dynamic initializer. continue; KeySym = getSymbol(GV); } MCSection *OutputSection = (isCtor ? Obj.getStaticCtorSection(S.Priority, KeySym) : Obj.getStaticDtorSection(S.Priority, KeySym)); OutStreamer->SwitchSection(OutputSection); if (OutStreamer->getCurrentSection() != OutStreamer->getPreviousSection()) EmitAlignment(Align); EmitXXStructor(DL, S.Func); } } void AsmPrinter::EmitModuleIdents(Module &M) { if (!MAI->hasIdentDirective()) return; if (const NamedMDNode *NMD = M.getNamedMetadata("llvm.ident")) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { const MDNode *N = NMD->getOperand(i); assert(N->getNumOperands() == 1 && "llvm.ident metadata entry can have only one operand"); const MDString *S = cast(N->getOperand(0)); OutStreamer->EmitIdent(S->getString()); } } } //===--------------------------------------------------------------------===// // Emission and print routines // /// EmitInt8 - Emit a byte directive and value. /// void AsmPrinter::EmitInt8(int Value) const { OutStreamer->EmitIntValue(Value, 1); } /// EmitInt16 - Emit a short directive and value. /// void AsmPrinter::EmitInt16(int Value) const { OutStreamer->EmitIntValue(Value, 2); } /// EmitInt32 - Emit a long directive and value. /// void AsmPrinter::EmitInt32(int Value) const { OutStreamer->EmitIntValue(Value, 4); } /// Emit something like ".long Hi-Lo" where the size in bytes of the directive /// is specified by Size and Hi/Lo specify the labels. This implicitly uses /// .set if it avoids relocations. void AsmPrinter::EmitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) const { OutStreamer->emitAbsoluteSymbolDiff(Hi, Lo, Size); } /// EmitLabelPlusOffset - Emit something like ".long Label+Offset" /// where the size in bytes of the directive is specified by Size and Label /// specifies the label. This implicitly uses .set if it is available. void AsmPrinter::EmitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset, unsigned Size, bool IsSectionRelative) const { if (MAI->needsDwarfSectionOffsetDirective() && IsSectionRelative) { OutStreamer->EmitCOFFSecRel32(Label, Offset); if (Size > 4) OutStreamer->EmitZeros(Size - 4); return; } // Emit Label+Offset (or just Label if Offset is zero) const MCExpr *Expr = MCSymbolRefExpr::create(Label, OutContext); if (Offset) Expr = MCBinaryExpr::createAdd( Expr, MCConstantExpr::create(Offset, OutContext), OutContext); OutStreamer->EmitValue(Expr, Size); } //===----------------------------------------------------------------------===// // EmitAlignment - Emit an alignment directive to the specified power of // two boundary. For example, if you pass in 3 here, you will get an 8 // byte alignment. If a global value is specified, and if that global has // an explicit alignment requested, it will override the alignment request // if required for correctness. // void AsmPrinter::EmitAlignment(unsigned NumBits, const GlobalObject *GV) const { if (GV) NumBits = getGVAlignmentLog2(GV, GV->getParent()->getDataLayout(), NumBits); if (NumBits == 0) return; // 1-byte aligned: no need to emit alignment. assert(NumBits < static_cast(std::numeric_limits::digits) && "undefined behavior"); if (getCurrentSection()->getKind().isText()) OutStreamer->EmitCodeAlignment(1u << NumBits); else OutStreamer->EmitValueToAlignment(1u << NumBits); } //===----------------------------------------------------------------------===// // Constant emission. //===----------------------------------------------------------------------===// const MCExpr *AsmPrinter::lowerConstant(const Constant *CV) { MCContext &Ctx = OutContext; if (CV->isNullValue() || isa(CV)) return MCConstantExpr::create(0, Ctx); if (const ConstantInt *CI = dyn_cast(CV)) return MCConstantExpr::create(CI->getZExtValue(), Ctx); if (const GlobalValue *GV = dyn_cast(CV)) return MCSymbolRefExpr::create(getSymbol(GV), Ctx); if (const BlockAddress *BA = dyn_cast(CV)) return MCSymbolRefExpr::create(GetBlockAddressSymbol(BA), Ctx); const ConstantExpr *CE = dyn_cast(CV); if (!CE) { llvm_unreachable("Unknown constant value to lower!"); } switch (CE->getOpcode()) { default: // If the code isn't optimized, there may be outstanding folding // opportunities. Attempt to fold the expression using DataLayout as a // last resort before giving up. if (Constant *C = ConstantFoldConstant(CE, getDataLayout())) if (C != CE) return lowerConstant(C); // Otherwise report the problem to the user. { std::string S; raw_string_ostream OS(S); OS << "Unsupported expression in static initializer: "; CE->printAsOperand(OS, /*PrintType=*/false, !MF ? nullptr : MF->getFunction()->getParent()); report_fatal_error(OS.str()); } case Instruction::GetElementPtr: { // Generate a symbolic expression for the byte address APInt OffsetAI(getDataLayout().getPointerTypeSizeInBits(CE->getType()), 0); cast(CE)->accumulateConstantOffset(getDataLayout(), OffsetAI); const MCExpr *Base = lowerConstant(CE->getOperand(0)); if (!OffsetAI) return Base; int64_t Offset = OffsetAI.getSExtValue(); return MCBinaryExpr::createAdd(Base, MCConstantExpr::create(Offset, Ctx), Ctx); } case Instruction::Trunc: // We emit the value and depend on the assembler to truncate the generated // expression properly. This is important for differences between // blockaddress labels. Since the two labels are in the same function, it // is reasonable to treat their delta as a 32-bit value. LLVM_FALLTHROUGH; case Instruction::BitCast: return lowerConstant(CE->getOperand(0)); case Instruction::IntToPtr: { const DataLayout &DL = getDataLayout(); // Handle casts to pointers by changing them into casts to the appropriate // integer type. This promotes constant folding and simplifies this code. Constant *Op = CE->getOperand(0); Op = ConstantExpr::getIntegerCast(Op, DL.getIntPtrType(CV->getType()), false/*ZExt*/); return lowerConstant(Op); } case Instruction::PtrToInt: { const DataLayout &DL = getDataLayout(); // Support only foldable casts to/from pointers that can be eliminated by // changing the pointer to the appropriately sized integer type. Constant *Op = CE->getOperand(0); Type *Ty = CE->getType(); const MCExpr *OpExpr = lowerConstant(Op); // We can emit the pointer value into this slot if the slot is an // integer slot equal to the size of the pointer. if (DL.getTypeAllocSize(Ty) == DL.getTypeAllocSize(Op->getType())) return OpExpr; // Otherwise the pointer is smaller than the resultant integer, mask off // the high bits so we are sure to get a proper truncation if the input is // a constant expr. unsigned InBits = DL.getTypeAllocSizeInBits(Op->getType()); const MCExpr *MaskExpr = MCConstantExpr::create(~0ULL >> (64-InBits), Ctx); return MCBinaryExpr::createAnd(OpExpr, MaskExpr, Ctx); } case Instruction::Sub: { GlobalValue *LHSGV; APInt LHSOffset; if (IsConstantOffsetFromGlobal(CE->getOperand(0), LHSGV, LHSOffset, getDataLayout())) { GlobalValue *RHSGV; APInt RHSOffset; if (IsConstantOffsetFromGlobal(CE->getOperand(1), RHSGV, RHSOffset, getDataLayout())) { const MCExpr *RelocExpr = getObjFileLowering().lowerRelativeReference(LHSGV, RHSGV, TM); if (!RelocExpr) RelocExpr = MCBinaryExpr::createSub( MCSymbolRefExpr::create(getSymbol(LHSGV), Ctx), MCSymbolRefExpr::create(getSymbol(RHSGV), Ctx), Ctx); int64_t Addend = (LHSOffset - RHSOffset).getSExtValue(); if (Addend != 0) RelocExpr = MCBinaryExpr::createAdd( RelocExpr, MCConstantExpr::create(Addend, Ctx), Ctx); return RelocExpr; } } } // else fallthrough // The MC library also has a right-shift operator, but it isn't consistently // signed or unsigned between different targets. case Instruction::Add: case Instruction::Mul: case Instruction::SDiv: case Instruction::SRem: case Instruction::Shl: case Instruction::And: case Instruction::Or: case Instruction::Xor: { const MCExpr *LHS = lowerConstant(CE->getOperand(0)); const MCExpr *RHS = lowerConstant(CE->getOperand(1)); switch (CE->getOpcode()) { default: llvm_unreachable("Unknown binary operator constant cast expr"); case Instruction::Add: return MCBinaryExpr::createAdd(LHS, RHS, Ctx); case Instruction::Sub: return MCBinaryExpr::createSub(LHS, RHS, Ctx); case Instruction::Mul: return MCBinaryExpr::createMul(LHS, RHS, Ctx); case Instruction::SDiv: return MCBinaryExpr::createDiv(LHS, RHS, Ctx); case Instruction::SRem: return MCBinaryExpr::createMod(LHS, RHS, Ctx); case Instruction::Shl: return MCBinaryExpr::createShl(LHS, RHS, Ctx); case Instruction::And: return MCBinaryExpr::createAnd(LHS, RHS, Ctx); case Instruction::Or: return MCBinaryExpr::createOr (LHS, RHS, Ctx); case Instruction::Xor: return MCBinaryExpr::createXor(LHS, RHS, Ctx); } } } } static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *C, AsmPrinter &AP, const Constant *BaseCV = nullptr, uint64_t Offset = 0); static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP); /// isRepeatedByteSequence - Determine whether the given value is /// composed of a repeated sequence of identical bytes and return the /// byte value. If it is not a repeated sequence, return -1. static int isRepeatedByteSequence(const ConstantDataSequential *V) { StringRef Data = V->getRawDataValues(); assert(!Data.empty() && "Empty aggregates should be CAZ node"); char C = Data[0]; for (unsigned i = 1, e = Data.size(); i != e; ++i) if (Data[i] != C) return -1; return static_cast(C); // Ensure 255 is not returned as -1. } /// isRepeatedByteSequence - Determine whether the given value is /// composed of a repeated sequence of identical bytes and return the /// byte value. If it is not a repeated sequence, return -1. static int isRepeatedByteSequence(const Value *V, const DataLayout &DL) { if (const ConstantInt *CI = dyn_cast(V)) { uint64_t Size = DL.getTypeAllocSizeInBits(V->getType()); assert(Size % 8 == 0); // Extend the element to take zero padding into account. APInt Value = CI->getValue().zextOrSelf(Size); if (!Value.isSplat(8)) return -1; return Value.zextOrTrunc(8).getZExtValue(); } if (const ConstantArray *CA = dyn_cast(V)) { // Make sure all array elements are sequences of the same repeated // byte. assert(CA->getNumOperands() != 0 && "Should be a CAZ"); Constant *Op0 = CA->getOperand(0); int Byte = isRepeatedByteSequence(Op0, DL); if (Byte == -1) return -1; // All array elements must be equal. for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) if (CA->getOperand(i) != Op0) return -1; return Byte; } if (const ConstantDataSequential *CDS = dyn_cast(V)) return isRepeatedByteSequence(CDS); return -1; } static void emitGlobalConstantDataSequential(const DataLayout &DL, const ConstantDataSequential *CDS, AsmPrinter &AP) { // See if we can aggregate this into a .fill, if so, emit it as such. int Value = isRepeatedByteSequence(CDS, DL); if (Value != -1) { uint64_t Bytes = DL.getTypeAllocSize(CDS->getType()); // Don't emit a 1-byte object as a .fill. if (Bytes > 1) return AP.OutStreamer->emitFill(Bytes, Value); } // If this can be emitted with .ascii/.asciz, emit it as such. if (CDS->isString()) return AP.OutStreamer->EmitBytes(CDS->getAsString()); // Otherwise, emit the values in successive locations. unsigned ElementByteSize = CDS->getElementByteSize(); if (isa(CDS->getElementType())) { for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { if (AP.isVerbose()) AP.OutStreamer->GetCommentOS() << format("0x%" PRIx64 "\n", CDS->getElementAsInteger(i)); AP.OutStreamer->EmitIntValue(CDS->getElementAsInteger(i), ElementByteSize); } } else { for (unsigned I = 0, E = CDS->getNumElements(); I != E; ++I) emitGlobalConstantFP(cast(CDS->getElementAsConstant(I)), AP); } unsigned Size = DL.getTypeAllocSize(CDS->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CDS->getType()->getElementType()) * CDS->getNumElements(); if (unsigned Padding = Size - EmittedSize) AP.OutStreamer->EmitZeros(Padding); } static void emitGlobalConstantArray(const DataLayout &DL, const ConstantArray *CA, AsmPrinter &AP, const Constant *BaseCV, uint64_t Offset) { // See if we can aggregate some values. Make sure it can be // represented as a series of bytes of the constant value. int Value = isRepeatedByteSequence(CA, DL); if (Value != -1) { uint64_t Bytes = DL.getTypeAllocSize(CA->getType()); AP.OutStreamer->emitFill(Bytes, Value); } else { for (unsigned i = 0, e = CA->getNumOperands(); i != e; ++i) { emitGlobalConstantImpl(DL, CA->getOperand(i), AP, BaseCV, Offset); Offset += DL.getTypeAllocSize(CA->getOperand(i)->getType()); } } } static void emitGlobalConstantVector(const DataLayout &DL, const ConstantVector *CV, AsmPrinter &AP) { for (unsigned i = 0, e = CV->getType()->getNumElements(); i != e; ++i) emitGlobalConstantImpl(DL, CV->getOperand(i), AP); unsigned Size = DL.getTypeAllocSize(CV->getType()); unsigned EmittedSize = DL.getTypeAllocSize(CV->getType()->getElementType()) * CV->getType()->getNumElements(); if (unsigned Padding = Size - EmittedSize) AP.OutStreamer->EmitZeros(Padding); } static void emitGlobalConstantStruct(const DataLayout &DL, const ConstantStruct *CS, AsmPrinter &AP, const Constant *BaseCV, uint64_t Offset) { // Print the fields in successive locations. Pad to align if needed! unsigned Size = DL.getTypeAllocSize(CS->getType()); const StructLayout *Layout = DL.getStructLayout(CS->getType()); uint64_t SizeSoFar = 0; for (unsigned i = 0, e = CS->getNumOperands(); i != e; ++i) { const Constant *Field = CS->getOperand(i); // Print the actual field value. emitGlobalConstantImpl(DL, Field, AP, BaseCV, Offset + SizeSoFar); // Check if padding is needed and insert one or more 0s. uint64_t FieldSize = DL.getTypeAllocSize(Field->getType()); uint64_t PadSize = ((i == e-1 ? Size : Layout->getElementOffset(i+1)) - Layout->getElementOffset(i)) - FieldSize; SizeSoFar += FieldSize + PadSize; // Insert padding - this may include padding to increase the size of the // current field up to the ABI size (if the struct is not packed) as well // as padding to ensure that the next field starts at the right offset. AP.OutStreamer->EmitZeros(PadSize); } assert(SizeSoFar == Layout->getSizeInBytes() && "Layout of constant struct may be incorrect!"); } static void emitGlobalConstantFP(const ConstantFP *CFP, AsmPrinter &AP) { APInt API = CFP->getValueAPF().bitcastToAPInt(); // First print a comment with what we think the original floating-point value // should have been. if (AP.isVerbose()) { SmallString<8> StrVal; CFP->getValueAPF().toString(StrVal); if (CFP->getType()) CFP->getType()->print(AP.OutStreamer->GetCommentOS()); else AP.OutStreamer->GetCommentOS() << "Printing Type"; AP.OutStreamer->GetCommentOS() << ' ' << StrVal << '\n'; } // Now iterate through the APInt chunks, emitting them in endian-correct // order, possibly with a smaller chunk at beginning/end (e.g. for x87 80-bit // floats). unsigned NumBytes = API.getBitWidth() / 8; unsigned TrailingBytes = NumBytes % sizeof(uint64_t); const uint64_t *p = API.getRawData(); // PPC's long double has odd notions of endianness compared to how LLVM // handles it: p[0] goes first for *big* endian on PPC. if (AP.getDataLayout().isBigEndian() && !CFP->getType()->isPPC_FP128Ty()) { int Chunk = API.getNumWords() - 1; if (TrailingBytes) AP.OutStreamer->EmitIntValue(p[Chunk--], TrailingBytes); for (; Chunk >= 0; --Chunk) AP.OutStreamer->EmitIntValue(p[Chunk], sizeof(uint64_t)); } else { unsigned Chunk; for (Chunk = 0; Chunk < NumBytes / sizeof(uint64_t); ++Chunk) AP.OutStreamer->EmitIntValue(p[Chunk], sizeof(uint64_t)); if (TrailingBytes) AP.OutStreamer->EmitIntValue(p[Chunk], TrailingBytes); } // Emit the tail padding for the long double. const DataLayout &DL = AP.getDataLayout(); AP.OutStreamer->EmitZeros(DL.getTypeAllocSize(CFP->getType()) - DL.getTypeStoreSize(CFP->getType())); } static void emitGlobalConstantLargeInt(const ConstantInt *CI, AsmPrinter &AP) { const DataLayout &DL = AP.getDataLayout(); unsigned BitWidth = CI->getBitWidth(); // Copy the value as we may massage the layout for constants whose bit width // is not a multiple of 64-bits. APInt Realigned(CI->getValue()); uint64_t ExtraBits = 0; unsigned ExtraBitsSize = BitWidth & 63; if (ExtraBitsSize) { // The bit width of the data is not a multiple of 64-bits. // The extra bits are expected to be at the end of the chunk of the memory. // Little endian: // * Nothing to be done, just record the extra bits to emit. // Big endian: // * Record the extra bits to emit. // * Realign the raw data to emit the chunks of 64-bits. if (DL.isBigEndian()) { // Basically the structure of the raw data is a chunk of 64-bits cells: // 0 1 BitWidth / 64 // [chunk1][chunk2] ... [chunkN]. // The most significant chunk is chunkN and it should be emitted first. // However, due to the alignment issue chunkN contains useless bits. // Realign the chunks so that they contain only useless information: // ExtraBits 0 1 (BitWidth / 64) - 1 // chu[nk1 chu][nk2 chu] ... [nkN-1 chunkN] ExtraBits = Realigned.getRawData()[0] & (((uint64_t)-1) >> (64 - ExtraBitsSize)); Realigned = Realigned.lshr(ExtraBitsSize); } else ExtraBits = Realigned.getRawData()[BitWidth / 64]; } // We don't expect assemblers to support integer data directives // for more than 64 bits, so we emit the data in at most 64-bit // quantities at a time. const uint64_t *RawData = Realigned.getRawData(); for (unsigned i = 0, e = BitWidth / 64; i != e; ++i) { uint64_t Val = DL.isBigEndian() ? RawData[e - i - 1] : RawData[i]; AP.OutStreamer->EmitIntValue(Val, 8); } if (ExtraBitsSize) { // Emit the extra bits after the 64-bits chunks. // Emit a directive that fills the expected size. uint64_t Size = AP.getDataLayout().getTypeAllocSize(CI->getType()); Size -= (BitWidth / 64) * 8; assert(Size && Size * 8 >= ExtraBitsSize && (ExtraBits & (((uint64_t)-1) >> (64 - ExtraBitsSize))) == ExtraBits && "Directive too small for extra bits."); AP.OutStreamer->EmitIntValue(ExtraBits, Size); } } /// \brief Transform a not absolute MCExpr containing a reference to a GOT /// equivalent global, by a target specific GOT pc relative access to the /// final symbol. static void handleIndirectSymViaGOTPCRel(AsmPrinter &AP, const MCExpr **ME, const Constant *BaseCst, uint64_t Offset) { // The global @foo below illustrates a global that uses a got equivalent. // // @bar = global i32 42 // @gotequiv = private unnamed_addr constant i32* @bar // @foo = i32 trunc (i64 sub (i64 ptrtoint (i32** @gotequiv to i64), // i64 ptrtoint (i32* @foo to i64)) // to i32) // // The cstexpr in @foo is converted into the MCExpr `ME`, where we actually // check whether @foo is suitable to use a GOTPCREL. `ME` is usually in the // form: // // foo = cstexpr, where // cstexpr := - "." + // cstexpr := - ( - ) + // // After canonicalization by evaluateAsRelocatable `ME` turns into: // // cstexpr := - + gotpcrelcst, where // gotpcrelcst := + // MCValue MV; if (!(*ME)->evaluateAsRelocatable(MV, nullptr, nullptr) || MV.isAbsolute()) return; const MCSymbolRefExpr *SymA = MV.getSymA(); if (!SymA) return; // Check that GOT equivalent symbol is cached. const MCSymbol *GOTEquivSym = &SymA->getSymbol(); if (!AP.GlobalGOTEquivs.count(GOTEquivSym)) return; const GlobalValue *BaseGV = dyn_cast_or_null(BaseCst); if (!BaseGV) return; // Check for a valid base symbol const MCSymbol *BaseSym = AP.getSymbol(BaseGV); const MCSymbolRefExpr *SymB = MV.getSymB(); if (!SymB || BaseSym != &SymB->getSymbol()) return; // Make sure to match: // // gotpcrelcst := + // // If gotpcrelcst is positive it means that we can safely fold the pc rel // displacement into the GOTPCREL. We can also can have an extra offset // if the target knows how to encode it. // int64_t GOTPCRelCst = Offset + MV.getConstant(); if (GOTPCRelCst < 0) return; if (!AP.getObjFileLowering().supportGOTPCRelWithOffset() && GOTPCRelCst != 0) return; // Emit the GOT PC relative to replace the got equivalent global, i.e.: // // bar: // .long 42 // gotequiv: // .quad bar // foo: // .long gotequiv - "." + // // is replaced by the target specific equivalent to: // // bar: // .long 42 // foo: // .long bar@GOTPCREL+ // AsmPrinter::GOTEquivUsePair Result = AP.GlobalGOTEquivs[GOTEquivSym]; const GlobalVariable *GV = Result.first; int NumUses = (int)Result.second; const GlobalValue *FinalGV = dyn_cast(GV->getOperand(0)); const MCSymbol *FinalSym = AP.getSymbol(FinalGV); *ME = AP.getObjFileLowering().getIndirectSymViaGOTPCRel( FinalSym, MV, Offset, AP.MMI, *AP.OutStreamer); // Update GOT equivalent usage information --NumUses; if (NumUses >= 0) AP.GlobalGOTEquivs[GOTEquivSym] = std::make_pair(GV, NumUses); } static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV, AsmPrinter &AP, const Constant *BaseCV, uint64_t Offset) { uint64_t Size = DL.getTypeAllocSize(CV->getType()); // Globals with sub-elements such as combinations of arrays and structs // are handled recursively by emitGlobalConstantImpl. Keep track of the // constant symbol base and the current position with BaseCV and Offset. if (!BaseCV && CV->hasOneUse()) BaseCV = dyn_cast(CV->user_back()); if (isa(CV) || isa(CV)) return AP.OutStreamer->EmitZeros(Size); if (const ConstantInt *CI = dyn_cast(CV)) { switch (Size) { case 1: case 2: case 4: case 8: if (AP.isVerbose()) AP.OutStreamer->GetCommentOS() << format("0x%" PRIx64 "\n", CI->getZExtValue()); AP.OutStreamer->EmitIntValue(CI->getZExtValue(), Size); return; default: emitGlobalConstantLargeInt(CI, AP); return; } } if (const ConstantFP *CFP = dyn_cast(CV)) return emitGlobalConstantFP(CFP, AP); if (isa(CV)) { AP.OutStreamer->EmitIntValue(0, Size); return; } if (const ConstantDataSequential *CDS = dyn_cast(CV)) return emitGlobalConstantDataSequential(DL, CDS, AP); if (const ConstantArray *CVA = dyn_cast(CV)) return emitGlobalConstantArray(DL, CVA, AP, BaseCV, Offset); if (const ConstantStruct *CVS = dyn_cast(CV)) return emitGlobalConstantStruct(DL, CVS, AP, BaseCV, Offset); if (const ConstantExpr *CE = dyn_cast(CV)) { // Look through bitcasts, which might not be able to be MCExpr'ized (e.g. of // vectors). if (CE->getOpcode() == Instruction::BitCast) return emitGlobalConstantImpl(DL, CE->getOperand(0), AP); if (Size > 8) { // If the constant expression's size is greater than 64-bits, then we have // to emit the value in chunks. Try to constant fold the value and emit it // that way. Constant *New = ConstantFoldConstant(CE, DL); if (New && New != CE) return emitGlobalConstantImpl(DL, New, AP); } } if (const ConstantVector *V = dyn_cast(CV)) return emitGlobalConstantVector(DL, V, AP); // Otherwise, it must be a ConstantExpr. Lower it to an MCExpr, then emit it // thread the streamer with EmitValue. const MCExpr *ME = AP.lowerConstant(CV); // Since lowerConstant already folded and got rid of all IR pointer and // integer casts, detect GOT equivalent accesses by looking into the MCExpr // directly. if (AP.getObjFileLowering().supportIndirectSymViaGOTPCRel()) handleIndirectSymViaGOTPCRel(AP, &ME, BaseCV, Offset); AP.OutStreamer->EmitValue(ME, Size); } /// EmitGlobalConstant - Print a general LLVM constant to the .s file. void AsmPrinter::EmitGlobalConstant(const DataLayout &DL, const Constant *CV) { uint64_t Size = DL.getTypeAllocSize(CV->getType()); if (Size) emitGlobalConstantImpl(DL, CV, *this); else if (MAI->hasSubsectionsViaSymbols()) { // If the global has zero size, emit a single byte so that two labels don't // look like they are at the same location. OutStreamer->EmitIntValue(0, 1); } } void AsmPrinter::EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { // Target doesn't support this yet! llvm_unreachable("Target does not support EmitMachineConstantPoolValue"); } void AsmPrinter::printOffset(int64_t Offset, raw_ostream &OS) const { if (Offset > 0) OS << '+' << Offset; else if (Offset < 0) OS << Offset; } //===----------------------------------------------------------------------===// // Symbol Lowering Routines. //===----------------------------------------------------------------------===// MCSymbol *AsmPrinter::createTempSymbol(const Twine &Name) const { return OutContext.createTempSymbol(Name, true); } MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BlockAddress *BA) const { return MMI->getAddrLabelSymbol(BA->getBasicBlock()); } MCSymbol *AsmPrinter::GetBlockAddressSymbol(const BasicBlock *BB) const { return MMI->getAddrLabelSymbol(BB); } /// GetCPISymbol - Return the symbol for the specified constant pool entry. MCSymbol *AsmPrinter::GetCPISymbol(unsigned CPID) const { const DataLayout &DL = getDataLayout(); return OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + "CPI" + Twine(getFunctionNumber()) + "_" + Twine(CPID)); } /// GetJTISymbol - Return the symbol for the specified jump table entry. MCSymbol *AsmPrinter::GetJTISymbol(unsigned JTID, bool isLinkerPrivate) const { return MF->getJTISymbol(JTID, OutContext, isLinkerPrivate); } /// GetJTSetSymbol - Return the symbol for the specified jump table .set /// FIXME: privatize to AsmPrinter. MCSymbol *AsmPrinter::GetJTSetSymbol(unsigned UID, unsigned MBBID) const { const DataLayout &DL = getDataLayout(); return OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + Twine(getFunctionNumber()) + "_" + Twine(UID) + "_set_" + Twine(MBBID)); } MCSymbol *AsmPrinter::getSymbolWithGlobalValueBase(const GlobalValue *GV, StringRef Suffix) const { return getObjFileLowering().getSymbolWithGlobalValueBase(GV, Suffix, TM); } /// Return the MCSymbol for the specified ExternalSymbol. MCSymbol *AsmPrinter::GetExternalSymbolSymbol(StringRef Sym) const { SmallString<60> NameStr; Mangler::getNameWithPrefix(NameStr, Sym, getDataLayout()); return OutContext.getOrCreateSymbol(NameStr); } /// PrintParentLoopComment - Print comments about parent loops of this one. static void PrintParentLoopComment(raw_ostream &OS, const MachineLoop *Loop, unsigned FunctionNumber) { if (!Loop) return; PrintParentLoopComment(OS, Loop->getParentLoop(), FunctionNumber); OS.indent(Loop->getLoopDepth()*2) << "Parent Loop BB" << FunctionNumber << "_" << Loop->getHeader()->getNumber() << " Depth=" << Loop->getLoopDepth() << '\n'; } /// PrintChildLoopComment - Print comments about child loops within /// the loop for this basic block, with nesting. static void PrintChildLoopComment(raw_ostream &OS, const MachineLoop *Loop, unsigned FunctionNumber) { // Add child loop information for (const MachineLoop *CL : *Loop) { OS.indent(CL->getLoopDepth()*2) << "Child Loop BB" << FunctionNumber << "_" << CL->getHeader()->getNumber() << " Depth " << CL->getLoopDepth() << '\n'; PrintChildLoopComment(OS, CL, FunctionNumber); } } /// emitBasicBlockLoopComments - Pretty-print comments for basic blocks. static void emitBasicBlockLoopComments(const MachineBasicBlock &MBB, const MachineLoopInfo *LI, const AsmPrinter &AP) { // Add loop depth information const MachineLoop *Loop = LI->getLoopFor(&MBB); if (!Loop) return; MachineBasicBlock *Header = Loop->getHeader(); assert(Header && "No header for loop"); // If this block is not a loop header, just print out what is the loop header // and return. if (Header != &MBB) { AP.OutStreamer->AddComment(" in Loop: Header=BB" + Twine(AP.getFunctionNumber())+"_" + Twine(Loop->getHeader()->getNumber())+ " Depth="+Twine(Loop->getLoopDepth())); return; } // Otherwise, it is a loop header. Print out information about child and // parent loops. raw_ostream &OS = AP.OutStreamer->GetCommentOS(); PrintParentLoopComment(OS, Loop->getParentLoop(), AP.getFunctionNumber()); OS << "=>"; OS.indent(Loop->getLoopDepth()*2-2); OS << "This "; if (Loop->empty()) OS << "Inner "; OS << "Loop Header: Depth=" + Twine(Loop->getLoopDepth()) << '\n'; PrintChildLoopComment(OS, Loop, AP.getFunctionNumber()); } /// EmitBasicBlockStart - This method prints the label for the specified /// MachineBasicBlock, an alignment (if present) and a comment describing /// it if appropriate. void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const { // End the previous funclet and start a new one. if (MBB.isEHFuncletEntry()) { for (const HandlerInfo &HI : Handlers) { HI.Handler->endFunclet(); HI.Handler->beginFunclet(MBB); } } // Emit an alignment directive for this block, if needed. if (unsigned Align = MBB.getAlignment()) EmitAlignment(Align); // If the block has its address taken, emit any labels that were used to // reference the block. It is possible that there is more than one label // here, because multiple LLVM BB's may have been RAUW'd to this block after // the references were generated. if (MBB.hasAddressTaken()) { const BasicBlock *BB = MBB.getBasicBlock(); if (isVerbose()) OutStreamer->AddComment("Block address taken"); // MBBs can have their address taken as part of CodeGen without having // their corresponding BB's address taken in IR if (BB->hasAddressTaken()) for (MCSymbol *Sym : MMI->getAddrLabelSymbolToEmit(BB)) OutStreamer->EmitLabel(Sym); } // Print some verbose block comments. if (isVerbose()) { if (const BasicBlock *BB = MBB.getBasicBlock()) { if (BB->hasName()) { BB->printAsOperand(OutStreamer->GetCommentOS(), /*PrintType=*/false, BB->getModule()); OutStreamer->GetCommentOS() << '\n'; } } emitBasicBlockLoopComments(MBB, LI, *this); } // Print the main label for the block. if (MBB.pred_empty() || (isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) { if (isVerbose()) { // NOTE: Want this comment at start of line, don't emit with AddComment. OutStreamer->emitRawComment(" BB#" + Twine(MBB.getNumber()) + ":", false); } } else { OutStreamer->EmitLabel(MBB.getSymbol()); } } void AsmPrinter::EmitVisibility(MCSymbol *Sym, unsigned Visibility, bool IsDefinition) const { MCSymbolAttr Attr = MCSA_Invalid; switch (Visibility) { default: break; case GlobalValue::HiddenVisibility: if (IsDefinition) Attr = MAI->getHiddenVisibilityAttr(); else Attr = MAI->getHiddenDeclarationVisibilityAttr(); break; case GlobalValue::ProtectedVisibility: Attr = MAI->getProtectedVisibilityAttr(); break; } if (Attr != MCSA_Invalid) OutStreamer->EmitSymbolAttribute(Sym, Attr); } /// isBlockOnlyReachableByFallthough - Return true if the basic block has /// exactly one predecessor and the control transfer mechanism between /// the predecessor and this block is a fall-through. bool AsmPrinter:: isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { // If this is a landing pad, it isn't a fall through. If it has no preds, // then nothing falls through to it. if (MBB->isEHPad() || MBB->pred_empty()) return false; // If there isn't exactly one predecessor, it can't be a fall through. if (MBB->pred_size() > 1) return false; // The predecessor has to be immediately before this block. MachineBasicBlock *Pred = *MBB->pred_begin(); if (!Pred->isLayoutSuccessor(MBB)) return false; // If the block is completely empty, then it definitely does fall through. if (Pred->empty()) return true; // Check the terminators in the previous blocks for (const auto &MI : Pred->terminators()) { // If it is not a simple branch, we are in a table somewhere. if (!MI.isBranch() || MI.isIndirectBranch()) return false; // If we are the operands of one of the branches, this is not a fall // through. Note that targets with delay slots will usually bundle // terminators with the delay slot instruction. for (ConstMIBundleOperands OP(MI); OP.isValid(); ++OP) { if (OP->isJTI()) return false; if (OP->isMBB() && OP->getMBB() == MBB) return false; } } return true; } GCMetadataPrinter *AsmPrinter::GetOrCreateGCPrinter(GCStrategy &S) { if (!S.usesMetadata()) return nullptr; assert(!S.useStatepoints() && "statepoints do not currently support custom" " stackmap formats, please see the documentation for a description of" " the default format. If you really need a custom serialized format," " please file a bug"); gcp_map_type &GCMap = getGCMap(GCMetadataPrinters); gcp_map_type::iterator GCPI = GCMap.find(&S); if (GCPI != GCMap.end()) return GCPI->second.get(); auto Name = S.getName(); for (GCMetadataPrinterRegistry::iterator I = GCMetadataPrinterRegistry::begin(), E = GCMetadataPrinterRegistry::end(); I != E; ++I) if (Name == I->getName()) { std::unique_ptr GMP = I->instantiate(); GMP->S = &S; auto IterBool = GCMap.insert(std::make_pair(&S, std::move(GMP))); return IterBool.first->second.get(); } report_fatal_error("no GCMetadataPrinter registered for GC: " + Twine(Name)); } /// Pin vtable to this file. AsmPrinterHandler::~AsmPrinterHandler() {} void AsmPrinterHandler::markFunctionEnd() {} // In the binary's "xray_instr_map" section, an array of these function entries // describes each instrumentation point. When XRay patches your code, the index // into this table will be given to your handler as a patch point identifier. void AsmPrinter::XRayFunctionEntry::emit(int Bytes, MCStreamer *Out, const MCSymbol *CurrentFnSym) const { Out->EmitSymbolValue(Sled, Bytes); Out->EmitSymbolValue(CurrentFnSym, Bytes); auto Kind8 = static_cast(Kind); Out->EmitBytes(StringRef(reinterpret_cast(&Kind8), 1)); Out->EmitBytes( StringRef(reinterpret_cast(&AlwaysInstrument), 1)); Out->EmitZeros(2 * Bytes - 2); // Pad the previous two entries } void AsmPrinter::emitXRayTable() { if (Sleds.empty()) return; auto PrevSection = OutStreamer->getCurrentSectionOnly(); auto Fn = MF->getFunction(); MCSection *Section = nullptr; if (MF->getSubtarget().getTargetTriple().isOSBinFormatELF()) { if (Fn->hasComdat()) { Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Fn->getComdat()->getName()); } else { Section = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); } } else if (MF->getSubtarget().getTargetTriple().isOSBinFormatMachO()) { Section = OutContext.getMachOSection("__DATA", "xray_instr_map", 0, SectionKind::getReadOnlyWithRel()); } else { llvm_unreachable("Unsupported target"); } // Before we switch over, we force a reference to a label inside the // xray_instr_map section. Since this function is always called just // before the function's end, we assume that this is happening after // the last return instruction. auto WordSizeBytes = TM.getPointerSize(); MCSymbol *Tmp = OutContext.createTempSymbol("xray_synthetic_", true); OutStreamer->EmitCodeAlignment(16); OutStreamer->EmitSymbolValue(Tmp, WordSizeBytes, false); OutStreamer->SwitchSection(Section); OutStreamer->EmitLabel(Tmp); for (const auto &Sled : Sleds) Sled.emit(WordSizeBytes, OutStreamer.get(), CurrentFnSym); OutStreamer->SwitchSection(PrevSection); Sleds.clear(); } void AsmPrinter::recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind) { auto Fn = MI.getParent()->getParent()->getFunction(); auto Attr = Fn->getFnAttribute("function-instrument"); bool AlwaysInstrument = Attr.isStringAttribute() && Attr.getValueAsString() == "xray-always"; Sleds.emplace_back( XRayFunctionEntry{ Sled, CurrentFnSym, Kind, AlwaysInstrument, Fn }); } uint16_t AsmPrinter::getDwarfVersion() const { return OutStreamer->getContext().getDwarfVersion(); } void AsmPrinter::setDwarfVersion(uint16_t Version) { OutStreamer->getContext().setDwarfVersion(Version); } Index: vendor/llvm/dist/lib/CodeGen/AsmPrinter/DIE.cpp =================================================================== --- vendor/llvm/dist/lib/CodeGen/AsmPrinter/DIE.cpp (revision 313055) +++ vendor/llvm/dist/lib/CodeGen/AsmPrinter/DIE.cpp (revision 313056) @@ -1,824 +1,824 @@ //===--- lib/CodeGen/DIE.cpp - DWARF Info Entries -------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Data structures for DWARF info entries. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/DIE.h" #include "DwarfCompileUnit.h" #include "DwarfDebug.h" #include "DwarfUnit.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; //===----------------------------------------------------------------------===// // DIEAbbrevData Implementation //===----------------------------------------------------------------------===// /// Profile - Used to gather unique data for the abbreviation folding set. /// void DIEAbbrevData::Profile(FoldingSetNodeID &ID) const { // Explicitly cast to an integer type for which FoldingSetNodeID has // overloads. Otherwise MSVC 2010 thinks this call is ambiguous. ID.AddInteger(unsigned(Attribute)); ID.AddInteger(unsigned(Form)); } //===----------------------------------------------------------------------===// // DIEAbbrev Implementation //===----------------------------------------------------------------------===// /// Profile - Used to gather unique data for the abbreviation folding set. /// void DIEAbbrev::Profile(FoldingSetNodeID &ID) const { ID.AddInteger(unsigned(Tag)); ID.AddInteger(unsigned(Children)); // For each attribute description. for (unsigned i = 0, N = Data.size(); i < N; ++i) Data[i].Profile(ID); } /// Emit - Print the abbreviation using the specified asm printer. /// void DIEAbbrev::Emit(const AsmPrinter *AP) const { // Emit its Dwarf tag type. AP->EmitULEB128(Tag, dwarf::TagString(Tag).data()); // Emit whether it has children DIEs. AP->EmitULEB128((unsigned)Children, dwarf::ChildrenString(Children).data()); // For each attribute description. for (unsigned i = 0, N = Data.size(); i < N; ++i) { const DIEAbbrevData &AttrData = Data[i]; // Emit attribute type. AP->EmitULEB128(AttrData.getAttribute(), dwarf::AttributeString(AttrData.getAttribute()).data()); // Emit form type. AP->EmitULEB128(AttrData.getForm(), dwarf::FormEncodingString(AttrData.getForm()).data()); // Emit value for DW_FORM_implicit_const. if (AttrData.getForm() == dwarf::DW_FORM_implicit_const) { assert(AP->getDwarfVersion() >= 5 && "DW_FORM_implicit_const is supported starting from DWARFv5"); AP->EmitSLEB128(AttrData.getValue()); } } // Mark end of abbreviation. AP->EmitULEB128(0, "EOM(1)"); AP->EmitULEB128(0, "EOM(2)"); } LLVM_DUMP_METHOD void DIEAbbrev::print(raw_ostream &O) { O << "Abbreviation @" << format("0x%lx", (long)(intptr_t)this) << " " << dwarf::TagString(Tag) << " " << dwarf::ChildrenString(Children) << '\n'; for (unsigned i = 0, N = Data.size(); i < N; ++i) { O << " " << dwarf::AttributeString(Data[i].getAttribute()) << " " << dwarf::FormEncodingString(Data[i].getForm()) << '\n'; } } LLVM_DUMP_METHOD void DIEAbbrev::dump() { print(dbgs()); } //===----------------------------------------------------------------------===// // DIEAbbrevSet Implementation //===----------------------------------------------------------------------===// DIEAbbrevSet::~DIEAbbrevSet() { for (DIEAbbrev *Abbrev : Abbreviations) Abbrev->~DIEAbbrev(); } DIEAbbrev &DIEAbbrevSet::uniqueAbbreviation(DIE &Die) { FoldingSetNodeID ID; DIEAbbrev Abbrev = Die.generateAbbrev(); Abbrev.Profile(ID); void *InsertPos; if (DIEAbbrev *Existing = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertPos)) { Die.setAbbrevNumber(Existing->getNumber()); return *Existing; } // Move the abbreviation to the heap and assign a number. DIEAbbrev *New = new (Alloc) DIEAbbrev(std::move(Abbrev)); Abbreviations.push_back(New); New->setNumber(Abbreviations.size()); Die.setAbbrevNumber(Abbreviations.size()); // Store it for lookup. AbbreviationsSet.InsertNode(New, InsertPos); return *New; } void DIEAbbrevSet::Emit(const AsmPrinter *AP, MCSection *Section) const { if (!Abbreviations.empty()) { // Start the debug abbrev section. AP->OutStreamer->SwitchSection(Section); AP->emitDwarfAbbrevs(Abbreviations); } } //===----------------------------------------------------------------------===// // DIE Implementation //===----------------------------------------------------------------------===// DIE *DIE::getParent() const { return Owner.dyn_cast(); } DIEAbbrev DIE::generateAbbrev() const { DIEAbbrev Abbrev(Tag, hasChildren()); for (const DIEValue &V : values()) if (V.getForm() == dwarf::DW_FORM_implicit_const) Abbrev.AddImplicitConstAttribute(V.getAttribute(), V.getDIEInteger().getValue()); else Abbrev.AddAttribute(V.getAttribute(), V.getForm()); return Abbrev; } unsigned DIE::getDebugSectionOffset() const { const DIEUnit *Unit = getUnit(); assert(Unit && "DIE must be owned by a DIEUnit to get its absolute offset"); return Unit->getDebugSectionOffset() + getOffset(); } const DIE *DIE::getUnitDie() const { const DIE *p = this; while (p) { if (p->getTag() == dwarf::DW_TAG_compile_unit || p->getTag() == dwarf::DW_TAG_type_unit) return p; p = p->getParent(); } return nullptr; } const DIEUnit *DIE::getUnit() const { const DIE *UnitDie = getUnitDie(); if (UnitDie) return UnitDie->Owner.dyn_cast(); return nullptr; } DIEValue DIE::findAttribute(dwarf::Attribute Attribute) const { // Iterate through all the attributes until we find the one we're // looking for, if we can't find it return NULL. for (const auto &V : values()) if (V.getAttribute() == Attribute) return V; return DIEValue(); } LLVM_DUMP_METHOD static void printValues(raw_ostream &O, const DIEValueList &Values, StringRef Type, unsigned Size, unsigned IndentCount) { O << Type << ": Size: " << Size << "\n"; unsigned I = 0; const std::string Indent(IndentCount, ' '); for (const auto &V : Values.values()) { O << Indent; O << "Blk[" << I++ << "]"; O << " " << dwarf::FormEncodingString(V.getForm()) << " "; V.print(O); O << "\n"; } } LLVM_DUMP_METHOD void DIE::print(raw_ostream &O, unsigned IndentCount) const { const std::string Indent(IndentCount, ' '); O << Indent << "Die: " << format("0x%lx", (long)(intptr_t) this) << ", Offset: " << Offset << ", Size: " << Size << "\n"; O << Indent << dwarf::TagString(getTag()) << " " << dwarf::ChildrenString(hasChildren()) << "\n"; IndentCount += 2; for (const auto &V : values()) { O << Indent; O << dwarf::AttributeString(V.getAttribute()); O << " " << dwarf::FormEncodingString(V.getForm()) << " "; V.print(O); O << "\n"; } IndentCount -= 2; for (const auto &Child : children()) Child.print(O, IndentCount + 4); O << "\n"; } LLVM_DUMP_METHOD void DIE::dump() { print(dbgs()); } unsigned DIE::computeOffsetsAndAbbrevs(const AsmPrinter *AP, DIEAbbrevSet &AbbrevSet, unsigned CUOffset) { // Unique the abbreviation and fill in the abbreviation number so this DIE // can be emitted. const DIEAbbrev &Abbrev = AbbrevSet.uniqueAbbreviation(*this); // Set compile/type unit relative offset of this DIE. setOffset(CUOffset); // Add the byte size of the abbreviation code. CUOffset += getULEB128Size(getAbbrevNumber()); // Add the byte size of all the DIE attribute values. for (const auto &V : values()) CUOffset += V.SizeOf(AP); // Let the children compute their offsets and abbreviation numbers. if (hasChildren()) { (void)Abbrev; assert(Abbrev.hasChildren() && "Children flag not set"); for (auto &Child : children()) CUOffset = Child.computeOffsetsAndAbbrevs(AP, AbbrevSet, CUOffset); // Each child chain is terminated with a zero byte, adjust the offset. CUOffset += sizeof(int8_t); } // Compute the byte size of this DIE and all of its children correctly. This // is needed so that top level DIE can help the compile unit set its length // correctly. setSize(CUOffset - getOffset()); return CUOffset; } //===----------------------------------------------------------------------===// // DIEUnit Implementation //===----------------------------------------------------------------------===// DIEUnit::DIEUnit(uint16_t V, uint8_t A, dwarf::Tag UnitTag) : Die(UnitTag), Section(nullptr), Offset(0), Length(0), Version(V), AddrSize(A) { Die.Owner = this; assert((UnitTag == dwarf::DW_TAG_compile_unit || UnitTag == dwarf::DW_TAG_type_unit || UnitTag == dwarf::DW_TAG_partial_unit) && "expected a unit TAG"); } void DIEValue::EmitValue(const AsmPrinter *AP) const { switch (Ty) { case isNone: llvm_unreachable("Expected valid DIEValue"); #define HANDLE_DIEVALUE(T) \ case is##T: \ getDIE##T().EmitValue(AP, Form); \ break; #include "llvm/CodeGen/DIEValue.def" } } unsigned DIEValue::SizeOf(const AsmPrinter *AP) const { switch (Ty) { case isNone: llvm_unreachable("Expected valid DIEValue"); #define HANDLE_DIEVALUE(T) \ case is##T: \ return getDIE##T().SizeOf(AP, Form); #include "llvm/CodeGen/DIEValue.def" } llvm_unreachable("Unknown DIE kind"); } LLVM_DUMP_METHOD void DIEValue::print(raw_ostream &O) const { switch (Ty) { case isNone: llvm_unreachable("Expected valid DIEValue"); #define HANDLE_DIEVALUE(T) \ case is##T: \ getDIE##T().print(O); \ break; #include "llvm/CodeGen/DIEValue.def" } } LLVM_DUMP_METHOD void DIEValue::dump() const { print(dbgs()); } //===----------------------------------------------------------------------===// // DIEInteger Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit integer of appropriate size. /// void DIEInteger::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_implicit_const: LLVM_FALLTHROUGH; case dwarf::DW_FORM_flag_present: // Emit something to keep the lines and comments in sync. // FIXME: Is there a better way to do this? Asm->OutStreamer->AddBlankLine(); return; case dwarf::DW_FORM_flag: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref1: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data1: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data2: LLVM_FALLTHROUGH; case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data4: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_ref_alt: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_strp_alt: LLVM_FALLTHROUGH; case dwarf::DW_FORM_line_strp: LLVM_FALLTHROUGH; case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH; case dwarf::DW_FORM_strp_sup: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_sup: LLVM_FALLTHROUGH; case dwarf::DW_FORM_addr: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_addr: Asm->OutStreamer->EmitIntValue(Integer, SizeOf(Asm, Form)); return; case dwarf::DW_FORM_GNU_str_index: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_addr_index: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_udata: LLVM_FALLTHROUGH; case dwarf::DW_FORM_udata: Asm->EmitULEB128(Integer); return; case dwarf::DW_FORM_sdata: Asm->EmitSLEB128(Integer); return; default: llvm_unreachable("DIE Value form not supported yet"); } } /// SizeOf - Determine size of integer value in bytes. /// unsigned DIEInteger::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_implicit_const: LLVM_FALLTHROUGH; case dwarf::DW_FORM_flag_present: return 0; case dwarf::DW_FORM_flag: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref1: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data1: return sizeof(int8_t); case dwarf::DW_FORM_ref2: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data2: return sizeof(int16_t); case dwarf::DW_FORM_ref4: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data4: return sizeof(int32_t); case dwarf::DW_FORM_ref8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_sig8: LLVM_FALLTHROUGH; case dwarf::DW_FORM_data8: return sizeof(int64_t); case dwarf::DW_FORM_ref_addr: if (AP->getDwarfVersion() == 2) return AP->getPointerSize(); LLVM_FALLTHROUGH; case dwarf::DW_FORM_strp: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_ref_alt: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_strp_alt: LLVM_FALLTHROUGH; case dwarf::DW_FORM_line_strp: LLVM_FALLTHROUGH; case dwarf::DW_FORM_sec_offset: LLVM_FALLTHROUGH; case dwarf::DW_FORM_strp_sup: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_sup: switch (AP->OutStreamer->getContext().getDwarfFormat()) { case dwarf::DWARF32: return 4; case dwarf::DWARF64: return 8; } llvm_unreachable("Invalid DWARF format"); case dwarf::DW_FORM_GNU_str_index: LLVM_FALLTHROUGH; case dwarf::DW_FORM_GNU_addr_index: LLVM_FALLTHROUGH; case dwarf::DW_FORM_ref_udata: LLVM_FALLTHROUGH; case dwarf::DW_FORM_udata: return getULEB128Size(Integer); case dwarf::DW_FORM_sdata: return getSLEB128Size(Integer); case dwarf::DW_FORM_addr: return AP->getPointerSize(); default: llvm_unreachable("DIE Value form not supported yet"); } } LLVM_DUMP_METHOD void DIEInteger::print(raw_ostream &O) const { O << "Int: " << (int64_t)Integer << " 0x"; O.write_hex(Integer); } //===----------------------------------------------------------------------===// // DIEExpr Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit expression value. /// void DIEExpr::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { - AP->OutStreamer->EmitValue(Expr, SizeOf(AP, Form)); + AP->EmitDebugValue(Expr, SizeOf(AP, Form)); } /// SizeOf - Determine size of expression value in bytes. /// unsigned DIEExpr::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_data4) return 4; if (Form == dwarf::DW_FORM_sec_offset) return 4; if (Form == dwarf::DW_FORM_strp) return 4; return AP->getPointerSize(); } LLVM_DUMP_METHOD void DIEExpr::print(raw_ostream &O) const { O << "Expr: " << *Expr; } //===----------------------------------------------------------------------===// // DIELabel Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit label value. /// void DIELabel::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { AP->EmitLabelReference(Label, SizeOf(AP, Form), Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_sec_offset || Form == dwarf::DW_FORM_ref_addr || Form == dwarf::DW_FORM_data4); } /// SizeOf - Determine size of label value in bytes. /// unsigned DIELabel::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_data4) return 4; if (Form == dwarf::DW_FORM_sec_offset) return 4; if (Form == dwarf::DW_FORM_strp) return 4; return AP->getPointerSize(); } LLVM_DUMP_METHOD void DIELabel::print(raw_ostream &O) const { O << "Lbl: " << Label->getName(); } //===----------------------------------------------------------------------===// // DIEDelta Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit delta value. /// void DIEDelta::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { AP->EmitLabelDifference(LabelHi, LabelLo, SizeOf(AP, Form)); } /// SizeOf - Determine size of delta value in bytes. /// unsigned DIEDelta::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_data4) return 4; if (Form == dwarf::DW_FORM_sec_offset) return 4; if (Form == dwarf::DW_FORM_strp) return 4; return AP->getPointerSize(); } LLVM_DUMP_METHOD void DIEDelta::print(raw_ostream &O) const { O << "Del: " << LabelHi->getName() << "-" << LabelLo->getName(); } //===----------------------------------------------------------------------===// // DIEString Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit string value. /// void DIEString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { assert( (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && "Expected valid string form"); // Index of string in symbol table. if (Form == dwarf::DW_FORM_GNU_str_index) { DIEInteger(S.getIndex()).EmitValue(AP, Form); return; } // Relocatable symbol. assert(Form == dwarf::DW_FORM_strp); if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) { DIELabel(S.getSymbol()).EmitValue(AP, Form); return; } // Offset into symbol table. DIEInteger(S.getOffset()).EmitValue(AP, Form); } /// SizeOf - Determine size of delta value in bytes. /// unsigned DIEString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { assert( (Form == dwarf::DW_FORM_strp || Form == dwarf::DW_FORM_GNU_str_index) && "Expected valid string form"); // Index of string in symbol table. if (Form == dwarf::DW_FORM_GNU_str_index) return DIEInteger(S.getIndex()).SizeOf(AP, Form); // Relocatable symbol. if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) return DIELabel(S.getSymbol()).SizeOf(AP, Form); // Offset into symbol table. return DIEInteger(S.getOffset()).SizeOf(AP, Form); } LLVM_DUMP_METHOD void DIEString::print(raw_ostream &O) const { O << "String: " << S.getString(); } //===----------------------------------------------------------------------===// // DIEInlineString Implementation //===----------------------------------------------------------------------===// void DIEInlineString::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_string) { for (char ch : S) AP->EmitInt8(ch); AP->EmitInt8(0); return; } llvm_unreachable("Expected valid string form"); } unsigned DIEInlineString::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { // Emit string bytes + NULL byte. return S.size() + 1; } LLVM_DUMP_METHOD void DIEInlineString::print(raw_ostream &O) const { O << "InlineString: " << S; } //===----------------------------------------------------------------------===// // DIEEntry Implementation //===----------------------------------------------------------------------===// /// EmitValue - Emit debug information entry offset. /// void DIEEntry::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_ref1: case dwarf::DW_FORM_ref2: case dwarf::DW_FORM_ref4: case dwarf::DW_FORM_ref8: AP->OutStreamer->EmitIntValue(Entry->getOffset(), SizeOf(AP, Form)); return; case dwarf::DW_FORM_ref_udata: AP->EmitULEB128(Entry->getOffset()); return; case dwarf::DW_FORM_ref_addr: { // Get the absolute offset for this DIE within the debug info/types section. unsigned Addr = Entry->getDebugSectionOffset(); if (AP->MAI->doesDwarfUseRelocationsAcrossSections()) { const DwarfDebug *DD = AP->getDwarfDebug(); if (DD) assert(!DD->useSplitDwarf() && "TODO: dwo files can't have relocations."); const DIEUnit *Unit = Entry->getUnit(); assert(Unit && "CUDie should belong to a CU."); MCSection *Section = Unit->getSection(); if (Section) { const MCSymbol *SectionSym = Section->getBeginSymbol(); AP->EmitLabelPlusOffset(SectionSym, Addr, SizeOf(AP, Form), true); return; } } AP->OutStreamer->EmitIntValue(Addr, SizeOf(AP, Form)); return; } default: llvm_unreachable("Improper form for DIE reference"); } } unsigned DIEEntry::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_ref1: return 1; case dwarf::DW_FORM_ref2: return 2; case dwarf::DW_FORM_ref4: return 4; case dwarf::DW_FORM_ref8: return 8; case dwarf::DW_FORM_ref_udata: return getULEB128Size(Entry->getOffset()); case dwarf::DW_FORM_ref_addr: if (AP->getDwarfVersion() == 2) return AP->getPointerSize(); switch (AP->OutStreamer->getContext().getDwarfFormat()) { case dwarf::DWARF32: return 4; case dwarf::DWARF64: return 8; } llvm_unreachable("Invalid DWARF format"); default: llvm_unreachable("Improper form for DIE reference"); } } LLVM_DUMP_METHOD void DIEEntry::print(raw_ostream &O) const { O << format("Die: 0x%lx", (long)(intptr_t)&Entry); } //===----------------------------------------------------------------------===// // DIELoc Implementation //===----------------------------------------------------------------------===// /// ComputeSize - calculate the size of the location expression. /// unsigned DIELoc::ComputeSize(const AsmPrinter *AP) const { if (!Size) { for (const auto &V : values()) Size += V.SizeOf(AP); } return Size; } /// EmitValue - Emit location data. /// void DIELoc::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { default: llvm_unreachable("Improper form for block"); case dwarf::DW_FORM_block1: Asm->EmitInt8(Size); break; case dwarf::DW_FORM_block2: Asm->EmitInt16(Size); break; case dwarf::DW_FORM_block4: Asm->EmitInt32(Size); break; case dwarf::DW_FORM_block: case dwarf::DW_FORM_exprloc: Asm->EmitULEB128(Size); break; } for (const auto &V : values()) V.EmitValue(Asm); } /// SizeOf - Determine size of location data in bytes. /// unsigned DIELoc::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_block1: return Size + sizeof(int8_t); case dwarf::DW_FORM_block2: return Size + sizeof(int16_t); case dwarf::DW_FORM_block4: return Size + sizeof(int32_t); case dwarf::DW_FORM_block: case dwarf::DW_FORM_exprloc: return Size + getULEB128Size(Size); default: llvm_unreachable("Improper form for block"); } } LLVM_DUMP_METHOD void DIELoc::print(raw_ostream &O) const { printValues(O, *this, "ExprLoc", Size, 5); } //===----------------------------------------------------------------------===// // DIEBlock Implementation //===----------------------------------------------------------------------===// /// ComputeSize - calculate the size of the block. /// unsigned DIEBlock::ComputeSize(const AsmPrinter *AP) const { if (!Size) { for (const auto &V : values()) Size += V.SizeOf(AP); } return Size; } /// EmitValue - Emit block data. /// void DIEBlock::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const { switch (Form) { default: llvm_unreachable("Improper form for block"); case dwarf::DW_FORM_block1: Asm->EmitInt8(Size); break; case dwarf::DW_FORM_block2: Asm->EmitInt16(Size); break; case dwarf::DW_FORM_block4: Asm->EmitInt32(Size); break; case dwarf::DW_FORM_block: Asm->EmitULEB128(Size); break; } for (const auto &V : values()) V.EmitValue(Asm); } /// SizeOf - Determine size of block data in bytes. /// unsigned DIEBlock::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { switch (Form) { case dwarf::DW_FORM_block1: return Size + sizeof(int8_t); case dwarf::DW_FORM_block2: return Size + sizeof(int16_t); case dwarf::DW_FORM_block4: return Size + sizeof(int32_t); case dwarf::DW_FORM_block: return Size + getULEB128Size(Size); default: llvm_unreachable("Improper form for block"); } } LLVM_DUMP_METHOD void DIEBlock::print(raw_ostream &O) const { printValues(O, *this, "Blk", Size, 5); } //===----------------------------------------------------------------------===// // DIELocList Implementation //===----------------------------------------------------------------------===// unsigned DIELocList::SizeOf(const AsmPrinter *AP, dwarf::Form Form) const { if (Form == dwarf::DW_FORM_data4) return 4; if (Form == dwarf::DW_FORM_sec_offset) return 4; return AP->getPointerSize(); } /// EmitValue - Emit label value. /// void DIELocList::EmitValue(const AsmPrinter *AP, dwarf::Form Form) const { DwarfDebug *DD = AP->getDwarfDebug(); MCSymbol *Label = DD->getDebugLocs().getList(Index).Label; AP->emitDwarfSymbolReference(Label, /*ForceOffset*/ DD->useSplitDwarf()); } LLVM_DUMP_METHOD void DIELocList::print(raw_ostream &O) const { O << "LocList: " << Index; } Index: vendor/llvm/dist/lib/CodeGen/InterleavedAccessPass.cpp =================================================================== --- vendor/llvm/dist/lib/CodeGen/InterleavedAccessPass.cpp (revision 313055) +++ vendor/llvm/dist/lib/CodeGen/InterleavedAccessPass.cpp (revision 313056) @@ -1,450 +1,454 @@ //===--------------------- InterleavedAccessPass.cpp ----------------------===// // // 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 Interleaved Access pass, which identifies // interleaved memory accesses and transforms them into target specific // intrinsics. // // An interleaved load reads data from memory into several vectors, with // DE-interleaving the data on a factor. An interleaved store writes several // vectors to memory with RE-interleaving the data on a factor. // // As interleaved accesses are difficult to identified in CodeGen (mainly // because the VECTOR_SHUFFLE DAG node is quite different from the shufflevector // IR), we identify and transform them to intrinsics in this pass so the // intrinsics can be easily matched into target specific instructions later in // CodeGen. // // E.g. An interleaved load (Factor = 2): // %wide.vec = load <8 x i32>, <8 x i32>* %ptr // %v0 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <0, 2, 4, 6> // %v1 = shuffle <8 x i32> %wide.vec, <8 x i32> undef, <1, 3, 5, 7> // // It could be transformed into a ld2 intrinsic in AArch64 backend or a vld2 // intrinsic in ARM backend. // // In X86, this can be further optimized into a set of target // specific loads followed by an optimized sequence of shuffles. // // E.g. An interleaved store (Factor = 3): // %i.vec = shuffle <8 x i32> %v0, <8 x i32> %v1, // <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> // store <12 x i32> %i.vec, <12 x i32>* %ptr // // It could be transformed into a st3 intrinsic in AArch64 backend or a vst3 // intrinsic in ARM backend. // // Similarly, a set of interleaved stores can be transformed into an optimized // sequence of shuffles followed by a set of target specific stores for X86. //===----------------------------------------------------------------------===// #include "llvm/CodeGen/Passes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/InstIterator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetSubtargetInfo.h" using namespace llvm; #define DEBUG_TYPE "interleaved-access" static cl::opt LowerInterleavedAccesses( "lower-interleaved-accesses", cl::desc("Enable lowering interleaved accesses to intrinsics"), cl::init(true), cl::Hidden); namespace { class InterleavedAccess : public FunctionPass { public: static char ID; InterleavedAccess(const TargetMachine *TM = nullptr) : FunctionPass(ID), DT(nullptr), TM(TM), TLI(nullptr) { initializeInterleavedAccessPass(*PassRegistry::getPassRegistry()); } StringRef getPassName() const override { return "Interleaved Access Pass"; } bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addPreserved(); } private: DominatorTree *DT; const TargetMachine *TM; const TargetLowering *TLI; /// The maximum supported interleave factor. unsigned MaxFactor; /// \brief Transform an interleaved load into target specific intrinsics. bool lowerInterleavedLoad(LoadInst *LI, SmallVector &DeadInsts); /// \brief Transform an interleaved store into target specific intrinsics. bool lowerInterleavedStore(StoreInst *SI, SmallVector &DeadInsts); /// \brief Returns true if the uses of an interleaved load by the /// extractelement instructions in \p Extracts can be replaced by uses of the /// shufflevector instructions in \p Shuffles instead. If so, the necessary /// replacements are also performed. bool tryReplaceExtracts(ArrayRef Extracts, ArrayRef Shuffles); }; } // end anonymous namespace. char InterleavedAccess::ID = 0; INITIALIZE_TM_PASS_BEGIN( InterleavedAccess, "interleaved-access", "Lower interleaved memory accesses to target specific intrinsics", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_TM_PASS_END( InterleavedAccess, "interleaved-access", "Lower interleaved memory accesses to target specific intrinsics", false, false) FunctionPass *llvm::createInterleavedAccessPass(const TargetMachine *TM) { return new InterleavedAccess(TM); } /// \brief Check if the mask is a DE-interleave mask of the given factor /// \p Factor like: /// static bool isDeInterleaveMaskOfFactor(ArrayRef Mask, unsigned Factor, unsigned &Index) { // Check all potential start indices from 0 to (Factor - 1). for (Index = 0; Index < Factor; Index++) { unsigned i = 0; // Check that elements are in ascending order by Factor. Ignore undef // elements. for (; i < Mask.size(); i++) if (Mask[i] >= 0 && static_cast(Mask[i]) != Index + i * Factor) break; if (i == Mask.size()) return true; } return false; } /// \brief Check if the mask is a DE-interleave mask for an interleaved load. /// /// E.g. DE-interleave masks (Factor = 2) could be: /// <0, 2, 4, 6> (mask of index 0 to extract even elements) /// <1, 3, 5, 7> (mask of index 1 to extract odd elements) static bool isDeInterleaveMask(ArrayRef Mask, unsigned &Factor, unsigned &Index, unsigned MaxFactor) { if (Mask.size() < 2) return false; // Check potential Factors. for (Factor = 2; Factor <= MaxFactor; Factor++) if (isDeInterleaveMaskOfFactor(Mask, Factor, Index)) return true; return false; } /// \brief Check if the mask can be used in an interleaved store. // /// It checks for a more general pattern than the RE-interleave mask. /// I.e. /// E.g. For a Factor of 2 (LaneLen=4): <4, 32, 5, 33, 6, 34, 7, 35> /// E.g. For a Factor of 3 (LaneLen=4): <4, 32, 16, 5, 33, 17, 6, 34, 18, 7, 35, 19> /// E.g. For a Factor of 4 (LaneLen=2): <8, 2, 12, 4, 9, 3, 13, 5> /// /// The particular case of an RE-interleave mask is: /// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...> /// E.g. For a Factor of 2 (LaneLen=4): <0, 4, 1, 5, 2, 6, 3, 7> static bool isReInterleaveMask(ArrayRef Mask, unsigned &Factor, - unsigned MaxFactor) { + unsigned MaxFactor, unsigned OpNumElts) { unsigned NumElts = Mask.size(); if (NumElts < 4) return false; // Check potential Factors. for (Factor = 2; Factor <= MaxFactor; Factor++) { if (NumElts % Factor) continue; unsigned LaneLen = NumElts / Factor; if (!isPowerOf2_32(LaneLen)) continue; // Check whether each element matches the general interleaved rule. // Ignore undef elements, as long as the defined elements match the rule. // Outer loop processes all factors (x, y, z in the above example) unsigned I = 0, J; for (; I < Factor; I++) { unsigned SavedLaneValue; unsigned SavedNoUndefs = 0; // Inner loop processes consecutive accesses (x, x+1... in the example) for (J = 0; J < LaneLen - 1; J++) { // Lane computes x's position in the Mask unsigned Lane = J * Factor + I; unsigned NextLane = Lane + Factor; int LaneValue = Mask[Lane]; int NextLaneValue = Mask[NextLane]; // If both are defined, values must be sequential if (LaneValue >= 0 && NextLaneValue >= 0 && LaneValue + 1 != NextLaneValue) break; // If the next value is undef, save the current one as reference if (LaneValue >= 0 && NextLaneValue < 0) { SavedLaneValue = LaneValue; SavedNoUndefs = 1; } // Undefs are allowed, but defined elements must still be consecutive: // i.e.: x,..., undef,..., x + 2,..., undef,..., undef,..., x + 5, .... // Verify this by storing the last non-undef followed by an undef // Check that following non-undef masks are incremented with the // corresponding distance. if (SavedNoUndefs > 0 && LaneValue < 0) { SavedNoUndefs++; if (NextLaneValue >= 0 && SavedLaneValue + SavedNoUndefs != (unsigned)NextLaneValue) break; } } if (J < LaneLen - 1) break; int StartMask = 0; if (Mask[I] >= 0) { // Check that the start of the I range (J=0) is greater than 0 StartMask = Mask[I]; } else if (Mask[(LaneLen - 1) * Factor + I] >= 0) { // StartMask defined by the last value in lane StartMask = Mask[(LaneLen - 1) * Factor + I] - J; } else if (SavedNoUndefs > 0) { // StartMask defined by some non-zero value in the j loop StartMask = SavedLaneValue - (LaneLen - 1 - SavedNoUndefs); } // else StartMask remains set to 0, i.e. all elements are undefs if (StartMask < 0) break; + // We must stay within the vectors; This case can happen with undefs. + if (StartMask + LaneLen > OpNumElts*2) + break; } // Found an interleaved mask of current factor. if (I == Factor) return true; } return false; } bool InterleavedAccess::lowerInterleavedLoad( LoadInst *LI, SmallVector &DeadInsts) { if (!LI->isSimple()) return false; SmallVector Shuffles; SmallVector Extracts; // Check if all users of this load are shufflevectors. If we encounter any // users that are extractelement instructions, we save them to later check if // they can be modifed to extract from one of the shufflevectors instead of // the load. for (auto UI = LI->user_begin(), E = LI->user_end(); UI != E; UI++) { auto *Extract = dyn_cast(*UI); if (Extract && isa(Extract->getIndexOperand())) { Extracts.push_back(Extract); continue; } ShuffleVectorInst *SVI = dyn_cast(*UI); if (!SVI || !isa(SVI->getOperand(1))) return false; Shuffles.push_back(SVI); } if (Shuffles.empty()) return false; unsigned Factor, Index; // Check if the first shufflevector is DE-interleave shuffle. if (!isDeInterleaveMask(Shuffles[0]->getShuffleMask(), Factor, Index, MaxFactor)) return false; // Holds the corresponding index for each DE-interleave shuffle. SmallVector Indices; Indices.push_back(Index); Type *VecTy = Shuffles[0]->getType(); // Check if other shufflevectors are also DE-interleaved of the same type // and factor as the first shufflevector. for (unsigned i = 1; i < Shuffles.size(); i++) { if (Shuffles[i]->getType() != VecTy) return false; if (!isDeInterleaveMaskOfFactor(Shuffles[i]->getShuffleMask(), Factor, Index)) return false; Indices.push_back(Index); } // Try and modify users of the load that are extractelement instructions to // use the shufflevector instructions instead of the load. if (!tryReplaceExtracts(Extracts, Shuffles)) return false; DEBUG(dbgs() << "IA: Found an interleaved load: " << *LI << "\n"); // Try to create target specific intrinsics to replace the load and shuffles. if (!TLI->lowerInterleavedLoad(LI, Shuffles, Indices, Factor)) return false; for (auto SVI : Shuffles) DeadInsts.push_back(SVI); DeadInsts.push_back(LI); return true; } bool InterleavedAccess::tryReplaceExtracts( ArrayRef Extracts, ArrayRef Shuffles) { // If there aren't any extractelement instructions to modify, there's nothing // to do. if (Extracts.empty()) return true; // Maps extractelement instructions to vector-index pairs. The extractlement // instructions will be modified to use the new vector and index operands. DenseMap> ReplacementMap; for (auto *Extract : Extracts) { // The vector index that is extracted. auto *IndexOperand = cast(Extract->getIndexOperand()); auto Index = IndexOperand->getSExtValue(); // Look for a suitable shufflevector instruction. The goal is to modify the // extractelement instruction (which uses an interleaved load) to use one // of the shufflevector instructions instead of the load. for (auto *Shuffle : Shuffles) { // If the shufflevector instruction doesn't dominate the extract, we // can't create a use of it. if (!DT->dominates(Shuffle, Extract)) continue; // Inspect the indices of the shufflevector instruction. If the shuffle // selects the same index that is extracted, we can modify the // extractelement instruction. SmallVector Indices; Shuffle->getShuffleMask(Indices); for (unsigned I = 0; I < Indices.size(); ++I) if (Indices[I] == Index) { assert(Extract->getOperand(0) == Shuffle->getOperand(0) && "Vector operations do not match"); ReplacementMap[Extract] = std::make_pair(Shuffle, I); break; } // If we found a suitable shufflevector instruction, stop looking. if (ReplacementMap.count(Extract)) break; } // If we did not find a suitable shufflevector instruction, the // extractelement instruction cannot be modified, so we must give up. if (!ReplacementMap.count(Extract)) return false; } // Finally, perform the replacements. IRBuilder<> Builder(Extracts[0]->getContext()); for (auto &Replacement : ReplacementMap) { auto *Extract = Replacement.first; auto *Vector = Replacement.second.first; auto Index = Replacement.second.second; Builder.SetInsertPoint(Extract); Extract->replaceAllUsesWith(Builder.CreateExtractElement(Vector, Index)); Extract->eraseFromParent(); } return true; } bool InterleavedAccess::lowerInterleavedStore( StoreInst *SI, SmallVector &DeadInsts) { if (!SI->isSimple()) return false; ShuffleVectorInst *SVI = dyn_cast(SI->getValueOperand()); if (!SVI || !SVI->hasOneUse()) return false; // Check if the shufflevector is RE-interleave shuffle. unsigned Factor; - if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor)) + unsigned OpNumElts = SVI->getOperand(0)->getType()->getVectorNumElements(); + if (!isReInterleaveMask(SVI->getShuffleMask(), Factor, MaxFactor, OpNumElts)) return false; DEBUG(dbgs() << "IA: Found an interleaved store: " << *SI << "\n"); // Try to create target specific intrinsics to replace the store and shuffle. if (!TLI->lowerInterleavedStore(SI, SVI, Factor)) return false; // Already have a new target specific interleaved store. Erase the old store. DeadInsts.push_back(SI); DeadInsts.push_back(SVI); return true; } bool InterleavedAccess::runOnFunction(Function &F) { if (!TM || !LowerInterleavedAccesses) return false; DEBUG(dbgs() << "*** " << getPassName() << ": " << F.getName() << "\n"); DT = &getAnalysis().getDomTree(); TLI = TM->getSubtargetImpl(F)->getTargetLowering(); MaxFactor = TLI->getMaxSupportedInterleaveFactor(); // Holds dead instructions that will be erased later. SmallVector DeadInsts; bool Changed = false; for (auto &I : instructions(F)) { if (LoadInst *LI = dyn_cast(&I)) Changed |= lowerInterleavedLoad(LI, DeadInsts); if (StoreInst *SI = dyn_cast(&I)) Changed |= lowerInterleavedStore(SI, DeadInsts); } for (auto I : DeadInsts) I->eraseFromParent(); return Changed; } Index: vendor/llvm/dist/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- vendor/llvm/dist/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (revision 313055) +++ vendor/llvm/dist/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp (revision 313056) @@ -1,3669 +1,3679 @@ //===-- SelectionDAGISel.cpp - Implement the SelectionDAGISel class -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This implements the SelectionDAGISel class. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/SelectionDAG.h" #include "ScheduleDAGSDNodes.h" #include "SelectionDAGBuilder.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/ScheduleHazardRecognizer.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/StackProtector.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include using namespace llvm; #define DEBUG_TYPE "isel" STATISTIC(NumFastIselFailures, "Number of instructions fast isel failed on"); STATISTIC(NumFastIselSuccess, "Number of instructions fast isel selected"); STATISTIC(NumFastIselBlocks, "Number of blocks selected entirely by fast isel"); STATISTIC(NumDAGBlocks, "Number of blocks selected using DAG"); STATISTIC(NumDAGIselRetries,"Number of times dag isel has to try another path"); STATISTIC(NumEntryBlocks, "Number of entry blocks encountered"); STATISTIC(NumFastIselFailLowerArguments, "Number of entry blocks where fast isel failed to lower arguments"); #ifndef NDEBUG static cl::opt EnableFastISelVerbose2("fast-isel-verbose2", cl::Hidden, cl::desc("Enable extra verbose messages in the \"fast\" " "instruction selector")); // Terminators STATISTIC(NumFastIselFailRet,"Fast isel fails on Ret"); STATISTIC(NumFastIselFailBr,"Fast isel fails on Br"); STATISTIC(NumFastIselFailSwitch,"Fast isel fails on Switch"); STATISTIC(NumFastIselFailIndirectBr,"Fast isel fails on IndirectBr"); STATISTIC(NumFastIselFailInvoke,"Fast isel fails on Invoke"); STATISTIC(NumFastIselFailResume,"Fast isel fails on Resume"); STATISTIC(NumFastIselFailUnreachable,"Fast isel fails on Unreachable"); // Standard binary operators... STATISTIC(NumFastIselFailAdd,"Fast isel fails on Add"); STATISTIC(NumFastIselFailFAdd,"Fast isel fails on FAdd"); STATISTIC(NumFastIselFailSub,"Fast isel fails on Sub"); STATISTIC(NumFastIselFailFSub,"Fast isel fails on FSub"); STATISTIC(NumFastIselFailMul,"Fast isel fails on Mul"); STATISTIC(NumFastIselFailFMul,"Fast isel fails on FMul"); STATISTIC(NumFastIselFailUDiv,"Fast isel fails on UDiv"); STATISTIC(NumFastIselFailSDiv,"Fast isel fails on SDiv"); STATISTIC(NumFastIselFailFDiv,"Fast isel fails on FDiv"); STATISTIC(NumFastIselFailURem,"Fast isel fails on URem"); STATISTIC(NumFastIselFailSRem,"Fast isel fails on SRem"); STATISTIC(NumFastIselFailFRem,"Fast isel fails on FRem"); // Logical operators... STATISTIC(NumFastIselFailAnd,"Fast isel fails on And"); STATISTIC(NumFastIselFailOr,"Fast isel fails on Or"); STATISTIC(NumFastIselFailXor,"Fast isel fails on Xor"); // Memory instructions... STATISTIC(NumFastIselFailAlloca,"Fast isel fails on Alloca"); STATISTIC(NumFastIselFailLoad,"Fast isel fails on Load"); STATISTIC(NumFastIselFailStore,"Fast isel fails on Store"); STATISTIC(NumFastIselFailAtomicCmpXchg,"Fast isel fails on AtomicCmpXchg"); STATISTIC(NumFastIselFailAtomicRMW,"Fast isel fails on AtomicRWM"); STATISTIC(NumFastIselFailFence,"Fast isel fails on Frence"); STATISTIC(NumFastIselFailGetElementPtr,"Fast isel fails on GetElementPtr"); // Convert instructions... STATISTIC(NumFastIselFailTrunc,"Fast isel fails on Trunc"); STATISTIC(NumFastIselFailZExt,"Fast isel fails on ZExt"); STATISTIC(NumFastIselFailSExt,"Fast isel fails on SExt"); STATISTIC(NumFastIselFailFPTrunc,"Fast isel fails on FPTrunc"); STATISTIC(NumFastIselFailFPExt,"Fast isel fails on FPExt"); STATISTIC(NumFastIselFailFPToUI,"Fast isel fails on FPToUI"); STATISTIC(NumFastIselFailFPToSI,"Fast isel fails on FPToSI"); STATISTIC(NumFastIselFailUIToFP,"Fast isel fails on UIToFP"); STATISTIC(NumFastIselFailSIToFP,"Fast isel fails on SIToFP"); STATISTIC(NumFastIselFailIntToPtr,"Fast isel fails on IntToPtr"); STATISTIC(NumFastIselFailPtrToInt,"Fast isel fails on PtrToInt"); STATISTIC(NumFastIselFailBitCast,"Fast isel fails on BitCast"); // Other instructions... STATISTIC(NumFastIselFailICmp,"Fast isel fails on ICmp"); STATISTIC(NumFastIselFailFCmp,"Fast isel fails on FCmp"); STATISTIC(NumFastIselFailPHI,"Fast isel fails on PHI"); STATISTIC(NumFastIselFailSelect,"Fast isel fails on Select"); STATISTIC(NumFastIselFailCall,"Fast isel fails on Call"); STATISTIC(NumFastIselFailShl,"Fast isel fails on Shl"); STATISTIC(NumFastIselFailLShr,"Fast isel fails on LShr"); STATISTIC(NumFastIselFailAShr,"Fast isel fails on AShr"); STATISTIC(NumFastIselFailVAArg,"Fast isel fails on VAArg"); STATISTIC(NumFastIselFailExtractElement,"Fast isel fails on ExtractElement"); STATISTIC(NumFastIselFailInsertElement,"Fast isel fails on InsertElement"); STATISTIC(NumFastIselFailShuffleVector,"Fast isel fails on ShuffleVector"); STATISTIC(NumFastIselFailExtractValue,"Fast isel fails on ExtractValue"); STATISTIC(NumFastIselFailInsertValue,"Fast isel fails on InsertValue"); STATISTIC(NumFastIselFailLandingPad,"Fast isel fails on LandingPad"); // Intrinsic instructions... STATISTIC(NumFastIselFailIntrinsicCall, "Fast isel fails on Intrinsic call"); STATISTIC(NumFastIselFailSAddWithOverflow, "Fast isel fails on sadd.with.overflow"); STATISTIC(NumFastIselFailUAddWithOverflow, "Fast isel fails on uadd.with.overflow"); STATISTIC(NumFastIselFailSSubWithOverflow, "Fast isel fails on ssub.with.overflow"); STATISTIC(NumFastIselFailUSubWithOverflow, "Fast isel fails on usub.with.overflow"); STATISTIC(NumFastIselFailSMulWithOverflow, "Fast isel fails on smul.with.overflow"); STATISTIC(NumFastIselFailUMulWithOverflow, "Fast isel fails on umul.with.overflow"); STATISTIC(NumFastIselFailFrameaddress, "Fast isel fails on Frameaddress"); STATISTIC(NumFastIselFailSqrt, "Fast isel fails on sqrt call"); STATISTIC(NumFastIselFailStackMap, "Fast isel fails on StackMap call"); STATISTIC(NumFastIselFailPatchPoint, "Fast isel fails on PatchPoint call"); #endif static cl::opt EnableFastISelVerbose("fast-isel-verbose", cl::Hidden, cl::desc("Enable verbose messages in the \"fast\" " "instruction selector")); static cl::opt EnableFastISelAbort( "fast-isel-abort", cl::Hidden, cl::desc("Enable abort calls when \"fast\" instruction selection " "fails to lower an instruction: 0 disable the abort, 1 will " "abort but for args, calls and terminators, 2 will also " "abort for argument lowering, and 3 will never fallback " "to SelectionDAG.")); static cl::opt UseMBPI("use-mbpi", cl::desc("use Machine Branch Probability Info"), cl::init(true), cl::Hidden); #ifndef NDEBUG static cl::opt FilterDAGBasicBlockName("filter-view-dags", cl::Hidden, cl::desc("Only display the basic block whose name " "matches this for all view-*-dags options")); static cl::opt ViewDAGCombine1("view-dag-combine1-dags", cl::Hidden, cl::desc("Pop up a window to show dags before the first " "dag combine pass")); static cl::opt ViewLegalizeTypesDAGs("view-legalize-types-dags", cl::Hidden, cl::desc("Pop up a window to show dags before legalize types")); static cl::opt ViewLegalizeDAGs("view-legalize-dags", cl::Hidden, cl::desc("Pop up a window to show dags before legalize")); static cl::opt ViewDAGCombine2("view-dag-combine2-dags", cl::Hidden, cl::desc("Pop up a window to show dags before the second " "dag combine pass")); static cl::opt ViewDAGCombineLT("view-dag-combine-lt-dags", cl::Hidden, cl::desc("Pop up a window to show dags before the post legalize types" " dag combine pass")); static cl::opt ViewISelDAGs("view-isel-dags", cl::Hidden, cl::desc("Pop up a window to show isel dags as they are selected")); static cl::opt ViewSchedDAGs("view-sched-dags", cl::Hidden, cl::desc("Pop up a window to show sched dags as they are processed")); static cl::opt ViewSUnitDAGs("view-sunit-dags", cl::Hidden, cl::desc("Pop up a window to show SUnit dags after they are processed")); #else static const bool ViewDAGCombine1 = false, ViewLegalizeTypesDAGs = false, ViewLegalizeDAGs = false, ViewDAGCombine2 = false, ViewDAGCombineLT = false, ViewISelDAGs = false, ViewSchedDAGs = false, ViewSUnitDAGs = false; #endif //===---------------------------------------------------------------------===// /// /// RegisterScheduler class - Track the registration of instruction schedulers. /// //===---------------------------------------------------------------------===// MachinePassRegistry RegisterScheduler::Registry; //===---------------------------------------------------------------------===// /// /// ISHeuristic command line option for instruction schedulers. /// //===---------------------------------------------------------------------===// static cl::opt > ISHeuristic("pre-RA-sched", cl::init(&createDefaultScheduler), cl::Hidden, cl::desc("Instruction schedulers available (before register" " allocation):")); static RegisterScheduler defaultListDAGScheduler("default", "Best scheduler for the target", createDefaultScheduler); namespace llvm { //===--------------------------------------------------------------------===// /// \brief This class is used by SelectionDAGISel to temporarily override /// the optimization level on a per-function basis. class OptLevelChanger { SelectionDAGISel &IS; CodeGenOpt::Level SavedOptLevel; bool SavedFastISel; public: OptLevelChanger(SelectionDAGISel &ISel, CodeGenOpt::Level NewOptLevel) : IS(ISel) { SavedOptLevel = IS.OptLevel; if (NewOptLevel == SavedOptLevel) return; IS.OptLevel = NewOptLevel; IS.TM.setOptLevel(NewOptLevel); DEBUG(dbgs() << "\nChanging optimization level for Function " << IS.MF->getFunction()->getName() << "\n"); DEBUG(dbgs() << "\tBefore: -O" << SavedOptLevel << " ; After: -O" << NewOptLevel << "\n"); SavedFastISel = IS.TM.Options.EnableFastISel; if (NewOptLevel == CodeGenOpt::None) { IS.TM.setFastISel(IS.TM.getO0WantsFastISel()); DEBUG(dbgs() << "\tFastISel is " << (IS.TM.Options.EnableFastISel ? "enabled" : "disabled") << "\n"); } } ~OptLevelChanger() { if (IS.OptLevel == SavedOptLevel) return; DEBUG(dbgs() << "\nRestoring optimization level for Function " << IS.MF->getFunction()->getName() << "\n"); DEBUG(dbgs() << "\tBefore: -O" << IS.OptLevel << " ; After: -O" << SavedOptLevel << "\n"); IS.OptLevel = SavedOptLevel; IS.TM.setOptLevel(SavedOptLevel); IS.TM.setFastISel(SavedFastISel); } }; //===--------------------------------------------------------------------===// /// createDefaultScheduler - This creates an instruction scheduler appropriate /// for the target. ScheduleDAGSDNodes* createDefaultScheduler(SelectionDAGISel *IS, CodeGenOpt::Level OptLevel) { const TargetLowering *TLI = IS->TLI; const TargetSubtargetInfo &ST = IS->MF->getSubtarget(); // Try first to see if the Target has its own way of selecting a scheduler if (auto *SchedulerCtor = ST.getDAGScheduler(OptLevel)) { return SchedulerCtor(IS, OptLevel); } if (OptLevel == CodeGenOpt::None || (ST.enableMachineScheduler() && ST.enableMachineSchedDefaultSched()) || TLI->getSchedulingPreference() == Sched::Source) return createSourceListDAGScheduler(IS, OptLevel); if (TLI->getSchedulingPreference() == Sched::RegPressure) return createBURRListDAGScheduler(IS, OptLevel); if (TLI->getSchedulingPreference() == Sched::Hybrid) return createHybridListDAGScheduler(IS, OptLevel); if (TLI->getSchedulingPreference() == Sched::VLIW) return createVLIWDAGScheduler(IS, OptLevel); assert(TLI->getSchedulingPreference() == Sched::ILP && "Unknown sched type!"); return createILPListDAGScheduler(IS, OptLevel); } } // end namespace llvm // EmitInstrWithCustomInserter - This method should be implemented by targets // that mark instructions with the 'usesCustomInserter' flag. These // instructions are special in various ways, which require special support to // insert. The specified MachineInstr is created but not inserted into any // basic blocks, and this method is called to expand it into a sequence of // instructions, potentially also creating new basic blocks and control flow. // When new basic blocks are inserted and the edges from MBB to its successors // are modified, the method should insert pairs of into the // DenseMap. MachineBasicBlock * TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *MBB) const { #ifndef NDEBUG dbgs() << "If a target marks an instruction with " "'usesCustomInserter', it must implement " "TargetLowering::EmitInstrWithCustomInserter!"; #endif llvm_unreachable(nullptr); } void TargetLowering::AdjustInstrPostInstrSelection(MachineInstr &MI, SDNode *Node) const { assert(!MI.hasPostISelHook() && "If a target marks an instruction with 'hasPostISelHook', " "it must implement TargetLowering::AdjustInstrPostInstrSelection!"); } //===----------------------------------------------------------------------===// // SelectionDAGISel code //===----------------------------------------------------------------------===// SelectionDAGISel::SelectionDAGISel(TargetMachine &tm, CodeGenOpt::Level OL) : MachineFunctionPass(ID), TM(tm), FuncInfo(new FunctionLoweringInfo()), CurDAG(new SelectionDAG(tm, OL)), SDB(new SelectionDAGBuilder(*CurDAG, *FuncInfo, OL)), GFI(), OptLevel(OL), DAGSize(0) { initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); initializeBranchProbabilityInfoWrapperPassPass( *PassRegistry::getPassRegistry()); initializeAAResultsWrapperPassPass(*PassRegistry::getPassRegistry()); initializeTargetLibraryInfoWrapperPassPass( *PassRegistry::getPassRegistry()); } SelectionDAGISel::~SelectionDAGISel() { delete SDB; delete CurDAG; delete FuncInfo; } void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addPreserved(); AU.addPreserved(); AU.addRequired(); if (UseMBPI && OptLevel != CodeGenOpt::None) AU.addRequired(); MachineFunctionPass::getAnalysisUsage(AU); } /// SplitCriticalSideEffectEdges - Look for critical edges with a PHI value that /// may trap on it. In this case we have to split the edge so that the path /// through the predecessor block that doesn't go to the phi block doesn't /// execute the possibly trapping instruction. /// /// This is required for correctness, so it must be done at -O0. /// static void SplitCriticalSideEffectEdges(Function &Fn) { // Loop for blocks with phi nodes. for (BasicBlock &BB : Fn) { PHINode *PN = dyn_cast(BB.begin()); if (!PN) continue; ReprocessBlock: // For each block with a PHI node, check to see if any of the input values // are potentially trapping constant expressions. Constant expressions are // the only potentially trapping value that can occur as the argument to a // PHI. for (BasicBlock::iterator I = BB.begin(); (PN = dyn_cast(I)); ++I) for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { ConstantExpr *CE = dyn_cast(PN->getIncomingValue(i)); if (!CE || !CE->canTrap()) continue; // The only case we have to worry about is when the edge is critical. // Since this block has a PHI Node, we assume it has multiple input // edges: check to see if the pred has multiple successors. BasicBlock *Pred = PN->getIncomingBlock(i); if (Pred->getTerminator()->getNumSuccessors() == 1) continue; // Okay, we have to split this edge. SplitCriticalEdge( Pred->getTerminator(), GetSuccessorNumber(Pred, &BB), CriticalEdgeSplittingOptions().setMergeIdenticalEdges()); goto ReprocessBlock; } } } bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { // If we already selected that function, we do not need to run SDISel. if (mf.getProperties().hasProperty( MachineFunctionProperties::Property::Selected)) return false; // Do some sanity-checking on the command-line options. assert((!EnableFastISelVerbose || TM.Options.EnableFastISel) && "-fast-isel-verbose requires -fast-isel"); assert((!EnableFastISelAbort || TM.Options.EnableFastISel) && "-fast-isel-abort > 0 requires -fast-isel"); const Function &Fn = *mf.getFunction(); MF = &mf; // Reset the target options before resetting the optimization // level below. // FIXME: This is a horrible hack and should be processed via // codegen looking at the optimization level explicitly when // it wants to look at it. TM.resetTargetOptions(Fn); // Reset OptLevel to None for optnone functions. CodeGenOpt::Level NewOptLevel = OptLevel; if (OptLevel != CodeGenOpt::None && skipFunction(Fn)) NewOptLevel = CodeGenOpt::None; OptLevelChanger OLC(*this, NewOptLevel); TII = MF->getSubtarget().getInstrInfo(); TLI = MF->getSubtarget().getTargetLowering(); RegInfo = &MF->getRegInfo(); AA = &getAnalysis().getAAResults(); LibInfo = &getAnalysis().getTLI(); GFI = Fn.hasGC() ? &getAnalysis().getFunctionInfo(Fn) : nullptr; DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n"); SplitCriticalSideEffectEdges(const_cast(Fn)); CurDAG->init(*MF); FuncInfo->set(Fn, *MF, CurDAG); if (UseMBPI && OptLevel != CodeGenOpt::None) FuncInfo->BPI = &getAnalysis().getBPI(); else FuncInfo->BPI = nullptr; SDB->init(GFI, *AA, LibInfo); MF->setHasInlineAsm(false); FuncInfo->SplitCSR = false; // We split CSR if the target supports it for the given function // and the function has only return exits. if (OptLevel != CodeGenOpt::None && TLI->supportSplitCSR(MF)) { FuncInfo->SplitCSR = true; // Collect all the return blocks. for (const BasicBlock &BB : Fn) { if (!succ_empty(&BB)) continue; const TerminatorInst *Term = BB.getTerminator(); if (isa(Term) || isa(Term)) continue; // Bail out if the exit block is not Return nor Unreachable. FuncInfo->SplitCSR = false; break; } } MachineBasicBlock *EntryMBB = &MF->front(); if (FuncInfo->SplitCSR) // This performs initialization so lowering for SplitCSR will be correct. TLI->initializeSplitCSR(EntryMBB); SelectAllBasicBlocks(Fn); // If the first basic block in the function has live ins that need to be // copied into vregs, emit the copies into the top of the block before // emitting the code for the block. const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo(); RegInfo->EmitLiveInCopies(EntryMBB, TRI, *TII); // Insert copies in the entry block and the return blocks. if (FuncInfo->SplitCSR) { SmallVector Returns; // Collect all the return blocks. for (MachineBasicBlock &MBB : mf) { if (!MBB.succ_empty()) continue; MachineBasicBlock::iterator Term = MBB.getFirstTerminator(); if (Term != MBB.end() && Term->isReturn()) { Returns.push_back(&MBB); continue; } } TLI->insertCopiesSplitCSR(EntryMBB, Returns); } DenseMap LiveInMap; if (!FuncInfo->ArgDbgValues.empty()) for (MachineRegisterInfo::livein_iterator LI = RegInfo->livein_begin(), E = RegInfo->livein_end(); LI != E; ++LI) if (LI->second) LiveInMap.insert(std::make_pair(LI->first, LI->second)); // Insert DBG_VALUE instructions for function arguments to the entry block. for (unsigned i = 0, e = FuncInfo->ArgDbgValues.size(); i != e; ++i) { MachineInstr *MI = FuncInfo->ArgDbgValues[e-i-1]; bool hasFI = MI->getOperand(0).isFI(); unsigned Reg = hasFI ? TRI.getFrameRegister(*MF) : MI->getOperand(0).getReg(); if (TargetRegisterInfo::isPhysicalRegister(Reg)) EntryMBB->insert(EntryMBB->begin(), MI); else { MachineInstr *Def = RegInfo->getVRegDef(Reg); if (Def) { MachineBasicBlock::iterator InsertPos = Def; // FIXME: VR def may not be in entry block. Def->getParent()->insert(std::next(InsertPos), MI); } else DEBUG(dbgs() << "Dropping debug info for dead vreg" << TargetRegisterInfo::virtReg2Index(Reg) << "\n"); } // If Reg is live-in then update debug info to track its copy in a vreg. DenseMap::iterator LDI = LiveInMap.find(Reg); if (LDI != LiveInMap.end()) { assert(!hasFI && "There's no handling of frame pointer updating here yet " "- add if needed"); MachineInstr *Def = RegInfo->getVRegDef(LDI->second); MachineBasicBlock::iterator InsertPos = Def; const MDNode *Variable = MI->getDebugVariable(); const MDNode *Expr = MI->getDebugExpression(); DebugLoc DL = MI->getDebugLoc(); bool IsIndirect = MI->isIndirectDebugValue(); unsigned Offset = IsIndirect ? MI->getOperand(1).getImm() : 0; assert(cast(Variable)->isValidLocationForIntrinsic(DL) && "Expected inlined-at fields to agree"); // Def is never a terminator here, so it is ok to increment InsertPos. BuildMI(*EntryMBB, ++InsertPos, DL, TII->get(TargetOpcode::DBG_VALUE), IsIndirect, LDI->second, Offset, Variable, Expr); // If this vreg is directly copied into an exported register then // that COPY instructions also need DBG_VALUE, if it is the only // user of LDI->second. MachineInstr *CopyUseMI = nullptr; for (MachineRegisterInfo::use_instr_iterator UI = RegInfo->use_instr_begin(LDI->second), E = RegInfo->use_instr_end(); UI != E; ) { MachineInstr *UseMI = &*(UI++); if (UseMI->isDebugValue()) continue; if (UseMI->isCopy() && !CopyUseMI && UseMI->getParent() == EntryMBB) { CopyUseMI = UseMI; continue; } // Otherwise this is another use or second copy use. CopyUseMI = nullptr; break; } if (CopyUseMI) { // Use MI's debug location, which describes where Variable was // declared, rather than whatever is attached to CopyUseMI. MachineInstr *NewMI = BuildMI(*MF, DL, TII->get(TargetOpcode::DBG_VALUE), IsIndirect, CopyUseMI->getOperand(0).getReg(), Offset, Variable, Expr); MachineBasicBlock::iterator Pos = CopyUseMI; EntryMBB->insertAfter(Pos, NewMI); } } } // Determine if there are any calls in this machine function. MachineFrameInfo &MFI = MF->getFrameInfo(); for (const auto &MBB : *MF) { if (MFI.hasCalls() && MF->hasInlineAsm()) break; for (const auto &MI : MBB) { const MCInstrDesc &MCID = TII->get(MI.getOpcode()); if ((MCID.isCall() && !MCID.isReturn()) || MI.isStackAligningInlineAsm()) { MFI.setHasCalls(true); } if (MI.isInlineAsm()) { MF->setHasInlineAsm(true); } } } // Determine if there is a call to setjmp in the machine function. MF->setExposesReturnsTwice(Fn.callsFunctionThatReturnsTwice()); // Replace forward-declared registers with the registers containing // the desired value. MachineRegisterInfo &MRI = MF->getRegInfo(); for (DenseMap::iterator I = FuncInfo->RegFixups.begin(), E = FuncInfo->RegFixups.end(); I != E; ++I) { unsigned From = I->first; unsigned To = I->second; // If To is also scheduled to be replaced, find what its ultimate // replacement is. for (;;) { DenseMap::iterator J = FuncInfo->RegFixups.find(To); if (J == E) break; To = J->second; } // Make sure the new register has a sufficiently constrained register class. if (TargetRegisterInfo::isVirtualRegister(From) && TargetRegisterInfo::isVirtualRegister(To)) MRI.constrainRegClass(To, MRI.getRegClass(From)); // Replace it. // Replacing one register with another won't touch the kill flags. // We need to conservatively clear the kill flags as a kill on the old // register might dominate existing uses of the new register. if (!MRI.use_empty(To)) MRI.clearKillFlags(From); MRI.replaceRegWith(From, To); } if (TLI->hasCopyImplyingStackAdjustment(MF)) MFI.setHasCopyImplyingStackAdjustment(true); // Freeze the set of reserved registers now that MachineFrameInfo has been // set up. All the information required by getReservedRegs() should be // available now. MRI.freezeReservedRegs(*MF); // Release function-specific state. SDB and CurDAG are already cleared // at this point. FuncInfo->clear(); DEBUG(dbgs() << "*** MachineFunction at end of ISel ***\n"); DEBUG(MF->print(dbgs())); return true; } void SelectionDAGISel::SelectBasicBlock(BasicBlock::const_iterator Begin, BasicBlock::const_iterator End, bool &HadTailCall) { // Lower the instructions. If a call is emitted as a tail call, cease emitting // nodes for this block. for (BasicBlock::const_iterator I = Begin; I != End && !SDB->HasTailCall; ++I) SDB->visit(*I); // Make sure the root of the DAG is up-to-date. CurDAG->setRoot(SDB->getControlRoot()); HadTailCall = SDB->HasTailCall; SDB->clear(); // Final step, emit the lowered DAG as machine code. CodeGenAndEmitDAG(); } void SelectionDAGISel::ComputeLiveOutVRegInfo() { SmallPtrSet VisitedNodes; SmallVector Worklist; Worklist.push_back(CurDAG->getRoot().getNode()); APInt KnownZero; APInt KnownOne; do { SDNode *N = Worklist.pop_back_val(); // If we've already seen this node, ignore it. if (!VisitedNodes.insert(N).second) continue; // Otherwise, add all chain operands to the worklist. for (const SDValue &Op : N->op_values()) if (Op.getValueType() == MVT::Other) Worklist.push_back(Op.getNode()); // If this is a CopyToReg with a vreg dest, process it. if (N->getOpcode() != ISD::CopyToReg) continue; unsigned DestReg = cast(N->getOperand(1))->getReg(); if (!TargetRegisterInfo::isVirtualRegister(DestReg)) continue; // Ignore non-scalar or non-integer values. SDValue Src = N->getOperand(2); EVT SrcVT = Src.getValueType(); if (!SrcVT.isInteger() || SrcVT.isVector()) continue; unsigned NumSignBits = CurDAG->ComputeNumSignBits(Src); CurDAG->computeKnownBits(Src, KnownZero, KnownOne); FuncInfo->AddLiveOutRegInfo(DestReg, NumSignBits, KnownZero, KnownOne); } while (!Worklist.empty()); } void SelectionDAGISel::CodeGenAndEmitDAG() { StringRef GroupName = "sdag"; StringRef GroupDescription = "Instruction Selection and Scheduling"; std::string BlockName; int BlockNumber = -1; (void)BlockNumber; bool MatchFilterBB = false; (void)MatchFilterBB; #ifndef NDEBUG MatchFilterBB = (FilterDAGBasicBlockName.empty() || FilterDAGBasicBlockName == FuncInfo->MBB->getBasicBlock()->getName().str()); #endif #ifdef NDEBUG if (ViewDAGCombine1 || ViewLegalizeTypesDAGs || ViewLegalizeDAGs || ViewDAGCombine2 || ViewDAGCombineLT || ViewISelDAGs || ViewSchedDAGs || ViewSUnitDAGs) #endif { BlockNumber = FuncInfo->MBB->getNumber(); BlockName = (MF->getName() + ":" + FuncInfo->MBB->getBasicBlock()->getName()).str(); } DEBUG(dbgs() << "Initial selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); if (ViewDAGCombine1 && MatchFilterBB) CurDAG->viewGraph("dag-combine1 input for " + BlockName); // Run the DAG combiner in pre-legalize mode. { NamedRegionTimer T("combine1", "DAG Combining 1", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Combine(BeforeLegalizeTypes, *AA, OptLevel); } DEBUG(dbgs() << "Optimized lowered selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); // Second step, hack on the DAG until it only uses operations and types that // the target supports. if (ViewLegalizeTypesDAGs && MatchFilterBB) CurDAG->viewGraph("legalize-types input for " + BlockName); bool Changed; { NamedRegionTimer T("legalize_types", "Type Legalization", GroupName, GroupDescription, TimePassesIsEnabled); Changed = CurDAG->LegalizeTypes(); } DEBUG(dbgs() << "Type-legalized selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); CurDAG->NewNodesMustHaveLegalTypes = true; if (Changed) { if (ViewDAGCombineLT && MatchFilterBB) CurDAG->viewGraph("dag-combine-lt input for " + BlockName); // Run the DAG combiner in post-type-legalize mode. { NamedRegionTimer T("combine_lt", "DAG Combining after legalize types", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Combine(AfterLegalizeTypes, *AA, OptLevel); } DEBUG(dbgs() << "Optimized type-legalized selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); } { NamedRegionTimer T("legalize_vec", "Vector Legalization", GroupName, GroupDescription, TimePassesIsEnabled); Changed = CurDAG->LegalizeVectors(); } if (Changed) { { NamedRegionTimer T("legalize_types2", "Type Legalization 2", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->LegalizeTypes(); } if (ViewDAGCombineLT && MatchFilterBB) CurDAG->viewGraph("dag-combine-lv input for " + BlockName); // Run the DAG combiner in post-type-legalize mode. { NamedRegionTimer T("combine_lv", "DAG Combining after legalize vectors", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Combine(AfterLegalizeVectorOps, *AA, OptLevel); } DEBUG(dbgs() << "Optimized vector-legalized selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); } if (ViewLegalizeDAGs && MatchFilterBB) CurDAG->viewGraph("legalize input for " + BlockName); { NamedRegionTimer T("legalize", "DAG Legalization", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Legalize(); } DEBUG(dbgs() << "Legalized selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); if (ViewDAGCombine2 && MatchFilterBB) CurDAG->viewGraph("dag-combine2 input for " + BlockName); // Run the DAG combiner in post-legalize mode. { NamedRegionTimer T("combine2", "DAG Combining 2", GroupName, GroupDescription, TimePassesIsEnabled); CurDAG->Combine(AfterLegalizeDAG, *AA, OptLevel); } DEBUG(dbgs() << "Optimized legalized selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); if (OptLevel != CodeGenOpt::None) ComputeLiveOutVRegInfo(); if (ViewISelDAGs && MatchFilterBB) CurDAG->viewGraph("isel input for " + BlockName); // Third, instruction select all of the operations to machine code, adding the // code to the MachineBasicBlock. { NamedRegionTimer T("isel", "Instruction Selection", GroupName, GroupDescription, TimePassesIsEnabled); DoInstructionSelection(); } DEBUG(dbgs() << "Selected selection DAG: BB#" << BlockNumber << " '" << BlockName << "'\n"; CurDAG->dump()); if (ViewSchedDAGs && MatchFilterBB) CurDAG->viewGraph("scheduler input for " + BlockName); // Schedule machine code. ScheduleDAGSDNodes *Scheduler = CreateScheduler(); { NamedRegionTimer T("sched", "Instruction Scheduling", GroupName, GroupDescription, TimePassesIsEnabled); Scheduler->Run(CurDAG, FuncInfo->MBB); } if (ViewSUnitDAGs && MatchFilterBB) Scheduler->viewGraph(); // Emit machine code to BB. This can change 'BB' to the last block being // inserted into. MachineBasicBlock *FirstMBB = FuncInfo->MBB, *LastMBB; { NamedRegionTimer T("emit", "Instruction Creation", GroupName, GroupDescription, TimePassesIsEnabled); // FuncInfo->InsertPt is passed by reference and set to the end of the // scheduled instructions. LastMBB = FuncInfo->MBB = Scheduler->EmitSchedule(FuncInfo->InsertPt); } // If the block was split, make sure we update any references that are used to // update PHI nodes later on. if (FirstMBB != LastMBB) SDB->UpdateSplitBlock(FirstMBB, LastMBB); // Free the scheduler state. { NamedRegionTimer T("cleanup", "Instruction Scheduling Cleanup", GroupName, GroupDescription, TimePassesIsEnabled); delete Scheduler; } // Free the SelectionDAG state, now that we're finished with it. CurDAG->clear(); } namespace { /// ISelUpdater - helper class to handle updates of the instruction selection /// graph. class ISelUpdater : public SelectionDAG::DAGUpdateListener { SelectionDAG::allnodes_iterator &ISelPosition; public: ISelUpdater(SelectionDAG &DAG, SelectionDAG::allnodes_iterator &isp) : SelectionDAG::DAGUpdateListener(DAG), ISelPosition(isp) {} /// NodeDeleted - Handle nodes deleted from the graph. If the node being /// deleted is the current ISelPosition node, update ISelPosition. /// void NodeDeleted(SDNode *N, SDNode *E) override { if (ISelPosition == SelectionDAG::allnodes_iterator(N)) ++ISelPosition; } }; } // end anonymous namespace void SelectionDAGISel::DoInstructionSelection() { DEBUG(dbgs() << "===== Instruction selection begins: BB#" << FuncInfo->MBB->getNumber() << " '" << FuncInfo->MBB->getName() << "'\n"); PreprocessISelDAG(); // Select target instructions for the DAG. { // Number all nodes with a topological order and set DAGSize. DAGSize = CurDAG->AssignTopologicalOrder(); // Create a dummy node (which is not added to allnodes), that adds // a reference to the root node, preventing it from being deleted, // and tracking any changes of the root. HandleSDNode Dummy(CurDAG->getRoot()); SelectionDAG::allnodes_iterator ISelPosition (CurDAG->getRoot().getNode()); ++ISelPosition; // Make sure that ISelPosition gets properly updated when nodes are deleted // in calls made from this function. ISelUpdater ISU(*CurDAG, ISelPosition); // The AllNodes list is now topological-sorted. Visit the // nodes by starting at the end of the list (the root of the // graph) and preceding back toward the beginning (the entry // node). while (ISelPosition != CurDAG->allnodes_begin()) { SDNode *Node = &*--ISelPosition; // Skip dead nodes. DAGCombiner is expected to eliminate all dead nodes, // but there are currently some corner cases that it misses. Also, this // makes it theoretically possible to disable the DAGCombiner. if (Node->use_empty()) continue; Select(Node); } CurDAG->setRoot(Dummy.getValue()); } DEBUG(dbgs() << "===== Instruction selection ends:\n"); PostprocessISelDAG(); } static bool hasExceptionPointerOrCodeUser(const CatchPadInst *CPI) { for (const User *U : CPI->users()) { if (const IntrinsicInst *EHPtrCall = dyn_cast(U)) { Intrinsic::ID IID = EHPtrCall->getIntrinsicID(); if (IID == Intrinsic::eh_exceptionpointer || IID == Intrinsic::eh_exceptioncode) return true; } } return false; } /// PrepareEHLandingPad - Emit an EH_LABEL, set up live-in registers, and /// do other setup for EH landing-pad blocks. bool SelectionDAGISel::PrepareEHLandingPad() { MachineBasicBlock *MBB = FuncInfo->MBB; const Constant *PersonalityFn = FuncInfo->Fn->getPersonalityFn(); const BasicBlock *LLVMBB = MBB->getBasicBlock(); const TargetRegisterClass *PtrRC = TLI->getRegClassFor(TLI->getPointerTy(CurDAG->getDataLayout())); // Catchpads have one live-in register, which typically holds the exception // pointer or code. if (const auto *CPI = dyn_cast(LLVMBB->getFirstNonPHI())) { if (hasExceptionPointerOrCodeUser(CPI)) { // Get or create the virtual register to hold the pointer or code. Mark // the live in physreg and copy into the vreg. MCPhysReg EHPhysReg = TLI->getExceptionPointerRegister(PersonalityFn); assert(EHPhysReg && "target lacks exception pointer register"); MBB->addLiveIn(EHPhysReg); unsigned VReg = FuncInfo->getCatchPadExceptionPointerVReg(CPI, PtrRC); BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), TII->get(TargetOpcode::COPY), VReg) .addReg(EHPhysReg, RegState::Kill); } return true; } if (!LLVMBB->isLandingPad()) 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. MCSymbol *Label = MF->addLandingPad(MBB); // Assign the call site to the landing pad's begin label. MF->setCallSiteLandingPad(Label, SDB->LPadToCallSiteMap[MBB]); const MCInstrDesc &II = TII->get(TargetOpcode::EH_LABEL); BuildMI(*MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(), II) .addSym(Label); // Mark exception register as live in. if (unsigned Reg = TLI->getExceptionPointerRegister(PersonalityFn)) FuncInfo->ExceptionPointerVirtReg = MBB->addLiveIn(Reg, PtrRC); // Mark exception selector register as live in. if (unsigned Reg = TLI->getExceptionSelectorRegister(PersonalityFn)) FuncInfo->ExceptionSelectorVirtReg = MBB->addLiveIn(Reg, PtrRC); return true; } /// isFoldedOrDeadInstruction - Return true if the specified instruction is /// side-effect free and is either dead or folded into a generated instruction. /// Return false if it needs to be emitted. static bool isFoldedOrDeadInstruction(const Instruction *I, FunctionLoweringInfo *FuncInfo) { return !I->mayWriteToMemory() && // Side-effecting instructions aren't folded. !isa(I) && // Terminators aren't folded. !isa(I) && // Debug instructions aren't folded. !I->isEHPad() && // EH pad instructions aren't folded. !FuncInfo->isExportedInst(I); // Exported instrs must be computed. } #ifndef NDEBUG // Collect per Instruction statistics for fast-isel misses. Only those // instructions that cause the bail are accounted for. It does not account for // instructions higher in the block. Thus, summing the per instructions stats // will not add up to what is reported by NumFastIselFailures. static void collectFailStats(const Instruction *I) { switch (I->getOpcode()) { default: assert (0 && " "); // Terminators case Instruction::Ret: NumFastIselFailRet++; return; case Instruction::Br: NumFastIselFailBr++; return; case Instruction::Switch: NumFastIselFailSwitch++; return; case Instruction::IndirectBr: NumFastIselFailIndirectBr++; return; case Instruction::Invoke: NumFastIselFailInvoke++; return; case Instruction::Resume: NumFastIselFailResume++; return; case Instruction::Unreachable: NumFastIselFailUnreachable++; return; // Standard binary operators... case Instruction::Add: NumFastIselFailAdd++; return; case Instruction::FAdd: NumFastIselFailFAdd++; return; case Instruction::Sub: NumFastIselFailSub++; return; case Instruction::FSub: NumFastIselFailFSub++; return; case Instruction::Mul: NumFastIselFailMul++; return; case Instruction::FMul: NumFastIselFailFMul++; return; case Instruction::UDiv: NumFastIselFailUDiv++; return; case Instruction::SDiv: NumFastIselFailSDiv++; return; case Instruction::FDiv: NumFastIselFailFDiv++; return; case Instruction::URem: NumFastIselFailURem++; return; case Instruction::SRem: NumFastIselFailSRem++; return; case Instruction::FRem: NumFastIselFailFRem++; return; // Logical operators... case Instruction::And: NumFastIselFailAnd++; return; case Instruction::Or: NumFastIselFailOr++; return; case Instruction::Xor: NumFastIselFailXor++; return; // Memory instructions... case Instruction::Alloca: NumFastIselFailAlloca++; return; case Instruction::Load: NumFastIselFailLoad++; return; case Instruction::Store: NumFastIselFailStore++; return; case Instruction::AtomicCmpXchg: NumFastIselFailAtomicCmpXchg++; return; case Instruction::AtomicRMW: NumFastIselFailAtomicRMW++; return; case Instruction::Fence: NumFastIselFailFence++; return; case Instruction::GetElementPtr: NumFastIselFailGetElementPtr++; return; // Convert instructions... case Instruction::Trunc: NumFastIselFailTrunc++; return; case Instruction::ZExt: NumFastIselFailZExt++; return; case Instruction::SExt: NumFastIselFailSExt++; return; case Instruction::FPTrunc: NumFastIselFailFPTrunc++; return; case Instruction::FPExt: NumFastIselFailFPExt++; return; case Instruction::FPToUI: NumFastIselFailFPToUI++; return; case Instruction::FPToSI: NumFastIselFailFPToSI++; return; case Instruction::UIToFP: NumFastIselFailUIToFP++; return; case Instruction::SIToFP: NumFastIselFailSIToFP++; return; case Instruction::IntToPtr: NumFastIselFailIntToPtr++; return; case Instruction::PtrToInt: NumFastIselFailPtrToInt++; return; case Instruction::BitCast: NumFastIselFailBitCast++; return; // Other instructions... case Instruction::ICmp: NumFastIselFailICmp++; return; case Instruction::FCmp: NumFastIselFailFCmp++; return; case Instruction::PHI: NumFastIselFailPHI++; return; case Instruction::Select: NumFastIselFailSelect++; return; case Instruction::Call: { if (auto const *Intrinsic = dyn_cast(I)) { switch (Intrinsic->getIntrinsicID()) { default: NumFastIselFailIntrinsicCall++; return; case Intrinsic::sadd_with_overflow: NumFastIselFailSAddWithOverflow++; return; case Intrinsic::uadd_with_overflow: NumFastIselFailUAddWithOverflow++; return; case Intrinsic::ssub_with_overflow: NumFastIselFailSSubWithOverflow++; return; case Intrinsic::usub_with_overflow: NumFastIselFailUSubWithOverflow++; return; case Intrinsic::smul_with_overflow: NumFastIselFailSMulWithOverflow++; return; case Intrinsic::umul_with_overflow: NumFastIselFailUMulWithOverflow++; return; case Intrinsic::frameaddress: NumFastIselFailFrameaddress++; return; case Intrinsic::sqrt: NumFastIselFailSqrt++; return; case Intrinsic::experimental_stackmap: NumFastIselFailStackMap++; return; case Intrinsic::experimental_patchpoint_void: // fall-through case Intrinsic::experimental_patchpoint_i64: NumFastIselFailPatchPoint++; return; } } NumFastIselFailCall++; return; } case Instruction::Shl: NumFastIselFailShl++; return; case Instruction::LShr: NumFastIselFailLShr++; return; case Instruction::AShr: NumFastIselFailAShr++; return; case Instruction::VAArg: NumFastIselFailVAArg++; return; case Instruction::ExtractElement: NumFastIselFailExtractElement++; return; case Instruction::InsertElement: NumFastIselFailInsertElement++; return; case Instruction::ShuffleVector: NumFastIselFailShuffleVector++; return; case Instruction::ExtractValue: NumFastIselFailExtractValue++; return; case Instruction::InsertValue: NumFastIselFailInsertValue++; return; case Instruction::LandingPad: NumFastIselFailLandingPad++; return; } } #endif // NDEBUG /// Set up SwiftErrorVals by going through the function. If the function has /// swifterror argument, it will be the first entry. static void setupSwiftErrorVals(const Function &Fn, const TargetLowering *TLI, FunctionLoweringInfo *FuncInfo) { if (!TLI->supportSwiftError()) return; FuncInfo->SwiftErrorVals.clear(); FuncInfo->SwiftErrorVRegDefMap.clear(); FuncInfo->SwiftErrorVRegUpwardsUse.clear(); FuncInfo->SwiftErrorArg = nullptr; // Check if function has a swifterror argument. bool HaveSeenSwiftErrorArg = false; for (Function::const_arg_iterator AI = Fn.arg_begin(), AE = Fn.arg_end(); AI != AE; ++AI) if (AI->hasSwiftErrorAttr()) { assert(!HaveSeenSwiftErrorArg && "Must have only one swifterror parameter"); (void)HaveSeenSwiftErrorArg; // silence warning. HaveSeenSwiftErrorArg = true; FuncInfo->SwiftErrorArg = &*AI; FuncInfo->SwiftErrorVals.push_back(&*AI); } for (const auto &LLVMBB : Fn) for (const auto &Inst : LLVMBB) { if (const AllocaInst *Alloca = dyn_cast(&Inst)) if (Alloca->isSwiftError()) FuncInfo->SwiftErrorVals.push_back(Alloca); } } static void createSwiftErrorEntriesInEntryBlock(FunctionLoweringInfo *FuncInfo, const TargetLowering *TLI, const TargetInstrInfo *TII, const BasicBlock *LLVMBB, SelectionDAGBuilder *SDB) { if (!TLI->supportSwiftError()) return; // We only need to do this when we have swifterror parameter or swifterror // alloc. if (FuncInfo->SwiftErrorVals.empty()) return; if (pred_begin(LLVMBB) == pred_end(LLVMBB)) { auto &DL = FuncInfo->MF->getDataLayout(); auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL)); for (const auto *SwiftErrorVal : FuncInfo->SwiftErrorVals) { // We will always generate a copy from the argument. It is always used at // least by the 'return' of the swifterror. if (FuncInfo->SwiftErrorArg && FuncInfo->SwiftErrorArg == SwiftErrorVal) continue; unsigned VReg = FuncInfo->MF->getRegInfo().createVirtualRegister(RC); // Assign Undef to Vreg. We construct MI directly to make sure it works // with FastISel. BuildMI(*FuncInfo->MBB, FuncInfo->MBB->getFirstNonPHI(), SDB->getCurDebugLoc(), TII->get(TargetOpcode::IMPLICIT_DEF), VReg); FuncInfo->setCurrentSwiftErrorVReg(FuncInfo->MBB, SwiftErrorVal, VReg); } } } /// Propagate swifterror values through the machine function CFG. static void propagateSwiftErrorVRegs(FunctionLoweringInfo *FuncInfo) { auto *TLI = FuncInfo->TLI; if (!TLI->supportSwiftError()) return; // We only need to do this when we have swifterror parameter or swifterror // alloc. if (FuncInfo->SwiftErrorVals.empty()) return; // For each machine basic block in reverse post order. ReversePostOrderTraversal RPOT(FuncInfo->MF); for (ReversePostOrderTraversal::rpo_iterator It = RPOT.begin(), E = RPOT.end(); It != E; ++It) { MachineBasicBlock *MBB = *It; // For each swifterror value in the function. for(const auto *SwiftErrorVal : FuncInfo->SwiftErrorVals) { auto Key = std::make_pair(MBB, SwiftErrorVal); auto UUseIt = FuncInfo->SwiftErrorVRegUpwardsUse.find(Key); auto VRegDefIt = FuncInfo->SwiftErrorVRegDefMap.find(Key); bool UpwardsUse = UUseIt != FuncInfo->SwiftErrorVRegUpwardsUse.end(); unsigned UUseVReg = UpwardsUse ? UUseIt->second : 0; bool DownwardDef = VRegDefIt != FuncInfo->SwiftErrorVRegDefMap.end(); assert(!(UpwardsUse && !DownwardDef) && "We can't have an upwards use but no downwards def"); // If there is no upwards exposed use and an entry for the swifterror in // the def map for this value we don't need to do anything: We already // have a downward def for this basic block. if (!UpwardsUse && DownwardDef) continue; // Otherwise we either have an upwards exposed use vreg that we need to // materialize or need to forward the downward def from predecessors. // Check whether we have a single vreg def from all predecessors. // Otherwise we need a phi. SmallVector, 4> VRegs; SmallSet Visited; for (auto *Pred : MBB->predecessors()) { if (!Visited.insert(Pred).second) continue; VRegs.push_back(std::make_pair( Pred, FuncInfo->getOrCreateSwiftErrorVReg(Pred, SwiftErrorVal))); if (Pred != MBB) continue; // We have a self-edge. // If there was no upwards use in this basic block there is now one: the // phi needs to use it self. if (!UpwardsUse) { UpwardsUse = true; UUseIt = FuncInfo->SwiftErrorVRegUpwardsUse.find(Key); assert(UUseIt != FuncInfo->SwiftErrorVRegUpwardsUse.end()); UUseVReg = UUseIt->second; } } // We need a phi node if we have more than one predecessor with different // downward defs. bool needPHI = VRegs.size() >= 1 && std::find_if( VRegs.begin(), VRegs.end(), [&](const std::pair &V) -> bool { return V.second != VRegs[0].second; }) != VRegs.end(); // If there is no upwards exposed used and we don't need a phi just // forward the swifterror vreg from the predecessor(s). if (!UpwardsUse && !needPHI) { assert(!VRegs.empty() && "No predecessors? The entry block should bail out earlier"); // Just forward the swifterror vreg from the predecessor(s). FuncInfo->setCurrentSwiftErrorVReg(MBB, SwiftErrorVal, VRegs[0].second); continue; } auto DLoc = isa(SwiftErrorVal) ? dyn_cast(SwiftErrorVal)->getDebugLoc() : DebugLoc(); const auto *TII = FuncInfo->MF->getSubtarget().getInstrInfo(); // If we don't need a phi create a copy to the upward exposed vreg. if (!needPHI) { assert(UpwardsUse); unsigned DestReg = UUseVReg; BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::COPY), DestReg) .addReg(VRegs[0].second); continue; } // We need a phi: if there is an upwards exposed use we already have a // destination virtual register number otherwise we generate a new one. auto &DL = FuncInfo->MF->getDataLayout(); auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL)); unsigned PHIVReg = UpwardsUse ? UUseVReg : FuncInfo->MF->getRegInfo().createVirtualRegister(RC); MachineInstrBuilder SwiftErrorPHI = BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::PHI), PHIVReg); for (auto BBRegPair : VRegs) { SwiftErrorPHI.addReg(BBRegPair.second).addMBB(BBRegPair.first); } // We did not have a definition in this block before: store the phi's vreg // as this block downward exposed def. if (!UpwardsUse) FuncInfo->setCurrentSwiftErrorVReg(MBB, SwiftErrorVal, PHIVReg); } } } void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { // Initialize the Fast-ISel state, if needed. FastISel *FastIS = nullptr; if (TM.Options.EnableFastISel) FastIS = TLI->createFastISel(*FuncInfo, LibInfo); setupSwiftErrorVals(Fn, TLI, FuncInfo); // Iterate over all basic blocks in the function. ReversePostOrderTraversal RPOT(&Fn); for (ReversePostOrderTraversal::rpo_iterator I = RPOT.begin(), E = RPOT.end(); I != E; ++I) { const BasicBlock *LLVMBB = *I; if (OptLevel != CodeGenOpt::None) { bool AllPredsVisited = true; for (const_pred_iterator PI = pred_begin(LLVMBB), PE = pred_end(LLVMBB); PI != PE; ++PI) { if (!FuncInfo->VisitedBBs.count(*PI)) { AllPredsVisited = false; break; } } if (AllPredsVisited) { for (BasicBlock::const_iterator I = LLVMBB->begin(); const PHINode *PN = dyn_cast(I); ++I) FuncInfo->ComputePHILiveOutRegInfo(PN); } else { for (BasicBlock::const_iterator I = LLVMBB->begin(); const PHINode *PN = dyn_cast(I); ++I) FuncInfo->InvalidatePHILiveOutRegInfo(PN); } FuncInfo->VisitedBBs.insert(LLVMBB); } BasicBlock::const_iterator const Begin = LLVMBB->getFirstNonPHI()->getIterator(); BasicBlock::const_iterator const End = LLVMBB->end(); BasicBlock::const_iterator BI = End; FuncInfo->MBB = FuncInfo->MBBMap[LLVMBB]; if (!FuncInfo->MBB) continue; // Some blocks like catchpads have no code or MBB. FuncInfo->InsertPt = FuncInfo->MBB->getFirstNonPHI(); createSwiftErrorEntriesInEntryBlock(FuncInfo, TLI, TII, LLVMBB, SDB); // Setup an EH landing-pad block. FuncInfo->ExceptionPointerVirtReg = 0; FuncInfo->ExceptionSelectorVirtReg = 0; if (LLVMBB->isEHPad()) if (!PrepareEHLandingPad()) continue; // Before doing SelectionDAG ISel, see if FastISel has been requested. if (FastIS) { FastIS->startNewBlock(); // Emit code for any incoming arguments. This must happen before // beginning FastISel on the entry block. if (LLVMBB == &Fn.getEntryBlock()) { ++NumEntryBlocks; // Lower any arguments needed in this block if this is the entry block. if (!FastIS->lowerArguments()) { // Fast isel failed to lower these arguments ++NumFastIselFailLowerArguments; if (EnableFastISelAbort > 1) report_fatal_error("FastISel didn't lower all arguments"); // Use SelectionDAG argument lowering LowerArguments(Fn); CurDAG->setRoot(SDB->getControlRoot()); SDB->clear(); CodeGenAndEmitDAG(); } // If we inserted any instructions at the beginning, make a note of // where they are, so we can be sure to emit subsequent instructions // after them. if (FuncInfo->InsertPt != FuncInfo->MBB->begin()) FastIS->setLastLocalValue(&*std::prev(FuncInfo->InsertPt)); else FastIS->setLastLocalValue(nullptr); } unsigned NumFastIselRemaining = std::distance(Begin, End); // Do FastISel on as many instructions as possible. for (; BI != Begin; --BI) { const Instruction *Inst = &*std::prev(BI); // If we no longer require this instruction, skip it. if (isFoldedOrDeadInstruction(Inst, FuncInfo)) { --NumFastIselRemaining; continue; } // Bottom-up: reset the insert pos at the top, after any local-value // instructions. FastIS->recomputeInsertPt(); // Try to select the instruction with FastISel. if (FastIS->selectInstruction(Inst)) { --NumFastIselRemaining; ++NumFastIselSuccess; // If fast isel succeeded, skip over all the folded instructions, and // then see if there is a load right before the selected instructions. // Try to fold the load if so. const Instruction *BeforeInst = Inst; while (BeforeInst != &*Begin) { BeforeInst = &*std::prev(BasicBlock::const_iterator(BeforeInst)); if (!isFoldedOrDeadInstruction(BeforeInst, FuncInfo)) break; } if (BeforeInst != Inst && isa(BeforeInst) && BeforeInst->hasOneUse() && FastIS->tryToFoldLoad(cast(BeforeInst), Inst)) { // If we succeeded, don't re-select the load. BI = std::next(BasicBlock::const_iterator(BeforeInst)); --NumFastIselRemaining; ++NumFastIselSuccess; } continue; } #ifndef NDEBUG if (EnableFastISelVerbose2) collectFailStats(Inst); #endif // Then handle certain instructions as single-LLVM-Instruction blocks. if (isa(Inst)) { if (EnableFastISelVerbose || EnableFastISelAbort) { dbgs() << "FastISel missed call: "; Inst->dump(); } if (EnableFastISelAbort > 2) // FastISel selector couldn't handle something and bailed. // For the purpose of debugging, just abort. report_fatal_error("FastISel didn't select the entire block"); if (!Inst->getType()->isVoidTy() && !Inst->getType()->isTokenTy() && !Inst->use_empty()) { unsigned &R = FuncInfo->ValueMap[Inst]; if (!R) R = FuncInfo->CreateRegs(Inst->getType()); } bool HadTailCall = false; MachineBasicBlock::iterator SavedInsertPt = FuncInfo->InsertPt; SelectBasicBlock(Inst->getIterator(), BI, HadTailCall); // If the call was emitted as a tail call, we're done with the block. // We also need to delete any previously emitted instructions. if (HadTailCall) { FastIS->removeDeadCode(SavedInsertPt, FuncInfo->MBB->end()); --BI; break; } // Recompute NumFastIselRemaining as Selection DAG instruction // selection may have handled the call, input args, etc. unsigned RemainingNow = std::distance(Begin, BI); NumFastIselFailures += NumFastIselRemaining - RemainingNow; NumFastIselRemaining = RemainingNow; continue; } bool ShouldAbort = EnableFastISelAbort; if (EnableFastISelVerbose || EnableFastISelAbort) { if (isa(Inst)) { // Use a different message for terminator misses. dbgs() << "FastISel missed terminator: "; // Don't abort unless for terminator unless the level is really high ShouldAbort = (EnableFastISelAbort > 2); } else { dbgs() << "FastISel miss: "; } Inst->dump(); } if (ShouldAbort) // FastISel selector couldn't handle something and bailed. // For the purpose of debugging, just abort. report_fatal_error("FastISel didn't select the entire block"); NumFastIselFailures += NumFastIselRemaining; break; } FastIS->recomputeInsertPt(); } else { // Lower any arguments needed in this block if this is the entry block. if (LLVMBB == &Fn.getEntryBlock()) { ++NumEntryBlocks; LowerArguments(Fn); } } if (getAnalysis().shouldEmitSDCheck(*LLVMBB)) { bool FunctionBasedInstrumentation = TLI->getSSPStackGuardCheck(*Fn.getParent()); SDB->SPDescriptor.initialize(LLVMBB, FuncInfo->MBBMap[LLVMBB], FunctionBasedInstrumentation); } if (Begin != BI) ++NumDAGBlocks; else ++NumFastIselBlocks; if (Begin != BI) { // Run SelectionDAG instruction selection on the remainder of the block // not handled by FastISel. If FastISel is not run, this is the entire // block. bool HadTailCall; SelectBasicBlock(Begin, BI, HadTailCall); } FinishBasicBlock(); FuncInfo->PHINodesToUpdate.clear(); } propagateSwiftErrorVRegs(FuncInfo); delete FastIS; SDB->clearDanglingDebugInfo(); SDB->SPDescriptor.resetPerFunctionState(); } /// Given that the input MI is before a partial terminator sequence TSeq, return /// true if M + TSeq also a partial terminator sequence. /// /// A Terminator sequence is a sequence of MachineInstrs which at this point in /// lowering copy vregs into physical registers, which are then passed into /// terminator instructors so we can satisfy ABI constraints. A partial /// terminator sequence is an improper subset of a terminator sequence (i.e. it /// may be the whole terminator sequence). static bool MIIsInTerminatorSequence(const MachineInstr &MI) { // If we do not have a copy or an implicit def, we return true if and only if // MI is a debug value. if (!MI.isCopy() && !MI.isImplicitDef()) // Sometimes DBG_VALUE MI sneak in between the copies from the vregs to the // physical registers if there is debug info associated with the terminator // of our mbb. We want to include said debug info in our terminator // sequence, so we return true in that case. return MI.isDebugValue(); // We have left the terminator sequence if we are not doing one of the // following: // // 1. Copying a vreg into a physical register. // 2. Copying a vreg into a vreg. // 3. Defining a register via an implicit def. // OPI should always be a register definition... MachineInstr::const_mop_iterator OPI = MI.operands_begin(); if (!OPI->isReg() || !OPI->isDef()) return false; // Defining any register via an implicit def is always ok. if (MI.isImplicitDef()) return true; // Grab the copy source... MachineInstr::const_mop_iterator OPI2 = OPI; ++OPI2; assert(OPI2 != MI.operands_end() && "Should have a copy implying we should have 2 arguments."); // Make sure that the copy dest is not a vreg when the copy source is a // physical register. if (!OPI2->isReg() || (!TargetRegisterInfo::isPhysicalRegister(OPI->getReg()) && TargetRegisterInfo::isPhysicalRegister(OPI2->getReg()))) return false; return true; } /// Find the split point at which to splice the end of BB into its success stack /// protector check machine basic block. /// /// On many platforms, due to ABI constraints, terminators, even before register /// allocation, use physical registers. This creates an issue for us since /// physical registers at this point can not travel across basic /// blocks. Luckily, selectiondag always moves physical registers into vregs /// when they enter functions and moves them through a sequence of copies back /// into the physical registers right before the terminator creating a /// ``Terminator Sequence''. This function is searching for the beginning of the /// terminator sequence so that we can ensure that we splice off not just the /// terminator, but additionally the copies that move the vregs into the /// physical registers. static MachineBasicBlock::iterator FindSplitPointForStackProtector(MachineBasicBlock *BB) { MachineBasicBlock::iterator SplitPoint = BB->getFirstTerminator(); // if (SplitPoint == BB->begin()) return SplitPoint; MachineBasicBlock::iterator Start = BB->begin(); MachineBasicBlock::iterator Previous = SplitPoint; --Previous; while (MIIsInTerminatorSequence(*Previous)) { SplitPoint = Previous; if (Previous == Start) break; --Previous; } return SplitPoint; } void SelectionDAGISel::FinishBasicBlock() { DEBUG(dbgs() << "Total amount of phi nodes to update: " << FuncInfo->PHINodesToUpdate.size() << "\n"; for (unsigned i = 0, e = FuncInfo->PHINodesToUpdate.size(); i != e; ++i) dbgs() << "Node " << i << " : (" << FuncInfo->PHINodesToUpdate[i].first << ", " << FuncInfo->PHINodesToUpdate[i].second << ")\n"); // Next, now that we know what the last MBB the LLVM BB expanded is, update // PHI nodes in successors. for (unsigned i = 0, e = FuncInfo->PHINodesToUpdate.size(); i != e; ++i) { MachineInstrBuilder PHI(*MF, FuncInfo->PHINodesToUpdate[i].first); assert(PHI->isPHI() && "This is not a machine PHI node that we are updating!"); if (!FuncInfo->MBB->isSuccessor(PHI->getParent())) continue; PHI.addReg(FuncInfo->PHINodesToUpdate[i].second).addMBB(FuncInfo->MBB); } // Handle stack protector. if (SDB->SPDescriptor.shouldEmitFunctionBasedCheckStackProtector()) { // The target provides a guard check function. There is no need to // generate error handling code or to split current basic block. MachineBasicBlock *ParentMBB = SDB->SPDescriptor.getParentMBB(); // Add load and check to the basicblock. FuncInfo->MBB = ParentMBB; FuncInfo->InsertPt = FindSplitPointForStackProtector(ParentMBB); SDB->visitSPDescriptorParent(SDB->SPDescriptor, ParentMBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); // Clear the Per-BB State. SDB->SPDescriptor.resetPerBBState(); } else if (SDB->SPDescriptor.shouldEmitStackProtector()) { MachineBasicBlock *ParentMBB = SDB->SPDescriptor.getParentMBB(); MachineBasicBlock *SuccessMBB = SDB->SPDescriptor.getSuccessMBB(); // Find the split point to split the parent mbb. At the same time copy all // physical registers used in the tail of parent mbb into virtual registers // before the split point and back into physical registers after the split // point. This prevents us needing to deal with Live-ins and many other // register allocation issues caused by us splitting the parent mbb. The // register allocator will clean up said virtual copies later on. MachineBasicBlock::iterator SplitPoint = FindSplitPointForStackProtector(ParentMBB); // Splice the terminator of ParentMBB into SuccessMBB. SuccessMBB->splice(SuccessMBB->end(), ParentMBB, SplitPoint, ParentMBB->end()); // Add compare/jump on neq/jump to the parent BB. FuncInfo->MBB = ParentMBB; FuncInfo->InsertPt = ParentMBB->end(); SDB->visitSPDescriptorParent(SDB->SPDescriptor, ParentMBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); // CodeGen Failure MBB if we have not codegened it yet. MachineBasicBlock *FailureMBB = SDB->SPDescriptor.getFailureMBB(); if (FailureMBB->empty()) { FuncInfo->MBB = FailureMBB; FuncInfo->InsertPt = FailureMBB->end(); SDB->visitSPDescriptorFailure(SDB->SPDescriptor); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); } // Clear the Per-BB State. SDB->SPDescriptor.resetPerBBState(); } // Lower each BitTestBlock. for (auto &BTB : SDB->BitTestCases) { // Lower header first, if it wasn't already lowered if (!BTB.Emitted) { // Set the current basic block to the mbb we wish to insert the code into FuncInfo->MBB = BTB.Parent; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Emit the code SDB->visitBitTestHeader(BTB, FuncInfo->MBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); } BranchProbability UnhandledProb = BTB.Prob; for (unsigned j = 0, ej = BTB.Cases.size(); j != ej; ++j) { UnhandledProb -= BTB.Cases[j].ExtraProb; // Set the current basic block to the mbb we wish to insert the code into FuncInfo->MBB = BTB.Cases[j].ThisBB; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Emit the code // If all cases cover a contiguous range, it is not necessary to jump to // the default block after the last bit test fails. This is because the // range check during bit test header creation has guaranteed that every // case here doesn't go outside the range. In this case, there is no need // to perform the last bit test, as it will always be true. Instead, make // the second-to-last bit-test fall through to the target of the last bit // test, and delete the last bit test. MachineBasicBlock *NextMBB; if (BTB.ContiguousRange && j + 2 == ej) { // Second-to-last bit-test with contiguous range: fall through to the // target of the final bit test. NextMBB = BTB.Cases[j + 1].TargetBB; } else if (j + 1 == ej) { // For the last bit test, fall through to Default. NextMBB = BTB.Default; } else { // Otherwise, fall through to the next bit test. NextMBB = BTB.Cases[j + 1].ThisBB; } SDB->visitBitTestCase(BTB, NextMBB, UnhandledProb, BTB.Reg, BTB.Cases[j], FuncInfo->MBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); if (BTB.ContiguousRange && j + 2 == ej) { // Since we're not going to use the final bit test, remove it. BTB.Cases.pop_back(); break; } } // Update PHI Nodes for (unsigned pi = 0, pe = FuncInfo->PHINodesToUpdate.size(); pi != pe; ++pi) { MachineInstrBuilder PHI(*MF, FuncInfo->PHINodesToUpdate[pi].first); MachineBasicBlock *PHIBB = PHI->getParent(); assert(PHI->isPHI() && "This is not a machine PHI node that we are updating!"); // This is "default" BB. We have two jumps to it. From "header" BB and // from last "case" BB, unless the latter was skipped. if (PHIBB == BTB.Default) { PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(BTB.Parent); if (!BTB.ContiguousRange) { PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second) .addMBB(BTB.Cases.back().ThisBB); } } // One of "cases" BB. for (unsigned j = 0, ej = BTB.Cases.size(); j != ej; ++j) { MachineBasicBlock* cBB = BTB.Cases[j].ThisBB; if (cBB->isSuccessor(PHIBB)) PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(cBB); } } } SDB->BitTestCases.clear(); // If the JumpTable record is filled in, then we need to emit a jump table. // Updating the PHI nodes is tricky in this case, since we need to determine // whether the PHI is a successor of the range check MBB or the jump table MBB for (unsigned i = 0, e = SDB->JTCases.size(); i != e; ++i) { // Lower header first, if it wasn't already lowered if (!SDB->JTCases[i].first.Emitted) { // Set the current basic block to the mbb we wish to insert the code into FuncInfo->MBB = SDB->JTCases[i].first.HeaderBB; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Emit the code SDB->visitJumpTableHeader(SDB->JTCases[i].second, SDB->JTCases[i].first, FuncInfo->MBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); } // Set the current basic block to the mbb we wish to insert the code into FuncInfo->MBB = SDB->JTCases[i].second.MBB; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Emit the code SDB->visitJumpTable(SDB->JTCases[i].second); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); // Update PHI Nodes for (unsigned pi = 0, pe = FuncInfo->PHINodesToUpdate.size(); pi != pe; ++pi) { MachineInstrBuilder PHI(*MF, FuncInfo->PHINodesToUpdate[pi].first); MachineBasicBlock *PHIBB = PHI->getParent(); assert(PHI->isPHI() && "This is not a machine PHI node that we are updating!"); // "default" BB. We can go there only from header BB. if (PHIBB == SDB->JTCases[i].second.Default) PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second) .addMBB(SDB->JTCases[i].first.HeaderBB); // JT BB. Just iterate over successors here if (FuncInfo->MBB->isSuccessor(PHIBB)) PHI.addReg(FuncInfo->PHINodesToUpdate[pi].second).addMBB(FuncInfo->MBB); } } SDB->JTCases.clear(); // If we generated any switch lowering information, build and codegen any // additional DAGs necessary. for (unsigned i = 0, e = SDB->SwitchCases.size(); i != e; ++i) { // Set the current basic block to the mbb we wish to insert the code into FuncInfo->MBB = SDB->SwitchCases[i].ThisBB; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Determine the unique successors. SmallVector Succs; Succs.push_back(SDB->SwitchCases[i].TrueBB); if (SDB->SwitchCases[i].TrueBB != SDB->SwitchCases[i].FalseBB) Succs.push_back(SDB->SwitchCases[i].FalseBB); // Emit the code. Note that this could result in FuncInfo->MBB being split. SDB->visitSwitchCase(SDB->SwitchCases[i], FuncInfo->MBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); // Remember the last block, now that any splitting is done, for use in // populating PHI nodes in successors. MachineBasicBlock *ThisBB = FuncInfo->MBB; // Handle any PHI nodes in successors of this chunk, as if we were coming // from the original BB before switch expansion. Note that PHI nodes can // occur multiple times in PHINodesToUpdate. We have to be very careful to // handle them the right number of times. for (unsigned i = 0, e = Succs.size(); i != e; ++i) { FuncInfo->MBB = Succs[i]; FuncInfo->InsertPt = FuncInfo->MBB->end(); // FuncInfo->MBB may have been removed from the CFG if a branch was // constant folded. if (ThisBB->isSuccessor(FuncInfo->MBB)) { for (MachineBasicBlock::iterator MBBI = FuncInfo->MBB->begin(), MBBE = FuncInfo->MBB->end(); MBBI != MBBE && MBBI->isPHI(); ++MBBI) { MachineInstrBuilder PHI(*MF, MBBI); // This value for this PHI node is recorded in PHINodesToUpdate. for (unsigned pn = 0; ; ++pn) { assert(pn != FuncInfo->PHINodesToUpdate.size() && "Didn't find PHI entry!"); if (FuncInfo->PHINodesToUpdate[pn].first == PHI) { PHI.addReg(FuncInfo->PHINodesToUpdate[pn].second).addMBB(ThisBB); break; } } } } } } SDB->SwitchCases.clear(); } /// Create the scheduler. If a specific scheduler was specified /// via the SchedulerRegistry, use it, otherwise select the /// one preferred by the target. /// ScheduleDAGSDNodes *SelectionDAGISel::CreateScheduler() { return ISHeuristic(this, OptLevel); } //===----------------------------------------------------------------------===// // Helper functions used by the generated instruction selector. //===----------------------------------------------------------------------===// // Calls to these methods are generated by tblgen. /// CheckAndMask - The isel is trying to match something like (and X, 255). If /// the dag combiner simplified the 255, we still want to match. RHS is the /// actual value in the DAG on the RHS of an AND, and DesiredMaskS is the value /// specified in the .td file (e.g. 255). bool SelectionDAGISel::CheckAndMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const { const APInt &ActualMask = RHS->getAPIntValue(); const APInt &DesiredMask = APInt(LHS.getValueSizeInBits(), DesiredMaskS); // If the actual mask exactly matches, success! if (ActualMask == DesiredMask) return true; // If the actual AND mask is allowing unallowed bits, this doesn't match. if (ActualMask.intersects(~DesiredMask)) return false; // Otherwise, the DAG Combiner may have proven that the value coming in is // either already zero or is not demanded. Check for known zero input bits. APInt NeededMask = DesiredMask & ~ActualMask; if (CurDAG->MaskedValueIsZero(LHS, NeededMask)) return true; // TODO: check to see if missing bits are just not demanded. // Otherwise, this pattern doesn't match. return false; } /// CheckOrMask - The isel is trying to match something like (or X, 255). If /// the dag combiner simplified the 255, we still want to match. RHS is the /// actual value in the DAG on the RHS of an OR, and DesiredMaskS is the value /// specified in the .td file (e.g. 255). bool SelectionDAGISel::CheckOrMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const { const APInt &ActualMask = RHS->getAPIntValue(); const APInt &DesiredMask = APInt(LHS.getValueSizeInBits(), DesiredMaskS); // If the actual mask exactly matches, success! if (ActualMask == DesiredMask) return true; // If the actual AND mask is allowing unallowed bits, this doesn't match. if (ActualMask.intersects(~DesiredMask)) return false; // Otherwise, the DAG Combiner may have proven that the value coming in is // either already zero or is not demanded. Check for known zero input bits. APInt NeededMask = DesiredMask & ~ActualMask; APInt KnownZero, KnownOne; CurDAG->computeKnownBits(LHS, KnownZero, KnownOne); // If all the missing bits in the or are already known to be set, match! if ((NeededMask & KnownOne) == NeededMask) return true; // TODO: check to see if missing bits are just not demanded. // Otherwise, this pattern doesn't match. return false; } /// SelectInlineAsmMemoryOperands - Calls to this are automatically generated /// by tblgen. Others should not call it. void SelectionDAGISel::SelectInlineAsmMemoryOperands(std::vector &Ops, const SDLoc &DL) { std::vector InOps; std::swap(InOps, Ops); Ops.push_back(InOps[InlineAsm::Op_InputChain]); // 0 Ops.push_back(InOps[InlineAsm::Op_AsmString]); // 1 Ops.push_back(InOps[InlineAsm::Op_MDNode]); // 2, !srcloc Ops.push_back(InOps[InlineAsm::Op_ExtraInfo]); // 3 (SideEffect, AlignStack) unsigned i = InlineAsm::Op_FirstOperand, e = InOps.size(); if (InOps[e-1].getValueType() == MVT::Glue) --e; // Don't process a glue operand if it is here. while (i != e) { unsigned Flags = cast(InOps[i])->getZExtValue(); if (!InlineAsm::isMemKind(Flags)) { // Just skip over this operand, copying the operands verbatim. Ops.insert(Ops.end(), InOps.begin()+i, InOps.begin()+i+InlineAsm::getNumOperandRegisters(Flags) + 1); i += InlineAsm::getNumOperandRegisters(Flags) + 1; } else { assert(InlineAsm::getNumOperandRegisters(Flags) == 1 && "Memory operand with multiple values?"); unsigned TiedToOperand; if (InlineAsm::isUseOperandTiedToDef(Flags, TiedToOperand)) { // We need the constraint ID from the operand this is tied to. unsigned CurOp = InlineAsm::Op_FirstOperand; Flags = cast(InOps[CurOp])->getZExtValue(); for (; TiedToOperand; --TiedToOperand) { CurOp += InlineAsm::getNumOperandRegisters(Flags)+1; Flags = cast(InOps[CurOp])->getZExtValue(); } } // Otherwise, this is a memory operand. Ask the target to select it. std::vector SelOps; unsigned ConstraintID = InlineAsm::getMemoryConstraintID(Flags); if (SelectInlineAsmMemoryOperand(InOps[i+1], ConstraintID, SelOps)) report_fatal_error("Could not match memory address. Inline asm" " failure!"); // Add this to the output node. unsigned NewFlags = InlineAsm::getFlagWord(InlineAsm::Kind_Mem, SelOps.size()); NewFlags = InlineAsm::getFlagWordForMem(NewFlags, ConstraintID); Ops.push_back(CurDAG->getTargetConstant(NewFlags, DL, MVT::i32)); Ops.insert(Ops.end(), SelOps.begin(), SelOps.end()); i += 2; } } // Add the glue input back if present. if (e != InOps.size()) Ops.push_back(InOps.back()); } /// findGlueUse - Return use of MVT::Glue value produced by the specified /// SDNode. /// static SDNode *findGlueUse(SDNode *N) { unsigned FlagResNo = N->getNumValues()-1; for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) { SDUse &Use = I.getUse(); if (Use.getResNo() == FlagResNo) return Use.getUser(); } return nullptr; } /// findNonImmUse - Return true if "Use" is a non-immediate use of "Def". /// This function recursively traverses up the operand chain, ignoring /// certain nodes. static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse, SDNode *Root, SmallPtrSetImpl &Visited, bool IgnoreChains) { // The NodeID's are given uniques ID's where a node ID is guaranteed to be // greater than all of its (recursive) operands. If we scan to a point where // 'use' is smaller than the node we're scanning for, then we know we will // never find it. // // The Use may be -1 (unassigned) if it is a newly allocated node. This can // happen because we scan down to newly selected nodes in the case of glue // uses. if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)) return false; // Don't revisit nodes if we already scanned it and didn't fail, we know we // won't fail if we scan it again. if (!Visited.insert(Use).second) return false; for (const SDValue &Op : Use->op_values()) { // Ignore chain uses, they are validated by HandleMergeInputChains. if (Op.getValueType() == MVT::Other && IgnoreChains) continue; SDNode *N = Op.getNode(); if (N == Def) { if (Use == ImmedUse || Use == Root) continue; // We are not looking for immediate use. assert(N != Root); return true; } // Traverse up the operand chain. if (findNonImmUse(N, Def, ImmedUse, Root, Visited, IgnoreChains)) return true; } return false; } /// IsProfitableToFold - Returns true if it's profitable to fold the specific /// operand node N of U during instruction selection that starts at Root. bool SelectionDAGISel::IsProfitableToFold(SDValue N, SDNode *U, SDNode *Root) const { if (OptLevel == CodeGenOpt::None) return false; return N.hasOneUse(); } /// IsLegalToFold - Returns true if the specific operand node N of /// U can be folded during instruction selection that starts at Root. bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, CodeGenOpt::Level OptLevel, bool IgnoreChains) { if (OptLevel == CodeGenOpt::None) return false; // If Root use can somehow reach N through a path that that doesn't contain // U then folding N would create a cycle. e.g. In the following // diagram, Root can reach N through X. If N is folded into into Root, then // X is both a predecessor and a successor of U. // // [N*] // // ^ ^ // // / \ // // [U*] [X]? // // ^ ^ // // \ / // // \ / // // [Root*] // // // * indicates nodes to be folded together. // // If Root produces glue, then it gets (even more) interesting. Since it // will be "glued" together with its glue use in the scheduler, we need to // check if it might reach N. // // [N*] // // ^ ^ // // / \ // // [U*] [X]? // // ^ ^ // // \ \ // // \ | // // [Root*] | // // ^ | // // f | // // | / // // [Y] / // // ^ / // // f / // // | / // // [GU] // // // If GU (glue use) indirectly reaches N (the load), and Root folds N // (call it Fold), then X is a predecessor of GU and a successor of // Fold. But since Fold and GU are glued together, this will create // a cycle in the scheduling graph. // If the node has glue, walk down the graph to the "lowest" node in the // glueged set. EVT VT = Root->getValueType(Root->getNumValues()-1); while (VT == MVT::Glue) { SDNode *GU = findGlueUse(Root); if (!GU) break; Root = GU; VT = Root->getValueType(Root->getNumValues()-1); // If our query node has a glue result with a use, we've walked up it. If // the user (which has already been selected) has a chain or indirectly uses // the chain, our WalkChainUsers predicate will not consider it. Because of // this, we cannot ignore chains in this predicate. IgnoreChains = false; } SmallPtrSet Visited; return !findNonImmUse(Root, N.getNode(), U, Root, Visited, IgnoreChains); } void SelectionDAGISel::Select_INLINEASM(SDNode *N) { SDLoc DL(N); std::vector Ops(N->op_begin(), N->op_end()); SelectInlineAsmMemoryOperands(Ops, DL); const EVT VTs[] = {MVT::Other, MVT::Glue}; SDValue New = CurDAG->getNode(ISD::INLINEASM, DL, VTs, Ops); New->setNodeId(-1); ReplaceUses(N, New.getNode()); CurDAG->RemoveDeadNode(N); } void SelectionDAGISel::Select_READ_REGISTER(SDNode *Op) { SDLoc dl(Op); MDNodeSDNode *MD = dyn_cast(Op->getOperand(1)); const MDString *RegStr = dyn_cast(MD->getMD()->getOperand(0)); unsigned Reg = TLI->getRegisterByName(RegStr->getString().data(), Op->getValueType(0), *CurDAG); SDValue New = CurDAG->getCopyFromReg( Op->getOperand(0), dl, Reg, Op->getValueType(0)); New->setNodeId(-1); ReplaceUses(Op, New.getNode()); CurDAG->RemoveDeadNode(Op); } void SelectionDAGISel::Select_WRITE_REGISTER(SDNode *Op) { SDLoc dl(Op); MDNodeSDNode *MD = dyn_cast(Op->getOperand(1)); const MDString *RegStr = dyn_cast(MD->getMD()->getOperand(0)); unsigned Reg = TLI->getRegisterByName(RegStr->getString().data(), Op->getOperand(2).getValueType(), *CurDAG); SDValue New = CurDAG->getCopyToReg( Op->getOperand(0), dl, Reg, Op->getOperand(2)); New->setNodeId(-1); ReplaceUses(Op, New.getNode()); CurDAG->RemoveDeadNode(Op); } void SelectionDAGISel::Select_UNDEF(SDNode *N) { CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); } /// GetVBR - decode a vbr encoding whose top bit is set. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { assert(Val >= 128 && "Not a VBR"); Val &= 127; // Remove first vbr bit. unsigned Shift = 7; uint64_t NextBits; do { NextBits = MatcherTable[Idx++]; Val |= (NextBits&127) << Shift; Shift += 7; } while (NextBits & 128); return Val; } /// When a match is complete, this method updates uses of interior chain results /// to use the new results. void SelectionDAGISel::UpdateChains( SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl &ChainNodesMatched, bool isMorphNodeTo) { + SmallVectorImpl &ChainNodesMatched, bool isMorphNodeTo) { SmallVector NowDeadNodes; // Now that all the normal results are replaced, we replace the chain and // glue results if present. if (!ChainNodesMatched.empty()) { assert(InputChain.getNode() && "Matched input chains but didn't produce a chain"); // Loop over all of the nodes we matched that produced a chain result. // Replace all the chain results with the final chain we ended up with. for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) { SDNode *ChainNode = ChainNodesMatched[i]; + // If ChainNode is null, it's because we replaced it on a previous + // iteration and we cleared it out of the map. Just skip it. + if (!ChainNode) + continue; + assert(ChainNode->getOpcode() != ISD::DELETED_NODE && "Deleted node left in chain"); // Don't replace the results of the root node if we're doing a // MorphNodeTo. if (ChainNode == NodeToMatch && isMorphNodeTo) continue; SDValue ChainVal = SDValue(ChainNode, ChainNode->getNumValues()-1); if (ChainVal.getValueType() == MVT::Glue) ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2); assert(ChainVal.getValueType() == MVT::Other && "Not a chain?"); + SelectionDAG::DAGNodeDeletedListener NDL( + *CurDAG, [&](SDNode *N, SDNode *E) { + std::replace(ChainNodesMatched.begin(), ChainNodesMatched.end(), N, + static_cast(nullptr)); + }); CurDAG->ReplaceAllUsesOfValueWith(ChainVal, InputChain); // If the node became dead and we haven't already seen it, delete it. if (ChainNode != NodeToMatch && ChainNode->use_empty() && !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), ChainNode)) NowDeadNodes.push_back(ChainNode); } } if (!NowDeadNodes.empty()) CurDAG->RemoveDeadNodes(NowDeadNodes); DEBUG(dbgs() << "ISEL: Match complete!\n"); } enum ChainResult { CR_Simple, CR_InducesCycle, CR_LeadsToInteriorNode }; /// WalkChainUsers - Walk down the users of the specified chained node that is /// part of the pattern we're matching, looking at all of the users we find. /// This determines whether something is an interior node, whether we have a /// non-pattern node in between two pattern nodes (which prevent folding because /// it would induce a cycle) and whether we have a TokenFactor node sandwiched /// between pattern nodes (in which case the TF becomes part of the pattern). /// /// The walk we do here is guaranteed to be small because we quickly get down to /// already selected nodes "below" us. static ChainResult WalkChainUsers(const SDNode *ChainedNode, SmallVectorImpl &ChainedNodesInPattern, DenseMap &TokenFactorResult, SmallVectorImpl &InteriorChainedNodes) { ChainResult Result = CR_Simple; for (SDNode::use_iterator UI = ChainedNode->use_begin(), E = ChainedNode->use_end(); UI != E; ++UI) { // Make sure the use is of the chain, not some other value we produce. if (UI.getUse().getValueType() != MVT::Other) continue; SDNode *User = *UI; if (User->getOpcode() == ISD::HANDLENODE) // Root of the graph. continue; // If we see an already-selected machine node, then we've gone beyond the // pattern that we're selecting down into the already selected chunk of the // DAG. unsigned UserOpcode = User->getOpcode(); if (User->isMachineOpcode() || UserOpcode == ISD::CopyToReg || UserOpcode == ISD::CopyFromReg || UserOpcode == ISD::INLINEASM || UserOpcode == ISD::EH_LABEL || UserOpcode == ISD::LIFETIME_START || UserOpcode == ISD::LIFETIME_END) { // If their node ID got reset to -1 then they've already been selected. // Treat them like a MachineOpcode. if (User->getNodeId() == -1) continue; } // If we have a TokenFactor, we handle it specially. if (User->getOpcode() != ISD::TokenFactor) { // If the node isn't a token factor and isn't part of our pattern, then it // must be a random chained node in between two nodes we're selecting. // This happens when we have something like: // x = load ptr // call // y = x+4 // store y -> ptr // Because we structurally match the load/store as a read/modify/write, // but the call is chained between them. We cannot fold in this case // because it would induce a cycle in the graph. if (!std::count(ChainedNodesInPattern.begin(), ChainedNodesInPattern.end(), User)) return CR_InducesCycle; // Otherwise we found a node that is part of our pattern. For example in: // x = load ptr // y = x+4 // store y -> ptr // This would happen when we're scanning down from the load and see the // store as a user. Record that there is a use of ChainedNode that is // part of the pattern and keep scanning uses. Result = CR_LeadsToInteriorNode; InteriorChainedNodes.push_back(User); continue; } // If we found a TokenFactor, there are two cases to consider: first if the // TokenFactor is just hanging "below" the pattern we're matching (i.e. no // uses of the TF are in our pattern) we just want to ignore it. Second, // the TokenFactor can be sandwiched in between two chained nodes, like so: // [Load chain] // ^ // | // [Load] // ^ ^ // | \ DAG's like cheese // / \ do you? // / | // [TokenFactor] [Op] // ^ ^ // | | // \ / // \ / // [Store] // // In this case, the TokenFactor becomes part of our match and we rewrite it // as a new TokenFactor. // // To distinguish these two cases, do a recursive walk down the uses. auto MemoizeResult = TokenFactorResult.find(User); bool Visited = MemoizeResult != TokenFactorResult.end(); // Recursively walk chain users only if the result is not memoized. if (!Visited) { auto Res = WalkChainUsers(User, ChainedNodesInPattern, TokenFactorResult, InteriorChainedNodes); MemoizeResult = TokenFactorResult.insert(std::make_pair(User, Res)).first; } switch (MemoizeResult->second) { case CR_Simple: // If the uses of the TokenFactor are just already-selected nodes, ignore // it, it is "below" our pattern. continue; case CR_InducesCycle: // If the uses of the TokenFactor lead to nodes that are not part of our // pattern that are not selected, folding would turn this into a cycle, // bail out now. return CR_InducesCycle; case CR_LeadsToInteriorNode: break; // Otherwise, keep processing. } // Okay, we know we're in the interesting interior case. The TokenFactor // is now going to be considered part of the pattern so that we rewrite its // uses (it may have uses that are not part of the pattern) with the // ultimate chain result of the generated code. We will also add its chain // inputs as inputs to the ultimate TokenFactor we create. Result = CR_LeadsToInteriorNode; if (!Visited) { ChainedNodesInPattern.push_back(User); InteriorChainedNodes.push_back(User); } } return Result; } /// HandleMergeInputChains - This implements the OPC_EmitMergeInputChains /// operation for when the pattern matched at least one node with a chains. The /// input vector contains a list of all of the chained nodes that we match. We /// must determine if this is a valid thing to cover (i.e. matching it won't /// induce cycles in the DAG) and if so, creating a TokenFactor node. that will /// be used as the input node chain for the generated nodes. static SDValue HandleMergeInputChains(SmallVectorImpl &ChainNodesMatched, SelectionDAG *CurDAG) { // Used for memoization. Without it WalkChainUsers could take exponential // time to run. DenseMap TokenFactorResult; // Walk all of the chained nodes we've matched, recursively scanning down the // users of the chain result. This adds any TokenFactor nodes that are caught // in between chained nodes to the chained and interior nodes list. SmallVector InteriorChainedNodes; for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) { if (WalkChainUsers(ChainNodesMatched[i], ChainNodesMatched, TokenFactorResult, InteriorChainedNodes) == CR_InducesCycle) return SDValue(); // Would induce a cycle. } // Okay, we have walked all the matched nodes and collected TokenFactor nodes // that we are interested in. Form our input TokenFactor node. SmallVector InputChains; for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) { // Add the input chain of this node to the InputChains list (which will be // the operands of the generated TokenFactor) if it's not an interior node. SDNode *N = ChainNodesMatched[i]; if (N->getOpcode() != ISD::TokenFactor) { if (std::count(InteriorChainedNodes.begin(),InteriorChainedNodes.end(),N)) continue; // Otherwise, add the input chain. SDValue InChain = ChainNodesMatched[i]->getOperand(0); assert(InChain.getValueType() == MVT::Other && "Not a chain"); InputChains.push_back(InChain); continue; } // If we have a token factor, we want to add all inputs of the token factor // that are not part of the pattern we're matching. for (const SDValue &Op : N->op_values()) { if (!std::count(ChainNodesMatched.begin(), ChainNodesMatched.end(), Op.getNode())) InputChains.push_back(Op); } } if (InputChains.size() == 1) return InputChains[0]; return CurDAG->getNode(ISD::TokenFactor, SDLoc(ChainNodesMatched[0]), MVT::Other, InputChains); } /// MorphNode - Handle morphing a node in place for the selector. SDNode *SelectionDAGISel:: MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList, ArrayRef Ops, unsigned EmitNodeInfo) { // It is possible we're using MorphNodeTo to replace a node with no // normal results with one that has a normal result (or we could be // adding a chain) and the input could have glue and chains as well. // In this case we need to shift the operands down. // FIXME: This is a horrible hack and broken in obscure cases, no worse // than the old isel though. int OldGlueResultNo = -1, OldChainResultNo = -1; unsigned NTMNumResults = Node->getNumValues(); if (Node->getValueType(NTMNumResults-1) == MVT::Glue) { OldGlueResultNo = NTMNumResults-1; if (NTMNumResults != 1 && Node->getValueType(NTMNumResults-2) == MVT::Other) OldChainResultNo = NTMNumResults-2; } else if (Node->getValueType(NTMNumResults-1) == MVT::Other) OldChainResultNo = NTMNumResults-1; // Call the underlying SelectionDAG routine to do the transmogrification. Note // that this deletes operands of the old node that become dead. SDNode *Res = CurDAG->MorphNodeTo(Node, ~TargetOpc, VTList, Ops); // MorphNodeTo can operate in two ways: if an existing node with the // specified operands exists, it can just return it. Otherwise, it // updates the node in place to have the requested operands. if (Res == Node) { // If we updated the node in place, reset the node ID. To the isel, // this should be just like a newly allocated machine node. Res->setNodeId(-1); } unsigned ResNumResults = Res->getNumValues(); // Move the glue if needed. if ((EmitNodeInfo & OPFL_GlueOutput) && OldGlueResultNo != -1 && (unsigned)OldGlueResultNo != ResNumResults-1) CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldGlueResultNo), SDValue(Res, ResNumResults-1)); if ((EmitNodeInfo & OPFL_GlueOutput) != 0) --ResNumResults; // Move the chain reference if needed. if ((EmitNodeInfo & OPFL_Chain) && OldChainResultNo != -1 && (unsigned)OldChainResultNo != ResNumResults-1) CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldChainResultNo), SDValue(Res, ResNumResults-1)); // Otherwise, no replacement happened because the node already exists. Replace // Uses of the old node with the new one. if (Res != Node) { CurDAG->ReplaceAllUsesWith(Node, Res); CurDAG->RemoveDeadNode(Node); } return Res; } /// CheckSame - Implements OP_CheckSame. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckSame(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const SmallVectorImpl > &RecordedNodes) { // Accept if it is exactly the same as a previously recorded node. unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); return N == RecordedNodes[RecNo].first; } /// CheckChildSame - Implements OP_CheckChildXSame. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckChildSame(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const SmallVectorImpl > &RecordedNodes, unsigned ChildNo) { if (ChildNo >= N.getNumOperands()) return false; // Match fails if out of range child #. return ::CheckSame(MatcherTable, MatcherIndex, N.getOperand(ChildNo), RecordedNodes); } /// CheckPatternPredicate - Implements OP_CheckPatternPredicate. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckPatternPredicate(const unsigned char *MatcherTable, unsigned &MatcherIndex, const SelectionDAGISel &SDISel) { return SDISel.CheckPatternPredicate(MatcherTable[MatcherIndex++]); } /// CheckNodePredicate - Implements OP_CheckNodePredicate. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckNodePredicate(const unsigned char *MatcherTable, unsigned &MatcherIndex, const SelectionDAGISel &SDISel, SDNode *N) { return SDISel.CheckNodePredicate(N, MatcherTable[MatcherIndex++]); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckOpcode(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDNode *N) { uint16_t Opc = MatcherTable[MatcherIndex++]; Opc |= (unsigned short)MatcherTable[MatcherIndex++] << 8; return N->getOpcode() == Opc; } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering *TLI, const DataLayout &DL) { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (N.getValueType() == VT) return true; // Handle the case when VT is iPTR. return VT == MVT::iPTR && N.getValueType() == TLI->getPointerTy(DL); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckChildType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering *TLI, const DataLayout &DL, unsigned ChildNo) { if (ChildNo >= N.getNumOperands()) return false; // Match fails if out of range child #. return ::CheckType(MatcherTable, MatcherIndex, N.getOperand(ChildNo), TLI, DL); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckCondCode(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N) { return cast(N)->get() == (ISD::CondCode)MatcherTable[MatcherIndex++]; } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckValueType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering *TLI, const DataLayout &DL) { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (cast(N)->getVT() == VT) return true; // Handle the case when VT is iPTR. return VT == MVT::iPTR && cast(N)->getVT() == TLI->getPointerTy(DL); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckInteger(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); ConstantSDNode *C = dyn_cast(N); return C && C->getSExtValue() == Val; } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckChildInteger(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, unsigned ChildNo) { if (ChildNo >= N.getNumOperands()) return false; // Match fails if out of range child #. return ::CheckInteger(MatcherTable, MatcherIndex, N.getOperand(ChildNo)); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckAndImm(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const SelectionDAGISel &SDISel) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); if (N->getOpcode() != ISD::AND) return false; ConstantSDNode *C = dyn_cast(N->getOperand(1)); return C && SDISel.CheckAndMask(N.getOperand(0), C, Val); } LLVM_ATTRIBUTE_ALWAYS_INLINE static inline bool CheckOrImm(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const SelectionDAGISel &SDISel) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); if (N->getOpcode() != ISD::OR) return false; ConstantSDNode *C = dyn_cast(N->getOperand(1)); return C && SDISel.CheckOrMask(N.getOperand(0), C, Val); } /// IsPredicateKnownToFail - If we know how and can do so without pushing a /// scope, evaluate the current node. If the current predicate is known to /// fail, set Result=true and return anything. If the current predicate is /// known to pass, set Result=false and return the MatcherIndex to continue /// with. If the current predicate is unknown, set Result=false and return the /// MatcherIndex to continue with. static unsigned IsPredicateKnownToFail(const unsigned char *Table, unsigned Index, SDValue N, bool &Result, const SelectionDAGISel &SDISel, SmallVectorImpl > &RecordedNodes) { switch (Table[Index++]) { default: Result = false; return Index-1; // Could not evaluate this predicate. case SelectionDAGISel::OPC_CheckSame: Result = !::CheckSame(Table, Index, N, RecordedNodes); return Index; case SelectionDAGISel::OPC_CheckChild0Same: case SelectionDAGISel::OPC_CheckChild1Same: case SelectionDAGISel::OPC_CheckChild2Same: case SelectionDAGISel::OPC_CheckChild3Same: Result = !::CheckChildSame(Table, Index, N, RecordedNodes, Table[Index-1] - SelectionDAGISel::OPC_CheckChild0Same); return Index; case SelectionDAGISel::OPC_CheckPatternPredicate: Result = !::CheckPatternPredicate(Table, Index, SDISel); return Index; case SelectionDAGISel::OPC_CheckPredicate: Result = !::CheckNodePredicate(Table, Index, SDISel, N.getNode()); return Index; case SelectionDAGISel::OPC_CheckOpcode: Result = !::CheckOpcode(Table, Index, N.getNode()); return Index; case SelectionDAGISel::OPC_CheckType: Result = !::CheckType(Table, Index, N, SDISel.TLI, SDISel.CurDAG->getDataLayout()); return Index; case SelectionDAGISel::OPC_CheckChild0Type: case SelectionDAGISel::OPC_CheckChild1Type: case SelectionDAGISel::OPC_CheckChild2Type: case SelectionDAGISel::OPC_CheckChild3Type: case SelectionDAGISel::OPC_CheckChild4Type: case SelectionDAGISel::OPC_CheckChild5Type: case SelectionDAGISel::OPC_CheckChild6Type: case SelectionDAGISel::OPC_CheckChild7Type: Result = !::CheckChildType( Table, Index, N, SDISel.TLI, SDISel.CurDAG->getDataLayout(), Table[Index - 1] - SelectionDAGISel::OPC_CheckChild0Type); return Index; case SelectionDAGISel::OPC_CheckCondCode: Result = !::CheckCondCode(Table, Index, N); return Index; case SelectionDAGISel::OPC_CheckValueType: Result = !::CheckValueType(Table, Index, N, SDISel.TLI, SDISel.CurDAG->getDataLayout()); return Index; case SelectionDAGISel::OPC_CheckInteger: Result = !::CheckInteger(Table, Index, N); return Index; case SelectionDAGISel::OPC_CheckChild0Integer: case SelectionDAGISel::OPC_CheckChild1Integer: case SelectionDAGISel::OPC_CheckChild2Integer: case SelectionDAGISel::OPC_CheckChild3Integer: case SelectionDAGISel::OPC_CheckChild4Integer: Result = !::CheckChildInteger(Table, Index, N, Table[Index-1] - SelectionDAGISel::OPC_CheckChild0Integer); return Index; case SelectionDAGISel::OPC_CheckAndImm: Result = !::CheckAndImm(Table, Index, N, SDISel); return Index; case SelectionDAGISel::OPC_CheckOrImm: Result = !::CheckOrImm(Table, Index, N, SDISel); return Index; } } namespace { struct MatchScope { /// FailIndex - If this match fails, this is the index to continue with. unsigned FailIndex; /// NodeStack - The node stack when the scope was formed. SmallVector NodeStack; /// NumRecordedNodes - The number of recorded nodes when the scope was formed. unsigned NumRecordedNodes; /// NumMatchedMemRefs - The number of matched memref entries. unsigned NumMatchedMemRefs; /// InputChain/InputGlue - The current chain/glue SDValue InputChain, InputGlue; /// HasChainNodesMatched - True if the ChainNodesMatched list is non-empty. bool HasChainNodesMatched; }; /// \\brief A DAG update listener to keep the matching state /// (i.e. RecordedNodes and MatchScope) uptodate if the target is allowed to /// change the DAG while matching. X86 addressing mode matcher is an example /// for this. class MatchStateUpdater : public SelectionDAG::DAGUpdateListener { SmallVectorImpl > &RecordedNodes; SmallVectorImpl &MatchScopes; public: MatchStateUpdater(SelectionDAG &DAG, SmallVectorImpl > &RN, SmallVectorImpl &MS) : SelectionDAG::DAGUpdateListener(DAG), RecordedNodes(RN), MatchScopes(MS) { } void NodeDeleted(SDNode *N, SDNode *E) override { // Some early-returns here to avoid the search if we deleted the node or // if the update comes from MorphNodeTo (MorphNodeTo is the last thing we // do, so it's unnecessary to update matching state at that point). // Neither of these can occur currently because we only install this // update listener during matching a complex patterns. if (!E || E->isMachineOpcode()) return; // Performing linear search here does not matter because we almost never // run this code. You'd have to have a CSE during complex pattern // matching. for (auto &I : RecordedNodes) if (I.first.getNode() == N) I.first.setNode(E); for (auto &I : MatchScopes) for (auto &J : I.NodeStack) if (J.getNode() == N) J.setNode(E); } }; } // end anonymous namespace void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned TableSize) { // FIXME: Should these even be selected? Handle these cases in the caller? switch (NodeToMatch->getOpcode()) { default: break; case ISD::EntryToken: // These nodes remain the same. case ISD::BasicBlock: case ISD::Register: case ISD::RegisterMask: case ISD::HANDLENODE: case ISD::MDNODE_SDNODE: case ISD::TargetConstant: case ISD::TargetConstantFP: case ISD::TargetConstantPool: case ISD::TargetFrameIndex: case ISD::TargetExternalSymbol: case ISD::MCSymbol: case ISD::TargetBlockAddress: case ISD::TargetJumpTable: case ISD::TargetGlobalTLSAddress: case ISD::TargetGlobalAddress: case ISD::TokenFactor: case ISD::CopyFromReg: case ISD::CopyToReg: case ISD::EH_LABEL: case ISD::LIFETIME_START: case ISD::LIFETIME_END: NodeToMatch->setNodeId(-1); // Mark selected. return; case ISD::AssertSext: case ISD::AssertZext: CurDAG->ReplaceAllUsesOfValueWith(SDValue(NodeToMatch, 0), NodeToMatch->getOperand(0)); CurDAG->RemoveDeadNode(NodeToMatch); return; case ISD::INLINEASM: Select_INLINEASM(NodeToMatch); return; case ISD::READ_REGISTER: Select_READ_REGISTER(NodeToMatch); return; case ISD::WRITE_REGISTER: Select_WRITE_REGISTER(NodeToMatch); return; case ISD::UNDEF: Select_UNDEF(NodeToMatch); return; } assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); // Set up the node stack with NodeToMatch as the only node on the stack. SmallVector NodeStack; SDValue N = SDValue(NodeToMatch, 0); NodeStack.push_back(N); // MatchScopes - Scopes used when matching, if a match failure happens, this // indicates where to continue checking. SmallVector MatchScopes; // RecordedNodes - This is the set of nodes that have been recorded by the // state machine. The second value is the parent of the node, or null if the // root is recorded. SmallVector, 8> RecordedNodes; // MatchedMemRefs - This is the set of MemRef's we've seen in the input // pattern. SmallVector MatchedMemRefs; // These are the current input chain and glue for use when generating nodes. // Various Emit operations change these. For example, emitting a copytoreg // uses and updates these. SDValue InputChain, InputGlue; // ChainNodesMatched - If a pattern matches nodes that have input/output // chains, the OPC_EmitMergeInputChains operation is emitted which indicates // which ones they are. The result is captured into this list so that we can // update the chain results when the pattern is complete. SmallVector ChainNodesMatched; DEBUG(dbgs() << "ISEL: Starting pattern match on root node: "; NodeToMatch->dump(CurDAG); dbgs() << '\n'); // Determine where to start the interpreter. Normally we start at opcode #0, // but if the state machine starts with an OPC_SwitchOpcode, then we // accelerate the first lookup (which is guaranteed to be hot) with the // OpcodeOffset table. unsigned MatcherIndex = 0; if (!OpcodeOffset.empty()) { // Already computed the OpcodeOffset table, just index into it. if (N.getOpcode() < OpcodeOffset.size()) MatcherIndex = OpcodeOffset[N.getOpcode()]; DEBUG(dbgs() << " Initial Opcode index to " << MatcherIndex << "\n"); } else if (MatcherTable[0] == OPC_SwitchOpcode) { // Otherwise, the table isn't computed, but the state machine does start // with an OPC_SwitchOpcode instruction. Populate the table now, since this // is the first time we're selecting an instruction. unsigned Idx = 1; while (1) { // Get the size of this case. unsigned CaseSize = MatcherTable[Idx++]; if (CaseSize & 128) CaseSize = GetVBR(CaseSize, MatcherTable, Idx); if (CaseSize == 0) break; // Get the opcode, add the index to the table. uint16_t Opc = MatcherTable[Idx++]; Opc |= (unsigned short)MatcherTable[Idx++] << 8; if (Opc >= OpcodeOffset.size()) OpcodeOffset.resize((Opc+1)*2); OpcodeOffset[Opc] = Idx; Idx += CaseSize; } // Okay, do the lookup for the first opcode. if (N.getOpcode() < OpcodeOffset.size()) MatcherIndex = OpcodeOffset[N.getOpcode()]; } while (1) { assert(MatcherIndex < TableSize && "Invalid index"); #ifndef NDEBUG unsigned CurrentOpcodeIndex = MatcherIndex; #endif BuiltinOpcodes Opcode = (BuiltinOpcodes)MatcherTable[MatcherIndex++]; switch (Opcode) { case OPC_Scope: { // Okay, the semantics of this operation are that we should push a scope // then evaluate the first child. However, pushing a scope only to have // the first check fail (which then pops it) is inefficient. If we can // determine immediately that the first check (or first several) will // immediately fail, don't even bother pushing a scope for them. unsigned FailIndex; while (1) { unsigned NumToSkip = MatcherTable[MatcherIndex++]; if (NumToSkip & 128) NumToSkip = GetVBR(NumToSkip, MatcherTable, MatcherIndex); // Found the end of the scope with no match. if (NumToSkip == 0) { FailIndex = 0; break; } FailIndex = MatcherIndex+NumToSkip; unsigned MatcherIndexOfPredicate = MatcherIndex; (void)MatcherIndexOfPredicate; // silence warning. // If we can't evaluate this predicate without pushing a scope (e.g. if // it is a 'MoveParent') or if the predicate succeeds on this node, we // push the scope and evaluate the full predicate chain. bool Result; MatcherIndex = IsPredicateKnownToFail(MatcherTable, MatcherIndex, N, Result, *this, RecordedNodes); if (!Result) break; DEBUG(dbgs() << " Skipped scope entry (due to false predicate) at " << "index " << MatcherIndexOfPredicate << ", continuing at " << FailIndex << "\n"); ++NumDAGIselRetries; // Otherwise, we know that this case of the Scope is guaranteed to fail, // move to the next case. MatcherIndex = FailIndex; } // If the whole scope failed to match, bail. if (FailIndex == 0) break; // Push a MatchScope which indicates where to go if the first child fails // to match. MatchScope NewEntry; NewEntry.FailIndex = FailIndex; NewEntry.NodeStack.append(NodeStack.begin(), NodeStack.end()); NewEntry.NumRecordedNodes = RecordedNodes.size(); NewEntry.NumMatchedMemRefs = MatchedMemRefs.size(); NewEntry.InputChain = InputChain; NewEntry.InputGlue = InputGlue; NewEntry.HasChainNodesMatched = !ChainNodesMatched.empty(); MatchScopes.push_back(NewEntry); continue; } case OPC_RecordNode: { // Remember this node, it may end up being an operand in the pattern. SDNode *Parent = nullptr; if (NodeStack.size() > 1) Parent = NodeStack[NodeStack.size()-2].getNode(); RecordedNodes.push_back(std::make_pair(N, Parent)); continue; } case OPC_RecordChild0: case OPC_RecordChild1: case OPC_RecordChild2: case OPC_RecordChild3: case OPC_RecordChild4: case OPC_RecordChild5: case OPC_RecordChild6: case OPC_RecordChild7: { unsigned ChildNo = Opcode-OPC_RecordChild0; if (ChildNo >= N.getNumOperands()) break; // Match fails if out of range child #. RecordedNodes.push_back(std::make_pair(N->getOperand(ChildNo), N.getNode())); continue; } case OPC_RecordMemRef: MatchedMemRefs.push_back(cast(N)->getMemOperand()); continue; case OPC_CaptureGlueInput: // If the current node has an input glue, capture it in InputGlue. if (N->getNumOperands() != 0 && N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue) InputGlue = N->getOperand(N->getNumOperands()-1); continue; case OPC_MoveChild: { unsigned ChildNo = MatcherTable[MatcherIndex++]; if (ChildNo >= N.getNumOperands()) break; // Match fails if out of range child #. N = N.getOperand(ChildNo); NodeStack.push_back(N); continue; } case OPC_MoveChild0: case OPC_MoveChild1: case OPC_MoveChild2: case OPC_MoveChild3: case OPC_MoveChild4: case OPC_MoveChild5: case OPC_MoveChild6: case OPC_MoveChild7: { unsigned ChildNo = Opcode-OPC_MoveChild0; if (ChildNo >= N.getNumOperands()) break; // Match fails if out of range child #. N = N.getOperand(ChildNo); NodeStack.push_back(N); continue; } case OPC_MoveParent: // Pop the current node off the NodeStack. NodeStack.pop_back(); assert(!NodeStack.empty() && "Node stack imbalance!"); N = NodeStack.back(); continue; case OPC_CheckSame: if (!::CheckSame(MatcherTable, MatcherIndex, N, RecordedNodes)) break; continue; case OPC_CheckChild0Same: case OPC_CheckChild1Same: case OPC_CheckChild2Same: case OPC_CheckChild3Same: if (!::CheckChildSame(MatcherTable, MatcherIndex, N, RecordedNodes, Opcode-OPC_CheckChild0Same)) break; continue; case OPC_CheckPatternPredicate: if (!::CheckPatternPredicate(MatcherTable, MatcherIndex, *this)) break; continue; case OPC_CheckPredicate: if (!::CheckNodePredicate(MatcherTable, MatcherIndex, *this, N.getNode())) break; continue; case OPC_CheckComplexPat: { unsigned CPNum = MatcherTable[MatcherIndex++]; unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckComplexPat"); // If target can modify DAG during matching, keep the matching state // consistent. std::unique_ptr MSU; if (ComplexPatternFuncMutatesDAG()) MSU.reset(new MatchStateUpdater(*CurDAG, RecordedNodes, MatchScopes)); if (!CheckComplexPattern(NodeToMatch, RecordedNodes[RecNo].second, RecordedNodes[RecNo].first, CPNum, RecordedNodes)) break; continue; } case OPC_CheckOpcode: if (!::CheckOpcode(MatcherTable, MatcherIndex, N.getNode())) break; continue; case OPC_CheckType: if (!::CheckType(MatcherTable, MatcherIndex, N, TLI, CurDAG->getDataLayout())) break; continue; case OPC_SwitchOpcode: { unsigned CurNodeOpcode = N.getOpcode(); unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; unsigned CaseSize; while (1) { // Get the size of this case. CaseSize = MatcherTable[MatcherIndex++]; if (CaseSize & 128) CaseSize = GetVBR(CaseSize, MatcherTable, MatcherIndex); if (CaseSize == 0) break; uint16_t Opc = MatcherTable[MatcherIndex++]; Opc |= (unsigned short)MatcherTable[MatcherIndex++] << 8; // If the opcode matches, then we will execute this case. if (CurNodeOpcode == Opc) break; // Otherwise, skip over this case. MatcherIndex += CaseSize; } // If no cases matched, bail out. if (CaseSize == 0) break; // Otherwise, execute the case we found. DEBUG(dbgs() << " OpcodeSwitch from " << SwitchStart << " to " << MatcherIndex << "\n"); continue; } case OPC_SwitchType: { MVT CurNodeVT = N.getSimpleValueType(); unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; unsigned CaseSize; while (1) { // Get the size of this case. CaseSize = MatcherTable[MatcherIndex++]; if (CaseSize & 128) CaseSize = GetVBR(CaseSize, MatcherTable, MatcherIndex); if (CaseSize == 0) break; MVT CaseVT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (CaseVT == MVT::iPTR) CaseVT = TLI->getPointerTy(CurDAG->getDataLayout()); // If the VT matches, then we will execute this case. if (CurNodeVT == CaseVT) break; // Otherwise, skip over this case. MatcherIndex += CaseSize; } // If no cases matched, bail out. if (CaseSize == 0) break; // Otherwise, execute the case we found. DEBUG(dbgs() << " TypeSwitch[" << EVT(CurNodeVT).getEVTString() << "] from " << SwitchStart << " to " << MatcherIndex<<'\n'); continue; } case OPC_CheckChild0Type: case OPC_CheckChild1Type: case OPC_CheckChild2Type: case OPC_CheckChild3Type: case OPC_CheckChild4Type: case OPC_CheckChild5Type: case OPC_CheckChild6Type: case OPC_CheckChild7Type: if (!::CheckChildType(MatcherTable, MatcherIndex, N, TLI, CurDAG->getDataLayout(), Opcode - OPC_CheckChild0Type)) break; continue; case OPC_CheckCondCode: if (!::CheckCondCode(MatcherTable, MatcherIndex, N)) break; continue; case OPC_CheckValueType: if (!::CheckValueType(MatcherTable, MatcherIndex, N, TLI, CurDAG->getDataLayout())) break; continue; case OPC_CheckInteger: if (!::CheckInteger(MatcherTable, MatcherIndex, N)) break; continue; case OPC_CheckChild0Integer: case OPC_CheckChild1Integer: case OPC_CheckChild2Integer: case OPC_CheckChild3Integer: case OPC_CheckChild4Integer: if (!::CheckChildInteger(MatcherTable, MatcherIndex, N, Opcode-OPC_CheckChild0Integer)) break; continue; case OPC_CheckAndImm: if (!::CheckAndImm(MatcherTable, MatcherIndex, N, *this)) break; continue; case OPC_CheckOrImm: if (!::CheckOrImm(MatcherTable, MatcherIndex, N, *this)) break; continue; case OPC_CheckFoldableChainNode: { assert(NodeStack.size() != 1 && "No parent node"); // Verify that all intermediate nodes between the root and this one have // a single use. bool HasMultipleUses = false; for (unsigned i = 1, e = NodeStack.size()-1; i != e; ++i) if (!NodeStack[i].hasOneUse()) { HasMultipleUses = true; break; } if (HasMultipleUses) break; // Check to see that the target thinks this is profitable to fold and that // we can fold it without inducing cycles in the graph. if (!IsProfitableToFold(N, NodeStack[NodeStack.size()-2].getNode(), NodeToMatch) || !IsLegalToFold(N, NodeStack[NodeStack.size()-2].getNode(), NodeToMatch, OptLevel, true/*We validate our own chains*/)) break; continue; } case OPC_EmitInteger: { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); RecordedNodes.push_back(std::pair( CurDAG->getTargetConstant(Val, SDLoc(NodeToMatch), VT), nullptr)); continue; } case OPC_EmitRegister: { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; unsigned RegNo = MatcherTable[MatcherIndex++]; RecordedNodes.push_back(std::pair( CurDAG->getRegister(RegNo, VT), nullptr)); continue; } case OPC_EmitRegister2: { // For targets w/ more than 256 register names, the register enum // values are stored in two bytes in the matcher table (just like // opcodes). MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; unsigned RegNo = MatcherTable[MatcherIndex++]; RegNo |= MatcherTable[MatcherIndex++] << 8; RecordedNodes.push_back(std::pair( CurDAG->getRegister(RegNo, VT), nullptr)); continue; } case OPC_EmitConvertToTarget: { // Convert from IMM/FPIMM to target version. unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid EmitConvertToTarget"); SDValue Imm = RecordedNodes[RecNo].first; if (Imm->getOpcode() == ISD::Constant) { const ConstantInt *Val=cast(Imm)->getConstantIntValue(); Imm = CurDAG->getTargetConstant(*Val, SDLoc(NodeToMatch), Imm.getValueType()); } else if (Imm->getOpcode() == ISD::ConstantFP) { const ConstantFP *Val=cast(Imm)->getConstantFPValue(); Imm = CurDAG->getTargetConstantFP(*Val, SDLoc(NodeToMatch), Imm.getValueType()); } RecordedNodes.push_back(std::make_pair(Imm, RecordedNodes[RecNo].second)); continue; } case OPC_EmitMergeInputChains1_0: // OPC_EmitMergeInputChains, 1, 0 case OPC_EmitMergeInputChains1_1: // OPC_EmitMergeInputChains, 1, 1 case OPC_EmitMergeInputChains1_2: { // OPC_EmitMergeInputChains, 1, 2 // These are space-optimized forms of OPC_EmitMergeInputChains. assert(!InputChain.getNode() && "EmitMergeInputChains should be the first chain producing node"); assert(ChainNodesMatched.empty() && "Should only have one EmitMergeInputChains per match"); // Read all of the chained nodes. unsigned RecNo = Opcode - OPC_EmitMergeInputChains1_0; assert(RecNo < RecordedNodes.size() && "Invalid EmitMergeInputChains"); ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode()); // FIXME: What if other value results of the node have uses not matched // by this pattern? if (ChainNodesMatched.back() != NodeToMatch && !RecordedNodes[RecNo].first.hasOneUse()) { ChainNodesMatched.clear(); break; } // Merge the input chains if they are not intra-pattern references. InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG); if (!InputChain.getNode()) break; // Failed to merge. continue; } case OPC_EmitMergeInputChains: { assert(!InputChain.getNode() && "EmitMergeInputChains should be the first chain producing node"); // This node gets a list of nodes we matched in the input that have // chains. We want to token factor all of the input chains to these nodes // together. However, if any of the input chains is actually one of the // nodes matched in this pattern, then we have an intra-match reference. // Ignore these because the newly token factored chain should not refer to // the old nodes. unsigned NumChains = MatcherTable[MatcherIndex++]; assert(NumChains != 0 && "Can't TF zero chains"); assert(ChainNodesMatched.empty() && "Should only have one EmitMergeInputChains per match"); // Read all of the chained nodes. for (unsigned i = 0; i != NumChains; ++i) { unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid EmitMergeInputChains"); ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode()); // FIXME: What if other value results of the node have uses not matched // by this pattern? if (ChainNodesMatched.back() != NodeToMatch && !RecordedNodes[RecNo].first.hasOneUse()) { ChainNodesMatched.clear(); break; } } // If the inner loop broke out, the match fails. if (ChainNodesMatched.empty()) break; // Merge the input chains if they are not intra-pattern references. InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG); if (!InputChain.getNode()) break; // Failed to merge. continue; } case OPC_EmitCopyToReg: { unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid EmitCopyToReg"); unsigned DestPhysReg = MatcherTable[MatcherIndex++]; if (!InputChain.getNode()) InputChain = CurDAG->getEntryNode(); InputChain = CurDAG->getCopyToReg(InputChain, SDLoc(NodeToMatch), DestPhysReg, RecordedNodes[RecNo].first, InputGlue); InputGlue = InputChain.getValue(1); continue; } case OPC_EmitNodeXForm: { unsigned XFormNo = MatcherTable[MatcherIndex++]; unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid EmitNodeXForm"); SDValue Res = RunSDNodeXForm(RecordedNodes[RecNo].first, XFormNo); RecordedNodes.push_back(std::pair(Res, nullptr)); continue; } case OPC_EmitNode: case OPC_MorphNodeTo: case OPC_EmitNode0: case OPC_EmitNode1: case OPC_EmitNode2: case OPC_MorphNodeTo0: case OPC_MorphNodeTo1: case OPC_MorphNodeTo2: { uint16_t TargetOpc = MatcherTable[MatcherIndex++]; TargetOpc |= (unsigned short)MatcherTable[MatcherIndex++] << 8; unsigned EmitNodeInfo = MatcherTable[MatcherIndex++]; // Get the result VT list. unsigned NumVTs; // If this is one of the compressed forms, get the number of VTs based // on the Opcode. Otherwise read the next byte from the table. if (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2) NumVTs = Opcode - OPC_MorphNodeTo0; else if (Opcode >= OPC_EmitNode0 && Opcode <= OPC_EmitNode2) NumVTs = Opcode - OPC_EmitNode0; else NumVTs = MatcherTable[MatcherIndex++]; SmallVector VTs; for (unsigned i = 0; i != NumVTs; ++i) { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (VT == MVT::iPTR) VT = TLI->getPointerTy(CurDAG->getDataLayout()).SimpleTy; VTs.push_back(VT); } if (EmitNodeInfo & OPFL_Chain) VTs.push_back(MVT::Other); if (EmitNodeInfo & OPFL_GlueOutput) VTs.push_back(MVT::Glue); // This is hot code, so optimize the two most common cases of 1 and 2 // results. SDVTList VTList; if (VTs.size() == 1) VTList = CurDAG->getVTList(VTs[0]); else if (VTs.size() == 2) VTList = CurDAG->getVTList(VTs[0], VTs[1]); else VTList = CurDAG->getVTList(VTs); // Get the operand list. unsigned NumOps = MatcherTable[MatcherIndex++]; SmallVector Ops; for (unsigned i = 0; i != NumOps; ++i) { unsigned RecNo = MatcherTable[MatcherIndex++]; if (RecNo & 128) RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex); assert(RecNo < RecordedNodes.size() && "Invalid EmitNode"); Ops.push_back(RecordedNodes[RecNo].first); } // If there are variadic operands to add, handle them now. if (EmitNodeInfo & OPFL_VariadicInfo) { // Determine the start index to copy from. unsigned FirstOpToCopy = getNumFixedFromVariadicInfo(EmitNodeInfo); FirstOpToCopy += (EmitNodeInfo & OPFL_Chain) ? 1 : 0; assert(NodeToMatch->getNumOperands() >= FirstOpToCopy && "Invalid variadic node"); // Copy all of the variadic operands, not including a potential glue // input. for (unsigned i = FirstOpToCopy, e = NodeToMatch->getNumOperands(); i != e; ++i) { SDValue V = NodeToMatch->getOperand(i); if (V.getValueType() == MVT::Glue) break; Ops.push_back(V); } } // If this has chain/glue inputs, add them. if (EmitNodeInfo & OPFL_Chain) Ops.push_back(InputChain); if ((EmitNodeInfo & OPFL_GlueInput) && InputGlue.getNode() != nullptr) Ops.push_back(InputGlue); // Create the node. SDNode *Res = nullptr; bool IsMorphNodeTo = Opcode == OPC_MorphNodeTo || (Opcode >= OPC_MorphNodeTo0 && Opcode <= OPC_MorphNodeTo2); if (!IsMorphNodeTo) { // If this is a normal EmitNode command, just create the new node and // add the results to the RecordedNodes list. Res = CurDAG->getMachineNode(TargetOpc, SDLoc(NodeToMatch), VTList, Ops); // Add all the non-glue/non-chain results to the RecordedNodes list. for (unsigned i = 0, e = VTs.size(); i != e; ++i) { if (VTs[i] == MVT::Other || VTs[i] == MVT::Glue) break; RecordedNodes.push_back(std::pair(SDValue(Res, i), nullptr)); } } else { assert(NodeToMatch->getOpcode() != ISD::DELETED_NODE && "NodeToMatch was removed partway through selection"); SelectionDAG::DAGNodeDeletedListener NDL(*CurDAG, [&](SDNode *N, SDNode *E) { auto &Chain = ChainNodesMatched; assert((!E || !is_contained(Chain, N)) && "Chain node replaced during MorphNode"); Chain.erase(std::remove(Chain.begin(), Chain.end(), N), Chain.end()); }); Res = MorphNode(NodeToMatch, TargetOpc, VTList, Ops, EmitNodeInfo); } // If the node had chain/glue results, update our notion of the current // chain and glue. if (EmitNodeInfo & OPFL_GlueOutput) { InputGlue = SDValue(Res, VTs.size()-1); if (EmitNodeInfo & OPFL_Chain) InputChain = SDValue(Res, VTs.size()-2); } else if (EmitNodeInfo & OPFL_Chain) InputChain = SDValue(Res, VTs.size()-1); // If the OPFL_MemRefs glue is set on this node, slap all of the // accumulated memrefs onto it. // // FIXME: This is vastly incorrect for patterns with multiple outputs // instructions that access memory and for ComplexPatterns that match // loads. if (EmitNodeInfo & OPFL_MemRefs) { // Only attach load or store memory operands if the generated // instruction may load or store. const MCInstrDesc &MCID = TII->get(TargetOpc); bool mayLoad = MCID.mayLoad(); bool mayStore = MCID.mayStore(); unsigned NumMemRefs = 0; for (SmallVectorImpl::const_iterator I = MatchedMemRefs.begin(), E = MatchedMemRefs.end(); I != E; ++I) { if ((*I)->isLoad()) { if (mayLoad) ++NumMemRefs; } else if ((*I)->isStore()) { if (mayStore) ++NumMemRefs; } else { ++NumMemRefs; } } MachineSDNode::mmo_iterator MemRefs = MF->allocateMemRefsArray(NumMemRefs); MachineSDNode::mmo_iterator MemRefsPos = MemRefs; for (SmallVectorImpl::const_iterator I = MatchedMemRefs.begin(), E = MatchedMemRefs.end(); I != E; ++I) { if ((*I)->isLoad()) { if (mayLoad) *MemRefsPos++ = *I; } else if ((*I)->isStore()) { if (mayStore) *MemRefsPos++ = *I; } else { *MemRefsPos++ = *I; } } cast(Res) ->setMemRefs(MemRefs, MemRefs + NumMemRefs); } DEBUG(dbgs() << " " << (IsMorphNodeTo ? "Morphed" : "Created") << " node: "; Res->dump(CurDAG); dbgs() << "\n"); // If this was a MorphNodeTo then we're completely done! if (IsMorphNodeTo) { // Update chain uses. UpdateChains(Res, InputChain, ChainNodesMatched, true); return; } continue; } case OPC_CompleteMatch: { // The match has been completed, and any new nodes (if any) have been // created. Patch up references to the matched dag to use the newly // created nodes. unsigned NumResults = MatcherTable[MatcherIndex++]; for (unsigned i = 0; i != NumResults; ++i) { unsigned ResSlot = MatcherTable[MatcherIndex++]; if (ResSlot & 128) ResSlot = GetVBR(ResSlot, MatcherTable, MatcherIndex); assert(ResSlot < RecordedNodes.size() && "Invalid CompleteMatch"); SDValue Res = RecordedNodes[ResSlot].first; assert(i < NodeToMatch->getNumValues() && NodeToMatch->getValueType(i) != MVT::Other && NodeToMatch->getValueType(i) != MVT::Glue && "Invalid number of results to complete!"); assert((NodeToMatch->getValueType(i) == Res.getValueType() || NodeToMatch->getValueType(i) == MVT::iPTR || Res.getValueType() == MVT::iPTR || NodeToMatch->getValueType(i).getSizeInBits() == Res.getValueSizeInBits()) && "invalid replacement"); CurDAG->ReplaceAllUsesOfValueWith(SDValue(NodeToMatch, i), Res); } // Update chain uses. UpdateChains(NodeToMatch, InputChain, ChainNodesMatched, false); // If the root node defines glue, we need to update it to the glue result. // TODO: This never happens in our tests and I think it can be removed / // replaced with an assert, but if we do it this the way the change is // NFC. if (NodeToMatch->getValueType(NodeToMatch->getNumValues() - 1) == MVT::Glue && InputGlue.getNode()) CurDAG->ReplaceAllUsesOfValueWith( SDValue(NodeToMatch, NodeToMatch->getNumValues() - 1), InputGlue); assert(NodeToMatch->use_empty() && "Didn't replace all uses of the node?"); CurDAG->RemoveDeadNode(NodeToMatch); return; } } // If the code reached this point, then the match failed. See if there is // another child to try in the current 'Scope', otherwise pop it until we // find a case to check. DEBUG(dbgs() << " Match failed at index " << CurrentOpcodeIndex << "\n"); ++NumDAGIselRetries; while (1) { if (MatchScopes.empty()) { CannotYetSelect(NodeToMatch); return; } // Restore the interpreter state back to the point where the scope was // formed. MatchScope &LastScope = MatchScopes.back(); RecordedNodes.resize(LastScope.NumRecordedNodes); NodeStack.clear(); NodeStack.append(LastScope.NodeStack.begin(), LastScope.NodeStack.end()); N = NodeStack.back(); if (LastScope.NumMatchedMemRefs != MatchedMemRefs.size()) MatchedMemRefs.resize(LastScope.NumMatchedMemRefs); MatcherIndex = LastScope.FailIndex; DEBUG(dbgs() << " Continuing at " << MatcherIndex << "\n"); InputChain = LastScope.InputChain; InputGlue = LastScope.InputGlue; if (!LastScope.HasChainNodesMatched) ChainNodesMatched.clear(); // Check to see what the offset is at the new MatcherIndex. If it is zero // we have reached the end of this scope, otherwise we have another child // in the current scope to try. unsigned NumToSkip = MatcherTable[MatcherIndex++]; if (NumToSkip & 128) NumToSkip = GetVBR(NumToSkip, MatcherTable, MatcherIndex); // If we have another child in this scope to match, update FailIndex and // try it. if (NumToSkip != 0) { LastScope.FailIndex = MatcherIndex+NumToSkip; break; } // End of this scope, pop it and try the next child in the containing // scope. MatchScopes.pop_back(); } } } void SelectionDAGISel::CannotYetSelect(SDNode *N) { std::string msg; raw_string_ostream Msg(msg); Msg << "Cannot select: "; if (N->getOpcode() != ISD::INTRINSIC_W_CHAIN && N->getOpcode() != ISD::INTRINSIC_WO_CHAIN && N->getOpcode() != ISD::INTRINSIC_VOID) { N->printrFull(Msg, CurDAG); Msg << "\nIn function: " << MF->getName(); } else { bool HasInputChain = N->getOperand(0).getValueType() == MVT::Other; unsigned iid = cast(N->getOperand(HasInputChain))->getZExtValue(); if (iid < Intrinsic::num_intrinsics) Msg << "intrinsic %" << Intrinsic::getName((Intrinsic::ID)iid, None); else if (const TargetIntrinsicInfo *TII = TM.getIntrinsicInfo()) Msg << "target intrinsic %" << TII->getName(iid); else Msg << "unknown intrinsic #" << iid; } report_fatal_error(Msg.str()); } char SelectionDAGISel::ID = 0; Index: vendor/llvm/dist/lib/MC/MCMachOStreamer.cpp =================================================================== --- vendor/llvm/dist/lib/MC/MCMachOStreamer.cpp (revision 313055) +++ vendor/llvm/dist/lib/MC/MCMachOStreamer.cpp (revision 313056) @@ -1,526 +1,527 @@ //===-- MCMachOStreamer.cpp - MachO Streamer ------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCLinkerOptimizationHint.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbolMachO.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { class MCMachOStreamer : public MCObjectStreamer { private: /// LabelSections - true if each section change should emit a linker local /// label for use in relocations for assembler local references. Obviates the /// need for local relocations. False by default. bool LabelSections; bool DWARFMustBeAtTheEnd; bool CreatedADWARFSection; /// HasSectionLabel - map of which sections have already had a non-local /// label emitted to them. Used so we don't emit extraneous linker local /// labels in the middle of the section. DenseMap HasSectionLabel; void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override; void EmitDataRegion(DataRegionData::KindTy Kind); void EmitDataRegionEnd(); public: MCMachOStreamer(MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter, bool DWARFMustBeAtTheEnd, bool label) : MCObjectStreamer(Context, MAB, OS, Emitter), LabelSections(label), DWARFMustBeAtTheEnd(DWARFMustBeAtTheEnd), CreatedADWARFSection(false) {} /// state management void reset() override { CreatedADWARFSection = false; HasSectionLabel.clear(); MCObjectStreamer::reset(); } /// @name MCStreamer Interface /// @{ void ChangeSection(MCSection *Sect, const MCExpr *Subsect) override; void EmitLabel(MCSymbol *Symbol) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) override; void EmitAssemblerFlag(MCAssemblerFlag Flag) override; void EmitLinkerOptions(ArrayRef Options) override; void EmitDataRegion(MCDataRegionType Kind) override; void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, unsigned Update) override; void EmitThumbFunc(MCSymbol *Func) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void BeginCOFFSymbolDef(const MCSymbol *Symbol) override { llvm_unreachable("macho doesn't support this directive"); } void EmitCOFFSymbolStorageClass(int StorageClass) override { llvm_unreachable("macho doesn't support this directive"); } void EmitCOFFSymbolType(int Type) override { llvm_unreachable("macho doesn't support this directive"); } void EndCOFFSymbolDef() override { llvm_unreachable("macho doesn't support this directive"); } void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, uint64_t Size = 0, unsigned ByteAlignment = 0) override; void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0) override; void EmitFileDirective(StringRef Filename) override { // FIXME: Just ignore the .file; it isn't important enough to fail the // entire assembly. // report_fatal_error("unsupported directive: '.file'"); } void EmitIdent(StringRef IdentString) override { llvm_unreachable("macho doesn't support this directive"); } void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override { getAssembler().getLOHContainer().addDirective(Kind, Args); } void FinishImpl() override; }; } // end anonymous namespace. static bool canGoAfterDWARF(const MCSectionMachO &MSec) { // These sections are created by the assembler itself after the end of // the .s file. StringRef SegName = MSec.getSegmentName(); StringRef SecName = MSec.getSectionName(); if (SegName == "__LD" && SecName == "__compact_unwind") return true; if (SegName == "__IMPORT") { if (SecName == "__jump_table") return true; if (SecName == "__pointers") return true; } if (SegName == "__TEXT" && SecName == "__eh_frame") return true; - if (SegName == "__DATA" && SecName == "__nl_symbol_ptr") + if (SegName == "__DATA" && (SecName == "__nl_symbol_ptr" || + SecName == "__thread_ptr")) return true; return false; } void MCMachOStreamer::ChangeSection(MCSection *Section, const MCExpr *Subsection) { // Change the section normally. bool Created = MCObjectStreamer::changeSectionImpl(Section, Subsection); const MCSectionMachO &MSec = *cast(Section); StringRef SegName = MSec.getSegmentName(); if (SegName == "__DWARF") CreatedADWARFSection = true; else if (Created && DWARFMustBeAtTheEnd && !canGoAfterDWARF(MSec)) assert(!CreatedADWARFSection && "Creating regular section after DWARF"); // Output a linker-local symbol so we don't need section-relative local // relocations. The linker hates us when we do that. if (LabelSections && !HasSectionLabel[Section] && !Section->getBeginSymbol()) { MCSymbol *Label = getContext().createLinkerPrivateTempSymbol(); Section->setBeginSymbol(Label); HasSectionLabel[Section] = true; } } void MCMachOStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) { getAssembler().registerSymbol(*Symbol); if (Symbol->isExternal()) EmitSymbolAttribute(EHSymbol, MCSA_Global); if (cast(Symbol)->isWeakDefinition()) EmitSymbolAttribute(EHSymbol, MCSA_WeakDefinition); if (Symbol->isPrivateExtern()) EmitSymbolAttribute(EHSymbol, MCSA_PrivateExtern); } void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); // We have to create a new fragment if this is an atom defining symbol, // fragments cannot span atoms. if (getAssembler().isSymbolLinkerVisible(*Symbol)) insert(new MCDataFragment()); MCObjectStreamer::EmitLabel(Symbol); // This causes the reference type flag to be cleared. Darwin 'as' was "trying" // to clear the weak reference and weak definition bits too, but the // implementation was buggy. For now we just try to match 'as', for // diffability. // // FIXME: Cleanup this code, these bits should be emitted based on semantic // properties, not on the order of definition, etc. cast(Symbol)->clearReferenceType(); } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { MCValue Res; if (Value->evaluateAsRelocatable(Res, nullptr, nullptr)) { if (const MCSymbolRefExpr *SymAExpr = Res.getSymA()) { const MCSymbol &SymA = SymAExpr->getSymbol(); if (!Res.getSymB() && (SymA.getName() == "" || Res.getConstant() != 0)) cast(Symbol)->setAltEntry(); } } MCObjectStreamer::EmitAssignment(Symbol, Value); } void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) { // Create a temporary label to mark the start of the data region. MCSymbol *Start = getContext().createTempSymbol(); EmitLabel(Start); // Record the region for the object writer to use. DataRegionData Data = { Kind, Start, nullptr }; std::vector &Regions = getAssembler().getDataRegions(); Regions.push_back(Data); } void MCMachOStreamer::EmitDataRegionEnd() { std::vector &Regions = getAssembler().getDataRegions(); assert(!Regions.empty() && "Mismatched .end_data_region!"); DataRegionData &Data = Regions.back(); assert(!Data.End && "Mismatched .end_data_region!"); // Create a temporary label to mark the end of the data region. Data.End = getContext().createTempSymbol(); EmitLabel(Data.End); } void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { // Let the target do whatever target specific stuff it needs to do. getAssembler().getBackend().handleAssemblerFlag(Flag); // Do any generic stuff we need to do. switch (Flag) { case MCAF_SyntaxUnified: return; // no-op here. case MCAF_Code16: return; // Change parsing mode; no-op here. case MCAF_Code32: return; // Change parsing mode; no-op here. case MCAF_Code64: return; // Change parsing mode; no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; } } void MCMachOStreamer::EmitLinkerOptions(ArrayRef Options) { getAssembler().getLinkerOptions().push_back(Options); } void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) { switch (Kind) { case MCDR_DataRegion: EmitDataRegion(DataRegionData::Data); return; case MCDR_DataRegionJT8: EmitDataRegion(DataRegionData::JumpTable8); return; case MCDR_DataRegionJT16: EmitDataRegion(DataRegionData::JumpTable16); return; case MCDR_DataRegionJT32: EmitDataRegion(DataRegionData::JumpTable32); return; case MCDR_DataRegionEnd: EmitDataRegionEnd(); return; } } void MCMachOStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor, unsigned Update) { getAssembler().setVersionMinInfo(Kind, Major, Minor, Update); } void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { // Remember that the function is a thumb function. Fixup and relocation // values will need adjusted. getAssembler().setIsThumbFunc(Symbol); cast(Symbol)->setThumbFunc(); } bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym, MCSymbolAttr Attribute) { MCSymbolMachO *Symbol = cast(Sym); // Indirect symbols are handled differently, to match how 'as' handles // them. This makes writing matching .o files easier. if (Attribute == MCSA_IndirectSymbol) { // Note that we intentionally cannot use the symbol data here; this is // important for matching the string table that 'as' generates. IndirectSymbolData ISD; ISD.Symbol = Symbol; ISD.Section = getCurrentSectionOnly(); getAssembler().getIndirectSymbols().push_back(ISD); return true; } // Adding a symbol attribute always introduces the symbol, note that an // important side effect of calling registerSymbol here is to register // the symbol with the assembler. getAssembler().registerSymbol(*Symbol); // The implementation of symbol attributes is designed to match 'as', but it // leaves much to desired. It doesn't really make sense to arbitrarily add and // remove flags, but 'as' allows this (in particular, see .desc). // // In the future it might be worth trying to make these operations more well // defined. switch (Attribute) { case MCSA_Invalid: case MCSA_ELF_TypeFunction: case MCSA_ELF_TypeIndFunction: case MCSA_ELF_TypeObject: case MCSA_ELF_TypeTLS: case MCSA_ELF_TypeCommon: case MCSA_ELF_TypeNoType: case MCSA_ELF_TypeGnuUniqueObject: case MCSA_Hidden: case MCSA_IndirectSymbol: case MCSA_Internal: case MCSA_Protected: case MCSA_Weak: case MCSA_Local: return false; case MCSA_Global: Symbol->setExternal(true); // This effectively clears the undefined lazy bit, in Darwin 'as', although // it isn't very consistent because it implements this as part of symbol // lookup. // // FIXME: Cleanup this code, these bits should be emitted based on semantic // properties, not on the order of definition, etc. Symbol->setReferenceTypeUndefinedLazy(false); break; case MCSA_LazyReference: // FIXME: This requires -dynamic. Symbol->setNoDeadStrip(); if (Symbol->isUndefined()) Symbol->setReferenceTypeUndefinedLazy(true); break; // Since .reference sets the no dead strip bit, it is equivalent to // .no_dead_strip in practice. case MCSA_Reference: case MCSA_NoDeadStrip: Symbol->setNoDeadStrip(); break; case MCSA_SymbolResolver: Symbol->setSymbolResolver(); break; case MCSA_AltEntry: Symbol->setAltEntry(); break; case MCSA_PrivateExtern: Symbol->setExternal(true); Symbol->setPrivateExtern(true); break; case MCSA_WeakReference: // FIXME: This requires -dynamic. if (Symbol->isUndefined()) Symbol->setWeakReference(); break; case MCSA_WeakDefinition: // FIXME: 'as' enforces that this is defined and global. The manual claims // it has to be in a coalesced section, but this isn't enforced. Symbol->setWeakDefinition(); break; case MCSA_WeakDefAutoPrivate: Symbol->setWeakDefinition(); Symbol->setWeakReference(); break; } return true; } void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { // Encode the 'desc' value into the lowest implementation defined bits. getAssembler().registerSymbol(*Symbol); cast(Symbol)->setDesc(DescValue); } void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); getAssembler().registerSymbol(*Symbol); Symbol->setExternal(true); Symbol->setCommon(Size, ByteAlignment); } void MCMachOStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { // '.lcomm' is equivalent to '.zerofill'. return EmitZerofill(getContext().getObjectFileInfo()->getDataBSSSection(), Symbol, Size, ByteAlignment); } void MCMachOStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { getAssembler().registerSection(*Section); // The symbol may not be present, which only creates the section. if (!Symbol) return; // On darwin all virtual sections have zerofill type. assert(Section->isVirtualSection() && "Section does not have zerofill type!"); assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); getAssembler().registerSymbol(*Symbol); // Emit an align fragment if necessary. if (ByteAlignment != 1) new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, Section); MCFragment *F = new MCFillFragment(0, Size, Section); Symbol->setFragment(F); // Update the maximum alignment on the zero fill section if necessary. if (ByteAlignment > Section->getAlignment()) Section->setAlignment(ByteAlignment); } // This should always be called with the thread local bss section. Like the // .zerofill directive this doesn't actually switch sections on us. void MCMachOStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { EmitZerofill(Section, Symbol, Size, ByteAlignment); } void MCMachOStreamer::EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) { MCDataFragment *DF = getOrCreateDataFragment(); SmallVector Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); // Add the fixups and data. for (MCFixup &Fixup : Fixups) { Fixup.setOffset(Fixup.getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixup); } DF->getContents().append(Code.begin(), Code.end()); } void MCMachOStreamer::FinishImpl() { EmitFrames(&getAssembler().getBackend()); // We have to set the fragment atom associations so we can relax properly for // Mach-O. // First, scan the symbol table to build a lookup table from fragments to // defining symbols. DenseMap DefiningSymbolMap; for (const MCSymbol &Symbol : getAssembler().symbols()) { if (getAssembler().isSymbolLinkerVisible(Symbol) && Symbol.isInSection() && !Symbol.isVariable()) { // An atom defining symbol should never be internal to a fragment. assert(Symbol.getOffset() == 0 && "Invalid offset in atom defining symbol!"); DefiningSymbolMap[Symbol.getFragment()] = &Symbol; } } // Set the fragment atom associations by tracking the last seen atom defining // symbol. for (MCSection &Sec : getAssembler()) { const MCSymbol *CurrentAtom = nullptr; for (MCFragment &Frag : Sec) { if (const MCSymbol *Symbol = DefiningSymbolMap.lookup(&Frag)) CurrentAtom = Symbol; Frag.setAtom(CurrentAtom); } } this->MCObjectStreamer::FinishImpl(); } MCStreamer *llvm::createMachOStreamer(MCContext &Context, MCAsmBackend &MAB, raw_pwrite_stream &OS, MCCodeEmitter *CE, bool RelaxAll, bool DWARFMustBeAtTheEnd, bool LabelSections) { MCMachOStreamer *S = new MCMachOStreamer(Context, MAB, OS, CE, DWARFMustBeAtTheEnd, LabelSections); const Triple &TT = Context.getObjectFileInfo()->getTargetTriple(); if (TT.isOSDarwin()) { unsigned Major, Minor, Update; TT.getOSVersion(Major, Minor, Update); // If there is a version specified, Major will be non-zero. if (Major) { MCVersionMinType VersionType; if (TT.isWatchOS()) VersionType = MCVM_WatchOSVersionMin; else if (TT.isTvOS()) VersionType = MCVM_TvOSVersionMin; else if (TT.isMacOSX()) VersionType = MCVM_OSXVersionMin; else { assert(TT.isiOS() && "Must only be iOS platform left"); VersionType = MCVM_IOSVersionMin; } S->EmitVersionMin(VersionType, Major, Minor, Update); } } if (RelaxAll) S->getAssembler().setRelaxAll(true); return S; } Index: vendor/llvm/dist/lib/Target/Mips/AsmParser/MipsAsmParser.cpp =================================================================== --- vendor/llvm/dist/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/AsmParser/MipsAsmParser.cpp (revision 313056) @@ -1,6766 +1,6775 @@ //===-- MipsAsmParser.cpp - Parse Mips 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 "MCTargetDesc/MipsABIInfo.h" #include "MCTargetDesc/MipsMCExpr.h" #include "MCTargetDesc/MipsMCTargetDesc.h" #include "MipsRegisterInfo.h" #include "MipsTargetObjectFile.h" #include "MipsTargetStreamer.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; #define DEBUG_TYPE "mips-asm-parser" namespace llvm { class MCInstrInfo; } namespace { class MipsAssemblerOptions { public: MipsAssemblerOptions(const FeatureBitset &Features_) : ATReg(1), Reorder(true), Macro(true), Features(Features_) {} MipsAssemblerOptions(const MipsAssemblerOptions *Opts) { ATReg = Opts->getATRegIndex(); Reorder = Opts->isReorder(); Macro = Opts->isMacro(); Features = Opts->getFeatures(); } unsigned getATRegIndex() const { return ATReg; } bool setATRegIndex(unsigned Reg) { if (Reg > 31) return false; ATReg = Reg; return true; } bool isReorder() const { return Reorder; } void setReorder() { Reorder = true; } void setNoReorder() { Reorder = false; } bool isMacro() const { return Macro; } void setMacro() { Macro = true; } void setNoMacro() { Macro = false; } const FeatureBitset &getFeatures() const { return Features; } void setFeatures(const FeatureBitset &Features_) { Features = Features_; } // Set of features that are either architecture features or referenced // by them (e.g.: FeatureNaN2008 implied by FeatureMips32r6). // The full table can be found in MipsGenSubtargetInfo.inc (MipsFeatureKV[]). // The reason we need this mask is explained in the selectArch function. // FIXME: Ideally we would like TableGen to generate this information. static const FeatureBitset AllArchRelatedMask; private: unsigned ATReg; bool Reorder; bool Macro; FeatureBitset Features; }; } const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = { Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3, Mips::FeatureMips3_32, Mips::FeatureMips3_32r2, Mips::FeatureMips4, Mips::FeatureMips4_32, Mips::FeatureMips4_32r2, Mips::FeatureMips5, Mips::FeatureMips5_32r2, Mips::FeatureMips32, Mips::FeatureMips32r2, Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6, Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3, Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips, Mips::FeatureFP64Bit, Mips::FeatureGP64Bit, Mips::FeatureNaN2008 }; namespace { class MipsAsmParser : public MCTargetAsmParser { MipsTargetStreamer &getTargetStreamer() { MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer(); return static_cast(TS); } MipsABIInfo ABI; SmallVector, 2> AssemblerOptions; MCSymbol *CurrentFn; // Pointer to the function being parsed. It may be a // nullptr, which indicates that no function is currently // selected. This usually happens after an '.end func' // directive. bool IsLittleEndian; bool IsPicEnabled; bool IsCpRestoreSet; int CpRestoreOffset; unsigned CpSaveLocation; /// If true, then CpSaveLocation is a register, otherwise it's an offset. bool CpSaveLocationIsRegister; // Print a warning along with its fix-it message at the given range. void printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, SMRange Range, bool ShowColors = true); #define GET_ASSEMBLER_HEADER #include "MipsGenAsmMatcher.inc" unsigned checkEarlyTargetMatchPredicate(MCInst &Inst, const OperandVector &Operands) override; unsigned checkTargetMatchPredicate(MCInst &Inst) override; bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) override; /// Parse a register as used in CFI directives bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; bool parseParenSuffix(StringRef Name, OperandVector &Operands); bool parseBracketSuffix(StringRef Name, OperandVector &Operands); bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override; bool ParseDirective(AsmToken DirectiveID) override; OperandMatchResultTy parseMemOperand(OperandVector &Operands); OperandMatchResultTy matchAnyRegisterNameWithoutDollar(OperandVector &Operands, StringRef Identifier, SMLoc S); OperandMatchResultTy matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S); OperandMatchResultTy parseAnyRegister(OperandVector &Operands); OperandMatchResultTy parseImm(OperandVector &Operands); OperandMatchResultTy parseJumpTarget(OperandVector &Operands); OperandMatchResultTy parseInvNum(OperandVector &Operands); OperandMatchResultTy parseRegisterPair(OperandVector &Operands); OperandMatchResultTy parseMovePRegPair(OperandVector &Operands); OperandMatchResultTy parseRegisterList(OperandVector &Operands); bool searchSymbolAlias(OperandVector &Operands); bool parseOperand(OperandVector &, StringRef Mnemonic); enum MacroExpanderResultTy { MER_NotAMacro, MER_Success, MER_Fail, }; // Expands assembly pseudo instructions. MacroExpanderResultTy tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, bool Is32BitImm, bool IsAddress, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool loadAndAddSymbolAddress(const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, bool Is32BitSym, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandLoadAddress(unsigned DstReg, unsigned BaseReg, const MCOperand &Offset, bool Is32BitAddress, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); void expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsLoad, bool IsImmOpnd); void expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsImmOpnd); void expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsImmOpnd); bool expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandCondBranches(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, const bool IsMips64, const bool Signed); bool expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandDRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandDRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsLoad); bool expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); bool reportParseError(Twine ErrorMsg); bool reportParseError(SMLoc Loc, Twine ErrorMsg); bool parseMemOffset(const MCExpr *&Res, bool isParenExpr); bool isEvaluated(const MCExpr *Expr); bool parseSetMips0Directive(); bool parseSetArchDirective(); bool parseSetFeature(uint64_t Feature); bool isPicAndNotNxxAbi(); // Used by .cpload, .cprestore, and .cpsetup. bool parseDirectiveCpLoad(SMLoc Loc); bool parseDirectiveCpRestore(SMLoc Loc); bool parseDirectiveCPSetup(); bool parseDirectiveCPReturn(); bool parseDirectiveNaN(); bool parseDirectiveSet(); bool parseDirectiveOption(); bool parseInsnDirective(); bool parseSSectionDirective(StringRef Section, unsigned Type); bool parseSetAtDirective(); bool parseSetNoAtDirective(); bool parseSetMacroDirective(); bool parseSetNoMacroDirective(); bool parseSetMsaDirective(); bool parseSetNoMsaDirective(); bool parseSetNoDspDirective(); bool parseSetReorderDirective(); bool parseSetNoReorderDirective(); bool parseSetMips16Directive(); bool parseSetNoMips16Directive(); bool parseSetFpDirective(); bool parseSetOddSPRegDirective(); bool parseSetNoOddSPRegDirective(); bool parseSetPopDirective(); bool parseSetPushDirective(); bool parseSetSoftFloatDirective(); bool parseSetHardFloatDirective(); bool parseSetAssignment(); bool parseDataDirective(unsigned Size, SMLoc L); bool parseDirectiveGpWord(); bool parseDirectiveGpDWord(); bool parseDirectiveDtpRelWord(); bool parseDirectiveDtpRelDWord(); bool parseDirectiveTpRelWord(); bool parseDirectiveTpRelDWord(); bool parseDirectiveModule(); bool parseDirectiveModuleFP(); bool parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, StringRef Directive); bool parseInternalDirectiveReallowModule(); bool eatComma(StringRef ErrorStr); int matchCPURegisterName(StringRef Symbol); int matchHWRegsRegisterName(StringRef Symbol); int matchFPURegisterName(StringRef Name); int matchFCCRegisterName(StringRef Name); int matchACRegisterName(StringRef Name); int matchMSA128RegisterName(StringRef Name); int matchMSA128CtrlRegisterName(StringRef Name); unsigned getReg(int RC, int RegNo); /// Returns the internal register number for the current AT. Also checks if /// the current AT is unavailable (set to $0) and gives an error if it is. /// This should be used in pseudo-instruction expansions which need AT. unsigned getATReg(SMLoc Loc); bool processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI); // Helper function that checks if the value of a vector index is within the // boundaries of accepted values for each RegisterKind // Example: INSERT.B $w0[n], $1 => 16 > n >= 0 bool validateMSAIndex(int Val, int RegKind); // Selects a new architecture by updating the FeatureBits with the necessary // info including implied dependencies. // Internally, it clears all the feature bits related to *any* architecture // and selects the new one using the ToggleFeature functionality of the // MCSubtargetInfo object that handles implied dependencies. The reason we // clear all the arch related bits manually is because ToggleFeature only // clears the features that imply the feature being cleared and not the // features implied by the feature being cleared. This is easier to see // with an example: // -------------------------------------------------- // | Feature | Implies | // | -------------------------------------------------| // | FeatureMips1 | None | // | FeatureMips2 | FeatureMips1 | // | FeatureMips3 | FeatureMips2 | FeatureMipsGP64 | // | FeatureMips4 | FeatureMips3 | // | ... | | // -------------------------------------------------- // // Setting Mips3 is equivalent to set: (FeatureMips3 | FeatureMips2 | // FeatureMipsGP64 | FeatureMips1) // Clearing Mips3 is equivalent to clear (FeatureMips3 | FeatureMips4). void selectArch(StringRef ArchFeature) { MCSubtargetInfo &STI = copySTI(); FeatureBitset FeatureBits = STI.getFeatureBits(); FeatureBits &= ~MipsAssemblerOptions::AllArchRelatedMask; STI.setFeatureBits(FeatureBits); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(ArchFeature))); AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } void setFeatureBits(uint64_t Feature, StringRef FeatureString) { if (!(getSTI().getFeatureBits()[Feature])) { MCSubtargetInfo &STI = copySTI(); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } } void clearFeatureBits(uint64_t Feature, StringRef FeatureString) { if (getSTI().getFeatureBits()[Feature]) { MCSubtargetInfo &STI = copySTI(); setAvailableFeatures( ComputeAvailableFeatures(STI.ToggleFeature(FeatureString))); AssemblerOptions.back()->setFeatures(STI.getFeatureBits()); } } void setModuleFeatureBits(uint64_t Feature, StringRef FeatureString) { setFeatureBits(Feature, FeatureString); AssemblerOptions.front()->setFeatures(getSTI().getFeatureBits()); } void clearModuleFeatureBits(uint64_t Feature, StringRef FeatureString) { clearFeatureBits(Feature, FeatureString); AssemblerOptions.front()->setFeatures(getSTI().getFeatureBits()); } public: enum MipsMatchResultTy { Match_RequiresDifferentSrcAndDst = FIRST_TARGET_MATCH_RESULT_TY, Match_RequiresDifferentOperands, Match_RequiresNoZeroRegister, Match_RequiresSameSrcAndDst, + Match_NoFCCRegisterForCurrentISA, Match_NonZeroOperandForSync, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "MipsGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES }; MipsAsmParser(const MCSubtargetInfo &sti, MCAsmParser &parser, const MCInstrInfo &MII, const MCTargetOptions &Options) : MCTargetAsmParser(Options, sti), ABI(MipsABIInfo::computeTargetABI(Triple(sti.getTargetTriple()), sti.getCPU(), Options)) { MCAsmParserExtension::Initialize(parser); parser.addAliasForDirective(".asciiz", ".asciz"); // Initialize the set of available features. setAvailableFeatures(ComputeAvailableFeatures(getSTI().getFeatureBits())); // Remember the initial assembler options. The user can not modify these. AssemblerOptions.push_back( llvm::make_unique(getSTI().getFeatureBits())); // Create an assembler options environment for the user to modify. AssemblerOptions.push_back( llvm::make_unique(getSTI().getFeatureBits())); getTargetStreamer().updateABIInfo(*this); if (!isABI_O32() && !useOddSPReg() != 0) report_fatal_error("-mno-odd-spreg requires the O32 ABI"); CurrentFn = nullptr; IsPicEnabled = getContext().getObjectFileInfo()->isPositionIndependent(); IsCpRestoreSet = false; CpRestoreOffset = -1; const Triple &TheTriple = sti.getTargetTriple(); if ((TheTriple.getArch() == Triple::mips) || (TheTriple.getArch() == Triple::mips64)) IsLittleEndian = false; else IsLittleEndian = true; } /// True if all of $fcc0 - $fcc7 exist for the current ISA. bool hasEightFccRegisters() const { return hasMips4() || hasMips32(); } bool isGP64bit() const { return getSTI().getFeatureBits()[Mips::FeatureGP64Bit]; } bool isFP64bit() const { return getSTI().getFeatureBits()[Mips::FeatureFP64Bit]; } const MipsABIInfo &getABI() const { return ABI; } bool isABI_N32() const { return ABI.IsN32(); } bool isABI_N64() const { return ABI.IsN64(); } bool isABI_O32() const { return ABI.IsO32(); } bool isABI_FPXX() const { return getSTI().getFeatureBits()[Mips::FeatureFPXX]; } bool useOddSPReg() const { return !(getSTI().getFeatureBits()[Mips::FeatureNoOddSPReg]); } bool inMicroMipsMode() const { return getSTI().getFeatureBits()[Mips::FeatureMicroMips]; } bool hasMips1() const { return getSTI().getFeatureBits()[Mips::FeatureMips1]; } bool hasMips2() const { return getSTI().getFeatureBits()[Mips::FeatureMips2]; } bool hasMips3() const { return getSTI().getFeatureBits()[Mips::FeatureMips3]; } bool hasMips4() const { return getSTI().getFeatureBits()[Mips::FeatureMips4]; } bool hasMips5() const { return getSTI().getFeatureBits()[Mips::FeatureMips5]; } bool hasMips32() const { return getSTI().getFeatureBits()[Mips::FeatureMips32]; } bool hasMips64() const { return getSTI().getFeatureBits()[Mips::FeatureMips64]; } bool hasMips32r2() const { return getSTI().getFeatureBits()[Mips::FeatureMips32r2]; } bool hasMips64r2() const { return getSTI().getFeatureBits()[Mips::FeatureMips64r2]; } bool hasMips32r3() const { return (getSTI().getFeatureBits()[Mips::FeatureMips32r3]); } bool hasMips64r3() const { return (getSTI().getFeatureBits()[Mips::FeatureMips64r3]); } bool hasMips32r5() const { return (getSTI().getFeatureBits()[Mips::FeatureMips32r5]); } bool hasMips64r5() const { return (getSTI().getFeatureBits()[Mips::FeatureMips64r5]); } bool hasMips32r6() const { return getSTI().getFeatureBits()[Mips::FeatureMips32r6]; } bool hasMips64r6() const { return getSTI().getFeatureBits()[Mips::FeatureMips64r6]; } bool hasDSP() const { return getSTI().getFeatureBits()[Mips::FeatureDSP]; } bool hasDSPR2() const { return getSTI().getFeatureBits()[Mips::FeatureDSPR2]; } bool hasDSPR3() const { return getSTI().getFeatureBits()[Mips::FeatureDSPR3]; } bool hasMSA() const { return getSTI().getFeatureBits()[Mips::FeatureMSA]; } bool hasCnMips() const { return (getSTI().getFeatureBits()[Mips::FeatureCnMips]); } bool inPicMode() { return IsPicEnabled; } bool inMips16Mode() const { return getSTI().getFeatureBits()[Mips::FeatureMips16]; } bool useTraps() const { return getSTI().getFeatureBits()[Mips::FeatureUseTCCInDIV]; } bool useSoftFloat() const { return getSTI().getFeatureBits()[Mips::FeatureSoftFloat]; } /// Warn if RegIndex is the same as the current AT. void warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc); void warnIfNoMacro(SMLoc Loc); bool isLittle() const { return IsLittleEndian; } const MCExpr *createTargetUnaryExpr(const MCExpr *E, AsmToken::TokenKind OperatorToken, MCContext &Ctx) override { switch(OperatorToken) { default: llvm_unreachable("Unknown token"); return nullptr; case AsmToken::PercentCall16: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, E, Ctx); case AsmToken::PercentCall_Hi: return MipsMCExpr::create(MipsMCExpr::MEK_CALL_HI16, E, Ctx); case AsmToken::PercentCall_Lo: return MipsMCExpr::create(MipsMCExpr::MEK_CALL_LO16, E, Ctx); case AsmToken::PercentDtprel_Hi: return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_HI, E, Ctx); case AsmToken::PercentDtprel_Lo: return MipsMCExpr::create(MipsMCExpr::MEK_DTPREL_LO, E, Ctx); case AsmToken::PercentGot: return MipsMCExpr::create(MipsMCExpr::MEK_GOT, E, Ctx); case AsmToken::PercentGot_Disp: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, E, Ctx); case AsmToken::PercentGot_Hi: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_HI16, E, Ctx); case AsmToken::PercentGot_Lo: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_LO16, E, Ctx); case AsmToken::PercentGot_Ofst: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_OFST, E, Ctx); case AsmToken::PercentGot_Page: return MipsMCExpr::create(MipsMCExpr::MEK_GOT_PAGE, E, Ctx); case AsmToken::PercentGottprel: return MipsMCExpr::create(MipsMCExpr::MEK_GOTTPREL, E, Ctx); case AsmToken::PercentGp_Rel: return MipsMCExpr::create(MipsMCExpr::MEK_GPREL, E, Ctx); case AsmToken::PercentHi: return MipsMCExpr::create(MipsMCExpr::MEK_HI, E, Ctx); case AsmToken::PercentHigher: return MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, E, Ctx); case AsmToken::PercentHighest: return MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, E, Ctx); case AsmToken::PercentLo: return MipsMCExpr::create(MipsMCExpr::MEK_LO, E, Ctx); case AsmToken::PercentNeg: return MipsMCExpr::create(MipsMCExpr::MEK_NEG, E, Ctx); case AsmToken::PercentPcrel_Hi: return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_HI16, E, Ctx); case AsmToken::PercentPcrel_Lo: return MipsMCExpr::create(MipsMCExpr::MEK_PCREL_LO16, E, Ctx); case AsmToken::PercentTlsgd: return MipsMCExpr::create(MipsMCExpr::MEK_TLSGD, E, Ctx); case AsmToken::PercentTlsldm: return MipsMCExpr::create(MipsMCExpr::MEK_TLSLDM, E, Ctx); case AsmToken::PercentTprel_Hi: return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_HI, E, Ctx); case AsmToken::PercentTprel_Lo: return MipsMCExpr::create(MipsMCExpr::MEK_TPREL_LO, E, Ctx); } } }; } namespace { /// MipsOperand - Instances of this class represent a parsed Mips machine /// instruction. class MipsOperand : public MCParsedAsmOperand { public: /// Broad categories of register classes /// The exact class is finalized by the render method. enum RegKind { RegKind_GPR = 1, /// GPR32 and GPR64 (depending on isGP64bit()) RegKind_FGR = 2, /// FGR32, FGR64, AFGR64 (depending on context and /// isFP64bit()) RegKind_FCC = 4, /// FCC RegKind_MSA128 = 8, /// MSA128[BHWD] (makes no difference which) RegKind_MSACtrl = 16, /// MSA control registers RegKind_COP2 = 32, /// COP2 RegKind_ACC = 64, /// HI32DSP, LO32DSP, and ACC64DSP (depending on /// context). RegKind_CCR = 128, /// CCR RegKind_HWRegs = 256, /// HWRegs RegKind_COP3 = 512, /// COP3 RegKind_COP0 = 1024, /// COP0 /// Potentially any (e.g. $1) RegKind_Numeric = RegKind_GPR | RegKind_FGR | RegKind_FCC | RegKind_MSA128 | RegKind_MSACtrl | RegKind_COP2 | RegKind_ACC | RegKind_CCR | RegKind_HWRegs | RegKind_COP3 | RegKind_COP0 }; private: enum KindTy { k_Immediate, /// An immediate (possibly involving symbol references) k_Memory, /// Base + Offset Memory Address k_RegisterIndex, /// A register index in one or more RegKind. k_Token, /// A simple token k_RegList, /// A physical register list k_RegPair /// A pair of physical register } Kind; public: MipsOperand(KindTy K, MipsAsmParser &Parser) : MCParsedAsmOperand(), Kind(K), AsmParser(Parser) {} private: /// For diagnostics, and checking the assembler temporary MipsAsmParser &AsmParser; struct Token { const char *Data; unsigned Length; }; struct RegIdxOp { unsigned Index; /// Index into the register class RegKind Kind; /// Bitfield of the kinds it could possibly be struct Token Tok; /// The input token this operand originated from. const MCRegisterInfo *RegInfo; }; struct ImmOp { const MCExpr *Val; }; struct MemOp { MipsOperand *Base; const MCExpr *Off; }; struct RegListOp { SmallVector *List; }; union { struct Token Tok; struct RegIdxOp RegIdx; struct ImmOp Imm; struct MemOp Mem; struct RegListOp RegList; }; SMLoc StartLoc, EndLoc; /// Internal constructor for register kinds static std::unique_ptr CreateReg(unsigned Index, StringRef Str, RegKind RegKind, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { auto Op = make_unique(k_RegisterIndex, Parser); Op->RegIdx.Index = Index; Op->RegIdx.RegInfo = RegInfo; Op->RegIdx.Kind = RegKind; Op->RegIdx.Tok.Data = Str.data(); Op->RegIdx.Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = E; return Op; } public: /// Coerce the register to GPR32 and return the real register for the current /// target. unsigned getGPR32Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); AsmParser.warnIfRegIndexIsAT(RegIdx.Index, StartLoc); unsigned ClassID = Mips::GPR32RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to GPR32 and return the real register for the current /// target. unsigned getGPRMM16Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); unsigned ClassID = Mips::GPR32RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to GPR64 and return the real register for the current /// target. unsigned getGPR64Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_GPR) && "Invalid access!"); unsigned ClassID = Mips::GPR64RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } private: /// Coerce the register to AFGR64 and return the real register for the current /// target. unsigned getAFGR64Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); if (RegIdx.Index % 2 != 0) AsmParser.Warning(StartLoc, "Float register should be even."); return RegIdx.RegInfo->getRegClass(Mips::AFGR64RegClassID) .getRegister(RegIdx.Index / 2); } /// Coerce the register to FGR64 and return the real register for the current /// target. unsigned getFGR64Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); return RegIdx.RegInfo->getRegClass(Mips::FGR64RegClassID) .getRegister(RegIdx.Index); } /// Coerce the register to FGR32 and return the real register for the current /// target. unsigned getFGR32Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); return RegIdx.RegInfo->getRegClass(Mips::FGR32RegClassID) .getRegister(RegIdx.Index); } /// Coerce the register to FGRH32 and return the real register for the current /// target. unsigned getFGRH32Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_FGR) && "Invalid access!"); return RegIdx.RegInfo->getRegClass(Mips::FGRH32RegClassID) .getRegister(RegIdx.Index); } /// Coerce the register to FCC and return the real register for the current /// target. unsigned getFCCReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_FCC) && "Invalid access!"); return RegIdx.RegInfo->getRegClass(Mips::FCCRegClassID) .getRegister(RegIdx.Index); } /// Coerce the register to MSA128 and return the real register for the current /// target. unsigned getMSA128Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_MSA128) && "Invalid access!"); // It doesn't matter which of the MSA128[BHWD] classes we use. They are all // identical unsigned ClassID = Mips::MSA128BRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to MSACtrl and return the real register for the /// current target. unsigned getMSACtrlReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_MSACtrl) && "Invalid access!"); unsigned ClassID = Mips::MSACtrlRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to COP0 and return the real register for the /// current target. unsigned getCOP0Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_COP0) && "Invalid access!"); unsigned ClassID = Mips::COP0RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to COP2 and return the real register for the /// current target. unsigned getCOP2Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_COP2) && "Invalid access!"); unsigned ClassID = Mips::COP2RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to COP3 and return the real register for the /// current target. unsigned getCOP3Reg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_COP3) && "Invalid access!"); unsigned ClassID = Mips::COP3RegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to ACC64DSP and return the real register for the /// current target. unsigned getACC64DSPReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); unsigned ClassID = Mips::ACC64DSPRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to HI32DSP and return the real register for the /// current target. unsigned getHI32DSPReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); unsigned ClassID = Mips::HI32DSPRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to LO32DSP and return the real register for the /// current target. unsigned getLO32DSPReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_ACC) && "Invalid access!"); unsigned ClassID = Mips::LO32DSPRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to CCR and return the real register for the /// current target. unsigned getCCRReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_CCR) && "Invalid access!"); unsigned ClassID = Mips::CCRRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } /// Coerce the register to HWRegs and return the real register for the /// current target. unsigned getHWRegsReg() const { assert(isRegIdx() && (RegIdx.Kind & RegKind_HWRegs) && "Invalid access!"); unsigned ClassID = Mips::HWRegsRegClassID; return RegIdx.RegInfo->getRegClass(ClassID).getRegister(RegIdx.Index); } public: void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediate when possible. Null MCExpr = 0. if (!Expr) Inst.addOperand(MCOperand::createImm(0)); else if (const MCConstantExpr *CE = dyn_cast(Expr)) Inst.addOperand(MCOperand::createImm(CE->getValue())); else Inst.addOperand(MCOperand::createExpr(Expr)); } void addRegOperands(MCInst &Inst, unsigned N) const { llvm_unreachable("Use a custom parser instead"); } /// Render the operand to an MCInst as a GPR32 /// Asserts if the wrong number of operands are requested, or the operand /// is not a k_RegisterIndex compatible with RegKind_GPR void addGPR32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPR32Reg())); } void addGPRMM16AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); } void addGPRMM16AsmRegZeroOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); } void addGPRMM16AsmRegMovePOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPRMM16Reg())); } /// Render the operand to an MCInst as a GPR64 /// Asserts if the wrong number of operands are requested, or the operand /// is not a k_RegisterIndex compatible with RegKind_GPR void addGPR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getGPR64Reg())); } void addAFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getAFGR64Reg())); } void addFGR64AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGR64Reg())); } void addFGR32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGR32Reg())); // FIXME: We ought to do this for -integrated-as without -via-file-asm too. // FIXME: This should propagate failure up to parseStatement. if (!AsmParser.useOddSPReg() && RegIdx.Index & 1) AsmParser.getParser().printError( StartLoc, "-mno-odd-spreg prohibits the use of odd FPU " "registers"); } void addFGRH32AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFGRH32Reg())); } void addFCCAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getFCCReg())); } void addMSA128AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getMSA128Reg())); } void addMSACtrlAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getMSACtrlReg())); } void addCOP0AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getCOP0Reg())); } void addCOP2AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getCOP2Reg())); } void addCOP3AsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getCOP3Reg())); } void addACC64DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getACC64DSPReg())); } void addHI32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getHI32DSPReg())); } void addLO32DSPAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getLO32DSPReg())); } void addCCRAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getCCRReg())); } void addHWRegsAsmRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getHWRegsReg())); } template void addConstantUImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); uint64_t Imm = getConstantImm() - Offset; Imm &= (1ULL << Bits) - 1; Imm += Offset; Imm += AdjustOffset; Inst.addOperand(MCOperand::createImm(Imm)); } template void addSImmOperands(MCInst &Inst, unsigned N) const { if (isImm() && !isConstantImm()) { addExpr(Inst, getImm()); return; } addConstantSImmOperands(Inst, N); } template void addUImmOperands(MCInst &Inst, unsigned N) const { if (isImm() && !isConstantImm()) { addExpr(Inst, getImm()); return; } addConstantUImmOperands(Inst, N); } template void addConstantSImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); int64_t Imm = getConstantImm() - Offset; Imm = SignExtend64(Imm); Imm += Offset; Imm += AdjustOffset; Inst.addOperand(MCOperand::createImm(Imm)); } void addImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); const MCExpr *Expr = getImm(); addExpr(Inst, Expr); } void addMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(AsmParser.getABI().ArePtrs64bit() ? getMemBase()->getGPR64Reg() : getMemBase()->getGPR32Reg())); const MCExpr *Expr = getMemOff(); addExpr(Inst, Expr); } void addMicroMipsMemOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getMemBase()->getGPRMM16Reg())); const MCExpr *Expr = getMemOff(); addExpr(Inst, Expr); } void addRegListOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); for (auto RegNo : getRegList()) Inst.addOperand(MCOperand::createReg(RegNo)); } void addRegPairOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); assert((RegIdx.Kind & RegKind_GPR) && "Invalid access!"); unsigned RegNo = getRegPair(); AsmParser.warnIfRegIndexIsAT(RegNo, StartLoc); Inst.addOperand(MCOperand::createReg( RegIdx.RegInfo->getRegClass( AsmParser.getABI().AreGprs64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID).getRegister(RegNo++))); Inst.addOperand(MCOperand::createReg( RegIdx.RegInfo->getRegClass( AsmParser.getABI().AreGprs64bit() ? Mips::GPR64RegClassID : Mips::GPR32RegClassID).getRegister(RegNo))); } void addMovePRegPairOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); for (auto RegNo : getRegList()) Inst.addOperand(MCOperand::createReg(RegNo)); } bool isReg() const override { // As a special case until we sort out the definition of div/divu, accept // $0/$zero here so that MCK_ZERO works correctly. return isGPRAsmReg() && RegIdx.Index == 0; } bool isRegIdx() const { return Kind == k_RegisterIndex; } bool isImm() const override { return Kind == k_Immediate; } bool isConstantImm() const { int64_t Res; return isImm() && getImm()->evaluateAsAbsolute(Res); } bool isConstantImmz() const { return isConstantImm() && getConstantImm() == 0; } template bool isConstantUImm() const { return isConstantImm() && isUInt(getConstantImm() - Offset); } template bool isSImm() const { return isConstantImm() ? isInt(getConstantImm()) : isImm(); } template bool isUImm() const { return isConstantImm() ? isUInt(getConstantImm()) : isImm(); } template bool isAnyImm() const { return isConstantImm() ? (isInt(getConstantImm()) || isUInt(getConstantImm())) : isImm(); } template bool isConstantSImm() const { return isConstantImm() && isInt(getConstantImm() - Offset); } template bool isConstantUImmRange() const { return isConstantImm() && getConstantImm() >= Bottom && getConstantImm() <= Top; } bool isToken() const override { // Note: It's not possible to pretend that other operand kinds are tokens. // The matcher emitter checks tokens first. return Kind == k_Token; } bool isMem() const override { return Kind == k_Memory; } bool isConstantMemOff() const { return isMem() && isa(getMemOff()); } // Allow relocation operators. // FIXME: This predicate and others need to look through binary expressions // and determine whether a Value is a constant or not. template bool isMemWithSimmOffset() const { if (!isMem()) return false; if (!getMemBase()->isGPRAsmReg()) return false; if (isa(getMemOff()) || (isConstantMemOff() && isShiftedInt(getConstantMemOff()))) return true; MCValue Res; bool IsReloc = getMemOff()->evaluateAsRelocatable(Res, nullptr, nullptr); return IsReloc && isShiftedInt(Res.getConstant()); } bool isMemWithGRPMM16Base() const { return isMem() && getMemBase()->isMM16AsmReg(); } template bool isMemWithUimmOffsetSP() const { return isMem() && isConstantMemOff() && isUInt(getConstantMemOff()) && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); } template bool isMemWithUimmWordAlignedOffsetSP() const { return isMem() && isConstantMemOff() && isUInt(getConstantMemOff()) && (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::SP); } template bool isMemWithSimmWordAlignedOffsetGP() const { return isMem() && isConstantMemOff() && isInt(getConstantMemOff()) && (getConstantMemOff() % 4 == 0) && getMemBase()->isRegIdx() && (getMemBase()->getGPR32Reg() == Mips::GP); } template bool isScaledUImm() const { return isConstantImm() && isShiftedUInt(getConstantImm()); } template bool isScaledSImm() const { if (isConstantImm() && isShiftedInt(getConstantImm())) return true; // Operand can also be a symbol or symbol plus offset in case of relocations. if (Kind != k_Immediate) return false; MCValue Res; bool Success = getImm()->evaluateAsRelocatable(Res, nullptr, nullptr); return Success && isShiftedInt(Res.getConstant()); } bool isRegList16() const { if (!isRegList()) return false; int Size = RegList.List->size(); if (Size < 2 || Size > 5) return false; unsigned R0 = RegList.List->front(); unsigned R1 = RegList.List->back(); if (!((R0 == Mips::S0 && R1 == Mips::RA) || (R0 == Mips::S0_64 && R1 == Mips::RA_64))) return false; int PrevReg = *RegList.List->begin(); for (int i = 1; i < Size - 1; i++) { int Reg = (*(RegList.List))[i]; if ( Reg != PrevReg + 1) return false; PrevReg = Reg; } return true; } bool isInvNum() const { return Kind == k_Immediate; } bool isLSAImm() const { if (!isConstantImm()) return false; int64_t Val = getConstantImm(); return 1 <= Val && Val <= 4; } bool isRegList() const { return Kind == k_RegList; } bool isMovePRegPair() const { if (Kind != k_RegList || RegList.List->size() != 2) return false; unsigned R0 = RegList.List->front(); unsigned R1 = RegList.List->back(); if ((R0 == Mips::A1 && R1 == Mips::A2) || (R0 == Mips::A1 && R1 == Mips::A3) || (R0 == Mips::A2 && R1 == Mips::A3) || (R0 == Mips::A0 && R1 == Mips::S5) || (R0 == Mips::A0 && R1 == Mips::S6) || (R0 == Mips::A0 && R1 == Mips::A1) || (R0 == Mips::A0 && R1 == Mips::A2) || (R0 == Mips::A0 && R1 == Mips::A3) || (R0 == Mips::A1_64 && R1 == Mips::A2_64) || (R0 == Mips::A1_64 && R1 == Mips::A3_64) || (R0 == Mips::A2_64 && R1 == Mips::A3_64) || (R0 == Mips::A0_64 && R1 == Mips::S5_64) || (R0 == Mips::A0_64 && R1 == Mips::S6_64) || (R0 == Mips::A0_64 && R1 == Mips::A1_64) || (R0 == Mips::A0_64 && R1 == Mips::A2_64) || (R0 == Mips::A0_64 && R1 == Mips::A3_64)) return true; return false; } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); } bool isRegPair() const { return Kind == k_RegPair && RegIdx.Index <= 30; } unsigned getReg() const override { // As a special case until we sort out the definition of div/divu, accept // $0/$zero here so that MCK_ZERO works correctly. if (Kind == k_RegisterIndex && RegIdx.Index == 0 && RegIdx.Kind & RegKind_GPR) return getGPR32Reg(); // FIXME: GPR64 too llvm_unreachable("Invalid access!"); return 0; } const MCExpr *getImm() const { assert((Kind == k_Immediate) && "Invalid access!"); return Imm.Val; } int64_t getConstantImm() const { const MCExpr *Val = getImm(); int64_t Value = 0; (void)Val->evaluateAsAbsolute(Value); return Value; } MipsOperand *getMemBase() const { assert((Kind == k_Memory) && "Invalid access!"); return Mem.Base; } const MCExpr *getMemOff() const { assert((Kind == k_Memory) && "Invalid access!"); return Mem.Off; } int64_t getConstantMemOff() const { return static_cast(getMemOff())->getValue(); } const SmallVectorImpl &getRegList() const { assert((Kind == k_RegList) && "Invalid access!"); return *(RegList.List); } unsigned getRegPair() const { assert((Kind == k_RegPair) && "Invalid access!"); return RegIdx.Index; } static std::unique_ptr CreateToken(StringRef Str, SMLoc S, MipsAsmParser &Parser) { auto Op = make_unique(k_Token, Parser); Op->Tok.Data = Str.data(); Op->Tok.Length = Str.size(); Op->StartLoc = S; Op->EndLoc = S; return Op; } /// Create a numeric register (e.g. $1). The exact register remains /// unresolved until an instruction successfully matches static std::unique_ptr createNumericReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { DEBUG(dbgs() << "createNumericReg(" << Index << ", ...)\n"); return CreateReg(Index, Str, RegKind_Numeric, RegInfo, S, E, Parser); } /// Create a register that is definitely a GPR. /// This is typically only used for named registers such as $gp. static std::unique_ptr createGPRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_GPR, RegInfo, S, E, Parser); } /// Create a register that is definitely a FGR. /// This is typically only used for named registers such as $f0. static std::unique_ptr createFGRReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_FGR, RegInfo, S, E, Parser); } /// Create a register that is definitely a HWReg. /// This is typically only used for named registers such as $hwr_cpunum. static std::unique_ptr createHWRegsReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_HWRegs, RegInfo, S, E, Parser); } /// Create a register that is definitely an FCC. /// This is typically only used for named registers such as $fcc0. static std::unique_ptr createFCCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_FCC, RegInfo, S, E, Parser); } /// Create a register that is definitely an ACC. /// This is typically only used for named registers such as $ac0. static std::unique_ptr createACCReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_ACC, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSA128. /// This is typically only used for named registers such as $w0. static std::unique_ptr createMSA128Reg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_MSA128, RegInfo, S, E, Parser); } /// Create a register that is definitely an MSACtrl. /// This is typically only used for named registers such as $msaaccess. static std::unique_ptr createMSACtrlReg(unsigned Index, StringRef Str, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, MipsAsmParser &Parser) { return CreateReg(Index, Str, RegKind_MSACtrl, RegInfo, S, E, Parser); } static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, MipsAsmParser &Parser) { auto Op = make_unique(k_Immediate, Parser); Op->Imm.Val = Val; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateMem(std::unique_ptr Base, const MCExpr *Off, SMLoc S, SMLoc E, MipsAsmParser &Parser) { auto Op = make_unique(k_Memory, Parser); Op->Mem.Base = Base.release(); Op->Mem.Off = Off; Op->StartLoc = S; Op->EndLoc = E; return Op; } static std::unique_ptr CreateRegList(SmallVectorImpl &Regs, SMLoc StartLoc, SMLoc EndLoc, MipsAsmParser &Parser) { assert (Regs.size() > 0 && "Empty list not allowed"); auto Op = make_unique(k_RegList, Parser); Op->RegList.List = new SmallVector(Regs.begin(), Regs.end()); Op->StartLoc = StartLoc; Op->EndLoc = EndLoc; return Op; } static std::unique_ptr CreateRegPair(const MipsOperand &MOP, SMLoc S, SMLoc E, MipsAsmParser &Parser) { auto Op = make_unique(k_RegPair, Parser); Op->RegIdx.Index = MOP.RegIdx.Index; Op->RegIdx.RegInfo = MOP.RegIdx.RegInfo; Op->RegIdx.Kind = MOP.RegIdx.Kind; Op->StartLoc = S; Op->EndLoc = E; return Op; } bool isGPRAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31; } bool isMM16AsmReg() const { if (!(isRegIdx() && RegIdx.Kind)) return false; return ((RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 16 || RegIdx.Index == 17); } bool isMM16AsmRegZero() const { if (!(isRegIdx() && RegIdx.Kind)) return false; return (RegIdx.Index == 0 || (RegIdx.Index >= 2 && RegIdx.Index <= 7) || RegIdx.Index == 17); } bool isMM16AsmRegMoveP() const { if (!(isRegIdx() && RegIdx.Kind)) return false; return (RegIdx.Index == 0 || (RegIdx.Index >= 2 && RegIdx.Index <= 3) || (RegIdx.Index >= 16 && RegIdx.Index <= 20)); } bool isFGRAsmReg() const { // AFGR64 is $0-$15 but we handle this in getAFGR64() return isRegIdx() && RegIdx.Kind & RegKind_FGR && RegIdx.Index <= 31; } bool isHWRegsAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_HWRegs && RegIdx.Index <= 31; } bool isCCRAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_CCR && RegIdx.Index <= 31; } bool isFCCAsmReg() const { if (!(isRegIdx() && RegIdx.Kind & RegKind_FCC)) return false; - if (!AsmParser.hasEightFccRegisters()) - return RegIdx.Index == 0; return RegIdx.Index <= 7; } bool isACCAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_ACC && RegIdx.Index <= 3; } bool isCOP0AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP0 && RegIdx.Index <= 31; } bool isCOP2AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP2 && RegIdx.Index <= 31; } bool isCOP3AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_COP3 && RegIdx.Index <= 31; } bool isMSA128AsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_MSA128 && RegIdx.Index <= 31; } bool isMSACtrlAsmReg() const { return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7; } /// getStartLoc - Get the location of the first token of this operand. SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const override { return EndLoc; } virtual ~MipsOperand() { switch (Kind) { case k_Immediate: break; case k_Memory: delete Mem.Base; break; case k_RegList: delete RegList.List; case k_RegisterIndex: case k_Token: case k_RegPair: break; } } void print(raw_ostream &OS) const override { switch (Kind) { case k_Immediate: OS << "Imm<"; OS << *Imm.Val; OS << ">"; break; case k_Memory: OS << "Mem<"; Mem.Base->print(OS); OS << ", "; OS << *Mem.Off; OS << ">"; break; case k_RegisterIndex: OS << "RegIdx<" << RegIdx.Index << ":" << RegIdx.Kind << ", " << StringRef(RegIdx.Tok.Data, RegIdx.Tok.Length) << ">"; break; case k_Token: OS << getToken(); break; case k_RegList: OS << "RegList< "; for (auto Reg : (*RegList.List)) OS << Reg << " "; OS << ">"; break; case k_RegPair: OS << "RegPair<" << RegIdx.Index << "," << RegIdx.Index + 1 << ">"; break; } } bool isValidForTie(const MipsOperand &Other) const { if (Kind != Other.Kind) return false; switch (Kind) { default: llvm_unreachable("Unexpected kind"); return false; case k_RegisterIndex: { StringRef Token(RegIdx.Tok.Data, RegIdx.Tok.Length); StringRef OtherToken(Other.RegIdx.Tok.Data, Other.RegIdx.Tok.Length); return Token == OtherToken; } } } }; // class MipsOperand } // namespace namespace llvm { extern const MCInstrDesc MipsInsts[]; } static const MCInstrDesc &getInstDesc(unsigned Opcode) { return MipsInsts[Opcode]; } static bool hasShortDelaySlot(unsigned Opcode) { switch (Opcode) { case Mips::JALS_MM: case Mips::JALRS_MM: case Mips::JALRS16_MM: case Mips::BGEZALS_MM: case Mips::BLTZALS_MM: return true; default: return false; } } static const MCSymbol *getSingleMCSymbol(const MCExpr *Expr) { if (const MCSymbolRefExpr *SRExpr = dyn_cast(Expr)) { return &SRExpr->getSymbol(); } if (const MCBinaryExpr *BExpr = dyn_cast(Expr)) { const MCSymbol *LHSSym = getSingleMCSymbol(BExpr->getLHS()); const MCSymbol *RHSSym = getSingleMCSymbol(BExpr->getRHS()); if (LHSSym) return LHSSym; if (RHSSym) return RHSSym; return nullptr; } if (const MCUnaryExpr *UExpr = dyn_cast(Expr)) return getSingleMCSymbol(UExpr->getSubExpr()); return nullptr; } static unsigned countMCSymbolRefExpr(const MCExpr *Expr) { if (isa(Expr)) return 1; if (const MCBinaryExpr *BExpr = dyn_cast(Expr)) return countMCSymbolRefExpr(BExpr->getLHS()) + countMCSymbolRefExpr(BExpr->getRHS()); if (const MCUnaryExpr *UExpr = dyn_cast(Expr)) return countMCSymbolRefExpr(UExpr->getSubExpr()); return 0; } bool MipsAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); bool ExpandedJalSym = false; Inst.setLoc(IDLoc); if (MCID.isBranch() || MCID.isCall()) { const unsigned Opcode = Inst.getOpcode(); MCOperand Offset; switch (Opcode) { default: break; case Mips::BBIT0: case Mips::BBIT032: case Mips::BBIT1: case Mips::BBIT132: assert(hasCnMips() && "instruction only valid for octeon cpus"); LLVM_FALLTHROUGH; case Mips::BEQ: case Mips::BNE: case Mips::BEQ_MM: case Mips::BNE_MM: assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); Offset = Inst.getOperand(2); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BGEZ: case Mips::BGTZ: case Mips::BLEZ: case Mips::BLTZ: case Mips::BGEZAL: case Mips::BLTZAL: case Mips::BC1F: case Mips::BC1T: case Mips::BGEZ_MM: case Mips::BGTZ_MM: case Mips::BLEZ_MM: case Mips::BLTZ_MM: case Mips::BGEZAL_MM: case Mips::BLTZAL_MM: case Mips::BC1F_MM: case Mips::BC1T_MM: case Mips::BC1EQZC_MMR6: case Mips::BC1NEZC_MMR6: case Mips::BC2EQZC_MMR6: case Mips::BC2NEZC_MMR6: assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); Offset = Inst.getOperand(1); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isIntN(inMicroMipsMode() ? 17 : 18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << (inMicroMipsMode() ? 1 : 2))) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BGEC: case Mips::BGEC_MMR6: case Mips::BLTC: case Mips::BLTC_MMR6: case Mips::BGEUC: case Mips::BGEUC_MMR6: case Mips::BLTUC: case Mips::BLTUC_MMR6: case Mips::BEQC: case Mips::BEQC_MMR6: case Mips::BNEC: case Mips::BNEC_MMR6: assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); Offset = Inst.getOperand(2); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isIntN(18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BLEZC: case Mips::BLEZC_MMR6: case Mips::BGEZC: case Mips::BGEZC_MMR6: case Mips::BGTZC: case Mips::BGTZC_MMR6: case Mips::BLTZC: case Mips::BLTZC_MMR6: assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); Offset = Inst.getOperand(1); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isIntN(18, Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BEQZC: case Mips::BEQZC_MMR6: case Mips::BNEZC: case Mips::BNEZC_MMR6: assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); Offset = Inst.getOperand(1); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isIntN(23, Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 2)) return Error(IDLoc, "branch to misaligned address"); break; case Mips::BEQZ16_MM: case Mips::BEQZC16_MMR6: case Mips::BNEZ16_MM: case Mips::BNEZC16_MMR6: assert(MCID.getNumOperands() == 2 && "unexpected number of operands"); Offset = Inst.getOperand(1); if (!Offset.isImm()) break; // We'll deal with this situation later on when applying fixups. if (!isInt<8>(Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 2LL)) return Error(IDLoc, "branch to misaligned address"); break; } } // SSNOP is deprecated on MIPS32r6/MIPS64r6 // We still accept it but it is a normal nop. if (hasMips32r6() && Inst.getOpcode() == Mips::SSNOP) { std::string ISA = hasMips64r6() ? "MIPS64r6" : "MIPS32r6"; Warning(IDLoc, "ssnop is deprecated for " + ISA + " and is equivalent to a " "nop instruction"); } if (hasCnMips()) { const unsigned Opcode = Inst.getOpcode(); MCOperand Opnd; int Imm; switch (Opcode) { default: break; case Mips::BBIT0: case Mips::BBIT032: case Mips::BBIT1: case Mips::BBIT132: assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); // The offset is handled above Opnd = Inst.getOperand(1); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < 0 || Imm > (Opcode == Mips::BBIT0 || Opcode == Mips::BBIT1 ? 63 : 31)) return Error(IDLoc, "immediate operand value out of range"); if (Imm > 31) { Inst.setOpcode(Opcode == Mips::BBIT0 ? Mips::BBIT032 : Mips::BBIT132); Inst.getOperand(1).setImm(Imm - 32); } break; case Mips::SEQi: case Mips::SNEi: assert(MCID.getNumOperands() == 3 && "unexpected number of operands"); Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (!isInt<10>(Imm)) return Error(IDLoc, "immediate operand value out of range"); break; } } // For PIC code convert unconditional jump to unconditional branch. if ((Inst.getOpcode() == Mips::J || Inst.getOpcode() == Mips::J_MM) && inPicMode()) { MCInst BInst; BInst.setOpcode(inMicroMipsMode() ? Mips::BEQ_MM : Mips::BEQ); BInst.addOperand(MCOperand::createReg(Mips::ZERO)); BInst.addOperand(MCOperand::createReg(Mips::ZERO)); BInst.addOperand(Inst.getOperand(0)); Inst = BInst; } // This expansion is not in a function called by tryExpandInstruction() // because the pseudo-instruction doesn't have a distinct opcode. if ((Inst.getOpcode() == Mips::JAL || Inst.getOpcode() == Mips::JAL_MM) && inPicMode()) { warnIfNoMacro(IDLoc); const MCExpr *JalExpr = Inst.getOperand(0).getExpr(); // We can do this expansion if there's only 1 symbol in the argument // expression. if (countMCSymbolRefExpr(JalExpr) > 1) return Error(IDLoc, "jal doesn't support multiple symbols in PIC mode"); // FIXME: This is checking the expression can be handled by the later stages // of the assembler. We ought to leave it to those later stages. const MCSymbol *JalSym = getSingleMCSymbol(JalExpr); // FIXME: Add support for label+offset operands (currently causes an error). // FIXME: Add support for forward-declared local symbols. // FIXME: Add expansion for when the LargeGOT option is enabled. if (JalSym->isInSection() || JalSym->isTemporary() || (JalSym->isELF() && cast(JalSym)->getBinding() == ELF::STB_LOCAL)) { if (isABI_O32()) { // If it's a local symbol and the O32 ABI is being used, we expand to: // lw $25, 0($gp) // R_(MICRO)MIPS_GOT16 label // addiu $25, $25, 0 // R_(MICRO)MIPS_LO16 label // jalr $25 const MCExpr *Got16RelocExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT, JalExpr, getContext()); const MCExpr *Lo16RelocExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, JalExpr, getContext()); TOut.emitRRX(Mips::LW, Mips::T9, Mips::GP, MCOperand::createExpr(Got16RelocExpr), IDLoc, STI); TOut.emitRRX(Mips::ADDiu, Mips::T9, Mips::T9, MCOperand::createExpr(Lo16RelocExpr), IDLoc, STI); } else if (isABI_N32() || isABI_N64()) { // If it's a local symbol and the N32/N64 ABIs are being used, // we expand to: // lw/ld $25, 0($gp) // R_(MICRO)MIPS_GOT_DISP label // jalr $25 const MCExpr *GotDispRelocExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT_DISP, JalExpr, getContext()); TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, MCOperand::createExpr(GotDispRelocExpr), IDLoc, STI); } } else { // If it's an external/weak symbol, we expand to: // lw/ld $25, 0($gp) // R_(MICRO)MIPS_CALL16 label // jalr $25 const MCExpr *Call16RelocExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, JalExpr, getContext()); TOut.emitRRX(ABI.ArePtrs64bit() ? Mips::LD : Mips::LW, Mips::T9, Mips::GP, MCOperand::createExpr(Call16RelocExpr), IDLoc, STI); } MCInst JalrInst; if (IsCpRestoreSet && inMicroMipsMode()) JalrInst.setOpcode(Mips::JALRS_MM); else JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); JalrInst.addOperand(MCOperand::createReg(Mips::RA)); JalrInst.addOperand(MCOperand::createReg(Mips::T9)); // FIXME: Add an R_(MICRO)MIPS_JALR relocation after the JALR. // This relocation is supposed to be an optimization hint for the linker // and is not necessary for correctness. Inst = JalrInst; ExpandedJalSym = true; } bool IsPCRelativeLoad = (MCID.TSFlags & MipsII::IsPCRelativeLoad) != 0; if ((MCID.mayLoad() || MCID.mayStore()) && !IsPCRelativeLoad) { // Check the offset of memory operand, if it is a symbol // reference or immediate we may have to expand instructions. for (unsigned i = 0; i < MCID.getNumOperands(); i++) { const MCOperandInfo &OpInfo = MCID.OpInfo[i]; if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { MCOperand &Op = Inst.getOperand(i); if (Op.isImm()) { int MemOffset = Op.getImm(); if (MemOffset < -32768 || MemOffset > 32767) { // Offset can't exceed 16bit value. expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), true); return getParser().hasPendingError(); } } else if (Op.isExpr()) { const MCExpr *Expr = Op.getExpr(); if (Expr->getKind() == MCExpr::SymbolRef) { const MCSymbolRefExpr *SR = static_cast(Expr); if (SR->getKind() == MCSymbolRefExpr::VK_None) { // Expand symbol. expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); return getParser().hasPendingError(); } } else if (!isEvaluated(Expr)) { expandMemInst(Inst, IDLoc, Out, STI, MCID.mayLoad(), false); return getParser().hasPendingError(); } } } } // for } // if load/store if (inMicroMipsMode()) { if (MCID.mayLoad()) { // Try to create 16-bit GP relative load instruction. for (unsigned i = 0; i < MCID.getNumOperands(); i++) { const MCOperandInfo &OpInfo = MCID.OpInfo[i]; if ((OpInfo.OperandType == MCOI::OPERAND_MEMORY) || (OpInfo.OperandType == MCOI::OPERAND_UNKNOWN)) { MCOperand &Op = Inst.getOperand(i); if (Op.isImm()) { int MemOffset = Op.getImm(); MCOperand &DstReg = Inst.getOperand(0); MCOperand &BaseReg = Inst.getOperand(1); if (isInt<9>(MemOffset) && (MemOffset % 4 == 0) && getContext().getRegisterInfo()->getRegClass( Mips::GPRMM16RegClassID).contains(DstReg.getReg()) && (BaseReg.getReg() == Mips::GP || BaseReg.getReg() == Mips::GP_64)) { TOut.emitRRI(Mips::LWGP_MM, DstReg.getReg(), Mips::GP, MemOffset, IDLoc, STI); return false; } } } } // for } // if load // TODO: Handle this with the AsmOperandClass.PredicateMethod. MCOperand Opnd; int Imm; switch (Inst.getOpcode()) { default: break; case Mips::ADDIUSP_MM: Opnd = Inst.getOperand(0); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < -1032 || Imm > 1028 || (Imm < 8 && Imm > -12) || Imm % 4 != 0) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::SLL16_MM: case Mips::SRL16_MM: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < 1 || Imm > 8) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::LI16_MM: Opnd = Inst.getOperand(1); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < -1 || Imm > 126) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::ADDIUR2_MM: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (!(Imm == 1 || Imm == -1 || ((Imm % 4 == 0) && Imm < 28 && Imm > 0))) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::ANDI16_MM: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (!(Imm == 128 || (Imm >= 1 && Imm <= 4) || Imm == 7 || Imm == 8 || Imm == 15 || Imm == 16 || Imm == 31 || Imm == 32 || Imm == 63 || Imm == 64 || Imm == 255 || Imm == 32768 || Imm == 65535)) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::LBU16_MM: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < -1 || Imm > 14) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::SB16_MM: case Mips::SB16_MMR6: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < 0 || Imm > 15) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::LHU16_MM: case Mips::SH16_MM: case Mips::SH16_MMR6: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < 0 || Imm > 30 || (Imm % 2 != 0)) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::LW16_MM: case Mips::SW16_MM: case Mips::SW16_MMR6: Opnd = Inst.getOperand(2); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); Imm = Opnd.getImm(); if (Imm < 0 || Imm > 60 || (Imm % 4 != 0)) return Error(IDLoc, "immediate operand value out of range"); break; case Mips::ADDIUPC_MM: MCOperand Opnd = Inst.getOperand(1); if (!Opnd.isImm()) return Error(IDLoc, "expected immediate operand kind"); int Imm = Opnd.getImm(); if ((Imm % 4 != 0) || !isInt<25>(Imm)) return Error(IDLoc, "immediate operand value out of range"); break; } } bool FillDelaySlot = MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder(); if (FillDelaySlot) TOut.emitDirectiveSetNoReorder(); MacroExpanderResultTy ExpandResult = tryExpandInstruction(Inst, IDLoc, Out, STI); switch (ExpandResult) { case MER_NotAMacro: Out.EmitInstruction(Inst, *STI); break; case MER_Success: break; case MER_Fail: return true; } // We know we emitted an instruction on the MER_NotAMacro or MER_Success path. // If we're in microMIPS mode then we must also set EF_MIPS_MICROMIPS. if (inMicroMipsMode()) TOut.setUsesMicroMips(); // If this instruction has a delay slot and .set reorder is active, // emit a NOP after it. if (FillDelaySlot) { TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst.getOpcode()), IDLoc, STI); TOut.emitDirectiveSetReorder(); } if ((Inst.getOpcode() == Mips::JalOneReg || Inst.getOpcode() == Mips::JalTwoReg || ExpandedJalSym) && isPicAndNotNxxAbi()) { if (IsCpRestoreSet) { // We need a NOP between the JALR and the LW: // If .set reorder has been used, we've already emitted a NOP. // If .set noreorder has been used, we need to emit a NOP at this point. if (!AssemblerOptions.back()->isReorder()) TOut.emitEmptyDelaySlot(hasShortDelaySlot(Inst.getOpcode()), IDLoc, STI); // Load the $gp from the stack. TOut.emitGPRestore(CpRestoreOffset, IDLoc, STI); } else Warning(IDLoc, "no .cprestore used in PIC mode"); } return false; } MipsAsmParser::MacroExpanderResultTy MipsAsmParser::tryExpandInstruction(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { switch (Inst.getOpcode()) { default: return MER_NotAMacro; case Mips::LoadImm32: return expandLoadImm(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LoadImm64: return expandLoadImm(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LoadAddrImm32: case Mips::LoadAddrImm64: assert(Inst.getOperand(0).isReg() && "expected register operand kind"); assert((Inst.getOperand(1).isImm() || Inst.getOperand(1).isExpr()) && "expected immediate operand kind"); return expandLoadAddress(Inst.getOperand(0).getReg(), Mips::NoRegister, Inst.getOperand(1), Inst.getOpcode() == Mips::LoadAddrImm32, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LoadAddrReg32: case Mips::LoadAddrReg64: assert(Inst.getOperand(0).isReg() && "expected register operand kind"); assert(Inst.getOperand(1).isReg() && "expected register operand kind"); assert((Inst.getOperand(2).isImm() || Inst.getOperand(2).isExpr()) && "expected immediate operand kind"); return expandLoadAddress(Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), Inst.getOperand(2), Inst.getOpcode() == Mips::LoadAddrReg32, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::B_MM_Pseudo: case Mips::B_MMR6_Pseudo: return expandUncondBranchMMPseudo(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::SWM_MM: case Mips::LWM_MM: return expandLoadStoreMultiple(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::JalOneReg: case Mips::JalTwoReg: return expandJalWithRegs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::BneImm: case Mips::BeqImm: return expandBranchImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::BLT: case Mips::BLE: case Mips::BGE: case Mips::BGT: case Mips::BLTU: case Mips::BLEU: case Mips::BGEU: case Mips::BGTU: case Mips::BLTL: case Mips::BLEL: case Mips::BGEL: case Mips::BGTL: case Mips::BLTUL: case Mips::BLEUL: case Mips::BGEUL: case Mips::BGTUL: case Mips::BLTImmMacro: case Mips::BLEImmMacro: case Mips::BGEImmMacro: case Mips::BGTImmMacro: case Mips::BLTUImmMacro: case Mips::BLEUImmMacro: case Mips::BGEUImmMacro: case Mips::BGTUImmMacro: case Mips::BLTLImmMacro: case Mips::BLELImmMacro: case Mips::BGELImmMacro: case Mips::BGTLImmMacro: case Mips::BLTULImmMacro: case Mips::BLEULImmMacro: case Mips::BGEULImmMacro: case Mips::BGTULImmMacro: return expandCondBranches(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::SDivMacro: return expandDiv(Inst, IDLoc, Out, STI, false, true) ? MER_Fail : MER_Success; case Mips::DSDivMacro: return expandDiv(Inst, IDLoc, Out, STI, true, true) ? MER_Fail : MER_Success; case Mips::UDivMacro: return expandDiv(Inst, IDLoc, Out, STI, false, false) ? MER_Fail : MER_Success; case Mips::DUDivMacro: return expandDiv(Inst, IDLoc, Out, STI, true, false) ? MER_Fail : MER_Success; case Mips::PseudoTRUNC_W_S: return expandTrunc(Inst, false, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::PseudoTRUNC_W_D32: return expandTrunc(Inst, true, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::PseudoTRUNC_W_D: return expandTrunc(Inst, true, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulh: return expandUlh(Inst, true, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulhu: return expandUlh(Inst, false, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ush: return expandUsh(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::Ulw: case Mips::Usw: return expandUxw(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::NORImm: return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ADDi: case Mips::ADDiu: case Mips::SLTi: case Mips::SLTiu: if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { int64_t ImmValue = Inst.getOperand(2).getImm(); if (isInt<16>(ImmValue)) return MER_NotAMacro; return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; } return MER_NotAMacro; case Mips::ANDi: case Mips::ORi: case Mips::XORi: if ((Inst.getNumOperands() == 3) && Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm()) { int64_t ImmValue = Inst.getOperand(2).getImm(); if (isUInt<16>(ImmValue)) return MER_NotAMacro; return expandAliasImmediate(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; } return MER_NotAMacro; case Mips::ROL: case Mips::ROR: return expandRotation(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ROLImm: case Mips::RORImm: return expandRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::DROL: case Mips::DROR: return expandDRotation(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::DROLImm: case Mips::DRORImm: return expandDRotationImm(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::ABSMacro: return expandAbs(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::LDMacro: case Mips::SDMacro: return expandLoadStoreDMacro(Inst, IDLoc, Out, STI, Inst.getOpcode() == Mips::LDMacro) ? MER_Fail : MER_Success; case Mips::SEQMacro: return expandSeq(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; case Mips::SEQIMacro: return expandSeqI(Inst, IDLoc, Out, STI) ? MER_Fail : MER_Success; } } bool MipsAsmParser::expandJalWithRegs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); // Create a JALR instruction which is going to replace the pseudo-JAL. MCInst JalrInst; JalrInst.setLoc(IDLoc); const MCOperand FirstRegOp = Inst.getOperand(0); const unsigned Opcode = Inst.getOpcode(); if (Opcode == Mips::JalOneReg) { // jal $rs => jalr $rs if (IsCpRestoreSet && inMicroMipsMode()) { JalrInst.setOpcode(Mips::JALRS16_MM); JalrInst.addOperand(FirstRegOp); } else if (inMicroMipsMode()) { JalrInst.setOpcode(hasMips32r6() ? Mips::JALRC16_MMR6 : Mips::JALR16_MM); JalrInst.addOperand(FirstRegOp); } else { JalrInst.setOpcode(Mips::JALR); JalrInst.addOperand(MCOperand::createReg(Mips::RA)); JalrInst.addOperand(FirstRegOp); } } else if (Opcode == Mips::JalTwoReg) { // jal $rd, $rs => jalr $rd, $rs if (IsCpRestoreSet && inMicroMipsMode()) JalrInst.setOpcode(Mips::JALRS_MM); else JalrInst.setOpcode(inMicroMipsMode() ? Mips::JALR_MM : Mips::JALR); JalrInst.addOperand(FirstRegOp); const MCOperand SecondRegOp = Inst.getOperand(1); JalrInst.addOperand(SecondRegOp); } Out.EmitInstruction(JalrInst, *STI); // If .set reorder is active and branch instruction has a delay slot, // emit a NOP after it. const MCInstrDesc &MCID = getInstDesc(JalrInst.getOpcode()); if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) TOut.emitEmptyDelaySlot(hasShortDelaySlot(JalrInst.getOpcode()), IDLoc, STI); return false; } /// Can the value be represented by a unsigned N-bit value and a shift left? template static bool isShiftedUIntAtAnyPosition(uint64_t x) { unsigned BitNum = findFirstSet(x); return (x == x >> BitNum << BitNum) && isUInt(x >> BitNum); } /// Load (or add) an immediate into a register. /// /// @param ImmValue The immediate to load. /// @param DstReg The register that will hold the immediate. /// @param SrcReg A register to add to the immediate or Mips::NoRegister /// for a simple initialization. /// @param Is32BitImm Is ImmValue 32-bit or 64-bit? /// @param IsAddress True if the immediate represents an address. False if it /// is an integer. /// @param IDLoc Location of the immediate in the source file. bool MipsAsmParser::loadImmediate(int64_t ImmValue, unsigned DstReg, unsigned SrcReg, bool Is32BitImm, bool IsAddress, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); if (!Is32BitImm && !isGP64bit()) { Error(IDLoc, "instruction requires a 64-bit architecture"); return true; } if (Is32BitImm) { if (isInt<32>(ImmValue) || isUInt<32>(ImmValue)) { // Sign extend up to 64-bit so that the predicates match the hardware // behaviour. In particular, isInt<16>(0xffff8000) and similar should be // true. ImmValue = SignExtend64<32>(ImmValue); } else { Error(IDLoc, "instruction requires a 32-bit immediate"); return true; } } unsigned ZeroReg = IsAddress ? ABI.GetNullPtr() : ABI.GetZeroReg(); unsigned AdduOp = !Is32BitImm ? Mips::DADDu : Mips::ADDu; bool UseSrcReg = false; if (SrcReg != Mips::NoRegister) UseSrcReg = true; unsigned TmpReg = DstReg; if (UseSrcReg && getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // At this point we need AT to perform the expansions and we exit if it is // not available. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; TmpReg = ATReg; } if (isInt<16>(ImmValue)) { if (!UseSrcReg) SrcReg = ZeroReg; // This doesn't quite follow the usual ABI expectations for N32 but matches // traditional assembler behaviour. N32 would normally use addiu for both // integers and addresses. if (IsAddress && !Is32BitImm) { TOut.emitRRI(Mips::DADDiu, DstReg, SrcReg, ImmValue, IDLoc, STI); return false; } TOut.emitRRI(Mips::ADDiu, DstReg, SrcReg, ImmValue, IDLoc, STI); return false; } if (isUInt<16>(ImmValue)) { unsigned TmpReg = DstReg; if (SrcReg == DstReg) { TmpReg = getATReg(IDLoc); if (!TmpReg) return true; } TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, ImmValue, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(ABI.GetPtrAdduOp(), DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } if (isInt<32>(ImmValue) || isUInt<32>(ImmValue)) { warnIfNoMacro(IDLoc); uint16_t Bits31To16 = (ImmValue >> 16) & 0xffff; uint16_t Bits15To0 = ImmValue & 0xffff; if (!Is32BitImm && !isInt<32>(ImmValue)) { // Traditional behaviour seems to special case this particular value. It's // not clear why other masks are handled differently. if (ImmValue == 0xffffffff) { TOut.emitRI(Mips::LUi, TmpReg, 0xffff, IDLoc, STI); TOut.emitRRI(Mips::DSRL32, TmpReg, TmpReg, 0, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } // Expand to an ORi instead of a LUi to avoid sign-extending into the // upper 32 bits. TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits31To16, IDLoc, STI); TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, 16, IDLoc, STI); if (Bits15To0) TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } TOut.emitRI(Mips::LUi, TmpReg, Bits31To16, IDLoc, STI); if (Bits15To0) TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, Bits15To0, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } if (isShiftedUIntAtAnyPosition<16>(ImmValue)) { if (Is32BitImm) { Error(IDLoc, "instruction requires a 32-bit immediate"); return true; } // Traditionally, these immediates are shifted as little as possible and as // such we align the most significant bit to bit 15 of our temporary. unsigned FirstSet = findFirstSet((uint64_t)ImmValue); unsigned LastSet = findLastSet((uint64_t)ImmValue); unsigned ShiftAmount = FirstSet - (15 - (LastSet - FirstSet)); uint16_t Bits = (ImmValue >> ShiftAmount) & 0xffff; TOut.emitRRI(Mips::ORi, TmpReg, ZeroReg, Bits, IDLoc, STI); TOut.emitRRI(Mips::DSLL, TmpReg, TmpReg, ShiftAmount, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } warnIfNoMacro(IDLoc); // The remaining case is packed with a sequence of dsll and ori with zeros // being omitted and any neighbouring dsll's being coalesced. // The highest 32-bit's are equivalent to a 32-bit immediate load. // Load bits 32-63 of ImmValue into bits 0-31 of the temporary register. if (loadImmediate(ImmValue >> 32, TmpReg, Mips::NoRegister, true, false, IDLoc, Out, STI)) return false; // Shift and accumulate into the register. If a 16-bit chunk is zero, then // skip it and defer the shift to the next chunk. unsigned ShiftCarriedForwards = 16; for (int BitNum = 16; BitNum >= 0; BitNum -= 16) { uint16_t ImmChunk = (ImmValue >> BitNum) & 0xffff; if (ImmChunk != 0) { TOut.emitDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, STI); TOut.emitRRI(Mips::ORi, TmpReg, TmpReg, ImmChunk, IDLoc, STI); ShiftCarriedForwards = 0; } ShiftCarriedForwards += 16; } ShiftCarriedForwards -= 16; // Finish any remaining shifts left by trailing zeros. if (ShiftCarriedForwards) TOut.emitDSLL(TmpReg, TmpReg, ShiftCarriedForwards, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(AdduOp, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } bool MipsAsmParser::expandLoadImm(MCInst &Inst, bool Is32BitImm, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { const MCOperand &ImmOp = Inst.getOperand(1); assert(ImmOp.isImm() && "expected immediate operand kind"); const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); if (loadImmediate(ImmOp.getImm(), DstRegOp.getReg(), Mips::NoRegister, Is32BitImm, false, IDLoc, Out, STI)) return true; return false; } bool MipsAsmParser::expandLoadAddress(unsigned DstReg, unsigned BaseReg, const MCOperand &Offset, bool Is32BitAddress, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { // la can't produce a usable address when addresses are 64-bit. if (Is32BitAddress && ABI.ArePtrs64bit()) { // FIXME: Demote this to a warning and continue as if we had 'dla' instead. // We currently can't do this because we depend on the equality // operator and N64 can end up with a GPR32/GPR64 mismatch. Error(IDLoc, "la used to load 64-bit address"); // Continue as if we had 'dla' instead. Is32BitAddress = false; return true; } // dla requires 64-bit addresses. if (!Is32BitAddress && !hasMips3()) { Error(IDLoc, "instruction requires a 64-bit architecture"); return true; } if (!Offset.isImm()) return loadAndAddSymbolAddress(Offset.getExpr(), DstReg, BaseReg, Is32BitAddress, IDLoc, Out, STI); if (!ABI.ArePtrs64bit()) { // Continue as if we had 'la' whether we had 'la' or 'dla'. Is32BitAddress = true; } return loadImmediate(Offset.getImm(), DstReg, BaseReg, Is32BitAddress, true, IDLoc, Out, STI); } bool MipsAsmParser::loadAndAddSymbolAddress(const MCExpr *SymExpr, unsigned DstReg, unsigned SrcReg, bool Is32BitSym, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); bool UseSrcReg = SrcReg != Mips::NoRegister; warnIfNoMacro(IDLoc); if (inPicMode() && ABI.IsO32()) { MCValue Res; if (!SymExpr->evaluateAsRelocatable(Res, nullptr, nullptr)) { Error(IDLoc, "expected relocatable expression"); return true; } if (Res.getSymB() != nullptr) { Error(IDLoc, "expected relocatable expression with only one symbol"); return true; } // The case where the result register is $25 is somewhat special. If the // symbol in the final relocation is external and not modified with a // constant then we must use R_MIPS_CALL16 instead of R_MIPS_GOT16. if ((DstReg == Mips::T9 || DstReg == Mips::T9_64) && !UseSrcReg && Res.getConstant() == 0 && !Res.getSymA()->getSymbol().isInSection() && !Res.getSymA()->getSymbol().isTemporary()) { const MCExpr *CallExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT_CALL, SymExpr, getContext()); TOut.emitRRX(Mips::LW, DstReg, ABI.GetGlobalPtr(), MCOperand::createExpr(CallExpr), IDLoc, STI); return false; } // The remaining cases are: // External GOT: lw $tmp, %got(symbol+offset)($gp) // >addiu $tmp, $tmp, %lo(offset) // >addiu $rd, $tmp, $rs // Local GOT: lw $tmp, %got(symbol+offset)($gp) // addiu $tmp, $tmp, %lo(symbol+offset)($gp) // >addiu $rd, $tmp, $rs // The addiu's marked with a '>' may be omitted if they are redundant. If // this happens then the last instruction must use $rd as the result // register. const MipsMCExpr *GotExpr = MipsMCExpr::create(MipsMCExpr::MEK_GOT, SymExpr, getContext()); const MCExpr *LoExpr = nullptr; if (Res.getSymA()->getSymbol().isInSection() || Res.getSymA()->getSymbol().isTemporary()) LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext()); else if (Res.getConstant() != 0) { // External symbols fully resolve the symbol with just the %got(symbol) // but we must still account for any offset to the symbol for expressions // like symbol+8. LoExpr = MCConstantExpr::create(Res.getConstant(), getContext()); } unsigned TmpReg = DstReg; if (UseSrcReg && getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // If $rs is the same as $rd, we need to use AT. // If it is not available we exit. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; TmpReg = ATReg; } TOut.emitRRX(Mips::LW, TmpReg, ABI.GetGlobalPtr(), MCOperand::createExpr(GotExpr), IDLoc, STI); if (LoExpr) TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), IDLoc, STI); if (UseSrcReg) TOut.emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, STI); return false; } const MipsMCExpr *HiExpr = MipsMCExpr::create(MipsMCExpr::MEK_HI, SymExpr, getContext()); const MipsMCExpr *LoExpr = MipsMCExpr::create(MipsMCExpr::MEK_LO, SymExpr, getContext()); // This is the 64-bit symbol address expansion. if (ABI.ArePtrs64bit() && isGP64bit()) { // We always need AT for the 64-bit expansion. // If it is not available we exit. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; const MipsMCExpr *HighestExpr = MipsMCExpr::create(MipsMCExpr::MEK_HIGHEST, SymExpr, getContext()); const MipsMCExpr *HigherExpr = MipsMCExpr::create(MipsMCExpr::MEK_HIGHER, SymExpr, getContext()); if (UseSrcReg && getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // If $rs is the same as $rd: // (d)la $rd, sym($rd) => lui $at, %highest(sym) // daddiu $at, $at, %higher(sym) // dsll $at, $at, 16 // daddiu $at, $at, %hi(sym) // dsll $at, $at, 16 // daddiu $at, $at, %lo(sym) // daddu $rd, $at, $rd TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HighestExpr), IDLoc, STI); TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HigherExpr), IDLoc, STI); TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); TOut.emitRRI(Mips::DSLL, ATReg, ATReg, 16, IDLoc, STI); TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, STI); TOut.emitRRR(Mips::DADDu, DstReg, ATReg, SrcReg, IDLoc, STI); return false; } // Otherwise, if the $rs is different from $rd or if $rs isn't specified: // (d)la $rd, sym/sym($rs) => lui $rd, %highest(sym) // lui $at, %hi(sym) // daddiu $rd, $rd, %higher(sym) // daddiu $at, $at, %lo(sym) // dsll32 $rd, $rd, 0 // daddu $rd, $rd, $at // (daddu $rd, $rd, $rs) TOut.emitRX(Mips::LUi, DstReg, MCOperand::createExpr(HighestExpr), IDLoc, STI); TOut.emitRX(Mips::LUi, ATReg, MCOperand::createExpr(HiExpr), IDLoc, STI); TOut.emitRRX(Mips::DADDiu, DstReg, DstReg, MCOperand::createExpr(HigherExpr), IDLoc, STI); TOut.emitRRX(Mips::DADDiu, ATReg, ATReg, MCOperand::createExpr(LoExpr), IDLoc, STI); TOut.emitRRI(Mips::DSLL32, DstReg, DstReg, 0, IDLoc, STI); TOut.emitRRR(Mips::DADDu, DstReg, DstReg, ATReg, IDLoc, STI); if (UseSrcReg) TOut.emitRRR(Mips::DADDu, DstReg, DstReg, SrcReg, IDLoc, STI); return false; } // And now, the 32-bit symbol address expansion: // If $rs is the same as $rd: // (d)la $rd, sym($rd) => lui $at, %hi(sym) // ori $at, $at, %lo(sym) // addu $rd, $at, $rd // Otherwise, if the $rs is different from $rd or if $rs isn't specified: // (d)la $rd, sym/sym($rs) => lui $rd, %hi(sym) // ori $rd, $rd, %lo(sym) // (addu $rd, $rd, $rs) unsigned TmpReg = DstReg; if (UseSrcReg && getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, SrcReg)) { // If $rs is the same as $rd, we need to use AT. // If it is not available we exit. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; TmpReg = ATReg; } TOut.emitRX(Mips::LUi, TmpReg, MCOperand::createExpr(HiExpr), IDLoc, STI); TOut.emitRRX(Mips::ADDiu, TmpReg, TmpReg, MCOperand::createExpr(LoExpr), IDLoc, STI); if (UseSrcReg) TOut.emitRRR(Mips::ADDu, DstReg, TmpReg, SrcReg, IDLoc, STI); else assert( getContext().getRegisterInfo()->isSuperOrSubRegisterEq(DstReg, TmpReg)); return false; } bool MipsAsmParser::expandUncondBranchMMPseudo(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); assert(getInstDesc(Inst.getOpcode()).getNumOperands() == 1 && "unexpected number of operands"); MCOperand Offset = Inst.getOperand(0); if (Offset.isExpr()) { Inst.clear(); Inst.setOpcode(Mips::BEQ_MM); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); Inst.addOperand(MCOperand::createExpr(Offset.getExpr())); } else { assert(Offset.isImm() && "expected immediate operand kind"); if (isInt<11>(Offset.getImm())) { // If offset fits into 11 bits then this instruction becomes microMIPS // 16-bit unconditional branch instruction. if (inMicroMipsMode()) Inst.setOpcode(hasMips32r6() ? Mips::BC16_MMR6 : Mips::B16_MM); } else { if (!isInt<17>(Offset.getImm())) return Error(IDLoc, "branch target out of range"); if (OffsetToAlignment(Offset.getImm(), 1LL << 1)) return Error(IDLoc, "branch to misaligned address"); Inst.clear(); Inst.setOpcode(Mips::BEQ_MM); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); Inst.addOperand(MCOperand::createReg(Mips::ZERO)); Inst.addOperand(MCOperand::createImm(Offset.getImm())); } } Out.EmitInstruction(Inst, *STI); // If .set reorder is active and branch instruction has a delay slot, // emit a NOP after it. const MCInstrDesc &MCID = getInstDesc(Inst.getOpcode()); if (MCID.hasDelaySlot() && AssemblerOptions.back()->isReorder()) TOut.emitEmptyDelaySlot(true, IDLoc, STI); return false; } bool MipsAsmParser::expandBranchImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); const MCOperand &ImmOp = Inst.getOperand(1); assert(ImmOp.isImm() && "expected immediate operand kind"); const MCOperand &MemOffsetOp = Inst.getOperand(2); assert((MemOffsetOp.isImm() || MemOffsetOp.isExpr()) && "expected immediate or expression operand"); unsigned OpCode = 0; switch(Inst.getOpcode()) { case Mips::BneImm: OpCode = Mips::BNE; break; case Mips::BeqImm: OpCode = Mips::BEQ; break; default: llvm_unreachable("Unknown immediate branch pseudo-instruction."); break; } int64_t ImmValue = ImmOp.getImm(); if (ImmValue == 0) TOut.emitRRX(OpCode, DstRegOp.getReg(), Mips::ZERO, MemOffsetOp, IDLoc, STI); else { warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; if (loadImmediate(ImmValue, ATReg, Mips::NoRegister, !isGP64bit(), true, IDLoc, Out, STI)) return true; TOut.emitRRX(OpCode, DstRegOp.getReg(), ATReg, MemOffsetOp, IDLoc, STI); } return false; } void MipsAsmParser::expandMemInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsLoad, bool IsImmOpnd) { if (IsLoad) { expandLoadInst(Inst, IDLoc, Out, STI, IsImmOpnd); return; } expandStoreInst(Inst, IDLoc, Out, STI, IsImmOpnd); } void MipsAsmParser::expandLoadInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsImmOpnd) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = Inst.getOperand(0).getReg(); unsigned BaseReg = Inst.getOperand(1).getReg(); const MCInstrDesc &Desc = getInstDesc(Inst.getOpcode()); int16_t DstRegClass = Desc.OpInfo[0].RegClass; unsigned DstRegClassID = getContext().getRegisterInfo()->getRegClass(DstRegClass).getID(); bool IsGPR = (DstRegClassID == Mips::GPR32RegClassID) || (DstRegClassID == Mips::GPR64RegClassID); if (IsImmOpnd) { // Try to use DstReg as the temporary. if (IsGPR && (BaseReg != DstReg)) { TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg, Inst.getOperand(2).getImm(), DstReg, IDLoc, STI); return; } // At this point we need AT to perform the expansions and we exit if it is // not available. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return; TOut.emitLoadWithImmOffset(Inst.getOpcode(), DstReg, BaseReg, Inst.getOperand(2).getImm(), ATReg, IDLoc, STI); return; } const MCExpr *ExprOffset = Inst.getOperand(2).getExpr(); MCOperand LoOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); MCOperand HiOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); // Try to use DstReg as the temporary. if (IsGPR && (BaseReg != DstReg)) { TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, LoOperand, DstReg, IDLoc, STI); return; } // At this point we need AT to perform the expansions and we exit if it is // not available. unsigned ATReg = getATReg(IDLoc); if (!ATReg) return; TOut.emitLoadWithSymOffset(Inst.getOpcode(), DstReg, BaseReg, HiOperand, LoOperand, ATReg, IDLoc, STI); } void MipsAsmParser::expandStoreInst(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsImmOpnd) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned SrcReg = Inst.getOperand(0).getReg(); unsigned BaseReg = Inst.getOperand(1).getReg(); if (IsImmOpnd) { TOut.emitStoreWithImmOffset(Inst.getOpcode(), SrcReg, BaseReg, Inst.getOperand(2).getImm(), [&]() { return getATReg(IDLoc); }, IDLoc, STI); return; } unsigned ATReg = getATReg(IDLoc); if (!ATReg) return; const MCExpr *ExprOffset = Inst.getOperand(2).getExpr(); MCOperand LoOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_LO, ExprOffset, getContext())); MCOperand HiOperand = MCOperand::createExpr( MipsMCExpr::create(MipsMCExpr::MEK_HI, ExprOffset, getContext())); TOut.emitStoreWithSymOffset(Inst.getOpcode(), SrcReg, BaseReg, HiOperand, LoOperand, ATReg, IDLoc, STI); } bool MipsAsmParser::expandLoadStoreMultiple(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { unsigned OpNum = Inst.getNumOperands(); unsigned Opcode = Inst.getOpcode(); unsigned NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM32_MM : Mips::LWM32_MM; assert (Inst.getOperand(OpNum - 1).isImm() && Inst.getOperand(OpNum - 2).isReg() && Inst.getOperand(OpNum - 3).isReg() && "Invalid instruction operand."); if (OpNum < 8 && Inst.getOperand(OpNum - 1).getImm() <= 60 && Inst.getOperand(OpNum - 1).getImm() >= 0 && (Inst.getOperand(OpNum - 2).getReg() == Mips::SP || Inst.getOperand(OpNum - 2).getReg() == Mips::SP_64) && (Inst.getOperand(OpNum - 3).getReg() == Mips::RA || Inst.getOperand(OpNum - 3).getReg() == Mips::RA_64)) { // It can be implemented as SWM16 or LWM16 instruction. if (inMicroMipsMode() && hasMips32r6()) NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MMR6 : Mips::LWM16_MMR6; else NewOpcode = Opcode == Mips::SWM_MM ? Mips::SWM16_MM : Mips::LWM16_MM; } Inst.setOpcode(NewOpcode); Out.EmitInstruction(Inst, *STI); return false; } bool MipsAsmParser::expandCondBranches(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); bool EmittedNoMacroWarning = false; unsigned PseudoOpcode = Inst.getOpcode(); unsigned SrcReg = Inst.getOperand(0).getReg(); const MCOperand &TrgOp = Inst.getOperand(1); const MCExpr *OffsetExpr = Inst.getOperand(2).getExpr(); unsigned ZeroSrcOpcode, ZeroTrgOpcode; bool ReverseOrderSLT, IsUnsigned, IsLikely, AcceptsEquality; unsigned TrgReg; if (TrgOp.isReg()) TrgReg = TrgOp.getReg(); else if (TrgOp.isImm()) { warnIfNoMacro(IDLoc); EmittedNoMacroWarning = true; TrgReg = getATReg(IDLoc); if (!TrgReg) return true; switch(PseudoOpcode) { default: llvm_unreachable("unknown opcode for branch pseudo-instruction"); case Mips::BLTImmMacro: PseudoOpcode = Mips::BLT; break; case Mips::BLEImmMacro: PseudoOpcode = Mips::BLE; break; case Mips::BGEImmMacro: PseudoOpcode = Mips::BGE; break; case Mips::BGTImmMacro: PseudoOpcode = Mips::BGT; break; case Mips::BLTUImmMacro: PseudoOpcode = Mips::BLTU; break; case Mips::BLEUImmMacro: PseudoOpcode = Mips::BLEU; break; case Mips::BGEUImmMacro: PseudoOpcode = Mips::BGEU; break; case Mips::BGTUImmMacro: PseudoOpcode = Mips::BGTU; break; case Mips::BLTLImmMacro: PseudoOpcode = Mips::BLTL; break; case Mips::BLELImmMacro: PseudoOpcode = Mips::BLEL; break; case Mips::BGELImmMacro: PseudoOpcode = Mips::BGEL; break; case Mips::BGTLImmMacro: PseudoOpcode = Mips::BGTL; break; case Mips::BLTULImmMacro: PseudoOpcode = Mips::BLTUL; break; case Mips::BLEULImmMacro: PseudoOpcode = Mips::BLEUL; break; case Mips::BGEULImmMacro: PseudoOpcode = Mips::BGEUL; break; case Mips::BGTULImmMacro: PseudoOpcode = Mips::BGTUL; break; } if (loadImmediate(TrgOp.getImm(), TrgReg, Mips::NoRegister, !isGP64bit(), false, IDLoc, Out, STI)) return true; } switch (PseudoOpcode) { case Mips::BLT: case Mips::BLTU: case Mips::BLTL: case Mips::BLTUL: AcceptsEquality = false; ReverseOrderSLT = false; IsUnsigned = ((PseudoOpcode == Mips::BLTU) || (PseudoOpcode == Mips::BLTUL)); IsLikely = ((PseudoOpcode == Mips::BLTL) || (PseudoOpcode == Mips::BLTUL)); ZeroSrcOpcode = Mips::BGTZ; ZeroTrgOpcode = Mips::BLTZ; break; case Mips::BLE: case Mips::BLEU: case Mips::BLEL: case Mips::BLEUL: AcceptsEquality = true; ReverseOrderSLT = true; IsUnsigned = ((PseudoOpcode == Mips::BLEU) || (PseudoOpcode == Mips::BLEUL)); IsLikely = ((PseudoOpcode == Mips::BLEL) || (PseudoOpcode == Mips::BLEUL)); ZeroSrcOpcode = Mips::BGEZ; ZeroTrgOpcode = Mips::BLEZ; break; case Mips::BGE: case Mips::BGEU: case Mips::BGEL: case Mips::BGEUL: AcceptsEquality = true; ReverseOrderSLT = false; IsUnsigned = ((PseudoOpcode == Mips::BGEU) || (PseudoOpcode == Mips::BGEUL)); IsLikely = ((PseudoOpcode == Mips::BGEL) || (PseudoOpcode == Mips::BGEUL)); ZeroSrcOpcode = Mips::BLEZ; ZeroTrgOpcode = Mips::BGEZ; break; case Mips::BGT: case Mips::BGTU: case Mips::BGTL: case Mips::BGTUL: AcceptsEquality = false; ReverseOrderSLT = true; IsUnsigned = ((PseudoOpcode == Mips::BGTU) || (PseudoOpcode == Mips::BGTUL)); IsLikely = ((PseudoOpcode == Mips::BGTL) || (PseudoOpcode == Mips::BGTUL)); ZeroSrcOpcode = Mips::BLTZ; ZeroTrgOpcode = Mips::BGTZ; break; default: llvm_unreachable("unknown opcode for branch pseudo-instruction"); } bool IsTrgRegZero = (TrgReg == Mips::ZERO); bool IsSrcRegZero = (SrcReg == Mips::ZERO); if (IsSrcRegZero && IsTrgRegZero) { // FIXME: All of these Opcode-specific if's are needed for compatibility // with GAS' behaviour. However, they may not generate the most efficient // code in some circumstances. if (PseudoOpcode == Mips::BLT) { TOut.emitRX(Mips::BLTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } if (PseudoOpcode == Mips::BLE) { TOut.emitRX(Mips::BLEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } if (PseudoOpcode == Mips::BGE) { TOut.emitRX(Mips::BGEZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } if (PseudoOpcode == Mips::BGT) { TOut.emitRX(Mips::BGTZ, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } if (PseudoOpcode == Mips::BGTU) { TOut.emitRRX(Mips::BNE, Mips::ZERO, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } if (AcceptsEquality) { // If both registers are $0 and the pseudo-branch accepts equality, it // will always be taken, so we emit an unconditional branch. TOut.emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } // If both registers are $0 and the pseudo-branch does not accept // equality, it will never be taken, so we don't have to emit anything. return false; } if (IsSrcRegZero || IsTrgRegZero) { if ((IsSrcRegZero && PseudoOpcode == Mips::BGTU) || (IsTrgRegZero && PseudoOpcode == Mips::BLTU)) { // If the $rs is $0 and the pseudo-branch is BGTU (0 > x) or // if the $rt is $0 and the pseudo-branch is BLTU (x < 0), // the pseudo-branch will never be taken, so we don't emit anything. // This only applies to unsigned pseudo-branches. return false; } if ((IsSrcRegZero && PseudoOpcode == Mips::BLEU) || (IsTrgRegZero && PseudoOpcode == Mips::BGEU)) { // If the $rs is $0 and the pseudo-branch is BLEU (0 <= x) or // if the $rt is $0 and the pseudo-branch is BGEU (x >= 0), // the pseudo-branch will always be taken, so we emit an unconditional // branch. // This only applies to unsigned pseudo-branches. TOut.emitRRX(Mips::BEQ, Mips::ZERO, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); Warning(IDLoc, "branch is always taken"); return false; } if (IsUnsigned) { // If the $rs is $0 and the pseudo-branch is BLTU (0 < x) or // if the $rt is $0 and the pseudo-branch is BGTU (x > 0), // the pseudo-branch will be taken only when the non-zero register is // different from 0, so we emit a BNEZ. // // If the $rs is $0 and the pseudo-branch is BGEU (0 >= x) or // if the $rt is $0 and the pseudo-branch is BLEU (x <= 0), // the pseudo-branch will be taken only when the non-zero register is // equal to 0, so we emit a BEQZ. // // Because only BLEU and BGEU branch on equality, we can use the // AcceptsEquality variable to decide when to emit the BEQZ. TOut.emitRRX(AcceptsEquality ? Mips::BEQ : Mips::BNE, IsSrcRegZero ? TrgReg : SrcReg, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } // If we have a signed pseudo-branch and one of the registers is $0, // we can use an appropriate compare-to-zero branch. We select which one // to use in the switch statement above. TOut.emitRX(IsSrcRegZero ? ZeroSrcOpcode : ZeroTrgOpcode, IsSrcRegZero ? TrgReg : SrcReg, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } // If neither the SrcReg nor the TrgReg are $0, we need AT to perform the // expansions. If it is not available, we return. unsigned ATRegNum = getATReg(IDLoc); if (!ATRegNum) return true; if (!EmittedNoMacroWarning) warnIfNoMacro(IDLoc); // SLT fits well with 2 of our 4 pseudo-branches: // BLT, where $rs < $rt, translates into "slt $at, $rs, $rt" and // BGT, where $rs > $rt, translates into "slt $at, $rt, $rs". // If the result of the SLT is 1, we branch, and if it's 0, we don't. // This is accomplished by using a BNEZ with the result of the SLT. // // The other 2 pseudo-branches are opposites of the above 2 (BGE with BLT // and BLE with BGT), so we change the BNEZ into a a BEQZ. // Because only BGE and BLE branch on equality, we can use the // AcceptsEquality variable to decide when to emit the BEQZ. // Note that the order of the SLT arguments doesn't change between // opposites. // // The same applies to the unsigned variants, except that SLTu is used // instead of SLT. TOut.emitRRR(IsUnsigned ? Mips::SLTu : Mips::SLT, ATRegNum, ReverseOrderSLT ? TrgReg : SrcReg, ReverseOrderSLT ? SrcReg : TrgReg, IDLoc, STI); TOut.emitRRX(IsLikely ? (AcceptsEquality ? Mips::BEQL : Mips::BNEL) : (AcceptsEquality ? Mips::BEQ : Mips::BNE), ATRegNum, Mips::ZERO, MCOperand::createExpr(OffsetExpr), IDLoc, STI); return false; } bool MipsAsmParser::expandDiv(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, const bool IsMips64, const bool Signed) { MipsTargetStreamer &TOut = getTargetStreamer(); warnIfNoMacro(IDLoc); const MCOperand &RdRegOp = Inst.getOperand(0); assert(RdRegOp.isReg() && "expected register operand kind"); unsigned RdReg = RdRegOp.getReg(); const MCOperand &RsRegOp = Inst.getOperand(1); assert(RsRegOp.isReg() && "expected register operand kind"); unsigned RsReg = RsRegOp.getReg(); const MCOperand &RtRegOp = Inst.getOperand(2); assert(RtRegOp.isReg() && "expected register operand kind"); unsigned RtReg = RtRegOp.getReg(); unsigned DivOp; unsigned ZeroReg; if (IsMips64) { DivOp = Signed ? Mips::DSDIV : Mips::DUDIV; ZeroReg = Mips::ZERO_64; } else { DivOp = Signed ? Mips::SDIV : Mips::UDIV; ZeroReg = Mips::ZERO; } bool UseTraps = useTraps(); if (RsReg == Mips::ZERO || RsReg == Mips::ZERO_64) { if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) Warning(IDLoc, "dividing zero by zero"); if (IsMips64) { if (Signed && (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64)) { if (UseTraps) { TOut.emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, STI); return false; } TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); return false; } } else { TOut.emitRR(DivOp, RsReg, RtReg, IDLoc, STI); return false; } } if (RtReg == Mips::ZERO || RtReg == Mips::ZERO_64) { Warning(IDLoc, "division by zero"); if (Signed) { if (UseTraps) { TOut.emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, STI); return false; } TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); return false; } } // FIXME: The values for these two BranchTarget variables may be different in // micromips. These magic numbers need to be removed. unsigned BranchTargetNoTraps; unsigned BranchTarget; if (UseTraps) { BranchTarget = IsMips64 ? 12 : 8; TOut.emitRRI(Mips::TEQ, RtReg, ZeroReg, 0x7, IDLoc, STI); } else { BranchTarget = IsMips64 ? 20 : 16; BranchTargetNoTraps = 8; // Branch to the li instruction. TOut.emitRRI(Mips::BNE, RtReg, ZeroReg, BranchTargetNoTraps, IDLoc, STI); } TOut.emitRR(DivOp, RsReg, RtReg, IDLoc, STI); if (!UseTraps) TOut.emitII(Mips::BREAK, 0x7, 0, IDLoc, STI); if (!Signed) { TOut.emitR(Mips::MFLO, RdReg, IDLoc, STI); return false; } unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; TOut.emitRRI(Mips::ADDiu, ATReg, ZeroReg, -1, IDLoc, STI); if (IsMips64) { // Branch to the mflo instruction. TOut.emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, STI); TOut.emitRRI(Mips::ADDiu, ATReg, ZeroReg, 1, IDLoc, STI); TOut.emitRRI(Mips::DSLL32, ATReg, ATReg, 0x1f, IDLoc, STI); } else { // Branch to the mflo instruction. TOut.emitRRI(Mips::BNE, RtReg, ATReg, BranchTarget, IDLoc, STI); TOut.emitRI(Mips::LUi, ATReg, (uint16_t)0x8000, IDLoc, STI); } if (UseTraps) TOut.emitRRI(Mips::TEQ, RsReg, ATReg, 0x6, IDLoc, STI); else { // Branch to the mflo instruction. TOut.emitRRI(Mips::BNE, RsReg, ATReg, BranchTargetNoTraps, IDLoc, STI); TOut.emitRRI(Mips::SLL, ZeroReg, ZeroReg, 0, IDLoc, STI); TOut.emitII(Mips::BREAK, 0x6, 0, IDLoc, STI); } TOut.emitR(Mips::MFLO, RdReg, IDLoc, STI); return false; } bool MipsAsmParser::expandTrunc(MCInst &Inst, bool IsDouble, bool Is64FPU, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); assert(Inst.getNumOperands() == 3 && "Invalid operand count"); assert(Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isReg() && "Invalid instruction operand."); unsigned FirstReg = Inst.getOperand(0).getReg(); unsigned SecondReg = Inst.getOperand(1).getReg(); unsigned ThirdReg = Inst.getOperand(2).getReg(); if (hasMips1() && !hasMips2()) { unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; TOut.emitRR(Mips::CFC1, ThirdReg, Mips::RA, IDLoc, STI); TOut.emitRR(Mips::CFC1, ThirdReg, Mips::RA, IDLoc, STI); TOut.emitNop(IDLoc, STI); TOut.emitRRI(Mips::ORi, ATReg, ThirdReg, 0x3, IDLoc, STI); TOut.emitRRI(Mips::XORi, ATReg, ATReg, 0x2, IDLoc, STI); TOut.emitRR(Mips::CTC1, Mips::RA, ATReg, IDLoc, STI); TOut.emitNop(IDLoc, STI); TOut.emitRR(IsDouble ? (Is64FPU ? Mips::CVT_W_D64 : Mips::CVT_W_D32) : Mips::CVT_W_S, FirstReg, SecondReg, IDLoc, STI); TOut.emitRR(Mips::CTC1, Mips::RA, ThirdReg, IDLoc, STI); TOut.emitNop(IDLoc, STI); return false; } TOut.emitRR(IsDouble ? (Is64FPU ? Mips::TRUNC_W_D64 : Mips::TRUNC_W_D32) : Mips::TRUNC_W_S, FirstReg, SecondReg, IDLoc, STI); return false; } bool MipsAsmParser::expandUlh(MCInst &Inst, bool Signed, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { if (hasMips32r6() || hasMips64r6()) { return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); // NOTE: We always need AT for ULHU, as it is always used as the source // register for one of the LBu's. warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); if (IsLargeOffset) { if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, IDLoc, Out, STI)) return true; } int64_t FirstOffset = IsLargeOffset ? 0 : OffsetValue; int64_t SecondOffset = IsLargeOffset ? 1 : (OffsetValue + 1); if (isLittle()) std::swap(FirstOffset, SecondOffset); unsigned FirstLbuDstReg = IsLargeOffset ? DstReg : ATReg; unsigned SecondLbuDstReg = IsLargeOffset ? ATReg : DstReg; unsigned LbuSrcReg = IsLargeOffset ? ATReg : SrcReg; unsigned SllReg = IsLargeOffset ? DstReg : ATReg; TOut.emitRRI(Signed ? Mips::LB : Mips::LBu, FirstLbuDstReg, LbuSrcReg, FirstOffset, IDLoc, STI); TOut.emitRRI(Mips::LBu, SecondLbuDstReg, LbuSrcReg, SecondOffset, IDLoc, STI); TOut.emitRRI(Mips::SLL, SllReg, SllReg, 8, IDLoc, STI); TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); return false; } bool MipsAsmParser::expandUsh(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { if (hasMips32r6() || hasMips64r6()) { return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); warnIfNoMacro(IDLoc); unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; bool IsLargeOffset = !(isInt<16>(OffsetValue + 1) && isInt<16>(OffsetValue)); if (IsLargeOffset) { if (loadImmediate(OffsetValue, ATReg, SrcReg, !ABI.ArePtrs64bit(), true, IDLoc, Out, STI)) return true; } int64_t FirstOffset = IsLargeOffset ? 1 : (OffsetValue + 1); int64_t SecondOffset = IsLargeOffset ? 0 : OffsetValue; if (isLittle()) std::swap(FirstOffset, SecondOffset); if (IsLargeOffset) { TOut.emitRRI(Mips::SB, DstReg, ATReg, FirstOffset, IDLoc, STI); TOut.emitRRI(Mips::SRL, DstReg, DstReg, 8, IDLoc, STI); TOut.emitRRI(Mips::SB, DstReg, ATReg, SecondOffset, IDLoc, STI); TOut.emitRRI(Mips::LBu, ATReg, ATReg, 0, IDLoc, STI); TOut.emitRRI(Mips::SLL, DstReg, DstReg, 8, IDLoc, STI); TOut.emitRRR(Mips::OR, DstReg, DstReg, ATReg, IDLoc, STI); } else { TOut.emitRRI(Mips::SB, DstReg, SrcReg, FirstOffset, IDLoc, STI); TOut.emitRRI(Mips::SRL, ATReg, DstReg, 8, IDLoc, STI); TOut.emitRRI(Mips::SB, ATReg, SrcReg, SecondOffset, IDLoc, STI); } return false; } bool MipsAsmParser::expandUxw(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { if (hasMips32r6() || hasMips64r6()) { return Error(IDLoc, "instruction not supported on mips32r6 or mips64r6"); } const MCOperand &DstRegOp = Inst.getOperand(0); assert(DstRegOp.isReg() && "expected register operand kind"); const MCOperand &SrcRegOp = Inst.getOperand(1); assert(SrcRegOp.isReg() && "expected register operand kind"); const MCOperand &OffsetImmOp = Inst.getOperand(2); assert(OffsetImmOp.isImm() && "expected immediate operand kind"); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned DstReg = DstRegOp.getReg(); unsigned SrcReg = SrcRegOp.getReg(); int64_t OffsetValue = OffsetImmOp.getImm(); // Compute left/right load/store offsets. bool IsLargeOffset = !(isInt<16>(OffsetValue + 3) && isInt<16>(OffsetValue)); int64_t LxlOffset = IsLargeOffset ? 0 : OffsetValue; int64_t LxrOffset = IsLargeOffset ? 3 : (OffsetValue + 3); if (isLittle()) std::swap(LxlOffset, LxrOffset); bool IsLoadInst = (Inst.getOpcode() == Mips::Ulw); bool DoMove = IsLoadInst && (SrcReg == DstReg) && !IsLargeOffset; unsigned TmpReg = SrcReg; if (IsLargeOffset || DoMove) { warnIfNoMacro(IDLoc); TmpReg = getATReg(IDLoc); if (!TmpReg) return true; } if (IsLargeOffset) { if (loadImmediate(OffsetValue, TmpReg, SrcReg, !ABI.ArePtrs64bit(), true, IDLoc, Out, STI)) return true; } if (DoMove) std::swap(DstReg, TmpReg); unsigned XWL = IsLoadInst ? Mips::LWL : Mips::SWL; unsigned XWR = IsLoadInst ? Mips::LWR : Mips::SWR; TOut.emitRRI(XWL, DstReg, TmpReg, LxlOffset, IDLoc, STI); TOut.emitRRI(XWR, DstReg, TmpReg, LxrOffset, IDLoc, STI); if (DoMove) TOut.emitRRR(Mips::OR, TmpReg, DstReg, Mips::ZERO, IDLoc, STI); return false; } bool MipsAsmParser::expandAliasImmediate(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); assert (Inst.getNumOperands() == 3 && "Invalid operand count"); assert (Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg() && Inst.getOperand(2).isImm() && "Invalid instruction operand."); unsigned ATReg = Mips::NoRegister; unsigned FinalDstReg = Mips::NoRegister; unsigned DstReg = Inst.getOperand(0).getReg(); unsigned SrcReg = Inst.getOperand(1).getReg(); int64_t ImmValue = Inst.getOperand(2).getImm(); bool Is32Bit = isInt<32>(ImmValue) || isUInt<32>(ImmValue); unsigned FinalOpcode = Inst.getOpcode(); if (DstReg == SrcReg) { ATReg = getATReg(Inst.getLoc()); if (!ATReg) return true; FinalDstReg = DstReg; DstReg = ATReg; } if (!loadImmediate(ImmValue, DstReg, Mips::NoRegister, Is32Bit, false, Inst.getLoc(), Out, STI)) { switch (FinalOpcode) { default: llvm_unreachable("unimplemented expansion"); case (Mips::ADDi): FinalOpcode = Mips::ADD; break; case (Mips::ADDiu): FinalOpcode = Mips::ADDu; break; case (Mips::ANDi): FinalOpcode = Mips::AND; break; case (Mips::NORImm): FinalOpcode = Mips::NOR; break; case (Mips::ORi): FinalOpcode = Mips::OR; break; case (Mips::SLTi): FinalOpcode = Mips::SLT; break; case (Mips::SLTiu): FinalOpcode = Mips::SLTu; break; case (Mips::XORi): FinalOpcode = Mips::XOR; break; } if (FinalDstReg == Mips::NoRegister) TOut.emitRRR(FinalOpcode, DstReg, DstReg, SrcReg, IDLoc, STI); else TOut.emitRRR(FinalOpcode, FinalDstReg, FinalDstReg, DstReg, IDLoc, STI); return false; } return true; } bool MipsAsmParser::expandRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); unsigned TReg = Inst.getOperand(2).getReg(); unsigned TmpReg = DReg; unsigned FirstShift = Mips::NOP; unsigned SecondShift = Mips::NOP; if (hasMips32r2()) { if (DReg == SReg) { TmpReg = getATReg(Inst.getLoc()); if (!TmpReg) return true; } if (Inst.getOpcode() == Mips::ROL) { TOut.emitRRR(Mips::SUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), STI); TOut.emitRRR(Mips::ROTRV, DReg, SReg, TmpReg, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::ROR) { TOut.emitRRR(Mips::ROTRV, DReg, SReg, TReg, Inst.getLoc(), STI); return false; } return true; } if (hasMips32()) { switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); case Mips::ROL: FirstShift = Mips::SRLV; SecondShift = Mips::SLLV; break; case Mips::ROR: FirstShift = Mips::SLLV; SecondShift = Mips::SRLV; break; } ATReg = getATReg(Inst.getLoc()); if (!ATReg) return true; TOut.emitRRR(Mips::SUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), STI); TOut.emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), STI); TOut.emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), STI); TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } return true; } bool MipsAsmParser::expandRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); int64_t ImmValue = Inst.getOperand(2).getImm(); unsigned FirstShift = Mips::NOP; unsigned SecondShift = Mips::NOP; if (hasMips32r2()) { if (Inst.getOpcode() == Mips::ROLImm) { uint64_t MaxShift = 32; uint64_t ShiftValue = ImmValue; if (ImmValue != 0) ShiftValue = MaxShift - ImmValue; TOut.emitRRI(Mips::ROTR, DReg, SReg, ShiftValue, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::RORImm) { TOut.emitRRI(Mips::ROTR, DReg, SReg, ImmValue, Inst.getLoc(), STI); return false; } return true; } if (hasMips32()) { if (ImmValue == 0) { TOut.emitRRI(Mips::SRL, DReg, SReg, 0, Inst.getLoc(), STI); return false; } switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); case Mips::ROLImm: FirstShift = Mips::SLL; SecondShift = Mips::SRL; break; case Mips::RORImm: FirstShift = Mips::SRL; SecondShift = Mips::SLL; break; } ATReg = getATReg(Inst.getLoc()); if (!ATReg) return true; TOut.emitRRI(FirstShift, ATReg, SReg, ImmValue, Inst.getLoc(), STI); TOut.emitRRI(SecondShift, DReg, SReg, 32 - ImmValue, Inst.getLoc(), STI); TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } return true; } bool MipsAsmParser::expandDRotation(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); unsigned TReg = Inst.getOperand(2).getReg(); unsigned TmpReg = DReg; unsigned FirstShift = Mips::NOP; unsigned SecondShift = Mips::NOP; if (hasMips64r2()) { if (TmpReg == SReg) { TmpReg = getATReg(Inst.getLoc()); if (!TmpReg) return true; } if (Inst.getOpcode() == Mips::DROL) { TOut.emitRRR(Mips::DSUBu, TmpReg, Mips::ZERO, TReg, Inst.getLoc(), STI); TOut.emitRRR(Mips::DROTRV, DReg, SReg, TmpReg, Inst.getLoc(), STI); return false; } if (Inst.getOpcode() == Mips::DROR) { TOut.emitRRR(Mips::DROTRV, DReg, SReg, TReg, Inst.getLoc(), STI); return false; } return true; } if (hasMips64()) { switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); case Mips::DROL: FirstShift = Mips::DSRLV; SecondShift = Mips::DSLLV; break; case Mips::DROR: FirstShift = Mips::DSLLV; SecondShift = Mips::DSRLV; break; } ATReg = getATReg(Inst.getLoc()); if (!ATReg) return true; TOut.emitRRR(Mips::DSUBu, ATReg, Mips::ZERO, TReg, Inst.getLoc(), STI); TOut.emitRRR(FirstShift, ATReg, SReg, ATReg, Inst.getLoc(), STI); TOut.emitRRR(SecondShift, DReg, SReg, TReg, Inst.getLoc(), STI); TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } return true; } bool MipsAsmParser::expandDRotationImm(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned ATReg = Mips::NoRegister; unsigned DReg = Inst.getOperand(0).getReg(); unsigned SReg = Inst.getOperand(1).getReg(); int64_t ImmValue = Inst.getOperand(2).getImm() % 64; unsigned FirstShift = Mips::NOP; unsigned SecondShift = Mips::NOP; MCInst TmpInst; if (hasMips64r2()) { unsigned FinalOpcode = Mips::NOP; if (ImmValue == 0) FinalOpcode = Mips::DROTR; else if (ImmValue % 32 == 0) FinalOpcode = Mips::DROTR32; else if ((ImmValue >= 1) && (ImmValue <= 32)) { if (Inst.getOpcode() == Mips::DROLImm) FinalOpcode = Mips::DROTR32; else FinalOpcode = Mips::DROTR; } else if (ImmValue >= 33) { if (Inst.getOpcode() == Mips::DROLImm) FinalOpcode = Mips::DROTR; else FinalOpcode = Mips::DROTR32; } uint64_t ShiftValue = ImmValue % 32; if (Inst.getOpcode() == Mips::DROLImm) ShiftValue = (32 - ImmValue % 32) % 32; TOut.emitRRI(FinalOpcode, DReg, SReg, ShiftValue, Inst.getLoc(), STI); return false; } if (hasMips64()) { if (ImmValue == 0) { TOut.emitRRI(Mips::DSRL, DReg, SReg, 0, Inst.getLoc(), STI); return false; } switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected instruction opcode"); case Mips::DROLImm: if ((ImmValue >= 1) && (ImmValue <= 31)) { FirstShift = Mips::DSLL; SecondShift = Mips::DSRL32; } if (ImmValue == 32) { FirstShift = Mips::DSLL32; SecondShift = Mips::DSRL32; } if ((ImmValue >= 33) && (ImmValue <= 63)) { FirstShift = Mips::DSLL32; SecondShift = Mips::DSRL; } break; case Mips::DRORImm: if ((ImmValue >= 1) && (ImmValue <= 31)) { FirstShift = Mips::DSRL; SecondShift = Mips::DSLL32; } if (ImmValue == 32) { FirstShift = Mips::DSRL32; SecondShift = Mips::DSLL32; } if ((ImmValue >= 33) && (ImmValue <= 63)) { FirstShift = Mips::DSRL32; SecondShift = Mips::DSLL; } break; } ATReg = getATReg(Inst.getLoc()); if (!ATReg) return true; TOut.emitRRI(FirstShift, ATReg, SReg, ImmValue % 32, Inst.getLoc(), STI); TOut.emitRRI(SecondShift, DReg, SReg, (32 - ImmValue % 32) % 32, Inst.getLoc(), STI); TOut.emitRRR(Mips::OR, DReg, DReg, ATReg, Inst.getLoc(), STI); return false; } return true; } bool MipsAsmParser::expandAbs(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { MipsTargetStreamer &TOut = getTargetStreamer(); unsigned FirstRegOp = Inst.getOperand(0).getReg(); unsigned SecondRegOp = Inst.getOperand(1).getReg(); TOut.emitRI(Mips::BGEZ, SecondRegOp, 8, IDLoc, STI); if (FirstRegOp != SecondRegOp) TOut.emitRRR(Mips::ADDu, FirstRegOp, SecondRegOp, Mips::ZERO, IDLoc, STI); else TOut.emitEmptyDelaySlot(false, IDLoc, STI); TOut.emitRRR(Mips::SUB, FirstRegOp, Mips::ZERO, SecondRegOp, IDLoc, STI); return false; } static unsigned nextReg(unsigned Reg) { switch (Reg) { case Mips::ZERO: return Mips::AT; case Mips::AT: return Mips::V0; case Mips::V0: return Mips::V1; case Mips::V1: return Mips::A0; case Mips::A0: return Mips::A1; case Mips::A1: return Mips::A2; case Mips::A2: return Mips::A3; case Mips::A3: return Mips::T0; case Mips::T0: return Mips::T1; case Mips::T1: return Mips::T2; case Mips::T2: return Mips::T3; case Mips::T3: return Mips::T4; case Mips::T4: return Mips::T5; case Mips::T5: return Mips::T6; case Mips::T6: return Mips::T7; case Mips::T7: return Mips::S0; case Mips::S0: return Mips::S1; case Mips::S1: return Mips::S2; case Mips::S2: return Mips::S3; case Mips::S3: return Mips::S4; case Mips::S4: return Mips::S5; case Mips::S5: return Mips::S6; case Mips::S6: return Mips::S7; case Mips::S7: return Mips::T8; case Mips::T8: return Mips::T9; case Mips::T9: return Mips::K0; case Mips::K0: return Mips::K1; case Mips::K1: return Mips::GP; case Mips::GP: return Mips::SP; case Mips::SP: return Mips::FP; case Mips::FP: return Mips::RA; case Mips::RA: return Mips::ZERO; default: return 0; } } // Expand 'ld $ offset($reg2)' to 'lw $, offset($reg2); // lw $>, offset+4($reg2)' // or expand 'sd $ offset($reg2)' to 'sw $, offset($reg2); // sw $>, offset+4($reg2)' // for O32. bool MipsAsmParser::expandLoadStoreDMacro(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI, bool IsLoad) { if (!isABI_O32()) return true; warnIfNoMacro(IDLoc); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned Opcode = IsLoad ? Mips::LW : Mips::SW; unsigned FirstReg = Inst.getOperand(0).getReg(); unsigned SecondReg = nextReg(FirstReg); unsigned BaseReg = Inst.getOperand(1).getReg(); if (!SecondReg) return true; warnIfRegIndexIsAT(FirstReg, IDLoc); assert(Inst.getOperand(2).isImm() && "Offset for load macro is not immediate!"); MCOperand &FirstOffset = Inst.getOperand(2); signed NextOffset = FirstOffset.getImm() + 4; MCOperand SecondOffset = MCOperand::createImm(NextOffset); if (!isInt<16>(FirstOffset.getImm()) || !isInt<16>(NextOffset)) return true; // For loads, clobber the base register with the second load instead of the // first if the BaseReg == FirstReg. if (FirstReg != BaseReg || !IsLoad) { TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); } else { TOut.emitRRX(Opcode, SecondReg, BaseReg, SecondOffset, IDLoc, STI); TOut.emitRRX(Opcode, FirstReg, BaseReg, FirstOffset, IDLoc, STI); } return false; } bool MipsAsmParser::expandSeq(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { warnIfNoMacro(IDLoc); MipsTargetStreamer &TOut = getTargetStreamer(); if (Inst.getOperand(1).getReg() != Mips::ZERO && Inst.getOperand(2).getReg() != Mips::ZERO) { TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), Inst.getOperand(2).getReg(), IDLoc, STI); TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Inst.getOperand(0).getReg(), 1, IDLoc, STI); return false; } unsigned Reg = 0; if (Inst.getOperand(1).getReg() == Mips::ZERO) { Reg = Inst.getOperand(2).getReg(); } else { Reg = Inst.getOperand(1).getReg(); } TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Reg, 1, IDLoc, STI); return false; } bool MipsAsmParser::expandSeqI(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out, const MCSubtargetInfo *STI) { warnIfNoMacro(IDLoc); MipsTargetStreamer &TOut = getTargetStreamer(); unsigned Opc; int64_t Imm = Inst.getOperand(2).getImm(); unsigned Reg = Inst.getOperand(1).getReg(); if (Imm == 0) { TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), 1, IDLoc, STI); return false; } else { if (Reg == Mips::ZERO) { Warning(IDLoc, "comparison is always false"); TOut.emitRRR(isGP64bit() ? Mips::DADDu : Mips::ADDu, Inst.getOperand(0).getReg(), Reg, Reg, IDLoc, STI); return false; } if (Imm > -0x8000 && Imm < 0) { Imm = -Imm; Opc = isGP64bit() ? Mips::DADDiu : Mips::ADDiu; } else { Opc = Mips::XORi; } } if (!isUInt<16>(Imm)) { unsigned ATReg = getATReg(IDLoc); if (!ATReg) return true; if (loadImmediate(Imm, ATReg, Mips::NoRegister, true, isGP64bit(), IDLoc, Out, STI)) return true; TOut.emitRRR(Mips::XOR, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), ATReg, IDLoc, STI); TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Inst.getOperand(0).getReg(), 1, IDLoc, STI); return false; } TOut.emitRRI(Opc, Inst.getOperand(0).getReg(), Inst.getOperand(1).getReg(), Imm, IDLoc, STI); TOut.emitRRI(Mips::SLTiu, Inst.getOperand(0).getReg(), Inst.getOperand(0).getReg(), 1, IDLoc, STI); return false; } unsigned MipsAsmParser::checkEarlyTargetMatchPredicate(MCInst &Inst, const OperandVector &Operands) { switch (Inst.getOpcode()) { default: return Match_Success; case Mips::DATI: case Mips::DAHI: case Mips::DATI_MM64R6: case Mips::DAHI_MM64R6: if (static_cast(*Operands[1]) .isValidForTie(static_cast(*Operands[2]))) return Match_Success; return Match_RequiresSameSrcAndDst; } } + unsigned MipsAsmParser::checkTargetMatchPredicate(MCInst &Inst) { switch (Inst.getOpcode()) { // As described by the MIPSR6 spec, daui must not use the zero operand for // its source operand. case Mips::DAUI: case Mips::DAUI_MM64R6: if (Inst.getOperand(1).getReg() == Mips::ZERO || Inst.getOperand(1).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; return Match_Success; // As described by the Mips32r2 spec, the registers Rd and Rs for // jalr.hb must be different. // It also applies for registers Rt and Rs of microMIPSr6 jalrc.hb instruction // and registers Rd and Base for microMIPS lwp instruction case Mips::JALR_HB: case Mips::JALRC_HB_MMR6: case Mips::JALRC_MMR6: if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) return Match_RequiresDifferentSrcAndDst; return Match_Success; case Mips::LWP_MM: case Mips::LWP_MMR6: if (Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg()) return Match_RequiresDifferentSrcAndDst; return Match_Success; case Mips::SYNC: if (Inst.getOperand(0).getImm() != 0 && !hasMips32()) return Match_NonZeroOperandForSync; return Match_Success; // As described the MIPSR6 spec, the compact branches that compare registers // must: // a) Not use the zero register. // b) Not use the same register twice. // c) rs < rt for bnec, beqc. // NB: For this case, the encoding will swap the operands as their // ordering doesn't matter. GAS performs this transformation too. // Hence, that constraint does not have to be enforced. // // The compact branches that branch iff the signed addition of two registers // would overflow must have rs >= rt. That can be handled like beqc/bnec with // operand swapping. They do not have restriction of using the zero register. case Mips::BLEZC: case Mips::BLEZC_MMR6: case Mips::BGEZC: case Mips::BGEZC_MMR6: case Mips::BGTZC: case Mips::BGTZC_MMR6: case Mips::BLTZC: case Mips::BLTZC_MMR6: case Mips::BEQZC: case Mips::BEQZC_MMR6: case Mips::BNEZC: case Mips::BNEZC_MMR6: case Mips::BLEZC64: case Mips::BGEZC64: case Mips::BGTZC64: case Mips::BLTZC64: case Mips::BEQZC64: case Mips::BNEZC64: if (Inst.getOperand(0).getReg() == Mips::ZERO || Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; return Match_Success; case Mips::BGEC: case Mips::BGEC_MMR6: case Mips::BLTC: case Mips::BLTC_MMR6: case Mips::BGEUC: case Mips::BGEUC_MMR6: case Mips::BLTUC: case Mips::BLTUC_MMR6: case Mips::BEQC: case Mips::BEQC_MMR6: case Mips::BNEC: case Mips::BNEC_MMR6: case Mips::BGEC64: case Mips::BLTC64: case Mips::BGEUC64: case Mips::BLTUC64: case Mips::BEQC64: case Mips::BNEC64: if (Inst.getOperand(0).getReg() == Mips::ZERO || Inst.getOperand(0).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; if (Inst.getOperand(1).getReg() == Mips::ZERO || Inst.getOperand(1).getReg() == Mips::ZERO_64) return Match_RequiresNoZeroRegister; if (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) return Match_RequiresDifferentOperands; return Match_Success; - default: - return Match_Success; } + + uint64_t TSFlags = getInstDesc(Inst.getOpcode()).TSFlags; + if ((TSFlags & MipsII::HasFCCRegOperand) && + (Inst.getOperand(0).getReg() != Mips::FCC0) && !hasEightFccRegisters()) + return Match_NoFCCRegisterForCurrentISA; + + return Match_Success; + } static SMLoc RefineErrorLoc(const SMLoc Loc, const OperandVector &Operands, uint64_t ErrorInfo) { if (ErrorInfo != ~0ULL && ErrorInfo < Operands.size()) { SMLoc ErrorLoc = Operands[ErrorInfo]->getStartLoc(); if (ErrorLoc == SMLoc()) return Loc; return ErrorLoc; } return Loc; } bool MipsAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { MCInst Inst; unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); switch (MatchResult) { case Match_Success: { if (processInstruction(Inst, IDLoc, Out, STI)) return true; return false; } case Match_MissingFeature: Error(IDLoc, "instruction requires a CPU feature not currently enabled"); return true; case Match_InvalidOperand: { SMLoc ErrorLoc = IDLoc; if (ErrorInfo != ~0ULL) { if (ErrorInfo >= Operands.size()) return Error(IDLoc, "too few operands for instruction"); ErrorLoc = Operands[ErrorInfo]->getStartLoc(); if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; } return Error(ErrorLoc, "invalid operand for instruction"); } case Match_NonZeroOperandForSync: return Error(IDLoc, "s-type must be zero or unspecified for pre-MIPS32 ISAs"); case Match_MnemonicFail: return Error(IDLoc, "invalid instruction"); case Match_RequiresDifferentSrcAndDst: return Error(IDLoc, "source and destination must be different"); case Match_RequiresDifferentOperands: return Error(IDLoc, "registers must be different"); case Match_RequiresNoZeroRegister: return Error(IDLoc, "invalid operand ($zero) for instruction"); case Match_RequiresSameSrcAndDst: return Error(IDLoc, "source and destination must match"); + case Match_NoFCCRegisterForCurrentISA: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "non-zero fcc register doesn't exist in current ISA level"); case Match_Immz: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected '0'"); case Match_UImm1_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 1-bit unsigned immediate"); case Match_UImm2_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 2-bit unsigned immediate"); case Match_UImm2_1: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 1 .. 4"); case Match_UImm3_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 3-bit unsigned immediate"); case Match_UImm4_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 4-bit unsigned immediate"); case Match_SImm4_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 4-bit signed immediate"); case Match_UImm5_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 5-bit unsigned immediate"); case Match_SImm5_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 5-bit signed immediate"); case Match_UImm5_1: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 1 .. 32"); case Match_UImm5_32: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 32 .. 63"); case Match_UImm5_33: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 33 .. 64"); case Match_UImm5_0_Report_UImm6: // This is used on UImm5 operands that have a corresponding UImm5_32 // operand to avoid confusing the user. return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 6-bit unsigned immediate"); case Match_UImm5_Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected both 7-bit unsigned immediate and multiple of 4"); case Match_UImmRange2_64: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range 2 .. 64"); case Match_UImm6_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 6-bit unsigned immediate"); case Match_UImm6_Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected both 8-bit unsigned immediate and multiple of 4"); case Match_SImm6_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 6-bit signed immediate"); case Match_UImm7_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 7-bit unsigned immediate"); case Match_UImm7_N1: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range -1 .. 126"); case Match_SImm7_Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected both 9-bit signed immediate and multiple of 4"); case Match_UImm8_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 8-bit unsigned immediate"); case Match_UImm10_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 10-bit unsigned immediate"); case Match_SImm10_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 10-bit signed immediate"); case Match_SImm11_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 11-bit signed immediate"); case Match_UImm16: case Match_UImm16_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 16-bit unsigned immediate"); case Match_SImm16: case Match_SImm16_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 16-bit signed immediate"); case Match_SImm19_Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected both 19-bit signed immediate and multiple of 4"); case Match_UImm20_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 20-bit unsigned immediate"); case Match_UImm26_0: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 26-bit unsigned immediate"); case Match_SImm32: case Match_SImm32_Relaxed: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 32-bit signed immediate"); case Match_UImm32_Coerced: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected 32-bit immediate"); case Match_MemSImm9: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 9-bit signed offset"); case Match_MemSImm10: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 10-bit signed offset"); case Match_MemSImm10Lsl1: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 11-bit signed offset and multiple of 2"); case Match_MemSImm10Lsl2: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 12-bit signed offset and multiple of 4"); case Match_MemSImm10Lsl3: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 13-bit signed offset and multiple of 8"); case Match_MemSImm11: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 11-bit signed offset"); case Match_MemSImm12: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 12-bit signed offset"); case Match_MemSImm16: return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected memory with 16-bit signed offset"); } llvm_unreachable("Implement any new match types added!"); } void MipsAsmParser::warnIfRegIndexIsAT(unsigned RegIndex, SMLoc Loc) { if (RegIndex != 0 && AssemblerOptions.back()->getATRegIndex() == RegIndex) Warning(Loc, "used $at (currently $" + Twine(RegIndex) + ") without \".set noat\""); } void MipsAsmParser::warnIfNoMacro(SMLoc Loc) { if (!AssemblerOptions.back()->isMacro()) Warning(Loc, "macro instruction expanded into multiple instructions"); } void MipsAsmParser::printWarningWithFixIt(const Twine &Msg, const Twine &FixMsg, SMRange Range, bool ShowColors) { getSourceManager().PrintMessage(Range.Start, SourceMgr::DK_Warning, Msg, Range, SMFixIt(Range, FixMsg), ShowColors); } int MipsAsmParser::matchCPURegisterName(StringRef Name) { int CC; CC = StringSwitch(Name) .Case("zero", 0) .Case("at", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) .Case("a3", 7) .Case("v0", 2) .Case("v1", 3) .Case("s0", 16) .Case("s1", 17) .Case("s2", 18) .Case("s3", 19) .Case("s4", 20) .Case("s5", 21) .Case("s6", 22) .Case("s7", 23) .Case("k0", 26) .Case("k1", 27) .Case("gp", 28) .Case("sp", 29) .Case("fp", 30) .Case("s8", 30) .Case("ra", 31) .Case("t0", 8) .Case("t1", 9) .Case("t2", 10) .Case("t3", 11) .Case("t4", 12) .Case("t5", 13) .Case("t6", 14) .Case("t7", 15) .Case("t8", 24) .Case("t9", 25) .Default(-1); if (!(isABI_N32() || isABI_N64())) return CC; if (12 <= CC && CC <= 15) { // Name is one of t4-t7 AsmToken RegTok = getLexer().peekTok(); SMRange RegRange = RegTok.getLocRange(); StringRef FixedName = StringSwitch(Name) .Case("t4", "t0") .Case("t5", "t1") .Case("t6", "t2") .Case("t7", "t3") .Default(""); assert(FixedName != "" && "Register name is not one of t4-t7."); printWarningWithFixIt("register names $t4-$t7 are only available in O32.", "Did you mean $" + FixedName + "?", RegRange); } // Although SGI documentation just cuts out t0-t3 for n32/n64, // GNU pushes the values of t0-t3 to override the o32/o64 values for t4-t7 // We are supporting both cases, so for t0-t3 we'll just push them to t4-t7. if (8 <= CC && CC <= 11) CC += 4; if (CC == -1) CC = StringSwitch(Name) .Case("a4", 8) .Case("a5", 9) .Case("a6", 10) .Case("a7", 11) .Case("kt0", 26) .Case("kt1", 27) .Default(-1); return CC; } int MipsAsmParser::matchHWRegsRegisterName(StringRef Name) { int CC; CC = StringSwitch(Name) .Case("hwr_cpunum", 0) .Case("hwr_synci_step", 1) .Case("hwr_cc", 2) .Case("hwr_ccres", 3) .Case("hwr_ulr", 29) .Default(-1); return CC; } int MipsAsmParser::matchFPURegisterName(StringRef Name) { if (Name[0] == 'f') { StringRef NumString = Name.substr(1); unsigned IntVal; if (NumString.getAsInteger(10, IntVal)) return -1; // This is not an integer. if (IntVal > 31) // Maximum index for fpu register. return -1; return IntVal; } return -1; } int MipsAsmParser::matchFCCRegisterName(StringRef Name) { if (Name.startswith("fcc")) { StringRef NumString = Name.substr(3); unsigned IntVal; if (NumString.getAsInteger(10, IntVal)) return -1; // This is not an integer. if (IntVal > 7) // There are only 8 fcc registers. return -1; return IntVal; } return -1; } int MipsAsmParser::matchACRegisterName(StringRef Name) { if (Name.startswith("ac")) { StringRef NumString = Name.substr(2); unsigned IntVal; if (NumString.getAsInteger(10, IntVal)) return -1; // This is not an integer. if (IntVal > 3) // There are only 3 acc registers. return -1; return IntVal; } return -1; } int MipsAsmParser::matchMSA128RegisterName(StringRef Name) { unsigned IntVal; if (Name.front() != 'w' || Name.drop_front(1).getAsInteger(10, IntVal)) return -1; if (IntVal > 31) return -1; return IntVal; } int MipsAsmParser::matchMSA128CtrlRegisterName(StringRef Name) { int CC; CC = StringSwitch(Name) .Case("msair", 0) .Case("msacsr", 1) .Case("msaaccess", 2) .Case("msasave", 3) .Case("msamodify", 4) .Case("msarequest", 5) .Case("msamap", 6) .Case("msaunmap", 7) .Default(-1); return CC; } unsigned MipsAsmParser::getATReg(SMLoc Loc) { unsigned ATIndex = AssemblerOptions.back()->getATRegIndex(); if (ATIndex == 0) { reportParseError(Loc, "pseudo-instruction requires $at, which is not available"); return 0; } unsigned AT = getReg( (isGP64bit()) ? Mips::GPR64RegClassID : Mips::GPR32RegClassID, ATIndex); return AT; } unsigned MipsAsmParser::getReg(int RC, int RegNo) { return *(getContext().getRegisterInfo()->getRegClass(RC).begin() + RegNo); } bool MipsAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseOperand\n"); // Check if the current operand has a custom associated parser, if so, try to // custom parse the operand, or fallback to the general approach. OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); if (ResTy == MatchOperand_Success) return false; // If there wasn't a custom match, try the generic matcher below. Otherwise, // there was a match, but an error occurred, in which case, just return that // the operand parsing failed. if (ResTy == MatchOperand_ParseFail) return true; DEBUG(dbgs() << ".. Generic Parser\n"); switch (getLexer().getKind()) { case AsmToken::Dollar: { // Parse the register. SMLoc S = Parser.getTok().getLoc(); // Almost all registers have been parsed by custom parsers. There is only // one exception to this. $zero (and it's alias $0) will reach this point // for div, divu, and similar instructions because it is not an operand // to the instruction definition but an explicit register. Special case // this situation for now. if (parseAnyRegister(Operands) != MatchOperand_NoMatch) return false; // Maybe it is a symbol reference. StringRef Identifier; if (Parser.parseIdentifier(Identifier)) return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); MCSymbol *Sym = getContext().getOrCreateSymbol("$" + Identifier); // Otherwise create a symbol reference. const MCExpr *Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); Operands.push_back(MipsOperand::CreateImm(Res, S, E, *this)); return false; } default: { DEBUG(dbgs() << ".. generic integer expression\n"); const MCExpr *Expr; SMLoc S = Parser.getTok().getLoc(); // Start location of the operand. if (getParser().parseExpression(Expr)) return true; SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm(Expr, S, E, *this)); return false; } } // switch(getLexer().getKind()) return true; } bool MipsAsmParser::isEvaluated(const MCExpr *Expr) { switch (Expr->getKind()) { case MCExpr::Constant: return true; case MCExpr::SymbolRef: return (cast(Expr)->getKind() != MCSymbolRefExpr::VK_None); case MCExpr::Binary: if (const MCBinaryExpr *BE = dyn_cast(Expr)) { if (!isEvaluated(BE->getLHS())) return false; return isEvaluated(BE->getRHS()); } case MCExpr::Unary: return isEvaluated(cast(Expr)->getSubExpr()); case MCExpr::Target: return true; } return false; } bool MipsAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { SmallVector, 1> Operands; OperandMatchResultTy ResTy = parseAnyRegister(Operands); if (ResTy == MatchOperand_Success) { assert(Operands.size() == 1); MipsOperand &Operand = static_cast(*Operands.front()); StartLoc = Operand.getStartLoc(); EndLoc = Operand.getEndLoc(); // AFAIK, we only support numeric registers and named GPR's in CFI // directives. // Don't worry about eating tokens before failing. Using an unrecognised // register is a parse error. if (Operand.isGPRAsmReg()) { // Resolve to GPR32 or GPR64 appropriately. RegNo = isGP64bit() ? Operand.getGPR64Reg() : Operand.getGPR32Reg(); } return (RegNo == (unsigned)-1); } assert(Operands.size() == 0); return (RegNo == (unsigned)-1); } bool MipsAsmParser::parseMemOffset(const MCExpr *&Res, bool isParenExpr) { SMLoc S; if (isParenExpr) return getParser().parseParenExprOfDepth(0, Res, S); return getParser().parseExpression(Res); } OperandMatchResultTy MipsAsmParser::parseMemOperand(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseMemOperand\n"); const MCExpr *IdVal = nullptr; SMLoc S; bool isParenExpr = false; OperandMatchResultTy Res = MatchOperand_NoMatch; // First operand is the offset. S = Parser.getTok().getLoc(); if (getLexer().getKind() == AsmToken::LParen) { Parser.Lex(); isParenExpr = true; } if (getLexer().getKind() != AsmToken::Dollar) { if (parseMemOffset(IdVal, isParenExpr)) return MatchOperand_ParseFail; const AsmToken &Tok = Parser.getTok(); // Get the next token. if (Tok.isNot(AsmToken::LParen)) { MipsOperand &Mnemonic = static_cast(*Operands[0]); if (Mnemonic.getToken() == "la" || Mnemonic.getToken() == "dla") { SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm(IdVal, S, E, *this)); return MatchOperand_Success; } if (Tok.is(AsmToken::EndOfStatement)) { SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); // Zero register assumed, add a memory operand with ZERO as its base. // "Base" will be managed by k_Memory. auto Base = MipsOperand::createGPRReg( 0, "0", getContext().getRegisterInfo(), S, E, *this); Operands.push_back( MipsOperand::CreateMem(std::move(Base), IdVal, S, E, *this)); return MatchOperand_Success; } MCBinaryExpr::Opcode Opcode; // GAS and LLVM treat comparison operators different. GAS will generate -1 // or 0, while LLVM will generate 0 or 1. Since a comparsion operator is // highly unlikely to be found in a memory offset expression, we don't // handle them. switch (Tok.getKind()) { case AsmToken::Plus: Opcode = MCBinaryExpr::Add; Parser.Lex(); break; case AsmToken::Minus: Opcode = MCBinaryExpr::Sub; Parser.Lex(); break; case AsmToken::Star: Opcode = MCBinaryExpr::Mul; Parser.Lex(); break; case AsmToken::Pipe: Opcode = MCBinaryExpr::Or; Parser.Lex(); break; case AsmToken::Amp: Opcode = MCBinaryExpr::And; Parser.Lex(); break; case AsmToken::LessLess: Opcode = MCBinaryExpr::Shl; Parser.Lex(); break; case AsmToken::GreaterGreater: Opcode = MCBinaryExpr::LShr; Parser.Lex(); break; case AsmToken::Caret: Opcode = MCBinaryExpr::Xor; Parser.Lex(); break; case AsmToken::Slash: Opcode = MCBinaryExpr::Div; Parser.Lex(); break; case AsmToken::Percent: Opcode = MCBinaryExpr::Mod; Parser.Lex(); break; default: Error(Parser.getTok().getLoc(), "'(' or expression expected"); return MatchOperand_ParseFail; } const MCExpr * NextExpr; if (getParser().parseExpression(NextExpr)) return MatchOperand_ParseFail; IdVal = MCBinaryExpr::create(Opcode, IdVal, NextExpr, getContext()); } Parser.Lex(); // Eat the '(' token. } Res = parseAnyRegister(Operands); if (Res != MatchOperand_Success) return Res; if (Parser.getTok().isNot(AsmToken::RParen)) { Error(Parser.getTok().getLoc(), "')' expected"); return MatchOperand_ParseFail; } SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Parser.Lex(); // Eat the ')' token. if (!IdVal) IdVal = MCConstantExpr::create(0, getContext()); // Replace the register operand with the memory operand. std::unique_ptr op( static_cast(Operands.back().release())); // Remove the register from the operands. // "op" will be managed by k_Memory. Operands.pop_back(); // Add the memory operand. if (const MCBinaryExpr *BE = dyn_cast(IdVal)) { int64_t Imm; if (IdVal->evaluateAsAbsolute(Imm)) IdVal = MCConstantExpr::create(Imm, getContext()); else if (BE->getLHS()->getKind() != MCExpr::SymbolRef) IdVal = MCBinaryExpr::create(BE->getOpcode(), BE->getRHS(), BE->getLHS(), getContext()); } Operands.push_back(MipsOperand::CreateMem(std::move(op), IdVal, S, E, *this)); return MatchOperand_Success; } bool MipsAsmParser::searchSymbolAlias(OperandVector &Operands) { MCAsmParser &Parser = getParser(); MCSymbol *Sym = getContext().lookupSymbol(Parser.getTok().getIdentifier()); if (Sym) { SMLoc S = Parser.getTok().getLoc(); const MCExpr *Expr; if (Sym->isVariable()) Expr = Sym->getVariableValue(); else return false; if (Expr->getKind() == MCExpr::SymbolRef) { const MCSymbolRefExpr *Ref = static_cast(Expr); StringRef DefSymbol = Ref->getSymbol().getName(); if (DefSymbol.startswith("$")) { OperandMatchResultTy ResTy = matchAnyRegisterNameWithoutDollar(Operands, DefSymbol.substr(1), S); if (ResTy == MatchOperand_Success) { Parser.Lex(); return true; } else if (ResTy == MatchOperand_ParseFail) llvm_unreachable("Should never ParseFail"); return false; } } } return false; } OperandMatchResultTy MipsAsmParser::matchAnyRegisterNameWithoutDollar(OperandVector &Operands, StringRef Identifier, SMLoc S) { int Index = matchCPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createGPRReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchHWRegsRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createHWRegsReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFPURegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFGRReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchFCCRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createFCCReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchACRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createACCReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128RegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSA128Reg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } Index = matchMSA128CtrlRegisterName(Identifier); if (Index != -1) { Operands.push_back(MipsOperand::createMSACtrlReg( Index, Identifier, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); return MatchOperand_Success; } return MatchOperand_NoMatch; } OperandMatchResultTy MipsAsmParser::matchAnyRegisterWithoutDollar(OperandVector &Operands, SMLoc S) { MCAsmParser &Parser = getParser(); auto Token = Parser.getLexer().peekTok(false); if (Token.is(AsmToken::Identifier)) { DEBUG(dbgs() << ".. identifier\n"); StringRef Identifier = Token.getIdentifier(); OperandMatchResultTy ResTy = matchAnyRegisterNameWithoutDollar(Operands, Identifier, S); return ResTy; } else if (Token.is(AsmToken::Integer)) { DEBUG(dbgs() << ".. integer\n"); Operands.push_back(MipsOperand::createNumericReg( Token.getIntVal(), Token.getString(), getContext().getRegisterInfo(), S, Token.getLoc(), *this)); return MatchOperand_Success; } DEBUG(dbgs() << Parser.getTok().getKind() << "\n"); return MatchOperand_NoMatch; } OperandMatchResultTy MipsAsmParser::parseAnyRegister(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseAnyRegister\n"); auto Token = Parser.getTok(); SMLoc S = Token.getLoc(); if (Token.isNot(AsmToken::Dollar)) { DEBUG(dbgs() << ".. !$ -> try sym aliasing\n"); if (Token.is(AsmToken::Identifier)) { if (searchSymbolAlias(Operands)) return MatchOperand_Success; } DEBUG(dbgs() << ".. !symalias -> NoMatch\n"); return MatchOperand_NoMatch; } DEBUG(dbgs() << ".. $\n"); OperandMatchResultTy ResTy = matchAnyRegisterWithoutDollar(Operands, S); if (ResTy == MatchOperand_Success) { Parser.Lex(); // $ Parser.Lex(); // identifier } return ResTy; } OperandMatchResultTy MipsAsmParser::parseJumpTarget(OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "parseJumpTarget\n"); SMLoc S = getLexer().getLoc(); // Registers are a valid target and have priority over symbols. OperandMatchResultTy ResTy = parseAnyRegister(Operands); if (ResTy != MatchOperand_NoMatch) return ResTy; // Integers and expressions are acceptable const MCExpr *Expr = nullptr; if (Parser.parseExpression(Expr)) { // We have no way of knowing if a symbol was consumed so we must ParseFail return MatchOperand_ParseFail; } Operands.push_back( MipsOperand::CreateImm(Expr, S, getLexer().getLoc(), *this)); return MatchOperand_Success; } OperandMatchResultTy MipsAsmParser::parseInvNum(OperandVector &Operands) { MCAsmParser &Parser = getParser(); const MCExpr *IdVal; // If the first token is '$' we may have register operand. if (Parser.getTok().is(AsmToken::Dollar)) return MatchOperand_NoMatch; SMLoc S = Parser.getTok().getLoc(); if (getParser().parseExpression(IdVal)) return MatchOperand_ParseFail; const MCConstantExpr *MCE = dyn_cast(IdVal); assert(MCE && "Unexpected MCExpr type."); int64_t Val = MCE->getValue(); SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); Operands.push_back(MipsOperand::CreateImm( MCConstantExpr::create(0 - Val, getContext()), S, E, *this)); return MatchOperand_Success; } OperandMatchResultTy MipsAsmParser::parseRegisterList(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SmallVector Regs; unsigned RegNo; unsigned PrevReg = Mips::NoRegister; bool RegRange = false; SmallVector, 8> TmpOperands; if (Parser.getTok().isNot(AsmToken::Dollar)) return MatchOperand_ParseFail; SMLoc S = Parser.getTok().getLoc(); while (parseAnyRegister(TmpOperands) == MatchOperand_Success) { SMLoc E = getLexer().getLoc(); MipsOperand &Reg = static_cast(*TmpOperands.back()); RegNo = isGP64bit() ? Reg.getGPR64Reg() : Reg.getGPR32Reg(); if (RegRange) { // Remove last register operand because registers from register range // should be inserted first. if ((isGP64bit() && RegNo == Mips::RA_64) || (!isGP64bit() && RegNo == Mips::RA)) { Regs.push_back(RegNo); } else { unsigned TmpReg = PrevReg + 1; while (TmpReg <= RegNo) { if ((((TmpReg < Mips::S0) || (TmpReg > Mips::S7)) && !isGP64bit()) || (((TmpReg < Mips::S0_64) || (TmpReg > Mips::S7_64)) && isGP64bit())) { Error(E, "invalid register operand"); return MatchOperand_ParseFail; } PrevReg = TmpReg; Regs.push_back(TmpReg++); } } RegRange = false; } else { if ((PrevReg == Mips::NoRegister) && ((isGP64bit() && (RegNo != Mips::S0_64) && (RegNo != Mips::RA_64)) || (!isGP64bit() && (RegNo != Mips::S0) && (RegNo != Mips::RA)))) { Error(E, "$16 or $31 expected"); return MatchOperand_ParseFail; } else if (!(((RegNo == Mips::FP || RegNo == Mips::RA || (RegNo >= Mips::S0 && RegNo <= Mips::S7)) && !isGP64bit()) || ((RegNo == Mips::FP_64 || RegNo == Mips::RA_64 || (RegNo >= Mips::S0_64 && RegNo <= Mips::S7_64)) && isGP64bit()))) { Error(E, "invalid register operand"); return MatchOperand_ParseFail; } else if ((PrevReg != Mips::NoRegister) && (RegNo != PrevReg + 1) && ((RegNo != Mips::FP && RegNo != Mips::RA && !isGP64bit()) || (RegNo != Mips::FP_64 && RegNo != Mips::RA_64 && isGP64bit()))) { Error(E, "consecutive register numbers expected"); return MatchOperand_ParseFail; } Regs.push_back(RegNo); } if (Parser.getTok().is(AsmToken::Minus)) RegRange = true; if (!Parser.getTok().isNot(AsmToken::Minus) && !Parser.getTok().isNot(AsmToken::Comma)) { Error(E, "',' or '-' expected"); return MatchOperand_ParseFail; } Lex(); // Consume comma or minus if (Parser.getTok().isNot(AsmToken::Dollar)) break; PrevReg = RegNo; } SMLoc E = Parser.getTok().getLoc(); Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); parseMemOperand(Operands); return MatchOperand_Success; } OperandMatchResultTy MipsAsmParser::parseRegisterPair(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SMLoc S = Parser.getTok().getLoc(); if (parseAnyRegister(Operands) != MatchOperand_Success) return MatchOperand_ParseFail; SMLoc E = Parser.getTok().getLoc(); MipsOperand Op = static_cast(*Operands.back()); Operands.pop_back(); Operands.push_back(MipsOperand::CreateRegPair(Op, S, E, *this)); return MatchOperand_Success; } OperandMatchResultTy MipsAsmParser::parseMovePRegPair(OperandVector &Operands) { MCAsmParser &Parser = getParser(); SmallVector, 8> TmpOperands; SmallVector Regs; if (Parser.getTok().isNot(AsmToken::Dollar)) return MatchOperand_ParseFail; SMLoc S = Parser.getTok().getLoc(); if (parseAnyRegister(TmpOperands) != MatchOperand_Success) return MatchOperand_ParseFail; MipsOperand *Reg = &static_cast(*TmpOperands.back()); unsigned RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); Regs.push_back(RegNo); SMLoc E = Parser.getTok().getLoc(); if (Parser.getTok().isNot(AsmToken::Comma)) { Error(E, "',' expected"); return MatchOperand_ParseFail; } // Remove comma. Parser.Lex(); if (parseAnyRegister(TmpOperands) != MatchOperand_Success) return MatchOperand_ParseFail; Reg = &static_cast(*TmpOperands.back()); RegNo = isGP64bit() ? Reg->getGPR64Reg() : Reg->getGPR32Reg(); Regs.push_back(RegNo); Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); return MatchOperand_Success; } /// Sometimes (i.e. load/stores) the operand may be followed immediately by /// either this. /// ::= '(', register, ')' /// handle it before we iterate so we don't get tripped up by the lack of /// a comma. bool MipsAsmParser::parseParenSuffix(StringRef Name, OperandVector &Operands) { MCAsmParser &Parser = getParser(); if (getLexer().is(AsmToken::LParen)) { Operands.push_back( MipsOperand::CreateToken("(", getLexer().getLoc(), *this)); Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RParen)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token, expected ')'"); } Operands.push_back( MipsOperand::CreateToken(")", getLexer().getLoc(), *this)); Parser.Lex(); } return false; } /// Sometimes (i.e. in MSA) the operand may be followed immediately by /// either one of these. /// ::= '[', register, ']' /// ::= '[', integer, ']' /// handle it before we iterate so we don't get tripped up by the lack of /// a comma. bool MipsAsmParser::parseBracketSuffix(StringRef Name, OperandVector &Operands) { MCAsmParser &Parser = getParser(); if (getLexer().is(AsmToken::LBrac)) { Operands.push_back( MipsOperand::CreateToken("[", getLexer().getLoc(), *this)); Parser.Lex(); if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token in argument list"); } if (Parser.getTok().isNot(AsmToken::RBrac)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token, expected ']'"); } Operands.push_back( MipsOperand::CreateToken("]", getLexer().getLoc(), *this)); Parser.Lex(); } return false; } bool MipsAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { MCAsmParser &Parser = getParser(); DEBUG(dbgs() << "ParseInstruction\n"); // We have reached first instruction, module directive are now forbidden. getTargetStreamer().forbidModuleDirective(); // Check if we have valid mnemonic if (!mnemonicIsValid(Name, 0)) { return Error(NameLoc, "unknown instruction"); } // First operand in MCInst is instruction mnemonic. Operands.push_back(MipsOperand::CreateToken(Name, NameLoc, *this)); // Read the remaining operands. if (getLexer().isNot(AsmToken::EndOfStatement)) { // Read the first operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token in argument list"); } if (getLexer().is(AsmToken::LBrac) && parseBracketSuffix(Name, Operands)) return true; // AFAIK, parenthesis suffixes are never on the first operand while (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. // Parse and remember the operand. if (parseOperand(Operands, Name)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token in argument list"); } // Parse bracket and parenthesis suffixes before we iterate if (getLexer().is(AsmToken::LBrac)) { if (parseBracketSuffix(Name, Operands)) return true; } else if (getLexer().is(AsmToken::LParen) && parseParenSuffix(Name, Operands)) return true; } } if (getLexer().isNot(AsmToken::EndOfStatement)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, "unexpected token in argument list"); } Parser.Lex(); // Consume the EndOfStatement. return false; } // FIXME: Given that these have the same name, these should both be // consistent on affecting the Parser. bool MipsAsmParser::reportParseError(Twine ErrorMsg) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, ErrorMsg); } bool MipsAsmParser::reportParseError(SMLoc Loc, Twine ErrorMsg) { return Error(Loc, ErrorMsg); } bool MipsAsmParser::parseSetNoAtDirective() { MCAsmParser &Parser = getParser(); // Line should look like: ".set noat". // Set the $at register to $0. AssemblerOptions.back()->setATRegIndex(0); Parser.Lex(); // Eat "noat". // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().emitDirectiveSetNoAt(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetAtDirective() { // Line can be: ".set at", which sets $at to $1 // or ".set at=$reg", which sets $at to $reg. MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "at". if (getLexer().is(AsmToken::EndOfStatement)) { // No register was specified, so we set $at to $1. AssemblerOptions.back()->setATRegIndex(1); getTargetStreamer().emitDirectiveSetAt(); Parser.Lex(); // Consume the EndOfStatement. return false; } if (getLexer().isNot(AsmToken::Equal)) { reportParseError("unexpected token, expected equals sign"); return false; } Parser.Lex(); // Eat "=". if (getLexer().isNot(AsmToken::Dollar)) { if (getLexer().is(AsmToken::EndOfStatement)) { reportParseError("no register specified"); return false; } else { reportParseError("unexpected token, expected dollar sign '$'"); return false; } } Parser.Lex(); // Eat "$". // Find out what "reg" is. unsigned AtRegNo; const AsmToken &Reg = Parser.getTok(); if (Reg.is(AsmToken::Identifier)) { AtRegNo = matchCPURegisterName(Reg.getIdentifier()); } else if (Reg.is(AsmToken::Integer)) { AtRegNo = Reg.getIntVal(); } else { reportParseError("unexpected token, expected identifier or integer"); return false; } // Check if $reg is a valid register. If it is, set $at to $reg. if (!AssemblerOptions.back()->setATRegIndex(AtRegNo)) { reportParseError("invalid register"); return false; } Parser.Lex(); // Eat "reg". // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().emitDirectiveSetAtWithArg(AtRegNo); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetReorderDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } AssemblerOptions.back()->setReorder(); getTargetStreamer().emitDirectiveSetReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetNoReorderDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } AssemblerOptions.back()->setNoReorder(); getTargetStreamer().emitDirectiveSetNoReorder(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetMacroDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } AssemblerOptions.back()->setMacro(); getTargetStreamer().emitDirectiveSetMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetNoMacroDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } if (AssemblerOptions.back()->isReorder()) { reportParseError("`noreorder' must be set before `nomacro'"); return false; } AssemblerOptions.back()->setNoMacro(); getTargetStreamer().emitDirectiveSetNoMacro(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetMsaDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); setFeatureBits(Mips::FeatureMSA, "msa"); getTargetStreamer().emitDirectiveSetMsa(); return false; } bool MipsAsmParser::parseSetNoMsaDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); clearFeatureBits(Mips::FeatureMSA, "msa"); getTargetStreamer().emitDirectiveSetNoMsa(); return false; } bool MipsAsmParser::parseSetNoDspDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "nodsp". // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } clearFeatureBits(Mips::FeatureDSP, "dsp"); getTargetStreamer().emitDirectiveSetNoDsp(); return false; } bool MipsAsmParser::parseSetMips16Directive() { MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "mips16". // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } setFeatureBits(Mips::FeatureMips16, "mips16"); getTargetStreamer().emitDirectiveSetMips16(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetNoMips16Directive() { MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "nomips16". // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } clearFeatureBits(Mips::FeatureMips16, "mips16"); getTargetStreamer().emitDirectiveSetNoMips16(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetFpDirective() { MCAsmParser &Parser = getParser(); MipsABIFlagsSection::FpABIKind FpAbiVal; // Line can be: .set fp=32 // .set fp=xx // .set fp=64 Parser.Lex(); // Eat fp token AsmToken Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Equal)) { reportParseError("unexpected token, expected equals sign '='"); return false; } Parser.Lex(); // Eat '=' token. Tok = Parser.getTok(); if (!parseFpABIValue(FpAbiVal, ".set")) return false; if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().emitDirectiveSetFp(FpAbiVal); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseSetOddSPRegDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "oddspreg". if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } clearFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); getTargetStreamer().emitDirectiveSetOddSPReg(); return false; } bool MipsAsmParser::parseSetNoOddSPRegDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); // Eat "nooddspreg". if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } setFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); getTargetStreamer().emitDirectiveSetNoOddSPReg(); return false; } bool MipsAsmParser::parseSetPopDirective() { MCAsmParser &Parser = getParser(); SMLoc Loc = getLexer().getLoc(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); // Always keep an element on the options "stack" to prevent the user // from changing the initial options. This is how we remember them. if (AssemblerOptions.size() == 2) return reportParseError(Loc, ".set pop with no .set push"); MCSubtargetInfo &STI = copySTI(); AssemblerOptions.pop_back(); setAvailableFeatures( ComputeAvailableFeatures(AssemblerOptions.back()->getFeatures())); STI.setFeatureBits(AssemblerOptions.back()->getFeatures()); getTargetStreamer().emitDirectiveSetPop(); return false; } bool MipsAsmParser::parseSetPushDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); // Create a copy of the current assembler options environment and push it. AssemblerOptions.push_back( make_unique(AssemblerOptions.back().get())); getTargetStreamer().emitDirectiveSetPush(); return false; } bool MipsAsmParser::parseSetSoftFloatDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); setFeatureBits(Mips::FeatureSoftFloat, "soft-float"); getTargetStreamer().emitDirectiveSetSoftFloat(); return false; } bool MipsAsmParser::parseSetHardFloatDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); clearFeatureBits(Mips::FeatureSoftFloat, "soft-float"); getTargetStreamer().emitDirectiveSetHardFloat(); return false; } bool MipsAsmParser::parseSetAssignment() { StringRef Name; const MCExpr *Value; MCAsmParser &Parser = getParser(); if (Parser.parseIdentifier(Name)) reportParseError("expected identifier after .set"); if (getLexer().isNot(AsmToken::Comma)) return reportParseError("unexpected token, expected comma"); Lex(); // Eat comma if (Parser.parseExpression(Value)) return reportParseError("expected valid expression after comma"); MCSymbol *Sym = getContext().getOrCreateSymbol(Name); Sym->setVariableValue(Value); return false; } bool MipsAsmParser::parseSetMips0Directive() { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); // Reset assembler options to their initial values. MCSubtargetInfo &STI = copySTI(); setAvailableFeatures( ComputeAvailableFeatures(AssemblerOptions.front()->getFeatures())); STI.setFeatureBits(AssemblerOptions.front()->getFeatures()); AssemblerOptions.back()->setFeatures(AssemblerOptions.front()->getFeatures()); getTargetStreamer().emitDirectiveSetMips0(); return false; } bool MipsAsmParser::parseSetArchDirective() { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::Equal)) return reportParseError("unexpected token, expected equals sign"); Parser.Lex(); StringRef Arch; if (Parser.parseIdentifier(Arch)) return reportParseError("expected arch identifier"); StringRef ArchFeatureName = StringSwitch(Arch) .Case("mips1", "mips1") .Case("mips2", "mips2") .Case("mips3", "mips3") .Case("mips4", "mips4") .Case("mips5", "mips5") .Case("mips32", "mips32") .Case("mips32r2", "mips32r2") .Case("mips32r3", "mips32r3") .Case("mips32r5", "mips32r5") .Case("mips32r6", "mips32r6") .Case("mips64", "mips64") .Case("mips64r2", "mips64r2") .Case("mips64r3", "mips64r3") .Case("mips64r5", "mips64r5") .Case("mips64r6", "mips64r6") .Case("octeon", "cnmips") .Case("r4000", "mips3") // This is an implementation of Mips3. .Default(""); if (ArchFeatureName.empty()) return reportParseError("unsupported architecture"); selectArch(ArchFeatureName); getTargetStreamer().emitDirectiveSetArch(Arch); return false; } bool MipsAsmParser::parseSetFeature(uint64_t Feature) { MCAsmParser &Parser = getParser(); Parser.Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return reportParseError("unexpected token, expected end of statement"); switch (Feature) { default: llvm_unreachable("Unimplemented feature"); case Mips::FeatureDSP: setFeatureBits(Mips::FeatureDSP, "dsp"); getTargetStreamer().emitDirectiveSetDsp(); break; case Mips::FeatureMicroMips: setFeatureBits(Mips::FeatureMicroMips, "micromips"); getTargetStreamer().emitDirectiveSetMicroMips(); break; case Mips::FeatureMips1: selectArch("mips1"); getTargetStreamer().emitDirectiveSetMips1(); break; case Mips::FeatureMips2: selectArch("mips2"); getTargetStreamer().emitDirectiveSetMips2(); break; case Mips::FeatureMips3: selectArch("mips3"); getTargetStreamer().emitDirectiveSetMips3(); break; case Mips::FeatureMips4: selectArch("mips4"); getTargetStreamer().emitDirectiveSetMips4(); break; case Mips::FeatureMips5: selectArch("mips5"); getTargetStreamer().emitDirectiveSetMips5(); break; case Mips::FeatureMips32: selectArch("mips32"); getTargetStreamer().emitDirectiveSetMips32(); break; case Mips::FeatureMips32r2: selectArch("mips32r2"); getTargetStreamer().emitDirectiveSetMips32R2(); break; case Mips::FeatureMips32r3: selectArch("mips32r3"); getTargetStreamer().emitDirectiveSetMips32R3(); break; case Mips::FeatureMips32r5: selectArch("mips32r5"); getTargetStreamer().emitDirectiveSetMips32R5(); break; case Mips::FeatureMips32r6: selectArch("mips32r6"); getTargetStreamer().emitDirectiveSetMips32R6(); break; case Mips::FeatureMips64: selectArch("mips64"); getTargetStreamer().emitDirectiveSetMips64(); break; case Mips::FeatureMips64r2: selectArch("mips64r2"); getTargetStreamer().emitDirectiveSetMips64R2(); break; case Mips::FeatureMips64r3: selectArch("mips64r3"); getTargetStreamer().emitDirectiveSetMips64R3(); break; case Mips::FeatureMips64r5: selectArch("mips64r5"); getTargetStreamer().emitDirectiveSetMips64R5(); break; case Mips::FeatureMips64r6: selectArch("mips64r6"); getTargetStreamer().emitDirectiveSetMips64R6(); break; } return false; } bool MipsAsmParser::eatComma(StringRef ErrorStr) { MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::Comma)) { SMLoc Loc = getLexer().getLoc(); return Error(Loc, ErrorStr); } Parser.Lex(); // Eat the comma. return true; } // Used to determine if .cpload, .cprestore, and .cpsetup have any effect. // In this class, it is only used for .cprestore. // FIXME: Only keep track of IsPicEnabled in one place, instead of in both // MipsTargetELFStreamer and MipsAsmParser. bool MipsAsmParser::isPicAndNotNxxAbi() { return inPicMode() && !(isABI_N32() || isABI_N64()); } bool MipsAsmParser::parseDirectiveCpLoad(SMLoc Loc) { if (AssemblerOptions.back()->isReorder()) Warning(Loc, ".cpload should be inside a noreorder section"); if (inMips16Mode()) { reportParseError(".cpload is not supported in Mips16 mode"); return false; } SmallVector, 1> Reg; OperandMatchResultTy ResTy = parseAnyRegister(Reg); if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { reportParseError("expected register containing function address"); return false; } MipsOperand &RegOpnd = static_cast(*Reg[0]); if (!RegOpnd.isGPRAsmReg()) { reportParseError(RegOpnd.getStartLoc(), "invalid register"); return false; } // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().emitDirectiveCpLoad(RegOpnd.getGPR32Reg()); return false; } bool MipsAsmParser::parseDirectiveCpRestore(SMLoc Loc) { MCAsmParser &Parser = getParser(); // Note that .cprestore is ignored if used with the N32 and N64 ABIs or if it // is used in non-PIC mode. if (inMips16Mode()) { reportParseError(".cprestore is not supported in Mips16 mode"); return false; } // Get the stack offset value. const MCExpr *StackOffset; int64_t StackOffsetVal; if (Parser.parseExpression(StackOffset)) { reportParseError("expected stack offset value"); return false; } if (!StackOffset->evaluateAsAbsolute(StackOffsetVal)) { reportParseError("stack offset is not an absolute expression"); return false; } if (StackOffsetVal < 0) { Warning(Loc, ".cprestore with negative stack offset has no effect"); IsCpRestoreSet = false; } else { IsCpRestoreSet = true; CpRestoreOffset = StackOffsetVal; } // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } if (!getTargetStreamer().emitDirectiveCpRestore( CpRestoreOffset, [&]() { return getATReg(Loc); }, Loc, STI)) return true; Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseDirectiveCPSetup() { MCAsmParser &Parser = getParser(); unsigned FuncReg; unsigned Save; bool SaveIsReg = true; SmallVector, 1> TmpReg; OperandMatchResultTy ResTy = parseAnyRegister(TmpReg); if (ResTy == MatchOperand_NoMatch) { reportParseError("expected register containing function address"); return false; } MipsOperand &FuncRegOpnd = static_cast(*TmpReg[0]); if (!FuncRegOpnd.isGPRAsmReg()) { reportParseError(FuncRegOpnd.getStartLoc(), "invalid register"); return false; } FuncReg = FuncRegOpnd.getGPR32Reg(); TmpReg.clear(); if (!eatComma("unexpected token, expected comma")) return true; ResTy = parseAnyRegister(TmpReg); if (ResTy == MatchOperand_NoMatch) { const MCExpr *OffsetExpr; int64_t OffsetVal; SMLoc ExprLoc = getLexer().getLoc(); if (Parser.parseExpression(OffsetExpr) || !OffsetExpr->evaluateAsAbsolute(OffsetVal)) { reportParseError(ExprLoc, "expected save register or stack offset"); return false; } Save = OffsetVal; SaveIsReg = false; } else { MipsOperand &SaveOpnd = static_cast(*TmpReg[0]); if (!SaveOpnd.isGPRAsmReg()) { reportParseError(SaveOpnd.getStartLoc(), "invalid register"); return false; } Save = SaveOpnd.getGPR32Reg(); } if (!eatComma("unexpected token, expected comma")) return true; const MCExpr *Expr; if (Parser.parseExpression(Expr)) { reportParseError("expected expression"); return false; } if (Expr->getKind() != MCExpr::SymbolRef) { reportParseError("expected symbol"); return false; } const MCSymbolRefExpr *Ref = static_cast(Expr); CpSaveLocation = Save; CpSaveLocationIsRegister = SaveIsReg; getTargetStreamer().emitDirectiveCpsetup(FuncReg, Save, Ref->getSymbol(), SaveIsReg); return false; } bool MipsAsmParser::parseDirectiveCPReturn() { getTargetStreamer().emitDirectiveCpreturn(CpSaveLocation, CpSaveLocationIsRegister); return false; } bool MipsAsmParser::parseDirectiveNaN() { MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::EndOfStatement)) { const AsmToken &Tok = Parser.getTok(); if (Tok.getString() == "2008") { Parser.Lex(); getTargetStreamer().emitDirectiveNaN2008(); return false; } else if (Tok.getString() == "legacy") { Parser.Lex(); getTargetStreamer().emitDirectiveNaNLegacy(); return false; } } // If we don't recognize the option passed to the .nan // directive (e.g. no option or unknown option), emit an error. reportParseError("invalid option in .nan directive"); return false; } bool MipsAsmParser::parseDirectiveSet() { MCAsmParser &Parser = getParser(); // Get the next token. const AsmToken &Tok = Parser.getTok(); if (Tok.getString() == "noat") { return parseSetNoAtDirective(); } else if (Tok.getString() == "at") { return parseSetAtDirective(); } else if (Tok.getString() == "arch") { return parseSetArchDirective(); } else if (Tok.getString() == "fp") { return parseSetFpDirective(); } else if (Tok.getString() == "oddspreg") { return parseSetOddSPRegDirective(); } else if (Tok.getString() == "nooddspreg") { return parseSetNoOddSPRegDirective(); } else if (Tok.getString() == "pop") { return parseSetPopDirective(); } else if (Tok.getString() == "push") { return parseSetPushDirective(); } else if (Tok.getString() == "reorder") { return parseSetReorderDirective(); } else if (Tok.getString() == "noreorder") { return parseSetNoReorderDirective(); } else if (Tok.getString() == "macro") { return parseSetMacroDirective(); } else if (Tok.getString() == "nomacro") { return parseSetNoMacroDirective(); } else if (Tok.getString() == "mips16") { return parseSetMips16Directive(); } else if (Tok.getString() == "nomips16") { return parseSetNoMips16Directive(); } else if (Tok.getString() == "nomicromips") { clearFeatureBits(Mips::FeatureMicroMips, "micromips"); getTargetStreamer().emitDirectiveSetNoMicroMips(); Parser.eatToEndOfStatement(); return false; } else if (Tok.getString() == "micromips") { return parseSetFeature(Mips::FeatureMicroMips); } else if (Tok.getString() == "mips0") { return parseSetMips0Directive(); } else if (Tok.getString() == "mips1") { return parseSetFeature(Mips::FeatureMips1); } else if (Tok.getString() == "mips2") { return parseSetFeature(Mips::FeatureMips2); } else if (Tok.getString() == "mips3") { return parseSetFeature(Mips::FeatureMips3); } else if (Tok.getString() == "mips4") { return parseSetFeature(Mips::FeatureMips4); } else if (Tok.getString() == "mips5") { return parseSetFeature(Mips::FeatureMips5); } else if (Tok.getString() == "mips32") { return parseSetFeature(Mips::FeatureMips32); } else if (Tok.getString() == "mips32r2") { return parseSetFeature(Mips::FeatureMips32r2); } else if (Tok.getString() == "mips32r3") { return parseSetFeature(Mips::FeatureMips32r3); } else if (Tok.getString() == "mips32r5") { return parseSetFeature(Mips::FeatureMips32r5); } else if (Tok.getString() == "mips32r6") { return parseSetFeature(Mips::FeatureMips32r6); } else if (Tok.getString() == "mips64") { return parseSetFeature(Mips::FeatureMips64); } else if (Tok.getString() == "mips64r2") { return parseSetFeature(Mips::FeatureMips64r2); } else if (Tok.getString() == "mips64r3") { return parseSetFeature(Mips::FeatureMips64r3); } else if (Tok.getString() == "mips64r5") { return parseSetFeature(Mips::FeatureMips64r5); } else if (Tok.getString() == "mips64r6") { return parseSetFeature(Mips::FeatureMips64r6); } else if (Tok.getString() == "dsp") { return parseSetFeature(Mips::FeatureDSP); } else if (Tok.getString() == "nodsp") { return parseSetNoDspDirective(); } else if (Tok.getString() == "msa") { return parseSetMsaDirective(); } else if (Tok.getString() == "nomsa") { return parseSetNoMsaDirective(); } else if (Tok.getString() == "softfloat") { return parseSetSoftFloatDirective(); } else if (Tok.getString() == "hardfloat") { return parseSetHardFloatDirective(); } else { // It is just an identifier, look for an assignment. parseSetAssignment(); return false; } return true; } /// parseDataDirective /// ::= .word [ expression (, expression)* ] bool MipsAsmParser::parseDataDirective(unsigned Size, SMLoc L) { MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { const MCExpr *Value; if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitValue(Value, Size); if (getLexer().is(AsmToken::EndOfStatement)) break; if (getLexer().isNot(AsmToken::Comma)) return Error(L, "unexpected token, expected comma"); Parser.Lex(); } } Parser.Lex(); return false; } /// parseDirectiveGpWord /// ::= .gpword local_sym bool MipsAsmParser::parseDirectiveGpWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitGPRel32Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitGPRel32Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveGpDWord /// ::= .gpdword local_sym bool MipsAsmParser::parseDirectiveGpDWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitGPRel64Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitGPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveDtpRelWord /// ::= .dtprelword tls_sym bool MipsAsmParser::parseDirectiveDtpRelWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitDTPRel32Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitDTPRel32Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveDtpRelDWord /// ::= .dtpreldword tls_sym bool MipsAsmParser::parseDirectiveDtpRelDWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitDTPRel64Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitDTPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveTpRelWord /// ::= .tprelword tls_sym bool MipsAsmParser::parseDirectiveTpRelWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitTPRel32Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitTPRel32Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveTpRelDWord /// ::= .tpreldword tls_sym bool MipsAsmParser::parseDirectiveTpRelDWord() { MCAsmParser &Parser = getParser(); const MCExpr *Value; // EmitTPRel64Value requires an expression, so we are using base class // method to evaluate the expression. if (getParser().parseExpression(Value)) return true; getParser().getStreamer().EmitTPRel64Value(Value); if (getLexer().isNot(AsmToken::EndOfStatement)) return Error(getLexer().getLoc(), "unexpected token, expected end of statement"); Parser.Lex(); // Eat EndOfStatement token. return false; } bool MipsAsmParser::parseDirectiveOption() { MCAsmParser &Parser = getParser(); // Get the option token. AsmToken Tok = Parser.getTok(); // At the moment only identifiers are supported. if (Tok.isNot(AsmToken::Identifier)) { return Error(Parser.getTok().getLoc(), "unexpected token, expected identifier"); } StringRef Option = Tok.getIdentifier(); if (Option == "pic0") { // MipsAsmParser needs to know if the current PIC mode changes. IsPicEnabled = false; getTargetStreamer().emitDirectiveOptionPic0(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { return Error(Parser.getTok().getLoc(), "unexpected token, expected end of statement"); } return false; } if (Option == "pic2") { // MipsAsmParser needs to know if the current PIC mode changes. IsPicEnabled = true; getTargetStreamer().emitDirectiveOptionPic2(); Parser.Lex(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { return Error(Parser.getTok().getLoc(), "unexpected token, expected end of statement"); } return false; } // Unknown option. Warning(Parser.getTok().getLoc(), "unknown option, expected 'pic0' or 'pic2'"); Parser.eatToEndOfStatement(); return false; } /// parseInsnDirective /// ::= .insn bool MipsAsmParser::parseInsnDirective() { // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } // The actual label marking happens in // MipsELFStreamer::createPendingLabelRelocs(). getTargetStreamer().emitDirectiveInsn(); getParser().Lex(); // Eat EndOfStatement token. return false; } /// parseSSectionDirective /// ::= .sbss /// ::= .sdata bool MipsAsmParser::parseSSectionDirective(StringRef Section, unsigned Type) { // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } MCSection *ELFSection = getContext().getELFSection( Section, Type, ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); getParser().getStreamer().SwitchSection(ELFSection); getParser().Lex(); // Eat EndOfStatement token. return false; } /// parseDirectiveModule /// ::= .module oddspreg /// ::= .module nooddspreg /// ::= .module fp=value /// ::= .module softfloat /// ::= .module hardfloat bool MipsAsmParser::parseDirectiveModule() { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); SMLoc L = Lexer.getLoc(); if (!getTargetStreamer().isModuleDirectiveAllowed()) { // TODO : get a better message. reportParseError(".module directive must appear before any code"); return false; } StringRef Option; if (Parser.parseIdentifier(Option)) { reportParseError("expected .module option identifier"); return false; } if (Option == "oddspreg") { clearModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); // Synchronize the abiflags information with the FeatureBits information we // changed above. getTargetStreamer().updateABIInfo(*this); // If printing assembly, use the recently updated abiflags information. // If generating ELF, don't do anything (the .MIPS.abiflags section gets // emitted at the end). getTargetStreamer().emitDirectiveModuleOddSPReg(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } return false; // parseDirectiveModule has finished successfully. } else if (Option == "nooddspreg") { if (!isABI_O32()) { return Error(L, "'.module nooddspreg' requires the O32 ABI"); } setModuleFeatureBits(Mips::FeatureNoOddSPReg, "nooddspreg"); // Synchronize the abiflags information with the FeatureBits information we // changed above. getTargetStreamer().updateABIInfo(*this); // If printing assembly, use the recently updated abiflags information. // If generating ELF, don't do anything (the .MIPS.abiflags section gets // emitted at the end). getTargetStreamer().emitDirectiveModuleOddSPReg(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } return false; // parseDirectiveModule has finished successfully. } else if (Option == "fp") { return parseDirectiveModuleFP(); } else if (Option == "softfloat") { setModuleFeatureBits(Mips::FeatureSoftFloat, "soft-float"); // Synchronize the ABI Flags information with the FeatureBits information we // updated above. getTargetStreamer().updateABIInfo(*this); // If printing assembly, use the recently updated ABI Flags information. // If generating ELF, don't do anything (the .MIPS.abiflags section gets // emitted later). getTargetStreamer().emitDirectiveModuleSoftFloat(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } return false; // parseDirectiveModule has finished successfully. } else if (Option == "hardfloat") { clearModuleFeatureBits(Mips::FeatureSoftFloat, "soft-float"); // Synchronize the ABI Flags information with the FeatureBits information we // updated above. getTargetStreamer().updateABIInfo(*this); // If printing assembly, use the recently updated ABI Flags information. // If generating ELF, don't do anything (the .MIPS.abiflags section gets // emitted later). getTargetStreamer().emitDirectiveModuleHardFloat(); // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } return false; // parseDirectiveModule has finished successfully. } else { return Error(L, "'" + Twine(Option) + "' is not a valid .module option."); } } /// parseDirectiveModuleFP /// ::= =32 /// ::= =xx /// ::= =64 bool MipsAsmParser::parseDirectiveModuleFP() { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); if (Lexer.isNot(AsmToken::Equal)) { reportParseError("unexpected token, expected equals sign '='"); return false; } Parser.Lex(); // Eat '=' token. MipsABIFlagsSection::FpABIKind FpABI; if (!parseFpABIValue(FpABI, ".module")) return false; if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } // Synchronize the abiflags information with the FeatureBits information we // changed above. getTargetStreamer().updateABIInfo(*this); // If printing assembly, use the recently updated abiflags information. // If generating ELF, don't do anything (the .MIPS.abiflags section gets // emitted at the end). getTargetStreamer().emitDirectiveModuleFP(); Parser.Lex(); // Consume the EndOfStatement. return false; } bool MipsAsmParser::parseFpABIValue(MipsABIFlagsSection::FpABIKind &FpABI, StringRef Directive) { MCAsmParser &Parser = getParser(); MCAsmLexer &Lexer = getLexer(); bool ModuleLevelOptions = Directive == ".module"; if (Lexer.is(AsmToken::Identifier)) { StringRef Value = Parser.getTok().getString(); Parser.Lex(); if (Value != "xx") { reportParseError("unsupported value, expected 'xx', '32' or '64'"); return false; } if (!isABI_O32()) { reportParseError("'" + Directive + " fp=xx' requires the O32 ABI"); return false; } FpABI = MipsABIFlagsSection::FpABIKind::XX; if (ModuleLevelOptions) { setModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); clearModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); } else { setFeatureBits(Mips::FeatureFPXX, "fpxx"); clearFeatureBits(Mips::FeatureFP64Bit, "fp64"); } return true; } if (Lexer.is(AsmToken::Integer)) { unsigned Value = Parser.getTok().getIntVal(); Parser.Lex(); if (Value != 32 && Value != 64) { reportParseError("unsupported value, expected 'xx', '32' or '64'"); return false; } if (Value == 32) { if (!isABI_O32()) { reportParseError("'" + Directive + " fp=32' requires the O32 ABI"); return false; } FpABI = MipsABIFlagsSection::FpABIKind::S32; if (ModuleLevelOptions) { clearModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); clearModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); } else { clearFeatureBits(Mips::FeatureFPXX, "fpxx"); clearFeatureBits(Mips::FeatureFP64Bit, "fp64"); } } else { FpABI = MipsABIFlagsSection::FpABIKind::S64; if (ModuleLevelOptions) { clearModuleFeatureBits(Mips::FeatureFPXX, "fpxx"); setModuleFeatureBits(Mips::FeatureFP64Bit, "fp64"); } else { clearFeatureBits(Mips::FeatureFPXX, "fpxx"); setFeatureBits(Mips::FeatureFP64Bit, "fp64"); } } return true; } return false; } bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { // This returns false if this function recognizes the directive // regardless of whether it is successfully handles or reports an // error. Otherwise it returns true to give the generic parser a // chance at recognizing it. MCAsmParser &Parser = getParser(); StringRef IDVal = DirectiveID.getString(); if (IDVal == ".cpload") { parseDirectiveCpLoad(DirectiveID.getLoc()); return false; } if (IDVal == ".cprestore") { parseDirectiveCpRestore(DirectiveID.getLoc()); return false; } if (IDVal == ".dword") { parseDataDirective(8, DirectiveID.getLoc()); return false; } if (IDVal == ".ent") { StringRef SymbolName; if (Parser.parseIdentifier(SymbolName)) { reportParseError("expected identifier after .ent"); return false; } // There's an undocumented extension that allows an integer to // follow the name of the procedure which AFAICS is ignored by GAS. // Example: .ent foo,2 if (getLexer().isNot(AsmToken::EndOfStatement)) { if (getLexer().isNot(AsmToken::Comma)) { // Even though we accept this undocumented extension for compatibility // reasons, the additional integer argument does not actually change // the behaviour of the '.ent' directive, so we would like to discourage // its use. We do this by not referring to the extended version in // error messages which are not directly related to its use. reportParseError("unexpected token, expected end of statement"); return false; } Parser.Lex(); // Eat the comma. const MCExpr *DummyNumber; int64_t DummyNumberVal; // If the user was explicitly trying to use the extended version, // we still give helpful extension-related error messages. if (Parser.parseExpression(DummyNumber)) { reportParseError("expected number after comma"); return false; } if (!DummyNumber->evaluateAsAbsolute(DummyNumberVal)) { reportParseError("expected an absolute expression after comma"); return false; } } // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); getTargetStreamer().emitDirectiveEnt(*Sym); CurrentFn = Sym; IsCpRestoreSet = false; return false; } if (IDVal == ".end") { StringRef SymbolName; if (Parser.parseIdentifier(SymbolName)) { reportParseError("expected identifier after .end"); return false; } if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } if (CurrentFn == nullptr) { reportParseError(".end used without .ent"); return false; } if ((SymbolName != CurrentFn->getName())) { reportParseError(".end symbol does not match .ent symbol"); return false; } getTargetStreamer().emitDirectiveEnd(SymbolName); CurrentFn = nullptr; IsCpRestoreSet = false; return false; } if (IDVal == ".frame") { // .frame $stack_reg, frame_size_in_bytes, $return_reg SmallVector, 1> TmpReg; OperandMatchResultTy ResTy = parseAnyRegister(TmpReg); if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { reportParseError("expected stack register"); return false; } MipsOperand &StackRegOpnd = static_cast(*TmpReg[0]); if (!StackRegOpnd.isGPRAsmReg()) { reportParseError(StackRegOpnd.getStartLoc(), "expected general purpose register"); return false; } unsigned StackReg = StackRegOpnd.getGPR32Reg(); if (Parser.getTok().is(AsmToken::Comma)) Parser.Lex(); else { reportParseError("unexpected token, expected comma"); return false; } // Parse the frame size. const MCExpr *FrameSize; int64_t FrameSizeVal; if (Parser.parseExpression(FrameSize)) { reportParseError("expected frame size value"); return false; } if (!FrameSize->evaluateAsAbsolute(FrameSizeVal)) { reportParseError("frame size not an absolute expression"); return false; } if (Parser.getTok().is(AsmToken::Comma)) Parser.Lex(); else { reportParseError("unexpected token, expected comma"); return false; } // Parse the return register. TmpReg.clear(); ResTy = parseAnyRegister(TmpReg); if (ResTy == MatchOperand_NoMatch || ResTy == MatchOperand_ParseFail) { reportParseError("expected return register"); return false; } MipsOperand &ReturnRegOpnd = static_cast(*TmpReg[0]); if (!ReturnRegOpnd.isGPRAsmReg()) { reportParseError(ReturnRegOpnd.getStartLoc(), "expected general purpose register"); return false; } // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().emitFrame(StackReg, FrameSizeVal, ReturnRegOpnd.getGPR32Reg()); IsCpRestoreSet = false; return false; } if (IDVal == ".set") { parseDirectiveSet(); return false; } if (IDVal == ".mask" || IDVal == ".fmask") { // .mask bitmask, frame_offset // bitmask: One bit for each register used. // frame_offset: Offset from Canonical Frame Address ($sp on entry) where // first register is expected to be saved. // Examples: // .mask 0x80000000, -4 // .fmask 0x80000000, -4 // // Parse the bitmask const MCExpr *BitMask; int64_t BitMaskVal; if (Parser.parseExpression(BitMask)) { reportParseError("expected bitmask value"); return false; } if (!BitMask->evaluateAsAbsolute(BitMaskVal)) { reportParseError("bitmask not an absolute expression"); return false; } if (Parser.getTok().is(AsmToken::Comma)) Parser.Lex(); else { reportParseError("unexpected token, expected comma"); return false; } // Parse the frame_offset const MCExpr *FrameOffset; int64_t FrameOffsetVal; if (Parser.parseExpression(FrameOffset)) { reportParseError("expected frame offset value"); return false; } if (!FrameOffset->evaluateAsAbsolute(FrameOffsetVal)) { reportParseError("frame offset not an absolute expression"); return false; } // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } if (IDVal == ".mask") getTargetStreamer().emitMask(BitMaskVal, FrameOffsetVal); else getTargetStreamer().emitFMask(BitMaskVal, FrameOffsetVal); return false; } if (IDVal == ".nan") return parseDirectiveNaN(); if (IDVal == ".gpword") { parseDirectiveGpWord(); return false; } if (IDVal == ".gpdword") { parseDirectiveGpDWord(); return false; } if (IDVal == ".dtprelword") { parseDirectiveDtpRelWord(); return false; } if (IDVal == ".dtpreldword") { parseDirectiveDtpRelDWord(); return false; } if (IDVal == ".tprelword") { parseDirectiveTpRelWord(); return false; } if (IDVal == ".tpreldword") { parseDirectiveTpRelDWord(); return false; } if (IDVal == ".word") { parseDataDirective(4, DirectiveID.getLoc()); return false; } if (IDVal == ".hword") { parseDataDirective(2, DirectiveID.getLoc()); return false; } if (IDVal == ".option") { parseDirectiveOption(); return false; } if (IDVal == ".abicalls") { getTargetStreamer().emitDirectiveAbiCalls(); if (Parser.getTok().isNot(AsmToken::EndOfStatement)) { Error(Parser.getTok().getLoc(), "unexpected token, expected end of statement"); } return false; } if (IDVal == ".cpsetup") { parseDirectiveCPSetup(); return false; } if (IDVal == ".cpreturn") { parseDirectiveCPReturn(); return false; } if (IDVal == ".module") { parseDirectiveModule(); return false; } if (IDVal == ".llvm_internal_mips_reallow_module_directive") { parseInternalDirectiveReallowModule(); return false; } if (IDVal == ".insn") { parseInsnDirective(); return false; } if (IDVal == ".sbss") { parseSSectionDirective(IDVal, ELF::SHT_NOBITS); return false; } if (IDVal == ".sdata") { parseSSectionDirective(IDVal, ELF::SHT_PROGBITS); return false; } return true; } bool MipsAsmParser::parseInternalDirectiveReallowModule() { // If this is not the end of the statement, report an error. if (getLexer().isNot(AsmToken::EndOfStatement)) { reportParseError("unexpected token, expected end of statement"); return false; } getTargetStreamer().reallowModuleDirective(); getParser().Lex(); // Eat EndOfStatement token. return false; } extern "C" void LLVMInitializeMipsAsmParser() { RegisterMCAsmParser X(getTheMipsTarget()); RegisterMCAsmParser Y(getTheMipselTarget()); RegisterMCAsmParser A(getTheMips64Target()); RegisterMCAsmParser B(getTheMips64elTarget()); } #define GET_REGISTER_MATCHER #define GET_MATCHER_IMPLEMENTATION #include "MipsGenAsmMatcher.inc" Index: vendor/llvm/dist/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h (revision 313056) @@ -1,132 +1,134 @@ //===-- MipsBaseInfo.h - Top level definitions for MIPS MC ------*- 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 small standalone helper functions and enum definitions for // the Mips target useful for the compiler back-end and the MC libraries. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H #define LLVM_LIB_TARGET_MIPS_MCTARGETDESC_MIPSBASEINFO_H #include "MipsFixupKinds.h" #include "MipsMCTargetDesc.h" #include "llvm/MC/MCExpr.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" namespace llvm { /// MipsII - This namespace holds all of the target specific flags that /// instruction info tracks. /// namespace MipsII { /// Target Operand Flag enum. enum TOF { //===------------------------------------------------------------------===// // Mips Specific MachineOperand flags. MO_NO_FLAG, /// MO_GOT - Represents the offset into the global offset table at which /// the address the relocation entry symbol resides during execution. MO_GOT, /// MO_GOT_CALL - Represents the offset into the global offset table at /// which the address of a call site relocation entry symbol resides /// during execution. This is different from the above since this flag /// can only be present in call instructions. MO_GOT_CALL, /// MO_GPREL - Represents the offset from the current gp value to be used /// for the relocatable object file being produced. MO_GPREL, /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol /// address. MO_ABS_HI, MO_ABS_LO, /// MO_TLSGD - Represents the offset into the global offset table at which // the module ID and TSL block offset reside during execution (General // Dynamic TLS). MO_TLSGD, /// MO_TLSLDM - Represents the offset into the global offset table at which // the module ID and TSL block offset reside during execution (Local // Dynamic TLS). MO_TLSLDM, MO_DTPREL_HI, MO_DTPREL_LO, /// MO_GOTTPREL - Represents the offset from the thread pointer (Initial // Exec TLS). MO_GOTTPREL, /// MO_TPREL_HI/LO - Represents the hi and low part of the offset from // the thread pointer (Local Exec TLS). MO_TPREL_HI, MO_TPREL_LO, // N32/64 Flags. MO_GPOFF_HI, MO_GPOFF_LO, MO_GOT_DISP, MO_GOT_PAGE, MO_GOT_OFST, /// MO_HIGHER/HIGHEST - Represents the highest or higher half word of a /// 64-bit symbol address. MO_HIGHER, MO_HIGHEST, /// MO_GOT_HI16/LO16, MO_CALL_HI16/LO16 - Relocations used for large GOTs. MO_GOT_HI16, MO_GOT_LO16, MO_CALL_HI16, MO_CALL_LO16 }; enum { //===------------------------------------------------------------------===// // Instruction encodings. These are the standard/most common forms for // Mips instructions. // // Pseudo - This represents an instruction that is a pseudo instruction // or one that has not been implemented yet. It is illegal to code generate // it, but tolerated for intermediate implementation stages. Pseudo = 0, /// FrmR - This form is for instructions of the format R. FrmR = 1, /// FrmI - This form is for instructions of the format I. FrmI = 2, /// FrmJ - This form is for instructions of the format J. FrmJ = 3, /// FrmFR - This form is for instructions of the format FR. FrmFR = 4, /// FrmFI - This form is for instructions of the format FI. FrmFI = 5, /// FrmOther - This form is for instructions that have no specific format. FrmOther = 6, FormMask = 15, /// IsCTI - Instruction is a Control Transfer Instruction. IsCTI = 1 << 4, /// HasForbiddenSlot - Instruction has a forbidden slot. HasForbiddenSlot = 1 << 5, /// IsPCRelativeLoad - A Load instruction with implicit source register /// ($pc) with explicit offset and destination register - IsPCRelativeLoad = 1 << 6 + IsPCRelativeLoad = 1 << 6, + /// HasFCCRegOperand - Instruction uses an $fcc register. + HasFCCRegOperand = 1 << 7 }; } } #endif Index: vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFPU.td =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFPU.td (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFPU.td (revision 313056) @@ -1,180 +1,283 @@ let isCodeGenOnly = 1, Predicates = [InMicroMips] in { def FADD_S_MM : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>, ADDS_FM_MM<0, 0x30>; def FDIV_S_MM : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>, ADDS_FM_MM<0, 0xf0>; def FMUL_S_MM : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>, ADDS_FM_MM<0, 0xb0>; def FSUB_S_MM : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, ADDS_FM_MM<0, 0x70>; def FADD_MM : MMRel, ADDS_FT<"add.d", AFGR64Opnd, II_ADD_D, 1, fadd>, ADDS_FM_MM<1, 0x30>; def FDIV_MM : MMRel, ADDS_FT<"div.d", AFGR64Opnd, II_DIV_D, 0, fdiv>, ADDS_FM_MM<1, 0xf0>; def FMUL_MM : MMRel, ADDS_FT<"mul.d", AFGR64Opnd, II_MUL_D, 1, fmul>, ADDS_FM_MM<1, 0xb0>; def FSUB_MM : MMRel, ADDS_FT<"sub.d", AFGR64Opnd, II_SUB_D, 0, fsub>, ADDS_FM_MM<1, 0x70>; def LWXC1_MM : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, LWXC1_FM_MM<0x48>, INSN_MIPS4_32R2_NOT_32R6_64R6; def SWXC1_MM : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM_MM<0x88>, INSN_MIPS4_32R2_NOT_32R6_64R6; def LUXC1_MM : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, LWXC1_FM_MM<0x148>, INSN_MIPS5_32R2_NOT_32R6_64R6; def SUXC1_MM : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM_MM<0x188>, INSN_MIPS5_32R2_NOT_32R6_64R6; def FCMP_S32_MM : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, - CEQS_FM_MM<0>; + CEQS_FM_MM<0> { + // FIXME: This is a required to work around the fact that these instructions + // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the + // fcc register set is used directly. + bits<3> fcc = 0; +} + def FCMP_D32_MM : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, - CEQS_FM_MM<1>; + CEQS_FM_MM<1> { + // FIXME: This is a required to work around the fact that these instructions + // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the + // fcc register set is used directly. + bits<3> fcc = 0; +} def BC1F_MM : MMRel, BC1F_FT<"bc1f", brtarget_mm, II_BC1F, MIPS_BRANCH_F>, BC1F_FM_MM<0x1c>, ISA_MIPS1_NOT_32R6_64R6; def BC1T_MM : MMRel, BC1F_FT<"bc1t", brtarget_mm, II_BC1T, MIPS_BRANCH_T>, BC1F_FM_MM<0x1d>, ISA_MIPS1_NOT_32R6_64R6; def CVT_W_S_MM : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, ROUND_W_FM_MM<0, 0x24>; def ROUND_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, ROUND_W_FM_MM<0, 0xec>; def CEIL_W_MM : MMRel, ABSS_FT<"ceil.w.d", FGR32Opnd, AFGR64Opnd, II_CEIL>, ROUND_W_FM_MM<1, 0x6c>; def CVT_W_MM : MMRel, ABSS_FT<"cvt.w.d", FGR32Opnd, AFGR64Opnd, II_CVT>, ROUND_W_FM_MM<1, 0x24>; def FLOOR_W_MM : MMRel, ABSS_FT<"floor.w.d", FGR32Opnd, AFGR64Opnd, II_FLOOR>, ROUND_W_FM_MM<1, 0x2c>; def ROUND_W_MM : MMRel, StdMMR6Rel, ABSS_FT<"round.w.d", FGR32Opnd, AFGR64Opnd, II_ROUND>, ROUND_W_FM_MM<1, 0xec>; def TRUNC_W_MM : MMRel, ABSS_FT<"trunc.w.d", FGR32Opnd, AFGR64Opnd, II_TRUNC>, ROUND_W_FM_MM<1, 0xac>; def FSQRT_MM : MMRel, ABSS_FT<"sqrt.d", AFGR64Opnd, AFGR64Opnd, II_SQRT_D, fsqrt>, ROUND_W_FM_MM<1, 0x28>; def CVT_L_S_MM : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, ROUND_W_FM_MM<0, 0x4>, INSN_MIPS3_32R2; def CVT_L_D64_MM : MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, ROUND_W_FM_MM<1, 0x4>, INSN_MIPS3_32R2; def FABS_S_MM : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, ABS_FM_MM<0, 0xd>; def FMOV_S_MM : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, ABS_FM_MM<0, 0x1>; def FNEG_S_MM : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, ABS_FM_MM<0, 0x2d>; def CVT_D_S_MM : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, ABS_FM_MM<0, 0x4d>; def CVT_D32_W_MM : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, ABS_FM_MM<1, 0x4d>; def CVT_S_D32_MM : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, ABS_FM_MM<0, 0x6d>; def CVT_S_W_MM : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, ABS_FM_MM<1, 0x6d>; def FABS_MM : MMRel, ABSS_FT<"abs.d", AFGR64Opnd, AFGR64Opnd, II_ABS, fabs>, ABS_FM_MM<1, 0xd>; def FNEG_MM : MMRel, ABSS_FT<"neg.d", AFGR64Opnd, AFGR64Opnd, II_NEG, fneg>, ABS_FM_MM<1, 0x2d>; def FMOV_D32_MM : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, ABS_FM_MM<1, 0x1>, FGR_32; def MOVZ_I_S_MM : MMRel, CMov_I_F_FT<"movz.s", GPR32Opnd, FGR32Opnd, II_MOVZ_S>, CMov_I_F_FM_MM<0x78, 0>; def MOVN_I_S_MM : MMRel, CMov_I_F_FT<"movn.s", GPR32Opnd, FGR32Opnd, II_MOVN_S>, CMov_I_F_FM_MM<0x38, 0>; def MOVZ_I_D32_MM : MMRel, CMov_I_F_FT<"movz.d", GPR32Opnd, AFGR64Opnd, II_MOVZ_D>, CMov_I_F_FM_MM<0x78, 1>; def MOVN_I_D32_MM : MMRel, CMov_I_F_FT<"movn.d", GPR32Opnd, AFGR64Opnd, II_MOVN_D>, CMov_I_F_FM_MM<0x38, 1>; def MOVT_S_MM : MMRel, CMov_F_F_FT<"movt.s", FGR32Opnd, II_MOVT_S, MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 0>; def MOVF_S_MM : MMRel, CMov_F_F_FT<"movf.s", FGR32Opnd, II_MOVF_S, MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 0>; def MOVT_D32_MM : MMRel, CMov_F_F_FT<"movt.d", AFGR64Opnd, II_MOVT_D, MipsCMovFP_T>, CMov_F_F_FM_MM<0x60, 1>; def MOVF_D32_MM : MMRel, CMov_F_F_FT<"movf.d", AFGR64Opnd, II_MOVF_D, MipsCMovFP_F>, CMov_F_F_FM_MM<0x20, 1>; def MFC1_MM : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, II_MFC1, bitconvert>, MFC1_FM_MM<0x80>; def MTC1_MM : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, bitconvert>, MFC1_FM_MM<0xa0>; def MADD_S_MM : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, MADDS_FM_MM<0x1>; def MSUB_S_MM : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, MADDS_FM_MM<0x21>; def NMADD_S_MM : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, MADDS_FM_MM<0x2>; def NMSUB_S_MM : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, MADDS_FM_MM<0x22>; def MADD_D32_MM : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, MADDS_FM_MM<0x9>; def MSUB_D32_MM : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, MADDS_FM_MM<0x29>; def NMADD_D32_MM : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, MADDS_FM_MM<0xa>; def NMSUB_D32_MM : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, MADDS_FM_MM<0x2a>; } let AdditionalPredicates = [InMicroMips] in { def FLOOR_W_S_MM : MMRel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, ROUND_W_FM_MM<0, 0x2c>; def TRUNC_W_S_MM : MMRel, StdMMR6Rel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, ROUND_W_FM_MM<0, 0xac>; def CEIL_W_S_MM : MMRel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, ROUND_W_FM_MM<0, 0x6c>; def FSQRT_S_MM : MMRel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S, fsqrt>, ROUND_W_FM_MM<0, 0x28>; def MTHC1_MM : MMRel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, MFC1_FM_MM<0xe0>, ISA_MIPS32R2, FGR_32; def MFHC1_MM : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>, MFC1_FM_MM<0xc0>, ISA_MIPS32R2, FGR_32; let DecoderNamespace = "MicroMips" in { def CFC1_MM : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM_MM<0x40>; def CTC1_MM : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM_MM<0x60>; def RECIP_S_MM : MMRel, ABSS_FT<"recip.s", FGR32Opnd, FGR32Opnd, II_RECIP_S>, ROUND_W_FM_MM<0b0, 0b01001000>; def RECIP_D_MM : MMRel, ABSS_FT<"recip.d", AFGR64Opnd, AFGR64Opnd, II_RECIP_D>, ROUND_W_FM_MM<0b1, 0b01001000>; def RSQRT_S_MM : MMRel, ABSS_FT<"rsqrt.s", FGR32Opnd, FGR32Opnd, II_RECIP_S>, ROUND_W_FM_MM<0b0, 0b00001000>; def RSQRT_D_MM : MMRel, ABSS_FT<"rsqrt.d", AFGR64Opnd, AFGR64Opnd, II_RECIP_D>, ROUND_W_FM_MM<0b1, 0b00001000>; } let DecoderNamespace = "MicroMips", DecoderMethod = "DecodeFMemMMR2" in { def LDC1_MM : MMRel, LW_FT<"ldc1", AFGR64Opnd, mem_mm_16, II_LDC1, load>, LW_FM_MM<0x2f>, FGR_32 { let BaseOpcode = "LDC132"; } def SDC1_MM : MMRel, SW_FT<"sdc1", AFGR64Opnd, mem_mm_16, II_SDC1, store>, LW_FM_MM<0x2e>, FGR_32; def LWC1_MM : MMRel, LW_FT<"lwc1", FGR32Opnd, mem_mm_16, II_LWC1, load>, LW_FM_MM<0x27>; def SWC1_MM : MMRel, SW_FT<"swc1", FGR32Opnd, mem_mm_16, II_SWC1, store>, LW_FM_MM<0x26>; } + + multiclass C_COND_MM fmt, + InstrItinClass itin> { + def C_F_#NAME#_MM : MMRel, C_COND_FT<"f", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.f."#NAME; + let isCommutable = 1; + } + def C_UN_#NAME#_MM : MMRel, C_COND_FT<"un", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.un."#NAME; + let isCommutable = 1; + } + def C_EQ_#NAME#_MM : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.eq."#NAME; + let isCommutable = 1; + } + def C_UEQ_#NAME#_MM : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ueq."#NAME; + let isCommutable = 1; + } + def C_OLT_#NAME#_MM : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.olt."#NAME; + } + def C_ULT_#NAME#_MM : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ult."#NAME; + } + def C_OLE_#NAME#_MM : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ole."#NAME; + } + def C_ULE_#NAME#_MM : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ule."#NAME; + } + def C_SF_#NAME#_MM : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.sf."#NAME; + let isCommutable = 1; + } + def C_NGLE_#NAME#_MM : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ngle."#NAME; + } + def C_SEQ_#NAME#_MM : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.seq."#NAME; + let isCommutable = 1; + } + def C_NGL_#NAME#_MM : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ngl."#NAME; + } + def C_LT_#NAME#_MM : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.lt."#NAME; + } + def C_NGE_#NAME#_MM : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.nge."#NAME; + } + def C_LE_#NAME#_MM : MMRel, C_COND_FT<"le", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.le."#NAME; + } + def C_NGT_#NAME#_MM : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>, + C_COND_FM_MM { + let BaseOpcode = "c.ngt."#NAME; + } + } + + defm S : C_COND_MM<"s", FGR32Opnd, 0b00, II_C_CC_S>, + ISA_MIPS1_NOT_32R6_64R6; + defm D32 : C_COND_MM<"d", AFGR64Opnd, 0b01, II_C_CC_D>, + ISA_MIPS1_NOT_32R6_64R6, FGR_32; + let DecoderNamespace = "Mips64" in + defm D64 : C_COND_MM<"d", FGR64Opnd, 0b01, II_C_CC_D>, + ISA_MIPS1_NOT_32R6_64R6, FGR_64; + + defm S_MM : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6; + defm D32_MM : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6, FGR_32; + defm D64_MM : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6, FGR_64; + + defm : BC1_ALIASES, + ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT; } //===----------------------------------------------------------------------===// // Floating Point Patterns //===----------------------------------------------------------------------===// let AdditionalPredicates = [InMicroMips] in { // Patterns for loads/stores with a reg+imm operand. let AddedComplexity = 40 in { def : LoadRegImmPat, FGR_32; def : StoreRegImmPat, FGR_32; def : LoadRegImmPat; def : StoreRegImmPat; } } Index: vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFormats.td =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFormats.td (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MicroMipsInstrFormats.td (revision 313056) @@ -1,1049 +1,1054 @@ //===----------------------------------------------------------------------===// // MicroMIPS Base Classes //===----------------------------------------------------------------------===// // // Base class for MicroMips instructions. // This class does not depend on the instruction size. // class MicroMipsInstBase pattern, InstrItinClass itin, Format f> : Instruction { let Namespace = "Mips"; let DecoderNamespace = "MicroMips"; let OutOperandList = outs; let InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; let Itinerary = itin; let Predicates = [InMicroMips]; Format Form = f; } // // Base class for MicroMIPS 16-bit instructions. // class MicroMipsInst16 pattern, InstrItinClass itin, Format f> : MicroMipsInstBase { let Size = 2; field bits<16> Inst; field bits<16> SoftFail = 0; bits<6> Opcode = 0x0; } //===----------------------------------------------------------------------===// // MicroMIPS 16-bit Instruction Formats //===----------------------------------------------------------------------===// class ARITH_FM_MM16 { bits<3> rd; bits<3> rt; bits<3> rs; bits<16> Inst; let Inst{15-10} = 0x01; let Inst{9-7} = rd; let Inst{6-4} = rt; let Inst{3-1} = rs; let Inst{0} = funct; } class ANDI_FM_MM16 funct> { bits<3> rd; bits<3> rs; bits<4> imm; bits<16> Inst; let Inst{15-10} = funct; let Inst{9-7} = rd; let Inst{6-4} = rs; let Inst{3-0} = imm; } class LOGIC_FM_MM16 funct> { bits<3> rt; bits<3> rs; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-6} = funct; let Inst{5-3} = rt; let Inst{2-0} = rs; } class SHIFT_FM_MM16 funct> { bits<3> rd; bits<3> rt; bits<3> shamt; bits<16> Inst; let Inst{15-10} = 0x09; let Inst{9-7} = rd; let Inst{6-4} = rt; let Inst{3-1} = shamt; let Inst{0} = funct; } class ADDIUR2_FM_MM16 { bits<3> rd; bits<3> rs; bits<3> imm; bits<16> Inst; let Inst{15-10} = 0x1b; let Inst{9-7} = rd; let Inst{6-4} = rs; let Inst{3-1} = imm; let Inst{0} = 0; } class LOAD_STORE_FM_MM16 op> { bits<3> rt; bits<7> addr; bits<16> Inst; let Inst{15-10} = op; let Inst{9-7} = rt; let Inst{6-4} = addr{6-4}; let Inst{3-0} = addr{3-0}; } class LOAD_STORE_SP_FM_MM16 op> { bits<5> rt; bits<5> offset; bits<16> Inst; let Inst{15-10} = op; let Inst{9-5} = rt; let Inst{4-0} = offset; } class LOAD_GP_FM_MM16 op> { bits<3> rt; bits<7> offset; bits<16> Inst; let Inst{15-10} = op; let Inst{9-7} = rt; let Inst{6-0} = offset; } class ADDIUS5_FM_MM16 { bits<5> rd; bits<4> imm; bits<16> Inst; let Inst{15-10} = 0x13; let Inst{9-5} = rd; let Inst{4-1} = imm; let Inst{0} = 0; } class ADDIUSP_FM_MM16 { bits<9> imm; bits<16> Inst; let Inst{15-10} = 0x13; let Inst{9-1} = imm; let Inst{0} = 1; } class MOVE_FM_MM16 funct> { bits<5> rs; bits<5> rd; bits<16> Inst; let Inst{15-10} = funct; let Inst{9-5} = rd; let Inst{4-0} = rs; } class LI_FM_MM16 { bits<3> rd; bits<7> imm; bits<16> Inst; let Inst{15-10} = 0x3b; let Inst{9-7} = rd; let Inst{6-0} = imm; } class JALR_FM_MM16 op> { bits<5> rs; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-5} = op; let Inst{4-0} = rs; } class MFHILO_FM_MM16 funct> { bits<5> rd; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-5} = funct; let Inst{4-0} = rd; } class JRADDIUSP_FM_MM16 op> { bits<5> rs; bits<5> imm; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-5} = op; let Inst{4-0} = imm; } class ADDIUR1SP_FM_MM16 { bits<3> rd; bits<6> imm; bits<16> Inst; let Inst{15-10} = 0x1b; let Inst{9-7} = rd; let Inst{6-1} = imm; let Inst{0} = 1; } class BRKSDBBP16_FM_MM op> { bits<4> code_; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-4} = op; let Inst{3-0} = code_; } class BEQNEZ_FM_MM16 op> { bits<3> rs; bits<7> offset; bits<16> Inst; let Inst{15-10} = op; let Inst{9-7} = rs; let Inst{6-0} = offset; } class B16_FM { bits<10> offset; bits<16> Inst; let Inst{15-10} = 0x33; let Inst{9-0} = offset; } class MOVEP_FM_MM16 { bits<3> dst_regs; bits<3> rt; bits<3> rs; bits<16> Inst; let Inst{15-10} = 0x21; let Inst{9-7} = dst_regs; let Inst{6-4} = rt; let Inst{3-1} = rs; let Inst{0} = 0; } //===----------------------------------------------------------------------===// // MicroMIPS 32-bit Instruction Formats //===----------------------------------------------------------------------===// class MMArch { string Arch = "micromips"; } class ADD_FM_MM op, bits<10> funct> : MMArch { bits<5> rt; bits<5> rs; bits<5> rd; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-11} = rd; let Inst{10} = 0; let Inst{9-0} = funct; } class ADDI_FM_MM op> : MMArch { bits<5> rs; bits<5> rt; bits<16> imm16; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-0} = imm16; } class SLTI_FM_MM op> : MMArch { bits<5> rt; bits<5> rs; bits<16> imm16; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-0} = imm16; } class LUI_FM_MM : MMArch { bits<5> rt; bits<16> imm16; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = 0xd; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class MULT_FM_MM funct> : MMArch { bits<5> rs; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class SRA_FM_MM funct, bit rotate> : MMArch { bits<5> rd; bits<5> rt; bits<5> shamt; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rd; let Inst{20-16} = rt; let Inst{15-11} = shamt; let Inst{10} = rotate; let Inst{9-0} = funct; } class SRLV_FM_MM funct, bit rotate> : MMArch { bits<5> rd; bits<5> rt; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-11} = rd; let Inst{10} = rotate; let Inst{9-0} = funct; } class LW_FM_MM op> : MMArch { bits<5> rt; bits<21> addr; bits<5> base = addr{20-16}; bits<16> offset = addr{15-0}; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = base; let Inst{15-0} = offset; } class POOL32C_LHUE_FM_MM op, bits<4> fmt, bits<3> funct> : MMArch { bits<5> rt; bits<21> addr; bits<5> base = addr{20-16}; bits<9> offset = addr{8-0}; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = base; let Inst{15-12} = fmt; let Inst{11-9} = funct; let Inst{8-0} = offset; } class LWL_FM_MM funct> { bits<5> rt; bits<21> addr; bits<32> Inst; let Inst{31-26} = 0x18; let Inst{25-21} = rt; let Inst{20-16} = addr{20-16}; let Inst{15-12} = funct; let Inst{11-0} = addr{11-0}; } class POOL32C_STEVA_LDEVA_FM_MM type, bits<3> funct> { bits<5> rt; bits<21> addr; bits<5> base = addr{20-16}; bits<9> offset = addr{8-0}; bits<32> Inst; let Inst{31-26} = 0x18; let Inst{25-21} = rt; let Inst{20-16} = base; let Inst{15-12} = type; let Inst{11-9} = funct; let Inst{8-0} = offset; } class CMov_F_I_FM_MM func> : MMArch { bits<5> rd; bits<5> rs; bits<3> fcc; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = rd; let Inst{20-16} = rs; let Inst{15-13} = fcc; let Inst{12-6} = func; let Inst{5-0} = 0x3b; } class MTLO_FM_MM funct> : MMArch { bits<5> rs; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = 0x00; let Inst{20-16} = rs; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class MFLO_FM_MM funct> : MMArch { bits<5> rd; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = 0x00; let Inst{20-16} = rd; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class CLO_FM_MM funct> : MMArch { bits<5> rd; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rd; let Inst{20-16} = rs; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class SEB_FM_MM funct> : MMArch { bits<5> rd; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rd; let Inst{20-16} = rt; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class EXT_FM_MM funct> : MMArch { bits<5> rt; bits<5> rs; bits<5> pos; bits<5> size; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-11} = size; let Inst{10-6} = pos; let Inst{5-0} = funct; } class J_FM_MM op> : MMArch { bits<26> target; bits<32> Inst; let Inst{31-26} = op; let Inst{25-0} = target; } class JR_FM_MM funct> : MMArch { bits<5> rs; bits<32> Inst; let Inst{31-21} = 0x00; let Inst{20-16} = rs; let Inst{15-14} = 0x0; let Inst{13-6} = funct; let Inst{5-0} = 0x3c; } class JALR_FM_MM funct> { bits<5> rs; bits<5> rd; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rd; let Inst{20-16} = rs; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class BEQ_FM_MM op> : MMArch { bits<5> rs; bits<5> rt; bits<16> offset; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-0} = offset; } class BGEZ_FM_MM funct> : MMArch { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = funct; let Inst{20-16} = rs; let Inst{15-0} = offset; } class BGEZAL_FM_MM funct> : MMArch { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = funct; let Inst{20-16} = rs; let Inst{15-0} = offset; } class SYNC_FM_MM : MMArch { bits<5> stype; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = 0x0; let Inst{20-16} = stype; let Inst{15-6} = 0x1ad; let Inst{5-0} = 0x3c; } class SYNCI_FM_MM : MMArch { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = 0b010000; let Inst{25-21} = 0b10000; let Inst{20-16} = rs; let Inst{15-0} = offset; } class BRK_FM_MM : MMArch { bits<10> code_1; bits<10> code_2; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-16} = code_1; let Inst{15-6} = code_2; let Inst{5-0} = 0x07; } class SYS_FM_MM : MMArch { bits<10> code_; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-16} = code_; let Inst{15-6} = 0x22d; let Inst{5-0} = 0x3c; } class WAIT_FM_MM { bits<10> code_; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-16} = code_; let Inst{15-6} = 0x24d; let Inst{5-0} = 0x3c; } class ER_FM_MM funct> : MMArch { bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-16} = 0x00; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class EI_FM_MM funct> : MMArch { bits<32> Inst; bits<5> rt; let Inst{31-26} = 0x00; let Inst{25-21} = 0x00; let Inst{20-16} = rt; let Inst{15-6} = funct; let Inst{5-0} = 0x3c; } class TEQ_FM_MM funct> : MMArch { bits<5> rs; bits<5> rt; bits<4> code_; bits<32> Inst; let Inst{31-26} = 0x00; let Inst{25-21} = rt; let Inst{20-16} = rs; let Inst{15-12} = code_; let Inst{11-6} = funct; let Inst{5-0} = 0x3c; } class TEQI_FM_MM funct> : MMArch { bits<5> rs; bits<16> imm16; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = funct; let Inst{20-16} = rs; let Inst{15-0} = imm16; } class LL_FM_MM funct> : MMArch { bits<5> rt; bits<21> addr; bits<32> Inst; let Inst{31-26} = 0x18; let Inst{25-21} = rt; let Inst{20-16} = addr{20-16}; let Inst{15-12} = funct; let Inst{11-0} = addr{11-0}; } class LLE_FM_MM funct> { bits<5> rt; bits<21> addr; bits<5> base = addr{20-16}; bits<9> offset = addr{8-0}; bits<32> Inst; let Inst{31-26} = 0x18; let Inst{25-21} = rt; let Inst{20-16} = base; let Inst{15-12} = funct; let Inst{11-9} = 0x6; let Inst{8-0} = offset; } class ADDS_FM_MM fmt, bits<8> funct> : MMArch { bits<5> ft; bits<5> fs; bits<5> fd; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = ft; let Inst{20-16} = fs; let Inst{15-11} = fd; let Inst{10} = 0; let Inst{9-8} = fmt; let Inst{7-0} = funct; list Pattern = []; } class LWXC1_FM_MM funct> : MMArch { bits<5> fd; bits<5> base; bits<5> index; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = index; let Inst{20-16} = base; let Inst{15-11} = fd; let Inst{10-9} = 0x0; let Inst{8-0} = funct; } class SWXC1_FM_MM funct> : MMArch { bits<5> fs; bits<5> base; bits<5> index; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = index; let Inst{20-16} = base; let Inst{15-11} = fs; let Inst{10-9} = 0x0; let Inst{8-0} = funct; } class CEQS_FM_MM fmt> : MMArch { bits<5> fs; bits<5> ft; + bits<3> fcc; bits<4> cond; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = ft; let Inst{20-16} = fs; - let Inst{15-13} = 0x0; // cc + let Inst{15-13} = fcc; let Inst{12} = 0; let Inst{11-10} = fmt; let Inst{9-6} = cond; let Inst{5-0} = 0x3c; +} + +class C_COND_FM_MM fmt, bits<4> c> : CEQS_FM_MM { + let cond = c; } class BC1F_FM_MM tf> : MMArch { bits<16> offset; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = tf; let Inst{20-18} = 0x0; // cc let Inst{17-16} = 0x0; let Inst{15-0} = offset; } class ROUND_W_FM_MM fmt, bits<8> funct> : MMArch { bits<5> fd; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = fd; let Inst{20-16} = fs; let Inst{15} = 0; let Inst{14} = fmt; let Inst{13-6} = funct; let Inst{5-0} = 0x3b; } class ABS_FM_MM fmt, bits<7> funct> : MMArch { bits<5> fd; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = fd; let Inst{20-16} = fs; let Inst{15} = 0; let Inst{14-13} = fmt; let Inst{12-6} = funct; let Inst{5-0} = 0x3b; } class CMov_F_F_FM_MM func, bits<2> fmt> : MMArch { bits<5> fd; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = fd; let Inst{20-16} = fs; let Inst{15-13} = 0x0; //cc let Inst{12-11} = 0x0; let Inst{10-9} = fmt; let Inst{8-0} = func; } class CMov_I_F_FM_MM funct, bits<2> fmt> : MMArch { bits<5> fd; bits<5> fs; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = rt; let Inst{20-16} = fs; let Inst{15-11} = fd; let Inst{9-8} = fmt; let Inst{7-0} = funct; } class MFC1_FM_MM funct> : MMArch { bits<5> rt; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = rt; let Inst{20-16} = fs; let Inst{15-14} = 0x0; let Inst{13-6} = funct; let Inst{5-0} = 0x3b; } class MADDS_FM_MM funct>: MMArch { bits<5> ft; bits<5> fs; bits<5> fd; bits<5> fr; bits<32> Inst; let Inst{31-26} = 0x15; let Inst{25-21} = ft; let Inst{20-16} = fs; let Inst{15-11} = fd; let Inst{10-6} = fr; let Inst{5-0} = funct; } class COMPACT_BRANCH_FM_MM funct> { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25-21} = funct; let Inst{20-16} = rs; let Inst{15-0} = offset; } class COP0_TLB_FM_MM op> : MMArch { bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-16} = 0x0; let Inst{15-6} = op; let Inst{5-0} = 0x3c; } class SDBBP_FM_MM : MMArch { bits<10> code_; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-16} = code_; let Inst{15-6} = 0x36d; let Inst{5-0} = 0x3c; } class RDHWR_FM_MM : MMArch { bits<5> rt; bits<5> rd; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-21} = rt; let Inst{20-16} = rd; let Inst{15-6} = 0x1ac; let Inst{5-0} = 0x3c; } class LWXS_FM_MM funct> { bits<5> rd; bits<5> base; bits<5> index; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-21} = index; let Inst{20-16} = base; let Inst{15-11} = rd; let Inst{10} = 0; let Inst{9-0} = funct; } class LWM_FM_MM funct> : MMArch { bits<5> rt; bits<21> addr; bits<32> Inst; let Inst{31-26} = 0x8; let Inst{25-21} = rt; let Inst{20-16} = addr{20-16}; let Inst{15-12} = funct; let Inst{11-0} = addr{11-0}; } class LWM_FM_MM16 funct> : MMArch, PredicateControl { bits<2> rt; bits<4> addr; bits<16> Inst; let Inst{15-10} = 0x11; let Inst{9-6} = funct; let Inst{5-4} = rt; let Inst{3-0} = addr; } class CACHE_PREF_FM_MM op, bits<4> funct> : MMArch { bits<21> addr; bits<5> hint; bits<5> base = addr{20-16}; bits<12> offset = addr{11-0}; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = hint; let Inst{20-16} = base; let Inst{15-12} = funct; let Inst{11-0} = offset; } class CACHE_PREFE_FM_MM op, bits<3> funct> : MMArch { bits<21> addr; bits<5> hint; bits<5> base = addr{20-16}; bits<9> offset = addr{8-0}; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = hint; let Inst{20-16} = base; let Inst{15-12} = 0xA; let Inst{11-9} = funct; let Inst{8-0} = offset; } class POOL32F_PREFX_FM_MM op, bits<9> funct> : MMArch { bits<5> index; bits<5> base; bits<5> hint; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = index; let Inst{20-16} = base; let Inst{15-11} = hint; let Inst{10-9} = 0x0; let Inst{8-0} = funct; } class BARRIER_FM_MM op> : MMArch { bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-21} = 0x0; let Inst{20-16} = 0x0; let Inst{15-11} = op; let Inst{10-6} = 0x0; let Inst{5-0} = 0x0; } class ADDIUPC_FM_MM { bits<3> rs; bits<23> imm; bits<32> Inst; let Inst{31-26} = 0x1e; let Inst{25-23} = rs; let Inst{22-0} = imm; } class POOL32A_CFTC2_FM_MM funct> : MMArch { bits<5> rt; bits<5> impl; bits<32> Inst; let Inst{31-26} = 0b000000; let Inst{25-21} = rt; let Inst{20-16} = impl; let Inst{15-6} = funct; let Inst{5-0} = 0b111100; } Index: vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.cpp =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.cpp (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.cpp (revision 313056) @@ -1,1073 +1,1089 @@ //===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation // of machine-dependent LLVM code to GAS-format MIPS assembly language. // //===----------------------------------------------------------------------===// #include "InstPrinter/MipsInstPrinter.h" #include "MCTargetDesc/MipsBaseInfo.h" #include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" #include "MipsMCInstLower.h" #include "MipsTargetMachine.h" #include "MipsTargetStreamer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Mangler.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" #include using namespace llvm; #define DEBUG_TYPE "mips-asm-printer" MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const { return static_cast(*OutStreamer->getTargetStreamer()); } bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { Subtarget = &MF.getSubtarget(); MipsFI = MF.getInfo(); if (Subtarget->inMips16Mode()) for (std::map< const char *, const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator it = MipsFI->StubsNeeded.begin(); it != MipsFI->StubsNeeded.end(); ++it) { const char *Symbol = it->first; const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; if (StubsNeeded.find(Symbol) == StubsNeeded.end()) StubsNeeded[Symbol] = Signature; } MCP = MF.getConstantPool(); // In NaCl, all indirect jump targets must be aligned to bundle size. if (Subtarget->isTargetNaCl()) NaClAlignIndirectJumpTargets(MF); AsmPrinter::runOnMachineFunction(MF); return true; } bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { MCOp = MCInstLowering.LowerOperand(MO); return MCOp.isValid(); } #include "MipsGenMCPseudoLowering.inc" // Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, // JALR, or JALR64 as appropriate for the target void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, const MachineInstr *MI) { bool HasLinkReg = false; bool InMicroMipsMode = Subtarget->inMicroMipsMode(); MCInst TmpInst0; if (Subtarget->hasMips64r6()) { // MIPS64r6 should use (JALR64 ZERO_64, $rs) TmpInst0.setOpcode(Mips::JALR64); HasLinkReg = true; } else if (Subtarget->hasMips32r6()) { // MIPS32r6 should use (JALR ZERO, $rs) if (InMicroMipsMode) TmpInst0.setOpcode(Mips::JRC16_MMR6); else { TmpInst0.setOpcode(Mips::JALR); HasLinkReg = true; } } else if (Subtarget->inMicroMipsMode()) // microMIPS should use (JR_MM $rs) TmpInst0.setOpcode(Mips::JR_MM); else { // Everything else should use (JR $rs) TmpInst0.setOpcode(Mips::JR); } MCOperand MCOp; if (HasLinkReg) { unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; TmpInst0.addOperand(MCOperand::createReg(ZeroReg)); } lowerOperand(MI->getOperand(0), MCOp); TmpInst0.addOperand(MCOp); EmitToStreamer(OutStreamer, TmpInst0); } void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { MipsTargetStreamer &TS = getTargetStreamer(); TS.forbidModuleDirective(); if (MI->isDebugValue()) { SmallString<128> Str; raw_svector_ostream OS(Str); PrintDebugValueComment(MI, OS); return; } // If we just ended a constant pool, mark it as such. if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) { OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); InConstantPool = false; } if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) { // CONSTPOOL_ENTRY - This instruction represents a floating //constant pool in the function. The first operand is the ID# // for this instruction, the second is the index into the // MachineConstantPool that this is, the third is the size in // bytes of this constant pool entry. // The required alignment is specified on the basic block holding this MI. // unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); // If this is the first entry of the pool, mark it. if (!InConstantPool) { OutStreamer->EmitDataRegion(MCDR_DataRegion); InConstantPool = true; } OutStreamer->EmitLabel(GetCPISymbol(LabelId)); const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; if (MCPE.isMachineConstantPoolEntry()) EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); else EmitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); return; } MachineBasicBlock::const_instr_iterator I = MI->getIterator(); MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); do { // Do any auto-generated pseudo lowerings. if (emitPseudoExpansionLowering(*OutStreamer, &*I)) continue; if (I->getOpcode() == Mips::PseudoReturn || I->getOpcode() == Mips::PseudoReturn64 || I->getOpcode() == Mips::PseudoIndirectBranch || I->getOpcode() == Mips::PseudoIndirectBranch64 || I->getOpcode() == Mips::TAILCALLREG || I->getOpcode() == Mips::TAILCALLREG64) { emitPseudoIndirectBranch(*OutStreamer, &*I); continue; } // The inMips16Mode() test is not permanent. // Some instructions are marked as pseudo right now which // would make the test fail for the wrong reason but // that will be fixed soon. We need this here because we are // removing another test for this situation downstream in the // callchain. // if (I->isPseudo() && !Subtarget->inMips16Mode() && !isLongBranchPseudo(I->getOpcode())) llvm_unreachable("Pseudo opcode found in EmitInstruction()"); MCInst TmpInst0; MCInstLowering.Lower(&*I, TmpInst0); EmitToStreamer(*OutStreamer, TmpInst0); } while ((++I != E) && I->isInsideBundle()); // Delay slot check } //===----------------------------------------------------------------------===// // // Mips Asm Directives // // -- Frame directive "frame Stackpointer, Stacksize, RARegister" // Describe the stack frame. // // -- Mask directives "(f)mask bitmask, offset" // Tells the assembler which registers are saved and where. // bitmask - contain a little endian bitset indicating which registers are // saved on function prologue (e.g. with a 0x80000000 mask, the // assembler knows the register 31 (RA) is saved at prologue. // offset - the position before stack pointer subtraction indicating where // the first saved register on prologue is located. (e.g. with a // // Consider the following function prologue: // // .frame $fp,48,$ra // .mask 0xc0000000,-8 // addiu $sp, $sp, -48 // sw $ra, 40($sp) // sw $fp, 36($sp) // // With a 0xc0000000 mask, the assembler knows the register 31 (RA) and // 30 (FP) are saved at prologue. As the save order on prologue is from // left to right, RA is saved first. A -8 offset means that after the // stack pointer subtration, the first register in the mask (RA) will be // saved at address 48-8=40. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Mask directives //===----------------------------------------------------------------------===// // Create a bitmask with all callee saved registers for CPU or Floating Point // registers. For CPU registers consider RA, GP and FP for saving if necessary. void MipsAsmPrinter::printSavedRegsBitmask() { // CPU and FPU Saved Registers Bitmasks unsigned CPUBitmask = 0, FPUBitmask = 0; int CPUTopSavedRegOff, FPUTopSavedRegOff; // Set the CPU and FPU Bitmasks const MachineFrameInfo &MFI = MF->getFrameInfo(); const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); const std::vector &CSI = MFI.getCalleeSavedInfo(); // size of stack area to which FP callee-saved regs are saved. unsigned CPURegSize = Mips::GPR32RegClass.getSize(); unsigned FGR32RegSize = Mips::FGR32RegClass.getSize(); unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize(); bool HasAFGR64Reg = false; unsigned CSFPRegsSize = 0; for (const auto &I : CSI) { unsigned Reg = I.getReg(); unsigned RegNum = TRI->getEncodingValue(Reg); // If it's a floating point register, set the FPU Bitmask. // If it's a general purpose register, set the CPU Bitmask. if (Mips::FGR32RegClass.contains(Reg)) { FPUBitmask |= (1 << RegNum); CSFPRegsSize += FGR32RegSize; } else if (Mips::AFGR64RegClass.contains(Reg)) { FPUBitmask |= (3 << RegNum); CSFPRegsSize += AFGR64RegSize; HasAFGR64Reg = true; } else if (Mips::GPR32RegClass.contains(Reg)) CPUBitmask |= (1 << RegNum); } // FP Regs are saved right below where the virtual frame pointer points to. FPUTopSavedRegOff = FPUBitmask ? (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0; // CPU Regs are saved below FP Regs. CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; MipsTargetStreamer &TS = getTargetStreamer(); // Print CPUBitmask TS.emitMask(CPUBitmask, CPUTopSavedRegOff); // Print FPUBitmask TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); } //===----------------------------------------------------------------------===// // Frame and Set directives //===----------------------------------------------------------------------===// /// Frame Directive void MipsAsmPrinter::emitFrameDirective() { const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo(); unsigned stackReg = RI.getFrameRegister(*MF); unsigned returnReg = RI.getRARegister(); unsigned stackSize = MF->getFrameInfo().getStackSize(); getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); } /// Emit Set directives. const char *MipsAsmPrinter::getCurrentABIString() const { switch (static_cast(TM).getABI().GetEnumValue()) { case MipsABIInfo::ABI::O32: return "abi32"; case MipsABIInfo::ABI::N32: return "abiN32"; case MipsABIInfo::ABI::N64: return "abi64"; default: llvm_unreachable("Unknown Mips ABI"); } } void MipsAsmPrinter::EmitFunctionEntryLabel() { MipsTargetStreamer &TS = getTargetStreamer(); // NaCl sandboxing requires that indirect call instructions are masked. // This means that function entry points should be bundle-aligned. if (Subtarget->isTargetNaCl()) EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN)); if (Subtarget->inMicroMipsMode()) { TS.emitDirectiveSetMicroMips(); TS.setUsesMicroMips(); } else TS.emitDirectiveSetNoMicroMips(); if (Subtarget->inMips16Mode()) TS.emitDirectiveSetMips16(); else TS.emitDirectiveSetNoMips16(); TS.emitDirectiveEnt(*CurrentFnSym); OutStreamer->EmitLabel(CurrentFnSym); } /// EmitFunctionBodyStart - Targets can override this to emit stuff before /// the first basic block in the function. void MipsAsmPrinter::EmitFunctionBodyStart() { MipsTargetStreamer &TS = getTargetStreamer(); MCInstLowering.Initialize(&MF->getContext()); bool IsNakedFunction = MF->getFunction()->hasFnAttribute(Attribute::Naked); if (!IsNakedFunction) emitFrameDirective(); if (!IsNakedFunction) printSavedRegsBitmask(); if (!Subtarget->inMips16Mode()) { TS.emitDirectiveSetNoReorder(); TS.emitDirectiveSetNoMacro(); TS.emitDirectiveSetNoAt(); } } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. void MipsAsmPrinter::EmitFunctionBodyEnd() { MipsTargetStreamer &TS = getTargetStreamer(); // There are instruction for this macros, but they must // always be at the function end, and we can't emit and // break with BB logic. if (!Subtarget->inMips16Mode()) { TS.emitDirectiveSetAt(); TS.emitDirectiveSetMacro(); TS.emitDirectiveSetReorder(); } TS.emitDirectiveEnd(CurrentFnSym->getName()); // Make sure to terminate any constant pools that were at the end // of the function. if (!InConstantPool) return; InConstantPool = false; OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); } void MipsAsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) { MipsTargetStreamer &TS = getTargetStreamer(); if (MBB.size() == 0) TS.emitDirectiveInsn(); } /// isBlockOnlyReachableByFallthough - Return true if the basic block has /// exactly one predecessor and the control transfer mechanism between /// the predecessor and this block is a fall-through. bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* MBB) const { // The predecessor has to be immediately before this block. const MachineBasicBlock *Pred = *MBB->pred_begin(); // If the predecessor is a switch statement, assume a jump table // implementation, so it is not a fall through. if (const BasicBlock *bb = Pred->getBasicBlock()) if (isa(bb->getTerminator())) return false; // If this is a landing pad, it isn't a fall through. If it has no preds, // then nothing falls through to it. if (MBB->isEHPad() || MBB->pred_empty()) return false; // If there isn't exactly one predecessor, it can't be a fall through. MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; ++PI2; if (PI2 != MBB->pred_end()) return false; // The predecessor has to be immediately before this block. if (!Pred->isLayoutSuccessor(MBB)) return false; // If the block is completely empty, then it definitely does fall through. if (Pred->empty()) return true; // Otherwise, check the last instruction. // Check if the last terminator is an unconditional branch. MachineBasicBlock::const_iterator I = Pred->end(); while (I != Pred->begin() && !(--I)->isTerminator()) ; return !I->isBarrier(); } // Print out an operand for an inline asm expression. bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { // Does this asm operand have a single letter operand modifier? if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. const MachineOperand &MO = MI->getOperand(OpNum); switch (ExtraCode[0]) { default: // See if this is a generic print operand return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O); case 'X': // hex const int if ((MO.getType()) != MachineOperand::MO_Immediate) return true; O << "0x" << Twine::utohexstr(MO.getImm()); return false; case 'x': // hex const int (low 16 bits) if ((MO.getType()) != MachineOperand::MO_Immediate) return true; O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff); return false; case 'd': // decimal const int if ((MO.getType()) != MachineOperand::MO_Immediate) return true; O << MO.getImm(); return false; case 'm': // decimal const int minus 1 if ((MO.getType()) != MachineOperand::MO_Immediate) return true; O << MO.getImm() - 1; return false; case 'z': { // $0 if zero, regular printing otherwise if (MO.getType() == MachineOperand::MO_Immediate && MO.getImm() == 0) { O << "$0"; return false; } // If not, call printOperand as normal. break; } case 'D': // Second part of a double word register operand case 'L': // Low order register of a double word register operand case 'M': // High order register of a double word register operand { if (OpNum == 0) return true; const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); if (!FlagsOP.isImm()) return true; unsigned Flags = FlagsOP.getImm(); unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); // Number of registers represented by this operand. We are looking // for 2 for 32 bit mode and 1 for 64 bit mode. if (NumVals != 2) { if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) { unsigned Reg = MO.getReg(); O << '$' << MipsInstPrinter::getRegisterName(Reg); return false; } return true; } unsigned RegOp = OpNum; if (!Subtarget->isGP64bit()){ // Endianness reverses which register holds the high or low value // between M and L. switch(ExtraCode[0]) { case 'M': RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum; break; case 'L': RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1; break; case 'D': // Always the second part RegOp = OpNum + 1; } if (RegOp >= MI->getNumOperands()) return true; const MachineOperand &MO = MI->getOperand(RegOp); if (!MO.isReg()) return true; unsigned Reg = MO.getReg(); O << '$' << MipsInstPrinter::getRegisterName(Reg); return false; } } case 'w': // Print MSA registers for the 'f' constraint // In LLVM, the 'w' modifier doesn't need to do anything. // We can just call printOperand as normal. break; } } printOperand(MI, OpNum, O); return false; } bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands"); const MachineOperand &BaseMO = MI->getOperand(OpNum); const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); int Offset = OffsetMO.getImm(); // Currently we are expecting either no ExtraCode or 'D' if (ExtraCode) { if (ExtraCode[0] == 'D') Offset += 4; else return true; // Unknown modifier. // FIXME: M = high order bits // FIXME: L = low order bits } O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg()) << ")"; return false; } void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand(opNum); bool closeP = false; if (MO.getTargetFlags()) closeP = true; switch(MO.getTargetFlags()) { case MipsII::MO_GPREL: O << "%gp_rel("; break; case MipsII::MO_GOT_CALL: O << "%call16("; break; case MipsII::MO_GOT: O << "%got("; break; case MipsII::MO_ABS_HI: O << "%hi("; break; case MipsII::MO_ABS_LO: O << "%lo("; break; case MipsII::MO_TLSGD: O << "%tlsgd("; break; case MipsII::MO_GOTTPREL: O << "%gottprel("; break; case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break; case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break; case MipsII::MO_GOT_DISP: O << "%got_disp("; break; case MipsII::MO_GOT_PAGE: O << "%got_page("; break; case MipsII::MO_GOT_OFST: O << "%got_ofst("; break; } switch (MO.getType()) { case MachineOperand::MO_Register: O << '$' << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); break; case MachineOperand::MO_Immediate: O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: MO.getMBB()->getSymbol()->print(O, MAI); return; case MachineOperand::MO_GlobalAddress: getSymbol(MO.getGlobal())->print(O, MAI); break; case MachineOperand::MO_BlockAddress: { MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); O << BA->getName(); break; } case MachineOperand::MO_ConstantPoolIndex: O << getDataLayout().getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" << MO.getIndex(); if (MO.getOffset()) O << "+" << MO.getOffset(); break; default: llvm_unreachable(""); } if (closeP) O << ")"; } void MipsAsmPrinter:: printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { // Load/Store memory operands -- imm($reg) // If PIC target the target is loaded as the // pattern lw $25,%call16($28) // opNum can be invalid if instruction has reglist as operand. // MemOperand is always last operand of instruction (base + offset). switch (MI->getOpcode()) { default: break; case Mips::SWM32_MM: case Mips::LWM32_MM: opNum = MI->getNumOperands() - 2; break; } printOperand(MI, opNum+1, O); O << "("; printOperand(MI, opNum, O); O << ")"; } void MipsAsmPrinter:: printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { // when using stack locations for not load/store instructions // print the same way as all normal 3 operand instructions. printOperand(MI, opNum, O); O << ", "; printOperand(MI, opNum+1, O); return; } void MipsAsmPrinter:: printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier) { const MachineOperand &MO = MI->getOperand(opNum); O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); } void MipsAsmPrinter:: printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) { for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) { if (i != opNum) O << ", "; printOperand(MI, i, O); } } void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { MipsTargetStreamer &TS = getTargetStreamer(); // MipsTargetStreamer has an initialization order problem when emitting an // object file directly (see MipsTargetELFStreamer for full details). Work // around it by re-initializing the PIC state here. TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent()); // Compute MIPS architecture attributes based on the default subtarget // that we'd have constructed. Module level directives aren't LTO // clean anyhow. // FIXME: For ifunc related functions we could iterate over and look // for a feature string that doesn't match the default one. const Triple &TT = TM.getTargetTriple(); StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU()); StringRef FS = TM.getTargetFeatureString(); const MipsTargetMachine &MTM = static_cast(TM); const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM); bool IsABICalls = STI.isABICalls(); const MipsABIInfo &ABI = MTM.getABI(); if (IsABICalls) { TS.emitDirectiveAbiCalls(); // FIXME: This condition should be a lot more complicated that it is here. // Ideally it should test for properties of the ABI and not the ABI // itself. // For the moment, I'm only correcting enough to make MIPS-IV work. if (!isPositionIndependent() && !ABI.IsN64()) TS.emitDirectiveOptionPic0(); } // Tell the assembler which ABI we are using std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); OutStreamer->SwitchSection( OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0)); // NaN: At the moment we only support: // 1. .nan legacy (default) // 2. .nan 2008 STI.isNaN2008() ? TS.emitDirectiveNaN2008() : TS.emitDirectiveNaNLegacy(); // TODO: handle O64 ABI TS.updateABIInfo(STI); // We should always emit a '.module fp=...' but binutils 2.24 does not accept // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or // -mfp64) and omit it otherwise. if (ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) TS.emitDirectiveModuleFP(); // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not // accept it. We therefore emit it when it contradicts the default or an // option has changed the default (i.e. FPXX) and omit it otherwise. if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX())) TS.emitDirectiveModuleOddSPReg(); } void MipsAsmPrinter::emitInlineAsmStart() const { MipsTargetStreamer &TS = getTargetStreamer(); // GCC's choice of assembler options for inline assembly code ('at', 'macro' // and 'reorder') is different from LLVM's choice for generated code ('noat', // 'nomacro' and 'noreorder'). // In order to maintain compatibility with inline assembly code which depends // on GCC's assembler options being used, we have to switch to those options // for the duration of the inline assembly block and then switch back. TS.emitDirectiveSetPush(); TS.emitDirectiveSetAt(); TS.emitDirectiveSetMacro(); TS.emitDirectiveSetReorder(); OutStreamer->AddBlankLine(); } void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, const MCSubtargetInfo *EndInfo) const { OutStreamer->AddBlankLine(); getTargetStreamer().emitDirectiveSetPop(); } void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) { MCInst I; I.setOpcode(Mips::JAL); I.addOperand( MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext))); OutStreamer->EmitInstruction(I, STI); } void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg) { MCInst I; I.setOpcode(Opcode); I.addOperand(MCOperand::createReg(Reg)); OutStreamer->EmitInstruction(I, STI); } void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg1, unsigned Reg2) { MCInst I; // // Because of the current td files for Mips32, the operands for MTC1 // appear backwards from their normal assembly order. It's not a trivial // change to fix this in the td file so we adjust for it here. // if (Opcode == Mips::MTC1) { unsigned Temp = Reg1; Reg1 = Reg2; Reg2 = Temp; } I.setOpcode(Opcode); I.addOperand(MCOperand::createReg(Reg1)); I.addOperand(MCOperand::createReg(Reg2)); OutStreamer->EmitInstruction(I, STI); } void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg1, unsigned Reg2, unsigned Reg3) { MCInst I; I.setOpcode(Opcode); I.addOperand(MCOperand::createReg(Reg1)); I.addOperand(MCOperand::createReg(Reg2)); I.addOperand(MCOperand::createReg(Reg3)); OutStreamer->EmitInstruction(I, STI); } void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI, unsigned MovOpc, unsigned Reg1, unsigned Reg2, unsigned FPReg1, unsigned FPReg2, bool LE) { if (!LE) { unsigned temp = Reg1; Reg1 = Reg2; Reg2 = temp; } EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1); EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2); } void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPParamVariant PV, bool LE, bool ToFP) { using namespace Mips16HardFloatInfo; unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; switch (PV) { case FSig: EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); break; case FFSig: EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); break; case FDSig: EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); break; case DSig: EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); break; case DDSig: EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); break; case DFSig: EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14); break; case NoSig: return; } } void MipsAsmPrinter::EmitSwapFPIntRetval( const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV, bool LE) { using namespace Mips16HardFloatInfo; unsigned MovOpc = Mips::MFC1; switch (RV) { case FRet: EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0); break; case DRet: EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); break; case CFRet: EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); break; case CDRet: EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); break; case NoFPRet: break; } } void MipsAsmPrinter::EmitFPCallStub( const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol)); using namespace Mips16HardFloatInfo; bool LE = getDataLayout().isLittleEndian(); // Construct a local MCSubtargetInfo here. // This is because the MachineFunction won't exist (but have not yet been // freed) and since we're at the global level we can use the default // constructed subtarget. std::unique_ptr STI(TM.getTarget().createMCSubtargetInfo( TM.getTargetTriple().str(), TM.getTargetCPU(), TM.getTargetFeatureString())); // // .global xxxx // OutStreamer->EmitSymbolAttribute(MSymbol, MCSA_Global); const char *RetType; // // make the comment field identifying the return and parameter // types of the floating point stub // # Stub function to call rettype xxxx (params) // switch (Signature->RetSig) { case FRet: RetType = "float"; break; case DRet: RetType = "double"; break; case CFRet: RetType = "complex"; break; case CDRet: RetType = "double complex"; break; case NoFPRet: RetType = ""; break; } const char *Parms; switch (Signature->ParamSig) { case FSig: Parms = "float"; break; case FFSig: Parms = "float, float"; break; case FDSig: Parms = "float, double"; break; case DSig: Parms = "double"; break; case DDSig: Parms = "double, double"; break; case DFSig: Parms = "double, float"; break; case NoSig: Parms = ""; break; } OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " + Twine(Symbol) + " (" + Twine(Parms) + ")"); // // probably not necessary but we save and restore the current section state // OutStreamer->PushSection(); // // .section mips16.call.fpxxxx,"ax",@progbits // MCSectionELF *M = OutContext.getELFSection( ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); OutStreamer->SwitchSection(M, nullptr); // // .align 2 // OutStreamer->EmitValueToAlignment(4); MipsTargetStreamer &TS = getTargetStreamer(); // // .set nomips16 // .set nomicromips // TS.emitDirectiveSetNoMips16(); TS.emitDirectiveSetNoMicroMips(); // // .ent __call_stub_fp_xxxx // .type __call_stub_fp_xxxx,@function // __call_stub_fp_xxxx: // std::string x = "__call_stub_fp_" + std::string(Symbol); MCSymbolELF *Stub = cast(OutContext.getOrCreateSymbol(StringRef(x))); TS.emitDirectiveEnt(*Stub); MCSymbol *MType = OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); OutStreamer->EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); OutStreamer->EmitLabel(Stub); // Only handle non-pic for now. assert(!isPositionIndependent() && "should not be here if we are compiling pic"); TS.emitDirectiveSetReorder(); // // We need to add a MipsMCExpr class to MCTargetDesc to fully implement // stubs without raw text but this current patch is for compiler generated // functions and they all return some value. // The calling sequence for non pic is different in that case and we need // to implement %lo and %hi in order to handle the case of no return value // See the corresponding method in Mips16HardFloat for details. // // mov the return address to S2. // we have no stack space to store it and we are about to make another call. // We need to make sure that the enclosing function knows to save S2 // This should have already been handled. // // Mov $18, $31 EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO); EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true); // Jal xxxx // EmitJal(*STI, MSymbol); // fix return values EmitSwapFPIntRetval(*STI, Signature->RetSig, LE); // // do the return // if (Signature->RetSig == NoFPRet) // llvm_unreachable("should not be any stubs here with no return value"); // else EmitInstrReg(*STI, Mips::JR, Mips::S2); MCSymbol *Tmp = OutContext.createTempSymbol(); OutStreamer->EmitLabel(Tmp); const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext); const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext); const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext); OutStreamer->emitELFSize(Stub, T_min_E); TS.emitDirectiveEnd(x); OutStreamer->PopSection(); } void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { // Emit needed stubs // for (std::map< const char *, const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator it = StubsNeeded.begin(); it != StubsNeeded.end(); ++it) { const char *Symbol = it->first; const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; EmitFPCallStub(Symbol, Signature); } // return to the text section OutStreamer->SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); } void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS) { // TODO: implement } +// Emit .dtprelword or .dtpreldword directive +// and value for debug thread local expression. +void MipsAsmPrinter::EmitDebugValue(const MCExpr *Value, + unsigned Size) const { + switch (Size) { + case 4: + OutStreamer->EmitDTPRel32Value(Value); + break; + case 8: + OutStreamer->EmitDTPRel64Value(Value); + break; + default: + llvm_unreachable("Unexpected size of expression value."); + } +} + // Align all targets of indirect branches on bundle size. Used only if target // is NaCl. void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { // Align all blocks that are jumped to through jump table. if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { const std::vector &JT = JtInfo->getJumpTables(); for (unsigned I = 0; I < JT.size(); ++I) { const std::vector &MBBs = JT[I].MBBs; for (unsigned J = 0; J < MBBs.size(); ++J) MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); } } // If basic block address is taken, block can be target of indirect branch. for (auto &MBB : MF) { if (MBB.hasAddressTaken()) MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN); } } bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const { return (Opcode == Mips::LONG_BRANCH_LUi || Opcode == Mips::LONG_BRANCH_ADDiu || Opcode == Mips::LONG_BRANCH_DADDiu); } // Force static initialization. extern "C" void LLVMInitializeMipsAsmPrinter() { RegisterAsmPrinter X(getTheMipsTarget()); RegisterAsmPrinter Y(getTheMipselTarget()); RegisterAsmPrinter A(getTheMips64Target()); RegisterAsmPrinter B(getTheMips64elTarget()); } Index: vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.h =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.h (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsAsmPrinter.h (revision 313056) @@ -1,147 +1,148 @@ //===-- MipsAsmPrinter.h - Mips LLVM Assembly Printer ----------*- C++ -*--===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Mips Assembly printer class. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_MIPS_MIPSASMPRINTER_H #define LLVM_LIB_TARGET_MIPS_MIPSASMPRINTER_H #include "Mips16HardFloatInfo.h" #include "MipsMCInstLower.h" #include "MipsMachineFunction.h" #include "MipsSubtarget.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/Support/Compiler.h" #include "llvm/Target/TargetMachine.h" namespace llvm { class MCStreamer; class MachineInstr; class MachineBasicBlock; class MipsTargetStreamer; class Module; class raw_ostream; class LLVM_LIBRARY_VISIBILITY MipsAsmPrinter : public AsmPrinter { MipsTargetStreamer &getTargetStreamer() const; void EmitInstrWithMacroNoAT(const MachineInstr *MI); private: // tblgen'erated function. bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, const MachineInstr *MI); // Emit PseudoReturn, PseudoReturn64, PseudoIndirectBranch, // and PseudoIndirectBranch64 as a JR, JR_MM, JALR, or JALR64 as appropriate // for the target. void emitPseudoIndirectBranch(MCStreamer &OutStreamer, const MachineInstr *MI); // lowerOperand - Convert a MachineOperand into the equivalent MCOperand. bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp); /// MCP - Keep a pointer to constantpool entries of the current /// MachineFunction. const MachineConstantPool *MCP; /// InConstantPool - Maintain state when emitting a sequence of constant /// pool entries so we can properly mark them as data regions. bool InConstantPool; std::map StubsNeeded; void emitInlineAsmStart() const override; void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, const MCSubtargetInfo *EndInfo) const override; void EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol); void EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg); void EmitInstrRegReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg1, unsigned Reg2); void EmitInstrRegRegReg(const MCSubtargetInfo &STI, unsigned Opcode, unsigned Reg1, unsigned Reg2, unsigned Reg3); void EmitMovFPIntPair(const MCSubtargetInfo &STI, unsigned MovOpc, unsigned Reg1, unsigned Reg2, unsigned FPReg1, unsigned FPReg2, bool LE); void EmitSwapFPIntParams(const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPParamVariant, bool LE, bool ToFP); void EmitSwapFPIntRetval(const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant, bool LE); void EmitFPCallStub(const char *, const Mips16HardFloatInfo::FuncSignature *); void NaClAlignIndirectJumpTargets(MachineFunction &MF); bool isLongBranchPseudo(int Opcode) const; public: const MipsSubtarget *Subtarget; const MipsFunctionInfo *MipsFI; MipsMCInstLower MCInstLowering; explicit MipsAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)), MCP(nullptr), InConstantPool(false), MCInstLowering(*this) {} StringRef getPassName() const override { return "Mips Assembly Printer"; } bool runOnMachineFunction(MachineFunction &MF) override; void EmitConstantPool() override { bool UsingConstantPools = (Subtarget->inMips16Mode() && Subtarget->useConstantIslands()); if (!UsingConstantPools) AsmPrinter::EmitConstantPool(); // we emit constant pools customly! } void EmitInstruction(const MachineInstr *MI) override; void printSavedRegsBitmask(); void emitFrameDirective(); const char *getCurrentABIString() const; void EmitFunctionEntryLabel() override; void EmitFunctionBodyStart() override; void EmitFunctionBodyEnd() override; void EmitBasicBlockEnd(const MachineBasicBlock &MBB) override; bool isBlockOnlyReachableByFallthrough( const MachineBasicBlock* MBB) const override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) override; void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O); void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O); void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier = nullptr); void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O); void EmitStartOfAsmFile(Module &M) override; void EmitEndOfAsmFile(Module &M) override; void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + void EmitDebugValue(const MCExpr *Value, unsigned Size) const override; }; } #endif Index: vendor/llvm/dist/lib/Target/Mips/MipsFastISel.cpp =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsFastISel.cpp (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsFastISel.cpp (revision 313056) @@ -1,2081 +1,2081 @@ //===-- MipsFastISel.cpp - Mips FastISel implementation --------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief This file defines the MIPS-specific support for the FastISel class. /// Some of the target-specific code is generated by tablegen in the file /// MipsGenFastISel.inc, which is #included here. /// //===----------------------------------------------------------------------===// #include "MipsCCState.h" #include "MipsInstrInfo.h" #include "MipsISelLowering.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "mips-fastisel" using namespace llvm; namespace { class MipsFastISel final : public FastISel { // All possible address modes. class Address { public: typedef enum { RegBase, FrameIndexBase } BaseKind; private: BaseKind Kind; union { unsigned Reg; int FI; } Base; int64_t Offset; const GlobalValue *GV; public: // Innocuous defaults for our address. Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } void setKind(BaseKind K) { Kind = K; } BaseKind getKind() const { return Kind; } bool isRegBase() const { return Kind == RegBase; } bool isFIBase() const { return Kind == FrameIndexBase; } void setReg(unsigned Reg) { assert(isRegBase() && "Invalid base register access!"); Base.Reg = Reg; } unsigned getReg() const { assert(isRegBase() && "Invalid base register access!"); return Base.Reg; } void setFI(unsigned FI) { assert(isFIBase() && "Invalid base frame index access!"); Base.FI = FI; } unsigned getFI() const { assert(isFIBase() && "Invalid base frame index access!"); return Base.FI; } void setOffset(int64_t Offset_) { Offset = Offset_; } int64_t getOffset() const { return Offset; } void setGlobalValue(const GlobalValue *G) { GV = G; } const GlobalValue *getGlobalValue() { return GV; } }; /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can /// make the right decision when generating code for different targets. const TargetMachine &TM; const MipsSubtarget *Subtarget; const TargetInstrInfo &TII; const TargetLowering &TLI; MipsFunctionInfo *MFI; // Convenience variables to avoid some queries. LLVMContext *Context; bool fastLowerArguments() override; bool fastLowerCall(CallLoweringInfo &CLI) override; bool fastLowerIntrinsicCall(const IntrinsicInst *II) override; bool UnsupportedFPMode; // To allow fast-isel to proceed and just not handle // floating point but not reject doing fast-isel in other // situations private: // Selection routines. bool selectLogicalOp(const Instruction *I); bool selectLoad(const Instruction *I); bool selectStore(const Instruction *I); bool selectBranch(const Instruction *I); bool selectSelect(const Instruction *I); bool selectCmp(const Instruction *I); bool selectFPExt(const Instruction *I); bool selectFPTrunc(const Instruction *I); bool selectFPToInt(const Instruction *I, bool IsSigned); bool selectRet(const Instruction *I); bool selectTrunc(const Instruction *I); bool selectIntExt(const Instruction *I); bool selectShift(const Instruction *I); bool selectDivRem(const Instruction *I, unsigned ISDOpcode); // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); bool isTypeSupported(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); bool computeAddress(const Value *Obj, Address &Addr); bool computeCallAddress(const Value *V, Address &Addr); void simplifyAddress(Address &Addr); // Emit helper routines. bool emitCmp(unsigned DestReg, const CmpInst *CI); bool emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, unsigned Alignment = 0); bool emitStore(MVT VT, unsigned SrcReg, Address Addr, MachineMemOperand *MMO = nullptr); bool emitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment = 0); unsigned emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); bool emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, bool IsZExt); bool emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); bool emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); bool emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); bool emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg); unsigned getRegEnsuringSimpleIntegerWidening(const Value *, bool IsUnsigned); unsigned emitLogicalOp(unsigned ISDOpc, MVT RetVT, const Value *LHS, const Value *RHS); unsigned materializeFP(const ConstantFP *CFP, MVT VT); unsigned materializeGV(const GlobalValue *GV, MVT VT); unsigned materializeInt(const Constant *C, MVT VT); unsigned materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC); unsigned materializeExternalCallSym(MCSymbol *Syn); MachineInstrBuilder emitInst(unsigned Opc) { return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)); } MachineInstrBuilder emitInst(unsigned Opc, unsigned DstReg) { return BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), DstReg); } MachineInstrBuilder emitInstStore(unsigned Opc, unsigned SrcReg, unsigned MemReg, int64_t MemOffset) { return emitInst(Opc).addReg(SrcReg).addReg(MemReg).addImm(MemOffset); } MachineInstrBuilder emitInstLoad(unsigned Opc, unsigned DstReg, unsigned MemReg, int64_t MemOffset) { return emitInst(Opc, DstReg).addReg(MemReg).addImm(MemOffset); } unsigned fastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill); // for some reason, this default is not generated by tablegen // so we explicitly generate it here. // unsigned fastEmitInst_riir(uint64_t inst, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, uint64_t imm1, uint64_t imm2, unsigned Op3, bool Op3IsKill) { return 0; } // Call handling routines. private: CCAssignFn *CCAssignFnForCall(CallingConv::ID CC) const; bool processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl &ArgVTs, unsigned &NumBytes); bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes); const MipsABIInfo &getABI() const { return static_cast(TM).getABI(); } public: // Backend specific FastISel code. explicit MipsFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) : FastISel(funcInfo, libInfo), TM(funcInfo.MF->getTarget()), Subtarget(&funcInfo.MF->getSubtarget()), TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) { MFI = funcInfo.MF->getInfo(); Context = &funcInfo.Fn->getContext(); UnsupportedFPMode = Subtarget->isFP64bit() || Subtarget->useSoftFloat(); } unsigned fastMaterializeAlloca(const AllocaInst *AI) override; unsigned fastMaterializeConstant(const Constant *C) override; bool fastSelectInstruction(const Instruction *I) override; #include "MipsGenFastISel.inc" }; } // end anonymous namespace. static bool CC_Mips(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) LLVM_ATTRIBUTE_UNUSED; static bool CC_MipsO32_FP32(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { llvm_unreachable("should not be called"); } static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { llvm_unreachable("should not be called"); } #include "MipsGenCallingConv.inc" CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const { return CC_MipsO32; } unsigned MipsFastISel::emitLogicalOp(unsigned ISDOpc, MVT RetVT, const Value *LHS, const Value *RHS) { // Canonicalize immediates to the RHS first. if (isa(LHS) && !isa(RHS)) std::swap(LHS, RHS); unsigned Opc; switch (ISDOpc) { case ISD::AND: Opc = Mips::AND; break; case ISD::OR: Opc = Mips::OR; break; case ISD::XOR: Opc = Mips::XOR; break; default: llvm_unreachable("unexpected opcode"); } unsigned LHSReg = getRegForValue(LHS); if (!LHSReg) return 0; unsigned RHSReg; if (const auto *C = dyn_cast(RHS)) RHSReg = materializeInt(C, MVT::i32); else RHSReg = getRegForValue(RHS); if (!RHSReg) return 0; unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); if (!ResultReg) return 0; emitInst(Opc, ResultReg).addReg(LHSReg).addReg(RHSReg); return ResultReg; } unsigned MipsFastISel::fastMaterializeAlloca(const AllocaInst *AI) { assert(TLI.getValueType(DL, AI->getType(), true) == MVT::i32 && "Alloca should always return a pointer."); DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::LEA_ADDiu), ResultReg) .addFrameIndex(SI->second) .addImm(0); return ResultReg; } return 0; } unsigned MipsFastISel::materializeInt(const Constant *C, MVT VT) { if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) return 0; const TargetRegisterClass *RC = &Mips::GPR32RegClass; const ConstantInt *CI = cast(C); return materialize32BitInt(CI->getZExtValue(), RC); } unsigned MipsFastISel::materialize32BitInt(int64_t Imm, const TargetRegisterClass *RC) { unsigned ResultReg = createResultReg(RC); if (isInt<16>(Imm)) { unsigned Opc = Mips::ADDiu; emitInst(Opc, ResultReg).addReg(Mips::ZERO).addImm(Imm); return ResultReg; } else if (isUInt<16>(Imm)) { emitInst(Mips::ORi, ResultReg).addReg(Mips::ZERO).addImm(Imm); return ResultReg; } unsigned Lo = Imm & 0xFFFF; unsigned Hi = (Imm >> 16) & 0xFFFF; if (Lo) { // Both Lo and Hi have nonzero bits. unsigned TmpReg = createResultReg(RC); emitInst(Mips::LUi, TmpReg).addImm(Hi); emitInst(Mips::ORi, ResultReg).addReg(TmpReg).addImm(Lo); } else { emitInst(Mips::LUi, ResultReg).addImm(Hi); } return ResultReg; } unsigned MipsFastISel::materializeFP(const ConstantFP *CFP, MVT VT) { if (UnsupportedFPMode) return 0; int64_t Imm = CFP->getValueAPF().bitcastToAPInt().getZExtValue(); if (VT == MVT::f32) { const TargetRegisterClass *RC = &Mips::FGR32RegClass; unsigned DestReg = createResultReg(RC); unsigned TempReg = materialize32BitInt(Imm, &Mips::GPR32RegClass); emitInst(Mips::MTC1, DestReg).addReg(TempReg); return DestReg; } else if (VT == MVT::f64) { const TargetRegisterClass *RC = &Mips::AFGR64RegClass; unsigned DestReg = createResultReg(RC); unsigned TempReg1 = materialize32BitInt(Imm >> 32, &Mips::GPR32RegClass); unsigned TempReg2 = materialize32BitInt(Imm & 0xFFFFFFFF, &Mips::GPR32RegClass); emitInst(Mips::BuildPairF64, DestReg).addReg(TempReg2).addReg(TempReg1); return DestReg; } return 0; } unsigned MipsFastISel::materializeGV(const GlobalValue *GV, MVT VT) { // For now 32-bit only. if (VT != MVT::i32) return 0; const TargetRegisterClass *RC = &Mips::GPR32RegClass; unsigned DestReg = createResultReg(RC); const GlobalVariable *GVar = dyn_cast(GV); bool IsThreadLocal = GVar && GVar->isThreadLocal(); // TLS not supported at this time. if (IsThreadLocal) return 0; emitInst(Mips::LW, DestReg) .addReg(MFI->getGlobalBaseReg()) .addGlobalAddress(GV, 0, MipsII::MO_GOT); if ((GV->hasInternalLinkage() || (GV->hasLocalLinkage() && !isa(GV)))) { unsigned TempReg = createResultReg(RC); emitInst(Mips::ADDiu, TempReg) .addReg(DestReg) .addGlobalAddress(GV, 0, MipsII::MO_ABS_LO); DestReg = TempReg; } return DestReg; } unsigned MipsFastISel::materializeExternalCallSym(MCSymbol *Sym) { const TargetRegisterClass *RC = &Mips::GPR32RegClass; unsigned DestReg = createResultReg(RC); emitInst(Mips::LW, DestReg) .addReg(MFI->getGlobalBaseReg()) .addSym(Sym, MipsII::MO_GOT); return DestReg; } // Materialize a constant into a register, and return the register // number (or zero if we failed to handle it). unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) { EVT CEVT = TLI.getValueType(DL, C->getType(), true); // Only handle simple types. if (!CEVT.isSimple()) return 0; MVT VT = CEVT.getSimpleVT(); if (const ConstantFP *CFP = dyn_cast(C)) return (UnsupportedFPMode) ? 0 : materializeFP(CFP, VT); else if (const GlobalValue *GV = dyn_cast(C)) return materializeGV(GV, VT); else if (isa(C)) return materializeInt(C, VT); return 0; } bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { const User *U = nullptr; unsigned Opcode = Instruction::UserOp1; if (const Instruction *I = dyn_cast(Obj)) { // Don't walk into other basic blocks unless the object is an alloca from // another block, otherwise it may not have a virtual register assigned. if (FuncInfo.StaticAllocaMap.count(static_cast(Obj)) || FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { Opcode = I->getOpcode(); U = I; } } else if (const ConstantExpr *C = dyn_cast(Obj)) { Opcode = C->getOpcode(); U = C; } switch (Opcode) { default: break; case Instruction::BitCast: { // Look through bitcasts. return computeAddress(U->getOperand(0), Addr); } case Instruction::GetElementPtr: { Address SavedAddr = Addr; int64_t TmpOffset = Addr.getOffset(); // Iterate through the GEP folding the constants into offsets where // we can. gep_type_iterator GTI = gep_type_begin(U); for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e; ++i, ++GTI) { const Value *Op = *i; if (StructType *STy = GTI.getStructTypeOrNull()) { const StructLayout *SL = DL.getStructLayout(STy); unsigned Idx = cast(Op)->getZExtValue(); TmpOffset += SL->getElementOffset(Idx); } else { uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType()); for (;;) { if (const ConstantInt *CI = dyn_cast(Op)) { // Constant-offset addressing. TmpOffset += CI->getSExtValue() * S; break; } if (canFoldAddIntoGEP(U, Op)) { // A compatible add with a constant operand. Fold the constant. ConstantInt *CI = cast(cast(Op)->getOperand(1)); TmpOffset += CI->getSExtValue() * S; // Iterate on the other operand. Op = cast(Op)->getOperand(0); continue; } // Unsupported goto unsupported_gep; } } } // Try to grab the base operand now. Addr.setOffset(TmpOffset); if (computeAddress(U->getOperand(0), Addr)) return true; // We failed, restore everything and try the other options. Addr = SavedAddr; unsupported_gep: break; } case Instruction::Alloca: { const AllocaInst *AI = cast(Obj); DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { Addr.setKind(Address::FrameIndexBase); Addr.setFI(SI->second); return true; } break; } } Addr.setReg(getRegForValue(Obj)); return Addr.getReg() != 0; } bool MipsFastISel::computeCallAddress(const Value *V, Address &Addr) { const User *U = nullptr; unsigned Opcode = Instruction::UserOp1; if (const auto *I = dyn_cast(V)) { // Check if the value is defined in the same basic block. This information // is crucial to know whether or not folding an operand is valid. if (I->getParent() == FuncInfo.MBB->getBasicBlock()) { Opcode = I->getOpcode(); U = I; } } else if (const auto *C = dyn_cast(V)) { Opcode = C->getOpcode(); U = C; } switch (Opcode) { default: break; case Instruction::BitCast: // Look past bitcasts if its operand is in the same BB. return computeCallAddress(U->getOperand(0), Addr); break; case Instruction::IntToPtr: // Look past no-op inttoptrs if its operand is in the same BB. if (TLI.getValueType(DL, U->getOperand(0)->getType()) == TLI.getPointerTy(DL)) return computeCallAddress(U->getOperand(0), Addr); break; case Instruction::PtrToInt: // Look past no-op ptrtoints if its operand is in the same BB. if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) return computeCallAddress(U->getOperand(0), Addr); break; } if (const GlobalValue *GV = dyn_cast(V)) { Addr.setGlobalValue(GV); return true; } // If all else fails, try to materialize the value in a register. if (!Addr.getGlobalValue()) { Addr.setReg(getRegForValue(V)); return Addr.getReg() != 0; } return false; } bool MipsFastISel::isTypeLegal(Type *Ty, MVT &VT) { EVT evt = TLI.getValueType(DL, Ty, true); // Only handle simple types. if (evt == MVT::Other || !evt.isSimple()) return false; VT = evt.getSimpleVT(); // Handle all legal types, i.e. a register that will directly hold this // value. return TLI.isTypeLegal(VT); } bool MipsFastISel::isTypeSupported(Type *Ty, MVT &VT) { if (Ty->isVectorTy()) return false; if (isTypeLegal(Ty, VT)) return true; // If this is a type than can be sign or zero-extended to a basic operation // go ahead and accept it now. if (VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16) return true; return false; } bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { if (isTypeLegal(Ty, VT)) return true; // We will extend this in a later patch: // If this is a type than can be sign or zero-extended to a basic operation // go ahead and accept it now. if (VT == MVT::i8 || VT == MVT::i16) return true; return false; } // Because of how EmitCmp is called with fast-isel, you can // end up with redundant "andi" instructions after the sequences emitted below. // We should try and solve this issue in the future. // bool MipsFastISel::emitCmp(unsigned ResultReg, const CmpInst *CI) { const Value *Left = CI->getOperand(0), *Right = CI->getOperand(1); bool IsUnsigned = CI->isUnsigned(); unsigned LeftReg = getRegEnsuringSimpleIntegerWidening(Left, IsUnsigned); if (LeftReg == 0) return false; unsigned RightReg = getRegEnsuringSimpleIntegerWidening(Right, IsUnsigned); if (RightReg == 0) return false; CmpInst::Predicate P = CI->getPredicate(); switch (P) { default: return false; case CmpInst::ICMP_EQ: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); emitInst(Mips::SLTiu, ResultReg).addReg(TempReg).addImm(1); break; } case CmpInst::ICMP_NE: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::XOR, TempReg).addReg(LeftReg).addReg(RightReg); emitInst(Mips::SLTu, ResultReg).addReg(Mips::ZERO).addReg(TempReg); break; } case CmpInst::ICMP_UGT: { emitInst(Mips::SLTu, ResultReg).addReg(RightReg).addReg(LeftReg); break; } case CmpInst::ICMP_ULT: { emitInst(Mips::SLTu, ResultReg).addReg(LeftReg).addReg(RightReg); break; } case CmpInst::ICMP_UGE: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::SLTu, TempReg).addReg(LeftReg).addReg(RightReg); emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); break; } case CmpInst::ICMP_ULE: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::SLTu, TempReg).addReg(RightReg).addReg(LeftReg); emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); break; } case CmpInst::ICMP_SGT: { emitInst(Mips::SLT, ResultReg).addReg(RightReg).addReg(LeftReg); break; } case CmpInst::ICMP_SLT: { emitInst(Mips::SLT, ResultReg).addReg(LeftReg).addReg(RightReg); break; } case CmpInst::ICMP_SGE: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::SLT, TempReg).addReg(LeftReg).addReg(RightReg); emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); break; } case CmpInst::ICMP_SLE: { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::SLT, TempReg).addReg(RightReg).addReg(LeftReg); emitInst(Mips::XORi, ResultReg).addReg(TempReg).addImm(1); break; } case CmpInst::FCMP_OEQ: case CmpInst::FCMP_UNE: case CmpInst::FCMP_OLT: case CmpInst::FCMP_OLE: case CmpInst::FCMP_OGT: case CmpInst::FCMP_OGE: { if (UnsupportedFPMode) return false; bool IsFloat = Left->getType()->isFloatTy(); bool IsDouble = Left->getType()->isDoubleTy(); if (!IsFloat && !IsDouble) return false; unsigned Opc, CondMovOpc; switch (P) { case CmpInst::FCMP_OEQ: Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; CondMovOpc = Mips::MOVT_I; break; case CmpInst::FCMP_UNE: Opc = IsFloat ? Mips::C_EQ_S : Mips::C_EQ_D32; CondMovOpc = Mips::MOVF_I; break; case CmpInst::FCMP_OLT: Opc = IsFloat ? Mips::C_OLT_S : Mips::C_OLT_D32; CondMovOpc = Mips::MOVT_I; break; case CmpInst::FCMP_OLE: Opc = IsFloat ? Mips::C_OLE_S : Mips::C_OLE_D32; CondMovOpc = Mips::MOVT_I; break; case CmpInst::FCMP_OGT: Opc = IsFloat ? Mips::C_ULE_S : Mips::C_ULE_D32; CondMovOpc = Mips::MOVF_I; break; case CmpInst::FCMP_OGE: Opc = IsFloat ? Mips::C_ULT_S : Mips::C_ULT_D32; CondMovOpc = Mips::MOVF_I; break; default: llvm_unreachable("Only switching of a subset of CCs."); } unsigned RegWithZero = createResultReg(&Mips::GPR32RegClass); unsigned RegWithOne = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::ADDiu, RegWithZero).addReg(Mips::ZERO).addImm(0); emitInst(Mips::ADDiu, RegWithOne).addReg(Mips::ZERO).addImm(1); - emitInst(Opc).addReg(LeftReg).addReg(RightReg).addReg( - Mips::FCC0, RegState::ImplicitDefine); + emitInst(Opc).addReg(Mips::FCC0, RegState::Define).addReg(LeftReg) + .addReg(RightReg); emitInst(CondMovOpc, ResultReg) .addReg(RegWithOne) .addReg(Mips::FCC0) .addReg(RegWithZero); break; } } return true; } bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr, unsigned Alignment) { // // more cases will be handled here in following patches. // unsigned Opc; switch (VT.SimpleTy) { case MVT::i32: { ResultReg = createResultReg(&Mips::GPR32RegClass); Opc = Mips::LW; break; } case MVT::i16: { ResultReg = createResultReg(&Mips::GPR32RegClass); Opc = Mips::LHu; break; } case MVT::i8: { ResultReg = createResultReg(&Mips::GPR32RegClass); Opc = Mips::LBu; break; } case MVT::f32: { if (UnsupportedFPMode) return false; ResultReg = createResultReg(&Mips::FGR32RegClass); Opc = Mips::LWC1; break; } case MVT::f64: { if (UnsupportedFPMode) return false; ResultReg = createResultReg(&Mips::AFGR64RegClass); Opc = Mips::LDC1; break; } default: return false; } if (Addr.isRegBase()) { simplifyAddress(Addr); emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); return true; } if (Addr.isFIBase()) { unsigned FI = Addr.getFI(); unsigned Align = 4; int64_t Offset = Addr.getOffset(); MachineFrameInfo &MFI = MF->getFrameInfo(); MachineMemOperand *MMO = MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOLoad, MFI.getObjectSize(FI), Align); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) .addFrameIndex(FI) .addImm(Offset) .addMemOperand(MMO); return true; } return false; } bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr, unsigned Alignment) { // // more cases will be handled here in following patches. // unsigned Opc; switch (VT.SimpleTy) { case MVT::i8: Opc = Mips::SB; break; case MVT::i16: Opc = Mips::SH; break; case MVT::i32: Opc = Mips::SW; break; case MVT::f32: if (UnsupportedFPMode) return false; Opc = Mips::SWC1; break; case MVT::f64: if (UnsupportedFPMode) return false; Opc = Mips::SDC1; break; default: return false; } if (Addr.isRegBase()) { simplifyAddress(Addr); emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); return true; } if (Addr.isFIBase()) { unsigned FI = Addr.getFI(); unsigned Align = 4; int64_t Offset = Addr.getOffset(); MachineFrameInfo &MFI = MF->getFrameInfo(); MachineMemOperand *MMO = MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(*MF, FI), MachineMemOperand::MOStore, MFI.getObjectSize(FI), Align); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) .addReg(SrcReg) .addFrameIndex(FI) .addImm(Offset) .addMemOperand(MMO); return true; } return false; } bool MipsFastISel::selectLogicalOp(const Instruction *I) { MVT VT; if (!isTypeSupported(I->getType(), VT)) return false; unsigned ResultReg; switch (I->getOpcode()) { default: llvm_unreachable("Unexpected instruction."); case Instruction::And: ResultReg = emitLogicalOp(ISD::AND, VT, I->getOperand(0), I->getOperand(1)); break; case Instruction::Or: ResultReg = emitLogicalOp(ISD::OR, VT, I->getOperand(0), I->getOperand(1)); break; case Instruction::Xor: ResultReg = emitLogicalOp(ISD::XOR, VT, I->getOperand(0), I->getOperand(1)); break; } if (!ResultReg) return false; updateValueMap(I, ResultReg); return true; } bool MipsFastISel::selectLoad(const Instruction *I) { // Atomic loads need special handling. if (cast(I)->isAtomic()) return false; // Verify we have a legal type before going any further. MVT VT; if (!isLoadTypeLegal(I->getType(), VT)) return false; // See if we can handle this address. Address Addr; if (!computeAddress(I->getOperand(0), Addr)) return false; unsigned ResultReg; if (!emitLoad(VT, ResultReg, Addr, cast(I)->getAlignment())) return false; updateValueMap(I, ResultReg); return true; } bool MipsFastISel::selectStore(const Instruction *I) { Value *Op0 = I->getOperand(0); unsigned SrcReg = 0; // Atomic stores need special handling. if (cast(I)->isAtomic()) return false; // Verify we have a legal type before going any further. MVT VT; if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) return false; // Get the value to be stored into a register. SrcReg = getRegForValue(Op0); if (SrcReg == 0) return false; // See if we can handle this address. Address Addr; if (!computeAddress(I->getOperand(1), Addr)) return false; if (!emitStore(VT, SrcReg, Addr, cast(I)->getAlignment())) return false; return true; } // // This can cause a redundant sltiu to be generated. // FIXME: try and eliminate this in a future patch. // bool MipsFastISel::selectBranch(const Instruction *I) { const BranchInst *BI = cast(I); MachineBasicBlock *BrBB = FuncInfo.MBB; // // TBB is the basic block for the case where the comparison is true. // FBB is the basic block for the case where the comparison is false. // if (cond) goto TBB // goto FBB // TBB: // MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; BI->getCondition(); // For now, just try the simplest case where it's fed by a compare. if (const CmpInst *CI = dyn_cast(BI->getCondition())) { unsigned CondReg = createResultReg(&Mips::GPR32RegClass); if (!emitCmp(CondReg, CI)) return false; BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::BGTZ)) .addReg(CondReg) .addMBB(TBB); finishCondBranch(BI->getParent(), TBB, FBB); return true; } return false; } bool MipsFastISel::selectCmp(const Instruction *I) { const CmpInst *CI = cast(I); unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); if (!emitCmp(ResultReg, CI)) return false; updateValueMap(I, ResultReg); return true; } // Attempt to fast-select a floating-point extend instruction. bool MipsFastISel::selectFPExt(const Instruction *I) { if (UnsupportedFPMode) return false; Value *Src = I->getOperand(0); EVT SrcVT = TLI.getValueType(DL, Src->getType(), true); EVT DestVT = TLI.getValueType(DL, I->getType(), true); if (SrcVT != MVT::f32 || DestVT != MVT::f64) return false; unsigned SrcReg = getRegForValue(Src); // this must be a 32bit floating point register class // maybe we should handle this differently if (!SrcReg) return false; unsigned DestReg = createResultReg(&Mips::AFGR64RegClass); emitInst(Mips::CVT_D32_S, DestReg).addReg(SrcReg); updateValueMap(I, DestReg); return true; } bool MipsFastISel::selectSelect(const Instruction *I) { assert(isa(I) && "Expected a select instruction."); DEBUG(dbgs() << "selectSelect\n"); MVT VT; if (!isTypeSupported(I->getType(), VT) || UnsupportedFPMode) { DEBUG(dbgs() << ".. .. gave up (!isTypeSupported || UnsupportedFPMode)\n"); return false; } unsigned CondMovOpc; const TargetRegisterClass *RC; if (VT.isInteger() && !VT.isVector() && VT.getSizeInBits() <= 32) { CondMovOpc = Mips::MOVN_I_I; RC = &Mips::GPR32RegClass; } else if (VT == MVT::f32) { CondMovOpc = Mips::MOVN_I_S; RC = &Mips::FGR32RegClass; } else if (VT == MVT::f64) { CondMovOpc = Mips::MOVN_I_D32; RC = &Mips::AFGR64RegClass; } else return false; const SelectInst *SI = cast(I); const Value *Cond = SI->getCondition(); unsigned Src1Reg = getRegForValue(SI->getTrueValue()); unsigned Src2Reg = getRegForValue(SI->getFalseValue()); unsigned CondReg = getRegForValue(Cond); if (!Src1Reg || !Src2Reg || !CondReg) return false; unsigned ZExtCondReg = createResultReg(&Mips::GPR32RegClass); if (!ZExtCondReg) return false; if (!emitIntExt(MVT::i1, CondReg, MVT::i32, ZExtCondReg, true)) return false; unsigned ResultReg = createResultReg(RC); unsigned TempReg = createResultReg(RC); if (!ResultReg || !TempReg) return false; emitInst(TargetOpcode::COPY, TempReg).addReg(Src2Reg); emitInst(CondMovOpc, ResultReg) .addReg(Src1Reg).addReg(ZExtCondReg).addReg(TempReg); updateValueMap(I, ResultReg); return true; } // Attempt to fast-select a floating-point truncate instruction. bool MipsFastISel::selectFPTrunc(const Instruction *I) { if (UnsupportedFPMode) return false; Value *Src = I->getOperand(0); EVT SrcVT = TLI.getValueType(DL, Src->getType(), true); EVT DestVT = TLI.getValueType(DL, I->getType(), true); if (SrcVT != MVT::f64 || DestVT != MVT::f32) return false; unsigned SrcReg = getRegForValue(Src); if (!SrcReg) return false; unsigned DestReg = createResultReg(&Mips::FGR32RegClass); if (!DestReg) return false; emitInst(Mips::CVT_S_D32, DestReg).addReg(SrcReg); updateValueMap(I, DestReg); return true; } // Attempt to fast-select a floating-point-to-integer conversion. bool MipsFastISel::selectFPToInt(const Instruction *I, bool IsSigned) { if (UnsupportedFPMode) return false; MVT DstVT, SrcVT; if (!IsSigned) return false; // We don't handle this case yet. There is no native // instruction for this but it can be synthesized. Type *DstTy = I->getType(); if (!isTypeLegal(DstTy, DstVT)) return false; if (DstVT != MVT::i32) return false; Value *Src = I->getOperand(0); Type *SrcTy = Src->getType(); if (!isTypeLegal(SrcTy, SrcVT)) return false; if (SrcVT != MVT::f32 && SrcVT != MVT::f64) return false; unsigned SrcReg = getRegForValue(Src); if (SrcReg == 0) return false; // Determine the opcode for the conversion, which takes place // entirely within FPRs. unsigned DestReg = createResultReg(&Mips::GPR32RegClass); unsigned TempReg = createResultReg(&Mips::FGR32RegClass); unsigned Opc = (SrcVT == MVT::f32) ? Mips::TRUNC_W_S : Mips::TRUNC_W_D32; // Generate the convert. emitInst(Opc, TempReg).addReg(SrcReg); emitInst(Mips::MFC1, DestReg).addReg(TempReg); updateValueMap(I, DestReg); return true; } bool MipsFastISel::processCallArgs(CallLoweringInfo &CLI, SmallVectorImpl &OutVTs, unsigned &NumBytes) { CallingConv::ID CC = CLI.CallConv; SmallVector ArgLocs; CCState CCInfo(CC, false, *FuncInfo.MF, ArgLocs, *Context); CCInfo.AnalyzeCallOperands(OutVTs, CLI.OutFlags, CCAssignFnForCall(CC)); // Get a count of how many bytes are to be pushed on the stack. NumBytes = CCInfo.getNextStackOffset(); // This is the minimum argument area used for A0-A3. if (NumBytes < 16) NumBytes = 16; emitInst(Mips::ADJCALLSTACKDOWN).addImm(16); // Process the args. MVT firstMVT; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; const Value *ArgVal = CLI.OutVals[VA.getValNo()]; MVT ArgVT = OutVTs[VA.getValNo()]; if (i == 0) { firstMVT = ArgVT; if (ArgVT == MVT::f32) { VA.convertToReg(Mips::F12); } else if (ArgVT == MVT::f64) { VA.convertToReg(Mips::D6); } } else if (i == 1) { if ((firstMVT == MVT::f32) || (firstMVT == MVT::f64)) { if (ArgVT == MVT::f32) { VA.convertToReg(Mips::F14); } else if (ArgVT == MVT::f64) { VA.convertToReg(Mips::D7); } } } if (((ArgVT == MVT::i32) || (ArgVT == MVT::f32) || (ArgVT == MVT::i16) || (ArgVT == MVT::i8)) && VA.isMemLoc()) { switch (VA.getLocMemOffset()) { case 0: VA.convertToReg(Mips::A0); break; case 4: VA.convertToReg(Mips::A1); break; case 8: VA.convertToReg(Mips::A2); break; case 12: VA.convertToReg(Mips::A3); break; default: break; } } unsigned ArgReg = getRegForValue(ArgVal); if (!ArgReg) return false; // Handle arg promotion: SExt, ZExt, AExt. switch (VA.getLocInfo()) { case CCValAssign::Full: break; case CCValAssign::AExt: case CCValAssign::SExt: { MVT DestVT = VA.getLocVT(); MVT SrcVT = ArgVT; ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/false); if (!ArgReg) return false; break; } case CCValAssign::ZExt: { MVT DestVT = VA.getLocVT(); MVT SrcVT = ArgVT; ArgReg = emitIntExt(SrcVT, ArgReg, DestVT, /*isZExt=*/true); if (!ArgReg) return false; break; } default: llvm_unreachable("Unknown arg promotion!"); } // Now copy/store arg to correct locations. if (VA.isRegLoc() && !VA.needsCustom()) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(ArgReg); CLI.OutRegs.push_back(VA.getLocReg()); } else if (VA.needsCustom()) { llvm_unreachable("Mips does not use custom args."); return false; } else { // // FIXME: This path will currently return false. It was copied // from the AArch64 port and should be essentially fine for Mips too. // The work to finish up this path will be done in a follow-on patch. // assert(VA.isMemLoc() && "Assuming store on stack."); // Don't emit stores for undef values. if (isa(ArgVal)) continue; // Need to store on the stack. // FIXME: This alignment is incorrect but this path is disabled // for now (will return false). We need to determine the right alignment // based on the normal alignment for the underlying machine type. // unsigned ArgSize = alignTo(ArgVT.getSizeInBits(), 4); unsigned BEAlign = 0; if (ArgSize < 8 && !Subtarget->isLittle()) BEAlign = 8 - ArgSize; Address Addr; Addr.setKind(Address::RegBase); Addr.setReg(Mips::SP); Addr.setOffset(VA.getLocMemOffset() + BEAlign); unsigned Alignment = DL.getABITypeAlignment(ArgVal->getType()); MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( MachinePointerInfo::getStack(*FuncInfo.MF, Addr.getOffset()), MachineMemOperand::MOStore, ArgVT.getStoreSize(), Alignment); (void)(MMO); // if (!emitStore(ArgVT, ArgReg, Addr, MMO)) return false; // can't store on the stack yet. } } return true; } bool MipsFastISel::finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes) { CallingConv::ID CC = CLI.CallConv; emitInst(Mips::ADJCALLSTACKUP).addImm(16).addImm(0); if (RetVT != MVT::isVoid) { SmallVector RVLocs; CCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context); CCInfo.AnalyzeCallResult(RetVT, RetCC_Mips); // Only handle a single return value. if (RVLocs.size() != 1) return false; // Copy all of the result registers out of their specified physreg. MVT CopyVT = RVLocs[0].getValVT(); // Special handling for extended integers. if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16) CopyVT = MVT::i32; unsigned ResultReg = createResultReg(TLI.getRegClassFor(CopyVT)); if (!ResultReg) return false; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY), ResultReg).addReg(RVLocs[0].getLocReg()); CLI.InRegs.push_back(RVLocs[0].getLocReg()); CLI.ResultReg = ResultReg; CLI.NumResultRegs = 1; } return true; } bool MipsFastISel::fastLowerArguments() { DEBUG(dbgs() << "fastLowerArguments\n"); if (!FuncInfo.CanLowerReturn) { DEBUG(dbgs() << ".. gave up (!CanLowerReturn)\n"); return false; } const Function *F = FuncInfo.Fn; if (F->isVarArg()) { DEBUG(dbgs() << ".. gave up (varargs)\n"); return false; } CallingConv::ID CC = F->getCallingConv(); if (CC != CallingConv::C) { DEBUG(dbgs() << ".. gave up (calling convention is not C)\n"); return false; } const ArrayRef GPR32ArgRegs = {Mips::A0, Mips::A1, Mips::A2, Mips::A3}; const ArrayRef FGR32ArgRegs = {Mips::F12, Mips::F14}; const ArrayRef AFGR64ArgRegs = {Mips::D6, Mips::D7}; ArrayRef::iterator NextGPR32 = GPR32ArgRegs.begin(); ArrayRef::iterator NextFGR32 = FGR32ArgRegs.begin(); ArrayRef::iterator NextAFGR64 = AFGR64ArgRegs.begin(); struct AllocatedReg { const TargetRegisterClass *RC; unsigned Reg; AllocatedReg(const TargetRegisterClass *RC, unsigned Reg) : RC(RC), Reg(Reg) {} }; // Only handle simple cases. i.e. All arguments are directly mapped to // registers of the appropriate type. SmallVector Allocation; unsigned Idx = 1; for (const auto &FormalArg : F->args()) { if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) || F->getAttributes().hasAttribute(Idx, Attribute::StructRet) || F->getAttributes().hasAttribute(Idx, Attribute::ByVal)) { DEBUG(dbgs() << ".. gave up (inreg, structret, byval)\n"); return false; } Type *ArgTy = FormalArg.getType(); if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy()) { DEBUG(dbgs() << ".. gave up (struct, array, or vector)\n"); return false; } EVT ArgVT = TLI.getValueType(DL, ArgTy); DEBUG(dbgs() << ".. " << (Idx - 1) << ": " << ArgVT.getEVTString() << "\n"); if (!ArgVT.isSimple()) { DEBUG(dbgs() << ".. .. gave up (not a simple type)\n"); return false; } switch (ArgVT.getSimpleVT().SimpleTy) { case MVT::i1: case MVT::i8: case MVT::i16: if (!F->getAttributes().hasAttribute(Idx, Attribute::SExt) && !F->getAttributes().hasAttribute(Idx, Attribute::ZExt)) { // It must be any extend, this shouldn't happen for clang-generated IR // so just fall back on SelectionDAG. DEBUG(dbgs() << ".. .. gave up (i8/i16 arg is not extended)\n"); return false; } if (NextGPR32 == GPR32ArgRegs.end()) { DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n"); return false; } DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n"); Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++); // Allocating any GPR32 prohibits further use of floating point arguments. NextFGR32 = FGR32ArgRegs.end(); NextAFGR64 = AFGR64ArgRegs.end(); break; case MVT::i32: if (F->getAttributes().hasAttribute(Idx, Attribute::ZExt)) { // The O32 ABI does not permit a zero-extended i32. DEBUG(dbgs() << ".. .. gave up (i32 arg is zero extended)\n"); return false; } if (NextGPR32 == GPR32ArgRegs.end()) { DEBUG(dbgs() << ".. .. gave up (ran out of GPR32 arguments)\n"); return false; } DEBUG(dbgs() << ".. .. GPR32(" << *NextGPR32 << ")\n"); Allocation.emplace_back(&Mips::GPR32RegClass, *NextGPR32++); // Allocating any GPR32 prohibits further use of floating point arguments. NextFGR32 = FGR32ArgRegs.end(); NextAFGR64 = AFGR64ArgRegs.end(); break; case MVT::f32: if (UnsupportedFPMode) { DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n"); return false; } if (NextFGR32 == FGR32ArgRegs.end()) { DEBUG(dbgs() << ".. .. gave up (ran out of FGR32 arguments)\n"); return false; } DEBUG(dbgs() << ".. .. FGR32(" << *NextFGR32 << ")\n"); Allocation.emplace_back(&Mips::FGR32RegClass, *NextFGR32++); // Allocating an FGR32 also allocates the super-register AFGR64, and // ABI rules require us to skip the corresponding GPR32. if (NextGPR32 != GPR32ArgRegs.end()) NextGPR32++; if (NextAFGR64 != AFGR64ArgRegs.end()) NextAFGR64++; break; case MVT::f64: if (UnsupportedFPMode) { DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode)\n"); return false; } if (NextAFGR64 == AFGR64ArgRegs.end()) { DEBUG(dbgs() << ".. .. gave up (ran out of AFGR64 arguments)\n"); return false; } DEBUG(dbgs() << ".. .. AFGR64(" << *NextAFGR64 << ")\n"); Allocation.emplace_back(&Mips::AFGR64RegClass, *NextAFGR64++); // Allocating an FGR32 also allocates the super-register AFGR64, and // ABI rules require us to skip the corresponding GPR32 pair. if (NextGPR32 != GPR32ArgRegs.end()) NextGPR32++; if (NextGPR32 != GPR32ArgRegs.end()) NextGPR32++; if (NextFGR32 != FGR32ArgRegs.end()) NextFGR32++; break; default: DEBUG(dbgs() << ".. .. gave up (unknown type)\n"); return false; } ++Idx; } Idx = 0; for (const auto &FormalArg : F->args()) { unsigned SrcReg = Allocation[Idx].Reg; unsigned DstReg = FuncInfo.MF->addLiveIn(SrcReg, Allocation[Idx].RC); // FIXME: Unfortunately it's necessary to emit a copy from the livein copy. // Without this, EmitLiveInCopies may eliminate the livein if its only // use is a bitcast (which isn't turned into an instruction). unsigned ResultReg = createResultReg(Allocation[Idx].RC); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY), ResultReg) .addReg(DstReg, getKillRegState(true)); updateValueMap(&FormalArg, ResultReg); ++Idx; } // Calculate the size of the incoming arguments area. // We currently reject all the cases where this would be non-zero. unsigned IncomingArgSizeInBytes = 0; // Account for the reserved argument area on ABI's that have one (O32). // It seems strange to do this on the caller side but it's necessary in // SelectionDAG's implementation. IncomingArgSizeInBytes = std::min(getABI().GetCalleeAllocdArgSizeInBytes(CC), IncomingArgSizeInBytes); MF->getInfo()->setFormalArgInfo(IncomingArgSizeInBytes, false); return true; } bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) { CallingConv::ID CC = CLI.CallConv; bool IsTailCall = CLI.IsTailCall; bool IsVarArg = CLI.IsVarArg; const Value *Callee = CLI.Callee; MCSymbol *Symbol = CLI.Symbol; // Do not handle FastCC. if (CC == CallingConv::Fast) return false; // Allow SelectionDAG isel to handle tail calls. if (IsTailCall) return false; // Let SDISel handle vararg functions. if (IsVarArg) return false; // FIXME: Only handle *simple* calls for now. MVT RetVT; if (CLI.RetTy->isVoidTy()) RetVT = MVT::isVoid; else if (!isTypeSupported(CLI.RetTy, RetVT)) return false; for (auto Flag : CLI.OutFlags) if (Flag.isInReg() || Flag.isSRet() || Flag.isNest() || Flag.isByVal()) return false; // Set up the argument vectors. SmallVector OutVTs; OutVTs.reserve(CLI.OutVals.size()); for (auto *Val : CLI.OutVals) { MVT VT; if (!isTypeLegal(Val->getType(), VT) && !(VT == MVT::i1 || VT == MVT::i8 || VT == MVT::i16)) return false; // We don't handle vector parameters yet. if (VT.isVector() || VT.getSizeInBits() > 64) return false; OutVTs.push_back(VT); } Address Addr; if (!computeCallAddress(Callee, Addr)) return false; // Handle the arguments now that we've gotten them. unsigned NumBytes; if (!processCallArgs(CLI, OutVTs, NumBytes)) return false; if (!Addr.getGlobalValue()) return false; // Issue the call. unsigned DestAddress; if (Symbol) DestAddress = materializeExternalCallSym(Symbol); else DestAddress = materializeGV(Addr.getGlobalValue(), MVT::i32); emitInst(TargetOpcode::COPY, Mips::T9).addReg(DestAddress); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Mips::JALR), Mips::RA).addReg(Mips::T9); // Add implicit physical register uses to the call. for (auto Reg : CLI.OutRegs) MIB.addReg(Reg, RegState::Implicit); // Add a register mask with the call-preserved registers. // Proper defs for return values will be added by setPhysRegsDeadExcept(). MIB.addRegMask(TRI.getCallPreservedMask(*FuncInfo.MF, CC)); CLI.Call = MIB; // Finish off the call including any return values. return finishCall(CLI, RetVT, NumBytes); } bool MipsFastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) { switch (II->getIntrinsicID()) { default: return false; case Intrinsic::bswap: { Type *RetTy = II->getCalledFunction()->getReturnType(); MVT VT; if (!isTypeSupported(RetTy, VT)) return false; unsigned SrcReg = getRegForValue(II->getOperand(0)); if (SrcReg == 0) return false; unsigned DestReg = createResultReg(&Mips::GPR32RegClass); if (DestReg == 0) return false; if (VT == MVT::i16) { if (Subtarget->hasMips32r2()) { emitInst(Mips::WSBH, DestReg).addReg(SrcReg); updateValueMap(II, DestReg); return true; } else { unsigned TempReg[3]; for (int i = 0; i < 3; i++) { TempReg[i] = createResultReg(&Mips::GPR32RegClass); if (TempReg[i] == 0) return false; } emitInst(Mips::SLL, TempReg[0]).addReg(SrcReg).addImm(8); emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(8); emitInst(Mips::OR, TempReg[2]).addReg(TempReg[0]).addReg(TempReg[1]); emitInst(Mips::ANDi, DestReg).addReg(TempReg[2]).addImm(0xFFFF); updateValueMap(II, DestReg); return true; } } else if (VT == MVT::i32) { if (Subtarget->hasMips32r2()) { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::WSBH, TempReg).addReg(SrcReg); emitInst(Mips::ROTR, DestReg).addReg(TempReg).addImm(16); updateValueMap(II, DestReg); return true; } else { unsigned TempReg[8]; for (int i = 0; i < 8; i++) { TempReg[i] = createResultReg(&Mips::GPR32RegClass); if (TempReg[i] == 0) return false; } emitInst(Mips::SRL, TempReg[0]).addReg(SrcReg).addImm(8); emitInst(Mips::SRL, TempReg[1]).addReg(SrcReg).addImm(24); emitInst(Mips::ANDi, TempReg[2]).addReg(TempReg[0]).addImm(0xFF00); emitInst(Mips::OR, TempReg[3]).addReg(TempReg[1]).addReg(TempReg[2]); emitInst(Mips::ANDi, TempReg[4]).addReg(SrcReg).addImm(0xFF00); emitInst(Mips::SLL, TempReg[5]).addReg(TempReg[4]).addImm(8); emitInst(Mips::SLL, TempReg[6]).addReg(SrcReg).addImm(24); emitInst(Mips::OR, TempReg[7]).addReg(TempReg[3]).addReg(TempReg[5]); emitInst(Mips::OR, DestReg).addReg(TempReg[6]).addReg(TempReg[7]); updateValueMap(II, DestReg); return true; } } return false; } case Intrinsic::memcpy: case Intrinsic::memmove: { const auto *MTI = cast(II); // Don't handle volatile. if (MTI->isVolatile()) return false; if (!MTI->getLength()->getType()->isIntegerTy(32)) return false; const char *IntrMemName = isa(II) ? "memcpy" : "memmove"; return lowerCallTo(II, IntrMemName, II->getNumArgOperands() - 2); } case Intrinsic::memset: { const MemSetInst *MSI = cast(II); // Don't handle volatile. if (MSI->isVolatile()) return false; if (!MSI->getLength()->getType()->isIntegerTy(32)) return false; return lowerCallTo(II, "memset", II->getNumArgOperands() - 2); } } return false; } bool MipsFastISel::selectRet(const Instruction *I) { const Function &F = *I->getParent()->getParent(); const ReturnInst *Ret = cast(I); DEBUG(dbgs() << "selectRet\n"); if (!FuncInfo.CanLowerReturn) return false; // Build a list of return value registers. SmallVector RetRegs; if (Ret->getNumOperands() > 0) { CallingConv::ID CC = F.getCallingConv(); // Do not handle FastCC. if (CC == CallingConv::Fast) return false; SmallVector Outs; GetReturnInfo(F.getReturnType(), F.getAttributes(), Outs, TLI, DL); // Analyze operands of the call, assigning locations to each operand. SmallVector ValLocs; MipsCCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs, I->getContext()); CCAssignFn *RetCC = RetCC_Mips; CCInfo.AnalyzeReturn(Outs, RetCC); // Only handle a single return value for now. if (ValLocs.size() != 1) return false; CCValAssign &VA = ValLocs[0]; const Value *RV = Ret->getOperand(0); // Don't bother handling odd stuff for now. if ((VA.getLocInfo() != CCValAssign::Full) && (VA.getLocInfo() != CCValAssign::BCvt)) return false; // Only handle register returns for now. if (!VA.isRegLoc()) return false; unsigned Reg = getRegForValue(RV); if (Reg == 0) return false; unsigned SrcReg = Reg + VA.getValNo(); unsigned DestReg = VA.getLocReg(); // Avoid a cross-class copy. This is very unlikely. if (!MRI.getRegClass(SrcReg)->contains(DestReg)) return false; EVT RVEVT = TLI.getValueType(DL, RV->getType()); if (!RVEVT.isSimple()) return false; if (RVEVT.isVector()) return false; MVT RVVT = RVEVT.getSimpleVT(); if (RVVT == MVT::f128) return false; // Do not handle FGR64 returns for now. if (RVVT == MVT::f64 && UnsupportedFPMode) { DEBUG(dbgs() << ".. .. gave up (UnsupportedFPMode\n"); return false; } MVT DestVT = VA.getValVT(); // Special handling for extended integers. if (RVVT != DestVT) { if (RVVT != MVT::i1 && RVVT != MVT::i8 && RVVT != MVT::i16) return false; if (Outs[0].Flags.isZExt() || Outs[0].Flags.isSExt()) { bool IsZExt = Outs[0].Flags.isZExt(); SrcReg = emitIntExt(RVVT, SrcReg, DestVT, IsZExt); if (SrcReg == 0) return false; } } // Make the copy. BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY), DestReg).addReg(SrcReg); // Add register to return instruction. RetRegs.push_back(VA.getLocReg()); } MachineInstrBuilder MIB = emitInst(Mips::RetRA); for (unsigned i = 0, e = RetRegs.size(); i != e; ++i) MIB.addReg(RetRegs[i], RegState::Implicit); return true; } bool MipsFastISel::selectTrunc(const Instruction *I) { // The high bits for a type smaller than the register size are assumed to be // undefined. Value *Op = I->getOperand(0); EVT SrcVT, DestVT; SrcVT = TLI.getValueType(DL, Op->getType(), true); DestVT = TLI.getValueType(DL, I->getType(), true); if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) return false; if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) return false; unsigned SrcReg = getRegForValue(Op); if (!SrcReg) return false; // Because the high bits are undefined, a truncate doesn't generate // any code. updateValueMap(I, SrcReg); return true; } bool MipsFastISel::selectIntExt(const Instruction *I) { Type *DestTy = I->getType(); Value *Src = I->getOperand(0); Type *SrcTy = Src->getType(); bool isZExt = isa(I); unsigned SrcReg = getRegForValue(Src); if (!SrcReg) return false; EVT SrcEVT, DestEVT; SrcEVT = TLI.getValueType(DL, SrcTy, true); DestEVT = TLI.getValueType(DL, DestTy, true); if (!SrcEVT.isSimple()) return false; if (!DestEVT.isSimple()) return false; MVT SrcVT = SrcEVT.getSimpleVT(); MVT DestVT = DestEVT.getSimpleVT(); unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); if (!emitIntExt(SrcVT, SrcReg, DestVT, ResultReg, isZExt)) return false; updateValueMap(I, ResultReg); return true; } bool MipsFastISel::emitIntSExt32r1(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg) { unsigned ShiftAmt; switch (SrcVT.SimpleTy) { default: return false; case MVT::i8: ShiftAmt = 24; break; case MVT::i16: ShiftAmt = 16; break; } unsigned TempReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::SLL, TempReg).addReg(SrcReg).addImm(ShiftAmt); emitInst(Mips::SRA, DestReg).addReg(TempReg).addImm(ShiftAmt); return true; } bool MipsFastISel::emitIntSExt32r2(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg) { switch (SrcVT.SimpleTy) { default: return false; case MVT::i8: emitInst(Mips::SEB, DestReg).addReg(SrcReg); break; case MVT::i16: emitInst(Mips::SEH, DestReg).addReg(SrcReg); break; } return true; } bool MipsFastISel::emitIntSExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg) { if ((DestVT != MVT::i32) && (DestVT != MVT::i16)) return false; if (Subtarget->hasMips32r2()) return emitIntSExt32r2(SrcVT, SrcReg, DestVT, DestReg); return emitIntSExt32r1(SrcVT, SrcReg, DestVT, DestReg); } bool MipsFastISel::emitIntZExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg) { int64_t Imm; switch (SrcVT.SimpleTy) { default: return false; case MVT::i1: Imm = 1; break; case MVT::i8: Imm = 0xff; break; case MVT::i16: Imm = 0xffff; break; } emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(Imm); return true; } bool MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, bool IsZExt) { // FastISel does not have plumbing to deal with extensions where the SrcVT or // DestVT are odd things, so test to make sure that they are both types we can // handle (i1/i8/i16/i32 for SrcVT and i8/i16/i32/i64 for DestVT), otherwise // bail out to SelectionDAG. if (((DestVT != MVT::i8) && (DestVT != MVT::i16) && (DestVT != MVT::i32)) || ((SrcVT != MVT::i1) && (SrcVT != MVT::i8) && (SrcVT != MVT::i16))) return false; if (IsZExt) return emitIntZExt(SrcVT, SrcReg, DestVT, DestReg); return emitIntSExt(SrcVT, SrcReg, DestVT, DestReg); } unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt) { unsigned DestReg = createResultReg(&Mips::GPR32RegClass); bool Success = emitIntExt(SrcVT, SrcReg, DestVT, DestReg, isZExt); return Success ? DestReg : 0; } bool MipsFastISel::selectDivRem(const Instruction *I, unsigned ISDOpcode) { EVT DestEVT = TLI.getValueType(DL, I->getType(), true); if (!DestEVT.isSimple()) return false; MVT DestVT = DestEVT.getSimpleVT(); if (DestVT != MVT::i32) return false; unsigned DivOpc; switch (ISDOpcode) { default: return false; case ISD::SDIV: case ISD::SREM: DivOpc = Mips::SDIV; break; case ISD::UDIV: case ISD::UREM: DivOpc = Mips::UDIV; break; } unsigned Src0Reg = getRegForValue(I->getOperand(0)); unsigned Src1Reg = getRegForValue(I->getOperand(1)); if (!Src0Reg || !Src1Reg) return false; emitInst(DivOpc).addReg(Src0Reg).addReg(Src1Reg); emitInst(Mips::TEQ).addReg(Src1Reg).addReg(Mips::ZERO).addImm(7); unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); if (!ResultReg) return false; unsigned MFOpc = (ISDOpcode == ISD::SREM || ISDOpcode == ISD::UREM) ? Mips::MFHI : Mips::MFLO; emitInst(MFOpc, ResultReg); updateValueMap(I, ResultReg); return true; } bool MipsFastISel::selectShift(const Instruction *I) { MVT RetVT; if (!isTypeSupported(I->getType(), RetVT)) return false; unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); if (!ResultReg) return false; unsigned Opcode = I->getOpcode(); const Value *Op0 = I->getOperand(0); unsigned Op0Reg = getRegForValue(Op0); if (!Op0Reg) return false; // If AShr or LShr, then we need to make sure the operand0 is sign extended. if (Opcode == Instruction::AShr || Opcode == Instruction::LShr) { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); if (!TempReg) return false; MVT Op0MVT = TLI.getValueType(DL, Op0->getType(), true).getSimpleVT(); bool IsZExt = Opcode == Instruction::LShr; if (!emitIntExt(Op0MVT, Op0Reg, MVT::i32, TempReg, IsZExt)) return false; Op0Reg = TempReg; } if (const auto *C = dyn_cast(I->getOperand(1))) { uint64_t ShiftVal = C->getZExtValue(); switch (Opcode) { default: llvm_unreachable("Unexpected instruction."); case Instruction::Shl: Opcode = Mips::SLL; break; case Instruction::AShr: Opcode = Mips::SRA; break; case Instruction::LShr: Opcode = Mips::SRL; break; } emitInst(Opcode, ResultReg).addReg(Op0Reg).addImm(ShiftVal); updateValueMap(I, ResultReg); return true; } unsigned Op1Reg = getRegForValue(I->getOperand(1)); if (!Op1Reg) return false; switch (Opcode) { default: llvm_unreachable("Unexpected instruction."); case Instruction::Shl: Opcode = Mips::SLLV; break; case Instruction::AShr: Opcode = Mips::SRAV; break; case Instruction::LShr: Opcode = Mips::SRLV; break; } emitInst(Opcode, ResultReg).addReg(Op0Reg).addReg(Op1Reg); updateValueMap(I, ResultReg); return true; } bool MipsFastISel::fastSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { default: break; case Instruction::Load: return selectLoad(I); case Instruction::Store: return selectStore(I); case Instruction::SDiv: if (!selectBinaryOp(I, ISD::SDIV)) return selectDivRem(I, ISD::SDIV); return true; case Instruction::UDiv: if (!selectBinaryOp(I, ISD::UDIV)) return selectDivRem(I, ISD::UDIV); return true; case Instruction::SRem: if (!selectBinaryOp(I, ISD::SREM)) return selectDivRem(I, ISD::SREM); return true; case Instruction::URem: if (!selectBinaryOp(I, ISD::UREM)) return selectDivRem(I, ISD::UREM); return true; case Instruction::Shl: case Instruction::LShr: case Instruction::AShr: return selectShift(I); case Instruction::And: case Instruction::Or: case Instruction::Xor: return selectLogicalOp(I); case Instruction::Br: return selectBranch(I); case Instruction::Ret: return selectRet(I); case Instruction::Trunc: return selectTrunc(I); case Instruction::ZExt: case Instruction::SExt: return selectIntExt(I); case Instruction::FPTrunc: return selectFPTrunc(I); case Instruction::FPExt: return selectFPExt(I); case Instruction::FPToSI: return selectFPToInt(I, /*isSigned*/ true); case Instruction::FPToUI: return selectFPToInt(I, /*isSigned*/ false); case Instruction::ICmp: case Instruction::FCmp: return selectCmp(I); case Instruction::Select: return selectSelect(I); } return false; } unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V, bool IsUnsigned) { unsigned VReg = getRegForValue(V); if (VReg == 0) return 0; MVT VMVT = TLI.getValueType(DL, V->getType(), true).getSimpleVT(); if ((VMVT == MVT::i8) || (VMVT == MVT::i16)) { unsigned TempReg = createResultReg(&Mips::GPR32RegClass); if (!emitIntExt(VMVT, VReg, MVT::i32, TempReg, IsUnsigned)) return 0; VReg = TempReg; } return VReg; } void MipsFastISel::simplifyAddress(Address &Addr) { if (!isInt<16>(Addr.getOffset())) { unsigned TempReg = materialize32BitInt(Addr.getOffset(), &Mips::GPR32RegClass); unsigned DestReg = createResultReg(&Mips::GPR32RegClass); emitInst(Mips::ADDu, DestReg).addReg(TempReg).addReg(Addr.getReg()); Addr.setReg(DestReg); Addr.setOffset(0); } } unsigned MipsFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, bool Op0IsKill, unsigned Op1, bool Op1IsKill) { // We treat the MUL instruction in a special way because it clobbers // the HI0 & LO0 registers. The TableGen definition of this instruction can // mark these registers only as implicitly defined. As a result, the // register allocator runs out of registers when this instruction is // followed by another instruction that defines the same registers too. // We can fix this by explicitly marking those registers as dead. if (MachineInstOpcode == Mips::MUL) { unsigned ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); Op0 = constrainOperandRegClass(II, Op0, II.getNumDefs()); Op1 = constrainOperandRegClass(II, Op1, II.getNumDefs() + 1); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg) .addReg(Op0, getKillRegState(Op0IsKill)) .addReg(Op1, getKillRegState(Op1IsKill)) .addReg(Mips::HI0, RegState::ImplicitDefine | RegState::Dead) .addReg(Mips::LO0, RegState::ImplicitDefine | RegState::Dead); return ResultReg; } return FastISel::fastEmitInst_rr(MachineInstOpcode, RC, Op0, Op0IsKill, Op1, Op1IsKill); } namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { return new MipsFastISel(funcInfo, libInfo); } } Index: vendor/llvm/dist/lib/Target/Mips/MipsInstrFPU.td =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsInstrFPU.td (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsInstrFPU.td (revision 313056) @@ -1,687 +1,834 @@ //===-- MipsInstrFPU.td - Mips FPU Instruction Information -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the Mips FPU instruction set. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Floating Point Instructions // ------------------------ // * 64bit fp: // - 32 64-bit registers (default mode) // - 16 even 32-bit registers (32-bit compatible mode) for // single and double access. // * 32bit fp: // - 16 even 32-bit registers - single and double (aliased) // - 32 32-bit registers (within single-only mode) //===----------------------------------------------------------------------===// // Floating Point Compare and Branch def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisVT<1, i32>, SDTCisVT<2, OtherVT>]>; def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<1>, SDTCisVT<2, i32>]>; def SDT_MipsCMovFP : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisVT<2, i32>, SDTCisSameAs<1, 3>]>; def SDT_MipsTruncIntFP : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisFP<1>]>; def SDT_MipsBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>, SDTCisVT<1, i32>, SDTCisSameAs<1, 2>]>; def SDT_MipsExtractElementF64 : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisVT<1, f64>, SDTCisVT<2, i32>]>; def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp, [SDNPOutGlue]>; def MipsCMovFP_T : SDNode<"MipsISD::CMovFP_T", SDT_MipsCMovFP, [SDNPInGlue]>; def MipsCMovFP_F : SDNode<"MipsISD::CMovFP_F", SDT_MipsCMovFP, [SDNPInGlue]>; def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond, [SDNPHasChain, SDNPOptInGlue]>; def MipsTruncIntFP : SDNode<"MipsISD::TruncIntFP", SDT_MipsTruncIntFP>; def MipsBuildPairF64 : SDNode<"MipsISD::BuildPairF64", SDT_MipsBuildPairF64>; def MipsExtractElementF64 : SDNode<"MipsISD::ExtractElementF64", SDT_MipsExtractElementF64>; // Operand for printing out a condition code. let PrintMethod = "printFCCOperand", DecoderMethod = "DecodeCondCode" in def condcode : Operand; //===----------------------------------------------------------------------===// // Feature predicates. //===----------------------------------------------------------------------===// def IsFP64bit : Predicate<"Subtarget->isFP64bit()">, AssemblerPredicate<"FeatureFP64Bit">; def NotFP64bit : Predicate<"!Subtarget->isFP64bit()">, AssemblerPredicate<"!FeatureFP64Bit">; def IsSingleFloat : Predicate<"Subtarget->isSingleFloat()">, AssemblerPredicate<"FeatureSingleFloat">; def IsNotSingleFloat : Predicate<"!Subtarget->isSingleFloat()">, AssemblerPredicate<"!FeatureSingleFloat">; def IsNotSoftFloat : Predicate<"!Subtarget->useSoftFloat()">, AssemblerPredicate<"!FeatureSoftFloat">; //===----------------------------------------------------------------------===// // Mips FGR size adjectives. // They are mutually exclusive. //===----------------------------------------------------------------------===// class FGR_32 { list FGRPredicates = [NotFP64bit]; } class FGR_64 { list FGRPredicates = [IsFP64bit]; } class HARDFLOAT { list HardFloatPredicate = [IsNotSoftFloat]; } //===----------------------------------------------------------------------===// // FP immediate patterns. def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; def fpimm0neg : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; //===----------------------------------------------------------------------===// // Instruction Class Templates // // A set of multiclasses is used to address the register usage. // // S32 - single precision in 16 32bit even fp registers // single precision in 32 32bit fp registers in SingleOnly mode // S64 - single precision in 32 64bit fp registers (In64BitMode) // D32 - double precision in 16 32bit even fp registers // D64 - double precision in 32 64bit fp registers (In64BitMode) // // Only S32 and D32 are supported right now. //===----------------------------------------------------------------------===// class ADDS_FT : InstSE<(outs RC:$fd), (ins RC:$fs, RC:$ft), !strconcat(opstr, "\t$fd, $fs, $ft"), [(set RC:$fd, (OpNode RC:$fs, RC:$ft))], Itin, FrmFR, opstr>, HARDFLOAT { let isCommutable = IsComm; } multiclass ADDS_M { def _D32 : MMRel, ADDS_FT, FGR_32; def _D64 : ADDS_FT, FGR_64 { string DecoderNamespace = "Mips64"; } } class ABSS_FT : InstSE<(outs DstRC:$fd), (ins SrcRC:$fs), !strconcat(opstr, "\t$fd, $fs"), [(set DstRC:$fd, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, HARDFLOAT, NeverHasSideEffects; multiclass ABSS_M { def _D32 : MMRel, ABSS_FT, FGR_32; def _D64 : ABSS_FT, FGR_64 { string DecoderNamespace = "Mips64"; } } multiclass ROUND_M { def _D32 : MMRel, ABSS_FT, FGR_32; def _D64 : StdMMR6Rel, ABSS_FT, FGR_64 { let DecoderNamespace = "Mips64"; } } class MFC1_FT : InstSE<(outs DstRC:$rt), (ins SrcRC:$fs), !strconcat(opstr, "\t$rt, $fs"), [(set DstRC:$rt, (OpNode SrcRC:$fs))], Itin, FrmFR, opstr>, HARDFLOAT; class MTC1_FT : InstSE<(outs DstRC:$fs), (ins SrcRC:$rt), !strconcat(opstr, "\t$rt, $fs"), [(set DstRC:$fs, (OpNode SrcRC:$rt))], Itin, FrmFR, opstr>, HARDFLOAT; class MTC1_64_FT : InstSE<(outs DstRC:$fs), (ins DstRC:$fs_in, SrcRC:$rt), !strconcat(opstr, "\t$rt, $fs"), [], Itin, FrmFR, opstr>, HARDFLOAT { // $fs_in is part of a white lie to work around a widespread bug in the FPU // implementation. See expandBuildPairF64 for details. let Constraints = "$fs = $fs_in"; } class LW_FT : InstSE<(outs RC:$rt), (ins MO:$addr), !strconcat(opstr, "\t$rt, $addr"), [(set RC:$rt, (OpNode addrDefault:$addr))], Itin, FrmFI, opstr>, HARDFLOAT { let DecoderMethod = "DecodeFMem"; let mayLoad = 1; } class SW_FT : InstSE<(outs), (ins RC:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr"), [(OpNode RC:$rt, addrDefault:$addr)], Itin, FrmFI, opstr>, HARDFLOAT { let DecoderMethod = "DecodeFMem"; let mayStore = 1; } class MADDS_FT : InstSE<(outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), !strconcat(opstr, "\t$fd, $fr, $fs, $ft"), [(set RC:$fd, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr))], Itin, FrmFR, opstr>, HARDFLOAT; class NMADDS_FT : InstSE<(outs RC:$fd), (ins RC:$fr, RC:$fs, RC:$ft), !strconcat(opstr, "\t$fd, $fr, $fs, $ft"), [(set RC:$fd, (fsub fpimm0, (OpNode (fmul RC:$fs, RC:$ft), RC:$fr)))], Itin, FrmFR, opstr>, HARDFLOAT; class LWXC1_FT : InstSE<(outs DRC:$fd), (ins PtrRC:$base, PtrRC:$index), !strconcat(opstr, "\t$fd, ${index}(${base})"), [(set DRC:$fd, (OpNode (add iPTR:$base, iPTR:$index)))], Itin, FrmFI, opstr>, HARDFLOAT { let AddedComplexity = 20; } class SWXC1_FT : InstSE<(outs), (ins DRC:$fs, PtrRC:$base, PtrRC:$index), !strconcat(opstr, "\t$fs, ${index}(${base})"), [(OpNode DRC:$fs, (add iPTR:$base, iPTR:$index))], Itin, FrmFI, opstr>, HARDFLOAT { let AddedComplexity = 20; } class BC1F_FT : InstSE<(outs), (ins FCCRegsOpnd:$fcc, opnd:$offset), !strconcat(opstr, "\t$fcc, $offset"), [(MipsFPBrcond Op, FCCRegsOpnd:$fcc, bb:$offset)], Itin, FrmFI, opstr>, HARDFLOAT { let isBranch = 1; let isTerminator = 1; let hasDelaySlot = DelaySlot; let Defs = [AT]; + let hasFCCRegOperand = 1; } class CEQS_FT : InstSE<(outs), (ins RC:$fs, RC:$ft, condcode:$cond), !strconcat("c.$cond.", typestr, "\t$fs, $ft"), [(OpNode RC:$fs, RC:$ft, imm:$cond)], Itin, FrmFR, !strconcat("c.$cond.", typestr)>, HARDFLOAT { let Defs = [FCC0]; let isCodeGenOnly = 1; + let hasFCCRegOperand = 1; } + +// Note: MIPS-IV introduced $fcc1-$fcc7 and renamed FCSR31[23] $fcc0. Rather +// duplicating the instruction definition for MIPS1 - MIPS3, we expand +// c.cond.ft if necessary, and reject it after constructing the +// instruction if the ISA doesn't support it. class C_COND_FT : - InstSE<(outs), (ins RC:$fs, RC:$ft), - !strconcat("c.", CondStr, ".", Typestr, "\t$fs, $ft"), [], itin, - FrmFR>, HARDFLOAT; + InstSE<(outs FCCRegsOpnd:$fcc), (ins RC:$fs, RC:$ft), + !strconcat("c.", CondStr, ".", Typestr, "\t$fcc, $fs, $ft"), [], itin, + FrmFR>, HARDFLOAT { + let isCompare = 1; + let hasFCCRegOperand = 1; +} + multiclass C_COND_M fmt, InstrItinClass itin> { - def C_F_#NAME : C_COND_FT<"f", TypeStr, RC, itin>, C_COND_FM; - def C_UN_#NAME : C_COND_FT<"un", TypeStr, RC, itin>, C_COND_FM; - def C_EQ_#NAME : C_COND_FT<"eq", TypeStr, RC, itin>, C_COND_FM; - def C_UEQ_#NAME : C_COND_FT<"ueq", TypeStr, RC, itin>, C_COND_FM; - def C_OLT_#NAME : C_COND_FT<"olt", TypeStr, RC, itin>, C_COND_FM; - def C_ULT_#NAME : C_COND_FT<"ult", TypeStr, RC, itin>, C_COND_FM; - def C_OLE_#NAME : C_COND_FT<"ole", TypeStr, RC, itin>, C_COND_FM; - def C_ULE_#NAME : C_COND_FT<"ule", TypeStr, RC, itin>, C_COND_FM; - def C_SF_#NAME : C_COND_FT<"sf", TypeStr, RC, itin>, C_COND_FM; - def C_NGLE_#NAME : C_COND_FT<"ngle", TypeStr, RC, itin>, C_COND_FM; - def C_SEQ_#NAME : C_COND_FT<"seq", TypeStr, RC, itin>, C_COND_FM; - def C_NGL_#NAME : C_COND_FT<"ngl", TypeStr, RC, itin>, C_COND_FM; - def C_LT_#NAME : C_COND_FT<"lt", TypeStr, RC, itin>, C_COND_FM; - def C_NGE_#NAME : C_COND_FT<"nge", TypeStr, RC, itin>, C_COND_FM; - def C_LE_#NAME : C_COND_FT<"le", TypeStr, RC, itin>, C_COND_FM; - def C_NGT_#NAME : C_COND_FT<"ngt", TypeStr, RC, itin>, C_COND_FM; + def C_F_#NAME : MMRel, C_COND_FT<"f", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.f."#NAME; + let isCommutable = 1; + } + def C_UN_#NAME : MMRel, C_COND_FT<"un", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.un."#NAME; + let isCommutable = 1; + } + def C_EQ_#NAME : MMRel, C_COND_FT<"eq", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.eq."#NAME; + let isCommutable = 1; + } + def C_UEQ_#NAME : MMRel, C_COND_FT<"ueq", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ueq."#NAME; + let isCommutable = 1; + } + def C_OLT_#NAME : MMRel, C_COND_FT<"olt", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.olt."#NAME; + } + def C_ULT_#NAME : MMRel, C_COND_FT<"ult", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ult."#NAME; + } + def C_OLE_#NAME : MMRel, C_COND_FT<"ole", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ole."#NAME; + } + def C_ULE_#NAME : MMRel, C_COND_FT<"ule", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ule."#NAME; + } + def C_SF_#NAME : MMRel, C_COND_FT<"sf", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.sf."#NAME; + let isCommutable = 1; + } + def C_NGLE_#NAME : MMRel, C_COND_FT<"ngle", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ngle."#NAME; + } + def C_SEQ_#NAME : MMRel, C_COND_FT<"seq", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.seq."#NAME; + let isCommutable = 1; + } + def C_NGL_#NAME : MMRel, C_COND_FT<"ngl", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ngl."#NAME; + } + def C_LT_#NAME : MMRel, C_COND_FT<"lt", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.lt."#NAME; + } + def C_NGE_#NAME : MMRel, C_COND_FT<"nge", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.nge."#NAME; + } + def C_LE_#NAME : MMRel, C_COND_FT<"le", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.le."#NAME; + } + def C_NGT_#NAME : MMRel, C_COND_FT<"ngt", TypeStr, RC, itin>, + C_COND_FM { + let BaseOpcode = "c.ngt."#NAME; + } } +let AdditionalPredicates = [NotInMicroMips] in { defm S : C_COND_M<"s", FGR32Opnd, 16, II_C_CC_S>, ISA_MIPS1_NOT_32R6_64R6; defm D32 : C_COND_M<"d", AFGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, FGR_32; let DecoderNamespace = "Mips64" in defm D64 : C_COND_M<"d", FGR64Opnd, 17, II_C_CC_D>, ISA_MIPS1_NOT_32R6_64R6, FGR_64; - +} //===----------------------------------------------------------------------===// // Floating Point Instructions //===----------------------------------------------------------------------===// def ROUND_W_S : MMRel, StdMMR6Rel, ABSS_FT<"round.w.s", FGR32Opnd, FGR32Opnd, II_ROUND>, ABSS_FM<0xc, 16>, ISA_MIPS2; defm ROUND_W : ROUND_M<"round.w.d", II_ROUND>, ABSS_FM<0xc, 17>, ISA_MIPS2; def TRUNC_W_S : MMRel, StdMMR6Rel, ABSS_FT<"trunc.w.s", FGR32Opnd, FGR32Opnd, II_TRUNC>, ABSS_FM<0xd, 16>, ISA_MIPS2; def CEIL_W_S : MMRel, StdMMR6Rel, ABSS_FT<"ceil.w.s", FGR32Opnd, FGR32Opnd, II_CEIL>, ABSS_FM<0xe, 16>, ISA_MIPS2; def FLOOR_W_S : MMRel, StdMMR6Rel, ABSS_FT<"floor.w.s", FGR32Opnd, FGR32Opnd, II_FLOOR>, ABSS_FM<0xf, 16>, ISA_MIPS2; def CVT_W_S : MMRel, ABSS_FT<"cvt.w.s", FGR32Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x24, 16>; defm TRUNC_W : ROUND_M<"trunc.w.d", II_TRUNC>, ABSS_FM<0xd, 17>, ISA_MIPS2; defm CEIL_W : ROUND_M<"ceil.w.d", II_CEIL>, ABSS_FM<0xe, 17>, ISA_MIPS2; defm FLOOR_W : ROUND_M<"floor.w.d", II_FLOOR>, ABSS_FM<0xf, 17>, ISA_MIPS2; defm CVT_W : ROUND_M<"cvt.w.d", II_CVT>, ABSS_FM<0x24, 17>; let AdditionalPredicates = [NotInMicroMips] in { def RECIP_S : MMRel, ABSS_FT<"recip.s", FGR32Opnd, FGR32Opnd, II_RECIP_S>, ABSS_FM<0b010101, 0x10>, INSN_MIPS4_32R2; def RECIP_D : MMRel, ABSS_FT<"recip.d", FGR64Opnd, FGR64Opnd, II_RECIP_D>, ABSS_FM<0b010101, 0x11>, INSN_MIPS4_32R2; def RSQRT_S : MMRel, ABSS_FT<"rsqrt.s", FGR32Opnd, FGR32Opnd, II_RSQRT_S>, ABSS_FM<0b010110, 0x10>, INSN_MIPS4_32R2; def RSQRT_D : MMRel, ABSS_FT<"rsqrt.d", FGR64Opnd, FGR64Opnd, II_RSQRT_D>, ABSS_FM<0b010110, 0x11>, INSN_MIPS4_32R2; } let DecoderNamespace = "Mips64" in { let AdditionalPredicates = [NotInMicroMips] in { def ROUND_L_S : ABSS_FT<"round.l.s", FGR64Opnd, FGR32Opnd, II_ROUND>, ABSS_FM<0x8, 16>, FGR_64; def ROUND_L_D64 : ABSS_FT<"round.l.d", FGR64Opnd, FGR64Opnd, II_ROUND>, ABSS_FM<0x8, 17>, FGR_64; def TRUNC_L_S : ABSS_FT<"trunc.l.s", FGR64Opnd, FGR32Opnd, II_TRUNC>, ABSS_FM<0x9, 16>, FGR_64; def TRUNC_L_D64 : ABSS_FT<"trunc.l.d", FGR64Opnd, FGR64Opnd, II_TRUNC>, ABSS_FM<0x9, 17>, FGR_64; def CEIL_L_S : ABSS_FT<"ceil.l.s", FGR64Opnd, FGR32Opnd, II_CEIL>, ABSS_FM<0xa, 16>, FGR_64; def CEIL_L_D64 : ABSS_FT<"ceil.l.d", FGR64Opnd, FGR64Opnd, II_CEIL>, ABSS_FM<0xa, 17>, FGR_64; def FLOOR_L_S : ABSS_FT<"floor.l.s", FGR64Opnd, FGR32Opnd, II_FLOOR>, ABSS_FM<0xb, 16>, FGR_64; def FLOOR_L_D64 : ABSS_FT<"floor.l.d", FGR64Opnd, FGR64Opnd, II_FLOOR>, ABSS_FM<0xb, 17>, FGR_64; } } def CVT_S_W : MMRel, ABSS_FT<"cvt.s.w", FGR32Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x20, 20>; let AdditionalPredicates = [NotInMicroMips] in{ def CVT_L_S : MMRel, ABSS_FT<"cvt.l.s", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x25, 16>, INSN_MIPS3_32R2; def CVT_L_D64: MMRel, ABSS_FT<"cvt.l.d", FGR64Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x25, 17>, INSN_MIPS3_32R2; } def CVT_S_D32 : MMRel, ABSS_FT<"cvt.s.d", FGR32Opnd, AFGR64Opnd, II_CVT>, ABSS_FM<0x20, 17>, FGR_32; def CVT_D32_W : MMRel, ABSS_FT<"cvt.d.w", AFGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 20>, FGR_32; def CVT_D32_S : MMRel, ABSS_FT<"cvt.d.s", AFGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 16>, FGR_32; let DecoderNamespace = "Mips64" in { def CVT_S_D64 : ABSS_FT<"cvt.s.d", FGR32Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x20, 17>, FGR_64; let AdditionalPredicates = [NotInMicroMips] in{ def CVT_S_L : ABSS_FT<"cvt.s.l", FGR32Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x20, 21>, FGR_64; } def CVT_D64_W : ABSS_FT<"cvt.d.w", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 20>, FGR_64; def CVT_D64_S : ABSS_FT<"cvt.d.s", FGR64Opnd, FGR32Opnd, II_CVT>, ABSS_FM<0x21, 16>, FGR_64; def CVT_D64_L : ABSS_FT<"cvt.d.l", FGR64Opnd, FGR64Opnd, II_CVT>, ABSS_FM<0x21, 21>, FGR_64; } let isPseudo = 1, isCodeGenOnly = 1 in { def PseudoCVT_S_W : ABSS_FT<"", FGR32Opnd, GPR32Opnd, II_CVT>; def PseudoCVT_D32_W : ABSS_FT<"", AFGR64Opnd, GPR32Opnd, II_CVT>; def PseudoCVT_S_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; def PseudoCVT_D64_W : ABSS_FT<"", FGR64Opnd, GPR32Opnd, II_CVT>; def PseudoCVT_D64_L : ABSS_FT<"", FGR64Opnd, GPR64Opnd, II_CVT>; } def FABS_S : MMRel, ABSS_FT<"abs.s", FGR32Opnd, FGR32Opnd, II_ABS, fabs>, ABSS_FM<0x5, 16>; def FNEG_S : MMRel, ABSS_FT<"neg.s", FGR32Opnd, FGR32Opnd, II_NEG, fneg>, ABSS_FM<0x7, 16>; defm FABS : ABSS_M<"abs.d", II_ABS, fabs>, ABSS_FM<0x5, 17>; defm FNEG : ABSS_M<"neg.d", II_NEG, fneg>, ABSS_FM<0x7, 17>; def FSQRT_S : MMRel, StdMMR6Rel, ABSS_FT<"sqrt.s", FGR32Opnd, FGR32Opnd, II_SQRT_S, fsqrt>, ABSS_FM<0x4, 16>, ISA_MIPS2; defm FSQRT : ABSS_M<"sqrt.d", II_SQRT_D, fsqrt>, ABSS_FM<0x4, 17>, ISA_MIPS2; // The odd-numbered registers are only referenced when doing loads, // stores, and moves between floating-point and integer registers. // When defining instructions, we reference all 32-bit registers, // regardless of register aliasing. /// Move Control Registers From/To CPU Registers let AdditionalPredicates = [NotInMicroMips] in { def CFC1 : MMRel, MFC1_FT<"cfc1", GPR32Opnd, CCROpnd, II_CFC1>, MFC1_FM<2>; def CTC1 : MMRel, MTC1_FT<"ctc1", CCROpnd, GPR32Opnd, II_CTC1>, MFC1_FM<6>; } def MFC1 : MMRel, MFC1_FT<"mfc1", GPR32Opnd, FGR32Opnd, II_MFC1, bitconvert>, MFC1_FM<0>; def MTC1 : MMRel, MTC1_FT<"mtc1", FGR32Opnd, GPR32Opnd, II_MTC1, bitconvert>, MFC1_FM<4>; let AdditionalPredicates = [NotInMicroMips] in { def MFHC1_D32 : MMRel, MFC1_FT<"mfhc1", GPR32Opnd, AFGR64Opnd, II_MFHC1>, MFC1_FM<3>, ISA_MIPS32R2, FGR_32; def MFHC1_D64 : MFC1_FT<"mfhc1", GPR32Opnd, FGR64Opnd, II_MFHC1>, MFC1_FM<3>, ISA_MIPS32R2, FGR_64 { let DecoderNamespace = "Mips64"; } } let AdditionalPredicates = [NotInMicroMips] in { def MTHC1_D32 : MMRel, StdMMR6Rel, MTC1_64_FT<"mthc1", AFGR64Opnd, GPR32Opnd, II_MTHC1>, MFC1_FM<7>, ISA_MIPS32R2, FGR_32; def MTHC1_D64 : MTC1_64_FT<"mthc1", FGR64Opnd, GPR32Opnd, II_MTHC1>, MFC1_FM<7>, ISA_MIPS32R2, FGR_64 { let DecoderNamespace = "Mips64"; } } let AdditionalPredicates = [NotInMicroMips] in { def DMTC1 : MTC1_FT<"dmtc1", FGR64Opnd, GPR64Opnd, II_DMTC1, bitconvert>, MFC1_FM<5>, ISA_MIPS3; def DMFC1 : MFC1_FT<"dmfc1", GPR64Opnd, FGR64Opnd, II_DMFC1, bitconvert>, MFC1_FM<1>, ISA_MIPS3; } def FMOV_S : MMRel, ABSS_FT<"mov.s", FGR32Opnd, FGR32Opnd, II_MOV_S>, ABSS_FM<0x6, 16>; def FMOV_D32 : MMRel, ABSS_FT<"mov.d", AFGR64Opnd, AFGR64Opnd, II_MOV_D>, ABSS_FM<0x6, 17>, FGR_32; def FMOV_D64 : ABSS_FT<"mov.d", FGR64Opnd, FGR64Opnd, II_MOV_D>, ABSS_FM<0x6, 17>, FGR_64 { let DecoderNamespace = "Mips64"; } /// Floating Point Memory Instructions let AdditionalPredicates = [NotInMicroMips] in { def LWC1 : MMRel, LW_FT<"lwc1", FGR32Opnd, mem_simm16, II_LWC1, load>, LW_FM<0x31>; def SWC1 : MMRel, SW_FT<"swc1", FGR32Opnd, mem_simm16, II_SWC1, store>, LW_FM<0x39>; } let DecoderNamespace = "Mips64", AdditionalPredicates = [NotInMicroMips] in { def LDC164 : StdMMR6Rel, LW_FT<"ldc1", FGR64Opnd, mem_simm16, II_LDC1, load>, LW_FM<0x35>, ISA_MIPS2, FGR_64 { let BaseOpcode = "LDC164"; } def SDC164 : StdMMR6Rel, SW_FT<"sdc1", FGR64Opnd, mem_simm16, II_SDC1, store>, LW_FM<0x3d>, ISA_MIPS2, FGR_64; } let AdditionalPredicates = [NotInMicroMips] in { def LDC1 : MMRel, StdMMR6Rel, LW_FT<"ldc1", AFGR64Opnd, mem_simm16, II_LDC1, load>, LW_FM<0x35>, ISA_MIPS2, FGR_32 { let BaseOpcode = "LDC132"; } def SDC1 : MMRel, SW_FT<"sdc1", AFGR64Opnd, mem_simm16, II_SDC1, store>, LW_FM<0x3d>, ISA_MIPS2, FGR_32; } // Indexed loads and stores. // Base register + offset register addressing mode (indicated by "x" in the // instruction mnemonic) is disallowed under NaCl. let AdditionalPredicates = [IsNotNaCl] in { def LWXC1 : MMRel, LWXC1_FT<"lwxc1", FGR32Opnd, II_LWXC1, load>, LWXC1_FM<0>, INSN_MIPS4_32R2_NOT_32R6_64R6; def SWXC1 : MMRel, SWXC1_FT<"swxc1", FGR32Opnd, II_SWXC1, store>, SWXC1_FM<8>, INSN_MIPS4_32R2_NOT_32R6_64R6; } let AdditionalPredicates = [NotInMicroMips, IsNotNaCl] in { def LDXC1 : LWXC1_FT<"ldxc1", AFGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; def SDXC1 : SWXC1_FT<"sdxc1", AFGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; } let DecoderNamespace="Mips64" in { def LDXC164 : LWXC1_FT<"ldxc1", FGR64Opnd, II_LDXC1, load>, LWXC1_FM<1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; def SDXC164 : SWXC1_FT<"sdxc1", FGR64Opnd, II_SDXC1, store>, SWXC1_FM<9>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; } // Load/store doubleword indexed unaligned. let AdditionalPredicates = [IsNotNaCl] in { def LUXC1 : MMRel, LWXC1_FT<"luxc1", AFGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; def SUXC1 : MMRel, SWXC1_FT<"suxc1", AFGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_32; } let DecoderNamespace="Mips64" in { def LUXC164 : LWXC1_FT<"luxc1", FGR64Opnd, II_LUXC1>, LWXC1_FM<0x5>, INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; def SUXC164 : SWXC1_FT<"suxc1", FGR64Opnd, II_SUXC1>, SWXC1_FM<0xd>, INSN_MIPS5_32R2_NOT_32R6_64R6, FGR_64; } /// Floating-point Aritmetic def FADD_S : MMRel, ADDS_FT<"add.s", FGR32Opnd, II_ADD_S, 1, fadd>, ADDS_FM<0x00, 16>; defm FADD : ADDS_M<"add.d", II_ADD_D, 1, fadd>, ADDS_FM<0x00, 17>; def FDIV_S : MMRel, ADDS_FT<"div.s", FGR32Opnd, II_DIV_S, 0, fdiv>, ADDS_FM<0x03, 16>; defm FDIV : ADDS_M<"div.d", II_DIV_D, 0, fdiv>, ADDS_FM<0x03, 17>; def FMUL_S : MMRel, ADDS_FT<"mul.s", FGR32Opnd, II_MUL_S, 1, fmul>, ADDS_FM<0x02, 16>; defm FMUL : ADDS_M<"mul.d", II_MUL_D, 1, fmul>, ADDS_FM<0x02, 17>; def FSUB_S : MMRel, ADDS_FT<"sub.s", FGR32Opnd, II_SUB_S, 0, fsub>, ADDS_FM<0x01, 16>; defm FSUB : ADDS_M<"sub.d", II_SUB_D, 0, fsub>, ADDS_FM<0x01, 17>; def MADD_S : MMRel, MADDS_FT<"madd.s", FGR32Opnd, II_MADD_S, fadd>, MADDS_FM<4, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; def MSUB_S : MMRel, MADDS_FT<"msub.s", FGR32Opnd, II_MSUB_S, fsub>, MADDS_FM<5, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; let AdditionalPredicates = [NoNaNsFPMath] in { def NMADD_S : MMRel, NMADDS_FT<"nmadd.s", FGR32Opnd, II_NMADD_S, fadd>, MADDS_FM<6, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; def NMSUB_S : MMRel, NMADDS_FT<"nmsub.s", FGR32Opnd, II_NMSUB_S, fsub>, MADDS_FM<7, 0>, INSN_MIPS4_32R2_NOT_32R6_64R6; } def MADD_D32 : MMRel, MADDS_FT<"madd.d", AFGR64Opnd, II_MADD_D, fadd>, MADDS_FM<4, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; def MSUB_D32 : MMRel, MADDS_FT<"msub.d", AFGR64Opnd, II_MSUB_D, fsub>, MADDS_FM<5, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; let AdditionalPredicates = [NoNaNsFPMath] in { def NMADD_D32 : MMRel, NMADDS_FT<"nmadd.d", AFGR64Opnd, II_NMADD_D, fadd>, MADDS_FM<6, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; def NMSUB_D32 : MMRel, NMADDS_FT<"nmsub.d", AFGR64Opnd, II_NMSUB_D, fsub>, MADDS_FM<7, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_32; } let DecoderNamespace = "Mips64" in { def MADD_D64 : MADDS_FT<"madd.d", FGR64Opnd, II_MADD_D, fadd>, MADDS_FM<4, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; def MSUB_D64 : MADDS_FT<"msub.d", FGR64Opnd, II_MSUB_D, fsub>, MADDS_FM<5, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; } let AdditionalPredicates = [NoNaNsFPMath], DecoderNamespace = "Mips64" in { def NMADD_D64 : NMADDS_FT<"nmadd.d", FGR64Opnd, II_NMADD_D, fadd>, MADDS_FM<6, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; def NMSUB_D64 : NMADDS_FT<"nmsub.d", FGR64Opnd, II_NMSUB_D, fsub>, MADDS_FM<7, 1>, INSN_MIPS4_32R2_NOT_32R6_64R6, FGR_64; } //===----------------------------------------------------------------------===// // Floating Point Branch Codes //===----------------------------------------------------------------------===// // Mips branch codes. These correspond to condcode in MipsInstrInfo.h. // They must be kept in synch. def MIPS_BRANCH_F : PatLeaf<(i32 0)>; def MIPS_BRANCH_T : PatLeaf<(i32 1)>; def BC1F : MMRel, BC1F_FT<"bc1f", brtarget, II_BC1F, MIPS_BRANCH_F>, BC1F_FM<0, 0>, ISA_MIPS1_NOT_32R6_64R6; def BC1FL : MMRel, BC1F_FT<"bc1fl", brtarget, II_BC1FL, MIPS_BRANCH_F, 0>, BC1F_FM<1, 0>, ISA_MIPS2_NOT_32R6_64R6; def BC1T : MMRel, BC1F_FT<"bc1t", brtarget, II_BC1T, MIPS_BRANCH_T>, BC1F_FM<0, 1>, ISA_MIPS1_NOT_32R6_64R6; def BC1TL : MMRel, BC1F_FT<"bc1tl", brtarget, II_BC1TL, MIPS_BRANCH_T, 0>, BC1F_FM<1, 1>, ISA_MIPS2_NOT_32R6_64R6; /// Floating Point Compare let AdditionalPredicates = [NotInMicroMips] in { def FCMP_S32 : MMRel, CEQS_FT<"s", FGR32, II_C_CC_S, MipsFPCmp>, CEQS_FM<16>, - ISA_MIPS1_NOT_32R6_64R6; + ISA_MIPS1_NOT_32R6_64R6 { + + // FIXME: This is a required to work around the fact that these instructions + // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the + // fcc register set is used directly. + bits<3> fcc = 0; + } def FCMP_D32 : MMRel, CEQS_FT<"d", AFGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, - ISA_MIPS1_NOT_32R6_64R6, FGR_32; + ISA_MIPS1_NOT_32R6_64R6, FGR_32 { + // FIXME: This is a required to work around the fact that these instructions + // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the + // fcc register set is used directly. + bits<3> fcc = 0; + } } let DecoderNamespace = "Mips64" in def FCMP_D64 : CEQS_FT<"d", FGR64, II_C_CC_D, MipsFPCmp>, CEQS_FM<17>, - ISA_MIPS1_NOT_32R6_64R6, FGR_64; + ISA_MIPS1_NOT_32R6_64R6, FGR_64 { + // FIXME: This is a required to work around the fact that thiese instructions + // only use $fcc0. Ideally, MipsFPCmp nodes could be removed and the + // fcc register set is used directly. + bits<3> fcc = 0; +} //===----------------------------------------------------------------------===// // Floating Point Pseudo-Instructions //===----------------------------------------------------------------------===// // This pseudo instr gets expanded into 2 mtc1 instrs after register // allocation. class BuildPairF64Base : PseudoSE<(outs RO:$dst), (ins GPR32Opnd:$lo, GPR32Opnd:$hi), [(set RO:$dst, (MipsBuildPairF64 GPR32Opnd:$lo, GPR32Opnd:$hi))], II_MTC1>; def BuildPairF64 : BuildPairF64Base, FGR_32, HARDFLOAT; def BuildPairF64_64 : BuildPairF64Base, FGR_64, HARDFLOAT; // This pseudo instr gets expanded into 2 mfc1 instrs after register // allocation. // if n is 0, lower part of src is extracted. // if n is 1, higher part of src is extracted. // This node has associated scheduling information as the pre RA scheduler // asserts otherwise. class ExtractElementF64Base : PseudoSE<(outs GPR32Opnd:$dst), (ins RO:$src, i32imm:$n), [(set GPR32Opnd:$dst, (MipsExtractElementF64 RO:$src, imm:$n))], II_MFC1>; def ExtractElementF64 : ExtractElementF64Base, FGR_32, HARDFLOAT; def ExtractElementF64_64 : ExtractElementF64Base, FGR_64, HARDFLOAT; def PseudoTRUNC_W_S : MipsAsmPseudoInst<(outs FGR32Opnd:$fd), (ins FGR32Opnd:$fs, GPR32Opnd:$rs), "trunc.w.s\t$fd, $fs, $rs">; def PseudoTRUNC_W_D32 : MipsAsmPseudoInst<(outs FGR32Opnd:$fd), (ins AFGR64Opnd:$fs, GPR32Opnd:$rs), "trunc.w.d\t$fd, $fs, $rs">, FGR_32, HARDFLOAT; def PseudoTRUNC_W_D : MipsAsmPseudoInst<(outs FGR32Opnd:$fd), (ins FGR64Opnd:$fs, GPR32Opnd:$rs), "trunc.w.d\t$fd, $fs, $rs">, FGR_64, HARDFLOAT; //===----------------------------------------------------------------------===// // InstAliases. //===----------------------------------------------------------------------===// -def : MipsInstAlias<"bc1t $offset", (BC1T FCC0, brtarget:$offset)>, - ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT; -def : MipsInstAlias<"bc1tl $offset", (BC1TL FCC0, brtarget:$offset)>, - ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT; -def : MipsInstAlias<"bc1f $offset", (BC1F FCC0, brtarget:$offset)>, - ISA_MIPS1_NOT_32R6_64R6, HARDFLOAT; -def : MipsInstAlias<"bc1fl $offset", (BC1FL FCC0, brtarget:$offset)>, - ISA_MIPS2_NOT_32R6_64R6, HARDFLOAT; - def : MipsInstAlias <"s.s $fd, $addr", (SWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>, ISA_MIPS2, HARDFLOAT; def : MipsInstAlias <"s.d $fd, $addr", (SDC1 AFGR64Opnd:$fd, mem_simm16:$addr), 0>, FGR_32, ISA_MIPS2, HARDFLOAT; def : MipsInstAlias <"s.d $fd, $addr", (SDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>, FGR_64, ISA_MIPS2, HARDFLOAT; def : MipsInstAlias <"l.s $fd, $addr", (LWC1 FGR32Opnd:$fd, mem_simm16:$addr), 0>, ISA_MIPS2, HARDFLOAT; def : MipsInstAlias <"l.d $fd, $addr", (LDC1 AFGR64Opnd:$fd, mem_simm16:$addr), 0>, FGR_32, ISA_MIPS2, HARDFLOAT; def : MipsInstAlias <"l.d $fd, $addr", (LDC164 FGR64Opnd:$fd, mem_simm16:$addr), 0>, FGR_64, ISA_MIPS2, HARDFLOAT; + +multiclass C_COND_ALIASES { + def : MipsInstAlias("C_F_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_UN_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_EQ_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_UEQ_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_OLT_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_ULT_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_OLE_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_ULE_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_SF_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_NGLE_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_SEQ_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_NGL_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_LT_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_NGE_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_LE_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; + def : MipsInstAlias("C_NGT_"#NAME) FCC0, + RC:$fs, RC:$ft), 1>; +} + +multiclass BC1_ALIASES { + def : MipsInstAlias; + + def : MipsInstAlias; +} + +let AdditionalPredicates = [NotInMicroMips] in { + defm S : C_COND_ALIASES<"s", FGR32Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6; + defm D32 : C_COND_ALIASES<"d", AFGR64Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6, FGR_32; + defm D64 : C_COND_ALIASES<"d", FGR64Opnd>, HARDFLOAT, + ISA_MIPS1_NOT_32R6_64R6, FGR_64; + + defm : BC1_ALIASES, ISA_MIPS1_NOT_32R6_64R6, + HARDFLOAT; + defm : BC1_ALIASES, ISA_MIPS2_NOT_32R6_64R6, + HARDFLOAT; +} //===----------------------------------------------------------------------===// // Floating Point Patterns //===----------------------------------------------------------------------===// def : MipsPat<(f32 fpimm0), (MTC1 ZERO)>; def : MipsPat<(f32 fpimm0neg), (FNEG_S (MTC1 ZERO))>; def : MipsPat<(f32 (sint_to_fp GPR32Opnd:$src)), (PseudoCVT_S_W GPR32Opnd:$src)>; def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), (TRUNC_W_S FGR32Opnd:$src)>; def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), (PseudoCVT_D32_W GPR32Opnd:$src)>, FGR_32; def : MipsPat<(MipsTruncIntFP AFGR64Opnd:$src), (TRUNC_W_D32 AFGR64Opnd:$src)>, FGR_32; def : MipsPat<(f32 (fpround AFGR64Opnd:$src)), (CVT_S_D32 AFGR64Opnd:$src)>, FGR_32; def : MipsPat<(f64 (fpextend FGR32Opnd:$src)), (CVT_D32_S FGR32Opnd:$src)>, FGR_32; def : MipsPat<(f64 fpimm0), (DMTC1 ZERO_64)>, FGR_64; def : MipsPat<(f64 fpimm0neg), (FNEG_D64 (DMTC1 ZERO_64))>, FGR_64; def : MipsPat<(f64 (sint_to_fp GPR32Opnd:$src)), (PseudoCVT_D64_W GPR32Opnd:$src)>, FGR_64; def : MipsPat<(f32 (sint_to_fp GPR64Opnd:$src)), (EXTRACT_SUBREG (PseudoCVT_S_L GPR64Opnd:$src), sub_lo)>, FGR_64; def : MipsPat<(f64 (sint_to_fp GPR64Opnd:$src)), (PseudoCVT_D64_L GPR64Opnd:$src)>, FGR_64; def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), (TRUNC_W_D64 FGR64Opnd:$src)>, FGR_64; def : MipsPat<(MipsTruncIntFP FGR32Opnd:$src), (TRUNC_L_S FGR32Opnd:$src)>, FGR_64; def : MipsPat<(MipsTruncIntFP FGR64Opnd:$src), (TRUNC_L_D64 FGR64Opnd:$src)>, FGR_64; def : MipsPat<(f32 (fpround FGR64Opnd:$src)), (CVT_S_D64 FGR64Opnd:$src)>, FGR_64; def : MipsPat<(f64 (fpextend FGR32Opnd:$src)), (CVT_D64_S FGR32Opnd:$src)>, FGR_64; // Patterns for loads/stores with a reg+imm operand. let AdditionalPredicates = [NotInMicroMips] in { let AddedComplexity = 40 in { def : LoadRegImmPat; def : StoreRegImmPat; def : LoadRegImmPat, FGR_64; def : StoreRegImmPat, FGR_64; def : LoadRegImmPat, FGR_32; def : StoreRegImmPat, FGR_32; } } Index: vendor/llvm/dist/lib/Target/Mips/MipsInstrFormats.td =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsInstrFormats.td (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsInstrFormats.td (revision 313056) @@ -1,968 +1,972 @@ //===-- MipsInstrFormats.td - Mips Instruction Formats -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Describe MIPS instructions format // // CPU INSTRUCTION FORMATS // // opcode - operation code. // rs - src reg. // rt - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). // rd - dst reg, only used on 3 regs instr. // shamt - only used on shift instructions, contains the shift amount. // funct - combined with opcode field give us an operation code. // //===----------------------------------------------------------------------===// // Format specifies the encoding used by the instruction. This is part of the // ad-hoc solution used to emit machine instruction encodings by our machine // code emitter. class Format val> { bits<4> Value = val; } def Pseudo : Format<0>; def FrmR : Format<1>; def FrmI : Format<2>; def FrmJ : Format<3>; def FrmFR : Format<4>; def FrmFI : Format<5>; def FrmOther : Format<6>; // Instruction w/ a custom format class MMRel; def Std2MicroMips : InstrMapping { let FilterClass = "MMRel"; // Instructions with the same BaseOpcode and isNVStore values form a row. let RowFields = ["BaseOpcode"]; // Instructions with the same predicate sense form a column. let ColFields = ["Arch"]; // The key column is the unpredicated instructions. let KeyCol = ["se"]; // Value columns are PredSense=true and PredSense=false let ValueCols = [["se"], ["micromips"]]; } class StdMMR6Rel; def Std2MicroMipsR6 : InstrMapping { let FilterClass = "StdMMR6Rel"; // Instructions with the same BaseOpcode and isNVStore values form a row. let RowFields = ["BaseOpcode"]; // Instructions with the same predicate sense form a column. let ColFields = ["Arch"]; // The key column is the unpredicated instructions. let KeyCol = ["se"]; // Value columns are PredSense=true and PredSense=false let ValueCols = [["se"], ["micromipsr6"]]; } class StdArch { string Arch = "se"; } // Generic Mips Format class MipsInst pattern, InstrItinClass itin, Format f>: Instruction { field bits<32> Inst; Format Form = f; let Namespace = "Mips"; let Size = 4; bits<6> Opcode = 0; // Top 6 bits are the 'opcode' field let Inst{31-26} = Opcode; let OutOperandList = outs; let InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; let Itinerary = itin; // // Attributes specific to Mips instructions... // bits<4> FormBits = Form.Value; bit isCTI = 0; // Any form of Control Transfer Instruction. // Required for MIPSR6 bit hasForbiddenSlot = 0; // Instruction has a forbidden slot. bit IsPCRelativeLoad = 0; // Load instruction with implicit source register // ($pc) and with explicit offset and destination // register + bit hasFCCRegOperand = 0; // Instruction uses $fcc register and is + // present in MIPS-I to MIPS-III. - // TSFlags layout should be kept in sync with MipsInstrInfo.h. + // TSFlags layout should be kept in sync with MCTargetDesc/MipsBaseInfo.h. let TSFlags{3-0} = FormBits; let TSFlags{4} = isCTI; let TSFlags{5} = hasForbiddenSlot; let TSFlags{6} = IsPCRelativeLoad; + let TSFlags{7} = hasFCCRegOperand; let DecoderNamespace = "Mips"; field bits<32> SoftFail = 0; } // Mips32/64 Instruction Format class InstSE pattern, InstrItinClass itin, Format f, string opstr = ""> : MipsInst, PredicateControl { let EncodingPredicates = [HasStdEnc]; string BaseOpcode = opstr; string Arch; } // Mips Pseudo Instructions Format class MipsPseudo pattern, InstrItinClass itin = IIPseudo> : MipsInst { let isCodeGenOnly = 1; let isPseudo = 1; } // Mips32/64 Pseudo Instruction Format class PseudoSE pattern, InstrItinClass itin = IIPseudo> : MipsPseudo, PredicateControl { let EncodingPredicates = [HasStdEnc]; } // Pseudo-instructions for alternate assembly syntax (never used by codegen). // These are aliases that require C++ handling to convert to the target // instruction, while InstAliases can be handled directly by tblgen. class MipsAsmPseudoInst: MipsInst, PredicateControl { let isPseudo = 1; let Pattern = []; } //===----------------------------------------------------------------------===// // Format R instruction class in Mips : <|opcode|rs|rt|rd|shamt|funct|> //===----------------------------------------------------------------------===// class FR op, bits<6> _funct, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin>: InstSE { bits<5> rd; bits<5> rs; bits<5> rt; bits<5> shamt; bits<6> funct; let Opcode = op; let funct = _funct; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = shamt; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Format I instruction class in Mips : <|opcode|rs|rt|immediate|> //===----------------------------------------------------------------------===// class FI op, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin>: InstSE { bits<5> rt; bits<5> rs; bits<16> imm16; let Opcode = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class BranchBase op, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin>: InstSE { bits<5> rs; bits<5> rt; bits<16> imm16; let Opcode = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } //===----------------------------------------------------------------------===// // Format J instruction class in Mips : <|opcode|address|> //===----------------------------------------------------------------------===// class FJ op> : StdArch { bits<26> target; bits<32> Inst; let Inst{31-26} = op; let Inst{25-0} = target; } //===----------------------------------------------------------------------===// // MFC instruction class in Mips : <|op|mf|rt|rd|0000000|sel|> //===----------------------------------------------------------------------===// class MFC3OP_FM op, bits<5> mfmt> { bits<5> rt; bits<5> rd; bits<3> sel; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = mfmt; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-3} = 0; let Inst{2-0} = sel; } class MFC2OP_FM op, bits<5> mfmt> : StdArch { bits<5> rt; bits<16> imm16; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = mfmt; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class ADD_FM op, bits<6> funct> : StdArch { bits<5> rd; bits<5> rs; bits<5> rt; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = funct; } class ADDI_FM op> : StdArch { bits<5> rs; bits<5> rt; bits<16> imm16; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class SRA_FM funct, bit rotate> : StdArch { bits<5> rd; bits<5> rt; bits<5> shamt; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-22} = 0; let Inst{21} = rotate; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = shamt; let Inst{5-0} = funct; } class SRLV_FM funct, bit rotate> : StdArch { bits<5> rd; bits<5> rt; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-7} = 0; let Inst{6} = rotate; let Inst{5-0} = funct; } class BEQ_FM op> : StdArch { bits<5> rs; bits<5> rt; bits<16> offset; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = offset; } class BGEZ_FM op, bits<5> funct> : StdArch { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = funct; let Inst{15-0} = offset; } class BBIT_FM op> : StdArch { bits<5> rs; bits<5> p; bits<16> offset; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = p; let Inst{15-0} = offset; } class SLTI_FM op> : StdArch { bits<5> rt; bits<5> rs; bits<16> imm16; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class MFLO_FM funct> : StdArch { bits<5> rd; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-16} = 0; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = funct; } class MTLO_FM funct> : StdArch { bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rs; let Inst{20-6} = 0; let Inst{5-0} = funct; } class SEB_FM funct, bits<6> funct2> : StdArch { bits<5> rd; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x1f; let Inst{25-21} = 0; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = funct; let Inst{5-0} = funct2; } class CLO_FM funct> : StdArch { bits<5> rd; bits<5> rs; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = funct; let rt = rd; } class LUI_FM : StdArch { bits<5> rt; bits<16> imm16; bits<32> Inst; let Inst{31-26} = 0xf; let Inst{25-21} = 0; let Inst{20-16} = rt; let Inst{15-0} = imm16; } class JALR_FM { bits<5> rd; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rs; let Inst{20-16} = 0; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = 9; } class BGEZAL_FM funct> : StdArch { bits<5> rs; bits<16> offset; bits<32> Inst; let Inst{31-26} = 1; let Inst{25-21} = rs; let Inst{20-16} = funct; let Inst{15-0} = offset; } class SYNC_FM : StdArch { bits<5> stype; bits<32> Inst; let Inst{31-26} = 0; let Inst{10-6} = stype; let Inst{5-0} = 0xf; } class SYNCI_FM : StdArch { // Produced by the mem_simm16 address as reg << 16 | imm (see getMemEncoding). bits<21> addr; bits<5> rs = addr{20-16}; bits<16> offset = addr{15-0}; bits<32> Inst; let Inst{31-26} = 0b000001; let Inst{25-21} = rs; let Inst{20-16} = 0b11111; let Inst{15-0} = offset; } class MULT_FM op, bits<6> funct> : StdArch { bits<5> rs; bits<5> rt; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-6} = 0; let Inst{5-0} = funct; } class EXT_FM funct> : StdArch { bits<5> rt; bits<5> rs; bits<5> pos; bits<5> size; bits<32> Inst; let Inst{31-26} = 0x1f; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = size; let Inst{10-6} = pos; let Inst{5-0} = funct; } class RDHWR_FM : StdArch { bits<5> rt; bits<5> rd; bits<32> Inst; let Inst{31-26} = 0x1f; let Inst{25-21} = 0; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = 0x3b; } class TEQ_FM funct> : StdArch { bits<5> rs; bits<5> rt; bits<10> code_; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-6} = code_; let Inst{5-0} = funct; } class TEQI_FM funct> : StdArch { bits<5> rs; bits<16> imm16; bits<32> Inst; let Inst{31-26} = 1; let Inst{25-21} = rs; let Inst{20-16} = funct; let Inst{15-0} = imm16; } class WAIT_FM : StdArch { bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25} = 1; let Inst{24-6} = 0; let Inst{5-0} = 0x20; } class EXTS_FM funct> : StdArch { bits<5> rt; bits<5> rs; bits<5> pos; bits<5> lenm1; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = lenm1; let Inst{10-6} = pos; let Inst{5-0} = funct; } class MTMR_FM funct> : StdArch { bits<5> rs; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-6} = 0; let Inst{5-0} = funct; } class POP_FM funct> : StdArch { bits<5> rd; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-16} = 0; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = funct; } class SEQ_FM funct> : StdArch { bits<5> rd; bits<5> rs; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = funct; } class SEQI_FM funct> : StdArch { bits<5> rs; bits<5> rt; bits<10> imm10; bits<32> Inst; let Inst{31-26} = 0x1c; let Inst{25-21} = rs; let Inst{20-16} = rt; let Inst{15-6} = imm10; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // System calls format //===----------------------------------------------------------------------===// class SYS_FM funct> : StdArch { bits<20> code_; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-6} = code_; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Break instruction format //===----------------------------------------------------------------------===// class BRK_FM funct> : StdArch { bits<10> code_1; bits<10> code_2; bits<32> Inst; let Inst{31-26} = 0x0; let Inst{25-16} = code_1; let Inst{15-6} = code_2; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Exception return format //===----------------------------------------------------------------------===// class ER_FM funct, bit LLBit> : StdArch { bits<32> Inst; let Inst{31-26} = 0x10; let Inst{25} = 1; let Inst{24-7} = 0; let Inst{6} = LLBit; let Inst{5-0} = funct; } //===----------------------------------------------------------------------===// // Enable/disable interrupt instruction format //===----------------------------------------------------------------------===// class EI_FM sc> : StdArch { bits<32> Inst; bits<5> rt; let Inst{31-26} = 0x10; let Inst{25-21} = 0xb; let Inst{20-16} = rt; let Inst{15-11} = 0xc; let Inst{10-6} = 0; let Inst{5} = sc; let Inst{4-0} = 0; } //===----------------------------------------------------------------------===// // // FLOATING POINT INSTRUCTION FORMATS // // opcode - operation code. // fs - src reg. // ft - dst reg (on a 2 regs instr) or src reg (on a 3 reg instr). // fd - dst reg, only used on 3 regs instr. // fmt - double or single precision. // funct - combined with opcode field give us an operation code. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Format FI instruction class in Mips : <|opcode|base|ft|immediate|> //===----------------------------------------------------------------------===// class FFI op, dag outs, dag ins, string asmstr, list pattern>: InstSE { bits<5> ft; bits<5> base; bits<16> imm16; let Opcode = op; let Inst{25-21} = base; let Inst{20-16} = ft; let Inst{15-0} = imm16; } class ADDS_FM funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; bits<5> ft; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = fmt; let Inst{20-16} = ft; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = funct; } class ABSS_FM funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = fmt; let Inst{20-16} = 0; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = funct; } class MFC1_FM funct> : StdArch { bits<5> rt; bits<5> fs; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = funct; let Inst{20-16} = rt; let Inst{15-11} = fs; let Inst{10-0} = 0; } class LW_FM op> : StdArch { bits<5> rt; bits<21> addr; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = addr{20-16}; let Inst{20-16} = rt; let Inst{15-0} = addr{15-0}; } class MADDS_FM funct, bits<3> fmt> : StdArch { bits<5> fd; bits<5> fr; bits<5> fs; bits<5> ft; bits<32> Inst; let Inst{31-26} = 0x13; let Inst{25-21} = fr; let Inst{20-16} = ft; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-3} = funct; let Inst{2-0} = fmt; } class LWXC1_FM funct> : StdArch { bits<5> fd; bits<5> base; bits<5> index; bits<32> Inst; let Inst{31-26} = 0x13; let Inst{25-21} = base; let Inst{20-16} = index; let Inst{15-11} = 0; let Inst{10-6} = fd; let Inst{5-0} = funct; } class SWXC1_FM funct> : StdArch { bits<5> fs; bits<5> base; bits<5> index; bits<32> Inst; let Inst{31-26} = 0x13; let Inst{25-21} = base; let Inst{20-16} = index; let Inst{15-11} = fs; let Inst{10-6} = 0; let Inst{5-0} = funct; } class BC1F_FM : StdArch { bits<3> fcc; bits<16> offset; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = 0x8; let Inst{20-18} = fcc; let Inst{17} = nd; let Inst{16} = tf; let Inst{15-0} = offset; } class CEQS_FM fmt> : StdArch { bits<5> fs; bits<5> ft; + bits<3> fcc; bits<4> cond; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = fmt; let Inst{20-16} = ft; let Inst{15-11} = fs; - let Inst{10-8} = 0; // cc + let Inst{10-8} = fcc; let Inst{7-4} = 0x3; let Inst{3-0} = cond; } class C_COND_FM fmt, bits<4> c> : CEQS_FM { let cond = c; } class CMov_I_F_FM funct, bits<5> fmt> : StdArch { bits<5> fd; bits<5> fs; bits<5> rt; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = fmt; let Inst{20-16} = rt; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = funct; } class CMov_F_I_FM : StdArch { bits<5> rd; bits<5> rs; bits<3> fcc; bits<32> Inst; let Inst{31-26} = 0; let Inst{25-21} = rs; let Inst{20-18} = fcc; let Inst{17} = 0; let Inst{16} = tf; let Inst{15-11} = rd; let Inst{10-6} = 0; let Inst{5-0} = 1; } class CMov_F_F_FM fmt, bit tf> : StdArch { bits<5> fd; bits<5> fs; bits<3> fcc; bits<32> Inst; let Inst{31-26} = 0x11; let Inst{25-21} = fmt; let Inst{20-18} = fcc; let Inst{17} = 0; let Inst{16} = tf; let Inst{15-11} = fs; let Inst{10-6} = fd; let Inst{5-0} = 0x11; } class BARRIER_FM op> : StdArch { bits<32> Inst; let Inst{31-26} = 0; // SPECIAL let Inst{25-21} = 0; let Inst{20-16} = 0; // rt = 0 let Inst{15-11} = 0; // rd = 0 let Inst{10-6} = op; // Operation let Inst{5-0} = 0; // SLL } class SDBBP_FM : StdArch { bits<20> code_; bits<32> Inst; let Inst{31-26} = 0b011100; // SPECIAL2 let Inst{25-6} = code_; let Inst{5-0} = 0b111111; // SDBBP } class JR_HB_FM op> : StdArch{ bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; // SPECIAL let Inst{25-21} = rs; let Inst{20-11} = 0; let Inst{10} = 1; let Inst{9-6} = 0; let Inst{5-0} = op; } class JALR_HB_FM op> : StdArch { bits<5> rd; bits<5> rs; bits<32> Inst; let Inst{31-26} = 0; // SPECIAL let Inst{25-21} = rs; let Inst{20-16} = 0; let Inst{15-11} = rd; let Inst{10} = 1; let Inst{9-6} = 0; let Inst{5-0} = op; } class COP0_TLB_FM op> : StdArch { bits<32> Inst; let Inst{31-26} = 0x10; // COP0 let Inst{25} = 1; // CO let Inst{24-6} = 0; let Inst{5-0} = op; // Operation } class CACHEOP_FM op> : StdArch { bits<21> addr; bits<5> hint; bits<5> base = addr{20-16}; bits<16> offset = addr{15-0}; bits<32> Inst; let Inst{31-26} = op; let Inst{25-21} = base; let Inst{20-16} = hint; let Inst{15-0} = offset; } Index: vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.cpp =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.cpp (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.cpp (revision 313056) @@ -1,150 +1,158 @@ //===-- MipsTargetObjectFile.cpp - Mips Object Files ----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "MipsTargetObjectFile.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ELF.h" #include "llvm/Target/TargetMachine.h" using namespace llvm; static cl::opt SSThreshold("mips-ssection-threshold", cl::Hidden, cl::desc("Small data and bss section threshold size (default=8)"), cl::init(8)); static cl::opt LocalSData("mlocal-sdata", cl::Hidden, cl::desc("MIPS: Use gp_rel for object-local data."), cl::init(true)); static cl::opt ExternSData("mextern-sdata", cl::Hidden, cl::desc("MIPS: Use gp_rel for data that is not defined by the " "current object."), cl::init(true)); void MipsTargetObjectFile::Initialize(MCContext &Ctx, const TargetMachine &TM){ TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(TM.Options.UseInitArray); SmallDataSection = getContext().getELFSection( ".sdata", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); SmallBSSSection = getContext().getELFSection(".sbss", ELF::SHT_NOBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC | ELF::SHF_MIPS_GPREL); this->TM = &static_cast(TM); } // A address must be loaded from a small section if its size is less than the // small section size threshold. Data in this section must be addressed using // gp_rel operator. static bool IsInSmallSection(uint64_t Size) { // gcc has traditionally not treated zero-sized objects as small data, so this // is effectively part of the ABI. return Size > 0 && Size <= SSThreshold; } /// Return true if this global address should be placed into small data/bss /// section. bool MipsTargetObjectFile::IsGlobalInSmallSection( const GlobalObject *GO, const TargetMachine &TM) const { // We first check the case where global is a declaration, because finding // section kind using getKindForGlobal() is only allowed for global // definitions. if (GO->isDeclaration() || GO->hasAvailableExternallyLinkage()) return IsGlobalInSmallSectionImpl(GO, TM); return IsGlobalInSmallSection(GO, TM, getKindForGlobal(GO, TM)); } /// Return true if this global address should be placed into small data/bss /// section. bool MipsTargetObjectFile:: IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM, SectionKind Kind) const { return (IsGlobalInSmallSectionImpl(GO, TM) && (Kind.isData() || Kind.isBSS() || Kind.isCommon())); } /// Return true if this global address should be placed into small data/bss /// section. This method does all the work, except for checking the section /// kind. bool MipsTargetObjectFile:: IsGlobalInSmallSectionImpl(const GlobalObject *GO, const TargetMachine &TM) const { const MipsSubtarget &Subtarget = *static_cast(TM).getSubtargetImpl(); // Return if small section is not available. if (!Subtarget.useSmallSection()) return false; // Only global variables, not functions. const GlobalVariable *GVA = dyn_cast(GO); if (!GVA) return false; // Enforce -mlocal-sdata. if (!LocalSData && GVA->hasLocalLinkage()) return false; // Enforce -mextern-sdata. if (!ExternSData && ((GVA->hasExternalLinkage() && GVA->isDeclaration()) || GVA->hasCommonLinkage())) return false; Type *Ty = GVA->getValueType(); return IsInSmallSection( GVA->getParent()->getDataLayout().getTypeAllocSize(Ty)); } MCSection *MipsTargetObjectFile::SelectSectionForGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { // TODO: Could also support "weak" symbols as well with ".gnu.linkonce.s.*" // sections? // Handle Small Section classification here. if (Kind.isBSS() && IsGlobalInSmallSection(GO, TM, Kind)) return SmallBSSSection; if (Kind.isData() && IsGlobalInSmallSection(GO, TM, Kind)) return SmallDataSection; // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, Kind, TM); } /// Return true if this constant should be placed into small data section. bool MipsTargetObjectFile::IsConstantInSmallSection( const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const { return (static_cast(TM) .getSubtargetImpl() ->useSmallSection() && LocalSData && IsInSmallSection(DL.getTypeAllocSize(CN->getType()))); } /// Return true if this constant should be placed into small data section. MCSection *MipsTargetObjectFile::getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, unsigned &Align) const { if (IsConstantInSmallSection(DL, C, *TM)) return SmallDataSection; // Otherwise, we work the same as ELF. return TargetLoweringObjectFileELF::getSectionForConstant(DL, Kind, C, Align); } + +const MCExpr * +MipsTargetObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const { + const MCExpr *Expr = + MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + return MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(0x8000, getContext()), getContext()); +} Index: vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.h =================================================================== --- vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.h (revision 313055) +++ vendor/llvm/dist/lib/Target/Mips/MipsTargetObjectFile.h (revision 313056) @@ -1,48 +1,50 @@ //===-- llvm/Target/MipsTargetObjectFile.h - Mips Object Info ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_MIPS_MIPSTARGETOBJECTFILE_H #define LLVM_LIB_TARGET_MIPS_MIPSTARGETOBJECTFILE_H #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" namespace llvm { class MipsTargetMachine; class MipsTargetObjectFile : public TargetLoweringObjectFileELF { MCSection *SmallDataSection; MCSection *SmallBSSSection; const MipsTargetMachine *TM; bool IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM, SectionKind Kind) const; bool IsGlobalInSmallSectionImpl(const GlobalObject *GO, const TargetMachine &TM) const; public: void Initialize(MCContext &Ctx, const TargetMachine &TM) override; /// Return true if this global address should be placed into small data/bss /// section. bool IsGlobalInSmallSection(const GlobalObject *GO, const TargetMachine &TM) const; MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const override; /// Return true if this constant should be placed into small data section. bool IsConstantInSmallSection(const DataLayout &DL, const Constant *CN, const TargetMachine &TM) const; MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, const Constant *C, unsigned &Align) const override; + /// Describe a TLS variable address within debug info. + const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override; }; } // end namespace llvm #endif Index: vendor/llvm/dist/lib/Target/PowerPC/PPCInstrInfo.td =================================================================== --- vendor/llvm/dist/lib/Target/PowerPC/PPCInstrInfo.td (revision 313055) +++ vendor/llvm/dist/lib/Target/PowerPC/PPCInstrInfo.td (revision 313056) @@ -1,4411 +1,4424 @@ //===-- PPCInstrInfo.td - The PowerPC Instruction Set ------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file describes the subset of the 32-bit PowerPC instruction set, as used // by the PowerPC instruction selector. // //===----------------------------------------------------------------------===// include "PPCInstrFormats.td" //===----------------------------------------------------------------------===// // PowerPC specific type constraints. // def SDT_PPCstfiwx : SDTypeProfile<0, 2, [ // stfiwx SDTCisVT<0, f64>, SDTCisPtrTy<1> ]>; def SDT_PPClfiwx : SDTypeProfile<1, 1, [ // lfiw[az]x SDTCisVT<0, f64>, SDTCisPtrTy<1> ]>; def SDT_PPCLxsizx : SDTypeProfile<1, 2, [ SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2> ]>; def SDT_PPCstxsix : SDTypeProfile<0, 3, [ SDTCisVT<0, f64>, SDTCisPtrTy<1>, SDTCisPtrTy<2> ]>; def SDT_PPCVexts : SDTypeProfile<1, 2, [ SDTCisVT<0, f64>, SDTCisVT<1, f64>, SDTCisPtrTy<2> ]>; def SDT_PPCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; def SDT_PPCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, SDTCisVT<1, i32> ]>; def SDT_PPCvperm : SDTypeProfile<1, 3, [ SDTCisVT<3, v16i8>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2> ]>; def SDT_PPCVecSplat : SDTypeProfile<1, 2, [ SDTCisVec<0>, SDTCisVec<1>, SDTCisInt<2> ]>; def SDT_PPCVecShift : SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3> ]>; def SDT_PPCVecInsert : SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisVec<1>, SDTCisVec<2>, SDTCisInt<3> ]>; def SDT_PPCvcmp : SDTypeProfile<1, 3, [ SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32> ]>; def SDT_PPCcondbr : SDTypeProfile<0, 3, [ SDTCisVT<0, i32>, SDTCisVT<2, OtherVT> ]>; def SDT_PPClbrx : SDTypeProfile<1, 2, [ SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT> ]>; def SDT_PPCstbrx : SDTypeProfile<0, 3, [ SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT> ]>; def SDT_PPCTC_ret : SDTypeProfile<0, 2, [ SDTCisPtrTy<0>, SDTCisVT<1, i32> ]>; def tocentry32 : Operand { let MIOperandInfo = (ops i32imm:$imm); } def SDT_PPCqvfperm : SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisVec<3> ]>; def SDT_PPCqvgpci : SDTypeProfile<1, 1, [ SDTCisVec<0>, SDTCisInt<1> ]>; def SDT_PPCqvaligni : SDTypeProfile<1, 3, [ SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisInt<3> ]>; def SDT_PPCqvesplati : SDTypeProfile<1, 2, [ SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisInt<2> ]>; def SDT_PPCqbflt : SDTypeProfile<1, 1, [ SDTCisVec<0>, SDTCisVec<1> ]>; def SDT_PPCqvlfsb : SDTypeProfile<1, 1, [ SDTCisVec<0>, SDTCisPtrTy<1> ]>; //===----------------------------------------------------------------------===// // PowerPC specific DAG Nodes. // def PPCfre : SDNode<"PPCISD::FRE", SDTFPUnaryOp, []>; def PPCfrsqrte: SDNode<"PPCISD::FRSQRTE", SDTFPUnaryOp, []>; def PPCfcfid : SDNode<"PPCISD::FCFID", SDTFPUnaryOp, []>; def PPCfcfidu : SDNode<"PPCISD::FCFIDU", SDTFPUnaryOp, []>; def PPCfcfids : SDNode<"PPCISD::FCFIDS", SDTFPRoundOp, []>; def PPCfcfidus: SDNode<"PPCISD::FCFIDUS", SDTFPRoundOp, []>; def PPCfctidz : SDNode<"PPCISD::FCTIDZ", SDTFPUnaryOp, []>; def PPCfctiwz : SDNode<"PPCISD::FCTIWZ", SDTFPUnaryOp, []>; def PPCfctiduz: SDNode<"PPCISD::FCTIDUZ",SDTFPUnaryOp, []>; def PPCfctiwuz: SDNode<"PPCISD::FCTIWUZ",SDTFPUnaryOp, []>; def PPCstfiwx : SDNode<"PPCISD::STFIWX", SDT_PPCstfiwx, [SDNPHasChain, SDNPMayStore]>; def PPClfiwax : SDNode<"PPCISD::LFIWAX", SDT_PPClfiwx, [SDNPHasChain, SDNPMayLoad]>; def PPClfiwzx : SDNode<"PPCISD::LFIWZX", SDT_PPClfiwx, [SDNPHasChain, SDNPMayLoad]>; def PPClxsizx : SDNode<"PPCISD::LXSIZX", SDT_PPCLxsizx, [SDNPHasChain, SDNPMayLoad]>; def PPCstxsix : SDNode<"PPCISD::STXSIX", SDT_PPCstxsix, [SDNPHasChain, SDNPMayStore]>; def PPCVexts : SDNode<"PPCISD::VEXTS", SDT_PPCVexts, []>; // Extract FPSCR (not modeled at the DAG level). def PPCmffs : SDNode<"PPCISD::MFFS", SDTypeProfile<1, 0, [SDTCisVT<0, f64>]>, []>; // Perform FADD in round-to-zero mode. def PPCfaddrtz: SDNode<"PPCISD::FADDRTZ", SDTFPBinOp, []>; def PPCfsel : SDNode<"PPCISD::FSEL", // Type constraint for fsel. SDTypeProfile<1, 3, [SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisFP<0>, SDTCisVT<1, f64>]>, []>; def PPChi : SDNode<"PPCISD::Hi", SDTIntBinOp, []>; def PPClo : SDNode<"PPCISD::Lo", SDTIntBinOp, []>; def PPCtoc_entry: SDNode<"PPCISD::TOC_ENTRY", SDTIntBinOp, [SDNPMayLoad, SDNPMemOperand]>; def PPCvmaddfp : SDNode<"PPCISD::VMADDFP", SDTFPTernaryOp, []>; def PPCvnmsubfp : SDNode<"PPCISD::VNMSUBFP", SDTFPTernaryOp, []>; def PPCppc32GOT : SDNode<"PPCISD::PPC32_GOT", SDTIntLeaf, []>; def PPCaddisGotTprelHA : SDNode<"PPCISD::ADDIS_GOT_TPREL_HA", SDTIntBinOp>; def PPCldGotTprelL : SDNode<"PPCISD::LD_GOT_TPREL_L", SDTIntBinOp, [SDNPMayLoad]>; def PPCaddTls : SDNode<"PPCISD::ADD_TLS", SDTIntBinOp, []>; def PPCaddisTlsgdHA : SDNode<"PPCISD::ADDIS_TLSGD_HA", SDTIntBinOp>; def PPCaddiTlsgdL : SDNode<"PPCISD::ADDI_TLSGD_L", SDTIntBinOp>; def PPCgetTlsAddr : SDNode<"PPCISD::GET_TLS_ADDR", SDTIntBinOp>; def PPCaddiTlsgdLAddr : SDNode<"PPCISD::ADDI_TLSGD_L_ADDR", SDTypeProfile<1, 3, [ SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisInt<0> ]>>; def PPCaddisTlsldHA : SDNode<"PPCISD::ADDIS_TLSLD_HA", SDTIntBinOp>; def PPCaddiTlsldL : SDNode<"PPCISD::ADDI_TLSLD_L", SDTIntBinOp>; def PPCgetTlsldAddr : SDNode<"PPCISD::GET_TLSLD_ADDR", SDTIntBinOp>; def PPCaddiTlsldLAddr : SDNode<"PPCISD::ADDI_TLSLD_L_ADDR", SDTypeProfile<1, 3, [ SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisInt<0> ]>>; def PPCaddisDtprelHA : SDNode<"PPCISD::ADDIS_DTPREL_HA", SDTIntBinOp>; def PPCaddiDtprelL : SDNode<"PPCISD::ADDI_DTPREL_L", SDTIntBinOp>; def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>; def PPCxxsplt : SDNode<"PPCISD::XXSPLT", SDT_PPCVecSplat, []>; def PPCxxinsert : SDNode<"PPCISD::XXINSERT", SDT_PPCVecInsert, []>; def PPCvecshl : SDNode<"PPCISD::VECSHL", SDT_PPCVecShift, []>; def PPCqvfperm : SDNode<"PPCISD::QVFPERM", SDT_PPCqvfperm, []>; def PPCqvgpci : SDNode<"PPCISD::QVGPCI", SDT_PPCqvgpci, []>; def PPCqvaligni : SDNode<"PPCISD::QVALIGNI", SDT_PPCqvaligni, []>; def PPCqvesplati : SDNode<"PPCISD::QVESPLATI", SDT_PPCqvesplati, []>; def PPCqbflt : SDNode<"PPCISD::QBFLT", SDT_PPCqbflt, []>; def PPCqvlfsb : SDNode<"PPCISD::QVLFSb", SDT_PPCqvlfsb, [SDNPHasChain, SDNPMayLoad]>; def PPCcmpb : SDNode<"PPCISD::CMPB", SDTIntBinOp, []>; // These nodes represent the 32-bit PPC shifts that operate on 6-bit shift // amounts. These nodes are generated by the multi-precision shift code. def PPCsrl : SDNode<"PPCISD::SRL" , SDTIntShiftOp>; def PPCsra : SDNode<"PPCISD::SRA" , SDTIntShiftOp>; def PPCshl : SDNode<"PPCISD::SHL" , SDTIntShiftOp>; // These are target-independent nodes, but have target-specific formats. def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_PPCCallSeqStart, [SDNPHasChain, SDNPOutGlue]>; def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_PPCCallSeqEnd, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; def SDT_PPCCall : SDTypeProfile<0, -1, [SDTCisInt<0>]>; def PPCcall : SDNode<"PPCISD::CALL", SDT_PPCCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def PPCcall_nop : SDNode<"PPCISD::CALL_NOP", SDT_PPCCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def PPCmtctr : SDNode<"PPCISD::MTCTR", SDT_PPCCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; def PPCbctrl : SDNode<"PPCISD::BCTRL", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def PPCbctrl_load_toc : SDNode<"PPCISD::BCTRL_LOAD_TOC", SDTypeProfile<0, 1, []>, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def retflag : SDNode<"PPCISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def PPCtc_return : SDNode<"PPCISD::TC_RETURN", SDT_PPCTC_ret, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def PPCeh_sjlj_setjmp : SDNode<"PPCISD::EH_SJLJ_SETJMP", SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisPtrTy<1>]>, [SDNPHasChain, SDNPSideEffect]>; def PPCeh_sjlj_longjmp : SDNode<"PPCISD::EH_SJLJ_LONGJMP", SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>, [SDNPHasChain, SDNPSideEffect]>; def SDT_PPCsc : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def PPCsc : SDNode<"PPCISD::SC", SDT_PPCsc, [SDNPHasChain, SDNPSideEffect]>; def PPCclrbhrb : SDNode<"PPCISD::CLRBHRB", SDTNone, [SDNPHasChain, SDNPSideEffect]>; def PPCmfbhrbe : SDNode<"PPCISD::MFBHRBE", SDTIntBinOp, [SDNPHasChain]>; def PPCrfebb : SDNode<"PPCISD::RFEBB", SDT_PPCsc, [SDNPHasChain, SDNPSideEffect]>; def PPCvcmp : SDNode<"PPCISD::VCMP" , SDT_PPCvcmp, []>; def PPCvcmp_o : SDNode<"PPCISD::VCMPo", SDT_PPCvcmp, [SDNPOutGlue]>; def PPCcondbranch : SDNode<"PPCISD::COND_BRANCH", SDT_PPCcondbr, [SDNPHasChain, SDNPOptInGlue]>; def PPClbrx : SDNode<"PPCISD::LBRX", SDT_PPClbrx, [SDNPHasChain, SDNPMayLoad]>; def PPCstbrx : SDNode<"PPCISD::STBRX", SDT_PPCstbrx, [SDNPHasChain, SDNPMayStore]>; // Instructions to set/unset CR bit 6 for SVR4 vararg calls def PPCcr6set : SDNode<"PPCISD::CR6SET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; def PPCcr6unset : SDNode<"PPCISD::CR6UNSET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; // Instructions to support dynamic alloca. def SDTDynOp : SDTypeProfile<1, 2, []>; def SDTDynAreaOp : SDTypeProfile<1, 1, []>; def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>; def PPCdynareaoffset : SDNode<"PPCISD::DYNAREAOFFSET", SDTDynAreaOp, [SDNPHasChain]>; //===----------------------------------------------------------------------===// // PowerPC specific transformation functions and pattern fragments. // def SHL32 : SDNodeXFormgetZExtValue(), SDLoc(N)); }]>; def SRL32 : SDNodeXFormgetZExtValue() ? getI32Imm(32 - N->getZExtValue(), SDLoc(N)) : getI32Imm(0, SDLoc(N)); }]>; def LO16 : SDNodeXFormgetZExtValue(), SDLoc(N)); }]>; def HI16 : SDNodeXFormgetZExtValue() >> 16, SDLoc(N)); }]>; def HA16 : SDNodeXFormgetZExtValue(); return getI32Imm((Val - (signed short)Val) >> 16, SDLoc(N)); }]>; def MB : SDNodeXFormgetZExtValue(), mb, me); return getI32Imm(mb, SDLoc(N)); }]>; def ME : SDNodeXFormgetZExtValue(), mb, me); return getI32Imm(me, SDLoc(N)); }]>; def maskimm32 : PatLeaf<(imm), [{ // maskImm predicate - True if immediate is a run of ones. unsigned mb, me; if (N->getValueType(0) == MVT::i32) return isRunOfOnes((unsigned)N->getZExtValue(), mb, me); else return false; }]>; def imm32SExt16 : Operand, ImmLeaf; def imm64SExt16 : Operand, ImmLeaf; def immZExt16 : PatLeaf<(imm), [{ // immZExt16 predicate - True if the immediate fits in a 16-bit zero extended // field. Used by instructions like 'ori'. return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); }], LO16>; def immAnyExt8 : ImmLeaf(Imm) || isUInt<8>(Imm); }]>; def immSExt5NonZero : ImmLeaf(Imm); }]>; // imm16Shifted* - These match immediates where the low 16-bits are zero. There // are two forms: imm16ShiftedSExt and imm16ShiftedZExt. These two forms are // identical in 32-bit mode, but in 64-bit mode, they return true if the // immediate fits into a sign/zero extended 32-bit immediate (with the low bits // clear). def imm16ShiftedZExt : PatLeaf<(imm), [{ // imm16ShiftedZExt predicate - True if only bits in the top 16-bits of the // immediate are set. Used by instructions like 'xoris'. return (N->getZExtValue() & ~uint64_t(0xFFFF0000)) == 0; }], HI16>; def imm16ShiftedSExt : PatLeaf<(imm), [{ // imm16ShiftedSExt predicate - True if only bits in the top 16-bits of the // immediate are set. Used by instructions like 'addis'. Identical to // imm16ShiftedZExt in 32-bit mode. if (N->getZExtValue() & 0xFFFF) return false; if (N->getValueType(0) == MVT::i32) return true; // For 64-bit, make sure it is sext right. return N->getZExtValue() == (uint64_t)(int)N->getZExtValue(); }], HI16>; def imm64ZExt32 : Operand, ImmLeaf(Imm); }]>; // Some r+i load/store instructions (such as LD, STD, LDU, etc.) that require // restricted memrix (4-aligned) constants are alignment sensitive. If these // offsets are hidden behind TOC entries than the values of the lower-order // bits cannot be checked directly. As a result, we need to also incorporate // an alignment check into the relevant patterns. def aligned4load : PatFrag<(ops node:$ptr), (load node:$ptr), [{ return cast(N)->getAlignment() >= 4; }]>; def aligned4store : PatFrag<(ops node:$val, node:$ptr), (store node:$val, node:$ptr), [{ return cast(N)->getAlignment() >= 4; }]>; def aligned4sextloadi32 : PatFrag<(ops node:$ptr), (sextloadi32 node:$ptr), [{ return cast(N)->getAlignment() >= 4; }]>; def aligned4pre_store : PatFrag< (ops node:$val, node:$base, node:$offset), (pre_store node:$val, node:$base, node:$offset), [{ return cast(N)->getAlignment() >= 4; }]>; def unaligned4load : PatFrag<(ops node:$ptr), (load node:$ptr), [{ return cast(N)->getAlignment() < 4; }]>; def unaligned4store : PatFrag<(ops node:$val, node:$ptr), (store node:$val, node:$ptr), [{ return cast(N)->getAlignment() < 4; }]>; def unaligned4sextloadi32 : PatFrag<(ops node:$ptr), (sextloadi32 node:$ptr), [{ return cast(N)->getAlignment() < 4; }]>; //===----------------------------------------------------------------------===// // PowerPC Flag Definitions. class isPPC64 { bit PPC64 = 1; } class isDOT { bit RC = 1; } class RegConstraint { string Constraints = C; } class NoEncode { string DisableEncoding = E; } //===----------------------------------------------------------------------===// // PowerPC Operand Definitions. // In the default PowerPC assembler syntax, registers are specified simply // by number, so they cannot be distinguished from immediate values (without // looking at the opcode). This means that the default operand matching logic // for the asm parser does not work, and we need to specify custom matchers. // Since those can only be specified with RegisterOperand classes and not // directly on the RegisterClass, all instructions patterns used by the asm // parser need to use a RegisterOperand (instead of a RegisterClass) for // all their register operands. // For this purpose, we define one RegisterOperand for each RegisterClass, // using the same name as the class, just in lower case. def PPCRegGPRCAsmOperand : AsmOperandClass { let Name = "RegGPRC"; let PredicateMethod = "isRegNumber"; } def gprc : RegisterOperand { let ParserMatchClass = PPCRegGPRCAsmOperand; } def PPCRegG8RCAsmOperand : AsmOperandClass { let Name = "RegG8RC"; let PredicateMethod = "isRegNumber"; } def g8rc : RegisterOperand { let ParserMatchClass = PPCRegG8RCAsmOperand; } def PPCRegGPRCNoR0AsmOperand : AsmOperandClass { let Name = "RegGPRCNoR0"; let PredicateMethod = "isRegNumber"; } def gprc_nor0 : RegisterOperand { let ParserMatchClass = PPCRegGPRCNoR0AsmOperand; } def PPCRegG8RCNoX0AsmOperand : AsmOperandClass { let Name = "RegG8RCNoX0"; let PredicateMethod = "isRegNumber"; } def g8rc_nox0 : RegisterOperand { let ParserMatchClass = PPCRegG8RCNoX0AsmOperand; } def PPCRegF8RCAsmOperand : AsmOperandClass { let Name = "RegF8RC"; let PredicateMethod = "isRegNumber"; } def f8rc : RegisterOperand { let ParserMatchClass = PPCRegF8RCAsmOperand; } def PPCRegF4RCAsmOperand : AsmOperandClass { let Name = "RegF4RC"; let PredicateMethod = "isRegNumber"; } def f4rc : RegisterOperand { let ParserMatchClass = PPCRegF4RCAsmOperand; } def PPCRegVRRCAsmOperand : AsmOperandClass { let Name = "RegVRRC"; let PredicateMethod = "isRegNumber"; } def vrrc : RegisterOperand { let ParserMatchClass = PPCRegVRRCAsmOperand; } def PPCRegVFRCAsmOperand : AsmOperandClass { let Name = "RegVFRC"; let PredicateMethod = "isRegNumber"; } def vfrc : RegisterOperand { let ParserMatchClass = PPCRegVFRCAsmOperand; } def PPCRegCRBITRCAsmOperand : AsmOperandClass { let Name = "RegCRBITRC"; let PredicateMethod = "isCRBitNumber"; } def crbitrc : RegisterOperand { let ParserMatchClass = PPCRegCRBITRCAsmOperand; } def PPCRegCRRCAsmOperand : AsmOperandClass { let Name = "RegCRRC"; let PredicateMethod = "isCCRegNumber"; } def crrc : RegisterOperand { let ParserMatchClass = PPCRegCRRCAsmOperand; } def crrc0 : RegisterOperand { let ParserMatchClass = PPCRegCRRCAsmOperand; } def PPCU1ImmAsmOperand : AsmOperandClass { let Name = "U1Imm"; let PredicateMethod = "isU1Imm"; let RenderMethod = "addImmOperands"; } def u1imm : Operand { let PrintMethod = "printU1ImmOperand"; let ParserMatchClass = PPCU1ImmAsmOperand; } def PPCU2ImmAsmOperand : AsmOperandClass { let Name = "U2Imm"; let PredicateMethod = "isU2Imm"; let RenderMethod = "addImmOperands"; } def u2imm : Operand { let PrintMethod = "printU2ImmOperand"; let ParserMatchClass = PPCU2ImmAsmOperand; } def PPCATBitsAsHintAsmOperand : AsmOperandClass { let Name = "ATBitsAsHint"; let PredicateMethod = "isATBitsAsHint"; let RenderMethod = "addImmOperands"; // Irrelevant, predicate always fails. } def atimm : Operand { let PrintMethod = "printATBitsAsHint"; let ParserMatchClass = PPCATBitsAsHintAsmOperand; } def PPCU3ImmAsmOperand : AsmOperandClass { let Name = "U3Imm"; let PredicateMethod = "isU3Imm"; let RenderMethod = "addImmOperands"; } def u3imm : Operand { let PrintMethod = "printU3ImmOperand"; let ParserMatchClass = PPCU3ImmAsmOperand; } def PPCU4ImmAsmOperand : AsmOperandClass { let Name = "U4Imm"; let PredicateMethod = "isU4Imm"; let RenderMethod = "addImmOperands"; } def u4imm : Operand { let PrintMethod = "printU4ImmOperand"; let ParserMatchClass = PPCU4ImmAsmOperand; } def PPCS5ImmAsmOperand : AsmOperandClass { let Name = "S5Imm"; let PredicateMethod = "isS5Imm"; let RenderMethod = "addImmOperands"; } def s5imm : Operand { let PrintMethod = "printS5ImmOperand"; let ParserMatchClass = PPCS5ImmAsmOperand; let DecoderMethod = "decodeSImmOperand<5>"; } def PPCU5ImmAsmOperand : AsmOperandClass { let Name = "U5Imm"; let PredicateMethod = "isU5Imm"; let RenderMethod = "addImmOperands"; } def u5imm : Operand { let PrintMethod = "printU5ImmOperand"; let ParserMatchClass = PPCU5ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<5>"; } def PPCU6ImmAsmOperand : AsmOperandClass { let Name = "U6Imm"; let PredicateMethod = "isU6Imm"; let RenderMethod = "addImmOperands"; } def u6imm : Operand { let PrintMethod = "printU6ImmOperand"; let ParserMatchClass = PPCU6ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<6>"; } def PPCU7ImmAsmOperand : AsmOperandClass { let Name = "U7Imm"; let PredicateMethod = "isU7Imm"; let RenderMethod = "addImmOperands"; } def u7imm : Operand { let PrintMethod = "printU7ImmOperand"; let ParserMatchClass = PPCU7ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<7>"; } def PPCU8ImmAsmOperand : AsmOperandClass { let Name = "U8Imm"; let PredicateMethod = "isU8Imm"; let RenderMethod = "addImmOperands"; } def u8imm : Operand { let PrintMethod = "printU8ImmOperand"; let ParserMatchClass = PPCU8ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<8>"; } def PPCU10ImmAsmOperand : AsmOperandClass { let Name = "U10Imm"; let PredicateMethod = "isU10Imm"; let RenderMethod = "addImmOperands"; } def u10imm : Operand { let PrintMethod = "printU10ImmOperand"; let ParserMatchClass = PPCU10ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<10>"; } def PPCU12ImmAsmOperand : AsmOperandClass { let Name = "U12Imm"; let PredicateMethod = "isU12Imm"; let RenderMethod = "addImmOperands"; } def u12imm : Operand { let PrintMethod = "printU12ImmOperand"; let ParserMatchClass = PPCU12ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<12>"; } def PPCS16ImmAsmOperand : AsmOperandClass { let Name = "S16Imm"; let PredicateMethod = "isS16Imm"; let RenderMethod = "addS16ImmOperands"; } def s16imm : Operand { let PrintMethod = "printS16ImmOperand"; let EncoderMethod = "getImm16Encoding"; let ParserMatchClass = PPCS16ImmAsmOperand; let DecoderMethod = "decodeSImmOperand<16>"; } def PPCU16ImmAsmOperand : AsmOperandClass { let Name = "U16Imm"; let PredicateMethod = "isU16Imm"; let RenderMethod = "addU16ImmOperands"; } def u16imm : Operand { let PrintMethod = "printU16ImmOperand"; let EncoderMethod = "getImm16Encoding"; let ParserMatchClass = PPCU16ImmAsmOperand; let DecoderMethod = "decodeUImmOperand<16>"; } def PPCS17ImmAsmOperand : AsmOperandClass { let Name = "S17Imm"; let PredicateMethod = "isS17Imm"; let RenderMethod = "addS16ImmOperands"; } def s17imm : Operand { // This operand type is used for addis/lis to allow the assembler parser // to accept immediates in the range -65536..65535 for compatibility with // the GNU assembler. The operand is treated as 16-bit otherwise. let PrintMethod = "printS16ImmOperand"; let EncoderMethod = "getImm16Encoding"; let ParserMatchClass = PPCS17ImmAsmOperand; let DecoderMethod = "decodeSImmOperand<16>"; } def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; def PPCDirectBrAsmOperand : AsmOperandClass { let Name = "DirectBr"; let PredicateMethod = "isDirectBr"; let RenderMethod = "addBranchTargetOperands"; } def directbrtarget : Operand { let PrintMethod = "printBranchOperand"; let EncoderMethod = "getDirectBrEncoding"; let ParserMatchClass = PPCDirectBrAsmOperand; } def absdirectbrtarget : Operand { let PrintMethod = "printAbsBranchOperand"; let EncoderMethod = "getAbsDirectBrEncoding"; let ParserMatchClass = PPCDirectBrAsmOperand; } def PPCCondBrAsmOperand : AsmOperandClass { let Name = "CondBr"; let PredicateMethod = "isCondBr"; let RenderMethod = "addBranchTargetOperands"; } def condbrtarget : Operand { let PrintMethod = "printBranchOperand"; let EncoderMethod = "getCondBrEncoding"; let ParserMatchClass = PPCCondBrAsmOperand; } def abscondbrtarget : Operand { let PrintMethod = "printAbsBranchOperand"; let EncoderMethod = "getAbsCondBrEncoding"; let ParserMatchClass = PPCCondBrAsmOperand; } def calltarget : Operand { let PrintMethod = "printBranchOperand"; let EncoderMethod = "getDirectBrEncoding"; let ParserMatchClass = PPCDirectBrAsmOperand; } def abscalltarget : Operand { let PrintMethod = "printAbsBranchOperand"; let EncoderMethod = "getAbsDirectBrEncoding"; let ParserMatchClass = PPCDirectBrAsmOperand; } def PPCCRBitMaskOperand : AsmOperandClass { let Name = "CRBitMask"; let PredicateMethod = "isCRBitMask"; } def crbitm: Operand { let PrintMethod = "printcrbitm"; let EncoderMethod = "get_crbitm_encoding"; let DecoderMethod = "decodeCRBitMOperand"; let ParserMatchClass = PPCCRBitMaskOperand; } // Address operands // A version of ptr_rc which excludes R0 (or X0 in 64-bit mode). def PPCRegGxRCNoR0Operand : AsmOperandClass { let Name = "RegGxRCNoR0"; let PredicateMethod = "isRegNumber"; } def ptr_rc_nor0 : Operand, PointerLikeRegClass<1> { let ParserMatchClass = PPCRegGxRCNoR0Operand; } // A version of ptr_rc usable with the asm parser. def PPCRegGxRCOperand : AsmOperandClass { let Name = "RegGxRC"; let PredicateMethod = "isRegNumber"; } def ptr_rc_idx : Operand, PointerLikeRegClass<0> { let ParserMatchClass = PPCRegGxRCOperand; } def PPCDispRIOperand : AsmOperandClass { let Name = "DispRI"; let PredicateMethod = "isS16Imm"; let RenderMethod = "addS16ImmOperands"; } def dispRI : Operand { let ParserMatchClass = PPCDispRIOperand; } def PPCDispRIXOperand : AsmOperandClass { let Name = "DispRIX"; let PredicateMethod = "isS16ImmX4"; let RenderMethod = "addImmOperands"; } def dispRIX : Operand { let ParserMatchClass = PPCDispRIXOperand; } def PPCDispRIX16Operand : AsmOperandClass { let Name = "DispRIX16"; let PredicateMethod = "isS16ImmX16"; let RenderMethod = "addImmOperands"; } def dispRIX16 : Operand { let ParserMatchClass = PPCDispRIX16Operand; } def PPCDispSPE8Operand : AsmOperandClass { let Name = "DispSPE8"; let PredicateMethod = "isU8ImmX8"; let RenderMethod = "addImmOperands"; } def dispSPE8 : Operand { let ParserMatchClass = PPCDispSPE8Operand; } def PPCDispSPE4Operand : AsmOperandClass { let Name = "DispSPE4"; let PredicateMethod = "isU7ImmX4"; let RenderMethod = "addImmOperands"; } def dispSPE4 : Operand { let ParserMatchClass = PPCDispSPE4Operand; } def PPCDispSPE2Operand : AsmOperandClass { let Name = "DispSPE2"; let PredicateMethod = "isU6ImmX2"; let RenderMethod = "addImmOperands"; } def dispSPE2 : Operand { let ParserMatchClass = PPCDispSPE2Operand; } def memri : Operand { let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispRI:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getMemRIEncoding"; let DecoderMethod = "decodeMemRIOperands"; } def memrr : Operand { let PrintMethod = "printMemRegReg"; let MIOperandInfo = (ops ptr_rc_nor0:$ptrreg, ptr_rc_idx:$offreg); } def memrix : Operand { // memri where the imm is 4-aligned. let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispRIX:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getMemRIXEncoding"; let DecoderMethod = "decodeMemRIXOperands"; } def memrix16 : Operand { // memri, imm is 16-aligned, 12-bit, Inst{16:27} let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispRIX16:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getMemRIX16Encoding"; let DecoderMethod = "decodeMemRIX16Operands"; } def spe8dis : Operand { // SPE displacement where the imm is 8-aligned. let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispSPE8:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getSPE8DisEncoding"; } def spe4dis : Operand { // SPE displacement where the imm is 4-aligned. let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispSPE4:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getSPE4DisEncoding"; } def spe2dis : Operand { // SPE displacement where the imm is 2-aligned. let PrintMethod = "printMemRegImm"; let MIOperandInfo = (ops dispSPE2:$imm, ptr_rc_nor0:$reg); let EncoderMethod = "getSPE2DisEncoding"; } // A single-register address. This is used with the SjLj // pseudo-instructions. def memr : Operand { let MIOperandInfo = (ops ptr_rc:$ptrreg); } def PPCTLSRegOperand : AsmOperandClass { let Name = "TLSReg"; let PredicateMethod = "isTLSReg"; let RenderMethod = "addTLSRegOperands"; } def tlsreg32 : Operand { let EncoderMethod = "getTLSRegEncoding"; let ParserMatchClass = PPCTLSRegOperand; } def tlsgd32 : Operand {} def tlscall32 : Operand { let PrintMethod = "printTLSCall"; let MIOperandInfo = (ops calltarget:$func, tlsgd32:$sym); let EncoderMethod = "getTLSCallEncoding"; } // PowerPC Predicate operand. def pred : Operand { let PrintMethod = "printPredicateOperand"; let MIOperandInfo = (ops i32imm:$bibo, crrc:$reg); } // Define PowerPC specific addressing mode. def iaddr : ComplexPattern; def xaddr : ComplexPattern; def xoaddr : ComplexPattern; def ixaddr : ComplexPattern; // "std" // The address in a single register. This is used with the SjLj // pseudo-instructions. def addr : ComplexPattern; /// This is just the offset part of iaddr, used for preinc. def iaddroff : ComplexPattern; //===----------------------------------------------------------------------===// // PowerPC Instruction Predicate Definitions. def In32BitMode : Predicate<"!PPCSubTarget->isPPC64()">; def In64BitMode : Predicate<"PPCSubTarget->isPPC64()">; def IsBookE : Predicate<"PPCSubTarget->isBookE()">; def IsNotBookE : Predicate<"!PPCSubTarget->isBookE()">; def HasOnlyMSYNC : Predicate<"PPCSubTarget->hasOnlyMSYNC()">; def HasSYNC : Predicate<"!PPCSubTarget->hasOnlyMSYNC()">; def IsPPC4xx : Predicate<"PPCSubTarget->isPPC4xx()">; def IsPPC6xx : Predicate<"PPCSubTarget->isPPC6xx()">; def IsE500 : Predicate<"PPCSubTarget->isE500()">; def HasSPE : Predicate<"PPCSubTarget->HasSPE()">; def HasICBT : Predicate<"PPCSubTarget->hasICBT()">; def HasPartwordAtomics : Predicate<"PPCSubTarget->hasPartwordAtomics()">; def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">; def NaNsFPMath : Predicate<"!TM.Options.NoNaNsFPMath">; def HasBPERMD : Predicate<"PPCSubTarget->hasBPERMD()">; def HasExtDiv : Predicate<"PPCSubTarget->hasExtDiv()">; def IsISA3_0 : Predicate<"PPCSubTarget->isISA3_0()">; //===----------------------------------------------------------------------===// // PowerPC Multiclass Definitions. multiclass XForm_6r opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XForm_6, RecFormRel; let Defs = [CR0] in def o : XForm_6, isDOT, RecFormRel; } } multiclass XForm_6rc opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { let Defs = [CARRY] in def NAME : XForm_6, RecFormRel; let Defs = [CARRY, CR0] in def o : XForm_6, isDOT, RecFormRel; } } multiclass XForm_10rc opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { let Defs = [CARRY] in def NAME : XForm_10, RecFormRel; let Defs = [CARRY, CR0] in def o : XForm_10, isDOT, RecFormRel; } } multiclass XForm_11r opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XForm_11, RecFormRel; let Defs = [CR0] in def o : XForm_11, isDOT, RecFormRel; } } multiclass XOForm_1r opcode, bits<9> xo, bit oe, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XOForm_1, RecFormRel; let Defs = [CR0] in def o : XOForm_1, isDOT, RecFormRel; } } // Multiclass for instructions for which the non record form is not cracked // and the record form is cracked (i.e. divw, mullw, etc.) multiclass XOForm_1rcr opcode, bits<9> xo, bit oe, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XOForm_1, RecFormRel; let Defs = [CR0] in def o : XOForm_1, isDOT, RecFormRel, PPC970_DGroup_First, PPC970_DGroup_Cracked; } } multiclass XOForm_1rc opcode, bits<9> xo, bit oe, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { let Defs = [CARRY] in def NAME : XOForm_1, RecFormRel; let Defs = [CARRY, CR0] in def o : XOForm_1, isDOT, RecFormRel; } } multiclass XOForm_3r opcode, bits<9> xo, bit oe, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XOForm_3, RecFormRel; let Defs = [CR0] in def o : XOForm_3, isDOT, RecFormRel; } } multiclass XOForm_3rc opcode, bits<9> xo, bit oe, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { let Defs = [CARRY] in def NAME : XOForm_3, RecFormRel; let Defs = [CARRY, CR0] in def o : XOForm_3, isDOT, RecFormRel; } } multiclass MForm_2r opcode, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : MForm_2, RecFormRel; let Defs = [CR0] in def o : MForm_2, isDOT, RecFormRel; } } multiclass MDForm_1r opcode, bits<3> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : MDForm_1, RecFormRel; let Defs = [CR0] in def o : MDForm_1, isDOT, RecFormRel; } } multiclass MDSForm_1r opcode, bits<4> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : MDSForm_1, RecFormRel; let Defs = [CR0] in def o : MDSForm_1, isDOT, RecFormRel; } } multiclass XSForm_1rc opcode, bits<9> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { let Defs = [CARRY] in def NAME : XSForm_1, RecFormRel; let Defs = [CARRY, CR0] in def o : XSForm_1, isDOT, RecFormRel; } } multiclass XForm_26r opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XForm_26, RecFormRel; let Defs = [CR1] in def o : XForm_26, isDOT, RecFormRel; } } multiclass XForm_28r opcode, bits<10> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : XForm_28, RecFormRel; let Defs = [CR1] in def o : XForm_28, isDOT, RecFormRel; } } multiclass AForm_1r opcode, bits<5> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : AForm_1, RecFormRel; let Defs = [CR1] in def o : AForm_1, isDOT, RecFormRel; } } multiclass AForm_2r opcode, bits<5> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : AForm_2, RecFormRel; let Defs = [CR1] in def o : AForm_2, isDOT, RecFormRel; } } multiclass AForm_3r opcode, bits<5> xo, dag OOL, dag IOL, string asmbase, string asmstr, InstrItinClass itin, list pattern> { let BaseName = asmbase in { def NAME : AForm_3, RecFormRel; let Defs = [CR1] in def o : AForm_3, isDOT, RecFormRel; } } //===----------------------------------------------------------------------===// // PowerPC Instruction Definitions. // Pseudo-instructions: let hasCtrlDep = 1 in { let Defs = [R1], Uses = [R1] in { def ADJCALLSTACKDOWN : Pseudo<(outs), (ins u16imm:$amt), "#ADJCALLSTACKDOWN $amt", [(callseq_start timm:$amt)]>; def ADJCALLSTACKUP : Pseudo<(outs), (ins u16imm:$amt1, u16imm:$amt2), "#ADJCALLSTACKUP $amt1 $amt2", [(callseq_end timm:$amt1, timm:$amt2)]>; } def UPDATE_VRSAVE : Pseudo<(outs gprc:$rD), (ins gprc:$rS), "UPDATE_VRSAVE $rD, $rS", []>; } let Defs = [R1], Uses = [R1] in def DYNALLOC : Pseudo<(outs gprc:$result), (ins gprc:$negsize, memri:$fpsi), "#DYNALLOC", [(set i32:$result, (PPCdynalloc i32:$negsize, iaddr:$fpsi))]>; def DYNAREAOFFSET : Pseudo<(outs i32imm:$result), (ins memri:$fpsi), "#DYNAREAOFFSET", [(set i32:$result, (PPCdynareaoffset iaddr:$fpsi))]>; // SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after // instruction selection into a branch sequence. let usesCustomInserter = 1, // Expanded after instruction selection. PPC970_Single = 1 in { // Note that SELECT_CC_I4 and SELECT_CC_I8 use the no-r0 register classes // because either operand might become the first operand in an isel, and // that operand cannot be r0. def SELECT_CC_I4 : Pseudo<(outs gprc:$dst), (ins crrc:$cond, gprc_nor0:$T, gprc_nor0:$F, i32imm:$BROPC), "#SELECT_CC_I4", []>; def SELECT_CC_I8 : Pseudo<(outs g8rc:$dst), (ins crrc:$cond, g8rc_nox0:$T, g8rc_nox0:$F, i32imm:$BROPC), "#SELECT_CC_I8", []>; def SELECT_CC_F4 : Pseudo<(outs f4rc:$dst), (ins crrc:$cond, f4rc:$T, f4rc:$F, i32imm:$BROPC), "#SELECT_CC_F4", []>; def SELECT_CC_F8 : Pseudo<(outs f8rc:$dst), (ins crrc:$cond, f8rc:$T, f8rc:$F, i32imm:$BROPC), "#SELECT_CC_F8", []>; def SELECT_CC_VRRC: Pseudo<(outs vrrc:$dst), (ins crrc:$cond, vrrc:$T, vrrc:$F, i32imm:$BROPC), "#SELECT_CC_VRRC", []>; // SELECT_* pseudo instructions, like SELECT_CC_* but taking condition // register bit directly. def SELECT_I4 : Pseudo<(outs gprc:$dst), (ins crbitrc:$cond, gprc_nor0:$T, gprc_nor0:$F), "#SELECT_I4", [(set i32:$dst, (select i1:$cond, i32:$T, i32:$F))]>; def SELECT_I8 : Pseudo<(outs g8rc:$dst), (ins crbitrc:$cond, g8rc_nox0:$T, g8rc_nox0:$F), "#SELECT_I8", [(set i64:$dst, (select i1:$cond, i64:$T, i64:$F))]>; def SELECT_F4 : Pseudo<(outs f4rc:$dst), (ins crbitrc:$cond, f4rc:$T, f4rc:$F), "#SELECT_F4", [(set f32:$dst, (select i1:$cond, f32:$T, f32:$F))]>; def SELECT_F8 : Pseudo<(outs f8rc:$dst), (ins crbitrc:$cond, f8rc:$T, f8rc:$F), "#SELECT_F8", [(set f64:$dst, (select i1:$cond, f64:$T, f64:$F))]>; def SELECT_VRRC: Pseudo<(outs vrrc:$dst), (ins crbitrc:$cond, vrrc:$T, vrrc:$F), "#SELECT_VRRC", [(set v4i32:$dst, (select i1:$cond, v4i32:$T, v4i32:$F))]>; } // SPILL_CR - Indicate that we're dumping the CR register, so we'll need to // scavenge a register for it. let mayStore = 1 in { def SPILL_CR : Pseudo<(outs), (ins crrc:$cond, memri:$F), "#SPILL_CR", []>; def SPILL_CRBIT : Pseudo<(outs), (ins crbitrc:$cond, memri:$F), "#SPILL_CRBIT", []>; } // RESTORE_CR - Indicate that we're restoring the CR register (previously // spilled), so we'll need to scavenge a register for it. let mayLoad = 1 in { def RESTORE_CR : Pseudo<(outs crrc:$cond), (ins memri:$F), "#RESTORE_CR", []>; def RESTORE_CRBIT : Pseudo<(outs crbitrc:$cond), (ins memri:$F), "#RESTORE_CRBIT", []>; } let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7 in { let isReturn = 1, Uses = [LR, RM] in def BLR : XLForm_2_ext<19, 16, 20, 0, 0, (outs), (ins), "blr", IIC_BrB, [(retflag)]>, Requires<[In32BitMode]>; let isBranch = 1, isIndirectBranch = 1, Uses = [CTR] in { def BCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", IIC_BrB, []>; let isCodeGenOnly = 1 in { def BCCCTR : XLForm_2_br<19, 528, 0, (outs), (ins pred:$cond), "b${cond:cc}ctr${cond:pm} ${cond:reg}", IIC_BrB, []>; def BCCTR : XLForm_2_br2<19, 528, 12, 0, (outs), (ins crbitrc:$bi), "bcctr 12, $bi, 0", IIC_BrB, []>; def BCCTRn : XLForm_2_br2<19, 528, 4, 0, (outs), (ins crbitrc:$bi), "bcctr 4, $bi, 0", IIC_BrB, []>; } } } let Defs = [LR] in def MovePCtoLR : Pseudo<(outs), (ins), "#MovePCtoLR", []>, PPC970_Unit_BRU; let Defs = [LR] in def MoveGOTtoLR : Pseudo<(outs), (ins), "#MoveGOTtoLR", []>, PPC970_Unit_BRU; let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7 in { let isBarrier = 1 in { def B : IForm<18, 0, 0, (outs), (ins directbrtarget:$dst), "b $dst", IIC_BrB, [(br bb:$dst)]>; def BA : IForm<18, 1, 0, (outs), (ins absdirectbrtarget:$dst), "ba $dst", IIC_BrB, []>; } // BCC represents an arbitrary conditional branch on a predicate. // FIXME: should be able to write a pattern for PPCcondbranch, but can't use // a two-value operand where a dag node expects two operands. :( let isCodeGenOnly = 1 in { def BCC : BForm<16, 0, 0, (outs), (ins pred:$cond, condbrtarget:$dst), "b${cond:cc}${cond:pm} ${cond:reg}, $dst" /*[(PPCcondbranch crrc:$crS, imm:$opc, bb:$dst)]*/>; def BCCA : BForm<16, 1, 0, (outs), (ins pred:$cond, abscondbrtarget:$dst), "b${cond:cc}a${cond:pm} ${cond:reg}, $dst">; let isReturn = 1, Uses = [LR, RM] in def BCCLR : XLForm_2_br<19, 16, 0, (outs), (ins pred:$cond), "b${cond:cc}lr${cond:pm} ${cond:reg}", IIC_BrB, []>; } let isCodeGenOnly = 1 in { let Pattern = [(brcond i1:$bi, bb:$dst)] in def BC : BForm_4<16, 12, 0, 0, (outs), (ins crbitrc:$bi, condbrtarget:$dst), "bc 12, $bi, $dst">; let Pattern = [(brcond (not i1:$bi), bb:$dst)] in def BCn : BForm_4<16, 4, 0, 0, (outs), (ins crbitrc:$bi, condbrtarget:$dst), "bc 4, $bi, $dst">; let isReturn = 1, Uses = [LR, RM] in def BCLR : XLForm_2_br2<19, 16, 12, 0, (outs), (ins crbitrc:$bi), "bclr 12, $bi, 0", IIC_BrB, []>; def BCLRn : XLForm_2_br2<19, 16, 4, 0, (outs), (ins crbitrc:$bi), "bclr 4, $bi, 0", IIC_BrB, []>; } let isReturn = 1, Defs = [CTR], Uses = [CTR, LR, RM] in { def BDZLR : XLForm_2_ext<19, 16, 18, 0, 0, (outs), (ins), "bdzlr", IIC_BrB, []>; def BDNZLR : XLForm_2_ext<19, 16, 16, 0, 0, (outs), (ins), "bdnzlr", IIC_BrB, []>; def BDZLRp : XLForm_2_ext<19, 16, 27, 0, 0, (outs), (ins), "bdzlr+", IIC_BrB, []>; def BDNZLRp: XLForm_2_ext<19, 16, 25, 0, 0, (outs), (ins), "bdnzlr+", IIC_BrB, []>; def BDZLRm : XLForm_2_ext<19, 16, 26, 0, 0, (outs), (ins), "bdzlr-", IIC_BrB, []>; def BDNZLRm: XLForm_2_ext<19, 16, 24, 0, 0, (outs), (ins), "bdnzlr-", IIC_BrB, []>; } let Defs = [CTR], Uses = [CTR] in { def BDZ : BForm_1<16, 18, 0, 0, (outs), (ins condbrtarget:$dst), "bdz $dst">; def BDNZ : BForm_1<16, 16, 0, 0, (outs), (ins condbrtarget:$dst), "bdnz $dst">; def BDZA : BForm_1<16, 18, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdza $dst">; def BDNZA : BForm_1<16, 16, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdnza $dst">; def BDZp : BForm_1<16, 27, 0, 0, (outs), (ins condbrtarget:$dst), "bdz+ $dst">; def BDNZp: BForm_1<16, 25, 0, 0, (outs), (ins condbrtarget:$dst), "bdnz+ $dst">; def BDZAp : BForm_1<16, 27, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdza+ $dst">; def BDNZAp: BForm_1<16, 25, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdnza+ $dst">; def BDZm : BForm_1<16, 26, 0, 0, (outs), (ins condbrtarget:$dst), "bdz- $dst">; def BDNZm: BForm_1<16, 24, 0, 0, (outs), (ins condbrtarget:$dst), "bdnz- $dst">; def BDZAm : BForm_1<16, 26, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdza- $dst">; def BDNZAm: BForm_1<16, 24, 1, 0, (outs), (ins abscondbrtarget:$dst), "bdnza- $dst">; } } // The unconditional BCL used by the SjLj setjmp code. let isCall = 1, hasCtrlDep = 1, isCodeGenOnly = 1, PPC970_Unit = 7 in { let Defs = [LR], Uses = [RM] in { def BCLalways : BForm_2<16, 20, 31, 0, 1, (outs), (ins condbrtarget:$dst), "bcl 20, 31, $dst">; } } let isCall = 1, PPC970_Unit = 7, Defs = [LR] in { // Convenient aliases for call instructions let Uses = [RM] in { def BL : IForm<18, 0, 1, (outs), (ins calltarget:$func), "bl $func", IIC_BrB, []>; // See Pat patterns below. def BLA : IForm<18, 1, 1, (outs), (ins abscalltarget:$func), "bla $func", IIC_BrB, [(PPCcall (i32 imm:$func))]>; let isCodeGenOnly = 1 in { def BL_TLS : IForm<18, 0, 1, (outs), (ins tlscall32:$func), "bl $func", IIC_BrB, []>; def BCCL : BForm<16, 0, 1, (outs), (ins pred:$cond, condbrtarget:$dst), "b${cond:cc}l${cond:pm} ${cond:reg}, $dst">; def BCCLA : BForm<16, 1, 1, (outs), (ins pred:$cond, abscondbrtarget:$dst), "b${cond:cc}la${cond:pm} ${cond:reg}, $dst">; def BCL : BForm_4<16, 12, 0, 1, (outs), (ins crbitrc:$bi, condbrtarget:$dst), "bcl 12, $bi, $dst">; def BCLn : BForm_4<16, 4, 0, 1, (outs), (ins crbitrc:$bi, condbrtarget:$dst), "bcl 4, $bi, $dst">; } } let Uses = [CTR, RM] in { def BCTRL : XLForm_2_ext<19, 528, 20, 0, 1, (outs), (ins), "bctrl", IIC_BrB, [(PPCbctrl)]>, Requires<[In32BitMode]>; let isCodeGenOnly = 1 in { def BCCCTRL : XLForm_2_br<19, 528, 1, (outs), (ins pred:$cond), "b${cond:cc}ctrl${cond:pm} ${cond:reg}", IIC_BrB, []>; def BCCTRL : XLForm_2_br2<19, 528, 12, 1, (outs), (ins crbitrc:$bi), "bcctrl 12, $bi, 0", IIC_BrB, []>; def BCCTRLn : XLForm_2_br2<19, 528, 4, 1, (outs), (ins crbitrc:$bi), "bcctrl 4, $bi, 0", IIC_BrB, []>; } } let Uses = [LR, RM] in { def BLRL : XLForm_2_ext<19, 16, 20, 0, 1, (outs), (ins), "blrl", IIC_BrB, []>; let isCodeGenOnly = 1 in { def BCCLRL : XLForm_2_br<19, 16, 1, (outs), (ins pred:$cond), "b${cond:cc}lrl${cond:pm} ${cond:reg}", IIC_BrB, []>; def BCLRL : XLForm_2_br2<19, 16, 12, 1, (outs), (ins crbitrc:$bi), "bclrl 12, $bi, 0", IIC_BrB, []>; def BCLRLn : XLForm_2_br2<19, 16, 4, 1, (outs), (ins crbitrc:$bi), "bclrl 4, $bi, 0", IIC_BrB, []>; } } let Defs = [CTR], Uses = [CTR, RM] in { def BDZL : BForm_1<16, 18, 0, 1, (outs), (ins condbrtarget:$dst), "bdzl $dst">; def BDNZL : BForm_1<16, 16, 0, 1, (outs), (ins condbrtarget:$dst), "bdnzl $dst">; def BDZLA : BForm_1<16, 18, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdzla $dst">; def BDNZLA : BForm_1<16, 16, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdnzla $dst">; def BDZLp : BForm_1<16, 27, 0, 1, (outs), (ins condbrtarget:$dst), "bdzl+ $dst">; def BDNZLp: BForm_1<16, 25, 0, 1, (outs), (ins condbrtarget:$dst), "bdnzl+ $dst">; def BDZLAp : BForm_1<16, 27, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdzla+ $dst">; def BDNZLAp: BForm_1<16, 25, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdnzla+ $dst">; def BDZLm : BForm_1<16, 26, 0, 1, (outs), (ins condbrtarget:$dst), "bdzl- $dst">; def BDNZLm: BForm_1<16, 24, 0, 1, (outs), (ins condbrtarget:$dst), "bdnzl- $dst">; def BDZLAm : BForm_1<16, 26, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdzla- $dst">; def BDNZLAm: BForm_1<16, 24, 1, 1, (outs), (ins abscondbrtarget:$dst), "bdnzla- $dst">; } let Defs = [CTR], Uses = [CTR, LR, RM] in { def BDZLRL : XLForm_2_ext<19, 16, 18, 0, 1, (outs), (ins), "bdzlrl", IIC_BrB, []>; def BDNZLRL : XLForm_2_ext<19, 16, 16, 0, 1, (outs), (ins), "bdnzlrl", IIC_BrB, []>; def BDZLRLp : XLForm_2_ext<19, 16, 27, 0, 1, (outs), (ins), "bdzlrl+", IIC_BrB, []>; def BDNZLRLp: XLForm_2_ext<19, 16, 25, 0, 1, (outs), (ins), "bdnzlrl+", IIC_BrB, []>; def BDZLRLm : XLForm_2_ext<19, 16, 26, 0, 1, (outs), (ins), "bdzlrl-", IIC_BrB, []>; def BDNZLRLm: XLForm_2_ext<19, 16, 24, 0, 1, (outs), (ins), "bdnzlrl-", IIC_BrB, []>; } } let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in def TCRETURNdi :Pseudo< (outs), (ins calltarget:$dst, i32imm:$offset), "#TC_RETURNd $dst $offset", []>; let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in def TCRETURNai :Pseudo<(outs), (ins abscalltarget:$func, i32imm:$offset), "#TC_RETURNa $func $offset", [(PPCtc_return (i32 imm:$func), imm:$offset)]>; let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in def TCRETURNri : Pseudo<(outs), (ins CTRRC:$dst, i32imm:$offset), "#TC_RETURNr $dst $offset", []>; let isCodeGenOnly = 1 in { let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7, isBranch = 1, isIndirectBranch = 1, isCall = 1, isReturn = 1, Uses = [CTR, RM] in def TAILBCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", IIC_BrB, []>, Requires<[In32BitMode]>; let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7, isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in def TAILB : IForm<18, 0, 0, (outs), (ins calltarget:$dst), "b $dst", IIC_BrB, []>; let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7, isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in def TAILBA : IForm<18, 0, 0, (outs), (ins abscalltarget:$dst), "ba $dst", IIC_BrB, []>; } let hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1 in { let Defs = [CTR] in def EH_SjLj_SetJmp32 : Pseudo<(outs gprc:$dst), (ins memr:$buf), "#EH_SJLJ_SETJMP32", [(set i32:$dst, (PPCeh_sjlj_setjmp addr:$buf))]>, Requires<[In32BitMode]>; let isTerminator = 1 in def EH_SjLj_LongJmp32 : Pseudo<(outs), (ins memr:$buf), "#EH_SJLJ_LONGJMP32", [(PPCeh_sjlj_longjmp addr:$buf)]>, Requires<[In32BitMode]>; } // This pseudo is never removed from the function, as it serves as // a terminator. Size is set to 0 to prevent the builtin assembler // from emitting it. let isBranch = 1, isTerminator = 1, Size = 0 in { def EH_SjLj_Setup : Pseudo<(outs), (ins directbrtarget:$dst), "#EH_SjLj_Setup\t$dst", []>; } // System call. let PPC970_Unit = 7 in { def SC : SCForm<17, 1, (outs), (ins i32imm:$lev), "sc $lev", IIC_BrB, [(PPCsc (i32 imm:$lev))]>; } // Branch history rolling buffer. def CLRBHRB : XForm_0<31, 430, (outs), (ins), "clrbhrb", IIC_BrB, [(PPCclrbhrb)]>, PPC970_DGroup_Single; // The $dmy argument used for MFBHRBE is not needed; however, including // it avoids automatic generation of PPCFastISel::fastEmit_i(), which // interferes with necessary special handling (see PPCFastISel.cpp). def MFBHRBE : XFXForm_3p<31, 302, (outs gprc:$rD), (ins u10imm:$imm, u10imm:$dmy), "mfbhrbe $rD, $imm", IIC_BrB, [(set i32:$rD, (PPCmfbhrbe imm:$imm, imm:$dmy))]>, PPC970_DGroup_First; def RFEBB : XLForm_S<19, 146, (outs), (ins u1imm:$imm), "rfebb $imm", IIC_BrB, [(PPCrfebb (i32 imm:$imm))]>, PPC970_DGroup_Single; // DCB* instructions. def DCBA : DCB_Form<758, 0, (outs), (ins memrr:$dst), "dcba $dst", IIC_LdStDCBF, [(int_ppc_dcba xoaddr:$dst)]>, PPC970_DGroup_Single; def DCBI : DCB_Form<470, 0, (outs), (ins memrr:$dst), "dcbi $dst", IIC_LdStDCBF, [(int_ppc_dcbi xoaddr:$dst)]>, PPC970_DGroup_Single; def DCBST : DCB_Form<54, 0, (outs), (ins memrr:$dst), "dcbst $dst", IIC_LdStDCBF, [(int_ppc_dcbst xoaddr:$dst)]>, PPC970_DGroup_Single; def DCBZ : DCB_Form<1014, 0, (outs), (ins memrr:$dst), "dcbz $dst", IIC_LdStDCBF, [(int_ppc_dcbz xoaddr:$dst)]>, PPC970_DGroup_Single; def DCBZL : DCB_Form<1014, 1, (outs), (ins memrr:$dst), "dcbzl $dst", IIC_LdStDCBF, [(int_ppc_dcbzl xoaddr:$dst)]>, PPC970_DGroup_Single; def DCBF : DCB_Form_hint<86, (outs), (ins u5imm:$TH, memrr:$dst), "dcbf $dst, $TH", IIC_LdStDCBF, []>, PPC970_DGroup_Single; let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in { def DCBT : DCB_Form_hint<278, (outs), (ins u5imm:$TH, memrr:$dst), "dcbt $dst, $TH", IIC_LdStDCBF, []>, PPC970_DGroup_Single; def DCBTST : DCB_Form_hint<246, (outs), (ins u5imm:$TH, memrr:$dst), "dcbtst $dst, $TH", IIC_LdStDCBF, []>, PPC970_DGroup_Single; } // hasSideEffects = 0 +def ICBLC : XForm_icbt<31, 230, (outs), (ins u4imm:$CT, memrr:$src), + "icblc $CT, $src", IIC_LdStStore>, Requires<[HasICBT]>; +def ICBLQ : XForm_icbt<31, 198, (outs), (ins u4imm:$CT, memrr:$src), + "icblq. $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>; def ICBT : XForm_icbt<31, 22, (outs), (ins u4imm:$CT, memrr:$src), "icbt $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>; +def ICBTLS : XForm_icbt<31, 486, (outs), (ins u4imm:$CT, memrr:$src), + "icbtls $CT, $src", IIC_LdStLoad>, Requires<[HasICBT]>; def : Pat<(int_ppc_dcbt xoaddr:$dst), (DCBT 0, xoaddr:$dst)>; def : Pat<(int_ppc_dcbtst xoaddr:$dst), (DCBTST 0, xoaddr:$dst)>; def : Pat<(int_ppc_dcbf xoaddr:$dst), (DCBF 0, xoaddr:$dst)>; def : Pat<(prefetch xoaddr:$dst, (i32 0), imm, (i32 1)), (DCBT 0, xoaddr:$dst)>; // data prefetch for loads def : Pat<(prefetch xoaddr:$dst, (i32 1), imm, (i32 1)), (DCBTST 0, xoaddr:$dst)>; // data prefetch for stores def : Pat<(prefetch xoaddr:$dst, (i32 0), imm, (i32 0)), (ICBT 0, xoaddr:$dst)>, Requires<[HasICBT]>; // inst prefetch (for read) // Atomic operations let usesCustomInserter = 1 in { let Defs = [CR0] in { def ATOMIC_LOAD_ADD_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I8", [(set i32:$dst, (atomic_load_add_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_SUB_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I8", [(set i32:$dst, (atomic_load_sub_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_AND_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I8", [(set i32:$dst, (atomic_load_and_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_OR_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I8", [(set i32:$dst, (atomic_load_or_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_XOR_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "ATOMIC_LOAD_XOR_I8", [(set i32:$dst, (atomic_load_xor_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_NAND_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I8", [(set i32:$dst, (atomic_load_nand_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MIN_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I8", [(set i32:$dst, (atomic_load_min_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MAX_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I8", [(set i32:$dst, (atomic_load_max_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMIN_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I8", [(set i32:$dst, (atomic_load_umin_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMAX_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I8", [(set i32:$dst, (atomic_load_umax_8 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_ADD_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I16", [(set i32:$dst, (atomic_load_add_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_SUB_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I16", [(set i32:$dst, (atomic_load_sub_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_AND_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I16", [(set i32:$dst, (atomic_load_and_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_OR_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I16", [(set i32:$dst, (atomic_load_or_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_XOR_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_XOR_I16", [(set i32:$dst, (atomic_load_xor_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_NAND_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I16", [(set i32:$dst, (atomic_load_nand_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MIN_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I16", [(set i32:$dst, (atomic_load_min_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MAX_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I16", [(set i32:$dst, (atomic_load_max_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMIN_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I16", [(set i32:$dst, (atomic_load_umin_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMAX_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I16", [(set i32:$dst, (atomic_load_umax_16 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_ADD_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_ADD_I32", [(set i32:$dst, (atomic_load_add_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_SUB_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_SUB_I32", [(set i32:$dst, (atomic_load_sub_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_AND_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_AND_I32", [(set i32:$dst, (atomic_load_and_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_OR_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_OR_I32", [(set i32:$dst, (atomic_load_or_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_XOR_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_XOR_I32", [(set i32:$dst, (atomic_load_xor_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_NAND_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_NAND_I32", [(set i32:$dst, (atomic_load_nand_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MIN_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MIN_I32", [(set i32:$dst, (atomic_load_min_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_MAX_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_MAX_I32", [(set i32:$dst, (atomic_load_max_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMIN_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMIN_I32", [(set i32:$dst, (atomic_load_umin_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_LOAD_UMAX_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$incr), "#ATOMIC_LOAD_UMAX_I32", [(set i32:$dst, (atomic_load_umax_32 xoaddr:$ptr, i32:$incr))]>; def ATOMIC_CMP_SWAP_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I8", [(set i32:$dst, (atomic_cmp_swap_8 xoaddr:$ptr, i32:$old, i32:$new))]>; def ATOMIC_CMP_SWAP_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I16 $dst $ptr $old $new", [(set i32:$dst, (atomic_cmp_swap_16 xoaddr:$ptr, i32:$old, i32:$new))]>; def ATOMIC_CMP_SWAP_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$old, gprc:$new), "#ATOMIC_CMP_SWAP_I32 $dst $ptr $old $new", [(set i32:$dst, (atomic_cmp_swap_32 xoaddr:$ptr, i32:$old, i32:$new))]>; def ATOMIC_SWAP_I8 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_i8", [(set i32:$dst, (atomic_swap_8 xoaddr:$ptr, i32:$new))]>; def ATOMIC_SWAP_I16 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_I16", [(set i32:$dst, (atomic_swap_16 xoaddr:$ptr, i32:$new))]>; def ATOMIC_SWAP_I32 : Pseudo< (outs gprc:$dst), (ins memrr:$ptr, gprc:$new), "#ATOMIC_SWAP_I32", [(set i32:$dst, (atomic_swap_32 xoaddr:$ptr, i32:$new))]>; } } // Instructions to support atomic operations let mayLoad = 1, hasSideEffects = 0 in { def LBARX : XForm_1<31, 52, (outs gprc:$rD), (ins memrr:$src), "lbarx $rD, $src", IIC_LdStLWARX, []>, Requires<[HasPartwordAtomics]>; def LHARX : XForm_1<31, 116, (outs gprc:$rD), (ins memrr:$src), "lharx $rD, $src", IIC_LdStLWARX, []>, Requires<[HasPartwordAtomics]>; def LWARX : XForm_1<31, 20, (outs gprc:$rD), (ins memrr:$src), "lwarx $rD, $src", IIC_LdStLWARX, []>; // Instructions to support lock versions of atomics // (EH=1 - see Power ISA 2.07 Book II 4.4.2) def LBARXL : XForm_1<31, 52, (outs gprc:$rD), (ins memrr:$src), "lbarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT, Requires<[HasPartwordAtomics]>; def LHARXL : XForm_1<31, 116, (outs gprc:$rD), (ins memrr:$src), "lharx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT, Requires<[HasPartwordAtomics]>; def LWARXL : XForm_1<31, 20, (outs gprc:$rD), (ins memrr:$src), "lwarx $rD, $src, 1", IIC_LdStLWARX, []>, isDOT; // The atomic instructions use the destination register as well as the next one // or two registers in order (modulo 31). let hasExtraSrcRegAllocReq = 1 in def LWAT : X_RD5_RS5_IM5<31, 582, (outs gprc:$rD), (ins gprc:$rA, u5imm:$FC), "lwat $rD, $rA, $FC", IIC_LdStLoad>, Requires<[IsISA3_0]>; } let Defs = [CR0], mayStore = 1, hasSideEffects = 0 in { def STBCX : XForm_1<31, 694, (outs), (ins gprc:$rS, memrr:$dst), "stbcx. $rS, $dst", IIC_LdStSTWCX, []>, isDOT, Requires<[HasPartwordAtomics]>; def STHCX : XForm_1<31, 726, (outs), (ins gprc:$rS, memrr:$dst), "sthcx. $rS, $dst", IIC_LdStSTWCX, []>, isDOT, Requires<[HasPartwordAtomics]>; def STWCX : XForm_1<31, 150, (outs), (ins gprc:$rS, memrr:$dst), "stwcx. $rS, $dst", IIC_LdStSTWCX, []>, isDOT; } let mayStore = 1, hasSideEffects = 0 in def STWAT : X_RD5_RS5_IM5<31, 710, (outs), (ins gprc:$rS, gprc:$rA, u5imm:$FC), "stwat $rS, $rA, $FC", IIC_LdStStore>, Requires<[IsISA3_0]>; let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in def TRAP : XForm_24<31, 4, (outs), (ins), "trap", IIC_LdStLoad, [(trap)]>; def TWI : DForm_base<3, (outs), (ins u5imm:$to, gprc:$rA, s16imm:$imm), "twi $to, $rA, $imm", IIC_IntTrapW, []>; def TW : XForm_1<31, 4, (outs), (ins u5imm:$to, gprc:$rA, gprc:$rB), "tw $to, $rA, $rB", IIC_IntTrapW, []>; def TDI : DForm_base<2, (outs), (ins u5imm:$to, g8rc:$rA, s16imm:$imm), "tdi $to, $rA, $imm", IIC_IntTrapD, []>; def TD : XForm_1<31, 68, (outs), (ins u5imm:$to, g8rc:$rA, g8rc:$rB), "td $to, $rA, $rB", IIC_IntTrapD, []>; //===----------------------------------------------------------------------===// // PPC32 Load Instructions. // // Unindexed (r+i) Loads. let PPC970_Unit = 2 in { def LBZ : DForm_1<34, (outs gprc:$rD), (ins memri:$src), "lbz $rD, $src", IIC_LdStLoad, [(set i32:$rD, (zextloadi8 iaddr:$src))]>; def LHA : DForm_1<42, (outs gprc:$rD), (ins memri:$src), "lha $rD, $src", IIC_LdStLHA, [(set i32:$rD, (sextloadi16 iaddr:$src))]>, PPC970_DGroup_Cracked; def LHZ : DForm_1<40, (outs gprc:$rD), (ins memri:$src), "lhz $rD, $src", IIC_LdStLoad, [(set i32:$rD, (zextloadi16 iaddr:$src))]>; def LWZ : DForm_1<32, (outs gprc:$rD), (ins memri:$src), "lwz $rD, $src", IIC_LdStLoad, [(set i32:$rD, (load iaddr:$src))]>; def LFS : DForm_1<48, (outs f4rc:$rD), (ins memri:$src), "lfs $rD, $src", IIC_LdStLFD, [(set f32:$rD, (load iaddr:$src))]>; def LFD : DForm_1<50, (outs f8rc:$rD), (ins memri:$src), "lfd $rD, $src", IIC_LdStLFD, [(set f64:$rD, (load iaddr:$src))]>; // Unindexed (r+i) Loads with Update (preinc). let mayLoad = 1, hasSideEffects = 0 in { def LBZU : DForm_1<35, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lbzu $rD, $addr", IIC_LdStLoadUpd, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; def LHAU : DForm_1<43, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lhau $rD, $addr", IIC_LdStLHAU, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; def LHZU : DForm_1<41, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lhzu $rD, $addr", IIC_LdStLoadUpd, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; def LWZU : DForm_1<33, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lwzu $rD, $addr", IIC_LdStLoadUpd, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; def LFSU : DForm_1<49, (outs f4rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lfsu $rD, $addr", IIC_LdStLFDU, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; def LFDU : DForm_1<51, (outs f8rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr), "lfdu $rD, $addr", IIC_LdStLFDU, []>, RegConstraint<"$addr.reg = $ea_result">, NoEncode<"$ea_result">; // Indexed (r+r) Loads with Update (preinc). def LBZUX : XForm_1<31, 119, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lbzux $rD, $addr", IIC_LdStLoadUpdX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; def LHAUX : XForm_1<31, 375, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lhaux $rD, $addr", IIC_LdStLHAUX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; def LHZUX : XForm_1<31, 311, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lhzux $rD, $addr", IIC_LdStLoadUpdX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; def LWZUX : XForm_1<31, 55, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lwzux $rD, $addr", IIC_LdStLoadUpdX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; def LFSUX : XForm_1<31, 567, (outs f4rc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lfsux $rD, $addr", IIC_LdStLFDUX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; def LFDUX : XForm_1<31, 631, (outs f8rc:$rD, ptr_rc_nor0:$ea_result), (ins memrr:$addr), "lfdux $rD, $addr", IIC_LdStLFDUX, []>, RegConstraint<"$addr.ptrreg = $ea_result">, NoEncode<"$ea_result">; } } // Indexed (r+r) Loads. // let PPC970_Unit = 2 in { def LBZX : XForm_1<31, 87, (outs gprc:$rD), (ins memrr:$src), "lbzx $rD, $src", IIC_LdStLoad, [(set i32:$rD, (zextloadi8 xaddr:$src))]>; def LHAX : XForm_1<31, 343, (outs gprc:$rD), (ins memrr:$src), "lhax $rD, $src", IIC_LdStLHA, [(set i32:$rD, (sextloadi16 xaddr:$src))]>, PPC970_DGroup_Cracked; def LHZX : XForm_1<31, 279, (outs gprc:$rD), (ins memrr:$src), "lhzx $rD, $src", IIC_LdStLoad, [(set i32:$rD, (zextloadi16 xaddr:$src))]>; def LWZX : XForm_1<31, 23, (outs gprc:$rD), (ins memrr:$src), "lwzx $rD, $src", IIC_LdStLoad, [(set i32:$rD, (load xaddr:$src))]>; def LHBRX : XForm_1<31, 790, (outs gprc:$rD), (ins memrr:$src), "lhbrx $rD, $src", IIC_LdStLoad, [(set i32:$rD, (PPClbrx xoaddr:$src, i16))]>; def LWBRX : XForm_1<31, 534, (outs gprc:$rD), (ins memrr:$src), "lwbrx $rD, $src", IIC_LdStLoad, [(set i32:$rD, (PPClbrx xoaddr:$src, i32))]>; def LFSX : XForm_25<31, 535, (outs f4rc:$frD), (ins memrr:$src), "lfsx $frD, $src", IIC_LdStLFD, [(set f32:$frD, (load xaddr:$src))]>; def LFDX : XForm_25<31, 599, (outs f8rc:$frD), (ins memrr:$src), "lfdx $frD, $src", IIC_LdStLFD, [(set f64:$frD, (load xaddr:$src))]>; def LFIWAX : XForm_25<31, 855, (outs f8rc:$frD), (ins memrr:$src), "lfiwax $frD, $src", IIC_LdStLFD, [(set f64:$frD, (PPClfiwax xoaddr:$src))]>; def LFIWZX : XForm_25<31, 887, (outs f8rc:$frD), (ins memrr:$src), "lfiwzx $frD, $src", IIC_LdStLFD, [(set f64:$frD, (PPClfiwzx xoaddr:$src))]>; } // Load Multiple def LMW : DForm_1<46, (outs gprc:$rD), (ins memri:$src), "lmw $rD, $src", IIC_LdStLMW, []>; //===----------------------------------------------------------------------===// // PPC32 Store Instructions. // // Unindexed (r+i) Stores. let PPC970_Unit = 2 in { def STB : DForm_1<38, (outs), (ins gprc:$rS, memri:$src), "stb $rS, $src", IIC_LdStStore, [(truncstorei8 i32:$rS, iaddr:$src)]>; def STH : DForm_1<44, (outs), (ins gprc:$rS, memri:$src), "sth $rS, $src", IIC_LdStStore, [(truncstorei16 i32:$rS, iaddr:$src)]>; def STW : DForm_1<36, (outs), (ins gprc:$rS, memri:$src), "stw $rS, $src", IIC_LdStStore, [(store i32:$rS, iaddr:$src)]>; def STFS : DForm_1<52, (outs), (ins f4rc:$rS, memri:$dst), "stfs $rS, $dst", IIC_LdStSTFD, [(store f32:$rS, iaddr:$dst)]>; def STFD : DForm_1<54, (outs), (ins f8rc:$rS, memri:$dst), "stfd $rS, $dst", IIC_LdStSTFD, [(store f64:$rS, iaddr:$dst)]>; } // Unindexed (r+i) Stores with Update (preinc). let PPC970_Unit = 2, mayStore = 1 in { def STBU : DForm_1<39, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst), "stbu $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">; def STHU : DForm_1<45, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst), "sthu $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">; def STWU : DForm_1<37, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst), "stwu $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">; def STFSU : DForm_1<53, (outs ptr_rc_nor0:$ea_res), (ins f4rc:$rS, memri:$dst), "stfsu $rS, $dst", IIC_LdStSTFDU, []>, RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">; def STFDU : DForm_1<55, (outs ptr_rc_nor0:$ea_res), (ins f8rc:$rS, memri:$dst), "stfdu $rS, $dst", IIC_LdStSTFDU, []>, RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">; } // Patterns to match the pre-inc stores. We can't put the patterns on // the instruction definitions directly as ISel wants the address base // and offset to be separate operands, not a single complex operand. def : Pat<(pre_truncsti8 i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STBU $rS, iaddroff:$ptroff, $ptrreg)>; def : Pat<(pre_truncsti16 i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STHU $rS, iaddroff:$ptroff, $ptrreg)>; def : Pat<(pre_store i32:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STWU $rS, iaddroff:$ptroff, $ptrreg)>; def : Pat<(pre_store f32:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STFSU $rS, iaddroff:$ptroff, $ptrreg)>; def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iaddroff:$ptroff), (STFDU $rS, iaddroff:$ptroff, $ptrreg)>; // Indexed (r+r) Stores. let PPC970_Unit = 2 in { def STBX : XForm_8<31, 215, (outs), (ins gprc:$rS, memrr:$dst), "stbx $rS, $dst", IIC_LdStStore, [(truncstorei8 i32:$rS, xaddr:$dst)]>, PPC970_DGroup_Cracked; def STHX : XForm_8<31, 407, (outs), (ins gprc:$rS, memrr:$dst), "sthx $rS, $dst", IIC_LdStStore, [(truncstorei16 i32:$rS, xaddr:$dst)]>, PPC970_DGroup_Cracked; def STWX : XForm_8<31, 151, (outs), (ins gprc:$rS, memrr:$dst), "stwx $rS, $dst", IIC_LdStStore, [(store i32:$rS, xaddr:$dst)]>, PPC970_DGroup_Cracked; def STHBRX: XForm_8<31, 918, (outs), (ins gprc:$rS, memrr:$dst), "sthbrx $rS, $dst", IIC_LdStStore, [(PPCstbrx i32:$rS, xoaddr:$dst, i16)]>, PPC970_DGroup_Cracked; def STWBRX: XForm_8<31, 662, (outs), (ins gprc:$rS, memrr:$dst), "stwbrx $rS, $dst", IIC_LdStStore, [(PPCstbrx i32:$rS, xoaddr:$dst, i32)]>, PPC970_DGroup_Cracked; def STFIWX: XForm_28<31, 983, (outs), (ins f8rc:$frS, memrr:$dst), "stfiwx $frS, $dst", IIC_LdStSTFD, [(PPCstfiwx f64:$frS, xoaddr:$dst)]>; def STFSX : XForm_28<31, 663, (outs), (ins f4rc:$frS, memrr:$dst), "stfsx $frS, $dst", IIC_LdStSTFD, [(store f32:$frS, xaddr:$dst)]>; def STFDX : XForm_28<31, 727, (outs), (ins f8rc:$frS, memrr:$dst), "stfdx $frS, $dst", IIC_LdStSTFD, [(store f64:$frS, xaddr:$dst)]>; } // Indexed (r+r) Stores with Update (preinc). let PPC970_Unit = 2, mayStore = 1 in { def STBUX : XForm_8<31, 247, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memrr:$dst), "stbux $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.ptrreg = $ea_res">, NoEncode<"$ea_res">, PPC970_DGroup_Cracked; def STHUX : XForm_8<31, 439, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memrr:$dst), "sthux $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.ptrreg = $ea_res">, NoEncode<"$ea_res">, PPC970_DGroup_Cracked; def STWUX : XForm_8<31, 183, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memrr:$dst), "stwux $rS, $dst", IIC_LdStStoreUpd, []>, RegConstraint<"$dst.ptrreg = $ea_res">, NoEncode<"$ea_res">, PPC970_DGroup_Cracked; def STFSUX: XForm_8<31, 695, (outs ptr_rc_nor0:$ea_res), (ins f4rc:$rS, memrr:$dst), "stfsux $rS, $dst", IIC_LdStSTFDU, []>, RegConstraint<"$dst.ptrreg = $ea_res">, NoEncode<"$ea_res">, PPC970_DGroup_Cracked; def STFDUX: XForm_8<31, 759, (outs ptr_rc_nor0:$ea_res), (ins f8rc:$rS, memrr:$dst), "stfdux $rS, $dst", IIC_LdStSTFDU, []>, RegConstraint<"$dst.ptrreg = $ea_res">, NoEncode<"$ea_res">, PPC970_DGroup_Cracked; } // Patterns to match the pre-inc stores. We can't put the patterns on // the instruction definitions directly as ISel wants the address base // and offset to be separate operands, not a single complex operand. def : Pat<(pre_truncsti8 i32:$rS, iPTR:$ptrreg, iPTR:$ptroff), (STBUX $rS, $ptrreg, $ptroff)>; def : Pat<(pre_truncsti16 i32:$rS, iPTR:$ptrreg, iPTR:$ptroff), (STHUX $rS, $ptrreg, $ptroff)>; def : Pat<(pre_store i32:$rS, iPTR:$ptrreg, iPTR:$ptroff), (STWUX $rS, $ptrreg, $ptroff)>; def : Pat<(pre_store f32:$rS, iPTR:$ptrreg, iPTR:$ptroff), (STFSUX $rS, $ptrreg, $ptroff)>; def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iPTR:$ptroff), (STFDUX $rS, $ptrreg, $ptroff)>; // Store Multiple def STMW : DForm_1<47, (outs), (ins gprc:$rS, memri:$dst), "stmw $rS, $dst", IIC_LdStLMW, []>; def SYNC : XForm_24_sync<31, 598, (outs), (ins i32imm:$L), "sync $L", IIC_LdStSync, []>; let isCodeGenOnly = 1 in { def MSYNC : XForm_24_sync<31, 598, (outs), (ins), "msync", IIC_LdStSync, []> { let L = 0; } } def : Pat<(int_ppc_sync), (SYNC 0)>, Requires<[HasSYNC]>; def : Pat<(int_ppc_lwsync), (SYNC 1)>, Requires<[HasSYNC]>; def : Pat<(int_ppc_sync), (MSYNC)>, Requires<[HasOnlyMSYNC]>; def : Pat<(int_ppc_lwsync), (MSYNC)>, Requires<[HasOnlyMSYNC]>; //===----------------------------------------------------------------------===// // PPC32 Arithmetic Instructions. // let PPC970_Unit = 1 in { // FXU Operations. def ADDI : DForm_2<14, (outs gprc:$rD), (ins gprc_nor0:$rA, s16imm:$imm), "addi $rD, $rA, $imm", IIC_IntSimple, [(set i32:$rD, (add i32:$rA, imm32SExt16:$imm))]>; let BaseName = "addic" in { let Defs = [CARRY] in def ADDIC : DForm_2<12, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm), "addic $rD, $rA, $imm", IIC_IntGeneral, [(set i32:$rD, (addc i32:$rA, imm32SExt16:$imm))]>, RecFormRel, PPC970_DGroup_Cracked; let Defs = [CARRY, CR0] in def ADDICo : DForm_2<13, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm), "addic. $rD, $rA, $imm", IIC_IntGeneral, []>, isDOT, RecFormRel; } def ADDIS : DForm_2<15, (outs gprc:$rD), (ins gprc_nor0:$rA, s17imm:$imm), "addis $rD, $rA, $imm", IIC_IntSimple, [(set i32:$rD, (add i32:$rA, imm16ShiftedSExt:$imm))]>; let isCodeGenOnly = 1 in def LA : DForm_2<14, (outs gprc:$rD), (ins gprc_nor0:$rA, s16imm:$sym), "la $rD, $sym($rA)", IIC_IntGeneral, [(set i32:$rD, (add i32:$rA, (PPClo tglobaladdr:$sym, 0)))]>; def MULLI : DForm_2< 7, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm), "mulli $rD, $rA, $imm", IIC_IntMulLI, [(set i32:$rD, (mul i32:$rA, imm32SExt16:$imm))]>; let Defs = [CARRY] in def SUBFIC : DForm_2< 8, (outs gprc:$rD), (ins gprc:$rA, s16imm:$imm), "subfic $rD, $rA, $imm", IIC_IntGeneral, [(set i32:$rD, (subc imm32SExt16:$imm, i32:$rA))]>; let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in { def LI : DForm_2_r0<14, (outs gprc:$rD), (ins s16imm:$imm), "li $rD, $imm", IIC_IntSimple, [(set i32:$rD, imm32SExt16:$imm)]>; def LIS : DForm_2_r0<15, (outs gprc:$rD), (ins s17imm:$imm), "lis $rD, $imm", IIC_IntSimple, [(set i32:$rD, imm16ShiftedSExt:$imm)]>; } } let PPC970_Unit = 1 in { // FXU Operations. let Defs = [CR0] in { def ANDIo : DForm_4<28, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "andi. $dst, $src1, $src2", IIC_IntGeneral, [(set i32:$dst, (and i32:$src1, immZExt16:$src2))]>, isDOT; def ANDISo : DForm_4<29, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "andis. $dst, $src1, $src2", IIC_IntGeneral, [(set i32:$dst, (and i32:$src1, imm16ShiftedZExt:$src2))]>, isDOT; } def ORI : DForm_4<24, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "ori $dst, $src1, $src2", IIC_IntSimple, [(set i32:$dst, (or i32:$src1, immZExt16:$src2))]>; def ORIS : DForm_4<25, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "oris $dst, $src1, $src2", IIC_IntSimple, [(set i32:$dst, (or i32:$src1, imm16ShiftedZExt:$src2))]>; def XORI : DForm_4<26, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "xori $dst, $src1, $src2", IIC_IntSimple, [(set i32:$dst, (xor i32:$src1, immZExt16:$src2))]>; def XORIS : DForm_4<27, (outs gprc:$dst), (ins gprc:$src1, u16imm:$src2), "xoris $dst, $src1, $src2", IIC_IntSimple, [(set i32:$dst, (xor i32:$src1, imm16ShiftedZExt:$src2))]>; def NOP : DForm_4_zero<24, (outs), (ins), "nop", IIC_IntSimple, []>; let isCodeGenOnly = 1 in { // The POWER6 and POWER7 have special group-terminating nops. def NOP_GT_PWR6 : DForm_4_fixedreg_zero<24, 1, (outs), (ins), "ori 1, 1, 0", IIC_IntSimple, []>; def NOP_GT_PWR7 : DForm_4_fixedreg_zero<24, 2, (outs), (ins), "ori 2, 2, 0", IIC_IntSimple, []>; } let isCompare = 1, hasSideEffects = 0 in { def CMPWI : DForm_5_ext<11, (outs crrc:$crD), (ins gprc:$rA, s16imm:$imm), "cmpwi $crD, $rA, $imm", IIC_IntCompare>; def CMPLWI : DForm_6_ext<10, (outs crrc:$dst), (ins gprc:$src1, u16imm:$src2), "cmplwi $dst, $src1, $src2", IIC_IntCompare>; def CMPRB : X_BF3_L1_RS5_RS5<31, 192, (outs crbitrc:$BF), (ins u1imm:$L, g8rc:$rA, g8rc:$rB), "cmprb $BF, $L, $rA, $rB", IIC_IntCompare, []>, Requires<[IsISA3_0]>; } } let PPC970_Unit = 1, hasSideEffects = 0 in { // FXU Operations. let isCommutable = 1 in { defm NAND : XForm_6r<31, 476, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "nand", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (not (and i32:$rS, i32:$rB)))]>; defm AND : XForm_6r<31, 28, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "and", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (and i32:$rS, i32:$rB))]>; } // isCommutable defm ANDC : XForm_6r<31, 60, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "andc", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (and i32:$rS, (not i32:$rB)))]>; let isCommutable = 1 in { defm OR : XForm_6r<31, 444, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "or", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (or i32:$rS, i32:$rB))]>; defm NOR : XForm_6r<31, 124, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "nor", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (not (or i32:$rS, i32:$rB)))]>; } // isCommutable defm ORC : XForm_6r<31, 412, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "orc", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (or i32:$rS, (not i32:$rB)))]>; let isCommutable = 1 in { defm EQV : XForm_6r<31, 284, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "eqv", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (not (xor i32:$rS, i32:$rB)))]>; defm XOR : XForm_6r<31, 316, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "xor", "$rA, $rS, $rB", IIC_IntSimple, [(set i32:$rA, (xor i32:$rS, i32:$rB))]>; } // isCommutable defm SLW : XForm_6r<31, 24, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "slw", "$rA, $rS, $rB", IIC_IntGeneral, [(set i32:$rA, (PPCshl i32:$rS, i32:$rB))]>; defm SRW : XForm_6r<31, 536, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "srw", "$rA, $rS, $rB", IIC_IntGeneral, [(set i32:$rA, (PPCsrl i32:$rS, i32:$rB))]>; defm SRAW : XForm_6rc<31, 792, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "sraw", "$rA, $rS, $rB", IIC_IntShift, [(set i32:$rA, (PPCsra i32:$rS, i32:$rB))]>; } let PPC970_Unit = 1 in { // FXU Operations. let hasSideEffects = 0 in { defm SRAWI : XForm_10rc<31, 824, (outs gprc:$rA), (ins gprc:$rS, u5imm:$SH), "srawi", "$rA, $rS, $SH", IIC_IntShift, [(set i32:$rA, (sra i32:$rS, (i32 imm:$SH)))]>; defm CNTLZW : XForm_11r<31, 26, (outs gprc:$rA), (ins gprc:$rS), "cntlzw", "$rA, $rS", IIC_IntGeneral, [(set i32:$rA, (ctlz i32:$rS))]>; defm CNTTZW : XForm_11r<31, 538, (outs gprc:$rA), (ins gprc:$rS), "cnttzw", "$rA, $rS", IIC_IntGeneral, [(set i32:$rA, (cttz i32:$rS))]>, Requires<[IsISA3_0]>; defm EXTSB : XForm_11r<31, 954, (outs gprc:$rA), (ins gprc:$rS), "extsb", "$rA, $rS", IIC_IntSimple, [(set i32:$rA, (sext_inreg i32:$rS, i8))]>; defm EXTSH : XForm_11r<31, 922, (outs gprc:$rA), (ins gprc:$rS), "extsh", "$rA, $rS", IIC_IntSimple, [(set i32:$rA, (sext_inreg i32:$rS, i16))]>; let isCommutable = 1 in def CMPB : XForm_6<31, 508, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB), "cmpb $rA, $rS, $rB", IIC_IntGeneral, [(set i32:$rA, (PPCcmpb i32:$rS, i32:$rB))]>; } let isCompare = 1, hasSideEffects = 0 in { def CMPW : XForm_16_ext<31, 0, (outs crrc:$crD), (ins gprc:$rA, gprc:$rB), "cmpw $crD, $rA, $rB", IIC_IntCompare>; def CMPLW : XForm_16_ext<31, 32, (outs crrc:$crD), (ins gprc:$rA, gprc:$rB), "cmplw $crD, $rA, $rB", IIC_IntCompare>; } } let PPC970_Unit = 3 in { // FPU Operations. //def FCMPO : XForm_17<63, 32, (outs CRRC:$crD), (ins FPRC:$fA, FPRC:$fB), // "fcmpo $crD, $fA, $fB", IIC_FPCompare>; let isCompare = 1, hasSideEffects = 0 in { def FCMPUS : XForm_17<63, 0, (outs crrc:$crD), (ins f4rc:$fA, f4rc:$fB), "fcmpu $crD, $fA, $fB", IIC_FPCompare>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in def FCMPUD : XForm_17<63, 0, (outs crrc:$crD), (ins f8rc:$fA, f8rc:$fB), "fcmpu $crD, $fA, $fB", IIC_FPCompare>; } def FTDIV: XForm_17<63, 128, (outs crrc:$crD), (ins f8rc:$fA, f8rc:$fB), "ftdiv $crD, $fA, $fB", IIC_FPCompare>; def FTSQRT: XForm_17a<63, 160, (outs crrc:$crD), (ins f8rc:$fB), "ftsqrt $crD, $fB", IIC_FPCompare>; let Uses = [RM] in { let hasSideEffects = 0 in { defm FCTIW : XForm_26r<63, 14, (outs f8rc:$frD), (ins f8rc:$frB), "fctiw", "$frD, $frB", IIC_FPGeneral, []>; defm FCTIWU : XForm_26r<63, 142, (outs f8rc:$frD), (ins f8rc:$frB), "fctiwu", "$frD, $frB", IIC_FPGeneral, []>; defm FCTIWZ : XForm_26r<63, 15, (outs f8rc:$frD), (ins f8rc:$frB), "fctiwz", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (PPCfctiwz f64:$frB))]>; defm FRSP : XForm_26r<63, 12, (outs f4rc:$frD), (ins f8rc:$frB), "frsp", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fpround f64:$frB))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FRIND : XForm_26r<63, 392, (outs f8rc:$frD), (ins f8rc:$frB), "frin", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (fround f64:$frB))]>; defm FRINS : XForm_26r<63, 392, (outs f4rc:$frD), (ins f4rc:$frB), "frin", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fround f32:$frB))]>; } let hasSideEffects = 0 in { let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FRIPD : XForm_26r<63, 456, (outs f8rc:$frD), (ins f8rc:$frB), "frip", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (fceil f64:$frB))]>; defm FRIPS : XForm_26r<63, 456, (outs f4rc:$frD), (ins f4rc:$frB), "frip", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fceil f32:$frB))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FRIZD : XForm_26r<63, 424, (outs f8rc:$frD), (ins f8rc:$frB), "friz", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (ftrunc f64:$frB))]>; defm FRIZS : XForm_26r<63, 424, (outs f4rc:$frD), (ins f4rc:$frB), "friz", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (ftrunc f32:$frB))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FRIMD : XForm_26r<63, 488, (outs f8rc:$frD), (ins f8rc:$frB), "frim", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (ffloor f64:$frB))]>; defm FRIMS : XForm_26r<63, 488, (outs f4rc:$frD), (ins f4rc:$frB), "frim", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (ffloor f32:$frB))]>; defm FSQRT : XForm_26r<63, 22, (outs f8rc:$frD), (ins f8rc:$frB), "fsqrt", "$frD, $frB", IIC_FPSqrtD, [(set f64:$frD, (fsqrt f64:$frB))]>; defm FSQRTS : XForm_26r<59, 22, (outs f4rc:$frD), (ins f4rc:$frB), "fsqrts", "$frD, $frB", IIC_FPSqrtS, [(set f32:$frD, (fsqrt f32:$frB))]>; } } } /// Note that FMR is defined as pseudo-ops on the PPC970 because they are /// often coalesced away and we don't want the dispatch group builder to think /// that they will fill slots (which could cause the load of a LSU reject to /// sneak into a d-group with a store). let hasSideEffects = 0 in defm FMR : XForm_26r<63, 72, (outs f4rc:$frD), (ins f4rc:$frB), "fmr", "$frD, $frB", IIC_FPGeneral, []>, // (set f32:$frD, f32:$frB) PPC970_Unit_Pseudo; let PPC970_Unit = 3, hasSideEffects = 0 in { // FPU Operations. // These are artificially split into two different forms, for 4/8 byte FP. defm FABSS : XForm_26r<63, 264, (outs f4rc:$frD), (ins f4rc:$frB), "fabs", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fabs f32:$frB))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FABSD : XForm_26r<63, 264, (outs f8rc:$frD), (ins f8rc:$frB), "fabs", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (fabs f64:$frB))]>; defm FNABSS : XForm_26r<63, 136, (outs f4rc:$frD), (ins f4rc:$frB), "fnabs", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fneg (fabs f32:$frB)))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FNABSD : XForm_26r<63, 136, (outs f8rc:$frD), (ins f8rc:$frB), "fnabs", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (fneg (fabs f64:$frB)))]>; defm FNEGS : XForm_26r<63, 40, (outs f4rc:$frD), (ins f4rc:$frB), "fneg", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (fneg f32:$frB))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FNEGD : XForm_26r<63, 40, (outs f8rc:$frD), (ins f8rc:$frB), "fneg", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (fneg f64:$frB))]>; defm FCPSGNS : XForm_28r<63, 8, (outs f4rc:$frD), (ins f4rc:$frA, f4rc:$frB), "fcpsgn", "$frD, $frA, $frB", IIC_FPGeneral, [(set f32:$frD, (fcopysign f32:$frB, f32:$frA))]>; let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FCPSGND : XForm_28r<63, 8, (outs f8rc:$frD), (ins f8rc:$frA, f8rc:$frB), "fcpsgn", "$frD, $frA, $frB", IIC_FPGeneral, [(set f64:$frD, (fcopysign f64:$frB, f64:$frA))]>; // Reciprocal estimates. defm FRE : XForm_26r<63, 24, (outs f8rc:$frD), (ins f8rc:$frB), "fre", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (PPCfre f64:$frB))]>; defm FRES : XForm_26r<59, 24, (outs f4rc:$frD), (ins f4rc:$frB), "fres", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (PPCfre f32:$frB))]>; defm FRSQRTE : XForm_26r<63, 26, (outs f8rc:$frD), (ins f8rc:$frB), "frsqrte", "$frD, $frB", IIC_FPGeneral, [(set f64:$frD, (PPCfrsqrte f64:$frB))]>; defm FRSQRTES : XForm_26r<59, 26, (outs f4rc:$frD), (ins f4rc:$frB), "frsqrtes", "$frD, $frB", IIC_FPGeneral, [(set f32:$frD, (PPCfrsqrte f32:$frB))]>; } // XL-Form instructions. condition register logical ops. // let hasSideEffects = 0 in def MCRF : XLForm_3<19, 0, (outs crrc:$BF), (ins crrc:$BFA), "mcrf $BF, $BFA", IIC_BrMCR>, PPC970_DGroup_First, PPC970_Unit_CRU; // FIXME: According to the ISA (section 2.5.1 of version 2.06), the // condition-register logical instructions have preferred forms. Specifically, // it is preferred that the bit specified by the BT field be in the same // condition register as that specified by the bit BB. We might want to account // for this via hinting the register allocator and anti-dep breakers, or we // could constrain the register class to force this constraint and then loosen // it during register allocation via convertToThreeAddress or some similar // mechanism. let isCommutable = 1 in { def CRAND : XLForm_1<19, 257, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crand $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (and i1:$CRA, i1:$CRB))]>; def CRNAND : XLForm_1<19, 225, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crnand $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (not (and i1:$CRA, i1:$CRB)))]>; def CROR : XLForm_1<19, 449, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "cror $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (or i1:$CRA, i1:$CRB))]>; def CRXOR : XLForm_1<19, 193, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crxor $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (xor i1:$CRA, i1:$CRB))]>; def CRNOR : XLForm_1<19, 33, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crnor $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (not (or i1:$CRA, i1:$CRB)))]>; def CREQV : XLForm_1<19, 289, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "creqv $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (not (xor i1:$CRA, i1:$CRB)))]>; } // isCommutable def CRANDC : XLForm_1<19, 129, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crandc $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (and i1:$CRA, (not i1:$CRB)))]>; def CRORC : XLForm_1<19, 417, (outs crbitrc:$CRD), (ins crbitrc:$CRA, crbitrc:$CRB), "crorc $CRD, $CRA, $CRB", IIC_BrCR, [(set i1:$CRD, (or i1:$CRA, (not i1:$CRB)))]>; let isCodeGenOnly = 1 in { def CRSET : XLForm_1_ext<19, 289, (outs crbitrc:$dst), (ins), "creqv $dst, $dst, $dst", IIC_BrCR, [(set i1:$dst, 1)]>; def CRUNSET: XLForm_1_ext<19, 193, (outs crbitrc:$dst), (ins), "crxor $dst, $dst, $dst", IIC_BrCR, [(set i1:$dst, 0)]>; let Defs = [CR1EQ], CRD = 6 in { def CR6SET : XLForm_1_ext<19, 289, (outs), (ins), "creqv 6, 6, 6", IIC_BrCR, [(PPCcr6set)]>; def CR6UNSET: XLForm_1_ext<19, 193, (outs), (ins), "crxor 6, 6, 6", IIC_BrCR, [(PPCcr6unset)]>; } } // XFX-Form instructions. Instructions that deal with SPRs. // def MFSPR : XFXForm_1<31, 339, (outs gprc:$RT), (ins i32imm:$SPR), "mfspr $RT, $SPR", IIC_SprMFSPR>; def MTSPR : XFXForm_1<31, 467, (outs), (ins i32imm:$SPR, gprc:$RT), "mtspr $SPR, $RT", IIC_SprMTSPR>; def MFTB : XFXForm_1<31, 371, (outs gprc:$RT), (ins i32imm:$SPR), "mftb $RT, $SPR", IIC_SprMFTB>; + +def MFPMR : XFXForm_1<31, 334, (outs gprc:$RT), (ins i32imm:$SPR), + "mfpmr $RT, $SPR", IIC_SprMFPMR>; + +def MTPMR : XFXForm_1<31, 462, (outs), (ins i32imm:$SPR, gprc:$RT), + "mtpmr $SPR, $RT", IIC_SprMTPMR>; + // A pseudo-instruction used to implement the read of the 64-bit cycle counter // on a 32-bit target. let hasSideEffects = 1, usesCustomInserter = 1 in def ReadTB : Pseudo<(outs gprc:$lo, gprc:$hi), (ins), "#ReadTB", []>; let Uses = [CTR] in { def MFCTR : XFXForm_1_ext<31, 339, 9, (outs gprc:$rT), (ins), "mfctr $rT", IIC_SprMFSPR>, PPC970_DGroup_First, PPC970_Unit_FXU; } let Defs = [CTR], Pattern = [(PPCmtctr i32:$rS)] in { def MTCTR : XFXForm_7_ext<31, 467, 9, (outs), (ins gprc:$rS), "mtctr $rS", IIC_SprMTSPR>, PPC970_DGroup_First, PPC970_Unit_FXU; } let hasSideEffects = 1, isCodeGenOnly = 1, Defs = [CTR] in { let Pattern = [(int_ppc_mtctr i32:$rS)] in def MTCTRloop : XFXForm_7_ext<31, 467, 9, (outs), (ins gprc:$rS), "mtctr $rS", IIC_SprMTSPR>, PPC970_DGroup_First, PPC970_Unit_FXU; } let Defs = [LR] in { def MTLR : XFXForm_7_ext<31, 467, 8, (outs), (ins gprc:$rS), "mtlr $rS", IIC_SprMTSPR>, PPC970_DGroup_First, PPC970_Unit_FXU; } let Uses = [LR] in { def MFLR : XFXForm_1_ext<31, 339, 8, (outs gprc:$rT), (ins), "mflr $rT", IIC_SprMFSPR>, PPC970_DGroup_First, PPC970_Unit_FXU; } let isCodeGenOnly = 1 in { // Move to/from VRSAVE: despite being a SPR, the VRSAVE register is renamed // like a GPR on the PPC970. As such, copies in and out have the same // performance characteristics as an OR instruction. def MTVRSAVE : XFXForm_7_ext<31, 467, 256, (outs), (ins gprc:$rS), "mtspr 256, $rS", IIC_IntGeneral>, PPC970_DGroup_Single, PPC970_Unit_FXU; def MFVRSAVE : XFXForm_1_ext<31, 339, 256, (outs gprc:$rT), (ins), "mfspr $rT, 256", IIC_IntGeneral>, PPC970_DGroup_First, PPC970_Unit_FXU; def MTVRSAVEv : XFXForm_7_ext<31, 467, 256, (outs VRSAVERC:$reg), (ins gprc:$rS), "mtspr 256, $rS", IIC_IntGeneral>, PPC970_DGroup_Single, PPC970_Unit_FXU; def MFVRSAVEv : XFXForm_1_ext<31, 339, 256, (outs gprc:$rT), (ins VRSAVERC:$reg), "mfspr $rT, 256", IIC_IntGeneral>, PPC970_DGroup_First, PPC970_Unit_FXU; } // Aliases for mtvrsave/mfvrsave to mfspr/mtspr. def : InstAlias<"mtvrsave $rS", (MTVRSAVE gprc:$rS)>; def : InstAlias<"mfvrsave $rS", (MFVRSAVE gprc:$rS)>; // SPILL_VRSAVE - Indicate that we're dumping the VRSAVE register, // so we'll need to scavenge a register for it. let mayStore = 1 in def SPILL_VRSAVE : Pseudo<(outs), (ins VRSAVERC:$vrsave, memri:$F), "#SPILL_VRSAVE", []>; // RESTORE_VRSAVE - Indicate that we're restoring the VRSAVE register (previously // spilled), so we'll need to scavenge a register for it. let mayLoad = 1 in def RESTORE_VRSAVE : Pseudo<(outs VRSAVERC:$vrsave), (ins memri:$F), "#RESTORE_VRSAVE", []>; let hasSideEffects = 0 in { // mtocrf's input needs to be prepared by shifting by an amount dependent // on the cr register selected. Thus, post-ra anti-dep breaking must not // later change that register assignment. let hasExtraDefRegAllocReq = 1 in { def MTOCRF: XFXForm_5a<31, 144, (outs crbitm:$FXM), (ins gprc:$ST), "mtocrf $FXM, $ST", IIC_BrMCRX>, PPC970_DGroup_First, PPC970_Unit_CRU; // Similarly to mtocrf, the mask for mtcrf must be prepared in a way that // is dependent on the cr fields being set. def MTCRF : XFXForm_5<31, 144, (outs), (ins i32imm:$FXM, gprc:$rS), "mtcrf $FXM, $rS", IIC_BrMCRX>, PPC970_MicroCode, PPC970_Unit_CRU; } // hasExtraDefRegAllocReq = 1 // mfocrf's input needs to be prepared by shifting by an amount dependent // on the cr register selected. Thus, post-ra anti-dep breaking must not // later change that register assignment. let hasExtraSrcRegAllocReq = 1 in { def MFOCRF: XFXForm_5a<31, 19, (outs gprc:$rT), (ins crbitm:$FXM), "mfocrf $rT, $FXM", IIC_SprMFCRF>, PPC970_DGroup_First, PPC970_Unit_CRU; // Similarly to mfocrf, the mask for mfcrf must be prepared in a way that // is dependent on the cr fields being copied. def MFCR : XFXForm_3<31, 19, (outs gprc:$rT), (ins), "mfcr $rT", IIC_SprMFCR>, PPC970_MicroCode, PPC970_Unit_CRU; } // hasExtraSrcRegAllocReq = 1 def MCRXRX : X_BF3<31, 576, (outs crrc:$BF), (ins), "mcrxrx $BF", IIC_BrMCRX>, Requires<[IsISA3_0]>; } // hasSideEffects = 0 // Pseudo instruction to perform FADD in round-to-zero mode. let usesCustomInserter = 1, Uses = [RM] in { def FADDrtz: Pseudo<(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "", [(set f64:$FRT, (PPCfaddrtz f64:$FRA, f64:$FRB))]>; } // The above pseudo gets expanded to make use of the following instructions // to manipulate FPSCR. Note that FPSCR is not modeled at the DAG level. let Uses = [RM], Defs = [RM] in { def MTFSB0 : XForm_43<63, 70, (outs), (ins u5imm:$FM), "mtfsb0 $FM", IIC_IntMTFSB0, []>, PPC970_DGroup_Single, PPC970_Unit_FPU; def MTFSB1 : XForm_43<63, 38, (outs), (ins u5imm:$FM), "mtfsb1 $FM", IIC_IntMTFSB0, []>, PPC970_DGroup_Single, PPC970_Unit_FPU; let isCodeGenOnly = 1 in def MTFSFb : XFLForm<63, 711, (outs), (ins i32imm:$FM, f8rc:$rT), "mtfsf $FM, $rT", IIC_IntMTFSB0, []>, PPC970_DGroup_Single, PPC970_Unit_FPU; } let Uses = [RM] in { def MFFS : XForm_42<63, 583, (outs f8rc:$rT), (ins), "mffs $rT", IIC_IntMFFS, [(set f64:$rT, (PPCmffs))]>, PPC970_DGroup_Single, PPC970_Unit_FPU; let Defs = [CR1] in def MFFSo : XForm_42<63, 583, (outs f8rc:$rT), (ins), "mffs. $rT", IIC_IntMFFS, []>, isDOT; } let PPC970_Unit = 1, hasSideEffects = 0 in { // FXU Operations. // XO-Form instructions. Arithmetic instructions that can set overflow bit let isCommutable = 1 in defm ADD4 : XOForm_1r<31, 266, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "add", "$rT, $rA, $rB", IIC_IntSimple, [(set i32:$rT, (add i32:$rA, i32:$rB))]>; let isCodeGenOnly = 1 in def ADD4TLS : XOForm_1<31, 266, 0, (outs gprc:$rT), (ins gprc:$rA, tlsreg32:$rB), "add $rT, $rA, $rB", IIC_IntSimple, [(set i32:$rT, (add i32:$rA, tglobaltlsaddr:$rB))]>; let isCommutable = 1 in defm ADDC : XOForm_1rc<31, 10, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "addc", "$rT, $rA, $rB", IIC_IntGeneral, [(set i32:$rT, (addc i32:$rA, i32:$rB))]>, PPC970_DGroup_Cracked; defm DIVW : XOForm_1rcr<31, 491, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divw", "$rT, $rA, $rB", IIC_IntDivW, [(set i32:$rT, (sdiv i32:$rA, i32:$rB))]>; defm DIVWU : XOForm_1rcr<31, 459, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divwu", "$rT, $rA, $rB", IIC_IntDivW, [(set i32:$rT, (udiv i32:$rA, i32:$rB))]>; def DIVWE : XOForm_1<31, 427, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divwe $rT, $rA, $rB", IIC_IntDivW, [(set i32:$rT, (int_ppc_divwe gprc:$rA, gprc:$rB))]>, Requires<[HasExtDiv]>; let Defs = [CR0] in def DIVWEo : XOForm_1<31, 427, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divwe. $rT, $rA, $rB", IIC_IntDivW, []>, isDOT, PPC970_DGroup_Cracked, PPC970_DGroup_First, Requires<[HasExtDiv]>; def DIVWEU : XOForm_1<31, 395, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divweu $rT, $rA, $rB", IIC_IntDivW, [(set i32:$rT, (int_ppc_divweu gprc:$rA, gprc:$rB))]>, Requires<[HasExtDiv]>; let Defs = [CR0] in def DIVWEUo : XOForm_1<31, 395, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "divweu. $rT, $rA, $rB", IIC_IntDivW, []>, isDOT, PPC970_DGroup_Cracked, PPC970_DGroup_First, Requires<[HasExtDiv]>; let isCommutable = 1 in { defm MULHW : XOForm_1r<31, 75, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "mulhw", "$rT, $rA, $rB", IIC_IntMulHW, [(set i32:$rT, (mulhs i32:$rA, i32:$rB))]>; defm MULHWU : XOForm_1r<31, 11, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "mulhwu", "$rT, $rA, $rB", IIC_IntMulHWU, [(set i32:$rT, (mulhu i32:$rA, i32:$rB))]>; defm MULLW : XOForm_1r<31, 235, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "mullw", "$rT, $rA, $rB", IIC_IntMulHW, [(set i32:$rT, (mul i32:$rA, i32:$rB))]>; } // isCommutable defm SUBF : XOForm_1r<31, 40, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "subf", "$rT, $rA, $rB", IIC_IntGeneral, [(set i32:$rT, (sub i32:$rB, i32:$rA))]>; defm SUBFC : XOForm_1rc<31, 8, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "subfc", "$rT, $rA, $rB", IIC_IntGeneral, [(set i32:$rT, (subc i32:$rB, i32:$rA))]>, PPC970_DGroup_Cracked; defm NEG : XOForm_3r<31, 104, 0, (outs gprc:$rT), (ins gprc:$rA), "neg", "$rT, $rA", IIC_IntSimple, [(set i32:$rT, (ineg i32:$rA))]>; let Uses = [CARRY] in { let isCommutable = 1 in defm ADDE : XOForm_1rc<31, 138, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "adde", "$rT, $rA, $rB", IIC_IntGeneral, [(set i32:$rT, (adde i32:$rA, i32:$rB))]>; defm ADDME : XOForm_3rc<31, 234, 0, (outs gprc:$rT), (ins gprc:$rA), "addme", "$rT, $rA", IIC_IntGeneral, [(set i32:$rT, (adde i32:$rA, -1))]>; defm ADDZE : XOForm_3rc<31, 202, 0, (outs gprc:$rT), (ins gprc:$rA), "addze", "$rT, $rA", IIC_IntGeneral, [(set i32:$rT, (adde i32:$rA, 0))]>; defm SUBFE : XOForm_1rc<31, 136, 0, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB), "subfe", "$rT, $rA, $rB", IIC_IntGeneral, [(set i32:$rT, (sube i32:$rB, i32:$rA))]>; defm SUBFME : XOForm_3rc<31, 232, 0, (outs gprc:$rT), (ins gprc:$rA), "subfme", "$rT, $rA", IIC_IntGeneral, [(set i32:$rT, (sube -1, i32:$rA))]>; defm SUBFZE : XOForm_3rc<31, 200, 0, (outs gprc:$rT), (ins gprc:$rA), "subfze", "$rT, $rA", IIC_IntGeneral, [(set i32:$rT, (sube 0, i32:$rA))]>; } } // A-Form instructions. Most of the instructions executed in the FPU are of // this type. // let PPC970_Unit = 3, hasSideEffects = 0 in { // FPU Operations. let Uses = [RM] in { let isCommutable = 1 in { defm FMADD : AForm_1r<63, 29, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), "fmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused, [(set f64:$FRT, (fma f64:$FRA, f64:$FRC, f64:$FRB))]>; defm FMADDS : AForm_1r<59, 29, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB), "fmadds", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fma f32:$FRA, f32:$FRC, f32:$FRB))]>; defm FMSUB : AForm_1r<63, 28, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), "fmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused, [(set f64:$FRT, (fma f64:$FRA, f64:$FRC, (fneg f64:$FRB)))]>; defm FMSUBS : AForm_1r<59, 28, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB), "fmsubs", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fma f32:$FRA, f32:$FRC, (fneg f32:$FRB)))]>; defm FNMADD : AForm_1r<63, 31, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), "fnmadd", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused, [(set f64:$FRT, (fneg (fma f64:$FRA, f64:$FRC, f64:$FRB)))]>; defm FNMADDS : AForm_1r<59, 31, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB), "fnmadds", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fneg (fma f32:$FRA, f32:$FRC, f32:$FRB)))]>; defm FNMSUB : AForm_1r<63, 30, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), "fnmsub", "$FRT, $FRA, $FRC, $FRB", IIC_FPFused, [(set f64:$FRT, (fneg (fma f64:$FRA, f64:$FRC, (fneg f64:$FRB))))]>; defm FNMSUBS : AForm_1r<59, 30, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC, f4rc:$FRB), "fnmsubs", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fneg (fma f32:$FRA, f32:$FRC, (fneg f32:$FRB))))]>; } // isCommutable } // FSEL is artificially split into 4 and 8-byte forms for the result. To avoid // having 4 of these, force the comparison to always be an 8-byte double (code // should use an FMRSD if the input comparison value really wants to be a float) // and 4/8 byte forms for the result and operand type.. let Interpretation64Bit = 1, isCodeGenOnly = 1 in defm FSELD : AForm_1r<63, 23, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC, f8rc:$FRB), "fsel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f64:$FRT, (PPCfsel f64:$FRA, f64:$FRC, f64:$FRB))]>; defm FSELS : AForm_1r<63, 23, (outs f4rc:$FRT), (ins f8rc:$FRA, f4rc:$FRC, f4rc:$FRB), "fsel", "$FRT, $FRA, $FRC, $FRB", IIC_FPGeneral, [(set f32:$FRT, (PPCfsel f64:$FRA, f32:$FRC, f32:$FRB))]>; let Uses = [RM] in { let isCommutable = 1 in { defm FADD : AForm_2r<63, 21, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "fadd", "$FRT, $FRA, $FRB", IIC_FPAddSub, [(set f64:$FRT, (fadd f64:$FRA, f64:$FRB))]>; defm FADDS : AForm_2r<59, 21, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB), "fadds", "$FRT, $FRA, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fadd f32:$FRA, f32:$FRB))]>; } // isCommutable defm FDIV : AForm_2r<63, 18, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "fdiv", "$FRT, $FRA, $FRB", IIC_FPDivD, [(set f64:$FRT, (fdiv f64:$FRA, f64:$FRB))]>; defm FDIVS : AForm_2r<59, 18, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB), "fdivs", "$FRT, $FRA, $FRB", IIC_FPDivS, [(set f32:$FRT, (fdiv f32:$FRA, f32:$FRB))]>; let isCommutable = 1 in { defm FMUL : AForm_3r<63, 25, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRC), "fmul", "$FRT, $FRA, $FRC", IIC_FPFused, [(set f64:$FRT, (fmul f64:$FRA, f64:$FRC))]>; defm FMULS : AForm_3r<59, 25, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRC), "fmuls", "$FRT, $FRA, $FRC", IIC_FPGeneral, [(set f32:$FRT, (fmul f32:$FRA, f32:$FRC))]>; } // isCommutable defm FSUB : AForm_2r<63, 20, (outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "fsub", "$FRT, $FRA, $FRB", IIC_FPAddSub, [(set f64:$FRT, (fsub f64:$FRA, f64:$FRB))]>; defm FSUBS : AForm_2r<59, 20, (outs f4rc:$FRT), (ins f4rc:$FRA, f4rc:$FRB), "fsubs", "$FRT, $FRA, $FRB", IIC_FPGeneral, [(set f32:$FRT, (fsub f32:$FRA, f32:$FRB))]>; } } let hasSideEffects = 0 in { let PPC970_Unit = 1 in { // FXU Operations. let isSelect = 1 in def ISEL : AForm_4<31, 15, (outs gprc:$rT), (ins gprc_nor0:$rA, gprc:$rB, crbitrc:$cond), "isel $rT, $rA, $rB, $cond", IIC_IntISEL, []>; } let PPC970_Unit = 1 in { // FXU Operations. // M-Form instructions. rotate and mask instructions. // let isCommutable = 1 in { // RLWIMI can be commuted if the rotate amount is zero. defm RLWIMI : MForm_2r<20, (outs gprc:$rA), (ins gprc:$rSi, gprc:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME), "rlwimi", "$rA, $rS, $SH, $MB, $ME", IIC_IntRotate, []>, PPC970_DGroup_Cracked, RegConstraint<"$rSi = $rA">, NoEncode<"$rSi">; } let BaseName = "rlwinm" in { def RLWINM : MForm_2<21, (outs gprc:$rA), (ins gprc:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME), "rlwinm $rA, $rS, $SH, $MB, $ME", IIC_IntGeneral, []>, RecFormRel; let Defs = [CR0] in def RLWINMo : MForm_2<21, (outs gprc:$rA), (ins gprc:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME), "rlwinm. $rA, $rS, $SH, $MB, $ME", IIC_IntGeneral, []>, isDOT, RecFormRel, PPC970_DGroup_Cracked; } defm RLWNM : MForm_2r<23, (outs gprc:$rA), (ins gprc:$rS, gprc:$rB, u5imm:$MB, u5imm:$ME), "rlwnm", "$rA, $rS, $rB, $MB, $ME", IIC_IntGeneral, []>; } } // hasSideEffects = 0 //===----------------------------------------------------------------------===// // PowerPC Instruction Patterns // // Arbitrary immediate support. Implement in terms of LIS/ORI. def : Pat<(i32 imm:$imm), (ORI (LIS (HI16 imm:$imm)), (LO16 imm:$imm))>; // Implement the 'not' operation with the NOR instruction. def i32not : OutPatFrag<(ops node:$in), (NOR $in, $in)>; def : Pat<(not i32:$in), (i32not $in)>; // ADD an arbitrary immediate. def : Pat<(add i32:$in, imm:$imm), (ADDIS (ADDI $in, (LO16 imm:$imm)), (HA16 imm:$imm))>; // OR an arbitrary immediate. def : Pat<(or i32:$in, imm:$imm), (ORIS (ORI $in, (LO16 imm:$imm)), (HI16 imm:$imm))>; // XOR an arbitrary immediate. def : Pat<(xor i32:$in, imm:$imm), (XORIS (XORI $in, (LO16 imm:$imm)), (HI16 imm:$imm))>; // SUBFIC def : Pat<(sub imm32SExt16:$imm, i32:$in), (SUBFIC $in, imm:$imm)>; // SHL/SRL def : Pat<(shl i32:$in, (i32 imm:$imm)), (RLWINM $in, imm:$imm, 0, (SHL32 imm:$imm))>; def : Pat<(srl i32:$in, (i32 imm:$imm)), (RLWINM $in, (SRL32 imm:$imm), imm:$imm, 31)>; // ROTL def : Pat<(rotl i32:$in, i32:$sh), (RLWNM $in, $sh, 0, 31)>; def : Pat<(rotl i32:$in, (i32 imm:$imm)), (RLWINM $in, imm:$imm, 0, 31)>; // RLWNM def : Pat<(and (rotl i32:$in, i32:$sh), maskimm32:$imm), (RLWNM $in, $sh, (MB maskimm32:$imm), (ME maskimm32:$imm))>; // Calls def : Pat<(PPCcall (i32 tglobaladdr:$dst)), (BL tglobaladdr:$dst)>; def : Pat<(PPCcall (i32 texternalsym:$dst)), (BL texternalsym:$dst)>; def : Pat<(PPCtc_return (i32 tglobaladdr:$dst), imm:$imm), (TCRETURNdi tglobaladdr:$dst, imm:$imm)>; def : Pat<(PPCtc_return (i32 texternalsym:$dst), imm:$imm), (TCRETURNdi texternalsym:$dst, imm:$imm)>; def : Pat<(PPCtc_return CTRRC:$dst, imm:$imm), (TCRETURNri CTRRC:$dst, imm:$imm)>; // Hi and Lo for Darwin Global Addresses. def : Pat<(PPChi tglobaladdr:$in, 0), (LIS tglobaladdr:$in)>; def : Pat<(PPClo tglobaladdr:$in, 0), (LI tglobaladdr:$in)>; def : Pat<(PPChi tconstpool:$in, 0), (LIS tconstpool:$in)>; def : Pat<(PPClo tconstpool:$in, 0), (LI tconstpool:$in)>; def : Pat<(PPChi tjumptable:$in, 0), (LIS tjumptable:$in)>; def : Pat<(PPClo tjumptable:$in, 0), (LI tjumptable:$in)>; def : Pat<(PPChi tblockaddress:$in, 0), (LIS tblockaddress:$in)>; def : Pat<(PPClo tblockaddress:$in, 0), (LI tblockaddress:$in)>; def : Pat<(PPChi tglobaltlsaddr:$g, i32:$in), (ADDIS $in, tglobaltlsaddr:$g)>; def : Pat<(PPClo tglobaltlsaddr:$g, i32:$in), (ADDI $in, tglobaltlsaddr:$g)>; def : Pat<(add i32:$in, (PPChi tglobaladdr:$g, 0)), (ADDIS $in, tglobaladdr:$g)>; def : Pat<(add i32:$in, (PPChi tconstpool:$g, 0)), (ADDIS $in, tconstpool:$g)>; def : Pat<(add i32:$in, (PPChi tjumptable:$g, 0)), (ADDIS $in, tjumptable:$g)>; def : Pat<(add i32:$in, (PPChi tblockaddress:$g, 0)), (ADDIS $in, tblockaddress:$g)>; // Support for thread-local storage. def PPC32GOT: Pseudo<(outs gprc:$rD), (ins), "#PPC32GOT", [(set i32:$rD, (PPCppc32GOT))]>; // Get the _GLOBAL_OFFSET_TABLE_ in PIC mode. // This uses two output registers, the first as the real output, the second as a // temporary register, used internally in code generation. def PPC32PICGOT: Pseudo<(outs gprc:$rD, gprc:$rT), (ins), "#PPC32PICGOT", []>, NoEncode<"$rT">; def LDgotTprelL32: Pseudo<(outs gprc:$rD), (ins s16imm:$disp, gprc_nor0:$reg), "#LDgotTprelL32", [(set i32:$rD, (PPCldGotTprelL tglobaltlsaddr:$disp, i32:$reg))]>; def : Pat<(PPCaddTls i32:$in, tglobaltlsaddr:$g), (ADD4TLS $in, tglobaltlsaddr:$g)>; def ADDItlsgdL32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp), "#ADDItlsgdL32", [(set i32:$rD, (PPCaddiTlsgdL i32:$reg, tglobaltlsaddr:$disp))]>; // LR is a true define, while the rest of the Defs are clobbers. R3 is // explicitly defined when this op is created, so not mentioned here. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, Defs = [R0,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in def GETtlsADDR32 : Pseudo<(outs gprc:$rD), (ins gprc:$reg, tlsgd32:$sym), "GETtlsADDR32", [(set i32:$rD, (PPCgetTlsAddr i32:$reg, tglobaltlsaddr:$sym))]>; // Combined op for ADDItlsgdL32 and GETtlsADDR32, late expanded. R3 and LR // are true defines while the rest of the Defs are clobbers. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, Defs = [R0,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in def ADDItlsgdLADDR32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp, tlsgd32:$sym), "#ADDItlsgdLADDR32", [(set i32:$rD, (PPCaddiTlsgdLAddr i32:$reg, tglobaltlsaddr:$disp, tglobaltlsaddr:$sym))]>; def ADDItlsldL32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp), "#ADDItlsldL32", [(set i32:$rD, (PPCaddiTlsldL i32:$reg, tglobaltlsaddr:$disp))]>; // LR is a true define, while the rest of the Defs are clobbers. R3 is // explicitly defined when this op is created, so not mentioned here. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, Defs = [R0,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in def GETtlsldADDR32 : Pseudo<(outs gprc:$rD), (ins gprc:$reg, tlsgd32:$sym), "GETtlsldADDR32", [(set i32:$rD, (PPCgetTlsldAddr i32:$reg, tglobaltlsaddr:$sym))]>; // Combined op for ADDItlsldL32 and GETtlsADDR32, late expanded. R3 and LR // are true defines while the rest of the Defs are clobbers. let hasExtraSrcRegAllocReq = 1, hasExtraDefRegAllocReq = 1, Defs = [R0,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,LR,CTR,CR0,CR1,CR5,CR6,CR7] in def ADDItlsldLADDR32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp, tlsgd32:$sym), "#ADDItlsldLADDR32", [(set i32:$rD, (PPCaddiTlsldLAddr i32:$reg, tglobaltlsaddr:$disp, tglobaltlsaddr:$sym))]>; def ADDIdtprelL32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp), "#ADDIdtprelL32", [(set i32:$rD, (PPCaddiDtprelL i32:$reg, tglobaltlsaddr:$disp))]>; def ADDISdtprelHA32 : Pseudo<(outs gprc:$rD), (ins gprc_nor0:$reg, s16imm:$disp), "#ADDISdtprelHA32", [(set i32:$rD, (PPCaddisDtprelHA i32:$reg, tglobaltlsaddr:$disp))]>; // Support for Position-independent code def LWZtoc : Pseudo<(outs gprc:$rD), (ins tocentry32:$disp, gprc:$reg), "#LWZtoc", [(set i32:$rD, (PPCtoc_entry tglobaladdr:$disp, i32:$reg))]>; // Get Global (GOT) Base Register offset, from the word immediately preceding // the function label. def UpdateGBR : Pseudo<(outs gprc:$rD, gprc:$rT), (ins gprc:$rI), "#UpdateGBR", []>; // Standard shifts. These are represented separately from the real shifts above // so that we can distinguish between shifts that allow 5-bit and 6-bit shift // amounts. def : Pat<(sra i32:$rS, i32:$rB), (SRAW $rS, $rB)>; def : Pat<(srl i32:$rS, i32:$rB), (SRW $rS, $rB)>; def : Pat<(shl i32:$rS, i32:$rB), (SLW $rS, $rB)>; def : Pat<(zextloadi1 iaddr:$src), (LBZ iaddr:$src)>; def : Pat<(zextloadi1 xaddr:$src), (LBZX xaddr:$src)>; def : Pat<(extloadi1 iaddr:$src), (LBZ iaddr:$src)>; def : Pat<(extloadi1 xaddr:$src), (LBZX xaddr:$src)>; def : Pat<(extloadi8 iaddr:$src), (LBZ iaddr:$src)>; def : Pat<(extloadi8 xaddr:$src), (LBZX xaddr:$src)>; def : Pat<(extloadi16 iaddr:$src), (LHZ iaddr:$src)>; def : Pat<(extloadi16 xaddr:$src), (LHZX xaddr:$src)>; def : Pat<(f64 (extloadf32 iaddr:$src)), (COPY_TO_REGCLASS (LFS iaddr:$src), F8RC)>; def : Pat<(f64 (extloadf32 xaddr:$src)), (COPY_TO_REGCLASS (LFSX xaddr:$src), F8RC)>; def : Pat<(f64 (fpextend f32:$src)), (COPY_TO_REGCLASS $src, F8RC)>; // Only seq_cst fences require the heavyweight sync (SYNC 0). // All others can use the lightweight sync (SYNC 1). // source: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html // The rule for seq_cst is duplicated to work with both 64 bits and 32 bits // versions of Power. def : Pat<(atomic_fence (i64 7), (imm)), (SYNC 0)>, Requires<[HasSYNC]>; def : Pat<(atomic_fence (i32 7), (imm)), (SYNC 0)>, Requires<[HasSYNC]>; def : Pat<(atomic_fence (imm), (imm)), (SYNC 1)>, Requires<[HasSYNC]>; def : Pat<(atomic_fence (imm), (imm)), (MSYNC)>, Requires<[HasOnlyMSYNC]>; // Additional FNMSUB patterns: -a*c + b == -(a*c - b) def : Pat<(fma (fneg f64:$A), f64:$C, f64:$B), (FNMSUB $A, $C, $B)>; def : Pat<(fma f64:$A, (fneg f64:$C), f64:$B), (FNMSUB $A, $C, $B)>; def : Pat<(fma (fneg f32:$A), f32:$C, f32:$B), (FNMSUBS $A, $C, $B)>; def : Pat<(fma f32:$A, (fneg f32:$C), f32:$B), (FNMSUBS $A, $C, $B)>; // FCOPYSIGN's operand types need not agree. def : Pat<(fcopysign f64:$frB, f32:$frA), (FCPSGND (COPY_TO_REGCLASS $frA, F8RC), $frB)>; def : Pat<(fcopysign f32:$frB, f64:$frA), (FCPSGNS (COPY_TO_REGCLASS $frA, F4RC), $frB)>; include "PPCInstrAltivec.td" include "PPCInstrSPE.td" include "PPCInstr64Bit.td" include "PPCInstrVSX.td" include "PPCInstrQPX.td" include "PPCInstrHTM.td" def crnot : OutPatFrag<(ops node:$in), (CRNOR $in, $in)>; def : Pat<(not i1:$in), (crnot $in)>; // Patterns for arithmetic i1 operations. def : Pat<(add i1:$a, i1:$b), (CRXOR $a, $b)>; def : Pat<(sub i1:$a, i1:$b), (CRXOR $a, $b)>; def : Pat<(mul i1:$a, i1:$b), (CRAND $a, $b)>; // We're sometimes asked to materialize i1 -1, which is just 1 in this case // (-1 is used to mean all bits set). def : Pat<(i1 -1), (CRSET)>; // i1 extensions, implemented in terms of isel. def : Pat<(i32 (zext i1:$in)), (SELECT_I4 $in, (LI 1), (LI 0))>; def : Pat<(i32 (sext i1:$in)), (SELECT_I4 $in, (LI -1), (LI 0))>; def : Pat<(i64 (zext i1:$in)), (SELECT_I8 $in, (LI8 1), (LI8 0))>; def : Pat<(i64 (sext i1:$in)), (SELECT_I8 $in, (LI8 -1), (LI8 0))>; // FIXME: We should choose either a zext or a sext based on other constants // already around. def : Pat<(i32 (anyext i1:$in)), (SELECT_I4 $in, (LI 1), (LI 0))>; def : Pat<(i64 (anyext i1:$in)), (SELECT_I8 $in, (LI8 1), (LI8 0))>; // match setcc on i1 variables. // CRANDC is: // 1 1 : F // 1 0 : T // 0 1 : F // 0 0 : F // // LT is: // -1 -1 : F // -1 0 : T // 0 -1 : F // 0 0 : F // // ULT is: // 1 1 : F // 1 0 : F // 0 1 : T // 0 0 : F def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETLT)), (CRANDC $s1, $s2)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETULT)), (CRANDC $s2, $s1)>; // CRORC is: // 1 1 : T // 1 0 : T // 0 1 : F // 0 0 : T // // LE is: // -1 -1 : T // -1 0 : T // 0 -1 : F // 0 0 : T // // ULE is: // 1 1 : T // 1 0 : F // 0 1 : T // 0 0 : T def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETLE)), (CRORC $s1, $s2)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETULE)), (CRORC $s2, $s1)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETEQ)), (CREQV $s1, $s2)>; // GE is: // -1 -1 : T // -1 0 : F // 0 -1 : T // 0 0 : T // // UGE is: // 1 1 : T // 1 0 : T // 0 1 : F // 0 0 : T def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETGE)), (CRORC $s2, $s1)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETUGE)), (CRORC $s1, $s2)>; // GT is: // -1 -1 : F // -1 0 : F // 0 -1 : T // 0 0 : F // // UGT is: // 1 1 : F // 1 0 : T // 0 1 : F // 0 0 : F def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETGT)), (CRANDC $s2, $s1)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETUGT)), (CRANDC $s1, $s2)>; def : Pat<(i1 (setcc i1:$s1, i1:$s2, SETNE)), (CRXOR $s1, $s2)>; // match setcc on non-i1 (non-vector) variables. Note that SETUEQ, SETOGE, // SETOLE, SETONE, SETULT and SETUGT should be expanded by legalize for // floating-point types. multiclass CRNotPat { def : Pat; def : Pat<(not pattern), result>; // We can also fold the crnot into an extension: def : Pat<(i32 (zext pattern)), (SELECT_I4 result, (LI 0), (LI 1))>; def : Pat<(i32 (sext pattern)), (SELECT_I4 result, (LI 0), (LI -1))>; // We can also fold the crnot into an extension: def : Pat<(i64 (zext pattern)), (SELECT_I8 result, (LI8 0), (LI8 1))>; def : Pat<(i64 (sext pattern)), (SELECT_I8 result, (LI8 0), (LI8 -1))>; // FIXME: We should choose either a zext or a sext based on other constants // already around. def : Pat<(i32 (anyext pattern)), (SELECT_I4 result, (LI 0), (LI 1))>; def : Pat<(i64 (anyext pattern)), (SELECT_I8 result, (LI8 0), (LI8 1))>; } // FIXME: Because of what seems like a bug in TableGen's type-inference code, // we need to write imm:$imm in the output patterns below, not just $imm, or // else the resulting matcher will not correctly add the immediate operand // (making it a register operand instead). // extended SETCC. multiclass ExtSetCCPat { def : Pat<(i32 (zext (i1 (pfrag i32:$s1, cc)))), (rfrag $s1)>; def : Pat<(i64 (zext (i1 (pfrag i64:$s1, cc)))), (rfrag8 $s1)>; def : Pat<(i64 (zext (i1 (pfrag i32:$s1, cc)))), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1), sub_32)>; def : Pat<(i32 (zext (i1 (pfrag i64:$s1, cc)))), (EXTRACT_SUBREG (rfrag8 $s1), sub_32)>; def : Pat<(i32 (anyext (i1 (pfrag i32:$s1, cc)))), (rfrag $s1)>; def : Pat<(i64 (anyext (i1 (pfrag i64:$s1, cc)))), (rfrag8 $s1)>; def : Pat<(i64 (anyext (i1 (pfrag i32:$s1, cc)))), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1), sub_32)>; def : Pat<(i32 (anyext (i1 (pfrag i64:$s1, cc)))), (EXTRACT_SUBREG (rfrag8 $s1), sub_32)>; } // Note that we do all inversions below with i(32|64)not, instead of using // (xori x, 1) because on the A2 nor has single-cycle latency while xori // has 2-cycle latency. defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (CNTLZW $in), 27, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (CNTLZD $in), 58, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (i32not (CNTLZW $in)), 27, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (i64not (CNTLZD $in)), 58, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM $in, 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL $in, 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (i32not $in), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (i64not $in), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (ANDC (NEG $in), $in), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (ANDC8 (NEG8 $in), $in), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (ORC $in, (NEG $in)), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (ORC8 $in, (NEG8 $in)), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (AND $in, (ADDI $in, 1)), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (AND8 $in, (ADDI8 $in, 1)), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (NAND $in, (ADDI $in, 1)), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (NAND8 $in, (ADDI8 $in, 1)), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM (i32not $in), 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL (i64not $in), 1, 63)> >; defm : ExtSetCCPat, OutPatFrag<(ops node:$in), (RLWINM $in, 1, 31, 31)>, OutPatFrag<(ops node:$in), (RLDICL $in, 1, 63)> >; // An extended SETCC with shift amount. multiclass ExtSetCCShiftPat { def : Pat<(i32 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))), (rfrag $s1, $sa)>; def : Pat<(i64 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))), (rfrag8 $s1, $sa)>; def : Pat<(i64 (zext (i1 (pfrag i32:$s1, i32:$sa, cc)))), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>; def : Pat<(i32 (zext (i1 (pfrag i64:$s1, i32:$sa, cc)))), (EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>; def : Pat<(i32 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))), (rfrag $s1, $sa)>; def : Pat<(i64 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))), (rfrag8 $s1, $sa)>; def : Pat<(i64 (anyext (i1 (pfrag i32:$s1, i32:$sa, cc)))), (INSERT_SUBREG (i64 (IMPLICIT_DEF)), (rfrag $s1, $sa), sub_32)>; def : Pat<(i32 (anyext (i1 (pfrag i64:$s1, i32:$sa, cc)))), (EXTRACT_SUBREG (rfrag8 $s1, $sa), sub_32)>; } defm : ExtSetCCShiftPat, OutPatFrag<(ops node:$in, node:$sa), (RLWNM $in, (SUBFIC $sa, 32), 31, 31)>, OutPatFrag<(ops node:$in, node:$sa), (RLDCL $in, (SUBFIC $sa, 64), 63)> >; defm : ExtSetCCShiftPat, OutPatFrag<(ops node:$in, node:$sa), (RLWNM (i32not $in), (SUBFIC $sa, 32), 31, 31)>, OutPatFrag<(ops node:$in, node:$sa), (RLDCL (i64not $in), (SUBFIC $sa, 64), 63)> >; // SETCC for i32. def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETULT)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_lt)>; def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETLT)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_lt)>; def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETUGT)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_gt)>; def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETGT)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_gt)>; def : Pat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETEQ)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_eq)>; def : Pat<(i1 (setcc i32:$s1, immZExt16:$imm, SETEQ)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_eq)>; // For non-equality comparisons, the default code would materialize the // constant, then compare against it, like this: // lis r2, 4660 // ori r2, r2, 22136 // cmpw cr0, r3, r2 // beq cr0,L6 // Since we are just comparing for equality, we can emit this instead: // xoris r0,r3,0x1234 // cmplwi cr0,r0,0x5678 // beq cr0,L6 def : Pat<(i1 (setcc i32:$s1, imm:$imm, SETEQ)), (EXTRACT_SUBREG (CMPLWI (XORIS $s1, (HI16 imm:$imm)), (LO16 imm:$imm)), sub_eq)>; defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETUGE)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_lt)>; defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETGE)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_lt)>; defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETULE)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_gt)>; defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETLE)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_gt)>; defm : CRNotPat<(i1 (setcc i32:$s1, imm32SExt16:$imm, SETNE)), (EXTRACT_SUBREG (CMPWI $s1, imm:$imm), sub_eq)>; defm : CRNotPat<(i1 (setcc i32:$s1, immZExt16:$imm, SETNE)), (EXTRACT_SUBREG (CMPLWI $s1, imm:$imm), sub_eq)>; defm : CRNotPat<(i1 (setcc i32:$s1, imm:$imm, SETNE)), (EXTRACT_SUBREG (CMPLWI (XORIS $s1, (HI16 imm:$imm)), (LO16 imm:$imm)), sub_eq)>; def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETULT)), (EXTRACT_SUBREG (CMPLW $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETLT)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETUGT)), (EXTRACT_SUBREG (CMPLW $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETGT)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc i32:$s1, i32:$s2, SETEQ)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETUGE)), (EXTRACT_SUBREG (CMPLW $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETGE)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETULE)), (EXTRACT_SUBREG (CMPLW $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETLE)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc i32:$s1, i32:$s2, SETNE)), (EXTRACT_SUBREG (CMPW $s1, $s2), sub_eq)>; // SETCC for i64. def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETULT)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_lt)>; def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETLT)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_lt)>; def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETUGT)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_gt)>; def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETGT)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_gt)>; def : Pat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETEQ)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_eq)>; def : Pat<(i1 (setcc i64:$s1, immZExt16:$imm, SETEQ)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_eq)>; // For non-equality comparisons, the default code would materialize the // constant, then compare against it, like this: // lis r2, 4660 // ori r2, r2, 22136 // cmpd cr0, r3, r2 // beq cr0,L6 // Since we are just comparing for equality, we can emit this instead: // xoris r0,r3,0x1234 // cmpldi cr0,r0,0x5678 // beq cr0,L6 def : Pat<(i1 (setcc i64:$s1, imm64ZExt32:$imm, SETEQ)), (EXTRACT_SUBREG (CMPLDI (XORIS8 $s1, (HI16 imm:$imm)), (LO16 imm:$imm)), sub_eq)>; defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETUGE)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_lt)>; defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETGE)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_lt)>; defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETULE)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_gt)>; defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETLE)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_gt)>; defm : CRNotPat<(i1 (setcc i64:$s1, imm64SExt16:$imm, SETNE)), (EXTRACT_SUBREG (CMPDI $s1, imm:$imm), sub_eq)>; defm : CRNotPat<(i1 (setcc i64:$s1, immZExt16:$imm, SETNE)), (EXTRACT_SUBREG (CMPLDI $s1, imm:$imm), sub_eq)>; defm : CRNotPat<(i1 (setcc i64:$s1, imm64ZExt32:$imm, SETNE)), (EXTRACT_SUBREG (CMPLDI (XORIS8 $s1, (HI16 imm:$imm)), (LO16 imm:$imm)), sub_eq)>; def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETULT)), (EXTRACT_SUBREG (CMPLD $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETLT)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETUGT)), (EXTRACT_SUBREG (CMPLD $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETGT)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc i64:$s1, i64:$s2, SETEQ)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETUGE)), (EXTRACT_SUBREG (CMPLD $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETGE)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETULE)), (EXTRACT_SUBREG (CMPLD $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETLE)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETNE)), (EXTRACT_SUBREG (CMPD $s1, $s2), sub_eq)>; // SETCC for f32. def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOLT)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETLT)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOGT)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETGT)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOEQ)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETEQ)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>; def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETUO)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_un)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUGE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETGE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETULE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETLE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUNE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETNE)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETO)), (EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_un)>; // SETCC for f64. def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOLT)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETLT)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOGT)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETGT)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOEQ)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETEQ)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>; def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETUO)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_un)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUGE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETGE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_lt)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETULE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETLE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_gt)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUNE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETNE)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_eq)>; defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETO)), (EXTRACT_SUBREG (FCMPUD $s1, $s2), sub_un)>; // match select on i1 variables: def : Pat<(i1 (select i1:$cond, i1:$tval, i1:$fval)), (CROR (CRAND $cond , $tval), (CRAND (crnot $cond), $fval))>; // match selectcc on i1 variables: // select (lhs == rhs), tval, fval is: // ((lhs == rhs) & tval) | (!(lhs == rhs) & fval) def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETLT)), (CROR (CRAND (CRANDC $lhs, $rhs), $tval), (CRAND (CRORC $rhs, $lhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETULT)), (CROR (CRAND (CRANDC $rhs, $lhs), $tval), (CRAND (CRORC $lhs, $rhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETLE)), (CROR (CRAND (CRORC $lhs, $rhs), $tval), (CRAND (CRANDC $rhs, $lhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETULE)), (CROR (CRAND (CRORC $rhs, $lhs), $tval), (CRAND (CRANDC $lhs, $rhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETEQ)), (CROR (CRAND (CREQV $lhs, $rhs), $tval), (CRAND (CRXOR $lhs, $rhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETGE)), (CROR (CRAND (CRORC $rhs, $lhs), $tval), (CRAND (CRANDC $lhs, $rhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETUGE)), (CROR (CRAND (CRORC $lhs, $rhs), $tval), (CRAND (CRANDC $rhs, $lhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETGT)), (CROR (CRAND (CRANDC $rhs, $lhs), $tval), (CRAND (CRORC $lhs, $rhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETUGT)), (CROR (CRAND (CRANDC $lhs, $rhs), $tval), (CRAND (CRORC $rhs, $lhs), $fval))>; def : Pat <(i1 (selectcc i1:$lhs, i1:$rhs, i1:$tval, i1:$fval, SETNE)), (CROR (CRAND (CREQV $lhs, $rhs), $fval), (CRAND (CRXOR $lhs, $rhs), $tval))>; // match selectcc on i1 variables with non-i1 output. def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETLT)), (SELECT_I4 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETULT)), (SELECT_I4 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETLE)), (SELECT_I4 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETULE)), (SELECT_I4 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETEQ)), (SELECT_I4 (CREQV $lhs, $rhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETGE)), (SELECT_I4 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETUGE)), (SELECT_I4 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETGT)), (SELECT_I4 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETUGT)), (SELECT_I4 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(i32 (selectcc i1:$lhs, i1:$rhs, i32:$tval, i32:$fval, SETNE)), (SELECT_I4 (CRXOR $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETLT)), (SELECT_I8 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETULT)), (SELECT_I8 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETLE)), (SELECT_I8 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETULE)), (SELECT_I8 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETEQ)), (SELECT_I8 (CREQV $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETGE)), (SELECT_I8 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETUGE)), (SELECT_I8 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETGT)), (SELECT_I8 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETUGT)), (SELECT_I8 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETNE)), (SELECT_I8 (CRXOR $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLT)), (SELECT_F4 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETULT)), (SELECT_F4 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLE)), (SELECT_F4 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETULE)), (SELECT_F4 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETEQ)), (SELECT_F4 (CREQV $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETGE)), (SELECT_F4 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETUGE)), (SELECT_F4 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETGT)), (SELECT_F4 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETUGT)), (SELECT_F4 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETNE)), (SELECT_F4 (CRXOR $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETLT)), (SELECT_F8 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETULT)), (SELECT_F8 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETLE)), (SELECT_F8 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETULE)), (SELECT_F8 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETEQ)), (SELECT_F8 (CREQV $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETGE)), (SELECT_F8 (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETUGE)), (SELECT_F8 (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETGT)), (SELECT_F8 (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETUGT)), (SELECT_F8 (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETNE)), (SELECT_F8 (CRXOR $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETLT)), (SELECT_VRRC (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETULT)), (SELECT_VRRC (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETLE)), (SELECT_VRRC (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETULE)), (SELECT_VRRC (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETEQ)), (SELECT_VRRC (CREQV $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETGE)), (SELECT_VRRC (CRORC $rhs, $lhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETUGE)), (SELECT_VRRC (CRORC $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETGT)), (SELECT_VRRC (CRANDC $rhs, $lhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETUGT)), (SELECT_VRRC (CRANDC $lhs, $rhs), $tval, $fval)>; def : Pat<(v4i32 (selectcc i1:$lhs, i1:$rhs, v4i32:$tval, v4i32:$fval, SETNE)), (SELECT_VRRC (CRXOR $lhs, $rhs), $tval, $fval)>; let usesCustomInserter = 1 in { def ANDIo_1_EQ_BIT : Pseudo<(outs crbitrc:$dst), (ins gprc:$in), "#ANDIo_1_EQ_BIT", [(set i1:$dst, (trunc (not i32:$in)))]>; def ANDIo_1_GT_BIT : Pseudo<(outs crbitrc:$dst), (ins gprc:$in), "#ANDIo_1_GT_BIT", [(set i1:$dst, (trunc i32:$in))]>; def ANDIo_1_EQ_BIT8 : Pseudo<(outs crbitrc:$dst), (ins g8rc:$in), "#ANDIo_1_EQ_BIT8", [(set i1:$dst, (trunc (not i64:$in)))]>; def ANDIo_1_GT_BIT8 : Pseudo<(outs crbitrc:$dst), (ins g8rc:$in), "#ANDIo_1_GT_BIT8", [(set i1:$dst, (trunc i64:$in))]>; } def : Pat<(i1 (not (trunc i32:$in))), (ANDIo_1_EQ_BIT $in)>; def : Pat<(i1 (not (trunc i64:$in))), (ANDIo_1_EQ_BIT8 $in)>; //===----------------------------------------------------------------------===// // PowerPC Instructions used for assembler/disassembler only // // FIXME: For B=0 or B > 8, the registers following RT are used. // WARNING: Do not add patterns for this instruction without fixing this. def LSWI : XForm_base_r3xo<31, 597, (outs gprc:$RT), (ins gprc:$A, u5imm:$B), "lswi $RT, $A, $B", IIC_LdStLoad, []>; // FIXME: For B=0 or B > 8, the registers following RT are used. // WARNING: Do not add patterns for this instruction without fixing this. def STSWI : XForm_base_r3xo<31, 725, (outs), (ins gprc:$RT, gprc:$A, u5imm:$B), "stswi $RT, $A, $B", IIC_LdStLoad, []>; def ISYNC : XLForm_2_ext<19, 150, 0, 0, 0, (outs), (ins), "isync", IIC_SprISYNC, []>; def ICBI : XForm_1a<31, 982, (outs), (ins memrr:$src), "icbi $src", IIC_LdStICBI, []>; // We used to have EIEIO as value but E[0-9A-Z] is a reserved name def EnforceIEIO : XForm_24_eieio<31, 854, (outs), (ins), "eieio", IIC_LdStLoad, []>; def WAIT : XForm_24_sync<31, 62, (outs), (ins i32imm:$L), "wait $L", IIC_LdStLoad, []>; def MBAR : XForm_mbar<31, 854, (outs), (ins u5imm:$MO), "mbar $MO", IIC_LdStLoad>, Requires<[IsBookE]>; def MTSR: XForm_sr<31, 210, (outs), (ins gprc:$RS, u4imm:$SR), "mtsr $SR, $RS", IIC_SprMTSR>; def MFSR: XForm_sr<31, 595, (outs gprc:$RS), (ins u4imm:$SR), "mfsr $RS, $SR", IIC_SprMFSR>; def MTSRIN: XForm_srin<31, 242, (outs), (ins gprc:$RS, gprc:$RB), "mtsrin $RS, $RB", IIC_SprMTSR>; def MFSRIN: XForm_srin<31, 659, (outs gprc:$RS), (ins gprc:$RB), "mfsrin $RS, $RB", IIC_SprMFSR>; def MTMSR: XForm_mtmsr<31, 146, (outs), (ins gprc:$RS, i32imm:$L), "mtmsr $RS, $L", IIC_SprMTMSR>; def WRTEE: XForm_mtmsr<31, 131, (outs), (ins gprc:$RS), "wrtee $RS", IIC_SprMTMSR>, Requires<[IsBookE]> { let L = 0; } def WRTEEI: I<31, (outs), (ins i1imm:$E), "wrteei $E", IIC_SprMTMSR>, Requires<[IsBookE]> { bits<1> E; let Inst{16} = E; let Inst{21-30} = 163; } def DCCCI : XForm_tlb<454, (outs), (ins gprc:$A, gprc:$B), "dccci $A, $B", IIC_LdStLoad>, Requires<[IsPPC4xx]>; def ICCCI : XForm_tlb<966, (outs), (ins gprc:$A, gprc:$B), "iccci $A, $B", IIC_LdStLoad>, Requires<[IsPPC4xx]>; def : InstAlias<"dci 0", (DCCCI R0, R0)>, Requires<[IsPPC4xx]>; def : InstAlias<"dccci", (DCCCI R0, R0)>, Requires<[IsPPC4xx]>; def : InstAlias<"ici 0", (ICCCI R0, R0)>, Requires<[IsPPC4xx]>; def : InstAlias<"iccci", (ICCCI R0, R0)>, Requires<[IsPPC4xx]>; def MFMSR : XForm_rs<31, 83, (outs gprc:$RT), (ins), "mfmsr $RT", IIC_SprMFMSR, []>; def MTMSRD : XForm_mtmsr<31, 178, (outs), (ins gprc:$RS, i32imm:$L), "mtmsrd $RS, $L", IIC_SprMTMSRD>; def MCRFS : XLForm_3<63, 64, (outs crrc:$BF), (ins crrc:$BFA), "mcrfs $BF, $BFA", IIC_BrMCR>; def MTFSFI : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W), "mtfsfi $BF, $U, $W", IIC_IntMFFS>; def MTFSFIo : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W), "mtfsfi. $BF, $U, $W", IIC_IntMFFS>, isDOT; def : InstAlias<"mtfsfi $BF, $U", (MTFSFI crrc:$BF, i32imm:$U, 0)>; def : InstAlias<"mtfsfi. $BF, $U", (MTFSFIo crrc:$BF, i32imm:$U, 0)>; def MTFSF : XFLForm_1<63, 711, (outs), (ins i32imm:$FLM, f8rc:$FRB, i32imm:$L, i32imm:$W), "mtfsf $FLM, $FRB, $L, $W", IIC_IntMFFS, []>; def MTFSFo : XFLForm_1<63, 711, (outs), (ins i32imm:$FLM, f8rc:$FRB, i32imm:$L, i32imm:$W), "mtfsf. $FLM, $FRB, $L, $W", IIC_IntMFFS, []>, isDOT; def : InstAlias<"mtfsf $FLM, $FRB", (MTFSF i32imm:$FLM, f8rc:$FRB, 0, 0)>; def : InstAlias<"mtfsf. $FLM, $FRB", (MTFSFo i32imm:$FLM, f8rc:$FRB, 0, 0)>; def SLBIE : XForm_16b<31, 434, (outs), (ins gprc:$RB), "slbie $RB", IIC_SprSLBIE, []>; def SLBMTE : XForm_26<31, 402, (outs), (ins gprc:$RS, gprc:$RB), "slbmte $RS, $RB", IIC_SprSLBMTE, []>; def SLBMFEE : XForm_26<31, 915, (outs gprc:$RT), (ins gprc:$RB), "slbmfee $RT, $RB", IIC_SprSLBMFEE, []>; def SLBMFEV : XLForm_1_gen<31, 851, (outs gprc:$RT), (ins gprc:$RB), "slbmfev $RT, $RB", IIC_SprSLBMFEV, []>; def SLBIA : XForm_0<31, 498, (outs), (ins), "slbia", IIC_SprSLBIA, []>; def TLBIA : XForm_0<31, 370, (outs), (ins), "tlbia", IIC_SprTLBIA, []>; def TLBSYNC : XForm_0<31, 566, (outs), (ins), "tlbsync", IIC_SprTLBSYNC, []>; def TLBIEL : XForm_16b<31, 274, (outs), (ins gprc:$RB), "tlbiel $RB", IIC_SprTLBIEL, []>; def TLBLD : XForm_16b<31, 978, (outs), (ins gprc:$RB), "tlbld $RB", IIC_LdStLoad, []>, Requires<[IsPPC6xx]>; def TLBLI : XForm_16b<31, 1010, (outs), (ins gprc:$RB), "tlbli $RB", IIC_LdStLoad, []>, Requires<[IsPPC6xx]>; def TLBIE : XForm_26<31, 306, (outs), (ins gprc:$RS, gprc:$RB), "tlbie $RB,$RS", IIC_SprTLBIE, []>; def TLBSX : XForm_tlb<914, (outs), (ins gprc:$A, gprc:$B), "tlbsx $A, $B", IIC_LdStLoad>, Requires<[IsBookE]>; def TLBIVAX : XForm_tlb<786, (outs), (ins gprc:$A, gprc:$B), "tlbivax $A, $B", IIC_LdStLoad>, Requires<[IsBookE]>; def TLBRE : XForm_24_eieio<31, 946, (outs), (ins), "tlbre", IIC_LdStLoad, []>, Requires<[IsBookE]>; def TLBWE : XForm_24_eieio<31, 978, (outs), (ins), "tlbwe", IIC_LdStLoad, []>, Requires<[IsBookE]>; def TLBRE2 : XForm_tlbws<31, 946, (outs gprc:$RS), (ins gprc:$A, i1imm:$WS), "tlbre $RS, $A, $WS", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>; def TLBWE2 : XForm_tlbws<31, 978, (outs), (ins gprc:$RS, gprc:$A, i1imm:$WS), "tlbwe $RS, $A, $WS", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>; def TLBSX2 : XForm_base_r3xo<31, 914, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "tlbsx $RST, $A, $B", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>; def TLBSX2D : XForm_base_r3xo<31, 914, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "tlbsx. $RST, $A, $B", IIC_LdStLoad, []>, Requires<[IsPPC4xx]>, isDOT; def RFID : XForm_0<19, 18, (outs), (ins), "rfid", IIC_IntRFID, []>; def RFI : XForm_0<19, 50, (outs), (ins), "rfi", IIC_SprRFI, []>, Requires<[IsBookE]>; def RFCI : XForm_0<19, 51, (outs), (ins), "rfci", IIC_BrB, []>, Requires<[IsBookE]>; def RFDI : XForm_0<19, 39, (outs), (ins), "rfdi", IIC_BrB, []>, Requires<[IsE500]>; def RFMCI : XForm_0<19, 38, (outs), (ins), "rfmci", IIC_BrB, []>, Requires<[IsE500]>; def MFDCR : XFXForm_1<31, 323, (outs gprc:$RT), (ins i32imm:$SPR), "mfdcr $RT, $SPR", IIC_SprMFSPR>, Requires<[IsPPC4xx]>; def MTDCR : XFXForm_1<31, 451, (outs), (ins gprc:$RT, i32imm:$SPR), "mtdcr $SPR, $RT", IIC_SprMTSPR>, Requires<[IsPPC4xx]>; def HRFID : XLForm_1_np<19, 274, (outs), (ins), "hrfid", IIC_BrB, []>; def NAP : XLForm_1_np<19, 434, (outs), (ins), "nap", IIC_BrB, []>; def ATTN : XForm_attn<0, 256, (outs), (ins), "attn", IIC_BrB>; def LBZCIX : XForm_base_r3xo<31, 853, (outs gprc:$RST), (ins gprc:$A, gprc:$B), "lbzcix $RST, $A, $B", IIC_LdStLoad, []>; def LHZCIX : XForm_base_r3xo<31, 821, (outs gprc:$RST), (ins gprc:$A, gprc:$B), "lhzcix $RST, $A, $B", IIC_LdStLoad, []>; def LWZCIX : XForm_base_r3xo<31, 789, (outs gprc:$RST), (ins gprc:$A, gprc:$B), "lwzcix $RST, $A, $B", IIC_LdStLoad, []>; def LDCIX : XForm_base_r3xo<31, 885, (outs gprc:$RST), (ins gprc:$A, gprc:$B), "ldcix $RST, $A, $B", IIC_LdStLoad, []>; def STBCIX : XForm_base_r3xo<31, 981, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "stbcix $RST, $A, $B", IIC_LdStLoad, []>; def STHCIX : XForm_base_r3xo<31, 949, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "sthcix $RST, $A, $B", IIC_LdStLoad, []>; def STWCIX : XForm_base_r3xo<31, 917, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "stwcix $RST, $A, $B", IIC_LdStLoad, []>; def STDCIX : XForm_base_r3xo<31, 1013, (outs), (ins gprc:$RST, gprc:$A, gprc:$B), "stdcix $RST, $A, $B", IIC_LdStLoad, []>; //===----------------------------------------------------------------------===// // PowerPC Assembler Instruction Aliases // // Pseudo-instructions for alternate assembly syntax (never used by codegen). // These are aliases that require C++ handling to convert to the target // instruction, while InstAliases can be handled directly by tblgen. class PPCAsmPseudo : Instruction { let Namespace = "PPC"; bit PPC64 = 0; // Default value, override with isPPC64 let OutOperandList = (outs); let InOperandList = iops; let Pattern = []; let AsmString = asm; let isAsmParserOnly = 1; let isPseudo = 1; } def : InstAlias<"sc", (SC 0)>; def : InstAlias<"sync", (SYNC 0)>, Requires<[HasSYNC]>; def : InstAlias<"msync", (SYNC 0), 0>, Requires<[HasSYNC]>; def : InstAlias<"lwsync", (SYNC 1)>, Requires<[HasSYNC]>; def : InstAlias<"ptesync", (SYNC 2)>, Requires<[HasSYNC]>; def : InstAlias<"wait", (WAIT 0)>; def : InstAlias<"waitrsv", (WAIT 1)>; def : InstAlias<"waitimpl", (WAIT 2)>; def : InstAlias<"mbar", (MBAR 0)>, Requires<[IsBookE]>; def DCBTx : PPCAsmPseudo<"dcbt $dst", (ins memrr:$dst)>; def DCBTSTx : PPCAsmPseudo<"dcbtst $dst", (ins memrr:$dst)>; def DCBTCT : PPCAsmPseudo<"dcbtct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTDS : PPCAsmPseudo<"dcbtds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTT : PPCAsmPseudo<"dcbtt $dst", (ins memrr:$dst)>; def DCBTSTCT : PPCAsmPseudo<"dcbtstct $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTSTDS : PPCAsmPseudo<"dcbtstds $dst, $TH", (ins memrr:$dst, u5imm:$TH)>; def DCBTSTT : PPCAsmPseudo<"dcbtstt $dst", (ins memrr:$dst)>; def DCBFx : PPCAsmPseudo<"dcbf $dst", (ins memrr:$dst)>; def DCBFL : PPCAsmPseudo<"dcbfl $dst", (ins memrr:$dst)>; def DCBFLP : PPCAsmPseudo<"dcbflp $dst", (ins memrr:$dst)>; def : InstAlias<"crset $bx", (CREQV crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>; def : InstAlias<"crclr $bx", (CRXOR crbitrc:$bx, crbitrc:$bx, crbitrc:$bx)>; def : InstAlias<"crmove $bx, $by", (CROR crbitrc:$bx, crbitrc:$by, crbitrc:$by)>; def : InstAlias<"crnot $bx, $by", (CRNOR crbitrc:$bx, crbitrc:$by, crbitrc:$by)>; def : InstAlias<"mtxer $Rx", (MTSPR 1, gprc:$Rx)>; def : InstAlias<"mfxer $Rx", (MFSPR gprc:$Rx, 1)>; def : InstAlias<"mfrtcu $Rx", (MFSPR gprc:$Rx, 4)>; def : InstAlias<"mfrtcl $Rx", (MFSPR gprc:$Rx, 5)>; def : InstAlias<"mtdscr $Rx", (MTSPR 17, gprc:$Rx)>; def : InstAlias<"mfdscr $Rx", (MFSPR gprc:$Rx, 17)>; def : InstAlias<"mtdsisr $Rx", (MTSPR 18, gprc:$Rx)>; def : InstAlias<"mfdsisr $Rx", (MFSPR gprc:$Rx, 18)>; def : InstAlias<"mtdar $Rx", (MTSPR 19, gprc:$Rx)>; def : InstAlias<"mfdar $Rx", (MFSPR gprc:$Rx, 19)>; def : InstAlias<"mtdec $Rx", (MTSPR 22, gprc:$Rx)>; def : InstAlias<"mfdec $Rx", (MFSPR gprc:$Rx, 22)>; def : InstAlias<"mtsdr1 $Rx", (MTSPR 25, gprc:$Rx)>; def : InstAlias<"mfsdr1 $Rx", (MFSPR gprc:$Rx, 25)>; def : InstAlias<"mtsrr0 $Rx", (MTSPR 26, gprc:$Rx)>; def : InstAlias<"mfsrr0 $Rx", (MFSPR gprc:$Rx, 26)>; def : InstAlias<"mtsrr1 $Rx", (MTSPR 27, gprc:$Rx)>; def : InstAlias<"mfsrr1 $Rx", (MFSPR gprc:$Rx, 27)>; def : InstAlias<"mtsrr2 $Rx", (MTSPR 990, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfsrr2 $Rx", (MFSPR gprc:$Rx, 990)>, Requires<[IsPPC4xx]>; def : InstAlias<"mtsrr3 $Rx", (MTSPR 991, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfsrr3 $Rx", (MFSPR gprc:$Rx, 991)>, Requires<[IsPPC4xx]>; def : InstAlias<"mtcfar $Rx", (MTSPR 28, gprc:$Rx)>; def : InstAlias<"mfcfar $Rx", (MFSPR gprc:$Rx, 28)>; def : InstAlias<"mtamr $Rx", (MTSPR 29, gprc:$Rx)>; def : InstAlias<"mfamr $Rx", (MFSPR gprc:$Rx, 29)>; def : InstAlias<"mtpid $Rx", (MTSPR 48, gprc:$Rx)>, Requires<[IsBookE]>; def : InstAlias<"mfpid $Rx", (MFSPR gprc:$Rx, 48)>, Requires<[IsBookE]>; def : InstAlias<"mftb $Rx", (MFTB gprc:$Rx, 268)>; def : InstAlias<"mftbl $Rx", (MFTB gprc:$Rx, 268)>; def : InstAlias<"mftbu $Rx", (MFTB gprc:$Rx, 269)>; def : InstAlias<"mttbl $Rx", (MTSPR 284, gprc:$Rx)>; def : InstAlias<"mttbu $Rx", (MTSPR 285, gprc:$Rx)>; def : InstAlias<"mftblo $Rx", (MFSPR gprc:$Rx, 989)>, Requires<[IsPPC4xx]>; def : InstAlias<"mttblo $Rx", (MTSPR 989, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mftbhi $Rx", (MFSPR gprc:$Rx, 988)>, Requires<[IsPPC4xx]>; def : InstAlias<"mttbhi $Rx", (MTSPR 988, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"xnop", (XORI R0, R0, 0)>; def : InstAlias<"mr $rA, $rB", (OR8 g8rc:$rA, g8rc:$rB, g8rc:$rB)>; def : InstAlias<"mr. $rA, $rB", (OR8o g8rc:$rA, g8rc:$rB, g8rc:$rB)>; def : InstAlias<"not $rA, $rB", (NOR8 g8rc:$rA, g8rc:$rB, g8rc:$rB)>; def : InstAlias<"not. $rA, $rB", (NOR8o g8rc:$rA, g8rc:$rB, g8rc:$rB)>; def : InstAlias<"mtcr $rA", (MTCRF8 255, g8rc:$rA)>; foreach BATR = 0-3 in { def : InstAlias<"mtdbatu "#BATR#", $Rx", (MTSPR !add(BATR, !add(BATR, 536)), gprc:$Rx)>, Requires<[IsPPC6xx]>; def : InstAlias<"mfdbatu $Rx, "#BATR, (MFSPR gprc:$Rx, !add(BATR, !add(BATR, 536)))>, Requires<[IsPPC6xx]>; def : InstAlias<"mtdbatl "#BATR#", $Rx", (MTSPR !add(BATR, !add(BATR, 537)), gprc:$Rx)>, Requires<[IsPPC6xx]>; def : InstAlias<"mfdbatl $Rx, "#BATR, (MFSPR gprc:$Rx, !add(BATR, !add(BATR, 537)))>, Requires<[IsPPC6xx]>; def : InstAlias<"mtibatu "#BATR#", $Rx", (MTSPR !add(BATR, !add(BATR, 528)), gprc:$Rx)>, Requires<[IsPPC6xx]>; def : InstAlias<"mfibatu $Rx, "#BATR, (MFSPR gprc:$Rx, !add(BATR, !add(BATR, 528)))>, Requires<[IsPPC6xx]>; def : InstAlias<"mtibatl "#BATR#", $Rx", (MTSPR !add(BATR, !add(BATR, 529)), gprc:$Rx)>, Requires<[IsPPC6xx]>; def : InstAlias<"mfibatl $Rx, "#BATR, (MFSPR gprc:$Rx, !add(BATR, !add(BATR, 529)))>, Requires<[IsPPC6xx]>; } foreach BR = 0-7 in { def : InstAlias<"mfbr"#BR#" $Rx", (MFDCR gprc:$Rx, !add(BR, 0x80))>, Requires<[IsPPC4xx]>; def : InstAlias<"mtbr"#BR#" $Rx", (MTDCR gprc:$Rx, !add(BR, 0x80))>, Requires<[IsPPC4xx]>; } def : InstAlias<"mtdccr $Rx", (MTSPR 1018, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfdccr $Rx", (MFSPR gprc:$Rx, 1018)>, Requires<[IsPPC4xx]>; def : InstAlias<"mticcr $Rx", (MTSPR 1019, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mficcr $Rx", (MFSPR gprc:$Rx, 1019)>, Requires<[IsPPC4xx]>; def : InstAlias<"mtdear $Rx", (MTSPR 981, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfdear $Rx", (MFSPR gprc:$Rx, 981)>, Requires<[IsPPC4xx]>; def : InstAlias<"mtesr $Rx", (MTSPR 980, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfesr $Rx", (MFSPR gprc:$Rx, 980)>, Requires<[IsPPC4xx]>; def : InstAlias<"mfspefscr $Rx", (MFSPR gprc:$Rx, 512)>; def : InstAlias<"mtspefscr $Rx", (MTSPR 512, gprc:$Rx)>; def : InstAlias<"mttcr $Rx", (MTSPR 986, gprc:$Rx)>, Requires<[IsPPC4xx]>; def : InstAlias<"mftcr $Rx", (MFSPR gprc:$Rx, 986)>, Requires<[IsPPC4xx]>; def LAx : PPCAsmPseudo<"la $rA, $addr", (ins gprc:$rA, memri:$addr)>; def SUBI : PPCAsmPseudo<"subi $rA, $rB, $imm", (ins gprc:$rA, gprc:$rB, s16imm:$imm)>; def SUBIS : PPCAsmPseudo<"subis $rA, $rB, $imm", (ins gprc:$rA, gprc:$rB, s16imm:$imm)>; def SUBIC : PPCAsmPseudo<"subic $rA, $rB, $imm", (ins gprc:$rA, gprc:$rB, s16imm:$imm)>; def SUBICo : PPCAsmPseudo<"subic. $rA, $rB, $imm", (ins gprc:$rA, gprc:$rB, s16imm:$imm)>; def : InstAlias<"sub $rA, $rB, $rC", (SUBF8 g8rc:$rA, g8rc:$rC, g8rc:$rB)>; def : InstAlias<"sub. $rA, $rB, $rC", (SUBF8o g8rc:$rA, g8rc:$rC, g8rc:$rB)>; def : InstAlias<"subc $rA, $rB, $rC", (SUBFC8 g8rc:$rA, g8rc:$rC, g8rc:$rB)>; def : InstAlias<"subc. $rA, $rB, $rC", (SUBFC8o g8rc:$rA, g8rc:$rC, g8rc:$rB)>; def : InstAlias<"mtmsrd $RS", (MTMSRD gprc:$RS, 0)>; def : InstAlias<"mtmsr $RS", (MTMSR gprc:$RS, 0)>; def : InstAlias<"mfasr $RT", (MFSPR gprc:$RT, 280)>; def : InstAlias<"mtasr $RT", (MTSPR 280, gprc:$RT)>; foreach SPRG = 0-3 in { def : InstAlias<"mfsprg $RT, "#SPRG, (MFSPR gprc:$RT, !add(SPRG, 272))>; def : InstAlias<"mfsprg"#SPRG#" $RT", (MFSPR gprc:$RT, !add(SPRG, 272))>; def : InstAlias<"mtsprg "#SPRG#", $RT", (MTSPR !add(SPRG, 272), gprc:$RT)>; def : InstAlias<"mtsprg"#SPRG#" $RT", (MTSPR !add(SPRG, 272), gprc:$RT)>; } foreach SPRG = 4-7 in { def : InstAlias<"mfsprg $RT, "#SPRG, (MFSPR gprc:$RT, !add(SPRG, 256))>, Requires<[IsBookE]>; def : InstAlias<"mfsprg"#SPRG#" $RT", (MFSPR gprc:$RT, !add(SPRG, 256))>, Requires<[IsBookE]>; def : InstAlias<"mtsprg "#SPRG#", $RT", (MTSPR !add(SPRG, 256), gprc:$RT)>, Requires<[IsBookE]>; def : InstAlias<"mtsprg"#SPRG#" $RT", (MTSPR !add(SPRG, 256), gprc:$RT)>, Requires<[IsBookE]>; } def : InstAlias<"mtasr $RS", (MTSPR 280, gprc:$RS)>; def : InstAlias<"mfdec $RT", (MFSPR gprc:$RT, 22)>; def : InstAlias<"mtdec $RT", (MTSPR 22, gprc:$RT)>; def : InstAlias<"mfpvr $RT", (MFSPR gprc:$RT, 287)>; def : InstAlias<"mfsdr1 $RT", (MFSPR gprc:$RT, 25)>; def : InstAlias<"mtsdr1 $RT", (MTSPR 25, gprc:$RT)>; def : InstAlias<"mfsrr0 $RT", (MFSPR gprc:$RT, 26)>; def : InstAlias<"mfsrr1 $RT", (MFSPR gprc:$RT, 27)>; def : InstAlias<"mtsrr0 $RT", (MTSPR 26, gprc:$RT)>; def : InstAlias<"mtsrr1 $RT", (MTSPR 27, gprc:$RT)>; def : InstAlias<"tlbie $RB", (TLBIE R0, gprc:$RB)>; def : InstAlias<"tlbrehi $RS, $A", (TLBRE2 gprc:$RS, gprc:$A, 0)>, Requires<[IsPPC4xx]>; def : InstAlias<"tlbrelo $RS, $A", (TLBRE2 gprc:$RS, gprc:$A, 1)>, Requires<[IsPPC4xx]>; def : InstAlias<"tlbwehi $RS, $A", (TLBWE2 gprc:$RS, gprc:$A, 0)>, Requires<[IsPPC4xx]>; def : InstAlias<"tlbwelo $RS, $A", (TLBWE2 gprc:$RS, gprc:$A, 1)>, Requires<[IsPPC4xx]>; def EXTLWI : PPCAsmPseudo<"extlwi $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def EXTLWIo : PPCAsmPseudo<"extlwi. $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def EXTRWI : PPCAsmPseudo<"extrwi $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def EXTRWIo : PPCAsmPseudo<"extrwi. $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def INSLWI : PPCAsmPseudo<"inslwi $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def INSLWIo : PPCAsmPseudo<"inslwi. $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def INSRWI : PPCAsmPseudo<"insrwi $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def INSRWIo : PPCAsmPseudo<"insrwi. $rA, $rS, $n, $b", (ins gprc:$rA, gprc:$rS, u5imm:$n, u5imm:$b)>; def ROTRWI : PPCAsmPseudo<"rotrwi $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def ROTRWIo : PPCAsmPseudo<"rotrwi. $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def SLWI : PPCAsmPseudo<"slwi $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def SLWIo : PPCAsmPseudo<"slwi. $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def SRWI : PPCAsmPseudo<"srwi $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def SRWIo : PPCAsmPseudo<"srwi. $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def CLRRWI : PPCAsmPseudo<"clrrwi $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def CLRRWIo : PPCAsmPseudo<"clrrwi. $rA, $rS, $n", (ins gprc:$rA, gprc:$rS, u5imm:$n)>; def CLRLSLWI : PPCAsmPseudo<"clrlslwi $rA, $rS, $b, $n", (ins gprc:$rA, gprc:$rS, u5imm:$b, u5imm:$n)>; def CLRLSLWIo : PPCAsmPseudo<"clrlslwi. $rA, $rS, $b, $n", (ins gprc:$rA, gprc:$rS, u5imm:$b, u5imm:$n)>; def : InstAlias<"rotlwi $rA, $rS, $n", (RLWINM gprc:$rA, gprc:$rS, u5imm:$n, 0, 31)>; def : InstAlias<"rotlwi. $rA, $rS, $n", (RLWINMo gprc:$rA, gprc:$rS, u5imm:$n, 0, 31)>; def : InstAlias<"rotlw $rA, $rS, $rB", (RLWNM gprc:$rA, gprc:$rS, gprc:$rB, 0, 31)>; def : InstAlias<"rotlw. $rA, $rS, $rB", (RLWNMo gprc:$rA, gprc:$rS, gprc:$rB, 0, 31)>; def : InstAlias<"clrlwi $rA, $rS, $n", (RLWINM gprc:$rA, gprc:$rS, 0, u5imm:$n, 31)>; def : InstAlias<"clrlwi. $rA, $rS, $n", (RLWINMo gprc:$rA, gprc:$rS, 0, u5imm:$n, 31)>; def : InstAlias<"cntlzw $rA, $rS", (CNTLZW gprc:$rA, gprc:$rS)>; def : InstAlias<"cntlzw. $rA, $rS", (CNTLZWo gprc:$rA, gprc:$rS)>; // The POWER variant def : MnemonicAlias<"cntlz", "cntlzw">; def : MnemonicAlias<"cntlz.", "cntlzw.">; def EXTLDI : PPCAsmPseudo<"extldi $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def EXTLDIo : PPCAsmPseudo<"extldi. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def EXTRDI : PPCAsmPseudo<"extrdi $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def EXTRDIo : PPCAsmPseudo<"extrdi. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def INSRDI : PPCAsmPseudo<"insrdi $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def INSRDIo : PPCAsmPseudo<"insrdi. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u6imm:$n, u6imm:$b)>; def ROTRDI : PPCAsmPseudo<"rotrdi $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def ROTRDIo : PPCAsmPseudo<"rotrdi. $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def SLDI : PPCAsmPseudo<"sldi $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def SLDIo : PPCAsmPseudo<"sldi. $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def SRDI : PPCAsmPseudo<"srdi $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def SRDIo : PPCAsmPseudo<"srdi. $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def CLRRDI : PPCAsmPseudo<"clrrdi $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def CLRRDIo : PPCAsmPseudo<"clrrdi. $rA, $rS, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$n)>; def CLRLSLDI : PPCAsmPseudo<"clrlsldi $rA, $rS, $b, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$b, u6imm:$n)>; def CLRLSLDIo : PPCAsmPseudo<"clrlsldi. $rA, $rS, $b, $n", (ins g8rc:$rA, g8rc:$rS, u6imm:$b, u6imm:$n)>; def : InstAlias<"rotldi $rA, $rS, $n", (RLDICL g8rc:$rA, g8rc:$rS, u6imm:$n, 0)>; def : InstAlias<"rotldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, u6imm:$n, 0)>; def : InstAlias<"rotld $rA, $rS, $rB", (RLDCL g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>; def : InstAlias<"rotld. $rA, $rS, $rB", (RLDCLo g8rc:$rA, g8rc:$rS, gprc:$rB, 0)>; def : InstAlias<"clrldi $rA, $rS, $n", (RLDICL g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>; def : InstAlias<"clrldi. $rA, $rS, $n", (RLDICLo g8rc:$rA, g8rc:$rS, 0, u6imm:$n)>; def RLWINMbm : PPCAsmPseudo<"rlwinm $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; def RLWINMobm : PPCAsmPseudo<"rlwinm. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; def RLWIMIbm : PPCAsmPseudo<"rlwimi $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; def RLWIMIobm : PPCAsmPseudo<"rlwimi. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; def RLWNMbm : PPCAsmPseudo<"rlwnm $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; def RLWNMobm : PPCAsmPseudo<"rlwnm. $rA, $rS, $n, $b", (ins g8rc:$rA, g8rc:$rS, u5imm:$n, i32imm:$b)>; // These generic branch instruction forms are used for the assembler parser only. // Defs and Uses are conservative, since we don't know the BO value. let PPC970_Unit = 7 in { let Defs = [CTR], Uses = [CTR, RM] in { def gBC : BForm_3<16, 0, 0, (outs), (ins u5imm:$bo, crbitrc:$bi, condbrtarget:$dst), "bc $bo, $bi, $dst">; def gBCA : BForm_3<16, 1, 0, (outs), (ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst), "bca $bo, $bi, $dst">; let isAsmParserOnly = 1 in { def gBCat : BForm_3_at<16, 0, 0, (outs), (ins u5imm:$bo, atimm:$at, crbitrc:$bi, condbrtarget:$dst), "bc$at $bo, $bi, $dst">; def gBCAat : BForm_3_at<16, 1, 0, (outs), (ins u5imm:$bo, atimm:$at, crbitrc:$bi, abscondbrtarget:$dst), "bca$at $bo, $bi, $dst">; } // isAsmParserOnly = 1 } let Defs = [LR, CTR], Uses = [CTR, RM] in { def gBCL : BForm_3<16, 0, 1, (outs), (ins u5imm:$bo, crbitrc:$bi, condbrtarget:$dst), "bcl $bo, $bi, $dst">; def gBCLA : BForm_3<16, 1, 1, (outs), (ins u5imm:$bo, crbitrc:$bi, abscondbrtarget:$dst), "bcla $bo, $bi, $dst">; let isAsmParserOnly = 1 in { def gBCLat : BForm_3_at<16, 0, 1, (outs), (ins u5imm:$bo, atimm:$at, crbitrc:$bi, condbrtarget:$dst), "bcl$at $bo, $bi, $dst">; def gBCLAat : BForm_3_at<16, 1, 1, (outs), (ins u5imm:$bo, atimm:$at, crbitrc:$bi, abscondbrtarget:$dst), "bcla$at $bo, $bi, $dst">; } // // isAsmParserOnly = 1 } let Defs = [CTR], Uses = [CTR, LR, RM] in def gBCLR : XLForm_2<19, 16, 0, (outs), (ins u5imm:$bo, crbitrc:$bi, i32imm:$bh), "bclr $bo, $bi, $bh", IIC_BrB, []>; let Defs = [LR, CTR], Uses = [CTR, LR, RM] in def gBCLRL : XLForm_2<19, 16, 1, (outs), (ins u5imm:$bo, crbitrc:$bi, i32imm:$bh), "bclrl $bo, $bi, $bh", IIC_BrB, []>; let Defs = [CTR], Uses = [CTR, LR, RM] in def gBCCTR : XLForm_2<19, 528, 0, (outs), (ins u5imm:$bo, crbitrc:$bi, i32imm:$bh), "bcctr $bo, $bi, $bh", IIC_BrB, []>; let Defs = [LR, CTR], Uses = [CTR, LR, RM] in def gBCCTRL : XLForm_2<19, 528, 1, (outs), (ins u5imm:$bo, crbitrc:$bi, i32imm:$bh), "bcctrl $bo, $bi, $bh", IIC_BrB, []>; } multiclass BranchSimpleMnemonicAT { def : InstAlias<"bc"#pm#" $bo, $bi, $dst", (gBCat u5imm:$bo, at, crbitrc:$bi, condbrtarget:$dst)>; def : InstAlias<"bca"#pm#" $bo, $bi, $dst", (gBCAat u5imm:$bo, at, crbitrc:$bi, condbrtarget:$dst)>; def : InstAlias<"bcl"#pm#" $bo, $bi, $dst", (gBCLat u5imm:$bo, at, crbitrc:$bi, condbrtarget:$dst)>; def : InstAlias<"bcla"#pm#" $bo, $bi, $dst", (gBCLAat u5imm:$bo, at, crbitrc:$bi, condbrtarget:$dst)>; } defm : BranchSimpleMnemonicAT<"+", 3>; defm : BranchSimpleMnemonicAT<"-", 2>; def : InstAlias<"bclr $bo, $bi", (gBCLR u5imm:$bo, crbitrc:$bi, 0)>; def : InstAlias<"bclrl $bo, $bi", (gBCLRL u5imm:$bo, crbitrc:$bi, 0)>; def : InstAlias<"bcctr $bo, $bi", (gBCCTR u5imm:$bo, crbitrc:$bi, 0)>; def : InstAlias<"bcctrl $bo, $bi", (gBCCTRL u5imm:$bo, crbitrc:$bi, 0)>; multiclass BranchSimpleMnemonic1 { def : InstAlias<"b"#name#pm#" $bi, $dst", (gBC bo, crbitrc:$bi, condbrtarget:$dst)>; def : InstAlias<"b"#name#"a"#pm#" $bi, $dst", (gBCA bo, crbitrc:$bi, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"lr"#pm#" $bi", (gBCLR bo, crbitrc:$bi, 0)>; def : InstAlias<"b"#name#"l"#pm#" $bi, $dst", (gBCL bo, crbitrc:$bi, condbrtarget:$dst)>; def : InstAlias<"b"#name#"la"#pm#" $bi, $dst", (gBCLA bo, crbitrc:$bi, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"lrl"#pm#" $bi", (gBCLRL bo, crbitrc:$bi, 0)>; } multiclass BranchSimpleMnemonic2 : BranchSimpleMnemonic1 { def : InstAlias<"b"#name#"ctr"#pm#" $bi", (gBCCTR bo, crbitrc:$bi, 0)>; def : InstAlias<"b"#name#"ctrl"#pm#" $bi", (gBCCTRL bo, crbitrc:$bi, 0)>; } defm : BranchSimpleMnemonic2<"t", "", 12>; defm : BranchSimpleMnemonic2<"f", "", 4>; defm : BranchSimpleMnemonic2<"t", "-", 14>; defm : BranchSimpleMnemonic2<"f", "-", 6>; defm : BranchSimpleMnemonic2<"t", "+", 15>; defm : BranchSimpleMnemonic2<"f", "+", 7>; defm : BranchSimpleMnemonic1<"dnzt", "", 8>; defm : BranchSimpleMnemonic1<"dnzf", "", 0>; defm : BranchSimpleMnemonic1<"dzt", "", 10>; defm : BranchSimpleMnemonic1<"dzf", "", 2>; multiclass BranchExtendedMnemonicPM { def : InstAlias<"b"#name#pm#" $cc, $dst", (BCC bibo, crrc:$cc, condbrtarget:$dst)>; def : InstAlias<"b"#name#pm#" $dst", (BCC bibo, CR0, condbrtarget:$dst)>; def : InstAlias<"b"#name#"a"#pm#" $cc, $dst", (BCCA bibo, crrc:$cc, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"a"#pm#" $dst", (BCCA bibo, CR0, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"lr"#pm#" $cc", (BCCLR bibo, crrc:$cc)>; def : InstAlias<"b"#name#"lr"#pm, (BCCLR bibo, CR0)>; def : InstAlias<"b"#name#"ctr"#pm#" $cc", (BCCCTR bibo, crrc:$cc)>; def : InstAlias<"b"#name#"ctr"#pm, (BCCCTR bibo, CR0)>; def : InstAlias<"b"#name#"l"#pm#" $cc, $dst", (BCCL bibo, crrc:$cc, condbrtarget:$dst)>; def : InstAlias<"b"#name#"l"#pm#" $dst", (BCCL bibo, CR0, condbrtarget:$dst)>; def : InstAlias<"b"#name#"la"#pm#" $cc, $dst", (BCCLA bibo, crrc:$cc, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"la"#pm#" $dst", (BCCLA bibo, CR0, abscondbrtarget:$dst)>; def : InstAlias<"b"#name#"lrl"#pm#" $cc", (BCCLRL bibo, crrc:$cc)>; def : InstAlias<"b"#name#"lrl"#pm, (BCCLRL bibo, CR0)>; def : InstAlias<"b"#name#"ctrl"#pm#" $cc", (BCCCTRL bibo, crrc:$cc)>; def : InstAlias<"b"#name#"ctrl"#pm, (BCCCTRL bibo, CR0)>; } multiclass BranchExtendedMnemonic { defm : BranchExtendedMnemonicPM; defm : BranchExtendedMnemonicPM; defm : BranchExtendedMnemonicPM; } defm : BranchExtendedMnemonic<"lt", 12>; defm : BranchExtendedMnemonic<"gt", 44>; defm : BranchExtendedMnemonic<"eq", 76>; defm : BranchExtendedMnemonic<"un", 108>; defm : BranchExtendedMnemonic<"so", 108>; defm : BranchExtendedMnemonic<"ge", 4>; defm : BranchExtendedMnemonic<"nl", 4>; defm : BranchExtendedMnemonic<"le", 36>; defm : BranchExtendedMnemonic<"ng", 36>; defm : BranchExtendedMnemonic<"ne", 68>; defm : BranchExtendedMnemonic<"nu", 100>; defm : BranchExtendedMnemonic<"ns", 100>; def : InstAlias<"cmpwi $rA, $imm", (CMPWI CR0, gprc:$rA, s16imm:$imm)>; def : InstAlias<"cmpw $rA, $rB", (CMPW CR0, gprc:$rA, gprc:$rB)>; def : InstAlias<"cmplwi $rA, $imm", (CMPLWI CR0, gprc:$rA, u16imm:$imm)>; def : InstAlias<"cmplw $rA, $rB", (CMPLW CR0, gprc:$rA, gprc:$rB)>; def : InstAlias<"cmpdi $rA, $imm", (CMPDI CR0, g8rc:$rA, s16imm64:$imm)>; def : InstAlias<"cmpd $rA, $rB", (CMPD CR0, g8rc:$rA, g8rc:$rB)>; def : InstAlias<"cmpldi $rA, $imm", (CMPLDI CR0, g8rc:$rA, u16imm64:$imm)>; def : InstAlias<"cmpld $rA, $rB", (CMPLD CR0, g8rc:$rA, g8rc:$rB)>; def : InstAlias<"cmpi $bf, 0, $rA, $imm", (CMPWI crrc:$bf, gprc:$rA, s16imm:$imm)>; def : InstAlias<"cmp $bf, 0, $rA, $rB", (CMPW crrc:$bf, gprc:$rA, gprc:$rB)>; def : InstAlias<"cmpli $bf, 0, $rA, $imm", (CMPLWI crrc:$bf, gprc:$rA, u16imm:$imm)>; def : InstAlias<"cmpl $bf, 0, $rA, $rB", (CMPLW crrc:$bf, gprc:$rA, gprc:$rB)>; def : InstAlias<"cmpi $bf, 1, $rA, $imm", (CMPDI crrc:$bf, g8rc:$rA, s16imm64:$imm)>; def : InstAlias<"cmp $bf, 1, $rA, $rB", (CMPD crrc:$bf, g8rc:$rA, g8rc:$rB)>; def : InstAlias<"cmpli $bf, 1, $rA, $imm", (CMPLDI crrc:$bf, g8rc:$rA, u16imm64:$imm)>; def : InstAlias<"cmpl $bf, 1, $rA, $rB", (CMPLD crrc:$bf, g8rc:$rA, g8rc:$rB)>; multiclass TrapExtendedMnemonic { def : InstAlias<"td"#name#"i $rA, $imm", (TDI to, g8rc:$rA, s16imm:$imm)>; def : InstAlias<"td"#name#" $rA, $rB", (TD to, g8rc:$rA, g8rc:$rB)>; def : InstAlias<"tw"#name#"i $rA, $imm", (TWI to, gprc:$rA, s16imm:$imm)>; def : InstAlias<"tw"#name#" $rA, $rB", (TW to, gprc:$rA, gprc:$rB)>; } defm : TrapExtendedMnemonic<"lt", 16>; defm : TrapExtendedMnemonic<"le", 20>; defm : TrapExtendedMnemonic<"eq", 4>; defm : TrapExtendedMnemonic<"ge", 12>; defm : TrapExtendedMnemonic<"gt", 8>; defm : TrapExtendedMnemonic<"nl", 12>; defm : TrapExtendedMnemonic<"ne", 24>; defm : TrapExtendedMnemonic<"ng", 20>; defm : TrapExtendedMnemonic<"llt", 2>; defm : TrapExtendedMnemonic<"lle", 6>; defm : TrapExtendedMnemonic<"lge", 5>; defm : TrapExtendedMnemonic<"lgt", 1>; defm : TrapExtendedMnemonic<"lnl", 5>; defm : TrapExtendedMnemonic<"lng", 6>; defm : TrapExtendedMnemonic<"u", 31>; // Atomic loads def : Pat<(atomic_load_8 iaddr:$src), (LBZ memri:$src)>; def : Pat<(atomic_load_16 iaddr:$src), (LHZ memri:$src)>; def : Pat<(atomic_load_32 iaddr:$src), (LWZ memri:$src)>; def : Pat<(atomic_load_8 xaddr:$src), (LBZX memrr:$src)>; def : Pat<(atomic_load_16 xaddr:$src), (LHZX memrr:$src)>; def : Pat<(atomic_load_32 xaddr:$src), (LWZX memrr:$src)>; // Atomic stores def : Pat<(atomic_store_8 iaddr:$ptr, i32:$val), (STB gprc:$val, memri:$ptr)>; def : Pat<(atomic_store_16 iaddr:$ptr, i32:$val), (STH gprc:$val, memri:$ptr)>; def : Pat<(atomic_store_32 iaddr:$ptr, i32:$val), (STW gprc:$val, memri:$ptr)>; def : Pat<(atomic_store_8 xaddr:$ptr, i32:$val), (STBX gprc:$val, memrr:$ptr)>; def : Pat<(atomic_store_16 xaddr:$ptr, i32:$val), (STHX gprc:$val, memrr:$ptr)>; def : Pat<(atomic_store_32 xaddr:$ptr, i32:$val), (STWX gprc:$val, memrr:$ptr)>; let Predicates = [IsISA3_0] in { // Copy-Paste Facility // We prefix 'CP' to COPY due to name conflict in Target.td. We also prefix to // PASTE for naming consistency. let mayLoad = 1 in def CP_COPY : X_L1_RA5_RB5<31, 774, "copy" , gprc, IIC_LdStCOPY, []>; let mayStore = 1 in def CP_PASTE : X_L1_RA5_RB5<31, 902, "paste" , gprc, IIC_LdStPASTE, []>; let mayStore = 1, Defs = [CR0] in def CP_PASTEo : X_L1_RA5_RB5<31, 902, "paste.", gprc, IIC_LdStPASTE, []>, isDOT; def CP_COPYx : PPCAsmPseudo<"copy $rA, $rB" , (ins gprc:$rA, gprc:$rB)>; def CP_PASTEx : PPCAsmPseudo<"paste $rA, $rB", (ins gprc:$rA, gprc:$rB)>; def CP_COPY_FIRST : PPCAsmPseudo<"copy_first $rA, $rB", (ins gprc:$rA, gprc:$rB)>; def CP_PASTE_LAST : PPCAsmPseudo<"paste_last $rA, $rB", (ins gprc:$rA, gprc:$rB)>; def CP_ABORT : XForm_0<31, 838, (outs), (ins), "cp_abort", IIC_SprABORT, []>; // Message Synchronize def MSGSYNC : XForm_0<31, 886, (outs), (ins), "msgsync", IIC_SprMSGSYNC, []>; // Power-Saving Mode Instruction: def STOP : XForm_0<19, 370, (outs), (ins), "stop", IIC_SprSTOP, []>; } // IsISA3_0 Index: vendor/llvm/dist/lib/Target/PowerPC/PPCSchedule.td =================================================================== --- vendor/llvm/dist/lib/Target/PowerPC/PPCSchedule.td (revision 313055) +++ vendor/llvm/dist/lib/Target/PowerPC/PPCSchedule.td (revision 313056) @@ -1,135 +1,137 @@ //===-- PPCSchedule.td - PowerPC Scheduling Definitions ----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Instruction Itinerary classes used for PowerPC // def IIC_IntSimple : InstrItinClass; def IIC_IntGeneral : InstrItinClass; def IIC_IntCompare : InstrItinClass; def IIC_IntISEL : InstrItinClass; def IIC_IntDivD : InstrItinClass; def IIC_IntDivW : InstrItinClass; def IIC_IntMFFS : InstrItinClass; def IIC_IntMFVSCR : InstrItinClass; def IIC_IntMTFSB0 : InstrItinClass; def IIC_IntMTSRD : InstrItinClass; def IIC_IntMulHD : InstrItinClass; def IIC_IntMulHW : InstrItinClass; def IIC_IntMulHWU : InstrItinClass; def IIC_IntMulLI : InstrItinClass; def IIC_IntRFID : InstrItinClass; def IIC_IntRotateD : InstrItinClass; def IIC_IntRotateDI : InstrItinClass; def IIC_IntRotate : InstrItinClass; def IIC_IntShift : InstrItinClass; def IIC_IntTrapD : InstrItinClass; def IIC_IntTrapW : InstrItinClass; def IIC_BrB : InstrItinClass; def IIC_BrCR : InstrItinClass; def IIC_BrMCR : InstrItinClass; def IIC_BrMCRX : InstrItinClass; def IIC_LdStDCBA : InstrItinClass; def IIC_LdStDCBF : InstrItinClass; def IIC_LdStDCBI : InstrItinClass; def IIC_LdStLoad : InstrItinClass; def IIC_LdStLoadUpd : InstrItinClass; def IIC_LdStLoadUpdX : InstrItinClass; def IIC_LdStStore : InstrItinClass; def IIC_LdStStoreUpd : InstrItinClass; def IIC_LdStDSS : InstrItinClass; def IIC_LdStICBI : InstrItinClass; def IIC_LdStLD : InstrItinClass; def IIC_LdStLDU : InstrItinClass; def IIC_LdStLDUX : InstrItinClass; def IIC_LdStLDARX : InstrItinClass; def IIC_LdStLFD : InstrItinClass; def IIC_LdStLFDU : InstrItinClass; def IIC_LdStLFDUX : InstrItinClass; def IIC_LdStLHA : InstrItinClass; def IIC_LdStLHAU : InstrItinClass; def IIC_LdStLHAUX : InstrItinClass; def IIC_LdStLMW : InstrItinClass; def IIC_LdStLVecX : InstrItinClass; def IIC_LdStLWA : InstrItinClass; def IIC_LdStLWARX : InstrItinClass; def IIC_LdStSLBIA : InstrItinClass; def IIC_LdStSLBIE : InstrItinClass; def IIC_LdStSTD : InstrItinClass; def IIC_LdStSTDCX : InstrItinClass; def IIC_LdStSTDU : InstrItinClass; def IIC_LdStSTDUX : InstrItinClass; def IIC_LdStSTFD : InstrItinClass; def IIC_LdStSTFDU : InstrItinClass; def IIC_LdStSTVEBX : InstrItinClass; def IIC_LdStSTWCX : InstrItinClass; def IIC_LdStSync : InstrItinClass; def IIC_LdStCOPY : InstrItinClass; def IIC_LdStPASTE : InstrItinClass; def IIC_SprISYNC : InstrItinClass; def IIC_SprMFSR : InstrItinClass; def IIC_SprMTMSR : InstrItinClass; def IIC_SprMTSR : InstrItinClass; def IIC_SprTLBSYNC : InstrItinClass; def IIC_SprMFCR : InstrItinClass; def IIC_SprMFCRF : InstrItinClass; def IIC_SprMFMSR : InstrItinClass; def IIC_SprMFSPR : InstrItinClass; def IIC_SprMFTB : InstrItinClass; def IIC_SprMTSPR : InstrItinClass; def IIC_SprMTSRIN : InstrItinClass; def IIC_SprRFI : InstrItinClass; def IIC_SprSC : InstrItinClass; def IIC_FPGeneral : InstrItinClass; def IIC_FPAddSub : InstrItinClass; def IIC_FPCompare : InstrItinClass; def IIC_FPDivD : InstrItinClass; def IIC_FPDivS : InstrItinClass; def IIC_FPFused : InstrItinClass; def IIC_FPRes : InstrItinClass; def IIC_FPSqrtD : InstrItinClass; def IIC_FPSqrtS : InstrItinClass; def IIC_VecGeneral : InstrItinClass; def IIC_VecFP : InstrItinClass; def IIC_VecFPCompare : InstrItinClass; def IIC_VecComplex : InstrItinClass; def IIC_VecPerm : InstrItinClass; def IIC_VecFPRound : InstrItinClass; def IIC_VecVSL : InstrItinClass; def IIC_VecVSR : InstrItinClass; def IIC_SprMTMSRD : InstrItinClass; def IIC_SprSLIE : InstrItinClass; def IIC_SprSLBIE : InstrItinClass; def IIC_SprSLBIEG : InstrItinClass; def IIC_SprSLBMTE : InstrItinClass; def IIC_SprSLBMFEE : InstrItinClass; def IIC_SprSLBMFEV : InstrItinClass; def IIC_SprSLBIA : InstrItinClass; def IIC_SprSLBSYNC : InstrItinClass; def IIC_SprTLBIA : InstrItinClass; def IIC_SprTLBIEL : InstrItinClass; def IIC_SprTLBIE : InstrItinClass; def IIC_SprABORT : InstrItinClass; def IIC_SprMSGSYNC : InstrItinClass; def IIC_SprSTOP : InstrItinClass; +def IIC_SprMFPMR : InstrItinClass; +def IIC_SprMTPMR : InstrItinClass; //===----------------------------------------------------------------------===// // Processor instruction itineraries. include "PPCScheduleG3.td" include "PPCSchedule440.td" include "PPCScheduleG4.td" include "PPCScheduleG4Plus.td" include "PPCScheduleG5.td" include "PPCScheduleP7.td" include "PPCScheduleP8.td" include "PPCScheduleP9.td" include "PPCScheduleA2.td" include "PPCScheduleE500mc.td" include "PPCScheduleE5500.td" Index: vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE500mc.td =================================================================== --- vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE500mc.td (revision 313055) +++ vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE500mc.td (revision 313056) @@ -1,321 +1,329 @@ //===-- PPCScheduleE500mc.td - e500mc Scheduling Defs ------*- 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 itinerary class data for the Freescale e500mc 32-bit // Power processor. // // All information is derived from the "e500mc Core Reference Manual", // Freescale Document Number E500MCRM, Rev. 1, 03/2012. // //===----------------------------------------------------------------------===// // Relevant functional units in the Freescale e500mc core: // // * Decode & Dispatch // Can dispatch up to 2 instructions per clock cycle to either the GPR Issue // queues (GIQx), FP Issue Queue (FIQ), or Branch issue queue (BIQ). def E500_DIS0 : FuncUnit; // Dispatch stage - insn 1 def E500_DIS1 : FuncUnit; // Dispatch stage - insn 2 // * Execute // 6 pipelined execution units: SFX0, SFX1, BU, FPU, LSU, CFX. // Some instructions can only execute in SFX0 but not SFX1. // The CFX has a bypass path, allowing non-divide instructions to execute // while a divide instruction is executed. def E500_SFX0 : FuncUnit; // Simple unit 0 def E500_SFX1 : FuncUnit; // Simple unit 1 def E500_BU : FuncUnit; // Branch unit def E500_CFX_DivBypass : FuncUnit; // CFX divide bypass path def E500_CFX_0 : FuncUnit; // CFX pipeline def E500_LSU_0 : FuncUnit; // LSU pipeline def E500_FPU_0 : FuncUnit; // FPU pipeline def E500_GPR_Bypass : Bypass; def E500_FPR_Bypass : Bypass; def E500_CR_Bypass : Bypass; def PPCE500mcItineraries : ProcessorItineraries< [E500_DIS0, E500_DIS1, E500_SFX0, E500_SFX1, E500_BU, E500_CFX_DivBypass, E500_CFX_0, E500_LSU_0, E500_FPU_0], [E500_CR_Bypass, E500_GPR_Bypass, E500_FPR_Bypass], [ InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1], // Latency = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1], // Latency = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1, 1], // Latency = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass, E500_CR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [5, 1, 1], // Latency = 1 or 2 [E500_CR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_CFX_0], 0>, InstrStage<14, [E500_CFX_DivBypass]>], [17, 1, 1], // Latency=4..35, Repeat= 4..35 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<8, [E500_FPU_0]>], [11], // Latency = 8 [E500_FPR_Bypass]>, InstrItinData, InstrStage<8, [E500_FPU_0]>], [11, 1, 1], // Latency = 8 [NoBypass, NoBypass, NoBypass]>, InstrItinData, InstrStage<1, [E500_CFX_0]>], [7, 1, 1], // Latency = 4, Repeat rate = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_CFX_0]>], [7, 1, 1], // Latency = 4, Repeat rate = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_CFX_0]>], [7, 1, 1], // Latency = 4, Repeat rate = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1], // Latency = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1], // Latency = 1 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E500_SFX0]>], [5, 1], // Latency = 2, Repeat rate = 2 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_BU]>], [4, 1], // Latency = 1 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_BU]>], [4, 1, 1], // Latency = 1 [E500_CR_Bypass, E500_CR_Bypass, E500_CR_Bypass]>, InstrItinData, InstrStage<1, [E500_BU]>], [4, 1], // Latency = 1 [E500_CR_Bypass, E500_CR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1, 1], // Latency = 1 [E500_CR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3, Repeat rate = 1 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [NoBypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_LSU_0]>], [7, 1, 1], // Latency = 4 [E500_FPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [7, 1, 1], // Latency = 4 [E500_FPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [7, 1, 1], // Latency = 4 [E500_FPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1], 0>, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [7, 1], // Latency = r+3 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<3, [E500_LSU_0]>], [6, 1, 1], // Latency = 3, Repeat rate = 3 [E500_GPR_Bypass, E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>], [6, 1], // Latency = 3 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0]>]>, InstrItinData, InstrStage<4, [E500_SFX0]>], [7, 1], [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E500_SFX0, E500_SFX1]>], [5, 1], // Latency = 2, Repeat rate = 4 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0]>], [5, 1], [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_LSU_0], 0>]>, InstrItinData, InstrStage<5, [E500_SFX0]>], [8, 1], [E500_GPR_Bypass, E500_CR_Bypass]>, InstrItinData, InstrStage<5, [E500_SFX0]>], [8, 1], [E500_GPR_Bypass, E500_CR_Bypass]>, + InstrItinData, + InstrStage<4, [E500_SFX0]>], + [7, 1], // Latency = 4, Repeat rate = 4 + [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<4, [E500_SFX0]>], [7, 1], // Latency = 4, Repeat rate = 4 [E500_GPR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1], // Latency = 1, Repeat rate = 1 [E500_GPR_Bypass, E500_CR_Bypass]>, + InstrItinData, + InstrStage<1, [E500_SFX0]>], + [4, 1], // Latency = 1, Repeat rate = 1 + [E500_CR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<4, [E500_SFX0]>], [7, 1], // Latency = 4, Repeat rate = 4 [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0, E500_SFX1]>], [4, 1], // Latency = 1, Repeat rate = 1 [E500_CR_Bypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E500_SFX0]>], [4, 1], [NoBypass, E500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E500_FPU_0]>], [11, 1, 1], // Latency = 8, Repeat rate = 2 [E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<4, [E500_FPU_0]>], [13, 1, 1], // Latency = 10, Repeat rate = 4 [E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<2, [E500_FPU_0]>], [11, 1, 1], // Latency = 8, Repeat rate = 2 [E500_CR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<68, [E500_FPU_0]>], [71, 1, 1], // Latency = 68, Repeat rate = 68 [E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<38, [E500_FPU_0]>], [41, 1, 1], // Latency = 38, Repeat rate = 38 [E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<4, [E500_FPU_0]>], [13, 1, 1, 1], // Latency = 10, Repeat rate = 4 [E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass, E500_FPR_Bypass]>, InstrItinData, InstrStage<38, [E500_FPU_0]>], [41, 1], // Latency = 38, Repeat rate = 38 [E500_FPR_Bypass, E500_FPR_Bypass]> ]>; // ===---------------------------------------------------------------------===// // e500mc machine model for scheduling and other instruction cost heuristics. def PPCE500mcModel : SchedMachineModel { let IssueWidth = 2; // 2 micro-ops are dispatched per cycle. let LoadLatency = 5; // Optimistic load latency assuming bypass. // This is overriden by OperandCycles if the // Itineraries are queried instead. let CompleteModel = 0; let Itineraries = PPCE500mcItineraries; } Index: vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE5500.td =================================================================== --- vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE5500.td (revision 313055) +++ vendor/llvm/dist/lib/Target/PowerPC/PPCScheduleE5500.td (revision 313056) @@ -1,381 +1,385 @@ //===-- PPCScheduleE500mc.td - e5500 Scheduling Defs -------*- 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 itinerary class data for the Freescale e5500 64-bit // Power processor. // // All information is derived from the "e5500 Core Reference Manual", // Freescale Document Number e5500RM, Rev. 1, 03/2012. // //===----------------------------------------------------------------------===// // Relevant functional units in the Freescale e5500 core // (These are the same as for the e500mc) // // * Decode & Dispatch // Can dispatch up to 2 instructions per clock cycle to either the GPR Issue // queues (GIQx), FP Issue Queue (FIQ), or Branch issue queue (BIQ). def E5500_DIS0 : FuncUnit; def E5500_DIS1 : FuncUnit; // * Execute // 6 pipelined execution units: SFX0, SFX1, BU, FPU, LSU, CFX. // The CFX has a bypass path, allowing non-divide instructions to execute // while a divide instruction is being executed. def E5500_SFX0 : FuncUnit; // Simple unit 0 def E5500_SFX1 : FuncUnit; // Simple unit 1 def E5500_BU : FuncUnit; // Branch unit def E5500_CFX_DivBypass : FuncUnit; // CFX divide bypass path def E5500_CFX_0 : FuncUnit; // CFX pipeline stage 0 def E5500_CFX_1 : FuncUnit; // CFX pipeline stage 1 def E5500_LSU_0 : FuncUnit; // LSU pipeline def E5500_FPU_0 : FuncUnit; // FPU pipeline def E5500_GPR_Bypass : Bypass; def E5500_FPR_Bypass : Bypass; def E5500_CR_Bypass : Bypass; def PPCE5500Itineraries : ProcessorItineraries< [E5500_DIS0, E5500_DIS1, E5500_SFX0, E5500_SFX1, E5500_BU, E5500_CFX_DivBypass, E5500_CFX_0, E5500_CFX_1, E5500_LSU_0, E5500_FPU_0], [E5500_CR_Bypass, E5500_GPR_Bypass, E5500_FPR_Bypass], [ InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [5, 2, 2], // Latency = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [5, 2, 2], // Latency = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [5, 2, 2, 2], // Latency = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_CR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [6, 2, 2], // Latency = 1 or 2 [E5500_CR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<26, [E5500_CFX_DivBypass]>], [30, 2, 2], // Latency= 4..26, Repeat rate= 4..26 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<16, [E5500_CFX_DivBypass]>], [20, 2, 2], // Latency= 4..16, Repeat rate= 4..16 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_FPU_0]>], [11], // Latency = 7, Repeat rate = 1 [E5500_FPR_Bypass]>, InstrItinData, InstrStage<7, [E5500_FPU_0]>], [11, 2, 2], // Latency = 7, Repeat rate = 7 [NoBypass, NoBypass, NoBypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<2, [E5500_CFX_1]>], [9, 2, 2], // Latency = 4..7, Repeat rate = 2..4 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<1, [E5500_CFX_1]>], [8, 2, 2], // Latency = 4, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<1, [E5500_CFX_1]>], [8, 2, 2], // Latency = 4, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0], 0>, InstrStage<2, [E5500_CFX_1]>], [8, 2, 2], // Latency = 4 or 5, Repeat = 2 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [5, 2, 2], // Latency = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E5500_SFX0, E5500_SFX1]>], [6, 2, 2], // Latency = 2, Repeat rate = 2 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1]>], [5, 2, 2], // Latency = 1, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E5500_SFX0, E5500_SFX1]>], [6, 2, 2], // Latency = 2, Repeat rate = 2 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<2, [E5500_SFX0]>], [6, 2], // Latency = 2, Repeat rate = 2 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_BU]>], [5, 2], // Latency = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_BU]>], [5, 2, 2], // Latency = 1 [E5500_CR_Bypass, E5500_CR_Bypass, E5500_CR_Bypass]>, InstrItinData, InstrStage<1, [E5500_BU]>], [5, 2], // Latency = 1 [E5500_CR_Bypass, E5500_CR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0]>], [5, 2, 2], // Latency = 1 [E5500_CR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<3, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 3 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [8, 2, 2], // Latency = 4, Repeat rate = 1 [E5500_FPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [8, 2, 2], // Latency = 4, Repeat rate = 1 [E5500_FPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [8, 2, 2], // Latency = 4, Repeat rate = 1 [E5500_FPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [E5500_GPR_Bypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<4, [E5500_LSU_0]>], [8, 2], // Latency = r+3, Repeat rate = r+3 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<3, [E5500_LSU_0]>], [7, 2, 2], // Latency = 3, Repeat rate = 3 [E5500_GPR_Bypass, E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_SFX0, E5500_SFX1], 0>, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass], 2>, // 2 micro-ops InstrItinData, InstrStage<1, [E5500_LSU_0]>], [7, 2], // Latency = 3, Repeat rate = 1 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0]>]>, InstrItinData, InstrStage<2, [E5500_CFX_0]>], [6, 2], // Latency = 2, Repeat rate = 4 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_LSU_0], 0>]>, InstrItinData, InstrStage<5, [E5500_CFX_0]>], [9, 2], // Latency = 5, Repeat rate = 5 [E5500_GPR_Bypass, E5500_CR_Bypass]>, InstrItinData, InstrStage<5, [E5500_CFX_0]>], [9, 2], // Latency = 5, Repeat rate = 5 [E5500_GPR_Bypass, E5500_CR_Bypass]>, - InstrItinData, - InstrStage<4, [E5500_SFX0]>], + InstrItinData, + InstrStage<4, [E5500_CFX_0]>], [8, 2], // Latency = 4, Repeat rate = 4 [E5500_GPR_Bypass, E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_CFX_0]>], [5], // Latency = 1, Repeat rate = 1 [E5500_GPR_Bypass]>, + InstrItinData, + InstrStage<1, [E5500_CFX_0]>], + [5], // Latency = 1, Repeat rate = 1 + [E5500_GPR_Bypass]>, InstrItinData, InstrStage<4, [E5500_CFX_0]>], [8, 2], // Latency = 4, Repeat rate = 4 [NoBypass, E5500_GPR_Bypass]>, InstrItinData, - InstrStage<1, [E5500_SFX0, E5500_SFX1]>], + InstrStage<1, [E5500_CFX_0]>], [5], // Latency = 1, Repeat rate = 1 [E5500_GPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_FPU_0]>], [11, 2, 2], // Latency = 7, Repeat rate = 1 [E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_FPU_0]>], [11, 2, 2], // Latency = 7, Repeat rate = 1 [E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_FPU_0]>], [11, 2, 2], // Latency = 7, Repeat rate = 1 [E5500_CR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<31, [E5500_FPU_0]>], [39, 2, 2], // Latency = 35, Repeat rate = 31 [E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<16, [E5500_FPU_0]>], [24, 2, 2], // Latency = 20, Repeat rate = 16 [E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<1, [E5500_FPU_0]>], [11, 2, 2, 2], // Latency = 7, Repeat rate = 1 [E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass, E5500_FPR_Bypass]>, InstrItinData, InstrStage<2, [E5500_FPU_0]>], [12, 2], // Latency = 8, Repeat rate = 2 [E5500_FPR_Bypass, E5500_FPR_Bypass]> ]>; // ===---------------------------------------------------------------------===// // e5500 machine model for scheduling and other instruction cost heuristics. def PPCE5500Model : SchedMachineModel { let IssueWidth = 2; // 2 micro-ops are dispatched per cycle. let LoadLatency = 6; // Optimistic load latency assuming bypass. // This is overriden by OperandCycles if the // Itineraries are queried instead. let CompleteModel = 0; let Itineraries = PPCE5500Itineraries; } Index: vendor/llvm/dist/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- vendor/llvm/dist/lib/Transforms/InstCombine/InstCombineCompares.cpp (revision 313055) +++ vendor/llvm/dist/lib/Transforms/InstCombine/InstCombineCompares.cpp (revision 313056) @@ -1,4865 +1,4869 @@ //===- InstCombineCompares.cpp --------------------------------------------===// // // 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 visitICmp and visitFCmp functions. // //===----------------------------------------------------------------------===// #include "InstCombineInternal.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/Debug.h" using namespace llvm; using namespace PatternMatch; #define DEBUG_TYPE "instcombine" // How many times is a select replaced by one of its operands? STATISTIC(NumSel, "Number of select opts"); static ConstantInt *extractElement(Constant *V, Constant *Idx) { return cast(ConstantExpr::getExtractElement(V, Idx)); } static bool hasAddOverflow(ConstantInt *Result, ConstantInt *In1, ConstantInt *In2, bool IsSigned) { if (!IsSigned) return Result->getValue().ult(In1->getValue()); if (In2->isNegative()) return Result->getValue().sgt(In1->getValue()); return Result->getValue().slt(In1->getValue()); } /// Compute Result = In1+In2, returning true if the result overflowed for this /// type. static bool addWithOverflow(Constant *&Result, Constant *In1, Constant *In2, bool IsSigned = false) { Result = ConstantExpr::getAdd(In1, In2); if (VectorType *VTy = dyn_cast(In1->getType())) { for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) { Constant *Idx = ConstantInt::get(Type::getInt32Ty(In1->getContext()), i); if (hasAddOverflow(extractElement(Result, Idx), extractElement(In1, Idx), extractElement(In2, Idx), IsSigned)) return true; } return false; } return hasAddOverflow(cast(Result), cast(In1), cast(In2), IsSigned); } static bool hasSubOverflow(ConstantInt *Result, ConstantInt *In1, ConstantInt *In2, bool IsSigned) { if (!IsSigned) return Result->getValue().ugt(In1->getValue()); if (In2->isNegative()) return Result->getValue().slt(In1->getValue()); return Result->getValue().sgt(In1->getValue()); } /// Compute Result = In1-In2, returning true if the result overflowed for this /// type. static bool subWithOverflow(Constant *&Result, Constant *In1, Constant *In2, bool IsSigned = false) { Result = ConstantExpr::getSub(In1, In2); if (VectorType *VTy = dyn_cast(In1->getType())) { for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) { Constant *Idx = ConstantInt::get(Type::getInt32Ty(In1->getContext()), i); if (hasSubOverflow(extractElement(Result, Idx), extractElement(In1, Idx), extractElement(In2, Idx), IsSigned)) return true; } return false; } return hasSubOverflow(cast(Result), cast(In1), cast(In2), IsSigned); } /// Given an icmp instruction, return true if any use of this comparison is a /// branch on sign bit comparison. static bool isBranchOnSignBitCheck(ICmpInst &I, bool isSignBit) { for (auto *U : I.users()) if (isa(U)) return isSignBit; return false; } /// Given an exploded icmp instruction, return true if the comparison only /// checks the sign bit. If it only checks the sign bit, set TrueIfSigned if the /// result of the comparison is true when the input value is signed. static bool isSignBitCheck(ICmpInst::Predicate Pred, const APInt &RHS, bool &TrueIfSigned) { switch (Pred) { case ICmpInst::ICMP_SLT: // True if LHS s< 0 TrueIfSigned = true; return RHS == 0; case ICmpInst::ICMP_SLE: // True if LHS s<= RHS and RHS == -1 TrueIfSigned = true; return RHS.isAllOnesValue(); case ICmpInst::ICMP_SGT: // True if LHS s> -1 TrueIfSigned = false; return RHS.isAllOnesValue(); case ICmpInst::ICMP_UGT: // True if LHS u> RHS and RHS == high-bit-mask - 1 TrueIfSigned = true; return RHS.isMaxSignedValue(); case ICmpInst::ICMP_UGE: // True if LHS u>= RHS and RHS == high-bit-mask (2^7, 2^15, 2^31, etc) TrueIfSigned = true; return RHS.isSignBit(); default: return false; } } /// Returns true if the exploded icmp can be expressed as a signed comparison /// to zero and updates the predicate accordingly. /// The signedness of the comparison is preserved. /// TODO: Refactor with decomposeBitTestICmp()? static bool isSignTest(ICmpInst::Predicate &Pred, const APInt &C) { if (!ICmpInst::isSigned(Pred)) return false; if (C == 0) return ICmpInst::isRelational(Pred); if (C == 1) { if (Pred == ICmpInst::ICMP_SLT) { Pred = ICmpInst::ICMP_SLE; return true; } } else if (C.isAllOnesValue()) { if (Pred == ICmpInst::ICMP_SGT) { Pred = ICmpInst::ICMP_SGE; return true; } } return false; } /// Given a signed integer type and a set of known zero and one bits, compute /// the maximum and minimum values that could have the specified known zero and /// known one bits, returning them in Min/Max. static void computeSignedMinMaxValuesFromKnownBits(const APInt &KnownZero, const APInt &KnownOne, APInt &Min, APInt &Max) { assert(KnownZero.getBitWidth() == KnownOne.getBitWidth() && KnownZero.getBitWidth() == Min.getBitWidth() && KnownZero.getBitWidth() == Max.getBitWidth() && "KnownZero, KnownOne and Min, Max must have equal bitwidth."); APInt UnknownBits = ~(KnownZero|KnownOne); // The minimum value is when all unknown bits are zeros, EXCEPT for the sign // bit if it is unknown. Min = KnownOne; Max = KnownOne|UnknownBits; if (UnknownBits.isNegative()) { // Sign bit is unknown Min.setBit(Min.getBitWidth()-1); Max.clearBit(Max.getBitWidth()-1); } } /// Given an unsigned integer type and a set of known zero and one bits, compute /// the maximum and minimum values that could have the specified known zero and /// known one bits, returning them in Min/Max. static void computeUnsignedMinMaxValuesFromKnownBits(const APInt &KnownZero, const APInt &KnownOne, APInt &Min, APInt &Max) { assert(KnownZero.getBitWidth() == KnownOne.getBitWidth() && KnownZero.getBitWidth() == Min.getBitWidth() && KnownZero.getBitWidth() == Max.getBitWidth() && "Ty, KnownZero, KnownOne and Min, Max must have equal bitwidth."); APInt UnknownBits = ~(KnownZero|KnownOne); // The minimum value is when the unknown bits are all zeros. Min = KnownOne; // The maximum value is when the unknown bits are all ones. Max = KnownOne|UnknownBits; } /// This is called when we see this pattern: /// cmp pred (load (gep GV, ...)), cmpcst /// where GV is a global variable with a constant initializer. Try to simplify /// this into some simple computation that does not need the load. For example /// we can optimize "icmp eq (load (gep "foo", 0, i)), 0" into "icmp eq i, 3". /// /// If AndCst is non-null, then the loaded value is masked with that constant /// before doing the comparison. This handles cases like "A[i]&4 == 0". Instruction *InstCombiner::foldCmpLoadFromIndexedGlobal(GetElementPtrInst *GEP, GlobalVariable *GV, CmpInst &ICI, ConstantInt *AndCst) { Constant *Init = GV->getInitializer(); if (!isa(Init) && !isa(Init)) return nullptr; uint64_t ArrayElementCount = Init->getType()->getArrayNumElements(); if (ArrayElementCount > 1024) return nullptr; // Don't blow up on huge arrays. // There are many forms of this optimization we can handle, for now, just do // the simple index into a single-dimensional array. // // Require: GEP GV, 0, i {{, constant indices}} if (GEP->getNumOperands() < 3 || !isa(GEP->getOperand(1)) || !cast(GEP->getOperand(1))->isZero() || isa(GEP->getOperand(2))) return nullptr; // Check that indices after the variable are constants and in-range for the // type they index. Collect the indices. This is typically for arrays of // structs. SmallVector LaterIndices; Type *EltTy = Init->getType()->getArrayElementType(); for (unsigned i = 3, e = GEP->getNumOperands(); i != e; ++i) { ConstantInt *Idx = dyn_cast(GEP->getOperand(i)); if (!Idx) return nullptr; // Variable index. uint64_t IdxVal = Idx->getZExtValue(); if ((unsigned)IdxVal != IdxVal) return nullptr; // Too large array index. if (StructType *STy = dyn_cast(EltTy)) EltTy = STy->getElementType(IdxVal); else if (ArrayType *ATy = dyn_cast(EltTy)) { if (IdxVal >= ATy->getNumElements()) return nullptr; EltTy = ATy->getElementType(); } else { return nullptr; // Unknown type. } LaterIndices.push_back(IdxVal); } enum { Overdefined = -3, Undefined = -2 }; // Variables for our state machines. // FirstTrueElement/SecondTrueElement - Used to emit a comparison of the form // "i == 47 | i == 87", where 47 is the first index the condition is true for, // and 87 is the second (and last) index. FirstTrueElement is -2 when // undefined, otherwise set to the first true element. SecondTrueElement is // -2 when undefined, -3 when overdefined and >= 0 when that index is true. int FirstTrueElement = Undefined, SecondTrueElement = Undefined; // FirstFalseElement/SecondFalseElement - Used to emit a comparison of the // form "i != 47 & i != 87". Same state transitions as for true elements. int FirstFalseElement = Undefined, SecondFalseElement = Undefined; /// TrueRangeEnd/FalseRangeEnd - In conjunction with First*Element, these /// define a state machine that triggers for ranges of values that the index /// is true or false for. This triggers on things like "abbbbc"[i] == 'b'. /// This is -2 when undefined, -3 when overdefined, and otherwise the last /// index in the range (inclusive). We use -2 for undefined here because we /// use relative comparisons and don't want 0-1 to match -1. int TrueRangeEnd = Undefined, FalseRangeEnd = Undefined; // MagicBitvector - This is a magic bitvector where we set a bit if the // comparison is true for element 'i'. If there are 64 elements or less in // the array, this will fully represent all the comparison results. uint64_t MagicBitvector = 0; // Scan the array and see if one of our patterns matches. Constant *CompareRHS = cast(ICI.getOperand(1)); for (unsigned i = 0, e = ArrayElementCount; i != e; ++i) { Constant *Elt = Init->getAggregateElement(i); if (!Elt) return nullptr; // If this is indexing an array of structures, get the structure element. if (!LaterIndices.empty()) Elt = ConstantExpr::getExtractValue(Elt, LaterIndices); // If the element is masked, handle it. if (AndCst) Elt = ConstantExpr::getAnd(Elt, AndCst); // Find out if the comparison would be true or false for the i'th element. Constant *C = ConstantFoldCompareInstOperands(ICI.getPredicate(), Elt, CompareRHS, DL, &TLI); // If the result is undef for this element, ignore it. if (isa(C)) { // Extend range state machines to cover this element in case there is an // undef in the middle of the range. if (TrueRangeEnd == (int)i-1) TrueRangeEnd = i; if (FalseRangeEnd == (int)i-1) FalseRangeEnd = i; continue; } // If we can't compute the result for any of the elements, we have to give // up evaluating the entire conditional. if (!isa(C)) return nullptr; // Otherwise, we know if the comparison is true or false for this element, // update our state machines. bool IsTrueForElt = !cast(C)->isZero(); // State machine for single/double/range index comparison. if (IsTrueForElt) { // Update the TrueElement state machine. if (FirstTrueElement == Undefined) FirstTrueElement = TrueRangeEnd = i; // First true element. else { // Update double-compare state machine. if (SecondTrueElement == Undefined) SecondTrueElement = i; else SecondTrueElement = Overdefined; // Update range state machine. if (TrueRangeEnd == (int)i-1) TrueRangeEnd = i; else TrueRangeEnd = Overdefined; } } else { // Update the FalseElement state machine. if (FirstFalseElement == Undefined) FirstFalseElement = FalseRangeEnd = i; // First false element. else { // Update double-compare state machine. if (SecondFalseElement == Undefined) SecondFalseElement = i; else SecondFalseElement = Overdefined; // Update range state machine. if (FalseRangeEnd == (int)i-1) FalseRangeEnd = i; else FalseRangeEnd = Overdefined; } } // If this element is in range, update our magic bitvector. if (i < 64 && IsTrueForElt) MagicBitvector |= 1ULL << i; // If all of our states become overdefined, bail out early. Since the // predicate is expensive, only check it every 8 elements. This is only // really useful for really huge arrays. if ((i & 8) == 0 && i >= 64 && SecondTrueElement == Overdefined && SecondFalseElement == Overdefined && TrueRangeEnd == Overdefined && FalseRangeEnd == Overdefined) return nullptr; } // Now that we've scanned the entire array, emit our new comparison(s). We // order the state machines in complexity of the generated code. Value *Idx = GEP->getOperand(2); // If the index is larger than the pointer size of the target, truncate the // index down like the GEP would do implicitly. We don't have to do this for // an inbounds GEP because the index can't be out of range. if (!GEP->isInBounds()) { Type *IntPtrTy = DL.getIntPtrType(GEP->getType()); unsigned PtrSize = IntPtrTy->getIntegerBitWidth(); if (Idx->getType()->getPrimitiveSizeInBits() > PtrSize) Idx = Builder->CreateTrunc(Idx, IntPtrTy); } // If the comparison is only true for one or two elements, emit direct // comparisons. if (SecondTrueElement != Overdefined) { // None true -> false. if (FirstTrueElement == Undefined) return replaceInstUsesWith(ICI, Builder->getFalse()); Value *FirstTrueIdx = ConstantInt::get(Idx->getType(), FirstTrueElement); // True for one element -> 'i == 47'. if (SecondTrueElement == Undefined) return new ICmpInst(ICmpInst::ICMP_EQ, Idx, FirstTrueIdx); // True for two elements -> 'i == 47 | i == 72'. Value *C1 = Builder->CreateICmpEQ(Idx, FirstTrueIdx); Value *SecondTrueIdx = ConstantInt::get(Idx->getType(), SecondTrueElement); Value *C2 = Builder->CreateICmpEQ(Idx, SecondTrueIdx); return BinaryOperator::CreateOr(C1, C2); } // If the comparison is only false for one or two elements, emit direct // comparisons. if (SecondFalseElement != Overdefined) { // None false -> true. if (FirstFalseElement == Undefined) return replaceInstUsesWith(ICI, Builder->getTrue()); Value *FirstFalseIdx = ConstantInt::get(Idx->getType(), FirstFalseElement); // False for one element -> 'i != 47'. if (SecondFalseElement == Undefined) return new ICmpInst(ICmpInst::ICMP_NE, Idx, FirstFalseIdx); // False for two elements -> 'i != 47 & i != 72'. Value *C1 = Builder->CreateICmpNE(Idx, FirstFalseIdx); Value *SecondFalseIdx = ConstantInt::get(Idx->getType(),SecondFalseElement); Value *C2 = Builder->CreateICmpNE(Idx, SecondFalseIdx); return BinaryOperator::CreateAnd(C1, C2); } // If the comparison can be replaced with a range comparison for the elements // where it is true, emit the range check. if (TrueRangeEnd != Overdefined) { assert(TrueRangeEnd != FirstTrueElement && "Should emit single compare"); // Generate (i-FirstTrue) getType(), -FirstTrueElement); Idx = Builder->CreateAdd(Idx, Offs); } Value *End = ConstantInt::get(Idx->getType(), TrueRangeEnd-FirstTrueElement+1); return new ICmpInst(ICmpInst::ICMP_ULT, Idx, End); } // False range check. if (FalseRangeEnd != Overdefined) { assert(FalseRangeEnd != FirstFalseElement && "Should emit single compare"); // Generate (i-FirstFalse) >u (FalseRangeEnd-FirstFalse). if (FirstFalseElement) { Value *Offs = ConstantInt::get(Idx->getType(), -FirstFalseElement); Idx = Builder->CreateAdd(Idx, Offs); } Value *End = ConstantInt::get(Idx->getType(), FalseRangeEnd-FirstFalseElement); return new ICmpInst(ICmpInst::ICMP_UGT, Idx, End); } // If a magic bitvector captures the entire comparison state // of this load, replace it with computation that does: // ((magic_cst >> i) & 1) != 0 { Type *Ty = nullptr; // Look for an appropriate type: // - The type of Idx if the magic fits // - The smallest fitting legal type if we have a DataLayout // - Default to i32 if (ArrayElementCount <= Idx->getType()->getIntegerBitWidth()) Ty = Idx->getType(); else Ty = DL.getSmallestLegalIntType(Init->getContext(), ArrayElementCount); if (Ty) { Value *V = Builder->CreateIntCast(Idx, Ty, false); V = Builder->CreateLShr(ConstantInt::get(Ty, MagicBitvector), V); V = Builder->CreateAnd(ConstantInt::get(Ty, 1), V); return new ICmpInst(ICmpInst::ICMP_NE, V, ConstantInt::get(Ty, 0)); } } return nullptr; } /// Return a value that can be used to compare the *offset* implied by a GEP to /// zero. For example, if we have &A[i], we want to return 'i' for /// "icmp ne i, 0". Note that, in general, indices can be complex, and scales /// are involved. The above expression would also be legal to codegen as /// "icmp ne (i*4), 0" (assuming A is a pointer to i32). /// This latter form is less amenable to optimization though, and we are allowed /// to generate the first by knowing that pointer arithmetic doesn't overflow. /// /// If we can't emit an optimized form for this expression, this returns null. /// static Value *evaluateGEPOffsetExpression(User *GEP, InstCombiner &IC, const DataLayout &DL) { gep_type_iterator GTI = gep_type_begin(GEP); // Check to see if this gep only has a single variable index. If so, and if // any constant indices are a multiple of its scale, then we can compute this // in terms of the scale of the variable index. For example, if the GEP // implies an offset of "12 + i*4", then we can codegen this as "3 + i", // because the expression will cross zero at the same point. unsigned i, e = GEP->getNumOperands(); int64_t Offset = 0; for (i = 1; i != e; ++i, ++GTI) { if (ConstantInt *CI = dyn_cast(GEP->getOperand(i))) { // Compute the aggregate offset of constant indices. if (CI->isZero()) continue; // Handle a struct index, which adds its field offset to the pointer. if (StructType *STy = GTI.getStructTypeOrNull()) { Offset += DL.getStructLayout(STy)->getElementOffset(CI->getZExtValue()); } else { uint64_t Size = DL.getTypeAllocSize(GTI.getIndexedType()); Offset += Size*CI->getSExtValue(); } } else { // Found our variable index. break; } } // If there are no variable indices, we must have a constant offset, just // evaluate it the general way. if (i == e) return nullptr; Value *VariableIdx = GEP->getOperand(i); // Determine the scale factor of the variable element. For example, this is // 4 if the variable index is into an array of i32. uint64_t VariableScale = DL.getTypeAllocSize(GTI.getIndexedType()); // Verify that there are no other variable indices. If so, emit the hard way. for (++i, ++GTI; i != e; ++i, ++GTI) { ConstantInt *CI = dyn_cast(GEP->getOperand(i)); if (!CI) return nullptr; // Compute the aggregate offset of constant indices. if (CI->isZero()) continue; // Handle a struct index, which adds its field offset to the pointer. if (StructType *STy = GTI.getStructTypeOrNull()) { Offset += DL.getStructLayout(STy)->getElementOffset(CI->getZExtValue()); } else { uint64_t Size = DL.getTypeAllocSize(GTI.getIndexedType()); Offset += Size*CI->getSExtValue(); } } // Okay, we know we have a single variable index, which must be a // pointer/array/vector index. If there is no offset, life is simple, return // the index. Type *IntPtrTy = DL.getIntPtrType(GEP->getOperand(0)->getType()); unsigned IntPtrWidth = IntPtrTy->getIntegerBitWidth(); if (Offset == 0) { // Cast to intptrty in case a truncation occurs. If an extension is needed, // we don't need to bother extending: the extension won't affect where the // computation crosses zero. if (VariableIdx->getType()->getPrimitiveSizeInBits() > IntPtrWidth) { VariableIdx = IC.Builder->CreateTrunc(VariableIdx, IntPtrTy); } return VariableIdx; } // Otherwise, there is an index. The computation we will do will be modulo // the pointer size, so get it. uint64_t PtrSizeMask = ~0ULL >> (64-IntPtrWidth); Offset &= PtrSizeMask; VariableScale &= PtrSizeMask; // To do this transformation, any constant index must be a multiple of the // variable scale factor. For example, we can evaluate "12 + 4*i" as "3 + i", // but we can't evaluate "10 + 3*i" in terms of i. Check that the offset is a // multiple of the variable scale. int64_t NewOffs = Offset / (int64_t)VariableScale; if (Offset != NewOffs*(int64_t)VariableScale) return nullptr; // Okay, we can do this evaluation. Start by converting the index to intptr. if (VariableIdx->getType() != IntPtrTy) VariableIdx = IC.Builder->CreateIntCast(VariableIdx, IntPtrTy, true /*Signed*/); Constant *OffsetVal = ConstantInt::get(IntPtrTy, NewOffs); return IC.Builder->CreateAdd(VariableIdx, OffsetVal, "offset"); } /// Returns true if we can rewrite Start as a GEP with pointer Base /// and some integer offset. The nodes that need to be re-written /// for this transformation will be added to Explored. static bool canRewriteGEPAsOffset(Value *Start, Value *Base, const DataLayout &DL, SetVector &Explored) { SmallVector WorkList(1, Start); Explored.insert(Base); // The following traversal gives us an order which can be used // when doing the final transformation. Since in the final // transformation we create the PHI replacement instructions first, // we don't have to get them in any particular order. // // However, for other instructions we will have to traverse the // operands of an instruction first, which means that we have to // do a post-order traversal. while (!WorkList.empty()) { SetVector PHIs; while (!WorkList.empty()) { if (Explored.size() >= 100) return false; Value *V = WorkList.back(); if (Explored.count(V) != 0) { WorkList.pop_back(); continue; } if (!isa(V) && !isa(V) && !isa(V) && !isa(V)) // We've found some value that we can't explore which is different from // the base. Therefore we can't do this transformation. return false; if (isa(V) || isa(V)) { auto *CI = dyn_cast(V); if (!CI->isNoopCast(DL)) return false; if (Explored.count(CI->getOperand(0)) == 0) WorkList.push_back(CI->getOperand(0)); } if (auto *GEP = dyn_cast(V)) { // We're limiting the GEP to having one index. This will preserve // the original pointer type. We could handle more cases in the // future. if (GEP->getNumIndices() != 1 || !GEP->isInBounds() || GEP->getType() != Start->getType()) return false; if (Explored.count(GEP->getOperand(0)) == 0) WorkList.push_back(GEP->getOperand(0)); } if (WorkList.back() == V) { WorkList.pop_back(); // We've finished visiting this node, mark it as such. Explored.insert(V); } if (auto *PN = dyn_cast(V)) { // We cannot transform PHIs on unsplittable basic blocks. if (isa(PN->getParent()->getTerminator())) return false; Explored.insert(PN); PHIs.insert(PN); } } // Explore the PHI nodes further. for (auto *PN : PHIs) for (Value *Op : PN->incoming_values()) if (Explored.count(Op) == 0) WorkList.push_back(Op); } // Make sure that we can do this. Since we can't insert GEPs in a basic // block before a PHI node, we can't easily do this transformation if // we have PHI node users of transformed instructions. for (Value *Val : Explored) { for (Value *Use : Val->uses()) { auto *PHI = dyn_cast(Use); auto *Inst = dyn_cast(Val); if (Inst == Base || Inst == PHI || !Inst || !PHI || Explored.count(PHI) == 0) continue; if (PHI->getParent() == Inst->getParent()) return false; } } return true; } // Sets the appropriate insert point on Builder where we can add // a replacement Instruction for V (if that is possible). static void setInsertionPoint(IRBuilder<> &Builder, Value *V, bool Before = true) { if (auto *PHI = dyn_cast(V)) { Builder.SetInsertPoint(&*PHI->getParent()->getFirstInsertionPt()); return; } if (auto *I = dyn_cast(V)) { if (!Before) I = &*std::next(I->getIterator()); Builder.SetInsertPoint(I); return; } if (auto *A = dyn_cast(V)) { // Set the insertion point in the entry block. BasicBlock &Entry = A->getParent()->getEntryBlock(); Builder.SetInsertPoint(&*Entry.getFirstInsertionPt()); return; } // Otherwise, this is a constant and we don't need to set a new // insertion point. assert(isa(V) && "Setting insertion point for unknown value!"); } /// Returns a re-written value of Start as an indexed GEP using Base as a /// pointer. static Value *rewriteGEPAsOffset(Value *Start, Value *Base, const DataLayout &DL, SetVector &Explored) { // Perform all the substitutions. This is a bit tricky because we can // have cycles in our use-def chains. // 1. Create the PHI nodes without any incoming values. // 2. Create all the other values. // 3. Add the edges for the PHI nodes. // 4. Emit GEPs to get the original pointers. // 5. Remove the original instructions. Type *IndexType = IntegerType::get( Base->getContext(), DL.getPointerTypeSizeInBits(Start->getType())); DenseMap NewInsts; NewInsts[Base] = ConstantInt::getNullValue(IndexType); // Create the new PHI nodes, without adding any incoming values. for (Value *Val : Explored) { if (Val == Base) continue; // Create empty phi nodes. This avoids cyclic dependencies when creating // the remaining instructions. if (auto *PHI = dyn_cast(Val)) NewInsts[PHI] = PHINode::Create(IndexType, PHI->getNumIncomingValues(), PHI->getName() + ".idx", PHI); } IRBuilder<> Builder(Base->getContext()); // Create all the other instructions. for (Value *Val : Explored) { if (NewInsts.find(Val) != NewInsts.end()) continue; if (auto *CI = dyn_cast(Val)) { NewInsts[CI] = NewInsts[CI->getOperand(0)]; continue; } if (auto *GEP = dyn_cast(Val)) { Value *Index = NewInsts[GEP->getOperand(1)] ? NewInsts[GEP->getOperand(1)] : GEP->getOperand(1); setInsertionPoint(Builder, GEP); // Indices might need to be sign extended. GEPs will magically do // this, but we need to do it ourselves here. if (Index->getType()->getScalarSizeInBits() != NewInsts[GEP->getOperand(0)]->getType()->getScalarSizeInBits()) { Index = Builder.CreateSExtOrTrunc( Index, NewInsts[GEP->getOperand(0)]->getType(), GEP->getOperand(0)->getName() + ".sext"); } auto *Op = NewInsts[GEP->getOperand(0)]; if (isa(Op) && dyn_cast(Op)->isZero()) NewInsts[GEP] = Index; else NewInsts[GEP] = Builder.CreateNSWAdd( Op, Index, GEP->getOperand(0)->getName() + ".add"); continue; } if (isa(Val)) continue; llvm_unreachable("Unexpected instruction type"); } // Add the incoming values to the PHI nodes. for (Value *Val : Explored) { if (Val == Base) continue; // All the instructions have been created, we can now add edges to the // phi nodes. if (auto *PHI = dyn_cast(Val)) { PHINode *NewPhi = static_cast(NewInsts[PHI]); for (unsigned I = 0, E = PHI->getNumIncomingValues(); I < E; ++I) { Value *NewIncoming = PHI->getIncomingValue(I); if (NewInsts.find(NewIncoming) != NewInsts.end()) NewIncoming = NewInsts[NewIncoming]; NewPhi->addIncoming(NewIncoming, PHI->getIncomingBlock(I)); } } } for (Value *Val : Explored) { if (Val == Base) continue; // Depending on the type, for external users we have to emit // a GEP or a GEP + ptrtoint. setInsertionPoint(Builder, Val, false); // If required, create an inttoptr instruction for Base. Value *NewBase = Base; if (!Base->getType()->isPointerTy()) NewBase = Builder.CreateBitOrPointerCast(Base, Start->getType(), Start->getName() + "to.ptr"); Value *GEP = Builder.CreateInBoundsGEP( Start->getType()->getPointerElementType(), NewBase, makeArrayRef(NewInsts[Val]), Val->getName() + ".ptr"); if (!Val->getType()->isPointerTy()) { Value *Cast = Builder.CreatePointerCast(GEP, Val->getType(), Val->getName() + ".conv"); GEP = Cast; } Val->replaceAllUsesWith(GEP); } return NewInsts[Start]; } /// Looks through GEPs, IntToPtrInsts and PtrToIntInsts in order to express /// the input Value as a constant indexed GEP. Returns a pair containing /// the GEPs Pointer and Index. static std::pair getAsConstantIndexedAddress(Value *V, const DataLayout &DL) { Type *IndexType = IntegerType::get(V->getContext(), DL.getPointerTypeSizeInBits(V->getType())); Constant *Index = ConstantInt::getNullValue(IndexType); while (true) { if (GEPOperator *GEP = dyn_cast(V)) { // We accept only inbouds GEPs here to exclude the possibility of // overflow. if (!GEP->isInBounds()) break; if (GEP->hasAllConstantIndices() && GEP->getNumIndices() == 1 && GEP->getType() == V->getType()) { V = GEP->getOperand(0); Constant *GEPIndex = static_cast(GEP->getOperand(1)); Index = ConstantExpr::getAdd( Index, ConstantExpr::getSExtOrBitCast(GEPIndex, IndexType)); continue; } break; } if (auto *CI = dyn_cast(V)) { if (!CI->isNoopCast(DL)) break; V = CI->getOperand(0); continue; } if (auto *CI = dyn_cast(V)) { if (!CI->isNoopCast(DL)) break; V = CI->getOperand(0); continue; } break; } return {V, Index}; } /// Converts (CMP GEPLHS, RHS) if this change would make RHS a constant. /// We can look through PHIs, GEPs and casts in order to determine a common base /// between GEPLHS and RHS. static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS, ICmpInst::Predicate Cond, const DataLayout &DL) { if (!GEPLHS->hasAllConstantIndices()) return nullptr; + // Make sure the pointers have the same type. + if (GEPLHS->getType() != RHS->getType()) + return nullptr; + Value *PtrBase, *Index; std::tie(PtrBase, Index) = getAsConstantIndexedAddress(GEPLHS, DL); // The set of nodes that will take part in this transformation. SetVector Nodes; if (!canRewriteGEPAsOffset(RHS, PtrBase, DL, Nodes)) return nullptr; // We know we can re-write this as // ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) // Since we've only looked through inbouds GEPs we know that we // can't have overflow on either side. We can therefore re-write // this as: // OFFSET1 cmp OFFSET2 Value *NewRHS = rewriteGEPAsOffset(RHS, PtrBase, DL, Nodes); // RewriteGEPAsOffset has replaced RHS and all of its uses with a re-written // GEP having PtrBase as the pointer base, and has returned in NewRHS the // offset. Since Index is the offset of LHS to the base pointer, we will now // compare the offsets instead of comparing the pointers. return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Index, NewRHS); } /// Fold comparisons between a GEP instruction and something else. At this point /// we know that the GEP is on the LHS of the comparison. Instruction *InstCombiner::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, ICmpInst::Predicate Cond, Instruction &I) { // Don't transform signed compares of GEPs into index compares. Even if the // GEP is inbounds, the final add of the base pointer can have signed overflow // and would change the result of the icmp. // e.g. "&foo[0] (RHS)) RHS = RHS->stripPointerCasts(); Value *PtrBase = GEPLHS->getOperand(0); if (PtrBase == RHS && GEPLHS->isInBounds()) { // ((gep Ptr, OFFSET) cmp Ptr) ---> (OFFSET cmp 0). // This transformation (ignoring the base and scales) is valid because we // know pointers can't overflow since the gep is inbounds. See if we can // output an optimized form. Value *Offset = evaluateGEPOffsetExpression(GEPLHS, *this, DL); // If not, synthesize the offset the hard way. if (!Offset) Offset = EmitGEPOffset(GEPLHS); return new ICmpInst(ICmpInst::getSignedPredicate(Cond), Offset, Constant::getNullValue(Offset->getType())); } else if (GEPOperator *GEPRHS = dyn_cast(RHS)) { // If the base pointers are different, but the indices are the same, just // compare the base pointer. if (PtrBase != GEPRHS->getOperand(0)) { bool IndicesTheSame = GEPLHS->getNumOperands()==GEPRHS->getNumOperands(); IndicesTheSame &= GEPLHS->getOperand(0)->getType() == GEPRHS->getOperand(0)->getType(); if (IndicesTheSame) for (unsigned i = 1, e = GEPLHS->getNumOperands(); i != e; ++i) if (GEPLHS->getOperand(i) != GEPRHS->getOperand(i)) { IndicesTheSame = false; break; } // If all indices are the same, just compare the base pointers. if (IndicesTheSame) return new ICmpInst(Cond, GEPLHS->getOperand(0), GEPRHS->getOperand(0)); // If we're comparing GEPs with two base pointers that only differ in type // and both GEPs have only constant indices or just one use, then fold // the compare with the adjusted indices. if (GEPLHS->isInBounds() && GEPRHS->isInBounds() && (GEPLHS->hasAllConstantIndices() || GEPLHS->hasOneUse()) && (GEPRHS->hasAllConstantIndices() || GEPRHS->hasOneUse()) && PtrBase->stripPointerCasts() == GEPRHS->getOperand(0)->stripPointerCasts()) { Value *LOffset = EmitGEPOffset(GEPLHS); Value *ROffset = EmitGEPOffset(GEPRHS); // If we looked through an addrspacecast between different sized address // spaces, the LHS and RHS pointers are different sized // integers. Truncate to the smaller one. Type *LHSIndexTy = LOffset->getType(); Type *RHSIndexTy = ROffset->getType(); if (LHSIndexTy != RHSIndexTy) { if (LHSIndexTy->getPrimitiveSizeInBits() < RHSIndexTy->getPrimitiveSizeInBits()) { ROffset = Builder->CreateTrunc(ROffset, LHSIndexTy); } else LOffset = Builder->CreateTrunc(LOffset, RHSIndexTy); } Value *Cmp = Builder->CreateICmp(ICmpInst::getSignedPredicate(Cond), LOffset, ROffset); return replaceInstUsesWith(I, Cmp); } // Otherwise, the base pointers are different and the indices are // different. Try convert this to an indexed compare by looking through // PHIs/casts. return transformToIndexedCompare(GEPLHS, RHS, Cond, DL); } // If one of the GEPs has all zero indices, recurse. if (GEPLHS->hasAllZeroIndices()) return foldGEPICmp(GEPRHS, GEPLHS->getOperand(0), ICmpInst::getSwappedPredicate(Cond), I); // If the other GEP has all zero indices, recurse. if (GEPRHS->hasAllZeroIndices()) return foldGEPICmp(GEPLHS, GEPRHS->getOperand(0), Cond, I); bool GEPsInBounds = GEPLHS->isInBounds() && GEPRHS->isInBounds(); if (GEPLHS->getNumOperands() == GEPRHS->getNumOperands()) { // If the GEPs only differ by one index, compare it. unsigned NumDifferences = 0; // Keep track of # differences. unsigned DiffOperand = 0; // The operand that differs. for (unsigned i = 1, e = GEPRHS->getNumOperands(); i != e; ++i) if (GEPLHS->getOperand(i) != GEPRHS->getOperand(i)) { if (GEPLHS->getOperand(i)->getType()->getPrimitiveSizeInBits() != GEPRHS->getOperand(i)->getType()->getPrimitiveSizeInBits()) { // Irreconcilable differences. NumDifferences = 2; break; } else { if (NumDifferences++) break; DiffOperand = i; } } if (NumDifferences == 0) // SAME GEP? return replaceInstUsesWith(I, // No comparison is needed here. Builder->getInt1(ICmpInst::isTrueWhenEqual(Cond))); else if (NumDifferences == 1 && GEPsInBounds) { Value *LHSV = GEPLHS->getOperand(DiffOperand); Value *RHSV = GEPRHS->getOperand(DiffOperand); // Make sure we do a signed comparison here. return new ICmpInst(ICmpInst::getSignedPredicate(Cond), LHSV, RHSV); } } // Only lower this if the icmp is the only user of the GEP or if we expect // the result to fold to a constant! if (GEPsInBounds && (isa(GEPLHS) || GEPLHS->hasOneUse()) && (isa(GEPRHS) || GEPRHS->hasOneUse())) { // ((gep Ptr, OFFSET1) cmp (gep Ptr, OFFSET2) ---> (OFFSET1 cmp OFFSET2) Value *L = EmitGEPOffset(GEPLHS); Value *R = EmitGEPOffset(GEPRHS); return new ICmpInst(ICmpInst::getSignedPredicate(Cond), L, R); } } // Try convert this to an indexed compare by looking through PHIs/casts as a // last resort. return transformToIndexedCompare(GEPLHS, RHS, Cond, DL); } Instruction *InstCombiner::foldAllocaCmp(ICmpInst &ICI, const AllocaInst *Alloca, const Value *Other) { assert(ICI.isEquality() && "Cannot fold non-equality comparison."); // It would be tempting to fold away comparisons between allocas and any // pointer not based on that alloca (e.g. an argument). However, even // though such pointers cannot alias, they can still compare equal. // // But LLVM doesn't specify where allocas get their memory, so if the alloca // doesn't escape we can argue that it's impossible to guess its value, and we // can therefore act as if any such guesses are wrong. // // The code below checks that the alloca doesn't escape, and that it's only // used in a comparison once (the current instruction). The // single-comparison-use condition ensures that we're trivially folding all // comparisons against the alloca consistently, and avoids the risk of // erroneously folding a comparison of the pointer with itself. unsigned MaxIter = 32; // Break cycles and bound to constant-time. SmallVector Worklist; for (const Use &U : Alloca->uses()) { if (Worklist.size() >= MaxIter) return nullptr; Worklist.push_back(&U); } unsigned NumCmps = 0; while (!Worklist.empty()) { assert(Worklist.size() <= MaxIter); const Use *U = Worklist.pop_back_val(); const Value *V = U->getUser(); --MaxIter; if (isa(V) || isa(V) || isa(V) || isa(V)) { // Track the uses. } else if (isa(V)) { // Loading from the pointer doesn't escape it. continue; } else if (const auto *SI = dyn_cast(V)) { // Storing *to* the pointer is fine, but storing the pointer escapes it. if (SI->getValueOperand() == U->get()) return nullptr; continue; } else if (isa(V)) { if (NumCmps++) return nullptr; // Found more than one cmp. continue; } else if (const auto *Intrin = dyn_cast(V)) { switch (Intrin->getIntrinsicID()) { // These intrinsics don't escape or compare the pointer. Memset is safe // because we don't allow ptrtoint. Memcpy and memmove are safe because // we don't allow stores, so src cannot point to V. case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::dbg_declare: case Intrinsic::dbg_value: case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: continue; default: return nullptr; } } else { return nullptr; } for (const Use &U : V->uses()) { if (Worklist.size() >= MaxIter) return nullptr; Worklist.push_back(&U); } } Type *CmpTy = CmpInst::makeCmpResultType(Other->getType()); return replaceInstUsesWith( ICI, ConstantInt::get(CmpTy, !CmpInst::isTrueWhenEqual(ICI.getPredicate()))); } /// Fold "icmp pred (X+CI), X". Instruction *InstCombiner::foldICmpAddOpConst(Instruction &ICI, Value *X, ConstantInt *CI, ICmpInst::Predicate Pred) { // From this point on, we know that (X+C <= X) --> (X+C < X) because C != 0, // so the values can never be equal. Similarly for all other "or equals" // operators. // (X+1) X >u (MAXUINT-1) --> X == 255 // (X+2) X >u (MAXUINT-2) --> X > 253 // (X+MAXUINT) X >u (MAXUINT-MAXUINT) --> X != 0 if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) { Value *R = ConstantExpr::getSub(ConstantInt::getAllOnesValue(CI->getType()), CI); return new ICmpInst(ICmpInst::ICMP_UGT, X, R); } // (X+1) >u X --> X X != 255 // (X+2) >u X --> X X u X --> X X X == 0 if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) return new ICmpInst(ICmpInst::ICMP_ULT, X, ConstantExpr::getNeg(CI)); unsigned BitWidth = CI->getType()->getPrimitiveSizeInBits(); ConstantInt *SMax = ConstantInt::get(X->getContext(), APInt::getSignedMaxValue(BitWidth)); // (X+ 1) X >s (MAXSINT-1) --> X == 127 // (X+ 2) X >s (MAXSINT-2) --> X >s 125 // (X+MAXSINT) X >s (MAXSINT-MAXSINT) --> X >s 0 // (X+MINSINT) X >s (MAXSINT-MINSINT) --> X >s -1 // (X+ -2) X >s (MAXSINT- -2) --> X >s 126 // (X+ -1) X >s (MAXSINT- -1) --> X != 127 if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) return new ICmpInst(ICmpInst::ICMP_SGT, X, ConstantExpr::getSub(SMax, CI)); // (X+ 1) >s X --> X X != 127 // (X+ 2) >s X --> X X s X --> X X s X --> X X s X --> X X s X --> X X == -128 assert(Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE); Constant *C = Builder->getInt(CI->getValue()-1); return new ICmpInst(ICmpInst::ICMP_SLT, X, ConstantExpr::getSub(SMax, C)); } /// Handle "(icmp eq/ne (ashr/lshr AP2, A), AP1)" -> /// (icmp eq/ne A, Log2(AP2/AP1)) -> /// (icmp eq/ne A, Log2(AP2) - Log2(AP1)). Instruction *InstCombiner::foldICmpShrConstConst(ICmpInst &I, Value *A, const APInt &AP1, const APInt &AP2) { assert(I.isEquality() && "Cannot fold icmp gt/lt"); auto getICmp = [&I](CmpInst::Predicate Pred, Value *LHS, Value *RHS) { if (I.getPredicate() == I.ICMP_NE) Pred = CmpInst::getInversePredicate(Pred); return new ICmpInst(Pred, LHS, RHS); }; // Don't bother doing any work for cases which InstSimplify handles. if (AP2 == 0) return nullptr; bool IsAShr = isa(I.getOperand(0)); if (IsAShr) { if (AP2.isAllOnesValue()) return nullptr; if (AP2.isNegative() != AP1.isNegative()) return nullptr; if (AP2.sgt(AP1)) return nullptr; } if (!AP1) // 'A' must be large enough to shift out the highest set bit. return getICmp(I.ICMP_UGT, A, ConstantInt::get(A->getType(), AP2.logBase2())); if (AP1 == AP2) return getICmp(I.ICMP_EQ, A, ConstantInt::getNullValue(A->getType())); int Shift; if (IsAShr && AP1.isNegative()) Shift = AP1.countLeadingOnes() - AP2.countLeadingOnes(); else Shift = AP1.countLeadingZeros() - AP2.countLeadingZeros(); if (Shift > 0) { if (IsAShr && AP1 == AP2.ashr(Shift)) { // There are multiple solutions if we are comparing against -1 and the LHS // of the ashr is not a power of two. if (AP1.isAllOnesValue() && !AP2.isPowerOf2()) return getICmp(I.ICMP_UGE, A, ConstantInt::get(A->getType(), Shift)); return getICmp(I.ICMP_EQ, A, ConstantInt::get(A->getType(), Shift)); } else if (AP1 == AP2.lshr(Shift)) { return getICmp(I.ICMP_EQ, A, ConstantInt::get(A->getType(), Shift)); } } // Shifting const2 will never be equal to const1. // FIXME: This should always be handled by InstSimplify? auto *TorF = ConstantInt::get(I.getType(), I.getPredicate() == I.ICMP_NE); return replaceInstUsesWith(I, TorF); } /// Handle "(icmp eq/ne (shl AP2, A), AP1)" -> /// (icmp eq/ne A, TrailingZeros(AP1) - TrailingZeros(AP2)). Instruction *InstCombiner::foldICmpShlConstConst(ICmpInst &I, Value *A, const APInt &AP1, const APInt &AP2) { assert(I.isEquality() && "Cannot fold icmp gt/lt"); auto getICmp = [&I](CmpInst::Predicate Pred, Value *LHS, Value *RHS) { if (I.getPredicate() == I.ICMP_NE) Pred = CmpInst::getInversePredicate(Pred); return new ICmpInst(Pred, LHS, RHS); }; // Don't bother doing any work for cases which InstSimplify handles. if (AP2 == 0) return nullptr; unsigned AP2TrailingZeros = AP2.countTrailingZeros(); if (!AP1 && AP2TrailingZeros != 0) return getICmp( I.ICMP_UGE, A, ConstantInt::get(A->getType(), AP2.getBitWidth() - AP2TrailingZeros)); if (AP1 == AP2) return getICmp(I.ICMP_EQ, A, ConstantInt::getNullValue(A->getType())); // Get the distance between the lowest bits that are set. int Shift = AP1.countTrailingZeros() - AP2TrailingZeros; if (Shift > 0 && AP2.shl(Shift) == AP1) return getICmp(I.ICMP_EQ, A, ConstantInt::get(A->getType(), Shift)); // Shifting const2 will never be equal to const1. // FIXME: This should always be handled by InstSimplify? auto *TorF = ConstantInt::get(I.getType(), I.getPredicate() == I.ICMP_NE); return replaceInstUsesWith(I, TorF); } /// The caller has matched a pattern of the form: /// I = icmp ugt (add (add A, B), CI2), CI1 /// If this is of the form: /// sum = a + b /// if (sum+128 >u 255) /// Then replace it with llvm.sadd.with.overflow.i8. /// static Instruction *processUGT_ADDCST_ADD(ICmpInst &I, Value *A, Value *B, ConstantInt *CI2, ConstantInt *CI1, InstCombiner &IC) { // The transformation we're trying to do here is to transform this into an // llvm.sadd.with.overflow. To do this, we have to replace the original add // with a narrower add, and discard the add-with-constant that is part of the // range check (if we can't eliminate it, this isn't profitable). // In order to eliminate the add-with-constant, the compare can be its only // use. Instruction *AddWithCst = cast(I.getOperand(0)); if (!AddWithCst->hasOneUse()) return nullptr; // If CI2 is 2^7, 2^15, 2^31, then it might be an sadd.with.overflow. if (!CI2->getValue().isPowerOf2()) return nullptr; unsigned NewWidth = CI2->getValue().countTrailingZeros(); if (NewWidth != 7 && NewWidth != 15 && NewWidth != 31) return nullptr; // The width of the new add formed is 1 more than the bias. ++NewWidth; // Check to see that CI1 is an all-ones value with NewWidth bits. if (CI1->getBitWidth() == NewWidth || CI1->getValue() != APInt::getLowBitsSet(CI1->getBitWidth(), NewWidth)) return nullptr; // This is only really a signed overflow check if the inputs have been // sign-extended; check for that condition. For example, if CI2 is 2^31 and // the operands of the add are 64 bits wide, we need at least 33 sign bits. unsigned NeededSignBits = CI1->getBitWidth() - NewWidth + 1; if (IC.ComputeNumSignBits(A, 0, &I) < NeededSignBits || IC.ComputeNumSignBits(B, 0, &I) < NeededSignBits) return nullptr; // In order to replace the original add with a narrower // llvm.sadd.with.overflow, the only uses allowed are the add-with-constant // and truncates that discard the high bits of the add. Verify that this is // the case. Instruction *OrigAdd = cast(AddWithCst->getOperand(0)); for (User *U : OrigAdd->users()) { if (U == AddWithCst) continue; // Only accept truncates for now. We would really like a nice recursive // predicate like SimplifyDemandedBits, but which goes downwards the use-def // chain to see which bits of a value are actually demanded. If the // original add had another add which was then immediately truncated, we // could still do the transformation. TruncInst *TI = dyn_cast(U); if (!TI || TI->getType()->getPrimitiveSizeInBits() > NewWidth) return nullptr; } // If the pattern matches, truncate the inputs to the narrower type and // use the sadd_with_overflow intrinsic to efficiently compute both the // result and the overflow bit. Type *NewType = IntegerType::get(OrigAdd->getContext(), NewWidth); Value *F = Intrinsic::getDeclaration(I.getModule(), Intrinsic::sadd_with_overflow, NewType); InstCombiner::BuilderTy *Builder = IC.Builder; // Put the new code above the original add, in case there are any uses of the // add between the add and the compare. Builder->SetInsertPoint(OrigAdd); Value *TruncA = Builder->CreateTrunc(A, NewType, A->getName() + ".trunc"); Value *TruncB = Builder->CreateTrunc(B, NewType, B->getName() + ".trunc"); CallInst *Call = Builder->CreateCall(F, {TruncA, TruncB}, "sadd"); Value *Add = Builder->CreateExtractValue(Call, 0, "sadd.result"); Value *ZExt = Builder->CreateZExt(Add, OrigAdd->getType()); // The inner add was the result of the narrow add, zero extended to the // wider type. Replace it with the result computed by the intrinsic. IC.replaceInstUsesWith(*OrigAdd, ZExt); // The original icmp gets replaced with the overflow value. return ExtractValueInst::Create(Call, 1, "sadd.overflow"); } // Fold icmp Pred X, C. Instruction *InstCombiner::foldICmpWithConstant(ICmpInst &Cmp) { CmpInst::Predicate Pred = Cmp.getPredicate(); Value *X = Cmp.getOperand(0); const APInt *C; if (!match(Cmp.getOperand(1), m_APInt(C))) return nullptr; Value *A = nullptr, *B = nullptr; // Match the following pattern, which is a common idiom when writing // overflow-safe integer arithmetic functions. The source performs an addition // in wider type and explicitly checks for overflow using comparisons against // INT_MIN and INT_MAX. Simplify by using the sadd_with_overflow intrinsic. // // TODO: This could probably be generalized to handle other overflow-safe // operations if we worked out the formulas to compute the appropriate magic // constants. // // sum = a + b // if (sum+128 >u 255) ... -> llvm.sadd.with.overflow.i8 { ConstantInt *CI2; // I = icmp ugt (add (add A, B), CI2), CI if (Pred == ICmpInst::ICMP_UGT && match(X, m_Add(m_Add(m_Value(A), m_Value(B)), m_ConstantInt(CI2)))) if (Instruction *Res = processUGT_ADDCST_ADD( Cmp, A, B, CI2, cast(Cmp.getOperand(1)), *this)) return Res; } // (icmp sgt smin(PosA, B) 0) -> (icmp sgt B 0) if (*C == 0 && Pred == ICmpInst::ICMP_SGT) { SelectPatternResult SPR = matchSelectPattern(X, A, B); if (SPR.Flavor == SPF_SMIN) { if (isKnownPositive(A, DL)) return new ICmpInst(Pred, B, Cmp.getOperand(1)); if (isKnownPositive(B, DL)) return new ICmpInst(Pred, A, Cmp.getOperand(1)); } } // FIXME: Use m_APInt to allow folds for splat constants. ConstantInt *CI = dyn_cast(Cmp.getOperand(1)); if (!CI) return nullptr; // Canonicalize icmp instructions based on dominating conditions. BasicBlock *Parent = Cmp.getParent(); BasicBlock *Dom = Parent->getSinglePredecessor(); auto *BI = Dom ? dyn_cast(Dom->getTerminator()) : nullptr; ICmpInst::Predicate Pred2; BasicBlock *TrueBB, *FalseBB; ConstantInt *CI2; if (BI && match(BI, m_Br(m_ICmp(Pred2, m_Specific(X), m_ConstantInt(CI2)), TrueBB, FalseBB)) && TrueBB != FalseBB) { ConstantRange CR = ConstantRange::makeAllowedICmpRegion(Pred, CI->getValue()); ConstantRange DominatingCR = (Parent == TrueBB) ? ConstantRange::makeExactICmpRegion(Pred2, CI2->getValue()) : ConstantRange::makeExactICmpRegion( CmpInst::getInversePredicate(Pred2), CI2->getValue()); ConstantRange Intersection = DominatingCR.intersectWith(CR); ConstantRange Difference = DominatingCR.difference(CR); if (Intersection.isEmptySet()) return replaceInstUsesWith(Cmp, Builder->getFalse()); if (Difference.isEmptySet()) return replaceInstUsesWith(Cmp, Builder->getTrue()); // If this is a normal comparison, it demands all bits. If it is a sign // bit comparison, it only demands the sign bit. bool UnusedBit; bool IsSignBit = isSignBitCheck(Pred, CI->getValue(), UnusedBit); // Canonicalizing a sign bit comparison that gets used in a branch, // pessimizes codegen by generating branch on zero instruction instead // of a test and branch. So we avoid canonicalizing in such situations // because test and branch instruction has better branch displacement // than compare and branch instruction. if (!isBranchOnSignBitCheck(Cmp, IsSignBit) && !Cmp.isEquality()) { if (auto *AI = Intersection.getSingleElement()) return new ICmpInst(ICmpInst::ICMP_EQ, X, Builder->getInt(*AI)); if (auto *AD = Difference.getSingleElement()) return new ICmpInst(ICmpInst::ICMP_NE, X, Builder->getInt(*AD)); } } return nullptr; } /// Fold icmp (trunc X, Y), C. Instruction *InstCombiner::foldICmpTruncConstant(ICmpInst &Cmp, Instruction *Trunc, const APInt *C) { ICmpInst::Predicate Pred = Cmp.getPredicate(); Value *X = Trunc->getOperand(0); if (*C == 1 && C->getBitWidth() > 1) { // icmp slt trunc(signum(V)) 1 --> icmp slt V, 1 Value *V = nullptr; if (Pred == ICmpInst::ICMP_SLT && match(X, m_Signum(m_Value(V)))) return new ICmpInst(ICmpInst::ICMP_SLT, V, ConstantInt::get(V->getType(), 1)); } if (Cmp.isEquality() && Trunc->hasOneUse()) { // Simplify icmp eq (trunc x to i8), 42 -> icmp eq x, 42|highbits if all // of the high bits truncated out of x are known. unsigned DstBits = Trunc->getType()->getScalarSizeInBits(), SrcBits = X->getType()->getScalarSizeInBits(); APInt KnownZero(SrcBits, 0), KnownOne(SrcBits, 0); computeKnownBits(X, KnownZero, KnownOne, 0, &Cmp); // If all the high bits are known, we can do this xform. if ((KnownZero | KnownOne).countLeadingOnes() >= SrcBits - DstBits) { // Pull in the high bits from known-ones set. APInt NewRHS = C->zext(SrcBits); NewRHS |= KnownOne & APInt::getHighBitsSet(SrcBits, SrcBits - DstBits); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), NewRHS)); } } return nullptr; } /// Fold icmp (xor X, Y), C. Instruction *InstCombiner::foldICmpXorConstant(ICmpInst &Cmp, BinaryOperator *Xor, const APInt *C) { Value *X = Xor->getOperand(0); Value *Y = Xor->getOperand(1); const APInt *XorC; if (!match(Y, m_APInt(XorC))) return nullptr; // If this is a comparison that tests the signbit (X < 0) or (x > -1), // fold the xor. ICmpInst::Predicate Pred = Cmp.getPredicate(); if ((Pred == ICmpInst::ICMP_SLT && *C == 0) || (Pred == ICmpInst::ICMP_SGT && C->isAllOnesValue())) { // If the sign bit of the XorCst is not set, there is no change to // the operation, just stop using the Xor. if (!XorC->isNegative()) { Cmp.setOperand(0, X); Worklist.Add(Xor); return &Cmp; } // Was the old condition true if the operand is positive? bool isTrueIfPositive = Pred == ICmpInst::ICMP_SGT; // If so, the new one isn't. isTrueIfPositive ^= true; Constant *CmpConstant = cast(Cmp.getOperand(1)); if (isTrueIfPositive) return new ICmpInst(ICmpInst::ICMP_SGT, X, SubOne(CmpConstant)); else return new ICmpInst(ICmpInst::ICMP_SLT, X, AddOne(CmpConstant)); } if (Xor->hasOneUse()) { // (icmp u/s (xor X SignBit), C) -> (icmp s/u X, (xor C SignBit)) if (!Cmp.isEquality() && XorC->isSignBit()) { Pred = Cmp.isSigned() ? Cmp.getUnsignedPredicate() : Cmp.getSignedPredicate(); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), *C ^ *XorC)); } // (icmp u/s (xor X ~SignBit), C) -> (icmp s/u X, (xor C ~SignBit)) if (!Cmp.isEquality() && XorC->isMaxSignedValue()) { Pred = Cmp.isSigned() ? Cmp.getUnsignedPredicate() : Cmp.getSignedPredicate(); Pred = Cmp.getSwappedPredicate(Pred); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), *C ^ *XorC)); } } // (icmp ugt (xor X, C), ~C) -> (icmp ult X, C) // iff -C is a power of 2 if (Pred == ICmpInst::ICMP_UGT && *XorC == ~(*C) && (*C + 1).isPowerOf2()) return new ICmpInst(ICmpInst::ICMP_ULT, X, Y); // (icmp ult (xor X, C), -C) -> (icmp uge X, C) // iff -C is a power of 2 if (Pred == ICmpInst::ICMP_ULT && *XorC == -(*C) && C->isPowerOf2()) return new ICmpInst(ICmpInst::ICMP_UGE, X, Y); return nullptr; } /// Fold icmp (and (sh X, Y), C2), C1. Instruction *InstCombiner::foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And, const APInt *C1, const APInt *C2) { BinaryOperator *Shift = dyn_cast(And->getOperand(0)); if (!Shift || !Shift->isShift()) return nullptr; // If this is: (X >> C3) & C2 != C1 (where any shift and any compare could // exist), turn it into (X & (C2 << C3)) != (C1 << C3). This happens a LOT in // code produced by the clang front-end, for bitfield access. // This seemingly simple opportunity to fold away a shift turns out to be // rather complicated. See PR17827 for details. unsigned ShiftOpcode = Shift->getOpcode(); bool IsShl = ShiftOpcode == Instruction::Shl; const APInt *C3; if (match(Shift->getOperand(1), m_APInt(C3))) { bool CanFold = false; if (ShiftOpcode == Instruction::AShr) { // There may be some constraints that make this possible, but nothing // simple has been discovered yet. CanFold = false; } else if (ShiftOpcode == Instruction::Shl) { // For a left shift, we can fold if the comparison is not signed. We can // also fold a signed comparison if the mask value and comparison value // are not negative. These constraints may not be obvious, but we can // prove that they are correct using an SMT solver. if (!Cmp.isSigned() || (!C2->isNegative() && !C1->isNegative())) CanFold = true; } else if (ShiftOpcode == Instruction::LShr) { // For a logical right shift, we can fold if the comparison is not signed. // We can also fold a signed comparison if the shifted mask value and the // shifted comparison value are not negative. These constraints may not be // obvious, but we can prove that they are correct using an SMT solver. if (!Cmp.isSigned() || (!C2->shl(*C3).isNegative() && !C1->shl(*C3).isNegative())) CanFold = true; } if (CanFold) { APInt NewCst = IsShl ? C1->lshr(*C3) : C1->shl(*C3); APInt SameAsC1 = IsShl ? NewCst.shl(*C3) : NewCst.lshr(*C3); // Check to see if we are shifting out any of the bits being compared. if (SameAsC1 != *C1) { // If we shifted bits out, the fold is not going to work out. As a // special case, check to see if this means that the result is always // true or false now. if (Cmp.getPredicate() == ICmpInst::ICMP_EQ) return replaceInstUsesWith(Cmp, ConstantInt::getFalse(Cmp.getType())); if (Cmp.getPredicate() == ICmpInst::ICMP_NE) return replaceInstUsesWith(Cmp, ConstantInt::getTrue(Cmp.getType())); } else { Cmp.setOperand(1, ConstantInt::get(And->getType(), NewCst)); APInt NewAndCst = IsShl ? C2->lshr(*C3) : C2->shl(*C3); And->setOperand(1, ConstantInt::get(And->getType(), NewAndCst)); And->setOperand(0, Shift->getOperand(0)); Worklist.Add(Shift); // Shift is dead. return &Cmp; } } } // Turn ((X >> Y) & C2) == 0 into (X & (C2 << Y)) == 0. The latter is // preferable because it allows the C2 << Y expression to be hoisted out of a // loop if Y is invariant and X is not. if (Shift->hasOneUse() && *C1 == 0 && Cmp.isEquality() && !Shift->isArithmeticShift() && !isa(Shift->getOperand(0))) { // Compute C2 << Y. Value *NewShift = IsShl ? Builder->CreateLShr(And->getOperand(1), Shift->getOperand(1)) : Builder->CreateShl(And->getOperand(1), Shift->getOperand(1)); // Compute X & (C2 << Y). Value *NewAnd = Builder->CreateAnd(Shift->getOperand(0), NewShift); Cmp.setOperand(0, NewAnd); return &Cmp; } return nullptr; } /// Fold icmp (and X, C2), C1. Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, BinaryOperator *And, const APInt *C1) { const APInt *C2; if (!match(And->getOperand(1), m_APInt(C2))) return nullptr; if (!And->hasOneUse() || !And->getOperand(0)->hasOneUse()) return nullptr; // If the LHS is an 'and' of a truncate and we can widen the and/compare to // the input width without changing the value produced, eliminate the cast: // // icmp (and (trunc W), C2), C1 -> icmp (and W, C2'), C1' // // We can do this transformation if the constants do not have their sign bits // set or if it is an equality comparison. Extending a relational comparison // when we're checking the sign bit would not work. Value *W; if (match(And->getOperand(0), m_Trunc(m_Value(W))) && (Cmp.isEquality() || (!C1->isNegative() && !C2->isNegative()))) { // TODO: Is this a good transform for vectors? Wider types may reduce // throughput. Should this transform be limited (even for scalars) by using // ShouldChangeType()? if (!Cmp.getType()->isVectorTy()) { Type *WideType = W->getType(); unsigned WideScalarBits = WideType->getScalarSizeInBits(); Constant *ZextC1 = ConstantInt::get(WideType, C1->zext(WideScalarBits)); Constant *ZextC2 = ConstantInt::get(WideType, C2->zext(WideScalarBits)); Value *NewAnd = Builder->CreateAnd(W, ZextC2, And->getName()); return new ICmpInst(Cmp.getPredicate(), NewAnd, ZextC1); } } if (Instruction *I = foldICmpAndShift(Cmp, And, C1, C2)) return I; // (icmp pred (and (or (lshr A, B), A), 1), 0) --> // (icmp pred (and A, (or (shl 1, B), 1), 0)) // // iff pred isn't signed if (!Cmp.isSigned() && *C1 == 0 && match(And->getOperand(1), m_One())) { Constant *One = cast(And->getOperand(1)); Value *Or = And->getOperand(0); Value *A, *B, *LShr; if (match(Or, m_Or(m_Value(LShr), m_Value(A))) && match(LShr, m_LShr(m_Specific(A), m_Value(B)))) { unsigned UsesRemoved = 0; if (And->hasOneUse()) ++UsesRemoved; if (Or->hasOneUse()) ++UsesRemoved; if (LShr->hasOneUse()) ++UsesRemoved; // Compute A & ((1 << B) | 1) Value *NewOr = nullptr; if (auto *C = dyn_cast(B)) { if (UsesRemoved >= 1) NewOr = ConstantExpr::getOr(ConstantExpr::getNUWShl(One, C), One); } else { if (UsesRemoved >= 3) NewOr = Builder->CreateOr(Builder->CreateShl(One, B, LShr->getName(), /*HasNUW=*/true), One, Or->getName()); } if (NewOr) { Value *NewAnd = Builder->CreateAnd(A, NewOr, And->getName()); Cmp.setOperand(0, NewAnd); return &Cmp; } } } // (X & C2) > C1 --> (X & C2) != 0, if any bit set in (X & C2) will produce a // result greater than C1. unsigned NumTZ = C2->countTrailingZeros(); if (Cmp.getPredicate() == ICmpInst::ICMP_UGT && NumTZ < C2->getBitWidth() && APInt::getOneBitSet(C2->getBitWidth(), NumTZ).ugt(*C1)) { Constant *Zero = Constant::getNullValue(And->getType()); return new ICmpInst(ICmpInst::ICMP_NE, And, Zero); } return nullptr; } /// Fold icmp (and X, Y), C. Instruction *InstCombiner::foldICmpAndConstant(ICmpInst &Cmp, BinaryOperator *And, const APInt *C) { if (Instruction *I = foldICmpAndConstConst(Cmp, And, C)) return I; // TODO: These all require that Y is constant too, so refactor with the above. // Try to optimize things like "A[i] & 42 == 0" to index computations. Value *X = And->getOperand(0); Value *Y = And->getOperand(1); if (auto *LI = dyn_cast(X)) if (auto *GEP = dyn_cast(LI->getOperand(0))) if (auto *GV = dyn_cast(GEP->getOperand(0))) if (GV->isConstant() && GV->hasDefinitiveInitializer() && !LI->isVolatile() && isa(Y)) { ConstantInt *C2 = cast(Y); if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, Cmp, C2)) return Res; } if (!Cmp.isEquality()) return nullptr; // X & -C == -C -> X > u ~C // X & -C != -C -> X <= u ~C // iff C is a power of 2 if (Cmp.getOperand(1) == Y && (-(*C)).isPowerOf2()) { auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_UGT : CmpInst::ICMP_ULE; return new ICmpInst(NewPred, X, SubOne(cast(Cmp.getOperand(1)))); } // (X & C2) == 0 -> (trunc X) >= 0 // (X & C2) != 0 -> (trunc X) < 0 // iff C2 is a power of 2 and it masks the sign bit of a legal integer type. const APInt *C2; if (And->hasOneUse() && *C == 0 && match(Y, m_APInt(C2))) { int32_t ExactLogBase2 = C2->exactLogBase2(); if (ExactLogBase2 != -1 && DL.isLegalInteger(ExactLogBase2 + 1)) { Type *NTy = IntegerType::get(Cmp.getContext(), ExactLogBase2 + 1); if (And->getType()->isVectorTy()) NTy = VectorType::get(NTy, And->getType()->getVectorNumElements()); Value *Trunc = Builder->CreateTrunc(X, NTy); auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE : CmpInst::ICMP_SLT; return new ICmpInst(NewPred, Trunc, Constant::getNullValue(NTy)); } } return nullptr; } /// Fold icmp (or X, Y), C. Instruction *InstCombiner::foldICmpOrConstant(ICmpInst &Cmp, BinaryOperator *Or, const APInt *C) { ICmpInst::Predicate Pred = Cmp.getPredicate(); if (*C == 1) { // icmp slt signum(V) 1 --> icmp slt V, 1 Value *V = nullptr; if (Pred == ICmpInst::ICMP_SLT && match(Or, m_Signum(m_Value(V)))) return new ICmpInst(ICmpInst::ICMP_SLT, V, ConstantInt::get(V->getType(), 1)); } if (!Cmp.isEquality() || *C != 0 || !Or->hasOneUse()) return nullptr; Value *P, *Q; if (match(Or, m_Or(m_PtrToInt(m_Value(P)), m_PtrToInt(m_Value(Q))))) { // Simplify icmp eq (or (ptrtoint P), (ptrtoint Q)), 0 // -> and (icmp eq P, null), (icmp eq Q, null). Value *CmpP = Builder->CreateICmp(Pred, P, ConstantInt::getNullValue(P->getType())); Value *CmpQ = Builder->CreateICmp(Pred, Q, ConstantInt::getNullValue(Q->getType())); auto LogicOpc = Pred == ICmpInst::Predicate::ICMP_EQ ? Instruction::And : Instruction::Or; return BinaryOperator::Create(LogicOpc, CmpP, CmpQ); } return nullptr; } /// Fold icmp (mul X, Y), C. Instruction *InstCombiner::foldICmpMulConstant(ICmpInst &Cmp, BinaryOperator *Mul, const APInt *C) { const APInt *MulC; if (!match(Mul->getOperand(1), m_APInt(MulC))) return nullptr; // If this is a test of the sign bit and the multiply is sign-preserving with // a constant operand, use the multiply LHS operand instead. ICmpInst::Predicate Pred = Cmp.getPredicate(); if (isSignTest(Pred, *C) && Mul->hasNoSignedWrap()) { if (MulC->isNegative()) Pred = ICmpInst::getSwappedPredicate(Pred); return new ICmpInst(Pred, Mul->getOperand(0), Constant::getNullValue(Mul->getType())); } return nullptr; } /// Fold icmp (shl 1, Y), C. static Instruction *foldICmpShlOne(ICmpInst &Cmp, Instruction *Shl, const APInt *C) { Value *Y; if (!match(Shl, m_Shl(m_One(), m_Value(Y)))) return nullptr; Type *ShiftType = Shl->getType(); uint32_t TypeBits = C->getBitWidth(); bool CIsPowerOf2 = C->isPowerOf2(); ICmpInst::Predicate Pred = Cmp.getPredicate(); if (Cmp.isUnsigned()) { // (1 << Y) pred C -> Y pred Log2(C) if (!CIsPowerOf2) { // (1 << Y) < 30 -> Y <= 4 // (1 << Y) <= 30 -> Y <= 4 // (1 << Y) >= 30 -> Y > 4 // (1 << Y) > 30 -> Y > 4 if (Pred == ICmpInst::ICMP_ULT) Pred = ICmpInst::ICMP_ULE; else if (Pred == ICmpInst::ICMP_UGE) Pred = ICmpInst::ICMP_UGT; } // (1 << Y) >= 2147483648 -> Y >= 31 -> Y == 31 // (1 << Y) < 2147483648 -> Y < 31 -> Y != 31 unsigned CLog2 = C->logBase2(); if (CLog2 == TypeBits - 1) { if (Pred == ICmpInst::ICMP_UGE) Pred = ICmpInst::ICMP_EQ; else if (Pred == ICmpInst::ICMP_ULT) Pred = ICmpInst::ICMP_NE; } return new ICmpInst(Pred, Y, ConstantInt::get(ShiftType, CLog2)); } else if (Cmp.isSigned()) { Constant *BitWidthMinusOne = ConstantInt::get(ShiftType, TypeBits - 1); if (C->isAllOnesValue()) { // (1 << Y) <= -1 -> Y == 31 if (Pred == ICmpInst::ICMP_SLE) return new ICmpInst(ICmpInst::ICMP_EQ, Y, BitWidthMinusOne); // (1 << Y) > -1 -> Y != 31 if (Pred == ICmpInst::ICMP_SGT) return new ICmpInst(ICmpInst::ICMP_NE, Y, BitWidthMinusOne); } else if (!(*C)) { // (1 << Y) < 0 -> Y == 31 // (1 << Y) <= 0 -> Y == 31 if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) return new ICmpInst(ICmpInst::ICMP_EQ, Y, BitWidthMinusOne); // (1 << Y) >= 0 -> Y != 31 // (1 << Y) > 0 -> Y != 31 if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) return new ICmpInst(ICmpInst::ICMP_NE, Y, BitWidthMinusOne); } } else if (Cmp.isEquality() && CIsPowerOf2) { return new ICmpInst(Pred, Y, ConstantInt::get(ShiftType, C->logBase2())); } return nullptr; } /// Fold icmp (shl X, Y), C. Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp, BinaryOperator *Shl, const APInt *C) { const APInt *ShiftVal; if (Cmp.isEquality() && match(Shl->getOperand(0), m_APInt(ShiftVal))) return foldICmpShlConstConst(Cmp, Shl->getOperand(1), *C, *ShiftVal); const APInt *ShiftAmt; if (!match(Shl->getOperand(1), m_APInt(ShiftAmt))) return foldICmpShlOne(Cmp, Shl, C); // Check that the shift amount is in range. If not, don't perform undefined // shifts. When the shift is visited, it will be simplified. unsigned TypeBits = C->getBitWidth(); if (ShiftAmt->uge(TypeBits)) return nullptr; ICmpInst::Predicate Pred = Cmp.getPredicate(); Value *X = Shl->getOperand(0); if (Cmp.isEquality()) { // If the shift is NUW, then it is just shifting out zeros, no need for an // AND. Constant *LShrC = ConstantInt::get(Shl->getType(), C->lshr(*ShiftAmt)); if (Shl->hasNoUnsignedWrap()) return new ICmpInst(Pred, X, LShrC); // If the shift is NSW and we compare to 0, then it is just shifting out // sign bits, no need for an AND either. if (Shl->hasNoSignedWrap() && *C == 0) return new ICmpInst(Pred, X, LShrC); if (Shl->hasOneUse()) { // Otherwise, strength reduce the shift into an and. Constant *Mask = ConstantInt::get(Shl->getType(), APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt->getZExtValue())); Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask"); return new ICmpInst(Pred, And, LShrC); } } // If this is a signed comparison to 0 and the shift is sign preserving, // use the shift LHS operand instead; isSignTest may change 'Pred', so only // do that if we're sure to not continue on in this function. if (Shl->hasNoSignedWrap() && isSignTest(Pred, *C)) return new ICmpInst(Pred, X, Constant::getNullValue(X->getType())); // Otherwise, if this is a comparison of the sign bit, simplify to and/test. bool TrueIfSigned = false; if (Shl->hasOneUse() && isSignBitCheck(Pred, *C, TrueIfSigned)) { // (X << 31) (X & 1) != 0 Constant *Mask = ConstantInt::get( X->getType(), APInt::getOneBitSet(TypeBits, TypeBits - ShiftAmt->getZExtValue() - 1)); Value *And = Builder->CreateAnd(X, Mask, Shl->getName() + ".mask"); return new ICmpInst(TrueIfSigned ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ, And, Constant::getNullValue(And->getType())); } // When the shift is nuw and pred is >u or <=u, comparison only really happens // in the pre-shifted bits. Since InstSimplify canonicalizes <=u into hasNoUnsignedWrap() && (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT)) { // Derivation for the ult case: // (X << S) <=u C is equiv to X <=u (C >> S) for all C // (X << S) > S) + 1 if C > S) + 1 if C >u 0 assert((Pred != ICmpInst::ICMP_ULT || C->ugt(0)) && "Encountered `ult 0` that should have been eliminated by " "InstSimplify."); APInt ShiftedC = Pred == ICmpInst::ICMP_ULT ? (*C - 1).lshr(*ShiftAmt) + 1 : C->lshr(*ShiftAmt); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), ShiftedC)); } // Transform (icmp pred iM (shl iM %v, N), C) // -> (icmp pred i(M-N) (trunc %v iM to i(M-N)), (trunc (C>>N)) // Transform the shl to a trunc if (trunc (C>>N)) has no loss and M-N. // This enables us to get rid of the shift in favor of a trunc that may be // free on the target. It has the additional benefit of comparing to a // smaller constant that may be more target-friendly. unsigned Amt = ShiftAmt->getLimitedValue(TypeBits - 1); if (Shl->hasOneUse() && Amt != 0 && C->countTrailingZeros() >= Amt && DL.isLegalInteger(TypeBits - Amt)) { Type *TruncTy = IntegerType::get(Cmp.getContext(), TypeBits - Amt); if (X->getType()->isVectorTy()) TruncTy = VectorType::get(TruncTy, X->getType()->getVectorNumElements()); Constant *NewC = ConstantInt::get(TruncTy, C->ashr(*ShiftAmt).trunc(TypeBits - Amt)); return new ICmpInst(Pred, Builder->CreateTrunc(X, TruncTy), NewC); } return nullptr; } /// Fold icmp ({al}shr X, Y), C. Instruction *InstCombiner::foldICmpShrConstant(ICmpInst &Cmp, BinaryOperator *Shr, const APInt *C) { // An exact shr only shifts out zero bits, so: // icmp eq/ne (shr X, Y), 0 --> icmp eq/ne X, 0 Value *X = Shr->getOperand(0); CmpInst::Predicate Pred = Cmp.getPredicate(); if (Cmp.isEquality() && Shr->isExact() && Shr->hasOneUse() && *C == 0) return new ICmpInst(Pred, X, Cmp.getOperand(1)); const APInt *ShiftVal; if (Cmp.isEquality() && match(Shr->getOperand(0), m_APInt(ShiftVal))) return foldICmpShrConstConst(Cmp, Shr->getOperand(1), *C, *ShiftVal); const APInt *ShiftAmt; if (!match(Shr->getOperand(1), m_APInt(ShiftAmt))) return nullptr; // Check that the shift amount is in range. If not, don't perform undefined // shifts. When the shift is visited it will be simplified. unsigned TypeBits = C->getBitWidth(); unsigned ShAmtVal = ShiftAmt->getLimitedValue(TypeBits); if (ShAmtVal >= TypeBits || ShAmtVal == 0) return nullptr; bool IsAShr = Shr->getOpcode() == Instruction::AShr; if (!Cmp.isEquality()) { // If we have an unsigned comparison and an ashr, we can't simplify this. // Similarly for signed comparisons with lshr. if (Cmp.isSigned() != IsAShr) return nullptr; // Otherwise, all lshr and most exact ashr's are equivalent to a udiv/sdiv // by a power of 2. Since we already have logic to simplify these, // transform to div and then simplify the resultant comparison. if (IsAShr && (!Shr->isExact() || ShAmtVal == TypeBits - 1)) return nullptr; // Revisit the shift (to delete it). Worklist.Add(Shr); Constant *DivCst = ConstantInt::get( Shr->getType(), APInt::getOneBitSet(TypeBits, ShAmtVal)); Value *Tmp = IsAShr ? Builder->CreateSDiv(X, DivCst, "", Shr->isExact()) : Builder->CreateUDiv(X, DivCst, "", Shr->isExact()); Cmp.setOperand(0, Tmp); // If the builder folded the binop, just return it. BinaryOperator *TheDiv = dyn_cast(Tmp); if (!TheDiv) return &Cmp; // Otherwise, fold this div/compare. assert(TheDiv->getOpcode() == Instruction::SDiv || TheDiv->getOpcode() == Instruction::UDiv); Instruction *Res = foldICmpDivConstant(Cmp, TheDiv, C); assert(Res && "This div/cst should have folded!"); return Res; } // Handle equality comparisons of shift-by-constant. // If the comparison constant changes with the shift, the comparison cannot // succeed (bits of the comparison constant cannot match the shifted value). // This should be known by InstSimplify and already be folded to true/false. assert(((IsAShr && C->shl(ShAmtVal).ashr(ShAmtVal) == *C) || (!IsAShr && C->shl(ShAmtVal).lshr(ShAmtVal) == *C)) && "Expected icmp+shr simplify did not occur."); // Check if the bits shifted out are known to be zero. If so, we can compare // against the unshifted value: // (X & 4) >> 1 == 2 --> (X & 4) == 4. Constant *ShiftedCmpRHS = ConstantInt::get(Shr->getType(), *C << ShAmtVal); if (Shr->hasOneUse()) { if (Shr->isExact()) return new ICmpInst(Pred, X, ShiftedCmpRHS); // Otherwise strength reduce the shift into an 'and'. APInt Val(APInt::getHighBitsSet(TypeBits, TypeBits - ShAmtVal)); Constant *Mask = ConstantInt::get(Shr->getType(), Val); Value *And = Builder->CreateAnd(X, Mask, Shr->getName() + ".mask"); return new ICmpInst(Pred, And, ShiftedCmpRHS); } return nullptr; } /// Fold icmp (udiv X, Y), C. Instruction *InstCombiner::foldICmpUDivConstant(ICmpInst &Cmp, BinaryOperator *UDiv, const APInt *C) { const APInt *C2; if (!match(UDiv->getOperand(0), m_APInt(C2))) return nullptr; assert(C2 != 0 && "udiv 0, X should have been simplified already."); // (icmp ugt (udiv C2, Y), C) -> (icmp ule Y, C2/(C+1)) Value *Y = UDiv->getOperand(1); if (Cmp.getPredicate() == ICmpInst::ICMP_UGT) { assert(!C->isMaxValue() && "icmp ugt X, UINT_MAX should have been simplified already."); return new ICmpInst(ICmpInst::ICMP_ULE, Y, ConstantInt::get(Y->getType(), C2->udiv(*C + 1))); } // (icmp ult (udiv C2, Y), C) -> (icmp ugt Y, C2/C) if (Cmp.getPredicate() == ICmpInst::ICMP_ULT) { assert(C != 0 && "icmp ult X, 0 should have been simplified already."); return new ICmpInst(ICmpInst::ICMP_UGT, Y, ConstantInt::get(Y->getType(), C2->udiv(*C))); } return nullptr; } /// Fold icmp ({su}div X, Y), C. Instruction *InstCombiner::foldICmpDivConstant(ICmpInst &Cmp, BinaryOperator *Div, const APInt *C) { // Fold: icmp pred ([us]div X, C2), C -> range test // Fold this div into the comparison, producing a range check. // Determine, based on the divide type, what the range is being // checked. If there is an overflow on the low or high side, remember // it, otherwise compute the range [low, hi) bounding the new value. // See: InsertRangeTest above for the kinds of replacements possible. const APInt *C2; if (!match(Div->getOperand(1), m_APInt(C2))) return nullptr; // FIXME: If the operand types don't match the type of the divide // then don't attempt this transform. The code below doesn't have the // logic to deal with a signed divide and an unsigned compare (and // vice versa). This is because (x /s C2) getOpcode() == Instruction::SDiv; if (!Cmp.isEquality() && DivIsSigned != Cmp.isSigned()) return nullptr; // The ProdOV computation fails on divide by 0 and divide by -1. Cases with // INT_MIN will also fail if the divisor is 1. Although folds of all these // division-by-constant cases should be present, we can not assert that they // have happened before we reach this icmp instruction. if (*C2 == 0 || *C2 == 1 || (DivIsSigned && C2->isAllOnesValue())) return nullptr; // TODO: We could do all of the computations below using APInt. Constant *CmpRHS = cast(Cmp.getOperand(1)); Constant *DivRHS = cast(Div->getOperand(1)); // Compute Prod = CmpRHS * DivRHS. We are essentially solving an equation of // form X / C2 = C. We solve for X by multiplying C2 (DivRHS) and C (CmpRHS). // By solving for X, we can turn this into a range check instead of computing // a divide. Constant *Prod = ConstantExpr::getMul(CmpRHS, DivRHS); // Determine if the product overflows by seeing if the product is not equal to // the divide. Make sure we do the same kind of divide as in the LHS // instruction that we're folding. bool ProdOV = (DivIsSigned ? ConstantExpr::getSDiv(Prod, DivRHS) : ConstantExpr::getUDiv(Prod, DivRHS)) != CmpRHS; ICmpInst::Predicate Pred = Cmp.getPredicate(); // If the division is known to be exact, then there is no remainder from the // divide, so the covered range size is unit, otherwise it is the divisor. Constant *RangeSize = Div->isExact() ? ConstantInt::get(Div->getType(), 1) : DivRHS; // Figure out the interval that is being checked. For example, a comparison // like "X /u 5 == 0" is really checking that X is in the interval [0, 5). // Compute this interval based on the constants involved and the signedness of // the compare/divide. This computes a half-open interval, keeping track of // whether either value in the interval overflows. After analysis each // overflow variable is set to 0 if it's corresponding bound variable is valid // -1 if overflowed off the bottom end, or +1 if overflowed off the top end. int LoOverflow = 0, HiOverflow = 0; Constant *LoBound = nullptr, *HiBound = nullptr; if (!DivIsSigned) { // udiv // e.g. X/5 op 3 --> [15, 20) LoBound = Prod; HiOverflow = LoOverflow = ProdOV; if (!HiOverflow) { // If this is not an exact divide, then many values in the range collapse // to the same result value. HiOverflow = addWithOverflow(HiBound, LoBound, RangeSize, false); } } else if (C2->isStrictlyPositive()) { // Divisor is > 0. if (*C == 0) { // (X / pos) op 0 // Can't overflow. e.g. X/2 op 0 --> [-1, 2) LoBound = ConstantExpr::getNeg(SubOne(RangeSize)); HiBound = RangeSize; } else if (C->isStrictlyPositive()) { // (X / pos) op pos LoBound = Prod; // e.g. X/5 op 3 --> [15, 20) HiOverflow = LoOverflow = ProdOV; if (!HiOverflow) HiOverflow = addWithOverflow(HiBound, Prod, RangeSize, true); } else { // (X / pos) op neg // e.g. X/5 op -3 --> [-15-4, -15+1) --> [-19, -14) HiBound = AddOne(Prod); LoOverflow = HiOverflow = ProdOV ? -1 : 0; if (!LoOverflow) { Constant *DivNeg = ConstantExpr::getNeg(RangeSize); LoOverflow = addWithOverflow(LoBound, HiBound, DivNeg, true) ? -1 : 0; } } } else if (C2->isNegative()) { // Divisor is < 0. if (Div->isExact()) RangeSize = ConstantExpr::getNeg(RangeSize); if (*C == 0) { // (X / neg) op 0 // e.g. X/-5 op 0 --> [-4, 5) LoBound = AddOne(RangeSize); HiBound = ConstantExpr::getNeg(RangeSize); if (HiBound == DivRHS) { // -INTMIN = INTMIN HiOverflow = 1; // [INTMIN+1, overflow) HiBound = nullptr; // e.g. X/INTMIN = 0 --> X > INTMIN } } else if (C->isStrictlyPositive()) { // (X / neg) op pos // e.g. X/-5 op 3 --> [-19, -14) HiBound = AddOne(Prod); HiOverflow = LoOverflow = ProdOV ? -1 : 0; if (!LoOverflow) LoOverflow = addWithOverflow(LoBound, HiBound, RangeSize, true) ? -1:0; } else { // (X / neg) op neg LoBound = Prod; // e.g. X/-5 op -3 --> [15, 20) LoOverflow = HiOverflow = ProdOV; if (!HiOverflow) HiOverflow = subWithOverflow(HiBound, Prod, RangeSize, true); } // Dividing by a negative swaps the condition. LT <-> GT Pred = ICmpInst::getSwappedPredicate(Pred); } Value *X = Div->getOperand(0); switch (Pred) { default: llvm_unreachable("Unhandled icmp opcode!"); case ICmpInst::ICMP_EQ: if (LoOverflow && HiOverflow) return replaceInstUsesWith(Cmp, Builder->getFalse()); if (HiOverflow) return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, X, LoBound); if (LoOverflow) return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, X, HiBound); return replaceInstUsesWith( Cmp, insertRangeTest(X, LoBound->getUniqueInteger(), HiBound->getUniqueInteger(), DivIsSigned, true)); case ICmpInst::ICMP_NE: if (LoOverflow && HiOverflow) return replaceInstUsesWith(Cmp, Builder->getTrue()); if (HiOverflow) return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT, X, LoBound); if (LoOverflow) return new ICmpInst(DivIsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE, X, HiBound); return replaceInstUsesWith(Cmp, insertRangeTest(X, LoBound->getUniqueInteger(), HiBound->getUniqueInteger(), DivIsSigned, false)); case ICmpInst::ICMP_ULT: case ICmpInst::ICMP_SLT: if (LoOverflow == +1) // Low bound is greater than input range. return replaceInstUsesWith(Cmp, Builder->getTrue()); if (LoOverflow == -1) // Low bound is less than input range. return replaceInstUsesWith(Cmp, Builder->getFalse()); return new ICmpInst(Pred, X, LoBound); case ICmpInst::ICMP_UGT: case ICmpInst::ICMP_SGT: if (HiOverflow == +1) // High bound greater than input range. return replaceInstUsesWith(Cmp, Builder->getFalse()); if (HiOverflow == -1) // High bound less than input range. return replaceInstUsesWith(Cmp, Builder->getTrue()); if (Pred == ICmpInst::ICMP_UGT) return new ICmpInst(ICmpInst::ICMP_UGE, X, HiBound); return new ICmpInst(ICmpInst::ICMP_SGE, X, HiBound); } return nullptr; } /// Fold icmp (sub X, Y), C. Instruction *InstCombiner::foldICmpSubConstant(ICmpInst &Cmp, BinaryOperator *Sub, const APInt *C) { Value *X = Sub->getOperand(0), *Y = Sub->getOperand(1); ICmpInst::Predicate Pred = Cmp.getPredicate(); // The following transforms are only worth it if the only user of the subtract // is the icmp. if (!Sub->hasOneUse()) return nullptr; if (Sub->hasNoSignedWrap()) { // (icmp sgt (sub nsw X, Y), -1) -> (icmp sge X, Y) if (Pred == ICmpInst::ICMP_SGT && C->isAllOnesValue()) return new ICmpInst(ICmpInst::ICMP_SGE, X, Y); // (icmp sgt (sub nsw X, Y), 0) -> (icmp sgt X, Y) if (Pred == ICmpInst::ICMP_SGT && *C == 0) return new ICmpInst(ICmpInst::ICMP_SGT, X, Y); // (icmp slt (sub nsw X, Y), 0) -> (icmp slt X, Y) if (Pred == ICmpInst::ICMP_SLT && *C == 0) return new ICmpInst(ICmpInst::ICMP_SLT, X, Y); // (icmp slt (sub nsw X, Y), 1) -> (icmp sle X, Y) if (Pred == ICmpInst::ICMP_SLT && *C == 1) return new ICmpInst(ICmpInst::ICMP_SLE, X, Y); } const APInt *C2; if (!match(X, m_APInt(C2))) return nullptr; // C2 - Y (Y | (C - 1)) == C2 // iff (C2 & (C - 1)) == C - 1 and C is a power of 2 if (Pred == ICmpInst::ICMP_ULT && C->isPowerOf2() && (*C2 & (*C - 1)) == (*C - 1)) return new ICmpInst(ICmpInst::ICMP_EQ, Builder->CreateOr(Y, *C - 1), X); // C2 - Y >u C -> (Y | C) != C2 // iff C2 & C == C and C + 1 is a power of 2 if (Pred == ICmpInst::ICMP_UGT && (*C + 1).isPowerOf2() && (*C2 & *C) == *C) return new ICmpInst(ICmpInst::ICMP_NE, Builder->CreateOr(Y, *C), X); return nullptr; } /// Fold icmp (add X, Y), C. Instruction *InstCombiner::foldICmpAddConstant(ICmpInst &Cmp, BinaryOperator *Add, const APInt *C) { Value *Y = Add->getOperand(1); const APInt *C2; if (Cmp.isEquality() || !match(Y, m_APInt(C2))) return nullptr; // Fold icmp pred (add X, C2), C. Value *X = Add->getOperand(0); Type *Ty = Add->getType(); auto CR = ConstantRange::makeExactICmpRegion(Cmp.getPredicate(), *C).subtract(*C2); const APInt &Upper = CR.getUpper(); const APInt &Lower = CR.getLower(); if (Cmp.isSigned()) { if (Lower.isSignBit()) return new ICmpInst(ICmpInst::ICMP_SLT, X, ConstantInt::get(Ty, Upper)); if (Upper.isSignBit()) return new ICmpInst(ICmpInst::ICMP_SGE, X, ConstantInt::get(Ty, Lower)); } else { if (Lower.isMinValue()) return new ICmpInst(ICmpInst::ICMP_ULT, X, ConstantInt::get(Ty, Upper)); if (Upper.isMinValue()) return new ICmpInst(ICmpInst::ICMP_UGE, X, ConstantInt::get(Ty, Lower)); } if (!Add->hasOneUse()) return nullptr; // X+C (X & -C2) == C // iff C & (C2-1) == 0 // C2 is a power of 2 if (Cmp.getPredicate() == ICmpInst::ICMP_ULT && C->isPowerOf2() && (*C2 & (*C - 1)) == 0) return new ICmpInst(ICmpInst::ICMP_EQ, Builder->CreateAnd(X, -(*C)), ConstantExpr::getNeg(cast(Y))); // X+C >u C2 -> (X & ~C2) != C // iff C & C2 == 0 // C2+1 is a power of 2 if (Cmp.getPredicate() == ICmpInst::ICMP_UGT && (*C + 1).isPowerOf2() && (*C2 & *C) == 0) return new ICmpInst(ICmpInst::ICMP_NE, Builder->CreateAnd(X, ~(*C)), ConstantExpr::getNeg(cast(Y))); return nullptr; } /// Try to fold integer comparisons with a constant operand: icmp Pred X, C /// where X is some kind of instruction. Instruction *InstCombiner::foldICmpInstWithConstant(ICmpInst &Cmp) { const APInt *C; if (!match(Cmp.getOperand(1), m_APInt(C))) return nullptr; BinaryOperator *BO; if (match(Cmp.getOperand(0), m_BinOp(BO))) { switch (BO->getOpcode()) { case Instruction::Xor: if (Instruction *I = foldICmpXorConstant(Cmp, BO, C)) return I; break; case Instruction::And: if (Instruction *I = foldICmpAndConstant(Cmp, BO, C)) return I; break; case Instruction::Or: if (Instruction *I = foldICmpOrConstant(Cmp, BO, C)) return I; break; case Instruction::Mul: if (Instruction *I = foldICmpMulConstant(Cmp, BO, C)) return I; break; case Instruction::Shl: if (Instruction *I = foldICmpShlConstant(Cmp, BO, C)) return I; break; case Instruction::LShr: case Instruction::AShr: if (Instruction *I = foldICmpShrConstant(Cmp, BO, C)) return I; break; case Instruction::UDiv: if (Instruction *I = foldICmpUDivConstant(Cmp, BO, C)) return I; LLVM_FALLTHROUGH; case Instruction::SDiv: if (Instruction *I = foldICmpDivConstant(Cmp, BO, C)) return I; break; case Instruction::Sub: if (Instruction *I = foldICmpSubConstant(Cmp, BO, C)) return I; break; case Instruction::Add: if (Instruction *I = foldICmpAddConstant(Cmp, BO, C)) return I; break; default: break; } // TODO: These folds could be refactored to be part of the above calls. if (Instruction *I = foldICmpBinOpEqualityWithConstant(Cmp, BO, C)) return I; } Instruction *LHSI; if (match(Cmp.getOperand(0), m_Instruction(LHSI)) && LHSI->getOpcode() == Instruction::Trunc) if (Instruction *I = foldICmpTruncConstant(Cmp, LHSI, C)) return I; if (Instruction *I = foldICmpIntrinsicWithConstant(Cmp, C)) return I; return nullptr; } /// Fold an icmp equality instruction with binary operator LHS and constant RHS: /// icmp eq/ne BO, C. Instruction *InstCombiner::foldICmpBinOpEqualityWithConstant(ICmpInst &Cmp, BinaryOperator *BO, const APInt *C) { // TODO: Some of these folds could work with arbitrary constants, but this // function is limited to scalar and vector splat constants. if (!Cmp.isEquality()) return nullptr; ICmpInst::Predicate Pred = Cmp.getPredicate(); bool isICMP_NE = Pred == ICmpInst::ICMP_NE; Constant *RHS = cast(Cmp.getOperand(1)); Value *BOp0 = BO->getOperand(0), *BOp1 = BO->getOperand(1); switch (BO->getOpcode()) { case Instruction::SRem: // If we have a signed (X % (2^c)) == 0, turn it into an unsigned one. if (*C == 0 && BO->hasOneUse()) { const APInt *BOC; if (match(BOp1, m_APInt(BOC)) && BOC->sgt(1) && BOC->isPowerOf2()) { Value *NewRem = Builder->CreateURem(BOp0, BOp1, BO->getName()); return new ICmpInst(Pred, NewRem, Constant::getNullValue(BO->getType())); } } break; case Instruction::Add: { // Replace ((add A, B) != C) with (A != C-B) if B & C are constants. const APInt *BOC; if (match(BOp1, m_APInt(BOC))) { if (BO->hasOneUse()) { Constant *SubC = ConstantExpr::getSub(RHS, cast(BOp1)); return new ICmpInst(Pred, BOp0, SubC); } } else if (*C == 0) { // Replace ((add A, B) != 0) with (A != -B) if A or B is // efficiently invertible, or if the add has just this one use. if (Value *NegVal = dyn_castNegVal(BOp1)) return new ICmpInst(Pred, BOp0, NegVal); if (Value *NegVal = dyn_castNegVal(BOp0)) return new ICmpInst(Pred, NegVal, BOp1); if (BO->hasOneUse()) { Value *Neg = Builder->CreateNeg(BOp1); Neg->takeName(BO); return new ICmpInst(Pred, BOp0, Neg); } } break; } case Instruction::Xor: if (BO->hasOneUse()) { if (Constant *BOC = dyn_cast(BOp1)) { // For the xor case, we can xor two constants together, eliminating // the explicit xor. return new ICmpInst(Pred, BOp0, ConstantExpr::getXor(RHS, BOC)); } else if (*C == 0) { // Replace ((xor A, B) != 0) with (A != B) return new ICmpInst(Pred, BOp0, BOp1); } } break; case Instruction::Sub: if (BO->hasOneUse()) { const APInt *BOC; if (match(BOp0, m_APInt(BOC))) { // Replace ((sub BOC, B) != C) with (B != BOC-C). Constant *SubC = ConstantExpr::getSub(cast(BOp0), RHS); return new ICmpInst(Pred, BOp1, SubC); } else if (*C == 0) { // Replace ((sub A, B) != 0) with (A != B). return new ICmpInst(Pred, BOp0, BOp1); } } break; case Instruction::Or: { const APInt *BOC; if (match(BOp1, m_APInt(BOC)) && BO->hasOneUse() && RHS->isAllOnesValue()) { // Comparing if all bits outside of a constant mask are set? // Replace (X | C) == -1 with (X & ~C) == ~C. // This removes the -1 constant. Constant *NotBOC = ConstantExpr::getNot(cast(BOp1)); Value *And = Builder->CreateAnd(BOp0, NotBOC); return new ICmpInst(Pred, And, NotBOC); } break; } case Instruction::And: { const APInt *BOC; if (match(BOp1, m_APInt(BOC))) { // If we have ((X & C) == C), turn it into ((X & C) != 0). if (C == BOC && C->isPowerOf2()) return new ICmpInst(isICMP_NE ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, BO, Constant::getNullValue(RHS->getType())); // Don't perform the following transforms if the AND has multiple uses if (!BO->hasOneUse()) break; // Replace (and X, (1 << size(X)-1) != 0) with x s< 0 if (BOC->isSignBit()) { Constant *Zero = Constant::getNullValue(BOp0->getType()); auto NewPred = isICMP_NE ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_SGE; return new ICmpInst(NewPred, BOp0, Zero); } // ((X & ~7) == 0) --> X < 8 if (*C == 0 && (~(*BOC) + 1).isPowerOf2()) { Constant *NegBOC = ConstantExpr::getNeg(cast(BOp1)); auto NewPred = isICMP_NE ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT; return new ICmpInst(NewPred, BOp0, NegBOC); } } break; } case Instruction::Mul: if (*C == 0 && BO->hasNoSignedWrap()) { const APInt *BOC; if (match(BOp1, m_APInt(BOC)) && *BOC != 0) { // The trivial case (mul X, 0) is handled by InstSimplify. // General case : (mul X, C) != 0 iff X != 0 // (mul X, C) == 0 iff X == 0 return new ICmpInst(Pred, BOp0, Constant::getNullValue(RHS->getType())); } } break; case Instruction::UDiv: if (*C == 0) { // (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A) auto NewPred = isICMP_NE ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_UGT; return new ICmpInst(NewPred, BOp1, BOp0); } break; default: break; } return nullptr; } /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C. Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, const APInt *C) { IntrinsicInst *II = dyn_cast(Cmp.getOperand(0)); if (!II || !Cmp.isEquality()) return nullptr; // Handle icmp {eq|ne} , intcst. switch (II->getIntrinsicID()) { case Intrinsic::bswap: Worklist.Add(II); Cmp.setOperand(0, II->getArgOperand(0)); Cmp.setOperand(1, Builder->getInt(C->byteSwap())); return &Cmp; case Intrinsic::ctlz: case Intrinsic::cttz: // ctz(A) == bitwidth(A) -> A == 0 and likewise for != if (*C == C->getBitWidth()) { Worklist.Add(II); Cmp.setOperand(0, II->getArgOperand(0)); Cmp.setOperand(1, ConstantInt::getNullValue(II->getType())); return &Cmp; } break; case Intrinsic::ctpop: { // popcount(A) == 0 -> A == 0 and likewise for != // popcount(A) == bitwidth(A) -> A == -1 and likewise for != bool IsZero = *C == 0; if (IsZero || *C == C->getBitWidth()) { Worklist.Add(II); Cmp.setOperand(0, II->getArgOperand(0)); auto *NewOp = IsZero ? Constant::getNullValue(II->getType()) : Constant::getAllOnesValue(II->getType()); Cmp.setOperand(1, NewOp); return &Cmp; } break; } default: break; } return nullptr; } /// Handle icmp with constant (but not simple integer constant) RHS. Instruction *InstCombiner::foldICmpInstWithConstantNotInt(ICmpInst &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Constant *RHSC = dyn_cast(Op1); Instruction *LHSI = dyn_cast(Op0); if (!RHSC || !LHSI) return nullptr; switch (LHSI->getOpcode()) { case Instruction::GetElementPtr: // icmp pred GEP (P, int 0, int 0, int 0), null -> icmp pred P, null if (RHSC->isNullValue() && cast(LHSI)->hasAllZeroIndices()) return new ICmpInst( I.getPredicate(), LHSI->getOperand(0), Constant::getNullValue(LHSI->getOperand(0)->getType())); break; case Instruction::PHI: // Only fold icmp into the PHI if the phi and icmp are in the same // block. If in the same block, we're encouraging jump threading. If // not, we are just pessimizing the code by making an i1 phi. if (LHSI->getParent() == I.getParent()) if (Instruction *NV = FoldOpIntoPhi(I)) return NV; break; case Instruction::Select: { // If either operand of the select is a constant, we can fold the // comparison into the select arms, which will cause one to be // constant folded and the select turned into a bitwise or. Value *Op1 = nullptr, *Op2 = nullptr; ConstantInt *CI = nullptr; if (Constant *C = dyn_cast(LHSI->getOperand(1))) { Op1 = ConstantExpr::getICmp(I.getPredicate(), C, RHSC); CI = dyn_cast(Op1); } if (Constant *C = dyn_cast(LHSI->getOperand(2))) { Op2 = ConstantExpr::getICmp(I.getPredicate(), C, RHSC); CI = dyn_cast(Op2); } // We only want to perform this transformation if it will not lead to // additional code. This is true if either both sides of the select // fold to a constant (in which case the icmp is replaced with a select // which will usually simplify) or this is the only user of the // select (in which case we are trading a select+icmp for a simpler // select+icmp) or all uses of the select can be replaced based on // dominance information ("Global cases"). bool Transform = false; if (Op1 && Op2) Transform = true; else if (Op1 || Op2) { // Local case if (LHSI->hasOneUse()) Transform = true; // Global cases else if (CI && !CI->isZero()) // When Op1 is constant try replacing select with second operand. // Otherwise Op2 is constant and try replacing select with first // operand. Transform = replacedSelectWithOperand(cast(LHSI), &I, Op1 ? 2 : 1); } if (Transform) { if (!Op1) Op1 = Builder->CreateICmp(I.getPredicate(), LHSI->getOperand(1), RHSC, I.getName()); if (!Op2) Op2 = Builder->CreateICmp(I.getPredicate(), LHSI->getOperand(2), RHSC, I.getName()); return SelectInst::Create(LHSI->getOperand(0), Op1, Op2); } break; } case Instruction::IntToPtr: // icmp pred inttoptr(X), null -> icmp pred X, 0 if (RHSC->isNullValue() && DL.getIntPtrType(RHSC->getType()) == LHSI->getOperand(0)->getType()) return new ICmpInst( I.getPredicate(), LHSI->getOperand(0), Constant::getNullValue(LHSI->getOperand(0)->getType())); break; case Instruction::Load: // Try to optimize things like "A[i] > 4" to index computations. if (GetElementPtrInst *GEP = dyn_cast(LHSI->getOperand(0))) { if (GlobalVariable *GV = dyn_cast(GEP->getOperand(0))) if (GV->isConstant() && GV->hasDefinitiveInitializer() && !cast(LHSI)->isVolatile()) if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, I)) return Res; } break; } return nullptr; } /// Try to fold icmp (binop), X or icmp X, (binop). Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); // Special logic for binary operators. BinaryOperator *BO0 = dyn_cast(Op0); BinaryOperator *BO1 = dyn_cast(Op1); if (!BO0 && !BO1) return nullptr; CmpInst::Predicate Pred = I.getPredicate(); bool NoOp0WrapProblem = false, NoOp1WrapProblem = false; if (BO0 && isa(BO0)) NoOp0WrapProblem = ICmpInst::isEquality(Pred) || (CmpInst::isUnsigned(Pred) && BO0->hasNoUnsignedWrap()) || (CmpInst::isSigned(Pred) && BO0->hasNoSignedWrap()); if (BO1 && isa(BO1)) NoOp1WrapProblem = ICmpInst::isEquality(Pred) || (CmpInst::isUnsigned(Pred) && BO1->hasNoUnsignedWrap()) || (CmpInst::isSigned(Pred) && BO1->hasNoSignedWrap()); // Analyze the case when either Op0 or Op1 is an add instruction. // Op0 = A + B (or A and B are null); Op1 = C + D (or C and D are null). Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr; if (BO0 && BO0->getOpcode() == Instruction::Add) { A = BO0->getOperand(0); B = BO0->getOperand(1); } if (BO1 && BO1->getOpcode() == Instruction::Add) { C = BO1->getOperand(0); D = BO1->getOperand(1); } // icmp (X+cst) < 0 --> X < -cst if (NoOp0WrapProblem && ICmpInst::isSigned(Pred) && match(Op1, m_Zero())) if (ConstantInt *RHSC = dyn_cast_or_null(B)) if (!RHSC->isMinValue(/*isSigned=*/true)) return new ICmpInst(Pred, A, ConstantExpr::getNeg(RHSC)); // icmp (X+Y), X -> icmp Y, 0 for equalities or if there is no overflow. if ((A == Op1 || B == Op1) && NoOp0WrapProblem) return new ICmpInst(Pred, A == Op1 ? B : A, Constant::getNullValue(Op1->getType())); // icmp X, (X+Y) -> icmp 0, Y for equalities or if there is no overflow. if ((C == Op0 || D == Op0) && NoOp1WrapProblem) return new ICmpInst(Pred, Constant::getNullValue(Op0->getType()), C == Op0 ? D : C); // icmp (X+Y), (X+Z) -> icmp Y, Z for equalities or if there is no overflow. if (A && C && (A == C || A == D || B == C || B == D) && NoOp0WrapProblem && NoOp1WrapProblem && // Try not to increase register pressure. BO0->hasOneUse() && BO1->hasOneUse()) { // Determine Y and Z in the form icmp (X+Y), (X+Z). Value *Y, *Z; if (A == C) { // C + B == C + D -> B == D Y = B; Z = D; } else if (A == D) { // D + B == C + D -> B == C Y = B; Z = C; } else if (B == C) { // A + C == C + D -> A == D Y = A; Z = D; } else { assert(B == D); // A + D == C + D -> A == C Y = A; Z = C; } return new ICmpInst(Pred, Y, Z); } // icmp slt (X + -1), Y -> icmp sle X, Y if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLT && match(B, m_AllOnes())) return new ICmpInst(CmpInst::ICMP_SLE, A, Op1); // icmp sge (X + -1), Y -> icmp sgt X, Y if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGE && match(B, m_AllOnes())) return new ICmpInst(CmpInst::ICMP_SGT, A, Op1); // icmp sle (X + 1), Y -> icmp slt X, Y if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLE && match(B, m_One())) return new ICmpInst(CmpInst::ICMP_SLT, A, Op1); // icmp sgt (X + 1), Y -> icmp sge X, Y if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGT && match(B, m_One())) return new ICmpInst(CmpInst::ICMP_SGE, A, Op1); // icmp sgt X, (Y + -1) -> icmp sge X, Y if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGT && match(D, m_AllOnes())) return new ICmpInst(CmpInst::ICMP_SGE, Op0, C); // icmp sle X, (Y + -1) -> icmp slt X, Y if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLE && match(D, m_AllOnes())) return new ICmpInst(CmpInst::ICMP_SLT, Op0, C); // icmp sge X, (Y + 1) -> icmp sgt X, Y if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGE && match(D, m_One())) return new ICmpInst(CmpInst::ICMP_SGT, Op0, C); // icmp slt X, (Y + 1) -> icmp sle X, Y if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLT && match(D, m_One())) return new ICmpInst(CmpInst::ICMP_SLE, Op0, C); // if C1 has greater magnitude than C2: // icmp (X + C1), (Y + C2) -> icmp (X + C3), Y // s.t. C3 = C1 - C2 // // if C2 has greater magnitude than C1: // icmp (X + C1), (Y + C2) -> icmp X, (Y + C3) // s.t. C3 = C2 - C1 if (A && C && NoOp0WrapProblem && NoOp1WrapProblem && (BO0->hasOneUse() || BO1->hasOneUse()) && !I.isUnsigned()) if (ConstantInt *C1 = dyn_cast(B)) if (ConstantInt *C2 = dyn_cast(D)) { const APInt &AP1 = C1->getValue(); const APInt &AP2 = C2->getValue(); if (AP1.isNegative() == AP2.isNegative()) { APInt AP1Abs = C1->getValue().abs(); APInt AP2Abs = C2->getValue().abs(); if (AP1Abs.uge(AP2Abs)) { ConstantInt *C3 = Builder->getInt(AP1 - AP2); Value *NewAdd = Builder->CreateNSWAdd(A, C3); return new ICmpInst(Pred, NewAdd, C); } else { ConstantInt *C3 = Builder->getInt(AP2 - AP1); Value *NewAdd = Builder->CreateNSWAdd(C, C3); return new ICmpInst(Pred, A, NewAdd); } } } // Analyze the case when either Op0 or Op1 is a sub instruction. // Op0 = A - B (or A and B are null); Op1 = C - D (or C and D are null). A = nullptr; B = nullptr; C = nullptr; D = nullptr; if (BO0 && BO0->getOpcode() == Instruction::Sub) { A = BO0->getOperand(0); B = BO0->getOperand(1); } if (BO1 && BO1->getOpcode() == Instruction::Sub) { C = BO1->getOperand(0); D = BO1->getOperand(1); } // icmp (X-Y), X -> icmp 0, Y for equalities or if there is no overflow. if (A == Op1 && NoOp0WrapProblem) return new ICmpInst(Pred, Constant::getNullValue(Op1->getType()), B); // icmp X, (X-Y) -> icmp Y, 0 for equalities or if there is no overflow. if (C == Op0 && NoOp1WrapProblem) return new ICmpInst(Pred, D, Constant::getNullValue(Op0->getType())); // icmp (Y-X), (Z-X) -> icmp Y, Z for equalities or if there is no overflow. if (B && D && B == D && NoOp0WrapProblem && NoOp1WrapProblem && // Try not to increase register pressure. BO0->hasOneUse() && BO1->hasOneUse()) return new ICmpInst(Pred, A, C); // icmp (X-Y), (X-Z) -> icmp Z, Y for equalities or if there is no overflow. if (A && C && A == C && NoOp0WrapProblem && NoOp1WrapProblem && // Try not to increase register pressure. BO0->hasOneUse() && BO1->hasOneUse()) return new ICmpInst(Pred, D, B); // icmp (0-X) < cst --> x > -cst if (NoOp0WrapProblem && ICmpInst::isSigned(Pred)) { Value *X; if (match(BO0, m_Neg(m_Value(X)))) if (ConstantInt *RHSC = dyn_cast(Op1)) if (!RHSC->isMinValue(/*isSigned=*/true)) return new ICmpInst(I.getSwappedPredicate(), X, ConstantExpr::getNeg(RHSC)); } BinaryOperator *SRem = nullptr; // icmp (srem X, Y), Y if (BO0 && BO0->getOpcode() == Instruction::SRem && Op1 == BO0->getOperand(1)) SRem = BO0; // icmp Y, (srem X, Y) else if (BO1 && BO1->getOpcode() == Instruction::SRem && Op0 == BO1->getOperand(1)) SRem = BO1; if (SRem) { // We don't check hasOneUse to avoid increasing register pressure because // the value we use is the same value this instruction was already using. switch (SRem == BO0 ? ICmpInst::getSwappedPredicate(Pred) : Pred) { default: break; case ICmpInst::ICMP_EQ: return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())); case ICmpInst::ICMP_NE: return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); case ICmpInst::ICMP_SGT: case ICmpInst::ICMP_SGE: return new ICmpInst(ICmpInst::ICMP_SGT, SRem->getOperand(1), Constant::getAllOnesValue(SRem->getType())); case ICmpInst::ICMP_SLT: case ICmpInst::ICMP_SLE: return new ICmpInst(ICmpInst::ICMP_SLT, SRem->getOperand(1), Constant::getNullValue(SRem->getType())); } } if (BO0 && BO1 && BO0->getOpcode() == BO1->getOpcode() && BO0->hasOneUse() && BO1->hasOneUse() && BO0->getOperand(1) == BO1->getOperand(1)) { switch (BO0->getOpcode()) { default: break; case Instruction::Add: case Instruction::Sub: case Instruction::Xor: if (I.isEquality()) // a+x icmp eq/ne b+x --> a icmp b return new ICmpInst(I.getPredicate(), BO0->getOperand(0), BO1->getOperand(0)); // icmp u/s (a ^ signbit), (b ^ signbit) --> icmp s/u a, b if (ConstantInt *CI = dyn_cast(BO0->getOperand(1))) { if (CI->getValue().isSignBit()) { ICmpInst::Predicate Pred = I.isSigned() ? I.getUnsignedPredicate() : I.getSignedPredicate(); return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0)); } if (BO0->getOpcode() == Instruction::Xor && CI->isMaxValue(true)) { ICmpInst::Predicate Pred = I.isSigned() ? I.getUnsignedPredicate() : I.getSignedPredicate(); Pred = I.getSwappedPredicate(Pred); return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0)); } } break; case Instruction::Mul: if (!I.isEquality()) break; if (ConstantInt *CI = dyn_cast(BO0->getOperand(1))) { // a * Cst icmp eq/ne b * Cst --> a & Mask icmp b & Mask // Mask = -1 >> count-trailing-zeros(Cst). if (!CI->isZero() && !CI->isOne()) { const APInt &AP = CI->getValue(); ConstantInt *Mask = ConstantInt::get( I.getContext(), APInt::getLowBitsSet(AP.getBitWidth(), AP.getBitWidth() - AP.countTrailingZeros())); Value *And1 = Builder->CreateAnd(BO0->getOperand(0), Mask); Value *And2 = Builder->CreateAnd(BO1->getOperand(0), Mask); return new ICmpInst(I.getPredicate(), And1, And2); } } break; case Instruction::UDiv: case Instruction::LShr: if (I.isSigned()) break; LLVM_FALLTHROUGH; case Instruction::SDiv: case Instruction::AShr: if (!BO0->isExact() || !BO1->isExact()) break; return new ICmpInst(I.getPredicate(), BO0->getOperand(0), BO1->getOperand(0)); case Instruction::Shl: { bool NUW = BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap(); bool NSW = BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap(); if (!NUW && !NSW) break; if (!NSW && I.isSigned()) break; return new ICmpInst(I.getPredicate(), BO0->getOperand(0), BO1->getOperand(0)); } } } if (BO0) { // Transform A & (L - 1) `ult` L --> L != 0 auto LSubOne = m_Add(m_Specific(Op1), m_AllOnes()); auto BitwiseAnd = m_CombineOr(m_And(m_Value(), LSubOne), m_And(LSubOne, m_Value())); if (match(BO0, BitwiseAnd) && I.getPredicate() == ICmpInst::ICMP_ULT) { auto *Zero = Constant::getNullValue(BO0->getType()); return new ICmpInst(ICmpInst::ICMP_NE, Op1, Zero); } } return nullptr; } /// Fold icmp Pred min|max(X, Y), X. static Instruction *foldICmpWithMinMax(ICmpInst &Cmp) { ICmpInst::Predicate Pred = Cmp.getPredicate(); Value *Op0 = Cmp.getOperand(0); Value *X = Cmp.getOperand(1); // Canonicalize minimum or maximum operand to LHS of the icmp. if (match(X, m_c_SMin(m_Specific(Op0), m_Value())) || match(X, m_c_SMax(m_Specific(Op0), m_Value())) || match(X, m_c_UMin(m_Specific(Op0), m_Value())) || match(X, m_c_UMax(m_Specific(Op0), m_Value()))) { std::swap(Op0, X); Pred = Cmp.getSwappedPredicate(); } Value *Y; if (match(Op0, m_c_SMin(m_Specific(X), m_Value(Y)))) { // smin(X, Y) == X --> X s<= Y // smin(X, Y) s>= X --> X s<= Y if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_SGE) return new ICmpInst(ICmpInst::ICMP_SLE, X, Y); // smin(X, Y) != X --> X s> Y // smin(X, Y) s< X --> X s> Y if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_SLT) return new ICmpInst(ICmpInst::ICMP_SGT, X, Y); // These cases should be handled in InstSimplify: // smin(X, Y) s<= X --> true // smin(X, Y) s> X --> false return nullptr; } if (match(Op0, m_c_SMax(m_Specific(X), m_Value(Y)))) { // smax(X, Y) == X --> X s>= Y // smax(X, Y) s<= X --> X s>= Y if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_SLE) return new ICmpInst(ICmpInst::ICMP_SGE, X, Y); // smax(X, Y) != X --> X s< Y // smax(X, Y) s> X --> X s< Y if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_SGT) return new ICmpInst(ICmpInst::ICMP_SLT, X, Y); // These cases should be handled in InstSimplify: // smax(X, Y) s>= X --> true // smax(X, Y) s< X --> false return nullptr; } if (match(Op0, m_c_UMin(m_Specific(X), m_Value(Y)))) { // umin(X, Y) == X --> X u<= Y // umin(X, Y) u>= X --> X u<= Y if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_UGE) return new ICmpInst(ICmpInst::ICMP_ULE, X, Y); // umin(X, Y) != X --> X u> Y // umin(X, Y) u< X --> X u> Y if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_ULT) return new ICmpInst(ICmpInst::ICMP_UGT, X, Y); // These cases should be handled in InstSimplify: // umin(X, Y) u<= X --> true // umin(X, Y) u> X --> false return nullptr; } if (match(Op0, m_c_UMax(m_Specific(X), m_Value(Y)))) { // umax(X, Y) == X --> X u>= Y // umax(X, Y) u<= X --> X u>= Y if (Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_ULE) return new ICmpInst(ICmpInst::ICMP_UGE, X, Y); // umax(X, Y) != X --> X u< Y // umax(X, Y) u> X --> X u< Y if (Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_UGT) return new ICmpInst(ICmpInst::ICMP_ULT, X, Y); // These cases should be handled in InstSimplify: // umax(X, Y) u>= X --> true // umax(X, Y) u< X --> false return nullptr; } return nullptr; } Instruction *InstCombiner::foldICmpEquality(ICmpInst &I) { if (!I.isEquality()) return nullptr; Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Value *A, *B, *C, *D; if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) { if (A == Op1 || B == Op1) { // (A^B) == A -> B == 0 Value *OtherVal = A == Op1 ? B : A; return new ICmpInst(I.getPredicate(), OtherVal, Constant::getNullValue(A->getType())); } if (match(Op1, m_Xor(m_Value(C), m_Value(D)))) { // A^c1 == C^c2 --> A == C^(c1^c2) ConstantInt *C1, *C2; if (match(B, m_ConstantInt(C1)) && match(D, m_ConstantInt(C2)) && Op1->hasOneUse()) { Constant *NC = Builder->getInt(C1->getValue() ^ C2->getValue()); Value *Xor = Builder->CreateXor(C, NC); return new ICmpInst(I.getPredicate(), A, Xor); } // A^B == A^D -> B == D if (A == C) return new ICmpInst(I.getPredicate(), B, D); if (A == D) return new ICmpInst(I.getPredicate(), B, C); if (B == C) return new ICmpInst(I.getPredicate(), A, D); if (B == D) return new ICmpInst(I.getPredicate(), A, C); } } if (match(Op1, m_Xor(m_Value(A), m_Value(B))) && (A == Op0 || B == Op0)) { // A == (A^B) -> B == 0 Value *OtherVal = A == Op0 ? B : A; return new ICmpInst(I.getPredicate(), OtherVal, Constant::getNullValue(A->getType())); } // (X&Z) == (Y&Z) -> (X^Y) & Z == 0 if (match(Op0, m_OneUse(m_And(m_Value(A), m_Value(B)))) && match(Op1, m_OneUse(m_And(m_Value(C), m_Value(D))))) { Value *X = nullptr, *Y = nullptr, *Z = nullptr; if (A == C) { X = B; Y = D; Z = A; } else if (A == D) { X = B; Y = C; Z = A; } else if (B == C) { X = A; Y = D; Z = B; } else if (B == D) { X = A; Y = C; Z = B; } if (X) { // Build (X^Y) & Z Op1 = Builder->CreateXor(X, Y); Op1 = Builder->CreateAnd(Op1, Z); I.setOperand(0, Op1); I.setOperand(1, Constant::getNullValue(Op1->getType())); return &I; } } // Transform (zext A) == (B & (1< A == (trunc B) // and (B & (1< A == (trunc B) ConstantInt *Cst1; if ((Op0->hasOneUse() && match(Op0, m_ZExt(m_Value(A))) && match(Op1, m_And(m_Value(B), m_ConstantInt(Cst1)))) || (Op1->hasOneUse() && match(Op0, m_And(m_Value(B), m_ConstantInt(Cst1))) && match(Op1, m_ZExt(m_Value(A))))) { APInt Pow2 = Cst1->getValue() + 1; if (Pow2.isPowerOf2() && isa(A->getType()) && Pow2.logBase2() == cast(A->getType())->getBitWidth()) return new ICmpInst(I.getPredicate(), A, Builder->CreateTrunc(B, A->getType())); } // (A >> C) == (B >> C) --> (A^B) u< (1 << C) // For lshr and ashr pairs. if ((match(Op0, m_OneUse(m_LShr(m_Value(A), m_ConstantInt(Cst1)))) && match(Op1, m_OneUse(m_LShr(m_Value(B), m_Specific(Cst1))))) || (match(Op0, m_OneUse(m_AShr(m_Value(A), m_ConstantInt(Cst1)))) && match(Op1, m_OneUse(m_AShr(m_Value(B), m_Specific(Cst1)))))) { unsigned TypeBits = Cst1->getBitWidth(); unsigned ShAmt = (unsigned)Cst1->getLimitedValue(TypeBits); if (ShAmt < TypeBits && ShAmt != 0) { ICmpInst::Predicate Pred = I.getPredicate() == ICmpInst::ICMP_NE ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT; Value *Xor = Builder->CreateXor(A, B, I.getName() + ".unshifted"); APInt CmpVal = APInt::getOneBitSet(TypeBits, ShAmt); return new ICmpInst(Pred, Xor, Builder->getInt(CmpVal)); } } // (A << C) == (B << C) --> ((A^B) & (~0U >> C)) == 0 if (match(Op0, m_OneUse(m_Shl(m_Value(A), m_ConstantInt(Cst1)))) && match(Op1, m_OneUse(m_Shl(m_Value(B), m_Specific(Cst1))))) { unsigned TypeBits = Cst1->getBitWidth(); unsigned ShAmt = (unsigned)Cst1->getLimitedValue(TypeBits); if (ShAmt < TypeBits && ShAmt != 0) { Value *Xor = Builder->CreateXor(A, B, I.getName() + ".unshifted"); APInt AndVal = APInt::getLowBitsSet(TypeBits, TypeBits - ShAmt); Value *And = Builder->CreateAnd(Xor, Builder->getInt(AndVal), I.getName() + ".mask"); return new ICmpInst(I.getPredicate(), And, Constant::getNullValue(Cst1->getType())); } } // Transform "icmp eq (trunc (lshr(X, cst1)), cst" to // "icmp (and X, mask), cst" uint64_t ShAmt = 0; if (Op0->hasOneUse() && match(Op0, m_Trunc(m_OneUse(m_LShr(m_Value(A), m_ConstantInt(ShAmt))))) && match(Op1, m_ConstantInt(Cst1)) && // Only do this when A has multiple uses. This is most important to do // when it exposes other optimizations. !A->hasOneUse()) { unsigned ASize = cast(A->getType())->getPrimitiveSizeInBits(); if (ShAmt < ASize) { APInt MaskV = APInt::getLowBitsSet(ASize, Op0->getType()->getPrimitiveSizeInBits()); MaskV <<= ShAmt; APInt CmpV = Cst1->getValue().zext(ASize); CmpV <<= ShAmt; Value *Mask = Builder->CreateAnd(A, Builder->getInt(MaskV)); return new ICmpInst(I.getPredicate(), Mask, Builder->getInt(CmpV)); } } return nullptr; } /// Handle icmp (cast x to y), (cast/cst). We only handle extending casts so /// far. Instruction *InstCombiner::foldICmpWithCastAndCast(ICmpInst &ICmp) { const CastInst *LHSCI = cast(ICmp.getOperand(0)); Value *LHSCIOp = LHSCI->getOperand(0); Type *SrcTy = LHSCIOp->getType(); Type *DestTy = LHSCI->getType(); Value *RHSCIOp; // Turn icmp (ptrtoint x), (ptrtoint/c) into a compare of the input if the // integer type is the same size as the pointer type. if (LHSCI->getOpcode() == Instruction::PtrToInt && DL.getPointerTypeSizeInBits(SrcTy) == DestTy->getIntegerBitWidth()) { Value *RHSOp = nullptr; if (auto *RHSC = dyn_cast(ICmp.getOperand(1))) { Value *RHSCIOp = RHSC->getOperand(0); if (RHSCIOp->getType()->getPointerAddressSpace() == LHSCIOp->getType()->getPointerAddressSpace()) { RHSOp = RHSC->getOperand(0); // If the pointer types don't match, insert a bitcast. if (LHSCIOp->getType() != RHSOp->getType()) RHSOp = Builder->CreateBitCast(RHSOp, LHSCIOp->getType()); } } else if (auto *RHSC = dyn_cast(ICmp.getOperand(1))) { RHSOp = ConstantExpr::getIntToPtr(RHSC, SrcTy); } if (RHSOp) return new ICmpInst(ICmp.getPredicate(), LHSCIOp, RHSOp); } // The code below only handles extension cast instructions, so far. // Enforce this. if (LHSCI->getOpcode() != Instruction::ZExt && LHSCI->getOpcode() != Instruction::SExt) return nullptr; bool isSignedExt = LHSCI->getOpcode() == Instruction::SExt; bool isSignedCmp = ICmp.isSigned(); if (auto *CI = dyn_cast(ICmp.getOperand(1))) { // Not an extension from the same type? RHSCIOp = CI->getOperand(0); if (RHSCIOp->getType() != LHSCIOp->getType()) return nullptr; // If the signedness of the two casts doesn't agree (i.e. one is a sext // and the other is a zext), then we can't handle this. if (CI->getOpcode() != LHSCI->getOpcode()) return nullptr; // Deal with equality cases early. if (ICmp.isEquality()) return new ICmpInst(ICmp.getPredicate(), LHSCIOp, RHSCIOp); // A signed comparison of sign extended values simplifies into a // signed comparison. if (isSignedCmp && isSignedExt) return new ICmpInst(ICmp.getPredicate(), LHSCIOp, RHSCIOp); // The other three cases all fold into an unsigned comparison. return new ICmpInst(ICmp.getUnsignedPredicate(), LHSCIOp, RHSCIOp); } // If we aren't dealing with a constant on the RHS, exit early. auto *C = dyn_cast(ICmp.getOperand(1)); if (!C) return nullptr; // Compute the constant that would happen if we truncated to SrcTy then // re-extended to DestTy. Constant *Res1 = ConstantExpr::getTrunc(C, SrcTy); Constant *Res2 = ConstantExpr::getCast(LHSCI->getOpcode(), Res1, DestTy); // If the re-extended constant didn't change... if (Res2 == C) { // Deal with equality cases early. if (ICmp.isEquality()) return new ICmpInst(ICmp.getPredicate(), LHSCIOp, Res1); // A signed comparison of sign extended values simplifies into a // signed comparison. if (isSignedExt && isSignedCmp) return new ICmpInst(ICmp.getPredicate(), LHSCIOp, Res1); // The other three cases all fold into an unsigned comparison. return new ICmpInst(ICmp.getUnsignedPredicate(), LHSCIOp, Res1); } // The re-extended constant changed, partly changed (in the case of a vector), // or could not be determined to be equal (in the case of a constant // expression), so the constant cannot be represented in the shorter type. // Consequently, we cannot emit a simple comparison. // All the cases that fold to true or false will have already been handled // by SimplifyICmpInst, so only deal with the tricky case. if (isSignedCmp || !isSignedExt || !isa(C)) return nullptr; // Evaluate the comparison for LT (we invert for GT below). LE and GE cases // should have been folded away previously and not enter in here. // We're performing an unsigned comp with a sign extended value. // This is true if the input is >= 0. [aka >s -1] Constant *NegOne = Constant::getAllOnesValue(SrcTy); Value *Result = Builder->CreateICmpSGT(LHSCIOp, NegOne, ICmp.getName()); // Finally, return the value computed. if (ICmp.getPredicate() == ICmpInst::ICMP_ULT) return replaceInstUsesWith(ICmp, Result); assert(ICmp.getPredicate() == ICmpInst::ICMP_UGT && "ICmp should be folded!"); return BinaryOperator::CreateNot(Result); } bool InstCombiner::OptimizeOverflowCheck(OverflowCheckFlavor OCF, Value *LHS, Value *RHS, Instruction &OrigI, Value *&Result, Constant *&Overflow) { if (OrigI.isCommutative() && isa(LHS) && !isa(RHS)) std::swap(LHS, RHS); auto SetResult = [&](Value *OpResult, Constant *OverflowVal, bool ReuseName) { Result = OpResult; Overflow = OverflowVal; if (ReuseName) Result->takeName(&OrigI); return true; }; // If the overflow check was an add followed by a compare, the insertion point // may be pointing to the compare. We want to insert the new instructions // before the add in case there are uses of the add between the add and the // compare. Builder->SetInsertPoint(&OrigI); switch (OCF) { case OCF_INVALID: llvm_unreachable("bad overflow check kind!"); case OCF_UNSIGNED_ADD: { OverflowResult OR = computeOverflowForUnsignedAdd(LHS, RHS, &OrigI); if (OR == OverflowResult::NeverOverflows) return SetResult(Builder->CreateNUWAdd(LHS, RHS), Builder->getFalse(), true); if (OR == OverflowResult::AlwaysOverflows) return SetResult(Builder->CreateAdd(LHS, RHS), Builder->getTrue(), true); // Fall through uadd into sadd LLVM_FALLTHROUGH; } case OCF_SIGNED_ADD: { // X + 0 -> {X, false} if (match(RHS, m_Zero())) return SetResult(LHS, Builder->getFalse(), false); // We can strength reduce this signed add into a regular add if we can prove // that it will never overflow. if (OCF == OCF_SIGNED_ADD) if (WillNotOverflowSignedAdd(LHS, RHS, OrigI)) return SetResult(Builder->CreateNSWAdd(LHS, RHS), Builder->getFalse(), true); break; } case OCF_UNSIGNED_SUB: case OCF_SIGNED_SUB: { // X - 0 -> {X, false} if (match(RHS, m_Zero())) return SetResult(LHS, Builder->getFalse(), false); if (OCF == OCF_SIGNED_SUB) { if (WillNotOverflowSignedSub(LHS, RHS, OrigI)) return SetResult(Builder->CreateNSWSub(LHS, RHS), Builder->getFalse(), true); } else { if (WillNotOverflowUnsignedSub(LHS, RHS, OrigI)) return SetResult(Builder->CreateNUWSub(LHS, RHS), Builder->getFalse(), true); } break; } case OCF_UNSIGNED_MUL: { OverflowResult OR = computeOverflowForUnsignedMul(LHS, RHS, &OrigI); if (OR == OverflowResult::NeverOverflows) return SetResult(Builder->CreateNUWMul(LHS, RHS), Builder->getFalse(), true); if (OR == OverflowResult::AlwaysOverflows) return SetResult(Builder->CreateMul(LHS, RHS), Builder->getTrue(), true); LLVM_FALLTHROUGH; } case OCF_SIGNED_MUL: // X * undef -> undef if (isa(RHS)) return SetResult(RHS, UndefValue::get(Builder->getInt1Ty()), false); // X * 0 -> {0, false} if (match(RHS, m_Zero())) return SetResult(RHS, Builder->getFalse(), false); // X * 1 -> {X, false} if (match(RHS, m_One())) return SetResult(LHS, Builder->getFalse(), false); if (OCF == OCF_SIGNED_MUL) if (WillNotOverflowSignedMul(LHS, RHS, OrigI)) return SetResult(Builder->CreateNSWMul(LHS, RHS), Builder->getFalse(), true); break; } return false; } /// \brief Recognize and process idiom involving test for multiplication /// overflow. /// /// The caller has matched a pattern of the form: /// I = cmp u (mul(zext A, zext B), V /// The function checks if this is a test for overflow and if so replaces /// multiplication with call to 'mul.with.overflow' intrinsic. /// /// \param I Compare instruction. /// \param MulVal Result of 'mult' instruction. It is one of the arguments of /// the compare instruction. Must be of integer type. /// \param OtherVal The other argument of compare instruction. /// \returns Instruction which must replace the compare instruction, NULL if no /// replacement required. static Instruction *processUMulZExtIdiom(ICmpInst &I, Value *MulVal, Value *OtherVal, InstCombiner &IC) { // Don't bother doing this transformation for pointers, don't do it for // vectors. if (!isa(MulVal->getType())) return nullptr; assert(I.getOperand(0) == MulVal || I.getOperand(1) == MulVal); assert(I.getOperand(0) == OtherVal || I.getOperand(1) == OtherVal); auto *MulInstr = dyn_cast(MulVal); if (!MulInstr) return nullptr; assert(MulInstr->getOpcode() == Instruction::Mul); auto *LHS = cast(MulInstr->getOperand(0)), *RHS = cast(MulInstr->getOperand(1)); assert(LHS->getOpcode() == Instruction::ZExt); assert(RHS->getOpcode() == Instruction::ZExt); Value *A = LHS->getOperand(0), *B = RHS->getOperand(0); // Calculate type and width of the result produced by mul.with.overflow. Type *TyA = A->getType(), *TyB = B->getType(); unsigned WidthA = TyA->getPrimitiveSizeInBits(), WidthB = TyB->getPrimitiveSizeInBits(); unsigned MulWidth; Type *MulType; if (WidthB > WidthA) { MulWidth = WidthB; MulType = TyB; } else { MulWidth = WidthA; MulType = TyA; } // In order to replace the original mul with a narrower mul.with.overflow, // all uses must ignore upper bits of the product. The number of used low // bits must be not greater than the width of mul.with.overflow. if (MulVal->hasNUsesOrMore(2)) for (User *U : MulVal->users()) { if (U == &I) continue; if (TruncInst *TI = dyn_cast(U)) { // Check if truncation ignores bits above MulWidth. unsigned TruncWidth = TI->getType()->getPrimitiveSizeInBits(); if (TruncWidth > MulWidth) return nullptr; } else if (BinaryOperator *BO = dyn_cast(U)) { // Check if AND ignores bits above MulWidth. if (BO->getOpcode() != Instruction::And) return nullptr; if (ConstantInt *CI = dyn_cast(BO->getOperand(1))) { const APInt &CVal = CI->getValue(); if (CVal.getBitWidth() - CVal.countLeadingZeros() > MulWidth) return nullptr; } } else { // Other uses prohibit this transformation. return nullptr; } } // Recognize patterns switch (I.getPredicate()) { case ICmpInst::ICMP_EQ: case ICmpInst::ICMP_NE: // Recognize pattern: // mulval = mul(zext A, zext B) // cmp eq/neq mulval, zext trunc mulval if (ZExtInst *Zext = dyn_cast(OtherVal)) if (Zext->hasOneUse()) { Value *ZextArg = Zext->getOperand(0); if (TruncInst *Trunc = dyn_cast(ZextArg)) if (Trunc->getType()->getPrimitiveSizeInBits() == MulWidth) break; //Recognized } // Recognize pattern: // mulval = mul(zext A, zext B) // cmp eq/neq mulval, and(mulval, mask), mask selects low MulWidth bits. ConstantInt *CI; Value *ValToMask; if (match(OtherVal, m_And(m_Value(ValToMask), m_ConstantInt(CI)))) { if (ValToMask != MulVal) return nullptr; const APInt &CVal = CI->getValue() + 1; if (CVal.isPowerOf2()) { unsigned MaskWidth = CVal.logBase2(); if (MaskWidth == MulWidth) break; // Recognized } } return nullptr; case ICmpInst::ICMP_UGT: // Recognize pattern: // mulval = mul(zext A, zext B) // cmp ugt mulval, max if (ConstantInt *CI = dyn_cast(OtherVal)) { APInt MaxVal = APInt::getMaxValue(MulWidth); MaxVal = MaxVal.zext(CI->getBitWidth()); if (MaxVal.eq(CI->getValue())) break; // Recognized } return nullptr; case ICmpInst::ICMP_UGE: // Recognize pattern: // mulval = mul(zext A, zext B) // cmp uge mulval, max+1 if (ConstantInt *CI = dyn_cast(OtherVal)) { APInt MaxVal = APInt::getOneBitSet(CI->getBitWidth(), MulWidth); if (MaxVal.eq(CI->getValue())) break; // Recognized } return nullptr; case ICmpInst::ICMP_ULE: // Recognize pattern: // mulval = mul(zext A, zext B) // cmp ule mulval, max if (ConstantInt *CI = dyn_cast(OtherVal)) { APInt MaxVal = APInt::getMaxValue(MulWidth); MaxVal = MaxVal.zext(CI->getBitWidth()); if (MaxVal.eq(CI->getValue())) break; // Recognized } return nullptr; case ICmpInst::ICMP_ULT: // Recognize pattern: // mulval = mul(zext A, zext B) // cmp ule mulval, max + 1 if (ConstantInt *CI = dyn_cast(OtherVal)) { APInt MaxVal = APInt::getOneBitSet(CI->getBitWidth(), MulWidth); if (MaxVal.eq(CI->getValue())) break; // Recognized } return nullptr; default: return nullptr; } InstCombiner::BuilderTy *Builder = IC.Builder; Builder->SetInsertPoint(MulInstr); // Replace: mul(zext A, zext B) --> mul.with.overflow(A, B) Value *MulA = A, *MulB = B; if (WidthA < MulWidth) MulA = Builder->CreateZExt(A, MulType); if (WidthB < MulWidth) MulB = Builder->CreateZExt(B, MulType); Value *F = Intrinsic::getDeclaration(I.getModule(), Intrinsic::umul_with_overflow, MulType); CallInst *Call = Builder->CreateCall(F, {MulA, MulB}, "umul"); IC.Worklist.Add(MulInstr); // If there are uses of mul result other than the comparison, we know that // they are truncation or binary AND. Change them to use result of // mul.with.overflow and adjust properly mask/size. if (MulVal->hasNUsesOrMore(2)) { Value *Mul = Builder->CreateExtractValue(Call, 0, "umul.value"); for (User *U : MulVal->users()) { if (U == &I || U == OtherVal) continue; if (TruncInst *TI = dyn_cast(U)) { if (TI->getType()->getPrimitiveSizeInBits() == MulWidth) IC.replaceInstUsesWith(*TI, Mul); else TI->setOperand(0, Mul); } else if (BinaryOperator *BO = dyn_cast(U)) { assert(BO->getOpcode() == Instruction::And); // Replace (mul & mask) --> zext (mul.with.overflow & short_mask) ConstantInt *CI = cast(BO->getOperand(1)); APInt ShortMask = CI->getValue().trunc(MulWidth); Value *ShortAnd = Builder->CreateAnd(Mul, ShortMask); Instruction *Zext = cast(Builder->CreateZExt(ShortAnd, BO->getType())); IC.Worklist.Add(Zext); IC.replaceInstUsesWith(*BO, Zext); } else { llvm_unreachable("Unexpected Binary operation"); } IC.Worklist.Add(cast(U)); } } if (isa(OtherVal)) IC.Worklist.Add(cast(OtherVal)); // The original icmp gets replaced with the overflow value, maybe inverted // depending on predicate. bool Inverse = false; switch (I.getPredicate()) { case ICmpInst::ICMP_NE: break; case ICmpInst::ICMP_EQ: Inverse = true; break; case ICmpInst::ICMP_UGT: case ICmpInst::ICMP_UGE: if (I.getOperand(0) == MulVal) break; Inverse = true; break; case ICmpInst::ICMP_ULT: case ICmpInst::ICMP_ULE: if (I.getOperand(1) == MulVal) break; Inverse = true; break; default: llvm_unreachable("Unexpected predicate"); } if (Inverse) { Value *Res = Builder->CreateExtractValue(Call, 1); return BinaryOperator::CreateNot(Res); } return ExtractValueInst::Create(Call, 1); } /// When performing a comparison against a constant, it is possible that not all /// the bits in the LHS are demanded. This helper method computes the mask that /// IS demanded. static APInt getDemandedBitsLHSMask(ICmpInst &I, unsigned BitWidth, bool isSignCheck) { if (isSignCheck) return APInt::getSignBit(BitWidth); ConstantInt *CI = dyn_cast(I.getOperand(1)); if (!CI) return APInt::getAllOnesValue(BitWidth); const APInt &RHS = CI->getValue(); switch (I.getPredicate()) { // For a UGT comparison, we don't care about any bits that // correspond to the trailing ones of the comparand. The value of these // bits doesn't impact the outcome of the comparison, because any value // greater than the RHS must differ in a bit higher than these due to carry. case ICmpInst::ICMP_UGT: { unsigned trailingOnes = RHS.countTrailingOnes(); APInt lowBitsSet = APInt::getLowBitsSet(BitWidth, trailingOnes); return ~lowBitsSet; } // Similarly, for a ULT comparison, we don't care about the trailing zeros. // Any value less than the RHS must differ in a higher bit because of carries. case ICmpInst::ICMP_ULT: { unsigned trailingZeros = RHS.countTrailingZeros(); APInt lowBitsSet = APInt::getLowBitsSet(BitWidth, trailingZeros); return ~lowBitsSet; } default: return APInt::getAllOnesValue(BitWidth); } } /// \brief Check if the order of \p Op0 and \p Op1 as operand in an ICmpInst /// should be swapped. /// The decision is based on how many times these two operands are reused /// as subtract operands and their positions in those instructions. /// The rational is that several architectures use the same instruction for /// both subtract and cmp, thus it is better if the order of those operands /// match. /// \return true if Op0 and Op1 should be swapped. static bool swapMayExposeCSEOpportunities(const Value * Op0, const Value * Op1) { // Filter out pointer value as those cannot appears directly in subtract. // FIXME: we may want to go through inttoptrs or bitcasts. if (Op0->getType()->isPointerTy()) return false; // Count every uses of both Op0 and Op1 in a subtract. // Each time Op0 is the first operand, count -1: swapping is bad, the // subtract has already the same layout as the compare. // Each time Op0 is the second operand, count +1: swapping is good, the // subtract has a different layout as the compare. // At the end, if the benefit is greater than 0, Op0 should come second to // expose more CSE opportunities. int GlobalSwapBenefits = 0; for (const User *U : Op0->users()) { const BinaryOperator *BinOp = dyn_cast(U); if (!BinOp || BinOp->getOpcode() != Instruction::Sub) continue; // If Op0 is the first argument, this is not beneficial to swap the // arguments. int LocalSwapBenefits = -1; unsigned Op1Idx = 1; if (BinOp->getOperand(Op1Idx) == Op0) { Op1Idx = 0; LocalSwapBenefits = 1; } if (BinOp->getOperand(Op1Idx) != Op1) continue; GlobalSwapBenefits += LocalSwapBenefits; } return GlobalSwapBenefits > 0; } /// \brief Check that one use is in the same block as the definition and all /// other uses are in blocks dominated by a given block. /// /// \param DI Definition /// \param UI Use /// \param DB Block that must dominate all uses of \p DI outside /// the parent block /// \return true when \p UI is the only use of \p DI in the parent block /// and all other uses of \p DI are in blocks dominated by \p DB. /// bool InstCombiner::dominatesAllUses(const Instruction *DI, const Instruction *UI, const BasicBlock *DB) const { assert(DI && UI && "Instruction not defined\n"); // Ignore incomplete definitions. if (!DI->getParent()) return false; // DI and UI must be in the same block. if (DI->getParent() != UI->getParent()) return false; // Protect from self-referencing blocks. if (DI->getParent() == DB) return false; for (const User *U : DI->users()) { auto *Usr = cast(U); if (Usr != UI && !DT.dominates(DB, Usr->getParent())) return false; } return true; } /// Return true when the instruction sequence within a block is select-cmp-br. static bool isChainSelectCmpBranch(const SelectInst *SI) { const BasicBlock *BB = SI->getParent(); if (!BB) return false; auto *BI = dyn_cast_or_null(BB->getTerminator()); if (!BI || BI->getNumSuccessors() != 2) return false; auto *IC = dyn_cast(BI->getCondition()); if (!IC || (IC->getOperand(0) != SI && IC->getOperand(1) != SI)) return false; return true; } /// \brief True when a select result is replaced by one of its operands /// in select-icmp sequence. This will eventually result in the elimination /// of the select. /// /// \param SI Select instruction /// \param Icmp Compare instruction /// \param SIOpd Operand that replaces the select /// /// Notes: /// - The replacement is global and requires dominator information /// - The caller is responsible for the actual replacement /// /// Example: /// /// entry: /// %4 = select i1 %3, %C* %0, %C* null /// %5 = icmp eq %C* %4, null /// br i1 %5, label %9, label %7 /// ... /// ;