summaryrefslogtreecommitdiff
path: root/lib/Target/ARM/ARMInstructionSelector.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/Target/ARM/ARMInstructionSelector.cpp
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
downloadsrc-test2-044eb2f6afba375a914ac9d8024f8f5142bb912e.tar.gz
src-test2-044eb2f6afba375a914ac9d8024f8f5142bb912e.zip
Notes
Diffstat (limited to 'lib/Target/ARM/ARMInstructionSelector.cpp')
-rw-r--r--lib/Target/ARM/ARMInstructionSelector.cpp190
1 files changed, 153 insertions, 37 deletions
diff --git a/lib/Target/ARM/ARMInstructionSelector.cpp b/lib/Target/ARM/ARMInstructionSelector.cpp
index faed6b867e2b..6bbeae2e1151 100644
--- a/lib/Target/ARM/ARMInstructionSelector.cpp
+++ b/lib/Target/ARM/ARMInstructionSelector.cpp
@@ -15,19 +15,15 @@
#include "ARMSubtarget.h"
#include "ARMTargetMachine.h"
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
+#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
+#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "arm-isel"
-#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
-
using namespace llvm;
-#ifndef LLVM_BUILD_GLOBAL_ISEL
-#error "You shouldn't build this"
-#endif
-
namespace {
#define GET_GLOBALISEL_PREDICATE_BITSET
@@ -39,10 +35,11 @@ public:
ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI,
const ARMRegisterBankInfo &RBI);
- bool select(MachineInstr &I) const override;
+ bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
+ static const char *getName() { return DEBUG_TYPE; }
private:
- bool selectImpl(MachineInstr &I) const;
+ bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
struct CmpConstants;
struct InsertInfo;
@@ -60,7 +57,9 @@ private:
// Set \p DestReg to \p Constant.
void putConstant(InsertInfo I, unsigned DestReg, unsigned Constant) const;
+ bool selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;
bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;
+ bool selectShift(unsigned ShiftOpc, MachineInstrBuilder &MIB) const;
// Check if the types match and both operands have the expected size and
// register bank.
@@ -98,7 +97,7 @@ createARMInstructionSelector(const ARMBaseTargetMachine &TM,
}
}
-unsigned zero_reg = 0;
+const unsigned zero_reg = 0;
#define GET_GLOBALISEL_IMPL
#include "ARMGenGlobalISel.inc"
@@ -488,6 +487,127 @@ bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I,
return true;
}
+bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,
+ MachineRegisterInfo &MRI) const {
+ if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) {
+ DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n");
+ return false;
+ }
+
+ auto GV = MIB->getOperand(1).getGlobal();
+ if (GV->isThreadLocal()) {
+ DEBUG(dbgs() << "TLS variables not supported yet\n");
+ return false;
+ }
+
+ auto &MBB = *MIB->getParent();
+ auto &MF = *MBB.getParent();
+
+ bool UseMovt = STI.useMovt(MF);
+
+ unsigned Size = TM.getPointerSize();
+ unsigned Alignment = 4;
+
+ auto addOpsForConstantPoolLoad = [&MF, Alignment,
+ Size](MachineInstrBuilder &MIB,
+ const GlobalValue *GV, bool IsSBREL) {
+ assert(MIB->getOpcode() == ARM::LDRi12 && "Unsupported instruction");
+ auto ConstPool = MF.getConstantPool();
+ auto CPIndex =
+ // For SB relative entries we need a target-specific constant pool.
+ // Otherwise, just use a regular constant pool entry.
+ IsSBREL
+ ? ConstPool->getConstantPoolIndex(
+ ARMConstantPoolConstant::Create(GV, ARMCP::SBREL), Alignment)
+ : ConstPool->getConstantPoolIndex(GV, Alignment);
+ MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0)
+ .addMemOperand(
+ MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
+ MachineMemOperand::MOLoad, Size, Alignment))
+ .addImm(0)
+ .add(predOps(ARMCC::AL));
+ };
+
+ if (TM.isPositionIndependent()) {
+ bool Indirect = STI.isGVIndirectSymbol(GV);
+ // FIXME: Taking advantage of MOVT for ELF is pretty involved, so we don't
+ // support it yet. See PR28229.
+ unsigned Opc =
+ UseMovt && !STI.isTargetELF()
+ ? (Indirect ? ARM::MOV_ga_pcrel_ldr : ARM::MOV_ga_pcrel)
+ : (Indirect ? ARM::LDRLIT_ga_pcrel_ldr : ARM::LDRLIT_ga_pcrel);
+ MIB->setDesc(TII.get(Opc));
+
+ int TargetFlags = ARMII::MO_NO_FLAG;
+ if (STI.isTargetDarwin())
+ TargetFlags |= ARMII::MO_NONLAZY;
+ if (STI.isGVInGOT(GV))
+ TargetFlags |= ARMII::MO_GOT;
+ MIB->getOperand(1).setTargetFlags(TargetFlags);
+
+ if (Indirect)
+ MIB.addMemOperand(MF.getMachineMemOperand(
+ MachinePointerInfo::getGOT(MF), MachineMemOperand::MOLoad,
+ TM.getPointerSize(), Alignment));
+
+ return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+ }
+
+ bool isReadOnly = STI.getTargetLowering()->isReadOnly(GV);
+ if (STI.isROPI() && isReadOnly) {
+ unsigned Opc = UseMovt ? ARM::MOV_ga_pcrel : ARM::LDRLIT_ga_pcrel;
+ MIB->setDesc(TII.get(Opc));
+ return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+ }
+ if (STI.isRWPI() && !isReadOnly) {
+ auto Offset = MRI.createVirtualRegister(&ARM::GPRRegClass);
+ MachineInstrBuilder OffsetMIB;
+ if (UseMovt) {
+ OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(),
+ TII.get(ARM::MOVi32imm), Offset);
+ OffsetMIB.addGlobalAddress(GV, /*Offset*/ 0, ARMII::MO_SBREL);
+ } else {
+ // Load the offset from the constant pool.
+ OffsetMIB =
+ BuildMI(MBB, *MIB, MIB->getDebugLoc(), TII.get(ARM::LDRi12), Offset);
+ addOpsForConstantPoolLoad(OffsetMIB, GV, /*IsSBREL*/ true);
+ }
+ if (!constrainSelectedInstRegOperands(*OffsetMIB, TII, TRI, RBI))
+ return false;
+
+ // Add the offset to the SB register.
+ MIB->setDesc(TII.get(ARM::ADDrr));
+ MIB->RemoveOperand(1);
+ MIB.addReg(ARM::R9) // FIXME: don't hardcode R9
+ .addReg(Offset)
+ .add(predOps(ARMCC::AL))
+ .add(condCodeOp());
+
+ return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+ }
+
+ if (STI.isTargetELF()) {
+ if (UseMovt) {
+ MIB->setDesc(TII.get(ARM::MOVi32imm));
+ } else {
+ // Load the global's address from the constant pool.
+ MIB->setDesc(TII.get(ARM::LDRi12));
+ MIB->RemoveOperand(1);
+ addOpsForConstantPoolLoad(MIB, GV, /*IsSBREL*/ false);
+ }
+ } else if (STI.isTargetMachO()) {
+ if (UseMovt)
+ MIB->setDesc(TII.get(ARM::MOVi32imm));
+ else
+ MIB->setDesc(TII.get(ARM::LDRLIT_ga_abs));
+ } else {
+ DEBUG(dbgs() << "Object format not supported yet\n");
+ return false;
+ }
+
+ return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+}
+
bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB,
MachineRegisterInfo &MRI) const {
auto &MBB = *MIB->getParent();
@@ -525,7 +645,16 @@ bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB,
return true;
}
-bool ARMInstructionSelector::select(MachineInstr &I) const {
+bool ARMInstructionSelector::selectShift(unsigned ShiftOpc,
+ MachineInstrBuilder &MIB) const {
+ MIB->setDesc(TII.get(ARM::MOVsr));
+ MIB.addImm(ShiftOpc);
+ MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
+ return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);
+}
+
+bool ARMInstructionSelector::select(MachineInstr &I,
+ CodeGenCoverage &CoverageInfo) const {
assert(I.getParent() && "Instruction should be in a basic block!");
assert(I.getParent()->getParent() && "Instruction should be in a function!");
@@ -540,7 +669,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
return true;
}
- if (selectImpl(I))
+ if (selectImpl(I, CoverageInfo))
return true;
MachineInstrBuilder MIB{MF, I};
@@ -633,12 +762,12 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
return selectCmp(Helper, MIB, MRI);
}
case G_FCMP: {
- assert(TII.getSubtarget().hasVFP2() && "Can't select fcmp without VFP");
+ assert(STI.hasVFP2() && "Can't select fcmp without VFP");
unsigned OpReg = I.getOperand(2).getReg();
unsigned Size = MRI.getType(OpReg).getSizeInBits();
- if (Size == 64 && TII.getSubtarget().isFPOnlySP()) {
+ if (Size == 64 && STI.isFPOnlySP()) {
DEBUG(dbgs() << "Subtarget only supports single precision");
return false;
}
@@ -651,6 +780,13 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
ARM::FPRRegBankID, Size);
return selectCmp(Helper, MIB, MRI);
}
+ case G_LSHR:
+ return selectShift(ARM_AM::ShiftOpc::lsr, MIB);
+ case G_ASHR:
+ return selectShift(ARM_AM::ShiftOpc::asr, MIB);
+ case G_SHL: {
+ return selectShift(ARM_AM::ShiftOpc::lsl, MIB);
+ }
case G_GEP:
I.setDesc(TII.get(ARM::ADDrr));
MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
@@ -661,28 +797,8 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
I.setDesc(TII.get(ARM::ADDri));
MIB.addImm(0).add(predOps(ARMCC::AL)).add(condCodeOp());
break;
- case G_CONSTANT: {
- unsigned Reg = I.getOperand(0).getReg();
-
- if (!validReg(MRI, Reg, 32, ARM::GPRRegBankID))
- return false;
-
- I.setDesc(TII.get(ARM::MOVi));
- MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
-
- auto &Val = I.getOperand(1);
- if (Val.isCImm()) {
- if (Val.getCImm()->getBitWidth() > 32)
- return false;
- Val.ChangeToImmediate(Val.getCImm()->getZExtValue());
- }
-
- if (!Val.isImm()) {
- return false;
- }
-
- break;
- }
+ case G_GLOBAL_VALUE:
+ return selectGlobal(MIB, MRI);
case G_STORE:
case G_LOAD: {
const auto &MemOp = **I.memoperands_begin();
@@ -697,7 +813,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
LLT ValTy = MRI.getType(Reg);
const auto ValSize = ValTy.getSizeInBits();
- assert((ValSize != 64 || TII.getSubtarget().hasVFP2()) &&
+ assert((ValSize != 64 || STI.hasVFP2()) &&
"Don't know how to load/store 64-bit value without VFP");
const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize);
@@ -739,7 +855,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
// Branch conditionally.
auto Branch = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(ARM::Bcc))
.add(I.getOperand(1))
- .add(predOps(ARMCC::EQ, ARM::CPSR));
+ .add(predOps(ARMCC::NE, ARM::CPSR));
if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI))
return false;
I.eraseFromParent();