//===-- CSKYAsmPrinter.cpp - CSKY 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 the CSKY assembly language. // //===----------------------------------------------------------------------===// #include "CSKYAsmPrinter.h" #include "CSKY.h" #include "CSKYConstantPoolValue.h" #include "CSKYTargetMachine.h" #include "MCTargetDesc/CSKYInstPrinter.h" #include "MCTargetDesc/CSKYMCExpr.h" #include "MCTargetDesc/CSKYTargetStreamer.h" #include "TargetInfo/CSKYTargetInfo.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/TargetRegistry.h" using namespace llvm; #define DEBUG_TYPE "csky-asm-printer" STATISTIC(CSKYNumInstrsCompressed, "Number of C-SKY Compressed instructions emitted"); CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { MCP = MF.getConstantPool(); TII = MF.getSubtarget().getInstrInfo(); // Set the current MCSubtargetInfo to a copy which has the correct // feature bits for the current MachineFunction MCSubtargetInfo &NewSTI = OutStreamer->getContext().getSubtargetCopy(*TM.getMCSubtargetInfo()); NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits()); Subtarget = &NewSTI; return AsmPrinter::runOnMachineFunction(MF); } #define GEN_COMPRESS_INSTR #include "CSKYGenCompressInstEmitter.inc" void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, *Subtarget); if (Res) ++CSKYNumInstrsCompressed; AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); } // Simple pseudo-instructions have their lowering (with expansion to real // instructions) auto-generated. #include "CSKYGenMCPseudoLowering.inc" void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) { DebugLoc DL = MI->getDebugLoc(); MCSymbol *PCLabel = OutContext.getOrCreateSymbol( Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + "_" + Twine(MI->getOperand(3).getImm())); OutStreamer->emitLabel(PCLabel); auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32)) .add(MI->getOperand(0)) .add(MI->getOperand(2)); MCInst LRWInst; MCInstLowering.Lower(Instr, LRWInst); EmitToStreamer(*OutStreamer, LRWInst); Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32)) .add(MI->getOperand(1)) .addSym(PCLabel); MCInst GRSInst; MCInstLowering.Lower(Instr, GRSInst); EmitToStreamer(*OutStreamer, GRSInst); return; } void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) { // This instruction represents a floating constant pool in the function. // The first operand is the ID# for this instruction, the second is the // index into the MachineConstantPool that this is, the third is the size // in bytes of this constant pool entry. // The required alignment is specified on the basic block holding this MI. unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); // If this is the first entry of the pool, mark it. if (!InConstantPool) { OutStreamer->emitValueToAlignment(Align(4)); InConstantPool = true; } OutStreamer->emitLabel(GetCPISymbol(LabelId)); const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; if (MCPE.isMachineConstantPoolEntry()) emitMachineConstantPoolValue(MCPE.Val.MachineCPVal); else emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); return; } void CSKYAsmPrinter::emitFunctionBodyEnd() { // Make sure to terminate any constant pools that were at the end // of the function. if (!InConstantPool) return; InConstantPool = false; } void CSKYAsmPrinter::emitStartOfAsmFile(Module &M) { if (TM.getTargetTriple().isOSBinFormatELF()) emitAttributes(); } void CSKYAsmPrinter::emitEndOfAsmFile(Module &M) { CSKYTargetStreamer &CTS = static_cast(*OutStreamer->getTargetStreamer()); if (TM.getTargetTriple().isOSBinFormatELF()) CTS.finishAttributeSection(); } void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { CSKY_MC::verifyInstructionPredicates(MI->getOpcode(), getSubtargetInfo().getFeatureBits()); // Do any auto-generated pseudo lowerings. if (emitPseudoExpansionLowering(*OutStreamer, MI)) return; // If we just ended a constant pool, mark it as such. if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { InConstantPool = false; } if (MI->getOpcode() == CSKY::PseudoTLSLA32) return expandTLSLA(MI); if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) return emitCustomConstantPool(MI); MCInst TmpInst; MCInstLowering.Lower(MI, TmpInst); EmitToStreamer(*OutStreamer, TmpInst); } // Convert a CSKY-specific constant pool modifier into the associated // MCSymbolRefExpr variant kind. static CSKYMCExpr::VariantKind getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { switch (Modifier) { case CSKYCP::NO_MOD: return CSKYMCExpr::VK_CSKY_None; case CSKYCP::ADDR: return CSKYMCExpr::VK_CSKY_ADDR; case CSKYCP::GOT: return CSKYMCExpr::VK_CSKY_GOT; case CSKYCP::GOTOFF: return CSKYMCExpr::VK_CSKY_GOTOFF; case CSKYCP::PLT: return CSKYMCExpr::VK_CSKY_PLT; case CSKYCP::TLSGD: return CSKYMCExpr::VK_CSKY_TLSGD; case CSKYCP::TLSLE: return CSKYMCExpr::VK_CSKY_TLSLE; case CSKYCP::TLSIE: return CSKYMCExpr::VK_CSKY_TLSIE; } llvm_unreachable("Invalid CSKYCPModifier!"); } void CSKYAsmPrinter::emitMachineConstantPoolValue( MachineConstantPoolValue *MCPV) { int Size = getDataLayout().getTypeAllocSize(MCPV->getType()); CSKYConstantPoolValue *CCPV = static_cast(MCPV); MCSymbol *MCSym; if (CCPV->isBlockAddress()) { const BlockAddress *BA = cast(CCPV)->getBlockAddress(); MCSym = GetBlockAddressSymbol(BA); } else if (CCPV->isGlobalValue()) { const GlobalValue *GV = cast(CCPV)->getGV(); MCSym = getSymbol(GV); } else if (CCPV->isMachineBasicBlock()) { const MachineBasicBlock *MBB = cast(CCPV)->getMBB(); MCSym = MBB->getSymbol(); } else if (CCPV->isJT()) { signed JTI = cast(CCPV)->getJTI(); MCSym = GetJTISymbol(JTI); } else if (CCPV->isConstPool()) { const Constant *C = cast(CCPV)->getConstantPool(); MCSym = GetCPISymbol(MCP->getConstantPoolIndex(C, Align(4))); } else { assert(CCPV->isExtSymbol() && "unrecognized constant pool value"); StringRef Sym = cast(CCPV)->getSymbol(); MCSym = GetExternalSymbolSymbol(Sym); } // Create an MCSymbol for the reference. const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext); if (CCPV->getPCAdjustment()) { MCSymbol *PCLabel = OutContext.getOrCreateSymbol( Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext); if (CCPV->mustAddCurrentAddress()) { // We want "( - .)", but MC doesn't have a concept of the '.' // label, so just emit a local label end reference that instead. MCSymbol *DotSym = OutContext.createTempSymbol(); OutStreamer->emitLabel(DotSym); const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext); PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext); } Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext); } // Create an MCSymbol for the reference. Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()), OutContext); OutStreamer->emitValue(Expr, Size); } void CSKYAsmPrinter::emitAttributes() { CSKYTargetStreamer &CTS = static_cast(*OutStreamer->getTargetStreamer()); const Triple &TT = TM.getTargetTriple(); StringRef CPU = TM.getTargetCPU(); StringRef FS = TM.getTargetFeatureString(); const CSKYTargetMachine &CTM = static_cast(TM); /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only care about arch related features, so we can set TuneCPU as CPU. */ const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM); CTS.emitTargetAttributes(STI); } bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) { // First try the generic code, which knows about modifiers like 'c' and 'n'. if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) return false; const MachineOperand &MO = MI->getOperand(OpNo); if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. switch (ExtraCode[0]) { default: return true; // Unknown modifier. case 'R': if (MO.getType() == MachineOperand::MO_Register) { OS << CSKYInstPrinter::getRegisterName(MO.getReg() + 1); return false; } } } switch (MO.getType()) { case MachineOperand::MO_Immediate: OS << MO.getImm(); return false; case MachineOperand::MO_Register: if (MO.getReg() == CSKY::C) return false; OS << CSKYInstPrinter::getRegisterName(MO.getReg()); return false; case MachineOperand::MO_GlobalAddress: PrintSymbolOperand(MO, OS); return false; case MachineOperand::MO_BlockAddress: { MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); Sym->print(OS, MAI); return false; } default: break; } return true; } bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) { if (!ExtraCode) { const MachineOperand &MO = MI->getOperand(OpNo); // For now, we only support register memory operands in registers and // assume there is no addend if (!MO.isReg()) return true; OS << "(" << CSKYInstPrinter::getRegisterName(MO.getReg()) << ", 0)"; return false; } return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); } extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { RegisterAsmPrinter X(getTheCSKYTarget()); }