//===-- VEAsmPrinter.cpp - VE LLVM assembly writer ------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation // of machine-dependent LLVM code to GAS-format VE assembly language. // //===----------------------------------------------------------------------===// #include "MCTargetDesc/VEInstPrinter.h" #include "MCTargetDesc/VEMCExpr.h" #include "MCTargetDesc/VETargetStreamer.h" #include "TargetInfo/VETargetInfo.h" #include "VE.h" #include "VEInstrInfo.h" #include "VETargetMachine.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/Mangler.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "ve-asmprinter" namespace { class VEAsmPrinter : public AsmPrinter { VETargetStreamer &getTargetStreamer() { return static_cast(*OutStreamer->getTargetStreamer()); } public: explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)) {} 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 lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, const MCSubtargetInfo &STI); void emitInstruction(const MachineInstr *MI) override; static const char *getRegisterName(MCRegister Reg) { return VEInstPrinter::getRegisterName(Reg); } void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS); bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override; }; } // 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 emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2, const MCSubtargetInfo &STI) { MCInst BSICInst; BSICInst.setOpcode(VE::BSICrii); BSICInst.addOperand(R1); BSICInst.addOperand(R2); MCOperand czero = MCOperand::createImm(0); BSICInst.addOperand(czero); BSICInst.addOperand(czero); OutStreamer.emitInstruction(BSICInst, STI); } static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, const MCSubtargetInfo &STI) { MCInst LEAInst; LEAInst.setOpcode(VE::LEAzii); LEAInst.addOperand(RD); MCOperand CZero = MCOperand::createImm(0); LEAInst.addOperand(CZero); LEAInst.addOperand(CZero); LEAInst.addOperand(Imm); OutStreamer.emitInstruction(LEAInst, STI); } static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, const MCSubtargetInfo &STI) { MCInst LEASLInst; LEASLInst.setOpcode(VE::LEASLzii); LEASLInst.addOperand(RD); MCOperand CZero = MCOperand::createImm(0); LEASLInst.addOperand(CZero); LEASLInst.addOperand(CZero); 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); MCOperand CZero = MCOperand::createImm(0); LEAInst.addOperand(CZero); 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(RD); LEASLInst.addOperand(RS1); LEASLInst.addOperand(RS2); 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 emitANDrm(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm, MCOperand &RD, const MCSubtargetInfo &STI) { emitBinary(OutStreamer, VE::ANDrm, 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); emitLEAzzi(OutStreamer, lo, RD, STI); MCOperand M032 = MCOperand::createImm(M0(32)); emitANDrm(OutStreamer, RD, M032, 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(%plt, %got) MCOperand cim24 = MCOperand::createImm(-24); MCOperand loImm = createGOTRelExprOp(VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext); emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI); MCOperand M032 = MCOperand::createImm(M0(32)); emitANDrm(*OutStreamer, MCRegOP, M032, 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, func@plt_lo(-24) // and %dst, %dst, (32)0 // sic %plt ; FIXME: is it safe to use %plt here? // lea.sl %dst, func@plt_hi(%plt, %dst) MCOperand cim24 = MCOperand::createImm(-24); MCOperand loImm = createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, AddrSym, OutContext); emitLEAzii(*OutStreamer, cim24, loImm, MCRegOP, STI); MCOperand M032 = MCOperand::createImm(M0(32)); emitANDrm(*OutStreamer, MCRegOP, M032, 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::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, const MCSubtargetInfo &STI) { const MachineOperand &Addr = MI->getOperand(0); 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; } MCOperand RegLR = MCOperand::createReg(VE::SX10); // LR MCOperand RegS0 = MCOperand::createReg(VE::SX0); // S0 MCOperand RegS12 = MCOperand::createReg(VE::SX12); // S12 MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Twine("__tls_get_addr")); // lea %s0, sym@tls_gd_lo(-24) // and %s0, %s0, (32)0 // sic %lr // lea.sl %s0, sym@tls_gd_hi(%lr, %s0) // lea %s12, __tls_get_addr@plt_lo(8) // and %s12, %s12, (32)0 // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr) // bsic %lr, (, %s12) MCOperand cim24 = MCOperand::createImm(-24); MCOperand loImm = createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_LO32, AddrSym, OutContext); emitLEAzii(*OutStreamer, cim24, loImm, RegS0, STI); MCOperand M032 = MCOperand::createImm(M0(32)); emitANDrm(*OutStreamer, RegS0, M032, RegS0, STI); emitSIC(*OutStreamer, RegLR, STI); MCOperand hiImm = createGOTRelExprOp(VEMCExpr::VK_VE_TLS_GD_HI32, AddrSym, OutContext); emitLEASLrri(*OutStreamer, RegS0, RegLR, hiImm, RegS0, STI); MCOperand ci8 = MCOperand::createImm(8); MCOperand loImm2 = createGOTRelExprOp(VEMCExpr::VK_VE_PLT_LO32, GetTLSLabel, OutContext); emitLEAzii(*OutStreamer, ci8, loImm2, RegS12, STI); emitANDrm(*OutStreamer, RegS12, M032, RegS12, STI); MCOperand hiImm2 = createGOTRelExprOp(VEMCExpr::VK_VE_PLT_HI32, GetTLSLabel, OutContext); emitLEASLrri(*OutStreamer, RegS12, RegLR, hiImm2, RegS12, STI); emitBSIC(*OutStreamer, RegLR, RegS12, STI); } void VEAsmPrinter::emitInstruction(const MachineInstr *MI) { VE_MC::verifyInstructionPredicates(MI->getOpcode(), getSubtargetInfo().getFeatureBits()); switch (MI->getOpcode()) { default: break; case TargetOpcode::DBG_VALUE: // FIXME: Debug Value. return; case VE::GETGOT: lowerGETGOTAndEmitMCInsts(MI, getSubtargetInfo()); return; case VE::GETFUNPLT: lowerGETFunPLTAndEmitMCInsts(MI, getSubtargetInfo()); return; case VE::GETTLSADDR: lowerGETTLSAddrAndEmitMCInsts(MI, getSubtargetInfo()); return; } MachineBasicBlock::const_instr_iterator I = MI->getIterator(); MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); do { MCInst TmpInst; LowerVEMachineInstrToMCInst(&*I, TmpInst, *this); EmitToStreamer(*OutStreamer, TmpInst); } while ((++I != E) && I->isInsideBundle()); // Delay slot check. } void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); break; case MachineOperand::MO_Immediate: O << (int)MO.getImm(); break; default: llvm_unreachable(""); } } // PrintAsmOperand - Print out an operand for an inline asm expression. bool VEAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) { if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. switch (ExtraCode[0]) { default: // See if this is a generic print operand return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O); case 'r': case 'v': break; } } printOperand(MI, OpNo, O); return false; } bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) { if (ExtraCode && ExtraCode[0]) return true; // Unknown modifier if (MI->getOperand(OpNo+1).isImm() && MI->getOperand(OpNo+1).getImm() == 0) { // don't print "+0" } else { printOperand(MI, OpNo+1, O); } if (MI->getOperand(OpNo).isImm() && MI->getOperand(OpNo).getImm() == 0) { if (MI->getOperand(OpNo+1).isImm() && MI->getOperand(OpNo+1).getImm() == 0) { O << "0"; } else { // don't print "(0)" } } else { O << "("; printOperand(MI, OpNo, O); O << ")"; } return false; } // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() { RegisterAsmPrinter X(getTheVETarget()); }