123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- FastISel.h - Definition of the FastISel class ------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- ///
- /// \file
- /// This file defines the FastISel class.
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CODEGEN_FASTISEL_H
- #define LLVM_CODEGEN_FASTISEL_H
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/CodeGen/MachineBasicBlock.h"
- #include "llvm/CodeGen/TargetLowering.h"
- #include "llvm/IR/Attributes.h"
- #include "llvm/IR/CallingConv.h"
- #include "llvm/IR/DebugLoc.h"
- #include "llvm/IR/DerivedTypes.h"
- #include "llvm/IR/InstrTypes.h"
- #include "llvm/IR/IntrinsicInst.h"
- #include "llvm/Support/MachineValueType.h"
- #include <algorithm>
- #include <cstdint>
- #include <utility>
- namespace llvm {
- class AllocaInst;
- class BasicBlock;
- class CallInst;
- class Constant;
- class ConstantFP;
- class DataLayout;
- class FunctionLoweringInfo;
- class LoadInst;
- class MachineConstantPool;
- class MachineFrameInfo;
- class MachineFunction;
- class MachineInstr;
- class MachineMemOperand;
- class MachineOperand;
- class MachineRegisterInfo;
- class MCContext;
- class MCInstrDesc;
- class MCSymbol;
- class TargetInstrInfo;
- class TargetLibraryInfo;
- class TargetMachine;
- class TargetRegisterClass;
- class TargetRegisterInfo;
- class Type;
- class User;
- class Value;
- /// This is a fast-path instruction selection class that generates poor
- /// code and doesn't support illegal types or non-trivial lowering, but runs
- /// quickly.
- class FastISel {
- public:
- using ArgListEntry = TargetLoweringBase::ArgListEntry;
- using ArgListTy = TargetLoweringBase::ArgListTy;
- struct CallLoweringInfo {
- Type *RetTy = nullptr;
- bool RetSExt : 1;
- bool RetZExt : 1;
- bool IsVarArg : 1;
- bool IsInReg : 1;
- bool DoesNotReturn : 1;
- bool IsReturnValueUsed : 1;
- bool IsPatchPoint : 1;
- // IsTailCall Should be modified by implementations of FastLowerCall
- // that perform tail call conversions.
- bool IsTailCall = false;
- unsigned NumFixedArgs = -1;
- CallingConv::ID CallConv = CallingConv::C;
- const Value *Callee = nullptr;
- MCSymbol *Symbol = nullptr;
- ArgListTy Args;
- const CallBase *CB = nullptr;
- MachineInstr *Call = nullptr;
- Register ResultReg;
- unsigned NumResultRegs = 0;
- SmallVector<Value *, 16> OutVals;
- SmallVector<ISD::ArgFlagsTy, 16> OutFlags;
- SmallVector<Register, 16> OutRegs;
- SmallVector<ISD::InputArg, 4> Ins;
- SmallVector<Register, 4> InRegs;
- CallLoweringInfo()
- : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false),
- DoesNotReturn(false), IsReturnValueUsed(true), IsPatchPoint(false) {}
- CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
- const Value *Target, ArgListTy &&ArgsList,
- const CallBase &Call) {
- RetTy = ResultTy;
- Callee = Target;
- IsInReg = Call.hasRetAttr(Attribute::InReg);
- DoesNotReturn = Call.doesNotReturn();
- IsVarArg = FuncTy->isVarArg();
- IsReturnValueUsed = !Call.use_empty();
- RetSExt = Call.hasRetAttr(Attribute::SExt);
- RetZExt = Call.hasRetAttr(Attribute::ZExt);
- CallConv = Call.getCallingConv();
- Args = std::move(ArgsList);
- NumFixedArgs = FuncTy->getNumParams();
- CB = &Call;
- return *this;
- }
- CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
- MCSymbol *Target, ArgListTy &&ArgsList,
- const CallBase &Call,
- unsigned FixedArgs = ~0U) {
- RetTy = ResultTy;
- Callee = Call.getCalledOperand();
- Symbol = Target;
- IsInReg = Call.hasRetAttr(Attribute::InReg);
- DoesNotReturn = Call.doesNotReturn();
- IsVarArg = FuncTy->isVarArg();
- IsReturnValueUsed = !Call.use_empty();
- RetSExt = Call.hasRetAttr(Attribute::SExt);
- RetZExt = Call.hasRetAttr(Attribute::ZExt);
- CallConv = Call.getCallingConv();
- Args = std::move(ArgsList);
- NumFixedArgs = (FixedArgs == ~0U) ? FuncTy->getNumParams() : FixedArgs;
- CB = &Call;
- return *this;
- }
- CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
- const Value *Target, ArgListTy &&ArgsList,
- unsigned FixedArgs = ~0U) {
- RetTy = ResultTy;
- Callee = Target;
- CallConv = CC;
- Args = std::move(ArgsList);
- NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
- return *this;
- }
- CallLoweringInfo &setCallee(const DataLayout &DL, MCContext &Ctx,
- CallingConv::ID CC, Type *ResultTy,
- StringRef Target, ArgListTy &&ArgsList,
- unsigned FixedArgs = ~0U);
- CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
- MCSymbol *Target, ArgListTy &&ArgsList,
- unsigned FixedArgs = ~0U) {
- RetTy = ResultTy;
- Symbol = Target;
- CallConv = CC;
- Args = std::move(ArgsList);
- NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
- return *this;
- }
- CallLoweringInfo &setTailCall(bool Value = true) {
- IsTailCall = Value;
- return *this;
- }
- CallLoweringInfo &setIsPatchPoint(bool Value = true) {
- IsPatchPoint = Value;
- return *this;
- }
- ArgListTy &getArgs() { return Args; }
- void clearOuts() {
- OutVals.clear();
- OutFlags.clear();
- OutRegs.clear();
- }
- void clearIns() {
- Ins.clear();
- InRegs.clear();
- }
- };
- protected:
- DenseMap<const Value *, Register> LocalValueMap;
- FunctionLoweringInfo &FuncInfo;
- MachineFunction *MF;
- MachineRegisterInfo &MRI;
- MachineFrameInfo &MFI;
- MachineConstantPool &MCP;
- DebugLoc DbgLoc;
- const TargetMachine &TM;
- const DataLayout &DL;
- const TargetInstrInfo &TII;
- const TargetLowering &TLI;
- const TargetRegisterInfo &TRI;
- const TargetLibraryInfo *LibInfo;
- bool SkipTargetIndependentISel;
- bool UseInstrRefDebugInfo = false;
- /// The position of the last instruction for materializing constants
- /// for use in the current block. It resets to EmitStartPt when it makes sense
- /// (for example, it's usually profitable to avoid function calls between the
- /// definition and the use)
- MachineInstr *LastLocalValue = nullptr;
- /// The top most instruction in the current block that is allowed for
- /// emitting local variables. LastLocalValue resets to EmitStartPt when it
- /// makes sense (for example, on function calls)
- MachineInstr *EmitStartPt = nullptr;
- public:
- virtual ~FastISel();
- /// Return the position of the last instruction emitted for
- /// materializing constants for use in the current block.
- MachineInstr *getLastLocalValue() { return LastLocalValue; }
- /// Update the position of the last instruction emitted for
- /// materializing constants for use in the current block.
- void setLastLocalValue(MachineInstr *I) {
- EmitStartPt = I;
- LastLocalValue = I;
- }
- /// Set the current block to which generated machine instructions will
- /// be appended.
- void startNewBlock();
- /// Flush the local value map.
- void finishBasicBlock();
- /// Return current debug location information.
- DebugLoc getCurDebugLoc() const { return DbgLoc; }
- /// Do "fast" instruction selection for function arguments and append
- /// the machine instructions to the current block. Returns true when
- /// successful.
- bool lowerArguments();
- /// Do "fast" instruction selection for the given LLVM IR instruction
- /// and append the generated machine instructions to the current block.
- /// Returns true if selection was successful.
- bool selectInstruction(const Instruction *I);
- /// Do "fast" instruction selection for the given LLVM IR operator
- /// (Instruction or ConstantExpr), and append generated machine instructions
- /// to the current block. Return true if selection was successful.
- bool selectOperator(const User *I, unsigned Opcode);
- /// Create a virtual register and arrange for it to be assigned the
- /// value for the given LLVM value.
- Register getRegForValue(const Value *V);
- /// Look up the value to see if its value is already cached in a
- /// register. It may be defined by instructions across blocks or defined
- /// locally.
- Register lookUpRegForValue(const Value *V);
- /// This is a wrapper around getRegForValue that also takes care of
- /// truncating or sign-extending the given getelementptr index value.
- Register getRegForGEPIndex(const Value *Idx);
- /// We're checking to see if we can fold \p LI into \p FoldInst. Note
- /// that we could have a sequence where multiple LLVM IR instructions are
- /// folded into the same machineinstr. For example we could have:
- ///
- /// A: x = load i32 *P
- /// B: y = icmp A, 42
- /// C: br y, ...
- ///
- /// In this scenario, \p LI is "A", and \p FoldInst is "C". We know about "B"
- /// (and any other folded instructions) because it is between A and C.
- ///
- /// If we succeed folding, return true.
- bool tryToFoldLoad(const LoadInst *LI, const Instruction *FoldInst);
- /// The specified machine instr operand is a vreg, and that vreg is
- /// being provided by the specified load instruction. If possible, try to
- /// fold the load as an operand to the instruction, returning true if
- /// possible.
- ///
- /// This method should be implemented by targets.
- virtual bool tryToFoldLoadIntoMI(MachineInstr * /*MI*/, unsigned /*OpNo*/,
- const LoadInst * /*LI*/) {
- return false;
- }
- /// Reset InsertPt to prepare for inserting instructions into the
- /// current block.
- void recomputeInsertPt();
- /// Remove all dead instructions between the I and E.
- void removeDeadCode(MachineBasicBlock::iterator I,
- MachineBasicBlock::iterator E);
- using SavePoint = MachineBasicBlock::iterator;
- /// Prepare InsertPt to begin inserting instructions into the local
- /// value area and return the old insert position.
- SavePoint enterLocalValueArea();
- /// Reset InsertPt to the given old insert position.
- void leaveLocalValueArea(SavePoint Old);
- /// Signal whether instruction referencing variable locations are desired for
- /// this function's debug-info.
- void useInstrRefDebugInfo(bool Flag) {
- UseInstrRefDebugInfo = Flag;
- }
- protected:
- explicit FastISel(FunctionLoweringInfo &FuncInfo,
- const TargetLibraryInfo *LibInfo,
- bool SkipTargetIndependentISel = false);
- /// This method is called by target-independent code when the normal
- /// FastISel process fails to select an instruction. This gives targets a
- /// chance to emit code for anything that doesn't fit into FastISel's
- /// framework. It returns true if it was successful.
- virtual bool fastSelectInstruction(const Instruction *I) = 0;
- /// This method is called by target-independent code to do target-
- /// specific argument lowering. It returns true if it was successful.
- virtual bool fastLowerArguments();
- /// This method is called by target-independent code to do target-
- /// specific call lowering. It returns true if it was successful.
- virtual bool fastLowerCall(CallLoweringInfo &CLI);
- /// This method is called by target-independent code to do target-
- /// specific intrinsic lowering. It returns true if it was successful.
- virtual bool fastLowerIntrinsicCall(const IntrinsicInst *II);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type and opcode be emitted.
- virtual unsigned fastEmit_(MVT VT, MVT RetVT, unsigned Opcode);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type, opcode, and register operand be emitted.
- virtual unsigned fastEmit_r(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type, opcode, and register operands be emitted.
- virtual unsigned fastEmit_rr(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0,
- unsigned Op1);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type, opcode, and register and immediate
- /// operands be emitted.
- virtual unsigned fastEmit_ri(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0,
- uint64_t Imm);
- /// This method is a wrapper of fastEmit_ri.
- ///
- /// It first tries to emit an instruction with an immediate operand using
- /// fastEmit_ri. If that fails, it materializes the immediate into a register
- /// and try fastEmit_rr instead.
- Register fastEmit_ri_(MVT VT, unsigned Opcode, unsigned Op0, uint64_t Imm,
- MVT ImmType);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type, opcode, and immediate operand be emitted.
- virtual unsigned fastEmit_i(MVT VT, MVT RetVT, unsigned Opcode, uint64_t Imm);
- /// This method is called by target-independent code to request that an
- /// instruction with the given type, opcode, and floating-point immediate
- /// operand be emitted.
- virtual unsigned fastEmit_f(MVT VT, MVT RetVT, unsigned Opcode,
- const ConstantFP *FPImm);
- /// Emit a MachineInstr with no operands and a result register in the
- /// given register class.
- Register fastEmitInst_(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC);
- /// Emit a MachineInstr with one register operand and a result register
- /// in the given register class.
- Register fastEmitInst_r(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0);
- /// Emit a MachineInstr with two register operands and a result
- /// register in the given register class.
- Register fastEmitInst_rr(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0,
- unsigned Op1);
- /// Emit a MachineInstr with three register operands and a result
- /// register in the given register class.
- Register fastEmitInst_rrr(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0,
- unsigned Op1, unsigned Op2);
- /// Emit a MachineInstr with a register operand, an immediate, and a
- /// result register in the given register class.
- Register fastEmitInst_ri(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0,
- uint64_t Imm);
- /// Emit a MachineInstr with one register operand and two immediate
- /// operands.
- Register fastEmitInst_rii(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0,
- uint64_t Imm1, uint64_t Imm2);
- /// Emit a MachineInstr with a floating point immediate, and a result
- /// register in the given register class.
- Register fastEmitInst_f(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC,
- const ConstantFP *FPImm);
- /// Emit a MachineInstr with two register operands, an immediate, and a
- /// result register in the given register class.
- Register fastEmitInst_rri(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, unsigned Op0,
- unsigned Op1, uint64_t Imm);
- /// Emit a MachineInstr with a single immediate operand, and a result
- /// register in the given register class.
- Register fastEmitInst_i(unsigned MachineInstOpcode,
- const TargetRegisterClass *RC, uint64_t Imm);
- /// Emit a MachineInstr for an extract_subreg from a specified index of
- /// a superregister to a specified type.
- Register fastEmitInst_extractsubreg(MVT RetVT, unsigned Op0, uint32_t Idx);
- /// Emit MachineInstrs to compute the value of Op with all but the
- /// least significant bit set to zero.
- Register fastEmitZExtFromI1(MVT VT, unsigned Op0);
- /// Emit an unconditional branch to the given block, unless it is the
- /// immediate (fall-through) successor, and update the CFG.
- void fastEmitBranch(MachineBasicBlock *MSucc, const DebugLoc &DbgLoc);
- /// Emit an unconditional branch to \p FalseMBB, obtains the branch weight
- /// and adds TrueMBB and FalseMBB to the successor list.
- void finishCondBranch(const BasicBlock *BranchBB, MachineBasicBlock *TrueMBB,
- MachineBasicBlock *FalseMBB);
- /// Update the value map to include the new mapping for this
- /// instruction, or insert an extra copy to get the result in a previous
- /// determined register.
- ///
- /// NOTE: This is only necessary because we might select a block that uses a
- /// value before we select the block that defines the value. It might be
- /// possible to fix this by selecting blocks in reverse postorder.
- void updateValueMap(const Value *I, Register Reg, unsigned NumRegs = 1);
- Register createResultReg(const TargetRegisterClass *RC);
- /// Try to constrain Op so that it is usable by argument OpNum of the
- /// provided MCInstrDesc. If this fails, create a new virtual register in the
- /// correct class and COPY the value there.
- Register constrainOperandRegClass(const MCInstrDesc &II, Register Op,
- unsigned OpNum);
- /// Emit a constant in a register using target-specific logic, such as
- /// constant pool loads.
- virtual unsigned fastMaterializeConstant(const Constant *C) { return 0; }
- /// Emit an alloca address in a register using target-specific logic.
- virtual unsigned fastMaterializeAlloca(const AllocaInst *C) { return 0; }
- /// Emit the floating-point constant +0.0 in a register using target-
- /// specific logic.
- virtual unsigned fastMaterializeFloatZero(const ConstantFP *CF) {
- return 0;
- }
- /// Check if \c Add is an add that can be safely folded into \c GEP.
- ///
- /// \c Add can be folded into \c GEP if:
- /// - \c Add is an add,
- /// - \c Add's size matches \c GEP's,
- /// - \c Add is in the same basic block as \c GEP, and
- /// - \c Add has a constant operand.
- bool canFoldAddIntoGEP(const User *GEP, const Value *Add);
- /// Create a machine mem operand from the given instruction.
- MachineMemOperand *createMachineMemOperandFor(const Instruction *I) const;
- CmpInst::Predicate optimizeCmpPredicate(const CmpInst *CI) const;
- bool lowerCallTo(const CallInst *CI, MCSymbol *Symbol, unsigned NumArgs);
- bool lowerCallTo(const CallInst *CI, const char *SymName,
- unsigned NumArgs);
- bool lowerCallTo(CallLoweringInfo &CLI);
- bool lowerCall(const CallInst *I);
- /// Select and emit code for a binary operator instruction, which has
- /// an opcode which directly corresponds to the given ISD opcode.
- bool selectBinaryOp(const User *I, unsigned ISDOpcode);
- bool selectFNeg(const User *I, const Value *In);
- bool selectGetElementPtr(const User *I);
- bool selectStackmap(const CallInst *I);
- bool selectPatchpoint(const CallInst *I);
- bool selectCall(const User *I);
- bool selectIntrinsicCall(const IntrinsicInst *II);
- bool selectBitCast(const User *I);
- bool selectFreeze(const User *I);
- bool selectCast(const User *I, unsigned Opcode);
- bool selectExtractValue(const User *U);
- bool selectXRayCustomEvent(const CallInst *II);
- bool selectXRayTypedEvent(const CallInst *II);
- bool shouldOptForSize(const MachineFunction *MF) const {
- // TODO: Implement PGSO.
- return MF->getFunction().hasOptSize();
- }
- private:
- /// Handle PHI nodes in successor blocks.
- ///
- /// Emit code to ensure constants are copied into registers when needed.
- /// Remember the virtual registers that need to be added to the Machine PHI
- /// nodes as input. We cannot just directly add them, because expansion might
- /// result in multiple MBB's for one BB. As such, the start of the BB might
- /// correspond to a different MBB than the end.
- bool handlePHINodesInSuccessorBlocks(const BasicBlock *LLVMBB);
- /// Helper for materializeRegForValue to materialize a constant in a
- /// target-independent way.
- Register materializeConstant(const Value *V, MVT VT);
- /// Helper for getRegForVale. This function is called when the value
- /// isn't already available in a register and must be materialized with new
- /// instructions.
- Register materializeRegForValue(const Value *V, MVT VT);
- /// Clears LocalValueMap and moves the area for the new local variables
- /// to the beginning of the block. It helps to avoid spilling cached variables
- /// across heavy instructions like calls.
- void flushLocalValueMap();
- /// Removes dead local value instructions after SavedLastLocalvalue.
- void removeDeadLocalValueCode(MachineInstr *SavedLastLocalValue);
- /// Insertion point before trying to select the current instruction.
- MachineBasicBlock::iterator SavedInsertPt;
- /// Add a stackmap or patchpoint intrinsic call's live variable
- /// operands to a stackmap or patchpoint machine instruction.
- bool addStackMapLiveVars(SmallVectorImpl<MachineOperand> &Ops,
- const CallInst *CI, unsigned StartIdx);
- bool lowerCallOperands(const CallInst *CI, unsigned ArgIdx, unsigned NumArgs,
- const Value *Callee, bool ForceRetVoidTy,
- CallLoweringInfo &CLI);
- };
- } // end namespace llvm
- #endif // LLVM_CODEGEN_FASTISEL_H
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|