//===-- PPCFastISel.cpp - PowerPC FastISel implementation -----------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file defines the PowerPC-specific support for the FastISel class. Some // of the target-specific code is generated by tablegen in the file // PPCGenFastISel.inc, which is #included here. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/PPCPredicates.h" #include "PPC.h" #include "PPCCCState.h" #include "PPCCallingConv.h" #include "PPCISelLowering.h" #include "PPCMachineFunctionInfo.h" #include "PPCSubtarget.h" #include "PPCTargetMachine.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Operator.h" #include "llvm/Support/Debug.h" #include "llvm/Target/TargetMachine.h" //===----------------------------------------------------------------------===// // // TBD: // fastLowerArguments: Handle simple cases. // PPCMaterializeGV: Handle TLS. // SelectCall: Handle function pointers. // SelectCall: Handle multi-register return values. // SelectCall: Optimize away nops for local calls. // processCallArgs: Handle bit-converted arguments. // finishCall: Handle multi-register return values. // PPCComputeAddress: Handle parameter references as FrameIndex's. // PPCEmitCmp: Handle immediate as operand 1. // SelectCall: Handle small byval arguments. // SelectIntrinsicCall: Implement. // SelectSelect: Implement. // Consider factoring isTypeLegal into the base class. // Implement switches and jump tables. // //===----------------------------------------------------------------------===// usingnamespacellvm; #define DEBUG_TYPE … namespace { struct Address { … }; class PPCFastISel final : public FastISel { … }; } // end anonymous namespace static std::optional<PPC::Predicate> getComparePred(CmpInst::Predicate Pred) { … } // Determine whether the type Ty is simple enough to be handled by // fast-isel, and return its equivalent machine type in VT. // FIXME: Copied directly from ARM -- factor into base class? bool PPCFastISel::isTypeLegal(Type *Ty, MVT &VT) { … } // Determine whether the type Ty is simple enough to be handled by // fast-isel as a load target, and return its equivalent machine type in VT. bool PPCFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { … } bool PPCFastISel::isValueAvailable(const Value *V) const { … } // Given a value Obj, create an Address object Addr that represents its // address. Return false if we can't handle it. bool PPCFastISel::PPCComputeAddress(const Value *Obj, Address &Addr) { … } // Fix up some addresses that can't be used directly. For example, if // an offset won't fit in an instruction field, we may need to move it // into an index register. void PPCFastISel::PPCSimplifyAddress(Address &Addr, bool &UseOffset, unsigned &IndexReg) { … } // Emit a load instruction if possible, returning true if we succeeded, // otherwise false. See commentary below for how the register class of // the load is determined. bool PPCFastISel::PPCEmitLoad(MVT VT, Register &ResultReg, Address &Addr, const TargetRegisterClass *RC, bool IsZExt, unsigned FP64LoadOpc) { … } // Attempt to fast-select a load instruction. bool PPCFastISel::SelectLoad(const Instruction *I) { … } // Emit a store instruction to store SrcReg at Addr. bool PPCFastISel::PPCEmitStore(MVT VT, unsigned SrcReg, Address &Addr) { … } // Attempt to fast-select a store instruction. bool PPCFastISel::SelectStore(const Instruction *I) { … } // Attempt to fast-select a branch instruction. bool PPCFastISel::SelectBranch(const Instruction *I) { … } // Attempt to emit a compare of the two source values. Signed and unsigned // comparisons are supported. Return false if we can't handle it. bool PPCFastISel::PPCEmitCmp(const Value *SrcValue1, const Value *SrcValue2, bool IsZExt, unsigned DestReg, const PPC::Predicate Pred) { … } // Attempt to fast-select a floating-point extend instruction. bool PPCFastISel::SelectFPExt(const Instruction *I) { … } // Attempt to fast-select a floating-point truncate instruction. bool PPCFastISel::SelectFPTrunc(const Instruction *I) { … } // Move an i32 or i64 value in a GPR to an f64 value in an FPR. // FIXME: When direct register moves are implemented (see PowerISA 2.07), // those should be used instead of moving via a stack slot when the // subtarget permits. // FIXME: The code here is sloppy for the 4-byte case. Can use a 4-byte // stack slot and 4-byte store/load sequence. Or just sext the 4-byte // case to 8 bytes which produces tighter code but wastes stack space. unsigned PPCFastISel::PPCMoveToFPReg(MVT SrcVT, unsigned SrcReg, bool IsSigned) { … } // Attempt to fast-select an integer-to-floating-point conversion. // FIXME: Once fast-isel has better support for VSX, conversions using // direct moves should be implemented. bool PPCFastISel::SelectIToFP(const Instruction *I, bool IsSigned) { … } // Move the floating-point value in SrcReg into an integer destination // register, and return the register (or zero if we can't handle it). // FIXME: When direct register moves are implemented (see PowerISA 2.07), // those should be used instead of moving via a stack slot when the // subtarget permits. unsigned PPCFastISel::PPCMoveToIntReg(const Instruction *I, MVT VT, unsigned SrcReg, bool IsSigned) { … } // Attempt to fast-select a floating-point-to-integer conversion. // FIXME: Once fast-isel has better support for VSX, conversions using // direct moves should be implemented. bool PPCFastISel::SelectFPToI(const Instruction *I, bool IsSigned) { … } // Attempt to fast-select a binary integer operation that isn't already // handled automatically. bool PPCFastISel::SelectBinaryIntOp(const Instruction *I, unsigned ISDOpcode) { … } // Handle arguments to a call that we're attempting to fast-select. // Return false if the arguments are too complex for us at the moment. bool PPCFastISel::processCallArgs(SmallVectorImpl<Value*> &Args, SmallVectorImpl<unsigned> &ArgRegs, SmallVectorImpl<MVT> &ArgVTs, SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags, SmallVectorImpl<unsigned> &RegArgs, CallingConv::ID CC, unsigned &NumBytes, bool IsVarArg) { … } // For a call that we've determined we can fast-select, finish the // call sequence and generate a copy to obtain the return value (if any). bool PPCFastISel::finishCall(MVT RetVT, CallLoweringInfo &CLI, unsigned &NumBytes) { … } bool PPCFastISel::fastLowerCall(CallLoweringInfo &CLI) { … } // Attempt to fast-select a return instruction. bool PPCFastISel::SelectRet(const Instruction *I) { … } // Attempt to emit an integer extend of SrcReg into DestReg. Both // signed and zero extensions are supported. Return false if we // can't handle it. bool PPCFastISel::PPCEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, unsigned DestReg, bool IsZExt) { … } // Attempt to fast-select an indirect branch instruction. bool PPCFastISel::SelectIndirectBr(const Instruction *I) { … } // Attempt to fast-select an integer truncate instruction. bool PPCFastISel::SelectTrunc(const Instruction *I) { … } // Attempt to fast-select an integer extend instruction. bool PPCFastISel::SelectIntExt(const Instruction *I) { … } // Attempt to fast-select an instruction that wasn't handled by // the table-generated machinery. bool PPCFastISel::fastSelectInstruction(const Instruction *I) { … } // Materialize a floating-point constant into a register, and return // the register number (or zero if we failed to handle it). unsigned PPCFastISel::PPCMaterializeFP(const ConstantFP *CFP, MVT VT) { … } // Materialize the address of a global value into a register, and return // the register number (or zero if we failed to handle it). unsigned PPCFastISel::PPCMaterializeGV(const GlobalValue *GV, MVT VT) { … } // Materialize a 32-bit integer constant into a register, and return // the register number (or zero if we failed to handle it). unsigned PPCFastISel::PPCMaterialize32BitInt(int64_t Imm, const TargetRegisterClass *RC) { … } // Materialize a 64-bit integer constant into a register, and return // the register number (or zero if we failed to handle it). unsigned PPCFastISel::PPCMaterialize64BitInt(int64_t Imm, const TargetRegisterClass *RC) { … } // Materialize an integer constant into a register, and return // the register number (or zero if we failed to handle it). unsigned PPCFastISel::PPCMaterializeInt(const ConstantInt *CI, MVT VT, bool UseSExt) { … } // Materialize a constant into a register, and return the register // number (or zero if we failed to handle it). unsigned PPCFastISel::fastMaterializeConstant(const Constant *C) { … } // Materialize the address created by an alloca into a register, and // return the register number (or zero if we failed to handle it). unsigned PPCFastISel::fastMaterializeAlloca(const AllocaInst *AI) { … } // Fold loads into extends when possible. // FIXME: We can have multiple redundant extend/trunc instructions // following a load. The folding only picks up one. Extend this // to check subsequent instructions for the same pattern and remove // them. Thus ResultReg should be the def reg for the last redundant // instruction in a chain, and all intervening instructions can be // removed from parent. Change test/CodeGen/PowerPC/fast-isel-fold.ll // to add ELF64-NOT: rldicl to the appropriate tests when this works. bool PPCFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo, const LoadInst *LI) { … } // Attempt to lower call arguments in a faster way than done by // the selection DAG code. bool PPCFastISel::fastLowerArguments() { … } // Handle materializing integer constants into a register. This is not // automatically generated for PowerPC, so must be explicitly created here. unsigned PPCFastISel::fastEmit_i(MVT Ty, MVT VT, unsigned Opc, uint64_t Imm) { … } // Override for ADDI and ADDI8 to set the correct register class // on RHS operand 0. The automatic infrastructure naively assumes // GPRC for i32 and G8RC for i64; the concept of "no R0" is lost // for these cases. At the moment, none of the other automatically // generated RI instructions require special treatment. However, once // SelectSelect is implemented, "isel" requires similar handling. // // Also be conservative about the output register class. Avoid // assigning R0 or X0 to the output register for GPRC and G8RC // register classes, as any such result could be used in ADDI, etc., // where those regs have another meaning. unsigned PPCFastISel::fastEmitInst_ri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, uint64_t Imm) { … } // Override for instructions with one register operand to avoid use of // R0/X0. The automatic infrastructure isn't aware of the context so // we must be conservative. unsigned PPCFastISel::fastEmitInst_r(unsigned MachineInstOpcode, const TargetRegisterClass* RC, unsigned Op0) { … } // Override for instructions with two register operands to avoid use // of R0/X0. The automatic infrastructure isn't aware of the context // so we must be conservative. unsigned PPCFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass* RC, unsigned Op0, unsigned Op1) { … } namespace llvm { // Create the fast instruction selector for PowerPC64 ELF. FastISel *PPC::createFastISel(FunctionLoweringInfo &FuncInfo, const TargetLibraryInfo *LibInfo) { … } }