diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h --- a/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h +++ b/llvm/lib/Target/VE/MCTargetDesc/VEFixupKinds.h @@ -20,6 +20,28 @@ /// 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 diff --git a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.h @@ -26,6 +26,14 @@ 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/MCTargetDesc/VEMCExpr.cpp b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp --- a/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp +++ b/llvm/lib/Target/VE/MCTargetDesc/VEMCExpr.cpp @@ -46,6 +46,14 @@ 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 << "@("; break; } return true; @@ -61,6 +69,30 @@ 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 @@ return StringSwitch(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 @@ 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/VEAsmPrinter.cpp b/llvm/lib/Target/VE/VEAsmPrinter.cpp --- 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 @@ 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 @@ }; } // 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(""); + 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 @@ 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 --- a/llvm/lib/Target/VE/VEISelDAGToDAG.cpp +++ b/llvm/lib/Target/VE/VEISelDAGToDAG.cpp @@ -53,6 +53,9 @@ // Include the pieces autogenerated from the target description. #include "VEGenDAGISel.inc" + +private: + SDNode *getGlobalBaseReg(); }; } // end anonymous namespace @@ -119,9 +122,22 @@ 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.h b/llvm/lib/Target/VE/VEISelLowering.h --- a/llvm/lib/Target/VE/VEISelLowering.h +++ b/llvm/lib/Target/VE/VEISelLowering.h @@ -27,8 +27,10 @@ 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/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -312,16 +312,42 @@ // 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(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(Callee)) { - Callee = - makeHiLoPair(Callee, VEMCExpr::VK_VE_HI32, VEMCExpr::VK_VE_LO32, DAG); - } else if (isa(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(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 @@ 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 @@ // 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(Op); + + if (isa(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/VEInstrInfo.h b/llvm/lib/Target/VE/VEInstrInfo.h --- a/llvm/lib/Target/VE/VEInstrInfo.h +++ b/llvm/lib/Target/VE/VEInstrInfo.h @@ -76,6 +76,8 @@ 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.cpp b/llvm/lib/Target/VE/VEInstrInfo.cpp --- 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 @@ report_fatal_error("Can't load this register from stack slot"); } +Register VEInstrInfo::getGlobalBaseReg(MachineFunction *MF) const { + VEMachineFunctionInfo *VEFI = MF->getInfo(); + 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.td b/llvm/lib/Target/VE/VEInstrInfo.td --- a/llvm/lib/Target/VE/VEInstrInfo.td +++ b/llvm/lib/Target/VE/VEInstrInfo.td @@ -210,6 +210,13 @@ def retflag : SDNode<"VEISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; + +def getGOT : Operand; + +// GETFUNPLT for PIC +def GetFunPLT : SDNode<"VEISD::GETFUNPLT", SDTIntUnaryOp>; + + //===----------------------------------------------------------------------===// // VE Flag Conditions //===----------------------------------------------------------------------===// @@ -264,6 +271,17 @@ 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 @@ 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 @@ // 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 --- a/llvm/lib/Target/VE/VEMachineFunctionInfo.h +++ b/llvm/lib/Target/VE/VEMachineFunctionInfo.h @@ -20,6 +20,8 @@ virtual void anchor(); private: + Register GlobalBaseReg; + /// VarArgsFrameOffset - Frame offset to start of varargs area. int VarArgsFrameOffset; @@ -27,9 +29,13 @@ 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 --- /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 + +@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 +} 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 --- /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 + +@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, ...) diff --git a/llvm/test/CodeGen/VE/pic_func_call.ll b/llvm/test/CodeGen/VE/pic_func_call.ll new file mode 100644 --- /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_@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(...) 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 --- /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 + +@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(...)