1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 20:23:11 +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:
Kazushi (Jam) Marukawa 2020-02-14 09:31:06 +01:00 committed by Simon Moll
parent 0b9c6d5bd5
commit 8a8a4f905c
15 changed files with 613 additions and 11 deletions

View File

@ -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

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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 {

View File

@ -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.
///

View File

@ -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);
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()) {

View File

@ -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.
};
}

View File

@ -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: {

View File

@ -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;

View File

@ -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",

View File

@ -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; }

View 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
}

View 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, ...)

View 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(...)

View 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(...)