1349cc55cSDimitry Andric //===-- CSKYAsmPrinter.cpp - CSKY LLVM assembly writer --------------------===// 2349cc55cSDimitry Andric // 3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6349cc55cSDimitry Andric // 7349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 8349cc55cSDimitry Andric // 9349cc55cSDimitry Andric // This file contains a printer that converts from our internal representation 10349cc55cSDimitry Andric // of machine-dependent LLVM code to the CSKY assembly language. 11349cc55cSDimitry Andric // 12349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 13349cc55cSDimitry Andric #include "CSKYAsmPrinter.h" 14349cc55cSDimitry Andric #include "CSKY.h" 15*04eeddc0SDimitry Andric #include "CSKYConstantPoolValue.h" 16349cc55cSDimitry Andric #include "CSKYTargetMachine.h" 17349cc55cSDimitry Andric #include "MCTargetDesc/CSKYInstPrinter.h" 18349cc55cSDimitry Andric #include "MCTargetDesc/CSKYMCExpr.h" 19349cc55cSDimitry Andric #include "TargetInfo/CSKYTargetInfo.h" 20349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h" 21349cc55cSDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 22349cc55cSDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 23349cc55cSDimitry Andric #include "llvm/IR/DataLayout.h" 24349cc55cSDimitry Andric #include "llvm/MC/MCAsmInfo.h" 25349cc55cSDimitry Andric #include "llvm/MC/MCContext.h" 26349cc55cSDimitry Andric #include "llvm/MC/MCInstBuilder.h" 27349cc55cSDimitry Andric #include "llvm/MC/MCStreamer.h" 28349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 29349cc55cSDimitry Andric 30349cc55cSDimitry Andric using namespace llvm; 31349cc55cSDimitry Andric 32349cc55cSDimitry Andric #define DEBUG_TYPE "csky-asm-printer" 33349cc55cSDimitry Andric 340eae32dcSDimitry Andric STATISTIC(CSKYNumInstrsCompressed, 350eae32dcSDimitry Andric "Number of C-SKY Compressed instructions emitted"); 360eae32dcSDimitry Andric 37349cc55cSDimitry Andric CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, 38349cc55cSDimitry Andric std::unique_ptr<llvm::MCStreamer> Streamer) 39349cc55cSDimitry Andric : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} 40349cc55cSDimitry Andric 41349cc55cSDimitry Andric bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 42*04eeddc0SDimitry Andric MCP = MF.getConstantPool(); 43349cc55cSDimitry Andric Subtarget = &MF.getSubtarget<CSKYSubtarget>(); 44349cc55cSDimitry Andric return AsmPrinter::runOnMachineFunction(MF); 45349cc55cSDimitry Andric } 46349cc55cSDimitry Andric 470eae32dcSDimitry Andric #define GEN_COMPRESS_INSTR 480eae32dcSDimitry Andric #include "CSKYGenCompressInstEmitter.inc" 490eae32dcSDimitry Andric void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { 500eae32dcSDimitry Andric MCInst CInst; 510eae32dcSDimitry Andric bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext()); 520eae32dcSDimitry Andric if (Res) 530eae32dcSDimitry Andric ++CSKYNumInstrsCompressed; 540eae32dcSDimitry Andric AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); 550eae32dcSDimitry Andric } 560eae32dcSDimitry Andric 57349cc55cSDimitry Andric // Simple pseudo-instructions have their lowering (with expansion to real 58349cc55cSDimitry Andric // instructions) auto-generated. 59349cc55cSDimitry Andric #include "CSKYGenMCPseudoLowering.inc" 60349cc55cSDimitry Andric 61*04eeddc0SDimitry Andric void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) { 62*04eeddc0SDimitry Andric const CSKYInstrInfo *TII = Subtarget->getInstrInfo(); 63*04eeddc0SDimitry Andric 64*04eeddc0SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 65*04eeddc0SDimitry Andric 66*04eeddc0SDimitry Andric MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 67*04eeddc0SDimitry Andric Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + 68*04eeddc0SDimitry Andric "_" + Twine(MI->getOperand(3).getImm())); 69*04eeddc0SDimitry Andric 70*04eeddc0SDimitry Andric OutStreamer->emitLabel(PCLabel); 71*04eeddc0SDimitry Andric 72*04eeddc0SDimitry Andric auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32)) 73*04eeddc0SDimitry Andric .add(MI->getOperand(0)) 74*04eeddc0SDimitry Andric .add(MI->getOperand(2)); 75*04eeddc0SDimitry Andric MCInst LRWInst; 76*04eeddc0SDimitry Andric MCInstLowering.Lower(Instr, LRWInst); 77*04eeddc0SDimitry Andric EmitToStreamer(*OutStreamer, LRWInst); 78*04eeddc0SDimitry Andric 79*04eeddc0SDimitry Andric Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32)) 80*04eeddc0SDimitry Andric .add(MI->getOperand(1)) 81*04eeddc0SDimitry Andric .addSym(PCLabel); 82*04eeddc0SDimitry Andric MCInst GRSInst; 83*04eeddc0SDimitry Andric MCInstLowering.Lower(Instr, GRSInst); 84*04eeddc0SDimitry Andric EmitToStreamer(*OutStreamer, GRSInst); 85*04eeddc0SDimitry Andric return; 86*04eeddc0SDimitry Andric } 87*04eeddc0SDimitry Andric 88*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) { 89*04eeddc0SDimitry Andric 90*04eeddc0SDimitry Andric // This instruction represents a floating constant pool in the function. 91*04eeddc0SDimitry Andric // The first operand is the ID# for this instruction, the second is the 92*04eeddc0SDimitry Andric // index into the MachineConstantPool that this is, the third is the size 93*04eeddc0SDimitry Andric // in bytes of this constant pool entry. 94*04eeddc0SDimitry Andric // The required alignment is specified on the basic block holding this MI. 95*04eeddc0SDimitry Andric unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); 96*04eeddc0SDimitry Andric unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); 97*04eeddc0SDimitry Andric 98*04eeddc0SDimitry Andric // If this is the first entry of the pool, mark it. 99*04eeddc0SDimitry Andric if (!InConstantPool) { 100*04eeddc0SDimitry Andric OutStreamer->emitValueToAlignment(4); 101*04eeddc0SDimitry Andric InConstantPool = true; 102*04eeddc0SDimitry Andric } 103*04eeddc0SDimitry Andric 104*04eeddc0SDimitry Andric OutStreamer->emitLabel(GetCPISymbol(LabelId)); 105*04eeddc0SDimitry Andric 106*04eeddc0SDimitry Andric const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; 107*04eeddc0SDimitry Andric if (MCPE.isMachineConstantPoolEntry()) 108*04eeddc0SDimitry Andric emitMachineConstantPoolValue(MCPE.Val.MachineCPVal); 109*04eeddc0SDimitry Andric else 110*04eeddc0SDimitry Andric emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); 111*04eeddc0SDimitry Andric return; 112*04eeddc0SDimitry Andric } 113*04eeddc0SDimitry Andric 114*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitFunctionBodyEnd() { 115*04eeddc0SDimitry Andric // Make sure to terminate any constant pools that were at the end 116*04eeddc0SDimitry Andric // of the function. 117*04eeddc0SDimitry Andric if (!InConstantPool) 118*04eeddc0SDimitry Andric return; 119*04eeddc0SDimitry Andric InConstantPool = false; 120*04eeddc0SDimitry Andric } 121*04eeddc0SDimitry Andric 122349cc55cSDimitry Andric void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { 123349cc55cSDimitry Andric // Do any auto-generated pseudo lowerings. 124349cc55cSDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, MI)) 125349cc55cSDimitry Andric return; 126349cc55cSDimitry Andric 127*04eeddc0SDimitry Andric // If we just ended a constant pool, mark it as such. 128*04eeddc0SDimitry Andric if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { 129*04eeddc0SDimitry Andric InConstantPool = false; 130*04eeddc0SDimitry Andric } 131*04eeddc0SDimitry Andric 132*04eeddc0SDimitry Andric if (MI->getOpcode() == CSKY::PseudoTLSLA32) 133*04eeddc0SDimitry Andric return expandTLSLA(MI); 134*04eeddc0SDimitry Andric 135*04eeddc0SDimitry Andric if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) 136*04eeddc0SDimitry Andric return emitCustomConstantPool(MI); 137*04eeddc0SDimitry Andric 138349cc55cSDimitry Andric MCInst TmpInst; 139349cc55cSDimitry Andric MCInstLowering.Lower(MI, TmpInst); 140349cc55cSDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 141349cc55cSDimitry Andric } 142349cc55cSDimitry Andric 143*04eeddc0SDimitry Andric // Convert a CSKY-specific constant pool modifier into the associated 144*04eeddc0SDimitry Andric // MCSymbolRefExpr variant kind. 145*04eeddc0SDimitry Andric static CSKYMCExpr::VariantKind 146*04eeddc0SDimitry Andric getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { 147*04eeddc0SDimitry Andric switch (Modifier) { 148*04eeddc0SDimitry Andric case CSKYCP::NO_MOD: 149*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_None; 150*04eeddc0SDimitry Andric case CSKYCP::ADDR: 151*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_ADDR; 152*04eeddc0SDimitry Andric case CSKYCP::GOT: 153*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_GOT; 154*04eeddc0SDimitry Andric case CSKYCP::GOTOFF: 155*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_GOTOFF; 156*04eeddc0SDimitry Andric case CSKYCP::PLT: 157*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_PLT; 158*04eeddc0SDimitry Andric case CSKYCP::TLSGD: 159*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_TLSGD; 160*04eeddc0SDimitry Andric case CSKYCP::TLSLE: 161*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_TLSLE; 162*04eeddc0SDimitry Andric case CSKYCP::TLSIE: 163*04eeddc0SDimitry Andric return CSKYMCExpr::VK_CSKY_TLSIE; 164*04eeddc0SDimitry Andric } 165*04eeddc0SDimitry Andric llvm_unreachable("Invalid CSKYCPModifier!"); 166*04eeddc0SDimitry Andric } 167*04eeddc0SDimitry Andric 168*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitMachineConstantPoolValue( 169*04eeddc0SDimitry Andric MachineConstantPoolValue *MCPV) { 170*04eeddc0SDimitry Andric int Size = getDataLayout().getTypeAllocSize(MCPV->getType()); 171*04eeddc0SDimitry Andric CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV); 172*04eeddc0SDimitry Andric MCSymbol *MCSym; 173*04eeddc0SDimitry Andric 174*04eeddc0SDimitry Andric if (CCPV->isBlockAddress()) { 175*04eeddc0SDimitry Andric const BlockAddress *BA = 176*04eeddc0SDimitry Andric cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress(); 177*04eeddc0SDimitry Andric MCSym = GetBlockAddressSymbol(BA); 178*04eeddc0SDimitry Andric } else if (CCPV->isGlobalValue()) { 179*04eeddc0SDimitry Andric const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV(); 180*04eeddc0SDimitry Andric MCSym = getSymbol(GV); 181*04eeddc0SDimitry Andric } else if (CCPV->isMachineBasicBlock()) { 182*04eeddc0SDimitry Andric const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB(); 183*04eeddc0SDimitry Andric MCSym = MBB->getSymbol(); 184*04eeddc0SDimitry Andric } else if (CCPV->isJT()) { 185*04eeddc0SDimitry Andric signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI(); 186*04eeddc0SDimitry Andric MCSym = GetJTISymbol(JTI); 187*04eeddc0SDimitry Andric } else { 188*04eeddc0SDimitry Andric assert(CCPV->isExtSymbol() && "unrecognized constant pool value"); 189*04eeddc0SDimitry Andric StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol(); 190*04eeddc0SDimitry Andric MCSym = GetExternalSymbolSymbol(Sym); 191*04eeddc0SDimitry Andric } 192*04eeddc0SDimitry Andric // Create an MCSymbol for the reference. 193*04eeddc0SDimitry Andric const MCExpr *Expr = 194*04eeddc0SDimitry Andric MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext); 195*04eeddc0SDimitry Andric 196*04eeddc0SDimitry Andric if (CCPV->getPCAdjustment()) { 197*04eeddc0SDimitry Andric 198*04eeddc0SDimitry Andric MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 199*04eeddc0SDimitry Andric Twine(MAI->getPrivateGlobalPrefix()) + "PC" + 200*04eeddc0SDimitry Andric Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); 201*04eeddc0SDimitry Andric 202*04eeddc0SDimitry Andric const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext); 203*04eeddc0SDimitry Andric if (CCPV->mustAddCurrentAddress()) { 204*04eeddc0SDimitry Andric // We want "(<expr> - .)", but MC doesn't have a concept of the '.' 205*04eeddc0SDimitry Andric // label, so just emit a local label end reference that instead. 206*04eeddc0SDimitry Andric MCSymbol *DotSym = OutContext.createTempSymbol(); 207*04eeddc0SDimitry Andric OutStreamer->emitLabel(DotSym); 208*04eeddc0SDimitry Andric const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext); 209*04eeddc0SDimitry Andric PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext); 210*04eeddc0SDimitry Andric } 211*04eeddc0SDimitry Andric Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext); 212*04eeddc0SDimitry Andric } 213*04eeddc0SDimitry Andric 214*04eeddc0SDimitry Andric // Create an MCSymbol for the reference. 215*04eeddc0SDimitry Andric Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()), 216*04eeddc0SDimitry Andric OutContext); 217*04eeddc0SDimitry Andric 218*04eeddc0SDimitry Andric OutStreamer->emitValue(Expr, Size); 219*04eeddc0SDimitry Andric } 220*04eeddc0SDimitry Andric 221349cc55cSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { 222349cc55cSDimitry Andric RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget()); 223349cc55cSDimitry Andric } 224