mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[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
This commit is contained in:
parent
0b9c6d5bd5
commit
8a8a4f905c
@ -20,6 +20,28 @@ enum Fixups {
|
||||
/// fixup_ve_lo32 - 32-bit fixup corresponding to foo@lo
|
||||
fixup_ve_lo32,
|
||||
|
||||
/// fixup_ve_pc_hi32 - 32-bit fixup corresponding to foo@pc_hi
|
||||
fixup_ve_pc_hi32,
|
||||
|
||||
/// fixup_ve_pc_lo32 - 32-bit fixup corresponding to foo@pc_lo
|
||||
fixup_ve_pc_lo32,
|
||||
|
||||
/// fixup_ve_got_hi32 - 32-bit fixup corresponding to foo@got_hi
|
||||
fixup_ve_got_hi32,
|
||||
|
||||
/// fixup_ve_got_lo32 - 32-bit fixup corresponding to foo@got_lo
|
||||
fixup_ve_got_lo32,
|
||||
|
||||
/// fixup_ve_gotoff_hi32 - 32-bit fixup corresponding to foo@gotoff_hi
|
||||
fixup_ve_gotoff_hi32,
|
||||
|
||||
/// fixup_ve_gotoff_lo32 - 32-bit fixup corresponding to foo@gotoff_lo
|
||||
fixup_ve_gotoff_lo32,
|
||||
|
||||
/// fixup_ve_plt_hi32/lo32
|
||||
fixup_ve_plt_hi32,
|
||||
fixup_ve_plt_lo32,
|
||||
|
||||
// Marker
|
||||
LastTargetFixupKind,
|
||||
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,14 @@ public:
|
||||
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:
|
||||
|
@ -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 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
};
|
||||
} // 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_@PC_LO(-24)
|
||||
// and %got, %got, (32)0
|
||||
// sic %plt
|
||||
// lea.sl %got, _GLOBAL_OFFSET_TABLE_@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 {
|
||||
|
@ -53,6 +53,9 @@ public:
|
||||
|
||||
// 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.
|
||||
///
|
||||
|
@ -312,17 +312,43 @@ 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)) {
|
||||
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 (isa<ExternalSymbolSDNode>(Callee)) {
|
||||
}
|
||||
} 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);
|
||||
EVT PtrVT = Op.getValueType();
|
||||
|
||||
assert(!isPositionIndependent() && "TODO implement PIC");
|
||||
// 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()) {
|
||||
|
@ -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.
|
||||
GLOBAL_BASE_REG, // Global base reg for PIC.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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: {
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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 @@ private:
|
||||
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; }
|
||||
|
39
test/CodeGen/VE/pic_access_data.ll
Normal file
39
test/CodeGen/VE/pic_access_data.ll
Normal file
@ -0,0 +1,39 @@
|
||||
; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
@dst = external global i32, align 4
|
||||
@ptr = external global i32*, align 8
|
||||
@src = external global i32, align 4
|
||||
|
||||
define i32 @func() {
|
||||
; CHECK-LABEL: func:
|
||||
; CHECK: .LBB{{[0-9]+}}_2:
|
||||
; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24)
|
||||
; CHECK-NEXT: and %s15, %s15, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15)
|
||||
; CHECK-NEXT: lea %s0, dst@got_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, dst@got_hi(%s0)
|
||||
; CHECK-NEXT: adds.l %s0, %s15, %s0
|
||||
; CHECK-NEXT: ld %s1, (,%s0)
|
||||
; CHECK-NEXT: lea %s0, ptr@got_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, ptr@got_hi(%s0)
|
||||
; CHECK-NEXT: lea %s2, src@got_lo
|
||||
; CHECK-NEXT: and %s2, %s2, (32)0
|
||||
; CHECK-NEXT: lea.sl %s2, src@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
|
||||
}
|
79
test/CodeGen/VE/pic_access_static_data.ll
Normal file
79
test/CodeGen/VE/pic_access_static_data.ll
Normal file
@ -0,0 +1,79 @@
|
||||
; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
@dst = internal unnamed_addr global i32 0, align 4
|
||||
@src = internal unnamed_addr global i1 false, align 4
|
||||
@.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_@pc_lo(-24)
|
||||
; CHECK-NEXT: and %s15, %s15, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15)
|
||||
; CHECK-NEXT: lea %s0, src@gotoff_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, src@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@gotoff_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, dst@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_@pc_lo(-24)
|
||||
; CHECK-NEXT: and %s15, %s15, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15)
|
||||
; CHECK-NEXT: lea %s0, src@gotoff_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, src@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@plt_lo(-24)
|
||||
; CHECK-NEXT: and %s12, %s12, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s12, func@plt_hi(%s16, %s12)
|
||||
; CHECK-NEXT: bsic %lr, (,%s12)
|
||||
; CHECK-NEXT: lea %s0, dst@gotoff_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, dst@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@gotoff_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, .L.str@gotoff_hi(%s0)
|
||||
; CHECK-NEXT: adds.l %s0, %s15, %s0
|
||||
; CHECK-NEXT: lea %s12, printf@plt_lo(-24)
|
||||
; CHECK-NEXT: and %s12, %s12, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s12, printf@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, ...)
|
21
test/CodeGen/VE/pic_func_call.ll
Normal file
21
test/CodeGen/VE/pic_func_call.ll
Normal file
@ -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_@pc_lo(-24)
|
||||
; CHECK-NEXT: and %s15, %s15, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15)
|
||||
; CHECK-NEXT: lea %s12, function@plt_lo(-24)
|
||||
; CHECK-NEXT: and %s12, %s12, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s12, function@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(...)
|
34
test/CodeGen/VE/pic_indirect_func_call.ll
Normal file
34
test/CodeGen/VE/pic_indirect_func_call.ll
Normal file
@ -0,0 +1,34 @@
|
||||
; RUN: llc -relocation-model=pic < %s -mtriple=ve-unknown-unknown | FileCheck %s
|
||||
|
||||
@ptr = external global void (...)*, align 8
|
||||
|
||||
define void @func() {
|
||||
; CHECK-LABEL: func:
|
||||
; CHECK: .LBB{{[0-9]+}}_2:
|
||||
; CHECK-NEXT: lea %s15, _GLOBAL_OFFSET_TABLE_@pc_lo(-24)
|
||||
; CHECK-NEXT: and %s15, %s15, (32)0
|
||||
; CHECK-NEXT: sic %s16
|
||||
; CHECK-NEXT: lea.sl %s15, _GLOBAL_OFFSET_TABLE_@pc_hi(%s16, %s15)
|
||||
; CHECK-NEXT: lea %s0, function@got_lo
|
||||
; CHECK-NEXT: and %s0, %s0, (32)0
|
||||
; CHECK-NEXT: lea.sl %s0, function@got_hi(%s0)
|
||||
; CHECK-NEXT: adds.l %s0, %s15, %s0
|
||||
; CHECK-NEXT: ld %s0, (,%s0)
|
||||
; CHECK-NEXT: lea %s1, ptr@got_lo
|
||||
; CHECK-NEXT: and %s1, %s1, (32)0
|
||||
; CHECK-NEXT: lea.sl %s1, ptr@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(...)
|
Loading…
Reference in New Issue
Block a user