//===- ARMFastISel.cpp - ARM 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 ARM-specific support for the FastISel class. Some // of the target-specific code is generated by tablegen in the file // ARMGenFastISel.inc, which is #included here. // //===----------------------------------------------------------------------===// #include "ARM.h" #include "ARMBaseInstrInfo.h" #include "ARMBaseRegisterInfo.h" #include "ARMCallingConv.h" #include "ARMConstantPoolValue.h" #include "ARMISelLowering.h" #include "ARMMachineFunctionInfo.h" #include "ARMSubtarget.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "MCTargetDesc/ARMBaseInfo.h" #include "Utils/ARMBaseInfo.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RuntimeLibcallUtil.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/CodeGenTypes/MachineValueType.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include #include #include using namespace llvm; namespace { // All possible address modes, plus some. struct Address { enum { RegBase, FrameIndexBase } BaseType = RegBase; union { unsigned Reg; int FI; } Base; int Offset = 0; // Innocuous defaults for our address. Address() { Base.Reg = 0; } }; class ARMFastISel final : public FastISel { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when generating code for different targets. const ARMSubtarget *Subtarget; Module &M; const TargetMachine &TM; const TargetInstrInfo &TII; const TargetLowering &TLI; ARMFunctionInfo *AFI; // Convenience variables to avoid some queries. bool isThumb2; LLVMContext *Context; public: explicit ARMFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) : FastISel(funcInfo, libInfo), Subtarget(&funcInfo.MF->getSubtarget()), M(const_cast(*funcInfo.Fn->getParent())), TM(funcInfo.MF->getTarget()), TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) { AFI = funcInfo.MF->getInfo(); isThumb2 = AFI->isThumbFunction(); Context = &funcInfo.Fn->getContext(); } private: // Code from FastISel.cpp. unsigned fastEmitInst_r(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0); unsigned fastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, unsigned Op1); unsigned fastEmitInst_ri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, uint64_t Imm); unsigned fastEmitInst_i(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm); // Backend specific FastISel code. bool fastSelectInstruction(const Instruction *I) override; unsigned fastMaterializeConstant(const Constant *C) override; unsigned fastMaterializeAlloca(const AllocaInst *AI) override; bool tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo, const LoadInst *LI) override; bool fastLowerArguments() override; #include "ARMGenFastISel.inc" // Instruction selection routines. bool SelectLoad(const Instruction *I); bool SelectStore(const Instruction *I); bool SelectBranch(const Instruction *I); bool SelectIndirectBr(const Instruction *I); bool SelectCmp(const Instruction *I); bool SelectFPExt(const Instruction *I); bool SelectFPTrunc(const Instruction *I); bool SelectBinaryIntOp(const Instruction *I, unsigned ISDOpcode); bool SelectBinaryFPOp(const Instruction *I, unsigned ISDOpcode); bool SelectIToFP(const Instruction *I, bool isSigned); bool SelectFPToI(const Instruction *I, bool isSigned); bool SelectDiv(const Instruction *I, bool isSigned); bool SelectRem(const Instruction *I, bool isSigned); bool SelectCall(const Instruction *I, const char *IntrMemName); bool SelectIntrinsicCall(const IntrinsicInst &I); bool SelectSelect(const Instruction *I); bool SelectRet(const Instruction *I); bool SelectTrunc(const Instruction *I); bool SelectIntExt(const Instruction *I); bool SelectShift(const Instruction *I, ARM_AM::ShiftOpc ShiftTy); // Utility routines. bool isPositionIndependent() const; bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); bool ARMEmitCmp(const Value *Src1Value, const Value *Src2Value, bool isZExt); bool ARMEmitLoad(MVT VT, Register &ResultReg, Address &Addr, MaybeAlign Alignment = std::nullopt, bool isZExt = true, bool allocReg = true); bool ARMEmitStore(MVT VT, unsigned SrcReg, Address &Addr, MaybeAlign Alignment = std::nullopt); bool ARMComputeAddress(const Value *Obj, Address &Addr); void ARMSimplifyAddress(Address &Addr, MVT VT, bool useAM3); bool ARMIsMemCpySmall(uint64_t Len); bool ARMTryEmitSmallMemCpy(Address Dest, Address Src, uint64_t Len, MaybeAlign Alignment); unsigned ARMEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt); unsigned ARMMaterializeFP(const ConstantFP *CFP, MVT VT); unsigned ARMMaterializeInt(const Constant *C, MVT VT); unsigned ARMMaterializeGV(const GlobalValue *GV, MVT VT); unsigned ARMMoveToFPReg(MVT VT, unsigned SrcReg); unsigned ARMMoveToIntReg(MVT VT, unsigned SrcReg); unsigned ARMSelectCallOp(bool UseReg); unsigned ARMLowerPICELF(const GlobalValue *GV, MVT VT); const TargetLowering *getTargetLowering() { return &TLI; } // Call handling routines. CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return, bool isVarArg); bool ProcessCallArgs(SmallVectorImpl &Args, SmallVectorImpl &ArgRegs, SmallVectorImpl &ArgVTs, SmallVectorImpl &ArgFlags, SmallVectorImpl &RegArgs, CallingConv::ID CC, unsigned &NumBytes, bool isVarArg); unsigned getLibcallReg(const Twine &Name); bool FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, const Instruction *I, CallingConv::ID CC, unsigned &NumBytes, bool isVarArg); bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call); // OptionalDef handling routines. bool isARMNEONPred(const MachineInstr *MI); bool DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR); const MachineInstrBuilder &AddOptionalDefs(const MachineInstrBuilder &MIB); void AddLoadStoreOperands(MVT VT, Address &Addr, const MachineInstrBuilder &MIB, MachineMemOperand::Flags Flags, bool useAM3); }; } // end anonymous namespace // DefinesOptionalPredicate - This is different from DefinesPredicate in that // we don't care about implicit defs here, just places we'll need to add a // default CCReg argument. Sets CPSR if we're setting CPSR instead of CCR. bool ARMFastISel::DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR) { if (!MI->hasOptionalDef()) return false; // Look to see if our OptionalDef is defining CPSR or CCR. for (const MachineOperand &MO : MI->operands()) { if (!MO.isReg() || !MO.isDef()) continue; if (MO.getReg() == ARM::CPSR) *CPSR = true; } return true; } bool ARMFastISel::isARMNEONPred(const MachineInstr *MI) { const MCInstrDesc &MCID = MI->getDesc(); // If we're a thumb2 or not NEON function we'll be handled via isPredicable. if ((MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainNEON || AFI->isThumb2Function()) return MI->isPredicable(); for (const MCOperandInfo &opInfo : MCID.operands()) if (opInfo.isPredicate()) return true; return false; } // If the machine is predicable go ahead and add the predicate operands, if // it needs default CC operands add those. // TODO: If we want to support thumb1 then we'll need to deal with optional // CPSR defs that need to be added before the remaining operands. See s_cc_out // for descriptions why. const MachineInstrBuilder & ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) { MachineInstr *MI = &*MIB; // Do we use a predicate? or... // Are we NEON in ARM mode and have a predicate operand? If so, I know // we're not predicable but add it anyways. if (isARMNEONPred(MI)) MIB.add(predOps(ARMCC::AL)); // Do we optionally set a predicate? Preds is size > 0 iff the predicate // defines CPSR. All other OptionalDefines in ARM are the CCR register. bool CPSR = false; if (DefinesOptionalPredicate(MI, &CPSR)) MIB.add(CPSR ? t1CondCodeOp() : condCodeOp()); return MIB; } unsigned ARMFastISel::fastEmitInst_r(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0) { Register ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); // Make sure the input operand is sufficiently constrained to be legal // for this instruction. Op0 = constrainOperandRegClass(II, Op0, 1); if (II.getNumDefs() >= 1) { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II, ResultReg).addReg(Op0)); } else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addReg(Op0)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.implicit_defs()[0])); } return ResultReg; } unsigned ARMFastISel::fastEmitInst_rr(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, unsigned Op1) { Register ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); // Make sure the input operands are sufficiently constrained to be legal // for this instruction. Op0 = constrainOperandRegClass(II, Op0, 1); Op1 = constrainOperandRegClass(II, Op1, 2); if (II.getNumDefs() >= 1) { AddOptionalDefs( BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II, ResultReg) .addReg(Op0) .addReg(Op1)); } else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addReg(Op0) .addReg(Op1)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.implicit_defs()[0])); } return ResultReg; } unsigned ARMFastISel::fastEmitInst_ri(unsigned MachineInstOpcode, const TargetRegisterClass *RC, unsigned Op0, uint64_t Imm) { Register ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); // Make sure the input operand is sufficiently constrained to be legal // for this instruction. Op0 = constrainOperandRegClass(II, Op0, 1); if (II.getNumDefs() >= 1) { AddOptionalDefs( BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II, ResultReg) .addReg(Op0) .addImm(Imm)); } else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addReg(Op0) .addImm(Imm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.implicit_defs()[0])); } return ResultReg; } unsigned ARMFastISel::fastEmitInst_i(unsigned MachineInstOpcode, const TargetRegisterClass *RC, uint64_t Imm) { Register ResultReg = createResultReg(RC); const MCInstrDesc &II = TII.get(MachineInstOpcode); if (II.getNumDefs() >= 1) { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II, ResultReg).addImm(Imm)); } else { AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addImm(Imm)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg) .addReg(II.implicit_defs()[0])); } return ResultReg; } // TODO: Don't worry about 64-bit now, but when this is fixed remove the // checks from the various callers. unsigned ARMFastISel::ARMMoveToFPReg(MVT VT, unsigned SrcReg) { if (VT == MVT::f64) return 0; Register MoveReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVSR), MoveReg) .addReg(SrcReg)); return MoveReg; } unsigned ARMFastISel::ARMMoveToIntReg(MVT VT, unsigned SrcReg) { if (VT == MVT::i64) return 0; Register MoveReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVRS), MoveReg) .addReg(SrcReg)); return MoveReg; } // For double width floating point we need to materialize two constants // (the high and the low) into integer registers then use a move to get // the combined constant into an FP reg. unsigned ARMFastISel::ARMMaterializeFP(const ConstantFP *CFP, MVT VT) { const APFloat Val = CFP->getValueAPF(); bool is64bit = VT == MVT::f64; // This checks to see if we can use VFP3 instructions to materialize // a constant, otherwise we have to go through the constant pool. if (TLI.isFPImmLegal(Val, VT)) { int Imm; unsigned Opc; if (is64bit) { Imm = ARM_AM::getFP64Imm(Val); Opc = ARM::FCONSTD; } else { Imm = ARM_AM::getFP32Imm(Val); Opc = ARM::FCONSTS; } Register DestReg = createResultReg(TLI.getRegClassFor(VT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), DestReg).addImm(Imm)); return DestReg; } // Require VFP2 for loading fp constants. if (!Subtarget->hasVFP2Base()) return false; // MachineConstantPool wants an explicit alignment. Align Alignment = DL.getPrefTypeAlign(CFP->getType()); unsigned Idx = MCP.getConstantPoolIndex(cast(CFP), Alignment); Register DestReg = createResultReg(TLI.getRegClassFor(VT)); unsigned Opc = is64bit ? ARM::VLDRD : ARM::VLDRS; // The extra reg is for addrmode5. AddOptionalDefs( BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), DestReg) .addConstantPoolIndex(Idx) .addReg(0)); return DestReg; } unsigned ARMFastISel::ARMMaterializeInt(const Constant *C, MVT VT) { if (VT != MVT::i32 && VT != MVT::i16 && VT != MVT::i8 && VT != MVT::i1) return 0; // If we can do this in a single instruction without a constant pool entry // do so now. const ConstantInt *CI = cast(C); if (Subtarget->hasV6T2Ops() && isUInt<16>(CI->getZExtValue())) { unsigned Opc = isThumb2 ? ARM::t2MOVi16 : ARM::MOVi16; const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass; Register ImmReg = createResultReg(RC); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ImmReg) .addImm(CI->getZExtValue())); return ImmReg; } // Use MVN to emit negative constants. if (VT == MVT::i32 && Subtarget->hasV6T2Ops() && CI->isNegative()) { unsigned Imm = (unsigned)~(CI->getSExtValue()); bool UseImm = isThumb2 ? (ARM_AM::getT2SOImmVal(Imm) != -1) : (ARM_AM::getSOImmVal(Imm) != -1); if (UseImm) { unsigned Opc = isThumb2 ? ARM::t2MVNi : ARM::MVNi; const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass; Register ImmReg = createResultReg(RC); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ImmReg) .addImm(Imm)); return ImmReg; } } unsigned ResultReg = 0; if (Subtarget->useMovt()) ResultReg = fastEmit_i(VT, VT, ISD::Constant, CI->getZExtValue()); if (ResultReg) return ResultReg; // Load from constant pool. For now 32-bit only. if (VT != MVT::i32) return 0; // MachineConstantPool wants an explicit alignment. Align Alignment = DL.getPrefTypeAlign(C->getType()); unsigned Idx = MCP.getConstantPoolIndex(C, Alignment); ResultReg = createResultReg(TLI.getRegClassFor(VT)); if (isThumb2) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::t2LDRpci), ResultReg) .addConstantPoolIndex(Idx)); else { // The extra immediate is for addrmode2. ResultReg = constrainOperandRegClass(TII.get(ARM::LDRcp), ResultReg, 0); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::LDRcp), ResultReg) .addConstantPoolIndex(Idx) .addImm(0)); } return ResultReg; } bool ARMFastISel::isPositionIndependent() const { return TLI.isPositionIndependent(); } unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, MVT VT) { // For now 32-bit only. if (VT != MVT::i32 || GV->isThreadLocal()) return 0; // ROPI/RWPI not currently supported. if (Subtarget->isROPI() || Subtarget->isRWPI()) return 0; bool IsIndirect = Subtarget->isGVIndirectSymbol(GV); const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass; Register DestReg = createResultReg(RC); // FastISel TLS support on non-MachO is broken, punt to SelectionDAG. const GlobalVariable *GVar = dyn_cast(GV); bool IsThreadLocal = GVar && GVar->isThreadLocal(); if (!Subtarget->isTargetMachO() && IsThreadLocal) return 0; bool IsPositionIndependent = isPositionIndependent(); // Use movw+movt when possible, it avoids constant pool entries. // Non-darwin targets only support static movt relocations in FastISel. if (Subtarget->useMovt() && (Subtarget->isTargetMachO() || !IsPositionIndependent)) { unsigned Opc; unsigned char TF = 0; if (Subtarget->isTargetMachO()) TF = ARMII::MO_NONLAZY; if (IsPositionIndependent) Opc = isThumb2 ? ARM::t2MOV_ga_pcrel : ARM::MOV_ga_pcrel; else Opc = isThumb2 ? ARM::t2MOVi32imm : ARM::MOVi32imm; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), DestReg).addGlobalAddress(GV, 0, TF)); } else { // MachineConstantPool wants an explicit alignment. Align Alignment = DL.getPrefTypeAlign(GV->getType()); if (Subtarget->isTargetELF() && IsPositionIndependent) return ARMLowerPICELF(GV, VT); // Grab index. unsigned PCAdj = IsPositionIndependent ? (Subtarget->isThumb() ? 4 : 8) : 0; unsigned Id = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, Id, ARMCP::CPValue, PCAdj); unsigned Idx = MCP.getConstantPoolIndex(CPV, Alignment); // Load value. MachineInstrBuilder MIB; if (isThumb2) { unsigned Opc = IsPositionIndependent ? ARM::t2LDRpci_pic : ARM::t2LDRpci; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), DestReg).addConstantPoolIndex(Idx); if (IsPositionIndependent) MIB.addImm(Id); AddOptionalDefs(MIB); } else { // The extra immediate is for addrmode2. DestReg = constrainOperandRegClass(TII.get(ARM::LDRcp), DestReg, 0); MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::LDRcp), DestReg) .addConstantPoolIndex(Idx) .addImm(0); AddOptionalDefs(MIB); if (IsPositionIndependent) { unsigned Opc = IsIndirect ? ARM::PICLDR : ARM::PICADD; Register NewDestReg = createResultReg(TLI.getRegClassFor(VT)); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), NewDestReg) .addReg(DestReg) .addImm(Id); AddOptionalDefs(MIB); return NewDestReg; } } } if ((Subtarget->isTargetELF() && Subtarget->isGVInGOT(GV)) || (Subtarget->isTargetMachO() && IsIndirect)) { MachineInstrBuilder MIB; Register NewDestReg = createResultReg(TLI.getRegClassFor(VT)); if (isThumb2) MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::t2LDRi12), NewDestReg) .addReg(DestReg) .addImm(0); else MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::LDRi12), NewDestReg) .addReg(DestReg) .addImm(0); DestReg = NewDestReg; AddOptionalDefs(MIB); } return DestReg; } unsigned ARMFastISel::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 ARMMaterializeFP(CFP, VT); else if (const GlobalValue *GV = dyn_cast(C)) return ARMMaterializeGV(GV, VT); else if (isa(C)) return ARMMaterializeInt(C, VT); return 0; } // TODO: unsigned ARMFastISel::TargetMaterializeFloatZero(const ConstantFP *CF); unsigned ARMFastISel::fastMaterializeAlloca(const AllocaInst *AI) { // Don't handle dynamic allocas. if (!FuncInfo.StaticAllocaMap.count(AI)) return 0; MVT VT; if (!isLoadTypeLegal(AI->getType(), VT)) return 0; DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); // This will get lowered later into the correct offsets and registers // via rewriteXFrameIndex. if (SI != FuncInfo.StaticAllocaMap.end()) { unsigned Opc = isThumb2 ? ARM::t2ADDri : ARM::ADDri; const TargetRegisterClass* RC = TLI.getRegClassFor(VT); Register ResultReg = createResultReg(RC); ResultReg = constrainOperandRegClass(TII.get(Opc), ResultReg, 0); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addFrameIndex(SI->second) .addImm(0)); return ResultReg; } return 0; } bool ARMFastISel::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 ARMFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { 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; } // Computes the address to get to an object. bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) { // Some boilerplate from the X86 FastISel. 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; } if (PointerType *Ty = dyn_cast(Obj->getType())) if (Ty->getAddressSpace() > 255) // Fast instruction selection doesn't support the special // address spaces. return false; switch (Opcode) { default: break; case Instruction::BitCast: // Look through bitcasts. return ARMComputeAddress(U->getOperand(0), Addr); case Instruction::IntToPtr: // Look past no-op inttoptrs. if (TLI.getValueType(DL, U->getOperand(0)->getType()) == TLI.getPointerTy(DL)) return ARMComputeAddress(U->getOperand(0), Addr); break; case Instruction::PtrToInt: // Look past no-op ptrtoints. if (TLI.getValueType(DL, U->getType()) == TLI.getPointerTy(DL)) return ARMComputeAddress(U->getOperand(0), Addr); break; case Instruction::GetElementPtr: { Address SavedAddr = Addr; int TmpOffset = Addr.Offset; // 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 = GTI.getSequentialElementStride(DL); while (true) { 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.Offset = TmpOffset; if (ARMComputeAddress(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.BaseType = Address::FrameIndexBase; Addr.Base.FI = SI->second; return true; } break; } } // Try to get this in a register if nothing else has worked. if (Addr.Base.Reg == 0) Addr.Base.Reg = getRegForValue(Obj); return Addr.Base.Reg != 0; } void ARMFastISel::ARMSimplifyAddress(Address &Addr, MVT VT, bool useAM3) { bool needsLowering = false; switch (VT.SimpleTy) { default: llvm_unreachable("Unhandled load/store type!"); case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: if (!useAM3) { // Integer loads/stores handle 12-bit offsets. needsLowering = ((Addr.Offset & 0xfff) != Addr.Offset); // Handle negative offsets. if (needsLowering && isThumb2) needsLowering = !(Subtarget->hasV6T2Ops() && Addr.Offset < 0 && Addr.Offset > -256); } else { // ARM halfword load/stores and signed byte loads use +/-imm8 offsets. needsLowering = (Addr.Offset > 255 || Addr.Offset < -255); } break; case MVT::f32: case MVT::f64: // Floating point operands handle 8-bit offsets. needsLowering = ((Addr.Offset & 0xff) != Addr.Offset); break; } // If this is a stack pointer and the offset needs to be simplified then // put the alloca address into a register, set the base type back to // register and continue. This should almost never happen. if (needsLowering && Addr.BaseType == Address::FrameIndexBase) { const TargetRegisterClass *RC = isThumb2 ? &ARM::tGPRRegClass : &ARM::GPRRegClass; Register ResultReg = createResultReg(RC); unsigned Opc = isThumb2 ? ARM::t2ADDri : ARM::ADDri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addFrameIndex(Addr.Base.FI) .addImm(0)); Addr.Base.Reg = ResultReg; Addr.BaseType = Address::RegBase; } // Since the offset is too large for the load/store instruction // get the reg+offset into a register. if (needsLowering) { Addr.Base.Reg = fastEmit_ri_(MVT::i32, ISD::ADD, Addr.Base.Reg, Addr.Offset, MVT::i32); Addr.Offset = 0; } } void ARMFastISel::AddLoadStoreOperands(MVT VT, Address &Addr, const MachineInstrBuilder &MIB, MachineMemOperand::Flags Flags, bool useAM3) { // addrmode5 output depends on the selection dag addressing dividing the // offset by 4 that it then later multiplies. Do this here as well. if (VT.SimpleTy == MVT::f32 || VT.SimpleTy == MVT::f64) Addr.Offset /= 4; // Frame base works a bit differently. Handle it separately. if (Addr.BaseType == Address::FrameIndexBase) { int FI = Addr.Base.FI; int Offset = Addr.Offset; MachineMemOperand *MMO = FuncInfo.MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(*FuncInfo.MF, FI, Offset), Flags, MFI.getObjectSize(FI), MFI.getObjectAlign(FI)); // Now add the rest of the operands. MIB.addFrameIndex(FI); // ARM halfword load/stores and signed byte loads need an additional // operand. if (useAM3) { int Imm = (Addr.Offset < 0) ? (0x100 | -Addr.Offset) : Addr.Offset; MIB.addReg(0); MIB.addImm(Imm); } else { MIB.addImm(Addr.Offset); } MIB.addMemOperand(MMO); } else { // Now add the rest of the operands. MIB.addReg(Addr.Base.Reg); // ARM halfword load/stores and signed byte loads need an additional // operand. if (useAM3) { int Imm = (Addr.Offset < 0) ? (0x100 | -Addr.Offset) : Addr.Offset; MIB.addReg(0); MIB.addImm(Imm); } else { MIB.addImm(Addr.Offset); } } AddOptionalDefs(MIB); } bool ARMFastISel::ARMEmitLoad(MVT VT, Register &ResultReg, Address &Addr, MaybeAlign Alignment, bool isZExt, bool allocReg) { unsigned Opc; bool useAM3 = false; bool needVMOV = false; const TargetRegisterClass *RC; switch (VT.SimpleTy) { // This is mostly going to be Neon/vector support. default: return false; case MVT::i1: case MVT::i8: if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) Opc = isZExt ? ARM::t2LDRBi8 : ARM::t2LDRSBi8; else Opc = isZExt ? ARM::t2LDRBi12 : ARM::t2LDRSBi12; } else { if (isZExt) { Opc = ARM::LDRBi12; } else { Opc = ARM::LDRSB; useAM3 = true; } } RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRnopcRegClass; break; case MVT::i16: if (Alignment && *Alignment < Align(2) && !Subtarget->allowsUnalignedMem()) return false; if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) Opc = isZExt ? ARM::t2LDRHi8 : ARM::t2LDRSHi8; else Opc = isZExt ? ARM::t2LDRHi12 : ARM::t2LDRSHi12; } else { Opc = isZExt ? ARM::LDRH : ARM::LDRSH; useAM3 = true; } RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRnopcRegClass; break; case MVT::i32: if (Alignment && *Alignment < Align(4) && !Subtarget->allowsUnalignedMem()) return false; if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) Opc = ARM::t2LDRi8; else Opc = ARM::t2LDRi12; } else { Opc = ARM::LDRi12; } RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRnopcRegClass; break; case MVT::f32: if (!Subtarget->hasVFP2Base()) return false; // Unaligned loads need special handling. Floats require word-alignment. if (Alignment && *Alignment < Align(4)) { needVMOV = true; VT = MVT::i32; Opc = isThumb2 ? ARM::t2LDRi12 : ARM::LDRi12; RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRnopcRegClass; } else { Opc = ARM::VLDRS; RC = TLI.getRegClassFor(VT); } break; case MVT::f64: // Can load and store double precision even without FeatureFP64 if (!Subtarget->hasVFP2Base()) return false; // FIXME: Unaligned loads need special handling. Doublewords require // word-alignment. if (Alignment && *Alignment < Align(4)) return false; Opc = ARM::VLDRD; RC = TLI.getRegClassFor(VT); break; } // Simplify this down to something we can handle. ARMSimplifyAddress(Addr, VT, useAM3); // Create the base instruction, then add the operands. if (allocReg) ResultReg = createResultReg(RC); assert(ResultReg > 255 && "Expected an allocated virtual register."); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg); AddLoadStoreOperands(VT, Addr, MIB, MachineMemOperand::MOLoad, useAM3); // If we had an unaligned load of a float we've converted it to an regular // load. Now we must move from the GRP to the FP register. if (needVMOV) { Register MoveReg = createResultReg(TLI.getRegClassFor(MVT::f32)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVSR), MoveReg) .addReg(ResultReg)); ResultReg = MoveReg; } return true; } bool ARMFastISel::SelectLoad(const Instruction *I) { // Atomic loads need special handling. if (cast(I)->isAtomic()) return false; const Value *SV = I->getOperand(0); if (TLI.supportSwiftError()) { // Swifterror values can come from either a function parameter with // swifterror attribute or an alloca with swifterror attribute. if (const Argument *Arg = dyn_cast(SV)) { if (Arg->hasSwiftErrorAttr()) return false; } if (const AllocaInst *Alloca = dyn_cast(SV)) { if (Alloca->isSwiftError()) 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 (!ARMComputeAddress(I->getOperand(0), Addr)) return false; Register ResultReg; if (!ARMEmitLoad(VT, ResultReg, Addr, cast(I)->getAlign())) return false; updateValueMap(I, ResultReg); return true; } bool ARMFastISel::ARMEmitStore(MVT VT, unsigned SrcReg, Address &Addr, MaybeAlign Alignment) { unsigned StrOpc; bool useAM3 = false; switch (VT.SimpleTy) { // This is mostly going to be Neon/vector support. default: return false; case MVT::i1: { Register Res = createResultReg(isThumb2 ? &ARM::tGPRRegClass : &ARM::GPRRegClass); unsigned Opc = isThumb2 ? ARM::t2ANDri : ARM::ANDri; SrcReg = constrainOperandRegClass(TII.get(Opc), SrcReg, 1); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), Res) .addReg(SrcReg).addImm(1)); SrcReg = Res; [[fallthrough]]; } case MVT::i8: if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) StrOpc = ARM::t2STRBi8; else StrOpc = ARM::t2STRBi12; } else { StrOpc = ARM::STRBi12; } break; case MVT::i16: if (Alignment && *Alignment < Align(2) && !Subtarget->allowsUnalignedMem()) return false; if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) StrOpc = ARM::t2STRHi8; else StrOpc = ARM::t2STRHi12; } else { StrOpc = ARM::STRH; useAM3 = true; } break; case MVT::i32: if (Alignment && *Alignment < Align(4) && !Subtarget->allowsUnalignedMem()) return false; if (isThumb2) { if (Addr.Offset < 0 && Addr.Offset > -256 && Subtarget->hasV6T2Ops()) StrOpc = ARM::t2STRi8; else StrOpc = ARM::t2STRi12; } else { StrOpc = ARM::STRi12; } break; case MVT::f32: if (!Subtarget->hasVFP2Base()) return false; // Unaligned stores need special handling. Floats require word-alignment. if (Alignment && *Alignment < Align(4)) { Register MoveReg = createResultReg(TLI.getRegClassFor(MVT::i32)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVRS), MoveReg) .addReg(SrcReg)); SrcReg = MoveReg; VT = MVT::i32; StrOpc = isThumb2 ? ARM::t2STRi12 : ARM::STRi12; } else { StrOpc = ARM::VSTRS; } break; case MVT::f64: // Can load and store double precision even without FeatureFP64 if (!Subtarget->hasVFP2Base()) return false; // FIXME: Unaligned stores need special handling. Doublewords require // word-alignment. if (Alignment && *Alignment < Align(4)) return false; StrOpc = ARM::VSTRD; break; } // Simplify this down to something we can handle. ARMSimplifyAddress(Addr, VT, useAM3); // Create the base instruction, then add the operands. SrcReg = constrainOperandRegClass(TII.get(StrOpc), SrcReg, 0); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(StrOpc)) .addReg(SrcReg); AddLoadStoreOperands(VT, Addr, MIB, MachineMemOperand::MOStore, useAM3); return true; } bool ARMFastISel::SelectStore(const Instruction *I) { Value *Op0 = I->getOperand(0); unsigned SrcReg = 0; // Atomic stores need special handling. if (cast(I)->isAtomic()) return false; const Value *PtrV = I->getOperand(1); if (TLI.supportSwiftError()) { // Swifterror values can come from either a function parameter with // swifterror attribute or an alloca with swifterror attribute. if (const Argument *Arg = dyn_cast(PtrV)) { if (Arg->hasSwiftErrorAttr()) return false; } if (const AllocaInst *Alloca = dyn_cast(PtrV)) { if (Alloca->isSwiftError()) 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 (!ARMComputeAddress(I->getOperand(1), Addr)) return false; if (!ARMEmitStore(VT, SrcReg, Addr, cast(I)->getAlign())) return false; return true; } static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) { switch (Pred) { // Needs two compares... case CmpInst::FCMP_ONE: case CmpInst::FCMP_UEQ: default: // AL is our "false" for now. The other two need more compares. return ARMCC::AL; case CmpInst::ICMP_EQ: case CmpInst::FCMP_OEQ: return ARMCC::EQ; case CmpInst::ICMP_SGT: case CmpInst::FCMP_OGT: return ARMCC::GT; case CmpInst::ICMP_SGE: case CmpInst::FCMP_OGE: return ARMCC::GE; case CmpInst::ICMP_UGT: case CmpInst::FCMP_UGT: return ARMCC::HI; case CmpInst::FCMP_OLT: return ARMCC::MI; case CmpInst::ICMP_ULE: case CmpInst::FCMP_OLE: return ARMCC::LS; case CmpInst::FCMP_ORD: return ARMCC::VC; case CmpInst::FCMP_UNO: return ARMCC::VS; case CmpInst::FCMP_UGE: return ARMCC::PL; case CmpInst::ICMP_SLT: case CmpInst::FCMP_ULT: return ARMCC::LT; case CmpInst::ICMP_SLE: case CmpInst::FCMP_ULE: return ARMCC::LE; case CmpInst::FCMP_UNE: case CmpInst::ICMP_NE: return ARMCC::NE; case CmpInst::ICMP_UGE: return ARMCC::HS; case CmpInst::ICMP_ULT: return ARMCC::LO; } } bool ARMFastISel::SelectBranch(const Instruction *I) { const BranchInst *BI = cast(I); MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; // Simple branch support. // If we can, avoid recomputing the compare - redoing it could lead to wonky // behavior. if (const CmpInst *CI = dyn_cast(BI->getCondition())) { if (CI->hasOneUse() && (CI->getParent() == I->getParent())) { // Get the compare predicate. // Try to take advantage of fallthrough opportunities. CmpInst::Predicate Predicate = CI->getPredicate(); if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); Predicate = CmpInst::getInversePredicate(Predicate); } ARMCC::CondCodes ARMPred = getComparePred(Predicate); // We may not handle every CC for now. if (ARMPred == ARMCC::AL) return false; // Emit the compare. if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1), CI->isUnsigned())) return false; unsigned BrOpc = isThumb2 ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(BrOpc)) .addMBB(TBB).addImm(ARMPred).addReg(ARM::CPSR); finishCondBranch(BI->getParent(), TBB, FBB); return true; } } else if (TruncInst *TI = dyn_cast(BI->getCondition())) { MVT SourceVT; if (TI->hasOneUse() && TI->getParent() == I->getParent() && (isLoadTypeLegal(TI->getOperand(0)->getType(), SourceVT))) { unsigned TstOpc = isThumb2 ? ARM::t2TSTri : ARM::TSTri; Register OpReg = getRegForValue(TI->getOperand(0)); OpReg = constrainOperandRegClass(TII.get(TstOpc), OpReg, 0); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TstOpc)) .addReg(OpReg).addImm(1)); unsigned CCMode = ARMCC::NE; if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); CCMode = ARMCC::EQ; } unsigned BrOpc = isThumb2 ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(BrOpc)) .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR); finishCondBranch(BI->getParent(), TBB, FBB); return true; } } else if (const ConstantInt *CI = dyn_cast(BI->getCondition())) { uint64_t Imm = CI->getZExtValue(); MachineBasicBlock *Target = (Imm == 0) ? FBB : TBB; fastEmitBranch(Target, MIMD.getDL()); return true; } Register CmpReg = getRegForValue(BI->getCondition()); if (CmpReg == 0) return false; // We've been divorced from our compare! Our block was split, and // now our compare lives in a predecessor block. We musn't // re-compare here, as the children of the compare aren't guaranteed // live across the block boundary (we *could* check for this). // Regardless, the compare has been done in the predecessor block, // and it left a value for us in a virtual register. Ergo, we test // the one-bit value left in the virtual register. unsigned TstOpc = isThumb2 ? ARM::t2TSTri : ARM::TSTri; CmpReg = constrainOperandRegClass(TII.get(TstOpc), CmpReg, 0); AddOptionalDefs( BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TstOpc)) .addReg(CmpReg) .addImm(1)); unsigned CCMode = ARMCC::NE; if (FuncInfo.MBB->isLayoutSuccessor(TBB)) { std::swap(TBB, FBB); CCMode = ARMCC::EQ; } unsigned BrOpc = isThumb2 ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(BrOpc)) .addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR); finishCondBranch(BI->getParent(), TBB, FBB); return true; } bool ARMFastISel::SelectIndirectBr(const Instruction *I) { Register AddrReg = getRegForValue(I->getOperand(0)); if (AddrReg == 0) return false; unsigned Opc = isThumb2 ? ARM::tBRIND : ARM::BX; assert(isThumb2 || Subtarget->hasV4TOps()); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc)).addReg(AddrReg)); const IndirectBrInst *IB = cast(I); for (const BasicBlock *SuccBB : IB->successors()) FuncInfo.MBB->addSuccessor(FuncInfo.MBBMap[SuccBB]); return true; } bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value, bool isZExt) { Type *Ty = Src1Value->getType(); EVT SrcEVT = TLI.getValueType(DL, Ty, true); if (!SrcEVT.isSimple()) return false; MVT SrcVT = SrcEVT.getSimpleVT(); if (Ty->isFloatTy() && !Subtarget->hasVFP2Base()) return false; if (Ty->isDoubleTy() && (!Subtarget->hasVFP2Base() || !Subtarget->hasFP64())) return false; // Check to see if the 2nd operand is a constant that we can encode directly // in the compare. int Imm = 0; bool UseImm = false; bool isNegativeImm = false; // FIXME: At -O0 we don't have anything that canonicalizes operand order. // Thus, Src1Value may be a ConstantInt, but we're missing it. if (const ConstantInt *ConstInt = dyn_cast(Src2Value)) { if (SrcVT == MVT::i32 || SrcVT == MVT::i16 || SrcVT == MVT::i8 || SrcVT == MVT::i1) { const APInt &CIVal = ConstInt->getValue(); Imm = (isZExt) ? (int)CIVal.getZExtValue() : (int)CIVal.getSExtValue(); // For INT_MIN/LONG_MIN (i.e., 0x80000000) we need to use a cmp, rather // then a cmn, because there is no way to represent 2147483648 as a // signed 32-bit int. if (Imm < 0 && Imm != (int)0x80000000) { isNegativeImm = true; Imm = -Imm; } UseImm = isThumb2 ? (ARM_AM::getT2SOImmVal(Imm) != -1) : (ARM_AM::getSOImmVal(Imm) != -1); } } else if (const ConstantFP *ConstFP = dyn_cast(Src2Value)) { if (SrcVT == MVT::f32 || SrcVT == MVT::f64) if (ConstFP->isZero() && !ConstFP->isNegative()) UseImm = true; } unsigned CmpOpc; bool isICmp = true; bool needsExt = false; switch (SrcVT.SimpleTy) { default: return false; // TODO: Verify compares. case MVT::f32: isICmp = false; CmpOpc = UseImm ? ARM::VCMPZS : ARM::VCMPS; break; case MVT::f64: isICmp = false; CmpOpc = UseImm ? ARM::VCMPZD : ARM::VCMPD; break; case MVT::i1: case MVT::i8: case MVT::i16: needsExt = true; [[fallthrough]]; case MVT::i32: if (isThumb2) { if (!UseImm) CmpOpc = ARM::t2CMPrr; else CmpOpc = isNegativeImm ? ARM::t2CMNri : ARM::t2CMPri; } else { if (!UseImm) CmpOpc = ARM::CMPrr; else CmpOpc = isNegativeImm ? ARM::CMNri : ARM::CMPri; } break; } Register SrcReg1 = getRegForValue(Src1Value); if (SrcReg1 == 0) return false; unsigned SrcReg2 = 0; if (!UseImm) { SrcReg2 = getRegForValue(Src2Value); if (SrcReg2 == 0) return false; } // We have i1, i8, or i16, we need to either zero extend or sign extend. if (needsExt) { SrcReg1 = ARMEmitIntExt(SrcVT, SrcReg1, MVT::i32, isZExt); if (SrcReg1 == 0) return false; if (!UseImm) { SrcReg2 = ARMEmitIntExt(SrcVT, SrcReg2, MVT::i32, isZExt); if (SrcReg2 == 0) return false; } } const MCInstrDesc &II = TII.get(CmpOpc); SrcReg1 = constrainOperandRegClass(II, SrcReg1, 0); if (!UseImm) { SrcReg2 = constrainOperandRegClass(II, SrcReg2, 1); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addReg(SrcReg1).addReg(SrcReg2)); } else { MachineInstrBuilder MIB; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, II) .addReg(SrcReg1); // Only add immediate for icmp as the immediate for fcmp is an implicit 0.0. if (isICmp) MIB.addImm(Imm); AddOptionalDefs(MIB); } // For floating point we need to move the result to a comparison register // that we can then use for branches. if (Ty->isFloatTy() || Ty->isDoubleTy()) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::FMSTAT))); return true; } bool ARMFastISel::SelectCmp(const Instruction *I) { const CmpInst *CI = cast(I); // Get the compare predicate. ARMCC::CondCodes ARMPred = getComparePred(CI->getPredicate()); // We may not handle every CC for now. if (ARMPred == ARMCC::AL) return false; // Emit the compare. if (!ARMEmitCmp(CI->getOperand(0), CI->getOperand(1), CI->isUnsigned())) return false; // Now set a register based on the comparison. Explicitly set the predicates // here. unsigned MovCCOpc = isThumb2 ? ARM::t2MOVCCi : ARM::MOVCCi; const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass; Register DestReg = createResultReg(RC); Constant *Zero = ConstantInt::get(Type::getInt32Ty(*Context), 0); unsigned ZeroReg = fastMaterializeConstant(Zero); // ARMEmitCmp emits a FMSTAT when necessary, so it's always safe to use CPSR. BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(MovCCOpc), DestReg) .addReg(ZeroReg).addImm(1) .addImm(ARMPred).addReg(ARM::CPSR); updateValueMap(I, DestReg); return true; } bool ARMFastISel::SelectFPExt(const Instruction *I) { // Make sure we have VFP and that we're extending float to double. if (!Subtarget->hasVFP2Base() || !Subtarget->hasFP64()) return false; Value *V = I->getOperand(0); if (!I->getType()->isDoubleTy() || !V->getType()->isFloatTy()) return false; Register Op = getRegForValue(V); if (Op == 0) return false; Register Result = createResultReg(&ARM::DPRRegClass); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VCVTDS), Result) .addReg(Op)); updateValueMap(I, Result); return true; } bool ARMFastISel::SelectFPTrunc(const Instruction *I) { // Make sure we have VFP and that we're truncating double to float. if (!Subtarget->hasVFP2Base() || !Subtarget->hasFP64()) return false; Value *V = I->getOperand(0); if (!(I->getType()->isFloatTy() && V->getType()->isDoubleTy())) return false; Register Op = getRegForValue(V); if (Op == 0) return false; Register Result = createResultReg(&ARM::SPRRegClass); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VCVTSD), Result) .addReg(Op)); updateValueMap(I, Result); return true; } bool ARMFastISel::SelectIToFP(const Instruction *I, bool isSigned) { // Make sure we have VFP. if (!Subtarget->hasVFP2Base()) return false; MVT DstVT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, DstVT)) return false; Value *Src = I->getOperand(0); EVT SrcEVT = TLI.getValueType(DL, Src->getType(), true); if (!SrcEVT.isSimple()) return false; MVT SrcVT = SrcEVT.getSimpleVT(); if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8) return false; Register SrcReg = getRegForValue(Src); if (SrcReg == 0) return false; // Handle sign-extension. if (SrcVT == MVT::i16 || SrcVT == MVT::i8) { SrcReg = ARMEmitIntExt(SrcVT, SrcReg, MVT::i32, /*isZExt*/!isSigned); if (SrcReg == 0) return false; } // The conversion routine works on fp-reg to fp-reg and the operand above // was an integer, move it to the fp registers if possible. unsigned FP = ARMMoveToFPReg(MVT::f32, SrcReg); if (FP == 0) return false; unsigned Opc; if (Ty->isFloatTy()) Opc = isSigned ? ARM::VSITOS : ARM::VUITOS; else if (Ty->isDoubleTy() && Subtarget->hasFP64()) Opc = isSigned ? ARM::VSITOD : ARM::VUITOD; else return false; Register ResultReg = createResultReg(TLI.getRegClassFor(DstVT)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg).addReg(FP)); updateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectFPToI(const Instruction *I, bool isSigned) { // Make sure we have VFP. if (!Subtarget->hasVFP2Base()) return false; MVT DstVT; Type *RetTy = I->getType(); if (!isTypeLegal(RetTy, DstVT)) return false; Register Op = getRegForValue(I->getOperand(0)); if (Op == 0) return false; unsigned Opc; Type *OpTy = I->getOperand(0)->getType(); if (OpTy->isFloatTy()) Opc = isSigned ? ARM::VTOSIZS : ARM::VTOUIZS; else if (OpTy->isDoubleTy() && Subtarget->hasFP64()) Opc = isSigned ? ARM::VTOSIZD : ARM::VTOUIZD; else return false; // f64->s32/u32 or f32->s32/u32 both need an intermediate f32 reg. Register ResultReg = createResultReg(TLI.getRegClassFor(MVT::f32)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg).addReg(Op)); // This result needs to be in an integer register, but the conversion only // takes place in fp-regs. unsigned IntReg = ARMMoveToIntReg(DstVT, ResultReg); if (IntReg == 0) return false; updateValueMap(I, IntReg); return true; } bool ARMFastISel::SelectSelect(const Instruction *I) { MVT VT; if (!isTypeLegal(I->getType(), VT)) return false; // Things need to be register sized for register moves. if (VT != MVT::i32) return false; Register CondReg = getRegForValue(I->getOperand(0)); if (CondReg == 0) return false; Register Op1Reg = getRegForValue(I->getOperand(1)); if (Op1Reg == 0) return false; // Check to see if we can use an immediate in the conditional move. int Imm = 0; bool UseImm = false; bool isNegativeImm = false; if (const ConstantInt *ConstInt = dyn_cast(I->getOperand(2))) { assert(VT == MVT::i32 && "Expecting an i32."); Imm = (int)ConstInt->getValue().getZExtValue(); if (Imm < 0) { isNegativeImm = true; Imm = ~Imm; } UseImm = isThumb2 ? (ARM_AM::getT2SOImmVal(Imm) != -1) : (ARM_AM::getSOImmVal(Imm) != -1); } unsigned Op2Reg = 0; if (!UseImm) { Op2Reg = getRegForValue(I->getOperand(2)); if (Op2Reg == 0) return false; } unsigned TstOpc = isThumb2 ? ARM::t2TSTri : ARM::TSTri; CondReg = constrainOperandRegClass(TII.get(TstOpc), CondReg, 0); AddOptionalDefs( BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TstOpc)) .addReg(CondReg) .addImm(1)); unsigned MovCCOpc; const TargetRegisterClass *RC; if (!UseImm) { RC = isThumb2 ? &ARM::tGPRRegClass : &ARM::GPRRegClass; MovCCOpc = isThumb2 ? ARM::t2MOVCCr : ARM::MOVCCr; } else { RC = isThumb2 ? &ARM::rGPRRegClass : &ARM::GPRRegClass; if (!isNegativeImm) MovCCOpc = isThumb2 ? ARM::t2MOVCCi : ARM::MOVCCi; else MovCCOpc = isThumb2 ? ARM::t2MVNCCi : ARM::MVNCCi; } Register ResultReg = createResultReg(RC); if (!UseImm) { Op2Reg = constrainOperandRegClass(TII.get(MovCCOpc), Op2Reg, 1); Op1Reg = constrainOperandRegClass(TII.get(MovCCOpc), Op1Reg, 2); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(MovCCOpc), ResultReg) .addReg(Op2Reg) .addReg(Op1Reg) .addImm(ARMCC::NE) .addReg(ARM::CPSR); } else { Op1Reg = constrainOperandRegClass(TII.get(MovCCOpc), Op1Reg, 1); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(MovCCOpc), ResultReg) .addReg(Op1Reg) .addImm(Imm) .addImm(ARMCC::EQ) .addReg(ARM::CPSR); } updateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectDiv(const Instruction *I, bool isSigned) { MVT VT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, VT)) return false; // If we have integer div support we should have selected this automagically. // In case we have a real miss go ahead and return false and we'll pick // it up later. if (Subtarget->hasDivideInThumbMode()) return false; // Otherwise emit a libcall. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i8) LC = isSigned ? RTLIB::SDIV_I8 : RTLIB::UDIV_I8; else if (VT == MVT::i16) LC = isSigned ? RTLIB::SDIV_I16 : RTLIB::UDIV_I16; else if (VT == MVT::i32) LC = isSigned ? RTLIB::SDIV_I32 : RTLIB::UDIV_I32; else if (VT == MVT::i64) LC = isSigned ? RTLIB::SDIV_I64 : RTLIB::UDIV_I64; else if (VT == MVT::i128) LC = isSigned ? RTLIB::SDIV_I128 : RTLIB::UDIV_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!"); return ARMEmitLibcall(I, LC); } bool ARMFastISel::SelectRem(const Instruction *I, bool isSigned) { MVT VT; Type *Ty = I->getType(); if (!isTypeLegal(Ty, VT)) return false; // Many ABIs do not provide a libcall for standalone remainder, so we need to // use divrem (see the RTABI 4.3.1). Since FastISel can't handle non-double // multi-reg returns, we'll have to bail out. if (!TLI.hasStandaloneRem(VT)) { return false; } RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i8) LC = isSigned ? RTLIB::SREM_I8 : RTLIB::UREM_I8; else if (VT == MVT::i16) LC = isSigned ? RTLIB::SREM_I16 : RTLIB::UREM_I16; else if (VT == MVT::i32) LC = isSigned ? RTLIB::SREM_I32 : RTLIB::UREM_I32; else if (VT == MVT::i64) LC = isSigned ? RTLIB::SREM_I64 : RTLIB::UREM_I64; else if (VT == MVT::i128) LC = isSigned ? RTLIB::SREM_I128 : RTLIB::UREM_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SREM!"); return ARMEmitLibcall(I, LC); } bool ARMFastISel::SelectBinaryIntOp(const Instruction *I, unsigned ISDOpcode) { EVT DestVT = TLI.getValueType(DL, I->getType(), true); // We can get here in the case when we have a binary operation on a non-legal // type and the target independent selector doesn't know how to handle it. if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1) return false; unsigned Opc; switch (ISDOpcode) { default: return false; case ISD::ADD: Opc = isThumb2 ? ARM::t2ADDrr : ARM::ADDrr; break; case ISD::OR: Opc = isThumb2 ? ARM::t2ORRrr : ARM::ORRrr; break; case ISD::SUB: Opc = isThumb2 ? ARM::t2SUBrr : ARM::SUBrr; break; } Register SrcReg1 = getRegForValue(I->getOperand(0)); if (SrcReg1 == 0) return false; // TODO: Often the 2nd operand is an immediate, which can be encoded directly // in the instruction, rather then materializing the value in a register. Register SrcReg2 = getRegForValue(I->getOperand(1)); if (SrcReg2 == 0) return false; Register ResultReg = createResultReg(&ARM::GPRnopcRegClass); SrcReg1 = constrainOperandRegClass(TII.get(Opc), SrcReg1, 1); SrcReg2 = constrainOperandRegClass(TII.get(Opc), SrcReg2, 2); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(SrcReg1).addReg(SrcReg2)); updateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectBinaryFPOp(const Instruction *I, unsigned ISDOpcode) { EVT FPVT = TLI.getValueType(DL, I->getType(), true); if (!FPVT.isSimple()) return false; MVT VT = FPVT.getSimpleVT(); // FIXME: Support vector types where possible. if (VT.isVector()) return false; // We can get here in the case when we want to use NEON for our fp // operations, but can't figure out how to. Just use the vfp instructions // if we have them. // FIXME: It'd be nice to use NEON instructions. Type *Ty = I->getType(); if (Ty->isFloatTy() && !Subtarget->hasVFP2Base()) return false; if (Ty->isDoubleTy() && (!Subtarget->hasVFP2Base() || !Subtarget->hasFP64())) return false; unsigned Opc; bool is64bit = VT == MVT::f64 || VT == MVT::i64; switch (ISDOpcode) { default: return false; case ISD::FADD: Opc = is64bit ? ARM::VADDD : ARM::VADDS; break; case ISD::FSUB: Opc = is64bit ? ARM::VSUBD : ARM::VSUBS; break; case ISD::FMUL: Opc = is64bit ? ARM::VMULD : ARM::VMULS; break; } Register Op1 = getRegForValue(I->getOperand(0)); if (Op1 == 0) return false; Register Op2 = getRegForValue(I->getOperand(1)); if (Op2 == 0) return false; Register ResultReg = createResultReg(TLI.getRegClassFor(VT.SimpleTy)); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(Op1).addReg(Op2)); updateValueMap(I, ResultReg); return true; } // Call Handling Code // This is largely taken directly from CCAssignFnForNode // TODO: We may not support all of this. CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return, bool isVarArg) { switch (CC) { default: report_fatal_error("Unsupported calling convention"); case CallingConv::Fast: if (Subtarget->hasVFP2Base() && !isVarArg) { if (!Subtarget->isAAPCS_ABI()) return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); // For AAPCS ABI targets, just use VFP variant of the calling convention. return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); } [[fallthrough]]; case CallingConv::C: case CallingConv::CXX_FAST_TLS: // Use target triple & subtarget features to do actual dispatch. if (Subtarget->isAAPCS_ABI()) { if (Subtarget->hasFPRegs() && TM.Options.FloatABIType == FloatABI::Hard && !isVarArg) return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); else return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); } else { return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); } case CallingConv::ARM_AAPCS_VFP: case CallingConv::Swift: case CallingConv::SwiftTail: if (!isVarArg) return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); // Fall through to soft float variant, variadic functions don't // use hard floating point ABI. [[fallthrough]]; case CallingConv::ARM_AAPCS: return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); case CallingConv::ARM_APCS: return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); case CallingConv::GHC: if (Return) report_fatal_error("Can't return in GHC call convention"); else return CC_ARM_APCS_GHC; case CallingConv::CFGuard_Check: return (Return ? RetCC_ARM_AAPCS : CC_ARM_Win32_CFGuard_Check); } } bool ARMFastISel::ProcessCallArgs(SmallVectorImpl &Args, SmallVectorImpl &ArgRegs, SmallVectorImpl &ArgVTs, SmallVectorImpl &ArgFlags, SmallVectorImpl &RegArgs, CallingConv::ID CC, unsigned &NumBytes, bool isVarArg) { SmallVector ArgLocs; CCState CCInfo(CC, isVarArg, *FuncInfo.MF, ArgLocs, *Context); CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false, isVarArg)); // Check that we can handle all of the arguments. If we can't, then bail out // now before we add code to the MBB. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; MVT ArgVT = ArgVTs[VA.getValNo()]; // We don't handle NEON/vector parameters yet. if (ArgVT.isVector() || ArgVT.getSizeInBits() > 64) return false; // Now copy/store arg to correct locations. if (VA.isRegLoc() && !VA.needsCustom()) { continue; } else if (VA.needsCustom()) { // TODO: We need custom lowering for vector (v2f64) args. if (VA.getLocVT() != MVT::f64 || // TODO: Only handle register args for now. !VA.isRegLoc() || !ArgLocs[++i].isRegLoc()) return false; } else { switch (ArgVT.SimpleTy) { default: return false; case MVT::i1: case MVT::i8: case MVT::i16: case MVT::i32: break; case MVT::f32: if (!Subtarget->hasVFP2Base()) return false; break; case MVT::f64: if (!Subtarget->hasVFP2Base()) return false; break; } } } // At the point, we are able to handle the call's arguments in fast isel. // Get a count of how many bytes are to be pushed on the stack. NumBytes = CCInfo.getStackSize(); // Issue CALLSEQ_START unsigned AdjStackDown = TII.getCallFrameSetupOpcode(); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(AdjStackDown)) .addImm(NumBytes).addImm(0)); // Process the args. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; const Value *ArgVal = Args[VA.getValNo()]; Register Arg = ArgRegs[VA.getValNo()]; MVT ArgVT = ArgVTs[VA.getValNo()]; assert((!ArgVT.isVector() && ArgVT.getSizeInBits() <= 64) && "We don't handle NEON/vector parameters yet."); // Handle arg promotion, etc. switch (VA.getLocInfo()) { case CCValAssign::Full: break; case CCValAssign::SExt: { MVT DestVT = VA.getLocVT(); Arg = ARMEmitIntExt(ArgVT, Arg, DestVT, /*isZExt*/false); assert(Arg != 0 && "Failed to emit a sext"); ArgVT = DestVT; break; } case CCValAssign::AExt: // Intentional fall-through. Handle AExt and ZExt. case CCValAssign::ZExt: { MVT DestVT = VA.getLocVT(); Arg = ARMEmitIntExt(ArgVT, Arg, DestVT, /*isZExt*/true); assert(Arg != 0 && "Failed to emit a zext"); ArgVT = DestVT; break; } case CCValAssign::BCvt: { unsigned BC = fastEmit_r(ArgVT, VA.getLocVT(), ISD::BITCAST, Arg); assert(BC != 0 && "Failed to emit a bitcast!"); Arg = BC; ArgVT = VA.getLocVT(); break; } default: llvm_unreachable("Unknown arg promotion!"); } // Now copy/store arg to correct locations. if (VA.isRegLoc() && !VA.needsCustom()) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), VA.getLocReg()).addReg(Arg); RegArgs.push_back(VA.getLocReg()); } else if (VA.needsCustom()) { // TODO: We need custom lowering for vector (v2f64) args. assert(VA.getLocVT() == MVT::f64 && "Custom lowering for v2f64 args not available"); // FIXME: ArgLocs[++i] may extend beyond ArgLocs.size() CCValAssign &NextVA = ArgLocs[++i]; assert(VA.isRegLoc() && NextVA.isRegLoc() && "We only handle register args!"); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVRRD), VA.getLocReg()) .addReg(NextVA.getLocReg(), RegState::Define) .addReg(Arg)); RegArgs.push_back(VA.getLocReg()); RegArgs.push_back(NextVA.getLocReg()); } else { assert(VA.isMemLoc()); // Need to store on the stack. // Don't emit stores for undef values. if (isa(ArgVal)) continue; Address Addr; Addr.BaseType = Address::RegBase; Addr.Base.Reg = ARM::SP; Addr.Offset = VA.getLocMemOffset(); bool EmitRet = ARMEmitStore(ArgVT, Arg, Addr); (void)EmitRet; assert(EmitRet && "Could not emit a store for argument!"); } } return true; } bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, const Instruction *I, CallingConv::ID CC, unsigned &NumBytes, bool isVarArg) { // Issue CALLSEQ_END unsigned AdjStackUp = TII.getCallFrameDestroyOpcode(); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(AdjStackUp)) .addImm(NumBytes).addImm(-1ULL)); // Now the return value. if (RetVT != MVT::isVoid) { SmallVector RVLocs; CCState CCInfo(CC, isVarArg, *FuncInfo.MF, RVLocs, *Context); CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, isVarArg)); // Copy all of the result registers out of their specified physreg. if (RVLocs.size() == 2 && RetVT == MVT::f64) { // For this move we copy into two registers and then move into the // double fp reg we want. MVT DestVT = RVLocs[0].getValVT(); const TargetRegisterClass* DstRC = TLI.getRegClassFor(DestVT); Register ResultReg = createResultReg(DstRC); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::VMOVDRR), ResultReg) .addReg(RVLocs[0].getLocReg()) .addReg(RVLocs[1].getLocReg())); UsedRegs.push_back(RVLocs[0].getLocReg()); UsedRegs.push_back(RVLocs[1].getLocReg()); // Finally update the result. updateValueMap(I, ResultReg); } else { assert(RVLocs.size() == 1 &&"Can't handle non-double multi-reg retvals!"); MVT CopyVT = RVLocs[0].getValVT(); // Special handling for extended integers. if (RetVT == MVT::i1 || RetVT == MVT::i8 || RetVT == MVT::i16) CopyVT = MVT::i32; const TargetRegisterClass* DstRC = TLI.getRegClassFor(CopyVT); Register ResultReg = createResultReg(DstRC); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg).addReg(RVLocs[0].getLocReg()); UsedRegs.push_back(RVLocs[0].getLocReg()); // Finally update the result. updateValueMap(I, ResultReg); } } return true; } bool ARMFastISel::SelectRet(const Instruction *I) { const ReturnInst *Ret = cast(I); const Function &F = *I->getParent()->getParent(); const bool IsCmseNSEntry = F.hasFnAttribute("cmse_nonsecure_entry"); if (!FuncInfo.CanLowerReturn) return false; if (TLI.supportSwiftError() && F.getAttributes().hasAttrSomewhere(Attribute::SwiftError)) return false; if (TLI.supportSplitCSR(FuncInfo.MF)) return false; // Build a list of return value registers. SmallVector RetRegs; CallingConv::ID CC = F.getCallingConv(); if (Ret->getNumOperands() > 0) { SmallVector Outs; GetReturnInfo(CC, F.getReturnType(), F.getAttributes(), Outs, TLI, DL); // Analyze operands of the call, assigning locations to each operand. SmallVector ValLocs; CCState CCInfo(CC, F.isVarArg(), *FuncInfo.MF, ValLocs, I->getContext()); CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC, true /* is Ret */, F.isVarArg())); const Value *RV = Ret->getOperand(0); Register Reg = getRegForValue(RV); if (Reg == 0) return false; // Only handle a single return value for now. if (ValLocs.size() != 1) return false; CCValAssign &VA = ValLocs[0]; // Don't bother handling odd stuff for now. if (VA.getLocInfo() != CCValAssign::Full) return false; // Only handle register returns for now. if (!VA.isRegLoc()) return false; unsigned SrcReg = Reg + VA.getValNo(); EVT RVEVT = TLI.getValueType(DL, RV->getType()); if (!RVEVT.isSimple()) return false; MVT RVVT = RVEVT.getSimpleVT(); MVT DestVT = VA.getValVT(); // Special handling for extended integers. if (RVVT != DestVT) { if (RVVT != MVT::i1 && RVVT != MVT::i8 && RVVT != MVT::i16) return false; assert(DestVT == MVT::i32 && "ARM should always ext to i32"); // Perform extension if flagged as either zext or sext. Otherwise, do // nothing. if (Outs[0].Flags.isZExt() || Outs[0].Flags.isSExt()) { SrcReg = ARMEmitIntExt(RVVT, SrcReg, DestVT, Outs[0].Flags.isZExt()); if (SrcReg == 0) return false; } } // Make the copy. Register DstReg = VA.getLocReg(); const TargetRegisterClass* SrcRC = MRI.getRegClass(SrcReg); // Avoid a cross-class copy. This is very unlikely. if (!SrcRC->contains(DstReg)) return false; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), DstReg).addReg(SrcReg); // Add register to return instruction. RetRegs.push_back(VA.getLocReg()); } unsigned RetOpc; if (IsCmseNSEntry) if (isThumb2) RetOpc = ARM::tBXNS_RET; else llvm_unreachable("CMSE not valid for non-Thumb targets"); else RetOpc = Subtarget->getReturnOpcode(); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(RetOpc)); AddOptionalDefs(MIB); for (unsigned R : RetRegs) MIB.addReg(R, RegState::Implicit); return true; } unsigned ARMFastISel::ARMSelectCallOp(bool UseReg) { if (UseReg) return isThumb2 ? gettBLXrOpcode(*MF) : getBLXOpcode(*MF); else return isThumb2 ? ARM::tBL : ARM::BL; } unsigned ARMFastISel::getLibcallReg(const Twine &Name) { // Manually compute the global's type to avoid building it when unnecessary. Type *GVTy = PointerType::get(*Context, /*AS=*/0); EVT LCREVT = TLI.getValueType(DL, GVTy); if (!LCREVT.isSimple()) return 0; GlobalValue *GV = M.getNamedGlobal(Name.str()); if (!GV) GV = new GlobalVariable(M, Type::getInt32Ty(*Context), false, GlobalValue::ExternalLinkage, nullptr, Name); return ARMMaterializeGV(GV, LCREVT.getSimpleVT()); } // A quick function that will emit a call for a named libcall in F with the // vector of passed arguments for the Instruction in I. We can assume that we // can emit a call for any libcall we can produce. This is an abridged version // of the full call infrastructure since we won't need to worry about things // like computed function pointers or strange arguments at call sites. // TODO: Try to unify this and the normal call bits for ARM, then try to unify // with X86. bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) { CallingConv::ID CC = TLI.getLibcallCallingConv(Call); // Handle *simple* calls for now. Type *RetTy = I->getType(); MVT RetVT; if (RetTy->isVoidTy()) RetVT = MVT::isVoid; else if (!isTypeLegal(RetTy, RetVT)) return false; // Can't handle non-double multi-reg retvals. if (RetVT != MVT::isVoid && RetVT != MVT::i32) { SmallVector RVLocs; CCState CCInfo(CC, false, *FuncInfo.MF, RVLocs, *Context); CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, false)); if (RVLocs.size() >= 2 && RetVT != MVT::f64) return false; } // Set up the argument vectors. SmallVector Args; SmallVector ArgRegs; SmallVector ArgVTs; SmallVector ArgFlags; Args.reserve(I->getNumOperands()); ArgRegs.reserve(I->getNumOperands()); ArgVTs.reserve(I->getNumOperands()); ArgFlags.reserve(I->getNumOperands()); for (Value *Op : I->operands()) { Register Arg = getRegForValue(Op); if (Arg == 0) return false; Type *ArgTy = Op->getType(); MVT ArgVT; if (!isTypeLegal(ArgTy, ArgVT)) return false; ISD::ArgFlagsTy Flags; Flags.setOrigAlign(DL.getABITypeAlign(ArgTy)); Args.push_back(Op); ArgRegs.push_back(Arg); ArgVTs.push_back(ArgVT); ArgFlags.push_back(Flags); } // Handle the arguments now that we've gotten them. SmallVector RegArgs; unsigned NumBytes; if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes, false)) return false; Register CalleeReg; if (Subtarget->genLongCalls()) { CalleeReg = getLibcallReg(TLI.getLibcallName(Call)); if (CalleeReg == 0) return false; } // Issue the call. unsigned CallOpc = ARMSelectCallOp(Subtarget->genLongCalls()); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(CallOpc)); // BL / BLX don't take a predicate, but tBL / tBLX do. if (isThumb2) MIB.add(predOps(ARMCC::AL)); if (Subtarget->genLongCalls()) { CalleeReg = constrainOperandRegClass(TII.get(CallOpc), CalleeReg, isThumb2 ? 2 : 0); MIB.addReg(CalleeReg); } else MIB.addExternalSymbol(TLI.getLibcallName(Call)); // Add implicit physical register uses to the call. for (Register R : RegArgs) MIB.addReg(R, 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)); // Finish off the call including any return values. SmallVector UsedRegs; if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, false)) return false; // Set all unused physreg defs as dead. static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; } bool ARMFastISel::SelectCall(const Instruction *I, const char *IntrMemName = nullptr) { const CallInst *CI = cast(I); const Value *Callee = CI->getCalledOperand(); // Can't handle inline asm. if (isa(Callee)) return false; // Allow SelectionDAG isel to handle tail calls. if (CI->isTailCall()) return false; // Check the calling convention. CallingConv::ID CC = CI->getCallingConv(); // TODO: Avoid some calling conventions? FunctionType *FTy = CI->getFunctionType(); bool isVarArg = FTy->isVarArg(); // Handle *simple* calls for now. Type *RetTy = I->getType(); MVT RetVT; if (RetTy->isVoidTy()) RetVT = MVT::isVoid; else if (!isTypeLegal(RetTy, RetVT) && RetVT != MVT::i16 && RetVT != MVT::i8 && RetVT != MVT::i1) return false; // Can't handle non-double multi-reg retvals. if (RetVT != MVT::isVoid && RetVT != MVT::i1 && RetVT != MVT::i8 && RetVT != MVT::i16 && RetVT != MVT::i32) { SmallVector RVLocs; CCState CCInfo(CC, isVarArg, *FuncInfo.MF, RVLocs, *Context); CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true, isVarArg)); if (RVLocs.size() >= 2 && RetVT != MVT::f64) return false; } // Set up the argument vectors. SmallVector Args; SmallVector ArgRegs; SmallVector ArgVTs; SmallVector ArgFlags; unsigned arg_size = CI->arg_size(); Args.reserve(arg_size); ArgRegs.reserve(arg_size); ArgVTs.reserve(arg_size); ArgFlags.reserve(arg_size); for (auto ArgI = CI->arg_begin(), ArgE = CI->arg_end(); ArgI != ArgE; ++ArgI) { // If we're lowering a memory intrinsic instead of a regular call, skip the // last argument, which shouldn't be passed to the underlying function. if (IntrMemName && ArgE - ArgI <= 1) break; ISD::ArgFlagsTy Flags; unsigned ArgIdx = ArgI - CI->arg_begin(); if (CI->paramHasAttr(ArgIdx, Attribute::SExt)) Flags.setSExt(); if (CI->paramHasAttr(ArgIdx, Attribute::ZExt)) Flags.setZExt(); // FIXME: Only handle *easy* calls for now. if (CI->paramHasAttr(ArgIdx, Attribute::InReg) || CI->paramHasAttr(ArgIdx, Attribute::StructRet) || CI->paramHasAttr(ArgIdx, Attribute::SwiftSelf) || CI->paramHasAttr(ArgIdx, Attribute::SwiftError) || CI->paramHasAttr(ArgIdx, Attribute::Nest) || CI->paramHasAttr(ArgIdx, Attribute::ByVal)) return false; Type *ArgTy = (*ArgI)->getType(); MVT ArgVT; if (!isTypeLegal(ArgTy, ArgVT) && ArgVT != MVT::i16 && ArgVT != MVT::i8 && ArgVT != MVT::i1) return false; Register Arg = getRegForValue(*ArgI); if (!Arg.isValid()) return false; Flags.setOrigAlign(DL.getABITypeAlign(ArgTy)); Args.push_back(*ArgI); ArgRegs.push_back(Arg); ArgVTs.push_back(ArgVT); ArgFlags.push_back(Flags); } // Handle the arguments now that we've gotten them. SmallVector RegArgs; unsigned NumBytes; if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes, isVarArg)) return false; bool UseReg = false; const GlobalValue *GV = dyn_cast(Callee); if (!GV || Subtarget->genLongCalls()) UseReg = true; Register CalleeReg; if (UseReg) { if (IntrMemName) CalleeReg = getLibcallReg(IntrMemName); else CalleeReg = getRegForValue(Callee); if (CalleeReg == 0) return false; } // Issue the call. unsigned CallOpc = ARMSelectCallOp(UseReg); MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(CallOpc)); // ARM calls don't take a predicate, but tBL / tBLX do. if(isThumb2) MIB.add(predOps(ARMCC::AL)); if (UseReg) { CalleeReg = constrainOperandRegClass(TII.get(CallOpc), CalleeReg, isThumb2 ? 2 : 0); MIB.addReg(CalleeReg); } else if (!IntrMemName) MIB.addGlobalAddress(GV, 0, 0); else MIB.addExternalSymbol(IntrMemName, 0); // Add implicit physical register uses to the call. for (Register R : RegArgs) MIB.addReg(R, 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)); // Finish off the call including any return values. SmallVector UsedRegs; if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, isVarArg)) return false; // Set all unused physreg defs as dead. static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); return true; } bool ARMFastISel::ARMIsMemCpySmall(uint64_t Len) { return Len <= 16; } bool ARMFastISel::ARMTryEmitSmallMemCpy(Address Dest, Address Src, uint64_t Len, MaybeAlign Alignment) { // Make sure we don't bloat code by inlining very large memcpy's. if (!ARMIsMemCpySmall(Len)) return false; while (Len) { MVT VT; if (!Alignment || *Alignment >= 4) { if (Len >= 4) VT = MVT::i32; else if (Len >= 2) VT = MVT::i16; else { assert(Len == 1 && "Expected a length of 1!"); VT = MVT::i8; } } else { assert(Alignment && "Alignment is set in this branch"); // Bound based on alignment. if (Len >= 2 && *Alignment == 2) VT = MVT::i16; else { VT = MVT::i8; } } bool RV; Register ResultReg; RV = ARMEmitLoad(VT, ResultReg, Src); assert(RV && "Should be able to handle this load."); RV = ARMEmitStore(VT, ResultReg, Dest); assert(RV && "Should be able to handle this store."); (void)RV; unsigned Size = VT.getSizeInBits()/8; Len -= Size; Dest.Offset += Size; Src.Offset += Size; } return true; } bool ARMFastISel::SelectIntrinsicCall(const IntrinsicInst &I) { // FIXME: Handle more intrinsics. switch (I.getIntrinsicID()) { default: return false; case Intrinsic::frameaddress: { MachineFrameInfo &MFI = FuncInfo.MF->getFrameInfo(); MFI.setFrameAddressIsTaken(true); unsigned LdrOpc = isThumb2 ? ARM::t2LDRi12 : ARM::LDRi12; const TargetRegisterClass *RC = isThumb2 ? &ARM::tGPRRegClass : &ARM::GPRRegClass; const ARMBaseRegisterInfo *RegInfo = static_cast(Subtarget->getRegisterInfo()); Register FramePtr = RegInfo->getFrameRegister(*(FuncInfo.MF)); unsigned SrcReg = FramePtr; // Recursively load frame address // ldr r0 [fp] // ldr r0 [r0] // ldr r0 [r0] // ... unsigned DestReg; unsigned Depth = cast(I.getOperand(0))->getZExtValue(); while (Depth--) { DestReg = createResultReg(RC); AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(LdrOpc), DestReg) .addReg(SrcReg).addImm(0)); SrcReg = DestReg; } updateValueMap(&I, SrcReg); return true; } case Intrinsic::memcpy: case Intrinsic::memmove: { const MemTransferInst &MTI = cast(I); // Don't handle volatile. if (MTI.isVolatile()) return false; // Disable inlining for memmove before calls to ComputeAddress. Otherwise, // we would emit dead code because we don't currently handle memmoves. bool isMemCpy = (I.getIntrinsicID() == Intrinsic::memcpy); if (isa(MTI.getLength()) && isMemCpy) { // Small memcpy's are common enough that we want to do them without a call // if possible. uint64_t Len = cast(MTI.getLength())->getZExtValue(); if (ARMIsMemCpySmall(Len)) { Address Dest, Src; if (!ARMComputeAddress(MTI.getRawDest(), Dest) || !ARMComputeAddress(MTI.getRawSource(), Src)) return false; MaybeAlign Alignment; if (MTI.getDestAlign() || MTI.getSourceAlign()) Alignment = std::min(MTI.getDestAlign().valueOrOne(), MTI.getSourceAlign().valueOrOne()); if (ARMTryEmitSmallMemCpy(Dest, Src, Len, Alignment)) return true; } } if (!MTI.getLength()->getType()->isIntegerTy(32)) return false; if (MTI.getSourceAddressSpace() > 255 || MTI.getDestAddressSpace() > 255) return false; const char *IntrMemName = isa(I) ? "memcpy" : "memmove"; return SelectCall(&I, IntrMemName); } case Intrinsic::memset: { const MemSetInst &MSI = cast(I); // Don't handle volatile. if (MSI.isVolatile()) return false; if (!MSI.getLength()->getType()->isIntegerTy(32)) return false; if (MSI.getDestAddressSpace() > 255) return false; return SelectCall(&I, "memset"); } case Intrinsic::trap: { unsigned Opcode; if (Subtarget->isThumb()) Opcode = ARM::tTRAP; else Opcode = Subtarget->useNaClTrap() ? ARM::TRAPNaCl : ARM::TRAP; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opcode)); return true; } } } bool ARMFastISel::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; Register 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; } unsigned ARMFastISel::ARMEmitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT, bool isZExt) { if (DestVT != MVT::i32 && DestVT != MVT::i16 && DestVT != MVT::i8) return 0; if (SrcVT != MVT::i16 && SrcVT != MVT::i8 && SrcVT != MVT::i1) return 0; // Table of which combinations can be emitted as a single instruction, // and which will require two. static const uint8_t isSingleInstrTbl[3][2][2][2] = { // ARM Thumb // !hasV6Ops hasV6Ops !hasV6Ops hasV6Ops // ext: s z s z s z s z /* 1 */ { { { 0, 1 }, { 0, 1 } }, { { 0, 0 }, { 0, 1 } } }, /* 8 */ { { { 0, 1 }, { 1, 1 } }, { { 0, 0 }, { 1, 1 } } }, /* 16 */ { { { 0, 0 }, { 1, 1 } }, { { 0, 0 }, { 1, 1 } } } }; // Target registers for: // - For ARM can never be PC. // - For 16-bit Thumb are restricted to lower 8 registers. // - For 32-bit Thumb are restricted to non-SP and non-PC. static const TargetRegisterClass *RCTbl[2][2] = { // Instructions: Two Single /* ARM */ { &ARM::GPRnopcRegClass, &ARM::GPRnopcRegClass }, /* Thumb */ { &ARM::tGPRRegClass, &ARM::rGPRRegClass } }; // Table governing the instruction(s) to be emitted. static const struct InstructionTable { uint32_t Opc : 16; uint32_t hasS : 1; // Some instructions have an S bit, always set it to 0. uint32_t Shift : 7; // For shift operand addressing mode, used by MOVsi. uint32_t Imm : 8; // All instructions have either a shift or a mask. } IT[2][2][3][2] = { { // Two instructions (first is left shift, second is in this table). { // ARM Opc S Shift Imm /* 1 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 31 }, /* 1 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 31 } }, /* 8 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 24 }, /* 8 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 24 } }, /* 16 bit sext */ { { ARM::MOVsi , 1, ARM_AM::asr , 16 }, /* 16 bit zext */ { ARM::MOVsi , 1, ARM_AM::lsr , 16 } } }, { // Thumb Opc S Shift Imm /* 1 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 31 }, /* 1 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 31 } }, /* 8 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 24 }, /* 8 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 24 } }, /* 16 bit sext */ { { ARM::tASRri , 0, ARM_AM::no_shift, 16 }, /* 16 bit zext */ { ARM::tLSRri , 0, ARM_AM::no_shift, 16 } } } }, { // Single instruction. { // ARM Opc S Shift Imm /* 1 bit sext */ { { ARM::KILL , 0, ARM_AM::no_shift, 0 }, /* 1 bit zext */ { ARM::ANDri , 1, ARM_AM::no_shift, 1 } }, /* 8 bit sext */ { { ARM::SXTB , 0, ARM_AM::no_shift, 0 }, /* 8 bit zext */ { ARM::ANDri , 1, ARM_AM::no_shift, 255 } }, /* 16 bit sext */ { { ARM::SXTH , 0, ARM_AM::no_shift, 0 }, /* 16 bit zext */ { ARM::UXTH , 0, ARM_AM::no_shift, 0 } } }, { // Thumb Opc S Shift Imm /* 1 bit sext */ { { ARM::KILL , 0, ARM_AM::no_shift, 0 }, /* 1 bit zext */ { ARM::t2ANDri, 1, ARM_AM::no_shift, 1 } }, /* 8 bit sext */ { { ARM::t2SXTB , 0, ARM_AM::no_shift, 0 }, /* 8 bit zext */ { ARM::t2ANDri, 1, ARM_AM::no_shift, 255 } }, /* 16 bit sext */ { { ARM::t2SXTH , 0, ARM_AM::no_shift, 0 }, /* 16 bit zext */ { ARM::t2UXTH , 0, ARM_AM::no_shift, 0 } } } } }; unsigned SrcBits = SrcVT.getSizeInBits(); unsigned DestBits = DestVT.getSizeInBits(); (void) DestBits; assert((SrcBits < DestBits) && "can only extend to larger types"); assert((DestBits == 32 || DestBits == 16 || DestBits == 8) && "other sizes unimplemented"); assert((SrcBits == 16 || SrcBits == 8 || SrcBits == 1) && "other sizes unimplemented"); bool hasV6Ops = Subtarget->hasV6Ops(); unsigned Bitness = SrcBits / 8; // {1,8,16}=>{0,1,2} assert((Bitness < 3) && "sanity-check table bounds"); bool isSingleInstr = isSingleInstrTbl[Bitness][isThumb2][hasV6Ops][isZExt]; const TargetRegisterClass *RC = RCTbl[isThumb2][isSingleInstr]; const InstructionTable *ITP = &IT[isSingleInstr][isThumb2][Bitness][isZExt]; unsigned Opc = ITP->Opc; assert(ARM::KILL != Opc && "Invalid table entry"); unsigned hasS = ITP->hasS; ARM_AM::ShiftOpc Shift = (ARM_AM::ShiftOpc) ITP->Shift; assert(((Shift == ARM_AM::no_shift) == (Opc != ARM::MOVsi)) && "only MOVsi has shift operand addressing mode"); unsigned Imm = ITP->Imm; // 16-bit Thumb instructions always set CPSR (unless they're in an IT block). bool setsCPSR = &ARM::tGPRRegClass == RC; unsigned LSLOpc = isThumb2 ? ARM::tLSLri : ARM::MOVsi; unsigned ResultReg; // MOVsi encodes shift and immediate in shift operand addressing mode. // The following condition has the same value when emitting two // instruction sequences: both are shifts. bool ImmIsSO = (Shift != ARM_AM::no_shift); // Either one or two instructions are emitted. // They're always of the form: // dst = in OP imm // CPSR is set only by 16-bit Thumb instructions. // Predicate, if any, is AL. // S bit, if available, is always 0. // When two are emitted the first's result will feed as the second's input, // that value is then dead. unsigned NumInstrsEmitted = isSingleInstr ? 1 : 2; for (unsigned Instr = 0; Instr != NumInstrsEmitted; ++Instr) { ResultReg = createResultReg(RC); bool isLsl = (0 == Instr) && !isSingleInstr; unsigned Opcode = isLsl ? LSLOpc : Opc; ARM_AM::ShiftOpc ShiftAM = isLsl ? ARM_AM::lsl : Shift; unsigned ImmEnc = ImmIsSO ? ARM_AM::getSORegOpc(ShiftAM, Imm) : Imm; bool isKill = 1 == Instr; MachineInstrBuilder MIB = BuildMI( *FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opcode), ResultReg); if (setsCPSR) MIB.addReg(ARM::CPSR, RegState::Define); SrcReg = constrainOperandRegClass(TII.get(Opcode), SrcReg, 1 + setsCPSR); MIB.addReg(SrcReg, isKill * RegState::Kill) .addImm(ImmEnc) .add(predOps(ARMCC::AL)); if (hasS) MIB.add(condCodeOp()); // Second instruction consumes the first's result. SrcReg = ResultReg; } return ResultReg; } bool ARMFastISel::SelectIntExt(const Instruction *I) { // On ARM, in general, integer casts don't involve legal types; this code // handles promotable integers. Type *DestTy = I->getType(); Value *Src = I->getOperand(0); Type *SrcTy = Src->getType(); bool isZExt = isa(I); Register 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 = ARMEmitIntExt(SrcVT, SrcReg, DestVT, isZExt); if (ResultReg == 0) return false; updateValueMap(I, ResultReg); return true; } bool ARMFastISel::SelectShift(const Instruction *I, ARM_AM::ShiftOpc ShiftTy) { // We handle thumb2 mode by target independent selector // or SelectionDAG ISel. if (isThumb2) return false; // Only handle i32 now. EVT DestVT = TLI.getValueType(DL, I->getType(), true); if (DestVT != MVT::i32) return false; unsigned Opc = ARM::MOVsr; unsigned ShiftImm; Value *Src2Value = I->getOperand(1); if (const ConstantInt *CI = dyn_cast(Src2Value)) { ShiftImm = CI->getZExtValue(); // Fall back to selection DAG isel if the shift amount // is zero or greater than the width of the value type. if (ShiftImm == 0 || ShiftImm >=32) return false; Opc = ARM::MOVsi; } Value *Src1Value = I->getOperand(0); Register Reg1 = getRegForValue(Src1Value); if (Reg1 == 0) return false; unsigned Reg2 = 0; if (Opc == ARM::MOVsr) { Reg2 = getRegForValue(Src2Value); if (Reg2 == 0) return false; } Register ResultReg = createResultReg(&ARM::GPRnopcRegClass); if(ResultReg == 0) return false; MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), ResultReg) .addReg(Reg1); if (Opc == ARM::MOVsi) MIB.addImm(ARM_AM::getSORegOpc(ShiftTy, ShiftImm)); else if (Opc == ARM::MOVsr) { MIB.addReg(Reg2); MIB.addImm(ARM_AM::getSORegOpc(ShiftTy, 0)); } AddOptionalDefs(MIB); updateValueMap(I, ResultReg); return true; } // TODO: SoftFP support. bool ARMFastISel::fastSelectInstruction(const Instruction *I) { switch (I->getOpcode()) { case Instruction::Load: return SelectLoad(I); case Instruction::Store: return SelectStore(I); case Instruction::Br: return SelectBranch(I); case Instruction::IndirectBr: return SelectIndirectBr(I); case Instruction::ICmp: case Instruction::FCmp: return SelectCmp(I); case Instruction::FPExt: return SelectFPExt(I); case Instruction::FPTrunc: return SelectFPTrunc(I); case Instruction::SIToFP: return SelectIToFP(I, /*isSigned*/ true); case Instruction::UIToFP: return SelectIToFP(I, /*isSigned*/ false); case Instruction::FPToSI: return SelectFPToI(I, /*isSigned*/ true); case Instruction::FPToUI: return SelectFPToI(I, /*isSigned*/ false); case Instruction::Add: return SelectBinaryIntOp(I, ISD::ADD); case Instruction::Or: return SelectBinaryIntOp(I, ISD::OR); case Instruction::Sub: return SelectBinaryIntOp(I, ISD::SUB); case Instruction::FAdd: return SelectBinaryFPOp(I, ISD::FADD); case Instruction::FSub: return SelectBinaryFPOp(I, ISD::FSUB); case Instruction::FMul: return SelectBinaryFPOp(I, ISD::FMUL); case Instruction::SDiv: return SelectDiv(I, /*isSigned*/ true); case Instruction::UDiv: return SelectDiv(I, /*isSigned*/ false); case Instruction::SRem: return SelectRem(I, /*isSigned*/ true); case Instruction::URem: return SelectRem(I, /*isSigned*/ false); case Instruction::Call: if (const IntrinsicInst *II = dyn_cast(I)) return SelectIntrinsicCall(*II); return SelectCall(I); case Instruction::Select: return SelectSelect(I); case Instruction::Ret: return SelectRet(I); case Instruction::Trunc: return SelectTrunc(I); case Instruction::ZExt: case Instruction::SExt: return SelectIntExt(I); case Instruction::Shl: return SelectShift(I, ARM_AM::lsl); case Instruction::LShr: return SelectShift(I, ARM_AM::lsr); case Instruction::AShr: return SelectShift(I, ARM_AM::asr); default: break; } return false; } // This table describes sign- and zero-extend instructions which can be // folded into a preceding load. All of these extends have an immediate // (sometimes a mask and sometimes a shift) that's applied after // extension. static const struct FoldableLoadExtendsStruct { uint16_t Opc[2]; // ARM, Thumb. uint8_t ExpectedImm; uint8_t isZExt : 1; uint8_t ExpectedVT : 7; } FoldableLoadExtends[] = { { { ARM::SXTH, ARM::t2SXTH }, 0, 0, MVT::i16 }, { { ARM::UXTH, ARM::t2UXTH }, 0, 1, MVT::i16 }, { { ARM::ANDri, ARM::t2ANDri }, 255, 1, MVT::i8 }, { { ARM::SXTB, ARM::t2SXTB }, 0, 0, MVT::i8 }, { { ARM::UXTB, ARM::t2UXTB }, 0, 1, MVT::i8 } }; /// 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 /// successful. bool ARMFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo, const LoadInst *LI) { // Verify we have a legal type before going any further. MVT VT; if (!isLoadTypeLegal(LI->getType(), VT)) return false; // Combine load followed by zero- or sign-extend. // ldrb r1, [r0] ldrb r1, [r0] // uxtb r2, r1 => // mov r3, r2 mov r3, r1 if (MI->getNumOperands() < 3 || !MI->getOperand(2).isImm()) return false; const uint64_t Imm = MI->getOperand(2).getImm(); bool Found = false; bool isZExt; for (const FoldableLoadExtendsStruct &FLE : FoldableLoadExtends) { if (FLE.Opc[isThumb2] == MI->getOpcode() && (uint64_t)FLE.ExpectedImm == Imm && MVT((MVT::SimpleValueType)FLE.ExpectedVT) == VT) { Found = true; isZExt = FLE.isZExt; } } if (!Found) return false; // See if we can handle this address. Address Addr; if (!ARMComputeAddress(LI->getOperand(0), Addr)) return false; Register ResultReg = MI->getOperand(0).getReg(); if (!ARMEmitLoad(VT, ResultReg, Addr, LI->getAlign(), isZExt, false)) return false; MachineBasicBlock::iterator I(MI); removeDeadCode(I, std::next(I)); return true; } unsigned ARMFastISel::ARMLowerPICELF(const GlobalValue *GV, MVT VT) { bool UseGOT_PREL = !GV->isDSOLocal(); LLVMContext *Context = &MF->getFunction().getContext(); unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create( GV, ARMPCLabelIndex, ARMCP::CPValue, PCAdj, UseGOT_PREL ? ARMCP::GOT_PREL : ARMCP::no_modifier, /*AddCurrentAddress=*/UseGOT_PREL); Align ConstAlign = MF->getDataLayout().getPrefTypeAlign(PointerType::get(*Context, 0)); unsigned Idx = MF->getConstantPool()->getConstantPoolIndex(CPV, ConstAlign); MachineMemOperand *CPMMO = MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF), MachineMemOperand::MOLoad, 4, Align(4)); Register TempReg = MF->getRegInfo().createVirtualRegister(&ARM::rGPRRegClass); unsigned Opc = isThumb2 ? ARM::t2LDRpci : ARM::LDRcp; MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), TempReg) .addConstantPoolIndex(Idx) .addMemOperand(CPMMO); if (Opc == ARM::LDRcp) MIB.addImm(0); MIB.add(predOps(ARMCC::AL)); // Fix the address by adding pc. Register DestReg = createResultReg(TLI.getRegClassFor(VT)); Opc = Subtarget->isThumb() ? ARM::tPICADD : UseGOT_PREL ? ARM::PICLDR : ARM::PICADD; DestReg = constrainOperandRegClass(TII.get(Opc), DestReg, 0); MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(Opc), DestReg) .addReg(TempReg) .addImm(ARMPCLabelIndex); if (!Subtarget->isThumb()) MIB.add(predOps(ARMCC::AL)); if (UseGOT_PREL && Subtarget->isThumb()) { Register NewDestReg = createResultReg(TLI.getRegClassFor(VT)); MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(ARM::t2LDRi12), NewDestReg) .addReg(DestReg) .addImm(0); DestReg = NewDestReg; AddOptionalDefs(MIB); } return DestReg; } bool ARMFastISel::fastLowerArguments() { if (!FuncInfo.CanLowerReturn) return false; const Function *F = FuncInfo.Fn; if (F->isVarArg()) return false; CallingConv::ID CC = F->getCallingConv(); switch (CC) { default: return false; case CallingConv::Fast: case CallingConv::C: case CallingConv::ARM_AAPCS_VFP: case CallingConv::ARM_AAPCS: case CallingConv::ARM_APCS: case CallingConv::Swift: case CallingConv::SwiftTail: break; } // Only handle simple cases. i.e. Up to 4 i8/i16/i32 scalar arguments // which are passed in r0 - r3. for (const Argument &Arg : F->args()) { if (Arg.getArgNo() >= 4) return false; if (Arg.hasAttribute(Attribute::InReg) || Arg.hasAttribute(Attribute::StructRet) || Arg.hasAttribute(Attribute::SwiftSelf) || Arg.hasAttribute(Attribute::SwiftError) || Arg.hasAttribute(Attribute::ByVal)) return false; Type *ArgTy = Arg.getType(); if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy()) return false; EVT ArgVT = TLI.getValueType(DL, ArgTy); if (!ArgVT.isSimple()) return false; switch (ArgVT.getSimpleVT().SimpleTy) { case MVT::i8: case MVT::i16: case MVT::i32: break; default: return false; } } static const MCPhysReg GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; const TargetRegisterClass *RC = &ARM::rGPRRegClass; for (const Argument &Arg : F->args()) { unsigned ArgNo = Arg.getArgNo(); unsigned SrcReg = GPRArgRegs[ArgNo]; Register DstReg = FuncInfo.MF->addLiveIn(SrcReg, 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). Register ResultReg = createResultReg(RC); BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, MIMD, TII.get(TargetOpcode::COPY), ResultReg).addReg(DstReg, getKillRegState(true)); updateValueMap(&Arg, ResultReg); } return true; } namespace llvm { FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { if (funcInfo.MF->getSubtarget().useFastISel()) return new ARMFastISel(funcInfo, libInfo); return nullptr; } } // end namespace llvm