[llvm] 60431bd - [VE] Support for PIC (global data and calls)
Simon Moll via llvm-commits
llvm-commits at lists.llvm.org
Fri Feb 14 00:50:43 PST 2020
Author: Kazushi (Jam) Marukawa
Date: 2020-02-14T09:50:02+01:00
New Revision: 60431bd728f73544a8c3507a9461ec13b53ced74
URL: https://github.com/llvm/llvm-project/commit/60431bd728f73544a8c3507a9461ec13b53ced74
DIFF: https://github.com/llvm/llvm-project/commit/60431bd728f73544a8c3507a9461ec13b53ced74.diff
LOG: [VE] Support for PIC (global data and calls)
Summary: Support for PIC with tests for global variables and function calls.
Reviewed By: arsenm
Differential Revision: https://reviews.llvm.org/D74536
Added:
llvm/test/CodeGen/VE/pic_access_data.ll
llvm/test/CodeGen/VE/pic_access_static_data.ll
llvm/test/CodeGen/VE/pic_func_call.ll
llvm/test/CodeGen/VE/pic_indirect_func_call.ll
Modified:
llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h
llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp
llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h
llvm/lib/Target/VE/VEAsmPrinter.cpp
llvm/lib/Target/VE/VEISelDAGToDAG.cpp
llvm/lib/Target/VE/VEISelLowering.cpp
llvm/lib/Target/VE/VEISelLowering.h
llvm/lib/Target/VE/VEInstrInfo.cpp
llvm/lib/Target/VE/VEInstrInfo.h
llvm/lib/Target/VE/VEInstrInfo.td
llvm/lib/Target/VE/VEMachineFunctionInfo.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h
index 65d850c6a1de..2d796699a3cf 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h
@@ -20,6 +20,28 @@ enum Fixups {
/// fixup_ve_lo32 - 32-bit fixup corresponding to foo at lo
fixup_ve_lo32,
+ /// fixup_ve_pc_hi32 - 32-bit fixup corresponding to foo at pc_hi
+ fixup_ve_pc_hi32,
+
+ /// fixup_ve_pc_lo32 - 32-bit fixup corresponding to foo at pc_lo
+ fixup_ve_pc_lo32,
+
+ /// fixup_ve_got_hi32 - 32-bit fixup corresponding to foo at got_hi
+ fixup_ve_got_hi32,
+
+ /// fixup_ve_got_lo32 - 32-bit fixup corresponding to foo at got_lo
+ fixup_ve_got_lo32,
+
+ /// fixup_ve_gotoff_hi32 - 32-bit fixup corresponding to foo at gotoff_hi
+ fixup_ve_gotoff_hi32,
+
+ /// fixup_ve_gotoff_lo32 - 32-bit fixup corresponding to foo at gotoff_lo
+ fixup_ve_gotoff_lo32,
+
+ /// fixup_ve_plt_hi32/lo32
+ fixup_ve_plt_hi32,
+ fixup_ve_plt_lo32,
+
// Marker
LastTargetFixupKind,
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp
index 678232383293..abb490eb1274 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp
@@ -46,6 +46,14 @@ bool VEMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind) {
case VK_VE_HI32:
case VK_VE_LO32:
+ case VK_VE_PC_HI32:
+ case VK_VE_PC_LO32:
+ case VK_VE_GOT_HI32:
+ case VK_VE_GOT_LO32:
+ case VK_VE_GOTOFF_HI32:
+ case VK_VE_GOTOFF_LO32:
+ case VK_VE_PLT_HI32:
+ case VK_VE_PLT_LO32:
return false; // OS << "@<text>("; break;
}
return true;
@@ -61,6 +69,30 @@ void VEMCExpr::printVariantKindSuffix(raw_ostream &OS, VariantKind Kind) {
case VK_VE_LO32:
OS << "@lo";
break;
+ case VK_VE_PC_HI32:
+ OS << "@pc_hi";
+ break;
+ case VK_VE_PC_LO32:
+ OS << "@pc_lo";
+ break;
+ case VK_VE_GOT_HI32:
+ OS << "@got_hi";
+ break;
+ case VK_VE_GOT_LO32:
+ OS << "@got_lo";
+ break;
+ case VK_VE_GOTOFF_HI32:
+ OS << "@gotoff_hi";
+ break;
+ case VK_VE_GOTOFF_LO32:
+ OS << "@gotoff_lo";
+ break;
+ case VK_VE_PLT_HI32:
+ OS << "@plt_hi";
+ break;
+ case VK_VE_PLT_LO32:
+ OS << "@plt_lo";
+ break;
}
}
@@ -68,6 +100,14 @@ VEMCExpr::VariantKind VEMCExpr::parseVariantKind(StringRef name) {
return StringSwitch<VEMCExpr::VariantKind>(name)
.Case("hi", VK_VE_HI32)
.Case("lo", VK_VE_LO32)
+ .Case("pc_hi", VK_VE_PC_HI32)
+ .Case("pc_lo", VK_VE_PC_LO32)
+ .Case("got_hi", VK_VE_GOT_HI32)
+ .Case("got_lo", VK_VE_GOT_LO32)
+ .Case("gotoff_hi", VK_VE_GOTOFF_HI32)
+ .Case("gotoff_lo", VK_VE_GOTOFF_LO32)
+ .Case("plt_hi", VK_VE_PLT_HI32)
+ .Case("plt_lo", VK_VE_PLT_LO32)
.Default(VK_VE_None);
}
@@ -79,6 +119,22 @@ VE::Fixups VEMCExpr::getFixupKind(VEMCExpr::VariantKind Kind) {
return VE::fixup_ve_hi32;
case VK_VE_LO32:
return VE::fixup_ve_lo32;
+ case VK_VE_PC_HI32:
+ return VE::fixup_ve_pc_hi32;
+ case VK_VE_PC_LO32:
+ return VE::fixup_ve_pc_lo32;
+ case VK_VE_GOT_HI32:
+ return VE::fixup_ve_got_hi32;
+ case VK_VE_GOT_LO32:
+ return VE::fixup_ve_got_lo32;
+ case VK_VE_GOTOFF_HI32:
+ return VE::fixup_ve_gotoff_hi32;
+ case VK_VE_GOTOFF_LO32:
+ return VE::fixup_ve_gotoff_lo32;
+ case VK_VE_PLT_HI32:
+ return VE::fixup_ve_plt_hi32;
+ case VK_VE_PLT_LO32:
+ return VE::fixup_ve_plt_lo32;
}
}
diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h
index d8515608d7b7..8e884443e41f 100644
--- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h
+++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h
@@ -26,6 +26,14 @@ class VEMCExpr : public MCTargetExpr {
VK_VE_None,
VK_VE_HI32,
VK_VE_LO32,
+ VK_VE_PC_HI32,
+ VK_VE_PC_LO32,
+ VK_VE_GOT_HI32,
+ VK_VE_GOT_LO32,
+ VK_VE_GOTOFF_HI32,
+ VK_VE_GOTOFF_LO32,
+ VK_VE_PLT_HI32,
+ VK_VE_PLT_LO32,
};
private:
diff --git a/llvm/lib/Target/VE/VEAsmPrinter.cpp b/llvm/lib/Target/VE/VEAsmPrinter.cpp
index c1e0cc3c422a..6e6acffcb402 100644
--- a/llvm/lib/Target/VE/VEAsmPrinter.cpp
+++ b/llvm/lib/Target/VE/VEAsmPrinter.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "InstPrinter/VEInstPrinter.h"
+#include "MCTargetDesc/VEMCExpr.h"
#include "MCTargetDesc/VETargetStreamer.h"
#include "VE.h"
#include "VEInstrInfo.h"
@@ -46,6 +47,11 @@ class VEAsmPrinter : public AsmPrinter {
StringRef getPassName() const override { return "VE Assembly Printer"; }
+ void lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI);
+ void lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI);
+
void emitInstruction(const MachineInstr *MI) override;
static const char *getRegisterName(unsigned RegNo) {
@@ -54,6 +60,187 @@ class VEAsmPrinter : public AsmPrinter {
};
} // end of anonymous namespace
+static MCOperand createVEMCOperand(VEMCExpr::VariantKind Kind, MCSymbol *Sym,
+ MCContext &OutContext) {
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);
+ const VEMCExpr *expr = VEMCExpr::create(Kind, MCSym, OutContext);
+ return MCOperand::createExpr(expr);
+}
+
+static MCOperand createGOTRelExprOp(VEMCExpr::VariantKind Kind,
+ MCSymbol *GOTLabel, MCContext &OutContext) {
+ const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
+ const VEMCExpr *expr = VEMCExpr::create(Kind, GOT, OutContext);
+ return MCOperand::createExpr(expr);
+}
+
+static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ MCInst SICInst;
+ SICInst.setOpcode(VE::SIC);
+ SICInst.addOperand(RD);
+ OutStreamer.emitInstruction(SICInst, STI);
+}
+
+static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ MCInst LEAInst;
+ LEAInst.setOpcode(VE::LEAzzi);
+ LEAInst.addOperand(RD);
+ LEAInst.addOperand(Imm);
+ OutStreamer.emitInstruction(LEAInst, STI);
+}
+
+static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ MCInst LEASLInst;
+ LEASLInst.setOpcode(VE::LEASLzzi);
+ LEASLInst.addOperand(RD);
+ LEASLInst.addOperand(Imm);
+ OutStreamer.emitInstruction(LEASLInst, STI);
+}
+
+static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
+ MCOperand &RD, const MCSubtargetInfo &STI) {
+ MCInst LEAInst;
+ LEAInst.setOpcode(VE::LEAzii);
+ LEAInst.addOperand(RD);
+ LEAInst.addOperand(RS1);
+ LEAInst.addOperand(Imm);
+ OutStreamer.emitInstruction(LEAInst, STI);
+}
+
+static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1,
+ MCOperand &RS2, MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ MCInst LEASLInst;
+ LEASLInst.setOpcode(VE::LEASLrri);
+ LEASLInst.addOperand(RS1);
+ LEASLInst.addOperand(RS2);
+ LEASLInst.addOperand(RD);
+ LEASLInst.addOperand(Imm);
+ OutStreamer.emitInstruction(LEASLInst, STI);
+}
+
+static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1,
+ MCOperand &Src2, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ MCInst Inst;
+ Inst.setOpcode(Opcode);
+ Inst.addOperand(RD);
+ Inst.addOperand(RS1);
+ Inst.addOperand(Src2);
+ OutStreamer.emitInstruction(Inst, STI);
+}
+
+static void emitANDrm0(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm,
+ MCOperand &RD, const MCSubtargetInfo &STI) {
+ emitBinary(OutStreamer, VE::ANDrm0, RS1, Imm, RD, STI);
+}
+
+static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
+ VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind,
+ MCOperand &RD, MCContext &OutContext,
+ const MCSubtargetInfo &STI) {
+
+ MCOperand hi = createVEMCOperand(HiKind, GOTSym, OutContext);
+ MCOperand lo = createVEMCOperand(LoKind, GOTSym, OutContext);
+ MCOperand ci32 = MCOperand::createImm(32);
+ emitLEAzzi(OutStreamer, lo, RD, STI);
+ emitANDrm0(OutStreamer, RD, ci32, RD, STI);
+ emitLEASLzzi(OutStreamer, hi, RD, STI);
+}
+
+void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI) {
+ MCSymbol *GOTLabel =
+ OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
+
+ const MachineOperand &MO = MI->getOperand(0);
+ MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
+
+ if (!isPositionIndependent()) {
+ // Just load the address of GOT to MCRegOP.
+ switch (TM.getCodeModel()) {
+ default:
+ llvm_unreachable("Unsupported absolute code model");
+ case CodeModel::Small:
+ case CodeModel::Medium:
+ case CodeModel::Large:
+ emitHiLo(*OutStreamer, GOTLabel, VEMCExpr::VK_VE_HI32,
+ VEMCExpr::VK_VE_LO32, MCRegOP, OutContext, STI);
+ break;
+ }
+ return;
+ }
+
+ MCOperand RegGOT = MCOperand::createReg(VE::SX15); // GOT
+ MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
+
+ // lea %got, _GLOBAL_OFFSET_TABLE_ at PC_LO(-24)
+ // and %got, %got, (32)0
+ // sic %plt
+ // lea.sl %got, _GLOBAL_OFFSET_TABLE_ at PC_HI(%got, %plt)
+ MCOperand cim24 = MCOperand::createImm(-24);
+ MCOperand loImm =
+ createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext);
+ emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
+ MCOperand ci32 = MCOperand::createImm(32);
+ emitANDrm0(*OutStreamer, MCRegOP, ci32, MCRegOP, STI);
+ emitSIC(*OutStreamer, RegPLT, STI);
+ MCOperand hiImm =
+ createGOTRelExprOp(VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext);
+ emitLEASLrri(*OutStreamer, RegGOT, RegPLT, hiImm, MCRegOP, STI);
+}
+
+void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI) {
+ const MachineOperand &MO = MI->getOperand(0);
+ MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
+ const MachineOperand &Addr = MI->getOperand(1);
+ MCSymbol *AddrSym = nullptr;
+
+ switch (Addr.getType()) {
+ default:
+ llvm_unreachable("<unknown operand type>");
+ return;
+ case MachineOperand::MO_MachineBasicBlock:
+ report_fatal_error("MBB is not supported yet");
+ return;
+ case MachineOperand::MO_ConstantPoolIndex:
+ report_fatal_error("ConstantPool is not supported yet");
+ return;
+ case MachineOperand::MO_ExternalSymbol:
+ AddrSym = GetExternalSymbolSymbol(Addr.getSymbolName());
+ break;
+ case MachineOperand::MO_GlobalAddress:
+ AddrSym = getSymbol(Addr.getGlobal());
+ break;
+ }
+
+ if (!isPositionIndependent()) {
+ llvm_unreachable("Unsupported uses of %plt in not PIC code");
+ return;
+ }
+
+ MCOperand RegPLT = MCOperand::createReg(VE::SX16); // PLT
+
+ // lea %dst, %plt_lo(func)(-24)
+ // and %dst, %dst, (32)0
+ // sic %plt ; FIXME: is it safe to use %plt here?
+ // lea.sl %dst, %plt_hi(func)(%dst, %plt)
+ MCOperand cim24 = MCOperand::createImm(-24);
+ MCOperand loImm =
+ createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, AddrSym, OutContext);
+ emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI);
+ MCOperand ci32 = MCOperand::createImm(32);
+ emitANDrm0(*OutStreamer, MCRegOP, ci32, MCRegOP, STI);
+ emitSIC(*OutStreamer, RegPLT, STI);
+ MCOperand hiImm =
+ createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, AddrSym, OutContext);
+ emitLEASLrri(*OutStreamer, MCRegOP, RegPLT, hiImm, MCRegOP, STI);
+}
+
void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
switch (MI->getOpcode()) {
@@ -62,7 +249,14 @@ void VEAsmPrinter::emitInstruction(const MachineInstr *MI) {
case TargetOpcode::DBG_VALUE:
// FIXME: Debug Value.
return;
+ case VE::GETGOT:
+ lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo());
+ return;
+ case VE::GETFUNPLT:
+ lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo());
+ return;
}
+
MachineBasicBlock::const_instr_iterator I = MI->getIterator();
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
do {
diff --git a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
index bb7ab594ebc3..c5c449b89e97 100644
--- a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
+++ b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp
@@ -53,6 +53,9 @@ class VEDAGToDAGISel : public SelectionDAGISel {
// Include the pieces autogenerated from the target description.
#include "VEGenDAGISel.inc"
+
+private:
+ SDNode *getGlobalBaseReg();
};
} // end anonymous namespace
@@ -119,9 +122,22 @@ void VEDAGToDAGISel::Select(SDNode *N) {
return; // Already selected.
}
+ switch (N->getOpcode()) {
+ case VEISD::GLOBAL_BASE_REG:
+ ReplaceNode(N, getGlobalBaseReg());
+ return;
+ }
+
SelectCode(N);
}
+SDNode *VEDAGToDAGISel::getGlobalBaseReg() {
+ Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
+ return CurDAG
+ ->getRegister(GlobalBaseReg, TLI->getPointerTy(CurDAG->getDataLayout()))
+ .getNode();
+}
+
/// createVEISelDag - This pass converts a legalized DAG into a
/// VE-specific DAG, ready for instruction scheduling.
///
diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp
index e0411dae1727..70dc35989ff2 100644
--- a/llvm/lib/Target/VE/VEISelLowering.cpp
+++ b/llvm/lib/Target/VE/VEISelLowering.cpp
@@ -312,16 +312,42 @@ SDValue VETargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// Likewise ExternalSymbol -> TargetExternalSymbol.
SDValue Callee = CLI.Callee;
- assert(!isPositionIndependent() && "TODO PIC");
+ bool IsPICCall = isPositionIndependent();
+
+ // PC-relative references to external symbols should go through $stub.
+ // If so, we need to prepare GlobalBaseReg first.
+ const TargetMachine &TM = DAG.getTarget();
+ const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
+ const GlobalValue *GV = nullptr;
+ auto *CalleeG = dyn_cast<GlobalAddressSDNode>(Callee);
+ if (CalleeG)
+ GV = CalleeG->getGlobal();
+ bool Local = TM.shouldAssumeDSOLocal(*Mod, GV);
+ bool UsePlt = !Local;
+ MachineFunction &MF = DAG.getMachineFunction();
// Turn GlobalAddress/ExternalSymbol node into a value node
// containing the address of them here.
- if (isa<GlobalAddressSDNode>(Callee)) {
- Callee =
- makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
- } else if (isa<ExternalSymbolSDNode>(Callee)) {
- Callee =
- makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
+ if (CalleeG) {
+ if (IsPICCall) {
+ if (UsePlt)
+ Subtarget->getInstrInfo()->getGlobalBaseReg(&MF);
+ Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, 0);
+ Callee = DAG.getNode(VEISD::GETFUNPLT, DL, PtrVT, Callee);
+ } else {
+ Callee =
+ makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
+ }
+ } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ if (IsPICCall) {
+ if (UsePlt)
+ Subtarget->getInstrInfo()->getGlobalBaseReg(&MF);
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), PtrVT, 0);
+ Callee = DAG.getNode(VEISD::GETFUNPLT, DL, PtrVT, Callee);
+ } else {
+ Callee =
+ makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG);
+ }
}
RegsToPass.push_back(std::make_pair(VE::SX12, Callee));
@@ -613,8 +639,10 @@ const char *VETargetLowering::getTargetNodeName(unsigned Opcode) const {
break;
TARGET_NODE_CASE(Lo)
TARGET_NODE_CASE(Hi)
+ TARGET_NODE_CASE(GETFUNPLT)
TARGET_NODE_CASE(CALL)
TARGET_NODE_CASE(RET_FLAG)
+ TARGET_NODE_CASE(GLOBAL_BASE_REG)
}
#undef TARGET_NODE_CASE
return nullptr;
@@ -658,8 +686,43 @@ SDValue VETargetLowering::makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF,
// or ExternalSymbol SDNode.
SDValue VETargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
SDLoc DL(Op);
-
- assert(!isPositionIndependent() && "TODO implement PIC");
+ EVT PtrVT = Op.getValueType();
+
+ // Handle PIC mode first. VE needs a got load for every variable!
+ if (isPositionIndependent()) {
+ // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
+ // function has calls.
+ MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI.setHasCalls(true);
+ auto GlobalN = dyn_cast<GlobalAddressSDNode>(Op);
+
+ if (isa<ConstantPoolSDNode>(Op) ||
+ (GlobalN && GlobalN->getGlobal()->hasLocalLinkage())) {
+ // Create following instructions for local linkage PIC code.
+ // lea %s35, %gotoff_lo(.LCPI0_0)
+ // and %s35, %s35, (32)0
+ // lea.sl %s35, %gotoff_hi(.LCPI0_0)(%s35)
+ // adds.l %s35, %s15, %s35 ; %s15 is GOT
+ // FIXME: use lea.sl %s35, %gotoff_hi(.LCPI0_0)(%s35, %s15)
+ SDValue HiLo = makeHiLoPair(Op, VEMCExpr::VK_VE_GOTOFF_HI32,
+ VEMCExpr::VK_VE_GOTOFF_LO32, DAG);
+ SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, PtrVT);
+ return DAG.getNode(ISD::ADD, DL, PtrVT, GlobalBase, HiLo);
+ }
+ // Create following instructions for not local linkage PIC code.
+ // lea %s35, %got_lo(.LCPI0_0)
+ // and %s35, %s35, (32)0
+ // lea.sl %s35, %got_hi(.LCPI0_0)(%s35)
+ // adds.l %s35, %s15, %s35 ; %s15 is GOT
+ // ld %s35, (,%s35)
+ // FIXME: use lea.sl %s35, %gotoff_hi(.LCPI0_0)(%s35, %s15)
+ SDValue HiLo = makeHiLoPair(Op, VEMCExpr::VK_VE_GOT_HI32,
+ VEMCExpr::VK_VE_GOT_LO32, DAG);
+ SDValue GlobalBase = DAG.getNode(VEISD::GLOBAL_BASE_REG, DL, PtrVT);
+ SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, PtrVT, GlobalBase, HiLo);
+ return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), AbsAddr,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+ }
// This is one of the absolute code models.
switch (getTargetMachine().getCodeModel()) {
diff --git a/llvm/lib/Target/VE/VEISelLowering.h b/llvm/lib/Target/VE/VEISelLowering.h
index 1fe0122457b3..0d3796ebb60e 100644
--- a/llvm/lib/Target/VE/VEISelLowering.h
+++ b/llvm/lib/Target/VE/VEISelLowering.h
@@ -27,8 +27,10 @@ enum NodeType : unsigned {
Hi,
Lo, // Hi/Lo operations, typically on a global address.
+ GETFUNPLT, // load function address through %plt insturction
CALL, // A call instruction.
- RET_FLAG, // Return with a flag operand.
+ RET_FLAG, // Return with a flag operand.
+ GLOBAL_BASE_REG, // Global base reg for PIC.
};
}
diff --git a/llvm/lib/Target/VE/VEInstrInfo.cpp b/llvm/lib/Target/VE/VEInstrInfo.cpp
index e51e48fc4dbb..8d2fff7b76df 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.cpp
+++ b/llvm/lib/Target/VE/VEInstrInfo.cpp
@@ -12,6 +12,7 @@
#include "VEInstrInfo.h"
#include "VE.h"
+#include "VEMachineFunctionInfo.h"
#include "VESubtarget.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -404,6 +405,25 @@ void VEInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
report_fatal_error("Can't load this register from stack slot");
}
+Register VEInstrInfo::getGlobalBaseReg(MachineFunction *MF) const {
+ VEMachineFunctionInfo *VEFI = MF->getInfo<VEMachineFunctionInfo>();
+ Register GlobalBaseReg = VEFI->getGlobalBaseReg();
+ if (GlobalBaseReg != 0)
+ return GlobalBaseReg;
+
+ // We use %s15 (%got) as a global base register
+ GlobalBaseReg = VE::SX15;
+
+ // Insert a pseudo instruction to set the GlobalBaseReg into the first
+ // MBB of the function
+ MachineBasicBlock &FirstMBB = MF->front();
+ MachineBasicBlock::iterator MBBI = FirstMBB.begin();
+ DebugLoc dl;
+ BuildMI(FirstMBB, MBBI, dl, get(VE::GETGOT), GlobalBaseReg);
+ VEFI->setGlobalBaseReg(GlobalBaseReg);
+ return GlobalBaseReg;
+}
+
bool VEInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
switch (MI.getOpcode()) {
case VE::EXTEND_STACK: {
diff --git a/llvm/lib/Target/VE/VEInstrInfo.h b/llvm/lib/Target/VE/VEInstrInfo.h
index 0fc9e48c1b0e..47021efa9016 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.h
+++ b/llvm/lib/Target/VE/VEInstrInfo.h
@@ -76,6 +76,8 @@ class VEInstrInfo : public VEGenInstrInfo {
const TargetRegisterInfo *TRI) const override;
/// } Stack Spill & Reload
+ Register getGlobalBaseReg(MachineFunction *MF) const;
+
// Lower pseudo instructions after register allocation.
bool expandPostRAPseudo(MachineInstr &MI) const override;
diff --git a/llvm/lib/Target/VE/VEInstrInfo.td b/llvm/lib/Target/VE/VEInstrInfo.td
index f788b3232f7e..8fb89c83c5ff 100644
--- a/llvm/lib/Target/VE/VEInstrInfo.td
+++ b/llvm/lib/Target/VE/VEInstrInfo.td
@@ -210,6 +210,13 @@ def call : SDNode<"VEISD::CALL", SDT_SPCall,
def retflag : SDNode<"VEISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+
+def getGOT : Operand<iPTR>;
+
+// GETFUNPLT for PIC
+def GetFunPLT : SDNode<"VEISD::GETFUNPLT", SDTIntUnaryOp>;
+
+
//===----------------------------------------------------------------------===//
// VE Flag Conditions
//===----------------------------------------------------------------------===//
@@ -264,6 +271,17 @@ multiclass RMm<string opcStr, bits<8>opc,
let cz = 1;
let hasSideEffects = 0;
}
+ def zii : RM<
+ opc, (outs RC:$sx), (ins immOp:$sy, immOp2:$imm32),
+ !strconcat(opcStr, " $sx, ${imm32}(${sy})"),
+ [/* Not define DAG pattern here to avoid llvm uses LEAzii for all add
+ instructions.
+ (set Ty:$sx, (OpNode (Ty simm7:$sy), (Ty simm32:$imm32))) */]> {
+ let cy = 0;
+ let cz = 0;
+ let sz = 0;
+ let hasSideEffects = 0;
+ }
def zzi : RM<
opc, (outs RC:$sx), (ins immOp2:$imm32),
!strconcat(opcStr, " $sx, $imm32")> {
@@ -1031,6 +1049,11 @@ def MONC : RR<
0x3F, (outs), (ins),
"monc">;
+// Save Instruction Counter
+
+let cx = 0, cy = 0, sy = 0, cz = 0, sz = 0, hasSideEffects = 0 /* , Uses = [IC] */ in
+def SIC : RR<0x28, (outs I32:$sx), (ins), "sic $sx">;
+
//===----------------------------------------------------------------------===//
// Instructions for CodeGenOnly
//===----------------------------------------------------------------------===//
@@ -1208,6 +1231,23 @@ def : Pat<(brcc cond:$cond, f64:$l, f64:$r, bb:$addr),
// Pseudo Instructions
//===----------------------------------------------------------------------===//
+// GETGOT for PIC
+let Defs = [SX15 /* %got */, SX16 /* %plt */], hasSideEffects = 0 in {
+ def GETGOT : Pseudo<(outs getGOT:$getpcseq), (ins), "$getpcseq">;
+}
+
+// GETFUNPLT for PIC
+let hasSideEffects = 0 in
+def GETFUNPLT : Pseudo<(outs I64:$dst), (ins i64imm:$addr),
+ "$dst, $addr",
+ [(set iPTR:$dst, (GetFunPLT tglobaladdr:$addr))] >;
+
+def : Pat<(GetFunPLT tglobaladdr:$dst),
+ (GETFUNPLT tglobaladdr:$dst)>;
+def : Pat<(GetFunPLT texternalsym:$dst),
+ (GETFUNPLT texternalsym:$dst)>;
+
+
let Defs = [SX11], Uses = [SX11], hasSideEffects = 0 in {
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i64imm:$amt, i64imm:$amt2),
"# ADJCALLSTACKDOWN $amt, $amt2",
diff --git a/llvm/lib/Target/VE/VEMachineFunctionInfo.h b/llvm/lib/Target/VE/VEMachineFunctionInfo.h
index be919a99b517..16b25fed3f11 100644
--- a/llvm/lib/Target/VE/VEMachineFunctionInfo.h
+++ b/llvm/lib/Target/VE/VEMachineFunctionInfo.h
@@ -20,6 +20,8 @@ class VEMachineFunctionInfo : public MachineFunctionInfo {
virtual void anchor();
private:
+ Register GlobalBaseReg;
+
/// VarArgsFrameOffset - Frame offset to start of varargs area.
int VarArgsFrameOffset;
@@ -27,9 +29,13 @@ class VEMachineFunctionInfo : public MachineFunctionInfo {
bool IsLeafProc;
public:
- VEMachineFunctionInfo() : VarArgsFrameOffset(0), IsLeafProc(false) {}
+ VEMachineFunctionInfo()
+ : GlobalBaseReg(), VarArgsFrameOffset(0), IsLeafProc(false) {}
explicit VEMachineFunctionInfo(MachineFunction &MF)
- : VarArgsFrameOffset(0), IsLeafProc(false) {}
+ : GlobalBaseReg(), VarArgsFrameOffset(0), IsLeafProc(false) {}
+
+ Register getGlobalBaseReg() const { return GlobalBaseReg; }
+ void setGlobalBaseReg(Register Reg) { GlobalBaseReg = Reg; }
int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
diff --git a/llvm/test/CodeGen/VE/pic_access_data.ll b/llvm/test/CodeGen/VE/pic_access_data.ll
new file mode 100644
index 000000000000..0cfabe804880
--- /dev/null
+++ b/llvm/test/CodeGen/VE/pic_access_data.ll
@@ -0,0 +1,39 @@
+; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
+
+ at dst = external global i32, align 4
+ at ptr = external global i32*, align 8
+ at src = external global i32, align 4
+
+define i32 @func() {
+; CHECK-LABEL: func:
+; CHECK: .LBB{{[0-9]+}}_2:
+; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_ at pc_lo(-24)
+; CHECK-NEXT: and %s15, %s15, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_ at pc_hi(%s16, %s15)
+; CHECK-NEXT: lea %s0, dst at got_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, dst at got_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: ld %s1, (,%s0)
+; CHECK-NEXT: lea %s0, ptr at got_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, ptr at got_hi(%s0)
+; CHECK-NEXT: lea %s2, src at got_lo
+; CHECK-NEXT: and %s2, %s2, (32)0
+; CHECK-NEXT: lea.sl %s2, src at got_hi(%s2)
+; CHECK-NEXT: adds.l %s2, %s15, %s2
+; CHECK-NEXT: ld %s2, (,%s2)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: ld %s0, (,%s0)
+; CHECK-NEXT: ldl.sx %s2, (,%s2)
+; CHECK-NEXT: st %s1, (,%s0)
+; CHECK-NEXT: or %s0, 1, (0)1
+; CHECK-NEXT: stl %s2, (,%s1)
+; CHECK-NEXT: or %s11, 0, %s9
+
+ store i32* @dst, i32** @ptr, align 8
+ %1 = load i32, i32* @src, align 4
+ store i32 %1, i32* @dst, align 4
+ ret i32 1
+}
diff --git a/llvm/test/CodeGen/VE/pic_access_static_data.ll b/llvm/test/CodeGen/VE/pic_access_static_data.ll
new file mode 100644
index 000000000000..b95ae66a6f78
--- /dev/null
+++ b/llvm/test/CodeGen/VE/pic_access_static_data.ll
@@ -0,0 +1,79 @@
+; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
+
+ at dst = internal unnamed_addr global i32 0, align 4
+ at src = internal unnamed_addr global i1 false, align 4
+ at .str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
+
+define void @func() {
+; CHECK-LABEL: func:
+; CHECK: .LBB{{[0-9]+}}_2:
+; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_ at pc_lo(-24)
+; CHECK-NEXT: and %s15, %s15, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_ at pc_hi(%s16, %s15)
+; CHECK-NEXT: lea %s0, src at gotoff_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, src at gotoff_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: ld1b.zx %s0, (,%s0)
+; CHECK-NEXT: or %s1, 0, (0)1
+; CHECK-NEXT: lea %s2, 100
+; CHECK-NEXT: cmov.w.ne %s1, %s2, %s0
+; CHECK-NEXT: lea %s0, dst at gotoff_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, dst at gotoff_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: stl %s1, (,%s0)
+; CHECK-NEXT: or %s11, 0, %s9
+
+ %1 = load i1, i1* @src, align 4
+ %2 = select i1 %1, i32 100, i32 0
+ store i32 %2, i32* @dst, align 4
+ ret void
+}
+
+; Function Attrs: nounwind
+define i32 @main() {
+; CHECK-LABEL: main:
+; CHECK: .LBB{{[0-9]+}}_2:
+; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_ at pc_lo(-24)
+; CHECK-NEXT: and %s15, %s15, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_ at pc_hi(%s16, %s15)
+; CHECK-NEXT: lea %s0, src at gotoff_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, src at gotoff_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: or %s1, 1, (0)1
+; CHECK-NEXT: st1b %s1, (,%s0)
+; CHECK-NEXT: lea %s12, func at plt_lo(-24)
+; CHECK-NEXT: and %s12, %s12, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s12, func at plt_hi(%s16, %s12)
+; CHECK-NEXT: bsic %lr, (,%s12)
+; CHECK-NEXT: lea %s0, dst at gotoff_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, dst at gotoff_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: ldl.sx %s1, (,%s0)
+; CHECK-NEXT: stl %s1, 184(,%s11)
+; CHECK-NEXT: lea %s0, .L.str at gotoff_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, .L.str at gotoff_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: lea %s12, printf at plt_lo(-24)
+; CHECK-NEXT: and %s12, %s12, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s12, printf at plt_hi(%s16, %s12)
+; CHECK-NEXT: st %s0, 176(,%s11)
+; CHECK-NEXT: bsic %lr, (,%s12)
+; CHECK-NEXT: or %s0, 0, (0)1
+; CHECK-NEXT: or %s11, 0, %s9
+ store i1 true, i1* @src, align 4
+ tail call void @func()
+ %1 = load i32, i32* @dst, align 4
+ %2 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i64 0, i64 0), i32 %1)
+ ret i32 0
+}
+
+declare i32 @printf(i8* nocapture readonly, ...)
diff --git a/llvm/test/CodeGen/VE/pic_func_call.ll b/llvm/test/CodeGen/VE/pic_func_call.ll
new file mode 100644
index 000000000000..a5f8a6acc075
--- /dev/null
+++ b/llvm/test/CodeGen/VE/pic_func_call.ll
@@ -0,0 +1,21 @@
+; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
+
+define void @func() {
+; CHECK-LABEL: func:
+; CHECK: .LBB{{[0-9]+}}_2:
+; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_ at pc_lo(-24)
+; CHECK-NEXT: and %s15, %s15, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_ at pc_hi(%s16, %s15)
+; CHECK-NEXT: lea %s12, function at plt_lo(-24)
+; CHECK-NEXT: and %s12, %s12, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s12, function at plt_hi(%s16, %s12)
+; CHECK-NEXT: bsic %lr, (,%s12)
+; CHECK-NEXT: or %s11, 0, %s9
+
+ call void bitcast (void (...)* @function to void ()*)()
+ ret void
+}
+
+declare void @function(...)
diff --git a/llvm/test/CodeGen/VE/pic_indirect_func_call.ll b/llvm/test/CodeGen/VE/pic_indirect_func_call.ll
new file mode 100644
index 000000000000..17069667029e
--- /dev/null
+++ b/llvm/test/CodeGen/VE/pic_indirect_func_call.ll
@@ -0,0 +1,34 @@
+; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
+
+ at ptr = external global void (...)*, align 8
+
+define void @func() {
+; CHECK-LABEL: func:
+; CHECK: .LBB{{[0-9]+}}_2:
+; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_ at pc_lo(-24)
+; CHECK-NEXT: and %s15, %s15, (32)0
+; CHECK-NEXT: sic %s16
+; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_ at pc_hi(%s16, %s15)
+; CHECK-NEXT: lea %s0, function at got_lo
+; CHECK-NEXT: and %s0, %s0, (32)0
+; CHECK-NEXT: lea.sl %s0, function at got_hi(%s0)
+; CHECK-NEXT: adds.l %s0, %s15, %s0
+; CHECK-NEXT: ld %s0, (,%s0)
+; CHECK-NEXT: lea %s1, ptr at got_lo
+; CHECK-NEXT: and %s1, %s1, (32)0
+; CHECK-NEXT: lea.sl %s1, ptr at got_hi(%s1)
+; CHECK-NEXT: adds.l %s1, %s15, %s1
+; CHECK-NEXT: ld %s1, (,%s1)
+; CHECK-NEXT: st %s0, (,%s1)
+; CHECK-NEXT: or %s12, 0, %s0
+; CHECK-NEXT: bsic %lr, (,%s12)
+; CHECK-NEXT: or %s11, 0, %s9
+
+ store void (...)* @function, void (...)** @ptr, align 8
+ %1 = load void (...)*, void (...)** @ptr, align 8
+ %2 = bitcast void (...)* %1 to void ()*
+ call void %2()
+ ret void
+}
+
+declare void @function(...)
More information about the llvm-commits
mailing list