mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
99413f0d40
With neon enabled, we reach SelectBinaryFPOp and are able to get registers for a <2 x double> add. However, we shouldn't actually attempt arithmetic on it as ARMIselLowering says "v2f64 is legal so that QR subregs can be extracted as f64 elements, but neither Neon nor VFP support any arithmetic operations on it." This commit disables SelectBinaryFPOp for any vector types. There's already a FIXME to try handle neon. Doing so would require fixing this conditional which isn't safe for vectors 'VT == MVT::f64 || VT == MVT::i64' git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236609 91177308-0d34-0410-b5e6-96231b3b80d8
3088 lines
107 KiB
C++
3088 lines
107 KiB
C++
//===-- ARMFastISel.cpp - ARM FastISel implementation ---------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the 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 "ARMBaseRegisterInfo.h"
|
|
#include "ARMCallingConv.h"
|
|
#include "ARMConstantPoolValue.h"
|
|
#include "ARMISelLowering.h"
|
|
#include "ARMMachineFunctionInfo.h"
|
|
#include "ARMSubtarget.h"
|
|
#include "MCTargetDesc/ARMAddressingModes.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/CodeGen/Analysis.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/MachineMemOperand.h"
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/IR/CallSite.h"
|
|
#include "llvm/IR/CallingConv.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/GetElementPtrTypeIterator.h"
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Operator.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
#include "llvm/Target/TargetLowering.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
using namespace llvm;
|
|
|
|
extern cl::opt<bool> EnableARMLongCalls;
|
|
|
|
namespace {
|
|
|
|
// All possible address modes, plus some.
|
|
typedef struct Address {
|
|
enum {
|
|
RegBase,
|
|
FrameIndexBase
|
|
} BaseType;
|
|
|
|
union {
|
|
unsigned Reg;
|
|
int FI;
|
|
} Base;
|
|
|
|
int Offset;
|
|
|
|
// Innocuous defaults for our address.
|
|
Address()
|
|
: BaseType(RegBase), Offset(0) {
|
|
Base.Reg = 0;
|
|
}
|
|
} Address;
|
|
|
|
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(
|
|
&static_cast<const ARMSubtarget &>(funcInfo.MF->getSubtarget())),
|
|
M(const_cast<Module &>(*funcInfo.Fn->getParent())),
|
|
TM(funcInfo.MF->getTarget()), TII(*Subtarget->getInstrInfo()),
|
|
TLI(*Subtarget->getTargetLowering()) {
|
|
AFI = funcInfo.MF->getInfo<ARMFunctionInfo>();
|
|
isThumb2 = AFI->isThumbFunction();
|
|
Context = &funcInfo.Fn->getContext();
|
|
}
|
|
|
|
// Code from FastISel.cpp.
|
|
private:
|
|
unsigned fastEmitInst_r(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill);
|
|
unsigned fastEmitInst_rr(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill);
|
|
unsigned fastEmitInst_rrr(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill,
|
|
unsigned Op2, bool Op2IsKill);
|
|
unsigned fastEmitInst_ri(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
uint64_t Imm);
|
|
unsigned fastEmitInst_rri(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill,
|
|
uint64_t Imm);
|
|
unsigned fastEmitInst_i(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
uint64_t Imm);
|
|
|
|
// Backend specific FastISel code.
|
|
private:
|
|
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;
|
|
private:
|
|
#include "ARMGenFastISel.inc"
|
|
|
|
// Instruction selection routines.
|
|
private:
|
|
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.
|
|
private:
|
|
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, unsigned &ResultReg, Address &Addr,
|
|
unsigned Alignment = 0, bool isZExt = true,
|
|
bool allocReg = true);
|
|
bool ARMEmitStore(MVT VT, unsigned SrcReg, Address &Addr,
|
|
unsigned Alignment = 0);
|
|
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,
|
|
unsigned 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, unsigned Align, MVT VT);
|
|
|
|
const TargetLowering *getTargetLowering() { return &TLI; }
|
|
|
|
// Call handling routines.
|
|
private:
|
|
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC,
|
|
bool Return,
|
|
bool isVarArg);
|
|
bool ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
|
SmallVectorImpl<unsigned> &ArgRegs,
|
|
SmallVectorImpl<MVT> &ArgVTs,
|
|
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
|
SmallVectorImpl<unsigned> &RegArgs,
|
|
CallingConv::ID CC,
|
|
unsigned &NumBytes,
|
|
bool isVarArg);
|
|
unsigned getLibcallReg(const Twine &Name);
|
|
bool FinishCall(MVT RetVT, SmallVectorImpl<unsigned> &UsedRegs,
|
|
const Instruction *I, CallingConv::ID CC,
|
|
unsigned &NumBytes, bool isVarArg);
|
|
bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call);
|
|
|
|
// OptionalDef handling routines.
|
|
private:
|
|
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,
|
|
unsigned Flags, bool useAM3);
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
#include "ARMGenCallingConv.inc"
|
|
|
|
// 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 (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
|
const MachineOperand &MO = MI->getOperand(i);
|
|
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 (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i)
|
|
if (MCID.OpInfo[i].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))
|
|
AddDefaultPred(MIB);
|
|
|
|
// 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)) {
|
|
if (CPSR)
|
|
AddDefaultT1CC(MIB);
|
|
else
|
|
AddDefaultCC(MIB);
|
|
}
|
|
return MIB;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_r(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill) {
|
|
unsigned 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, DbgLoc, II,
|
|
ResultReg).addReg(Op0, Op0IsKill * RegState::Kill));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[0]));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_rr(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill) {
|
|
unsigned 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, DbgLoc, II, ResultReg)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[0]));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_rrr(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill,
|
|
unsigned Op2, bool Op2IsKill) {
|
|
unsigned 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);
|
|
Op2 = constrainOperandRegClass(II, Op1, 3);
|
|
|
|
if (II.getNumDefs() >= 1) {
|
|
AddOptionalDefs(
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II, ResultReg)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill)
|
|
.addReg(Op2, Op2IsKill * RegState::Kill));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill)
|
|
.addReg(Op2, Op2IsKill * RegState::Kill));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[0]));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_ri(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
uint64_t Imm) {
|
|
unsigned 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, DbgLoc, II, ResultReg)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addImm(Imm));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addImm(Imm));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[0]));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_rri(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
unsigned Op0, bool Op0IsKill,
|
|
unsigned Op1, bool Op1IsKill,
|
|
uint64_t Imm) {
|
|
unsigned 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, DbgLoc, II, ResultReg)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill)
|
|
.addImm(Imm));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addReg(Op0, Op0IsKill * RegState::Kill)
|
|
.addReg(Op1, Op1IsKill * RegState::Kill)
|
|
.addImm(Imm));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[0]));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::fastEmitInst_i(unsigned MachineInstOpcode,
|
|
const TargetRegisterClass *RC,
|
|
uint64_t Imm) {
|
|
unsigned ResultReg = createResultReg(RC);
|
|
const MCInstrDesc &II = TII.get(MachineInstOpcode);
|
|
|
|
if (II.getNumDefs() >= 1) {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II,
|
|
ResultReg).addImm(Imm));
|
|
} else {
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, II)
|
|
.addImm(Imm));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), ResultReg)
|
|
.addReg(II.ImplicitDefs[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;
|
|
|
|
unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(ARM::VMOVSR), MoveReg)
|
|
.addReg(SrcReg));
|
|
return MoveReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::ARMMoveToIntReg(MVT VT, unsigned SrcReg) {
|
|
if (VT == MVT::i64) return 0;
|
|
|
|
unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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;
|
|
}
|
|
unsigned DestReg = createResultReg(TLI.getRegClassFor(VT));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(Opc), DestReg).addImm(Imm));
|
|
return DestReg;
|
|
}
|
|
|
|
// Require VFP2 for loading fp constants.
|
|
if (!Subtarget->hasVFP2()) return false;
|
|
|
|
// MachineConstantPool wants an explicit alignment.
|
|
unsigned Align = DL.getPrefTypeAlignment(CFP->getType());
|
|
if (Align == 0) {
|
|
// TODO: Figure out if this is correct.
|
|
Align = DL.getTypeAllocSize(CFP->getType());
|
|
}
|
|
unsigned Idx = MCP.getConstantPoolIndex(cast<Constant>(CFP), Align);
|
|
unsigned DestReg = createResultReg(TLI.getRegClassFor(VT));
|
|
unsigned Opc = is64bit ? ARM::VLDRD : ARM::VLDRS;
|
|
|
|
// The extra reg is for addrmode5.
|
|
AddOptionalDefs(
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 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<ConstantInt>(C);
|
|
if (Subtarget->hasV6T2Ops() && isUInt<16>(CI->getZExtValue())) {
|
|
unsigned Opc = isThumb2 ? ARM::t2MOVi16 : ARM::MOVi16;
|
|
const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass :
|
|
&ARM::GPRRegClass;
|
|
unsigned ImmReg = createResultReg(RC);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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;
|
|
unsigned ImmReg = createResultReg(RC);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(Opc), ImmReg)
|
|
.addImm(Imm));
|
|
return ImmReg;
|
|
}
|
|
}
|
|
|
|
unsigned ResultReg = 0;
|
|
if (Subtarget->useMovt(*FuncInfo.MF))
|
|
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.
|
|
unsigned Align = DL.getPrefTypeAlignment(C->getType());
|
|
if (Align == 0) {
|
|
// TODO: Figure out if this is correct.
|
|
Align = DL.getTypeAllocSize(C->getType());
|
|
}
|
|
unsigned Idx = MCP.getConstantPoolIndex(C, Align);
|
|
ResultReg = createResultReg(TLI.getRegClassFor(VT));
|
|
if (isThumb2)
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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, DbgLoc,
|
|
TII.get(ARM::LDRcp), ResultReg)
|
|
.addConstantPoolIndex(Idx)
|
|
.addImm(0));
|
|
}
|
|
return ResultReg;
|
|
}
|
|
|
|
unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, MVT VT) {
|
|
// For now 32-bit only.
|
|
if (VT != MVT::i32) return 0;
|
|
|
|
Reloc::Model RelocM = TM.getRelocationModel();
|
|
bool IsIndirect = Subtarget->GVIsIndirectSymbol(GV, RelocM);
|
|
const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass
|
|
: &ARM::GPRRegClass;
|
|
unsigned DestReg = createResultReg(RC);
|
|
|
|
// FastISel TLS support on non-MachO is broken, punt to SelectionDAG.
|
|
const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV);
|
|
bool IsThreadLocal = GVar && GVar->isThreadLocal();
|
|
if (!Subtarget->isTargetMachO() && IsThreadLocal) return 0;
|
|
|
|
// Use movw+movt when possible, it avoids constant pool entries.
|
|
// Non-darwin targets only support static movt relocations in FastISel.
|
|
if (Subtarget->useMovt(*FuncInfo.MF) &&
|
|
(Subtarget->isTargetMachO() || RelocM == Reloc::Static)) {
|
|
unsigned Opc;
|
|
unsigned char TF = 0;
|
|
if (Subtarget->isTargetMachO())
|
|
TF = ARMII::MO_NONLAZY;
|
|
|
|
switch (RelocM) {
|
|
case Reloc::PIC_:
|
|
Opc = isThumb2 ? ARM::t2MOV_ga_pcrel : ARM::MOV_ga_pcrel;
|
|
break;
|
|
default:
|
|
Opc = isThumb2 ? ARM::t2MOVi32imm : ARM::MOVi32imm;
|
|
break;
|
|
}
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(Opc), DestReg).addGlobalAddress(GV, 0, TF));
|
|
} else {
|
|
// MachineConstantPool wants an explicit alignment.
|
|
unsigned Align = DL.getPrefTypeAlignment(GV->getType());
|
|
if (Align == 0) {
|
|
// TODO: Figure out if this is correct.
|
|
Align = DL.getTypeAllocSize(GV->getType());
|
|
}
|
|
|
|
if (Subtarget->isTargetELF() && RelocM == Reloc::PIC_)
|
|
return ARMLowerPICELF(GV, Align, VT);
|
|
|
|
// Grab index.
|
|
unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 :
|
|
(Subtarget->isThumb() ? 4 : 8);
|
|
unsigned Id = AFI->createPICLabelUId();
|
|
ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(GV, Id,
|
|
ARMCP::CPValue,
|
|
PCAdj);
|
|
unsigned Idx = MCP.getConstantPoolIndex(CPV, Align);
|
|
|
|
// Load value.
|
|
MachineInstrBuilder MIB;
|
|
if (isThumb2) {
|
|
unsigned Opc = (RelocM!=Reloc::PIC_) ? ARM::t2LDRpci : ARM::t2LDRpci_pic;
|
|
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
|
|
DestReg).addConstantPoolIndex(Idx);
|
|
if (RelocM == Reloc::PIC_)
|
|
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, DbgLoc,
|
|
TII.get(ARM::LDRcp), DestReg)
|
|
.addConstantPoolIndex(Idx)
|
|
.addImm(0);
|
|
AddOptionalDefs(MIB);
|
|
|
|
if (RelocM == Reloc::PIC_) {
|
|
unsigned Opc = IsIndirect ? ARM::PICLDR : ARM::PICADD;
|
|
unsigned NewDestReg = createResultReg(TLI.getRegClassFor(VT));
|
|
|
|
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt,
|
|
DbgLoc, TII.get(Opc), NewDestReg)
|
|
.addReg(DestReg)
|
|
.addImm(Id);
|
|
AddOptionalDefs(MIB);
|
|
return NewDestReg;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (IsIndirect) {
|
|
MachineInstrBuilder MIB;
|
|
unsigned NewDestReg = createResultReg(TLI.getRegClassFor(VT));
|
|
if (isThumb2)
|
|
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(ARM::t2LDRi12), NewDestReg)
|
|
.addReg(DestReg)
|
|
.addImm(0);
|
|
else
|
|
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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(C->getType(), true);
|
|
|
|
// Only handle simple types.
|
|
if (!CEVT.isSimple()) return 0;
|
|
MVT VT = CEVT.getSimpleVT();
|
|
|
|
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C))
|
|
return ARMMaterializeFP(CFP, VT);
|
|
else if (const GlobalValue *GV = dyn_cast<GlobalValue>(C))
|
|
return ARMMaterializeGV(GV, VT);
|
|
else if (isa<ConstantInt>(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<const AllocaInst*, int>::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);
|
|
unsigned ResultReg = createResultReg(RC);
|
|
ResultReg = constrainOperandRegClass(TII.get(Opc), ResultReg, 0);
|
|
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(Opc), ResultReg)
|
|
.addFrameIndex(SI->second)
|
|
.addImm(0));
|
|
return ResultReg;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool ARMFastISel::isTypeLegal(Type *Ty, MVT &VT) {
|
|
EVT evt = TLI.getValueType(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<Instruction>(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<const AllocaInst *>(Obj)) ||
|
|
FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
|
|
Opcode = I->getOpcode();
|
|
U = I;
|
|
}
|
|
} else if (const ConstantExpr *C = dyn_cast<ConstantExpr>(Obj)) {
|
|
Opcode = C->getOpcode();
|
|
U = C;
|
|
}
|
|
|
|
if (PointerType *Ty = dyn_cast<PointerType>(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(U->getOperand(0)->getType()) == TLI.getPointerTy())
|
|
return ARMComputeAddress(U->getOperand(0), Addr);
|
|
break;
|
|
case Instruction::PtrToInt:
|
|
// Look past no-op ptrtoints.
|
|
if (TLI.getValueType(U->getType()) == TLI.getPointerTy())
|
|
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 = dyn_cast<StructType>(*GTI)) {
|
|
const StructLayout *SL = DL.getStructLayout(STy);
|
|
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
|
|
TmpOffset += SL->getElementOffset(Idx);
|
|
} else {
|
|
uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
|
|
for (;;) {
|
|
if (const ConstantInt *CI = dyn_cast<ConstantInt>(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<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
|
|
TmpOffset += CI->getSExtValue() * S;
|
|
// Iterate on the other operand.
|
|
Op = cast<AddOperator>(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<AllocaInst>(Obj);
|
|
DenseMap<const AllocaInst*, int>::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;
|
|
unsigned ResultReg = createResultReg(RC);
|
|
unsigned Opc = isThumb2 ? ARM::t2ADDri : ARM::ADDri;
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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,
|
|
/*Op0IsKill*/false, Addr.Offset, MVT::i32);
|
|
Addr.Offset = 0;
|
|
}
|
|
}
|
|
|
|
void ARMFastISel::AddLoadStoreOperands(MVT VT, Address &Addr,
|
|
const MachineInstrBuilder &MIB,
|
|
unsigned 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(FI, Offset),
|
|
Flags,
|
|
MFI.getObjectSize(FI),
|
|
MFI.getObjectAlignment(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) {
|
|
signed 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) {
|
|
signed 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, unsigned &ResultReg, Address &Addr,
|
|
unsigned 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 < 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 < 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->hasVFP2()) return false;
|
|
// Unaligned loads need special handling. Floats require word-alignment.
|
|
if (Alignment && Alignment < 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:
|
|
if (!Subtarget->hasVFP2()) return false;
|
|
// FIXME: Unaligned loads need special handling. Doublewords require
|
|
// word-alignment.
|
|
if (Alignment && Alignment < 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, DbgLoc,
|
|
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) {
|
|
unsigned MoveReg = createResultReg(TLI.getRegClassFor(MVT::f32));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(ARM::VMOVSR), MoveReg)
|
|
.addReg(ResultReg));
|
|
ResultReg = MoveReg;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::SelectLoad(const Instruction *I) {
|
|
// Atomic loads need special handling.
|
|
if (cast<LoadInst>(I)->isAtomic())
|
|
return false;
|
|
|
|
// Verify we have a legal type before going any further.
|
|
MVT VT;
|
|
if (!isLoadTypeLegal(I->getType(), VT))
|
|
return false;
|
|
|
|
// See if we can handle this address.
|
|
Address Addr;
|
|
if (!ARMComputeAddress(I->getOperand(0), Addr)) return false;
|
|
|
|
unsigned ResultReg;
|
|
if (!ARMEmitLoad(VT, ResultReg, Addr, cast<LoadInst>(I)->getAlignment()))
|
|
return false;
|
|
updateValueMap(I, ResultReg);
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::ARMEmitStore(MVT VT, unsigned SrcReg, Address &Addr,
|
|
unsigned Alignment) {
|
|
unsigned StrOpc;
|
|
bool useAM3 = false;
|
|
switch (VT.SimpleTy) {
|
|
// This is mostly going to be Neon/vector support.
|
|
default: return false;
|
|
case MVT::i1: {
|
|
unsigned 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, DbgLoc,
|
|
TII.get(Opc), Res)
|
|
.addReg(SrcReg).addImm(1));
|
|
SrcReg = Res;
|
|
} // Fallthrough here.
|
|
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 < 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 < 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->hasVFP2()) return false;
|
|
// Unaligned stores need special handling. Floats require word-alignment.
|
|
if (Alignment && Alignment < 4) {
|
|
unsigned MoveReg = createResultReg(TLI.getRegClassFor(MVT::i32));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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:
|
|
if (!Subtarget->hasVFP2()) return false;
|
|
// FIXME: Unaligned stores need special handling. Doublewords require
|
|
// word-alignment.
|
|
if (Alignment && Alignment < 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, DbgLoc,
|
|
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<StoreInst>(I)->isAtomic())
|
|
return false;
|
|
|
|
// Verify we have a legal type before going any further.
|
|
MVT VT;
|
|
if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT))
|
|
return false;
|
|
|
|
// Get the value to be stored into a register.
|
|
SrcReg = getRegForValue(Op0);
|
|
if (SrcReg == 0) return false;
|
|
|
|
// See if we can handle this address.
|
|
Address Addr;
|
|
if (!ARMComputeAddress(I->getOperand(1), Addr))
|
|
return false;
|
|
|
|
if (!ARMEmitStore(VT, SrcReg, Addr, cast<StoreInst>(I)->getAlignment()))
|
|
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<BranchInst>(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<CmpInst>(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, DbgLoc, TII.get(BrOpc))
|
|
.addMBB(TBB).addImm(ARMPred).addReg(ARM::CPSR);
|
|
fastEmitBranch(FBB, DbgLoc);
|
|
FuncInfo.MBB->addSuccessor(TBB);
|
|
return true;
|
|
}
|
|
} else if (TruncInst *TI = dyn_cast<TruncInst>(BI->getCondition())) {
|
|
MVT SourceVT;
|
|
if (TI->hasOneUse() && TI->getParent() == I->getParent() &&
|
|
(isLoadTypeLegal(TI->getOperand(0)->getType(), SourceVT))) {
|
|
unsigned TstOpc = isThumb2 ? ARM::t2TSTri : ARM::TSTri;
|
|
unsigned OpReg = getRegForValue(TI->getOperand(0));
|
|
OpReg = constrainOperandRegClass(TII.get(TstOpc), OpReg, 0);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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, DbgLoc, TII.get(BrOpc))
|
|
.addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR);
|
|
|
|
fastEmitBranch(FBB, DbgLoc);
|
|
FuncInfo.MBB->addSuccessor(TBB);
|
|
return true;
|
|
}
|
|
} else if (const ConstantInt *CI =
|
|
dyn_cast<ConstantInt>(BI->getCondition())) {
|
|
uint64_t Imm = CI->getZExtValue();
|
|
MachineBasicBlock *Target = (Imm == 0) ? FBB : TBB;
|
|
fastEmitBranch(Target, DbgLoc);
|
|
return true;
|
|
}
|
|
|
|
unsigned 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, DbgLoc, 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, DbgLoc, TII.get(BrOpc))
|
|
.addMBB(TBB).addImm(CCMode).addReg(ARM::CPSR);
|
|
fastEmitBranch(FBB, DbgLoc);
|
|
FuncInfo.MBB->addSuccessor(TBB);
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::SelectIndirectBr(const Instruction *I) {
|
|
unsigned AddrReg = getRegForValue(I->getOperand(0));
|
|
if (AddrReg == 0) return false;
|
|
|
|
unsigned Opc = isThumb2 ? ARM::tBRIND : ARM::BX;
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(Opc)).addReg(AddrReg));
|
|
|
|
const IndirectBrInst *IB = cast<IndirectBrInst>(I);
|
|
for (unsigned i = 0, e = IB->getNumSuccessors(); i != e; ++i)
|
|
FuncInfo.MBB->addSuccessor(FuncInfo.MBBMap[IB->getSuccessor(i)]);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::ARMEmitCmp(const Value *Src1Value, const Value *Src2Value,
|
|
bool isZExt) {
|
|
Type *Ty = Src1Value->getType();
|
|
EVT SrcEVT = TLI.getValueType(Ty, true);
|
|
if (!SrcEVT.isSimple()) return false;
|
|
MVT SrcVT = SrcEVT.getSimpleVT();
|
|
|
|
bool isFloat = (Ty->isFloatTy() || Ty->isDoubleTy());
|
|
if (isFloat && !Subtarget->hasVFP2())
|
|
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<ConstantInt>(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<ConstantFP>(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::VCMPEZS : ARM::VCMPES;
|
|
break;
|
|
case MVT::f64:
|
|
isICmp = false;
|
|
CmpOpc = UseImm ? ARM::VCMPEZD : ARM::VCMPED;
|
|
break;
|
|
case MVT::i1:
|
|
case MVT::i8:
|
|
case MVT::i16:
|
|
needsExt = true;
|
|
// Intentional fall-through.
|
|
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;
|
|
}
|
|
|
|
unsigned 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, DbgLoc, II)
|
|
.addReg(SrcReg1).addReg(SrcReg2));
|
|
} else {
|
|
MachineInstrBuilder MIB;
|
|
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 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, DbgLoc,
|
|
TII.get(ARM::FMSTAT)));
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::SelectCmp(const Instruction *I) {
|
|
const CmpInst *CI = cast<CmpInst>(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;
|
|
unsigned 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, DbgLoc, 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->hasVFP2()) return false;
|
|
|
|
Value *V = I->getOperand(0);
|
|
if (!I->getType()->isDoubleTy() ||
|
|
!V->getType()->isFloatTy()) return false;
|
|
|
|
unsigned Op = getRegForValue(V);
|
|
if (Op == 0) return false;
|
|
|
|
unsigned Result = createResultReg(&ARM::DPRRegClass);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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->hasVFP2()) return false;
|
|
|
|
Value *V = I->getOperand(0);
|
|
if (!(I->getType()->isFloatTy() &&
|
|
V->getType()->isDoubleTy())) return false;
|
|
|
|
unsigned Op = getRegForValue(V);
|
|
if (Op == 0) return false;
|
|
|
|
unsigned Result = createResultReg(&ARM::SPRRegClass);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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->hasVFP2()) return false;
|
|
|
|
MVT DstVT;
|
|
Type *Ty = I->getType();
|
|
if (!isTypeLegal(Ty, DstVT))
|
|
return false;
|
|
|
|
Value *Src = I->getOperand(0);
|
|
EVT SrcEVT = TLI.getValueType(Src->getType(), true);
|
|
if (!SrcEVT.isSimple())
|
|
return false;
|
|
MVT SrcVT = SrcEVT.getSimpleVT();
|
|
if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8)
|
|
return false;
|
|
|
|
unsigned 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()) Opc = isSigned ? ARM::VSITOD : ARM::VUITOD;
|
|
else return false;
|
|
|
|
unsigned ResultReg = createResultReg(TLI.getRegClassFor(DstVT));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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->hasVFP2()) return false;
|
|
|
|
MVT DstVT;
|
|
Type *RetTy = I->getType();
|
|
if (!isTypeLegal(RetTy, DstVT))
|
|
return false;
|
|
|
|
unsigned 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()) Opc = isSigned ? ARM::VTOSIZD : ARM::VTOUIZD;
|
|
else return false;
|
|
|
|
// f64->s32/u32 or f32->s32/u32 both need an intermediate f32 reg.
|
|
unsigned ResultReg = createResultReg(TLI.getRegClassFor(MVT::f32));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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;
|
|
|
|
unsigned CondReg = getRegForValue(I->getOperand(0));
|
|
if (CondReg == 0) return false;
|
|
unsigned 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<ConstantInt>(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, DbgLoc, 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;
|
|
}
|
|
unsigned ResultReg = createResultReg(RC);
|
|
if (!UseImm) {
|
|
Op2Reg = constrainOperandRegClass(TII.get(MovCCOpc), Op2Reg, 1);
|
|
Op1Reg = constrainOperandRegClass(TII.get(MovCCOpc), Op1Reg, 2);
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, 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, DbgLoc, 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->hasDivide()) 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;
|
|
|
|
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(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;
|
|
}
|
|
|
|
unsigned 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.
|
|
unsigned SrcReg2 = getRegForValue(I->getOperand(1));
|
|
if (SrcReg2 == 0) return false;
|
|
|
|
unsigned ResultReg = createResultReg(&ARM::GPRnopcRegClass);
|
|
SrcReg1 = constrainOperandRegClass(TII.get(Opc), SrcReg1, 1);
|
|
SrcReg2 = constrainOperandRegClass(TII.get(Opc), SrcReg2, 2);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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(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();
|
|
bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy());
|
|
if (isFloat && !Subtarget->hasVFP2())
|
|
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;
|
|
}
|
|
unsigned Op1 = getRegForValue(I->getOperand(0));
|
|
if (Op1 == 0) return false;
|
|
|
|
unsigned Op2 = getRegForValue(I->getOperand(1));
|
|
if (Op2 == 0) return false;
|
|
|
|
unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT.SimpleTy));
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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:
|
|
llvm_unreachable("Unsupported calling convention");
|
|
case CallingConv::Fast:
|
|
if (Subtarget->hasVFP2() && !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:
|
|
// Use target triple & subtarget features to do actual dispatch.
|
|
if (Subtarget->isAAPCS_ABI()) {
|
|
if (Subtarget->hasVFP2() &&
|
|
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:
|
|
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.
|
|
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)
|
|
llvm_unreachable("Can't return in GHC call convention");
|
|
else
|
|
return CC_ARM_APCS_GHC;
|
|
}
|
|
}
|
|
|
|
bool ARMFastISel::ProcessCallArgs(SmallVectorImpl<Value*> &Args,
|
|
SmallVectorImpl<unsigned> &ArgRegs,
|
|
SmallVectorImpl<MVT> &ArgVTs,
|
|
SmallVectorImpl<ISD::ArgFlagsTy> &ArgFlags,
|
|
SmallVectorImpl<unsigned> &RegArgs,
|
|
CallingConv::ID CC,
|
|
unsigned &NumBytes,
|
|
bool isVarArg) {
|
|
SmallVector<CCValAssign, 16> 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->hasVFP2())
|
|
return false;
|
|
break;
|
|
case MVT::f64:
|
|
if (!Subtarget->hasVFP2())
|
|
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.getNextStackOffset();
|
|
|
|
// Issue CALLSEQ_START
|
|
unsigned AdjStackDown = TII.getCallFrameSetupOpcode();
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(AdjStackDown))
|
|
.addImm(NumBytes));
|
|
|
|
// Process the args.
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
CCValAssign &VA = ArgLocs[i];
|
|
const Value *ArgVal = Args[VA.getValNo()];
|
|
unsigned 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,
|
|
/*TODO: Kill=*/false);
|
|
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, DbgLoc,
|
|
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");
|
|
|
|
CCValAssign &NextVA = ArgLocs[++i];
|
|
|
|
assert(VA.isRegLoc() && NextVA.isRegLoc() &&
|
|
"We only handle register args!");
|
|
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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<UndefValue>(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<unsigned> &UsedRegs,
|
|
const Instruction *I, CallingConv::ID CC,
|
|
unsigned &NumBytes, bool isVarArg) {
|
|
// Issue CALLSEQ_END
|
|
unsigned AdjStackUp = TII.getCallFrameDestroyOpcode();
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(AdjStackUp))
|
|
.addImm(NumBytes).addImm(0));
|
|
|
|
// Now the return value.
|
|
if (RetVT != MVT::isVoid) {
|
|
SmallVector<CCValAssign, 16> 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);
|
|
unsigned ResultReg = createResultReg(DstRC);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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);
|
|
|
|
unsigned ResultReg = createResultReg(DstRC);
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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<ReturnInst>(I);
|
|
const Function &F = *I->getParent()->getParent();
|
|
|
|
if (!FuncInfo.CanLowerReturn)
|
|
return false;
|
|
|
|
// Build a list of return value registers.
|
|
SmallVector<unsigned, 4> RetRegs;
|
|
|
|
CallingConv::ID CC = F.getCallingConv();
|
|
if (Ret->getNumOperands() > 0) {
|
|
SmallVector<ISD::OutputArg, 4> Outs;
|
|
GetReturnInfo(F.getReturnType(), F.getAttributes(), Outs, TLI);
|
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
SmallVector<CCValAssign, 16> 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);
|
|
unsigned 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(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.
|
|
unsigned 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, DbgLoc,
|
|
TII.get(TargetOpcode::COPY), DstReg).addReg(SrcReg);
|
|
|
|
// Add register to return instruction.
|
|
RetRegs.push_back(VA.getLocReg());
|
|
}
|
|
|
|
unsigned RetOpc = isThumb2 ? ARM::tBX_RET : ARM::BX_RET;
|
|
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(RetOpc));
|
|
AddOptionalDefs(MIB);
|
|
for (unsigned i = 0, e = RetRegs.size(); i != e; ++i)
|
|
MIB.addReg(RetRegs[i], RegState::Implicit);
|
|
return true;
|
|
}
|
|
|
|
unsigned ARMFastISel::ARMSelectCallOp(bool UseReg) {
|
|
if (UseReg)
|
|
return isThumb2 ? ARM::tBLXr : ARM::BLX;
|
|
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 = Type::getInt32PtrTy(*Context, /*AS=*/0);
|
|
EVT LCREVT = TLI.getValueType(GVTy);
|
|
if (!LCREVT.isSimple()) return 0;
|
|
|
|
GlobalValue *GV = new GlobalVariable(M, Type::getInt32Ty(*Context), false,
|
|
GlobalValue::ExternalLinkage, nullptr,
|
|
Name);
|
|
assert(GV->getType() == GVTy && "We miscomputed the type for the global!");
|
|
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<CCValAssign, 16> 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<Value*, 8> Args;
|
|
SmallVector<unsigned, 8> ArgRegs;
|
|
SmallVector<MVT, 8> ArgVTs;
|
|
SmallVector<ISD::ArgFlagsTy, 8> ArgFlags;
|
|
Args.reserve(I->getNumOperands());
|
|
ArgRegs.reserve(I->getNumOperands());
|
|
ArgVTs.reserve(I->getNumOperands());
|
|
ArgFlags.reserve(I->getNumOperands());
|
|
for (unsigned i = 0; i < I->getNumOperands(); ++i) {
|
|
Value *Op = I->getOperand(i);
|
|
unsigned Arg = getRegForValue(Op);
|
|
if (Arg == 0) return false;
|
|
|
|
Type *ArgTy = Op->getType();
|
|
MVT ArgVT;
|
|
if (!isTypeLegal(ArgTy, ArgVT)) return false;
|
|
|
|
ISD::ArgFlagsTy Flags;
|
|
unsigned OriginalAlignment = DL.getABITypeAlignment(ArgTy);
|
|
Flags.setOrigAlign(OriginalAlignment);
|
|
|
|
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<unsigned, 4> RegArgs;
|
|
unsigned NumBytes;
|
|
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags,
|
|
RegArgs, CC, NumBytes, false))
|
|
return false;
|
|
|
|
unsigned CalleeReg = 0;
|
|
if (EnableARMLongCalls) {
|
|
CalleeReg = getLibcallReg(TLI.getLibcallName(Call));
|
|
if (CalleeReg == 0) return false;
|
|
}
|
|
|
|
// Issue the call.
|
|
unsigned CallOpc = ARMSelectCallOp(EnableARMLongCalls);
|
|
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt,
|
|
DbgLoc, TII.get(CallOpc));
|
|
// BL / BLX don't take a predicate, but tBL / tBLX do.
|
|
if (isThumb2)
|
|
AddDefaultPred(MIB);
|
|
if (EnableARMLongCalls)
|
|
MIB.addReg(CalleeReg);
|
|
else
|
|
MIB.addExternalSymbol(TLI.getLibcallName(Call));
|
|
|
|
// Add implicit physical register uses to the call.
|
|
for (unsigned i = 0, e = RegArgs.size(); i != e; ++i)
|
|
MIB.addReg(RegArgs[i], 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<unsigned, 4> UsedRegs;
|
|
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, false)) return false;
|
|
|
|
// Set all unused physreg defs as dead.
|
|
static_cast<MachineInstr *>(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ARMFastISel::SelectCall(const Instruction *I,
|
|
const char *IntrMemName = nullptr) {
|
|
const CallInst *CI = cast<CallInst>(I);
|
|
const Value *Callee = CI->getCalledValue();
|
|
|
|
// Can't handle inline asm.
|
|
if (isa<InlineAsm>(Callee)) return false;
|
|
|
|
// Allow SelectionDAG isel to handle tail calls.
|
|
if (CI->isTailCall()) return false;
|
|
|
|
// Check the calling convention.
|
|
ImmutableCallSite CS(CI);
|
|
CallingConv::ID CC = CS.getCallingConv();
|
|
|
|
// TODO: Avoid some calling conventions?
|
|
|
|
PointerType *PT = cast<PointerType>(CS.getCalledValue()->getType());
|
|
FunctionType *FTy = cast<FunctionType>(PT->getElementType());
|
|
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<CCValAssign, 16> 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<Value*, 8> Args;
|
|
SmallVector<unsigned, 8> ArgRegs;
|
|
SmallVector<MVT, 8> ArgVTs;
|
|
SmallVector<ISD::ArgFlagsTy, 8> ArgFlags;
|
|
unsigned arg_size = CS.arg_size();
|
|
Args.reserve(arg_size);
|
|
ArgRegs.reserve(arg_size);
|
|
ArgVTs.reserve(arg_size);
|
|
ArgFlags.reserve(arg_size);
|
|
for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end();
|
|
i != e; ++i) {
|
|
// If we're lowering a memory intrinsic instead of a regular call, skip the
|
|
// last two arguments, which shouldn't be passed to the underlying function.
|
|
if (IntrMemName && e-i <= 2)
|
|
break;
|
|
|
|
ISD::ArgFlagsTy Flags;
|
|
unsigned AttrInd = i - CS.arg_begin() + 1;
|
|
if (CS.paramHasAttr(AttrInd, Attribute::SExt))
|
|
Flags.setSExt();
|
|
if (CS.paramHasAttr(AttrInd, Attribute::ZExt))
|
|
Flags.setZExt();
|
|
|
|
// FIXME: Only handle *easy* calls for now.
|
|
if (CS.paramHasAttr(AttrInd, Attribute::InReg) ||
|
|
CS.paramHasAttr(AttrInd, Attribute::StructRet) ||
|
|
CS.paramHasAttr(AttrInd, Attribute::Nest) ||
|
|
CS.paramHasAttr(AttrInd, Attribute::ByVal))
|
|
return false;
|
|
|
|
Type *ArgTy = (*i)->getType();
|
|
MVT ArgVT;
|
|
if (!isTypeLegal(ArgTy, ArgVT) && ArgVT != MVT::i16 && ArgVT != MVT::i8 &&
|
|
ArgVT != MVT::i1)
|
|
return false;
|
|
|
|
unsigned Arg = getRegForValue(*i);
|
|
if (Arg == 0)
|
|
return false;
|
|
|
|
unsigned OriginalAlignment = DL.getABITypeAlignment(ArgTy);
|
|
Flags.setOrigAlign(OriginalAlignment);
|
|
|
|
Args.push_back(*i);
|
|
ArgRegs.push_back(Arg);
|
|
ArgVTs.push_back(ArgVT);
|
|
ArgFlags.push_back(Flags);
|
|
}
|
|
|
|
// Handle the arguments now that we've gotten them.
|
|
SmallVector<unsigned, 4> RegArgs;
|
|
unsigned NumBytes;
|
|
if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags,
|
|
RegArgs, CC, NumBytes, isVarArg))
|
|
return false;
|
|
|
|
bool UseReg = false;
|
|
const GlobalValue *GV = dyn_cast<GlobalValue>(Callee);
|
|
if (!GV || EnableARMLongCalls) UseReg = true;
|
|
|
|
unsigned CalleeReg = 0;
|
|
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,
|
|
DbgLoc, TII.get(CallOpc));
|
|
|
|
unsigned char OpFlags = 0;
|
|
|
|
// Add MO_PLT for global address or external symbol in the PIC relocation
|
|
// model.
|
|
if (Subtarget->isTargetELF() && TM.getRelocationModel() == Reloc::PIC_)
|
|
OpFlags = ARMII::MO_PLT;
|
|
|
|
// ARM calls don't take a predicate, but tBL / tBLX do.
|
|
if(isThumb2)
|
|
AddDefaultPred(MIB);
|
|
if (UseReg)
|
|
MIB.addReg(CalleeReg);
|
|
else if (!IntrMemName)
|
|
MIB.addGlobalAddress(GV, 0, OpFlags);
|
|
else
|
|
MIB.addExternalSymbol(IntrMemName, OpFlags);
|
|
|
|
// Add implicit physical register uses to the call.
|
|
for (unsigned i = 0, e = RegArgs.size(); i != e; ++i)
|
|
MIB.addReg(RegArgs[i], 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<unsigned, 4> UsedRegs;
|
|
if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes, isVarArg))
|
|
return false;
|
|
|
|
// Set all unused physreg defs as dead.
|
|
static_cast<MachineInstr *>(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, unsigned 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 {
|
|
// Bound based on alignment.
|
|
if (Len >= 2 && Alignment == 2)
|
|
VT = MVT::i16;
|
|
else {
|
|
VT = MVT::i8;
|
|
}
|
|
}
|
|
|
|
bool RV;
|
|
unsigned ResultReg;
|
|
RV = ARMEmitLoad(VT, ResultReg, Src);
|
|
assert (RV == true && "Should be able to handle this load.");
|
|
RV = ARMEmitStore(VT, ResultReg, Dest);
|
|
assert (RV == true && "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<const ARMBaseRegisterInfo *>(Subtarget->getRegisterInfo());
|
|
unsigned 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<ConstantInt>(I.getOperand(0))->getZExtValue();
|
|
while (Depth--) {
|
|
DestReg = createResultReg(RC);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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<MemTransferInst>(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<ConstantInt>(MTI.getLength()) && isMemCpy) {
|
|
// Small memcpy's are common enough that we want to do them without a call
|
|
// if possible.
|
|
uint64_t Len = cast<ConstantInt>(MTI.getLength())->getZExtValue();
|
|
if (ARMIsMemCpySmall(Len)) {
|
|
Address Dest, Src;
|
|
if (!ARMComputeAddress(MTI.getRawDest(), Dest) ||
|
|
!ARMComputeAddress(MTI.getRawSource(), Src))
|
|
return false;
|
|
unsigned Alignment = MTI.getAlignment();
|
|
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<MemCpyInst>(I) ? "memcpy" : "memmove";
|
|
return SelectCall(&I, IntrMemName);
|
|
}
|
|
case Intrinsic::memset: {
|
|
const MemSetInst &MSI = cast<MemSetInst>(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: {
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(
|
|
Subtarget->useNaClTrap() ? ARM::TRAPNaCl : ARM::TRAP));
|
|
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(Op->getType(), true);
|
|
DestVT = TLI.getValueType(I->getType(), true);
|
|
|
|
if (SrcVT != MVT::i32 && SrcVT != MVT::i16 && SrcVT != MVT::i8)
|
|
return false;
|
|
if (DestVT != MVT::i16 && DestVT != MVT::i8 && DestVT != MVT::i1)
|
|
return false;
|
|
|
|
unsigned SrcReg = getRegForValue(Op);
|
|
if (!SrcReg) return false;
|
|
|
|
// Because the high bits are undefined, a truncate doesn't generate
|
|
// any code.
|
|
updateValueMap(I, SrcReg);
|
|
return true;
|
|
}
|
|
|
|
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, DbgLoc, TII.get(Opcode), ResultReg);
|
|
if (setsCPSR)
|
|
MIB.addReg(ARM::CPSR, RegState::Define);
|
|
SrcReg = constrainOperandRegClass(TII.get(Opcode), SrcReg, 1 + setsCPSR);
|
|
AddDefaultPred(MIB.addReg(SrcReg, isKill * RegState::Kill).addImm(ImmEnc));
|
|
if (hasS)
|
|
AddDefaultCC(MIB);
|
|
// 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<ZExtInst>(I);
|
|
unsigned SrcReg = getRegForValue(Src);
|
|
if (!SrcReg) return false;
|
|
|
|
EVT SrcEVT, DestEVT;
|
|
SrcEVT = TLI.getValueType(SrcTy, true);
|
|
DestEVT = TLI.getValueType(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(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<ConstantInt>(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);
|
|
unsigned Reg1 = getRegForValue(Src1Value);
|
|
if (Reg1 == 0) return false;
|
|
|
|
unsigned Reg2 = 0;
|
|
if (Opc == ARM::MOVsr) {
|
|
Reg2 = getRegForValue(Src2Value);
|
|
if (Reg2 == 0) return false;
|
|
}
|
|
|
|
unsigned ResultReg = createResultReg(&ARM::GPRnopcRegClass);
|
|
if(ResultReg == 0) return false;
|
|
|
|
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
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<IntrinsicInst>(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;
|
|
}
|
|
|
|
namespace {
|
|
// 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.
|
|
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 }
|
|
};
|
|
}
|
|
|
|
/// \brief 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 (unsigned i = 0, e = array_lengthof(FoldableLoadExtends);
|
|
i != e; ++i) {
|
|
if (FoldableLoadExtends[i].Opc[isThumb2] == MI->getOpcode() &&
|
|
(uint64_t)FoldableLoadExtends[i].ExpectedImm == Imm &&
|
|
MVT((MVT::SimpleValueType)FoldableLoadExtends[i].ExpectedVT) == VT) {
|
|
Found = true;
|
|
isZExt = FoldableLoadExtends[i].isZExt;
|
|
}
|
|
}
|
|
if (!Found) return false;
|
|
|
|
// See if we can handle this address.
|
|
Address Addr;
|
|
if (!ARMComputeAddress(LI->getOperand(0), Addr)) return false;
|
|
|
|
unsigned ResultReg = MI->getOperand(0).getReg();
|
|
if (!ARMEmitLoad(VT, ResultReg, Addr, LI->getAlignment(), isZExt, false))
|
|
return false;
|
|
MI->eraseFromParent();
|
|
return true;
|
|
}
|
|
|
|
unsigned ARMFastISel::ARMLowerPICELF(const GlobalValue *GV,
|
|
unsigned Align, MVT VT) {
|
|
bool UseGOTOFF = GV->hasLocalLinkage() || GV->hasHiddenVisibility();
|
|
ARMConstantPoolConstant *CPV =
|
|
ARMConstantPoolConstant::Create(GV, UseGOTOFF ? ARMCP::GOTOFF : ARMCP::GOT);
|
|
unsigned Idx = MCP.getConstantPoolIndex(CPV, Align);
|
|
|
|
unsigned Opc;
|
|
unsigned DestReg1 = createResultReg(TLI.getRegClassFor(VT));
|
|
// Load value.
|
|
if (isThumb2) {
|
|
DestReg1 = constrainOperandRegClass(TII.get(ARM::t2LDRpci), DestReg1, 0);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(ARM::t2LDRpci), DestReg1)
|
|
.addConstantPoolIndex(Idx));
|
|
Opc = UseGOTOFF ? ARM::t2ADDrr : ARM::t2LDRs;
|
|
} else {
|
|
// The extra immediate is for addrmode2.
|
|
DestReg1 = constrainOperandRegClass(TII.get(ARM::LDRcp), DestReg1, 0);
|
|
AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt,
|
|
DbgLoc, TII.get(ARM::LDRcp), DestReg1)
|
|
.addConstantPoolIndex(Idx).addImm(0));
|
|
Opc = UseGOTOFF ? ARM::ADDrr : ARM::LDRrs;
|
|
}
|
|
|
|
unsigned GlobalBaseReg = AFI->getGlobalBaseReg();
|
|
if (GlobalBaseReg == 0) {
|
|
GlobalBaseReg = MRI.createVirtualRegister(TLI.getRegClassFor(VT));
|
|
AFI->setGlobalBaseReg(GlobalBaseReg);
|
|
}
|
|
|
|
unsigned DestReg2 = createResultReg(TLI.getRegClassFor(VT));
|
|
DestReg2 = constrainOperandRegClass(TII.get(Opc), DestReg2, 0);
|
|
DestReg1 = constrainOperandRegClass(TII.get(Opc), DestReg1, 1);
|
|
GlobalBaseReg = constrainOperandRegClass(TII.get(Opc), GlobalBaseReg, 2);
|
|
MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt,
|
|
DbgLoc, TII.get(Opc), DestReg2)
|
|
.addReg(DestReg1)
|
|
.addReg(GlobalBaseReg);
|
|
if (!UseGOTOFF)
|
|
MIB.addImm(0);
|
|
AddOptionalDefs(MIB);
|
|
|
|
return DestReg2;
|
|
}
|
|
|
|
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:
|
|
break;
|
|
}
|
|
|
|
// Only handle simple cases. i.e. Up to 4 i8/i16/i32 scalar arguments
|
|
// which are passed in r0 - r3.
|
|
unsigned Idx = 1;
|
|
for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
|
|
I != E; ++I, ++Idx) {
|
|
if (Idx > 4)
|
|
return false;
|
|
|
|
if (F->getAttributes().hasAttribute(Idx, Attribute::InReg) ||
|
|
F->getAttributes().hasAttribute(Idx, Attribute::StructRet) ||
|
|
F->getAttributes().hasAttribute(Idx, Attribute::ByVal))
|
|
return false;
|
|
|
|
Type *ArgTy = I->getType();
|
|
if (ArgTy->isStructTy() || ArgTy->isArrayTy() || ArgTy->isVectorTy())
|
|
return false;
|
|
|
|
EVT ArgVT = TLI.getValueType(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 uint16_t GPRArgRegs[] = {
|
|
ARM::R0, ARM::R1, ARM::R2, ARM::R3
|
|
};
|
|
|
|
const TargetRegisterClass *RC = &ARM::rGPRRegClass;
|
|
Idx = 0;
|
|
for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end();
|
|
I != E; ++I, ++Idx) {
|
|
unsigned SrcReg = GPRArgRegs[Idx];
|
|
unsigned 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).
|
|
unsigned ResultReg = createResultReg(RC);
|
|
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
|
TII.get(TargetOpcode::COPY),
|
|
ResultReg).addReg(DstReg, getKillRegState(true));
|
|
updateValueMap(I, ResultReg);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
namespace llvm {
|
|
FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo,
|
|
const TargetLibraryInfo *libInfo) {
|
|
const TargetMachine &TM = funcInfo.MF->getTarget();
|
|
const ARMSubtarget &STI =
|
|
static_cast<const ARMSubtarget &>(funcInfo.MF->getSubtarget());
|
|
// Thumb2 support on iOS; ARM support on iOS, Linux and NaCl.
|
|
bool UseFastISel = false;
|
|
UseFastISel |= STI.isTargetMachO() && !STI.isThumb1Only();
|
|
UseFastISel |= STI.isTargetLinux() && !STI.isThumb();
|
|
UseFastISel |= STI.isTargetNaCl() && !STI.isThumb();
|
|
|
|
if (UseFastISel) {
|
|
// iOS always has a FP for backtracking, force other targets
|
|
// to keep their FP when doing FastISel. The emitted code is
|
|
// currently superior, and in cases like test-suite's lencod
|
|
// FastISel isn't quite correct when FP is eliminated.
|
|
TM.Options.NoFramePointerElim = true;
|
|
return new ARMFastISel(funcInfo, libInfo);
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|