1 //===-- CSKYAsmPrinter.cpp - CSKY LLVM assembly writer --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a printer that converts from our internal representation 10 // of machine-dependent LLVM code to the CSKY assembly language. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "CSKYAsmPrinter.h" 14 #include "CSKY.h" 15 #include "CSKYConstantPoolValue.h" 16 #include "CSKYTargetMachine.h" 17 #include "MCTargetDesc/CSKYInstPrinter.h" 18 #include "MCTargetDesc/CSKYMCExpr.h" 19 #include "TargetInfo/CSKYTargetInfo.h" 20 #include "llvm/ADT/Statistic.h" 21 #include "llvm/CodeGen/AsmPrinter.h" 22 #include "llvm/CodeGen/MachineConstantPool.h" 23 #include "llvm/IR/DataLayout.h" 24 #include "llvm/MC/MCAsmInfo.h" 25 #include "llvm/MC/MCContext.h" 26 #include "llvm/MC/MCInstBuilder.h" 27 #include "llvm/MC/MCStreamer.h" 28 #include "llvm/MC/TargetRegistry.h" 29 30 using namespace llvm; 31 32 #define DEBUG_TYPE "csky-asm-printer" 33 34 STATISTIC(CSKYNumInstrsCompressed, 35 "Number of C-SKY Compressed instructions emitted"); 36 37 CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, 38 std::unique_ptr<llvm::MCStreamer> Streamer) 39 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} 40 41 bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 42 MCP = MF.getConstantPool(); 43 Subtarget = &MF.getSubtarget<CSKYSubtarget>(); 44 return AsmPrinter::runOnMachineFunction(MF); 45 } 46 47 #define GEN_COMPRESS_INSTR 48 #include "CSKYGenCompressInstEmitter.inc" 49 void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { 50 MCInst CInst; 51 bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext()); 52 if (Res) 53 ++CSKYNumInstrsCompressed; 54 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); 55 } 56 57 // Simple pseudo-instructions have their lowering (with expansion to real 58 // instructions) auto-generated. 59 #include "CSKYGenMCPseudoLowering.inc" 60 61 void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) { 62 const CSKYInstrInfo *TII = Subtarget->getInstrInfo(); 63 64 DebugLoc DL = MI->getDebugLoc(); 65 66 MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 67 Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + 68 "_" + Twine(MI->getOperand(3).getImm())); 69 70 OutStreamer->emitLabel(PCLabel); 71 72 auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32)) 73 .add(MI->getOperand(0)) 74 .add(MI->getOperand(2)); 75 MCInst LRWInst; 76 MCInstLowering.Lower(Instr, LRWInst); 77 EmitToStreamer(*OutStreamer, LRWInst); 78 79 Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32)) 80 .add(MI->getOperand(1)) 81 .addSym(PCLabel); 82 MCInst GRSInst; 83 MCInstLowering.Lower(Instr, GRSInst); 84 EmitToStreamer(*OutStreamer, GRSInst); 85 return; 86 } 87 88 void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) { 89 90 // This instruction represents a floating constant pool in the function. 91 // The first operand is the ID# for this instruction, the second is the 92 // index into the MachineConstantPool that this is, the third is the size 93 // in bytes of this constant pool entry. 94 // The required alignment is specified on the basic block holding this MI. 95 unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); 96 unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); 97 98 // If this is the first entry of the pool, mark it. 99 if (!InConstantPool) { 100 OutStreamer->emitValueToAlignment(4); 101 InConstantPool = true; 102 } 103 104 OutStreamer->emitLabel(GetCPISymbol(LabelId)); 105 106 const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; 107 if (MCPE.isMachineConstantPoolEntry()) 108 emitMachineConstantPoolValue(MCPE.Val.MachineCPVal); 109 else 110 emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); 111 return; 112 } 113 114 void CSKYAsmPrinter::emitFunctionBodyEnd() { 115 // Make sure to terminate any constant pools that were at the end 116 // of the function. 117 if (!InConstantPool) 118 return; 119 InConstantPool = false; 120 } 121 122 void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { 123 // Do any auto-generated pseudo lowerings. 124 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 125 return; 126 127 // If we just ended a constant pool, mark it as such. 128 if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { 129 InConstantPool = false; 130 } 131 132 if (MI->getOpcode() == CSKY::PseudoTLSLA32) 133 return expandTLSLA(MI); 134 135 if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) 136 return emitCustomConstantPool(MI); 137 138 MCInst TmpInst; 139 MCInstLowering.Lower(MI, TmpInst); 140 EmitToStreamer(*OutStreamer, TmpInst); 141 } 142 143 // Convert a CSKY-specific constant pool modifier into the associated 144 // MCSymbolRefExpr variant kind. 145 static CSKYMCExpr::VariantKind 146 getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { 147 switch (Modifier) { 148 case CSKYCP::NO_MOD: 149 return CSKYMCExpr::VK_CSKY_None; 150 case CSKYCP::ADDR: 151 return CSKYMCExpr::VK_CSKY_ADDR; 152 case CSKYCP::GOT: 153 return CSKYMCExpr::VK_CSKY_GOT; 154 case CSKYCP::GOTOFF: 155 return CSKYMCExpr::VK_CSKY_GOTOFF; 156 case CSKYCP::PLT: 157 return CSKYMCExpr::VK_CSKY_PLT; 158 case CSKYCP::TLSGD: 159 return CSKYMCExpr::VK_CSKY_TLSGD; 160 case CSKYCP::TLSLE: 161 return CSKYMCExpr::VK_CSKY_TLSLE; 162 case CSKYCP::TLSIE: 163 return CSKYMCExpr::VK_CSKY_TLSIE; 164 } 165 llvm_unreachable("Invalid CSKYCPModifier!"); 166 } 167 168 void CSKYAsmPrinter::emitMachineConstantPoolValue( 169 MachineConstantPoolValue *MCPV) { 170 int Size = getDataLayout().getTypeAllocSize(MCPV->getType()); 171 CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV); 172 MCSymbol *MCSym; 173 174 if (CCPV->isBlockAddress()) { 175 const BlockAddress *BA = 176 cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress(); 177 MCSym = GetBlockAddressSymbol(BA); 178 } else if (CCPV->isGlobalValue()) { 179 const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV(); 180 MCSym = getSymbol(GV); 181 } else if (CCPV->isMachineBasicBlock()) { 182 const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB(); 183 MCSym = MBB->getSymbol(); 184 } else if (CCPV->isJT()) { 185 signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI(); 186 MCSym = GetJTISymbol(JTI); 187 } else { 188 assert(CCPV->isExtSymbol() && "unrecognized constant pool value"); 189 StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol(); 190 MCSym = GetExternalSymbolSymbol(Sym); 191 } 192 // Create an MCSymbol for the reference. 193 const MCExpr *Expr = 194 MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext); 195 196 if (CCPV->getPCAdjustment()) { 197 198 MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 199 Twine(MAI->getPrivateGlobalPrefix()) + "PC" + 200 Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); 201 202 const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext); 203 if (CCPV->mustAddCurrentAddress()) { 204 // We want "(<expr> - .)", but MC doesn't have a concept of the '.' 205 // label, so just emit a local label end reference that instead. 206 MCSymbol *DotSym = OutContext.createTempSymbol(); 207 OutStreamer->emitLabel(DotSym); 208 const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext); 209 PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext); 210 } 211 Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext); 212 } 213 214 // Create an MCSymbol for the reference. 215 Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()), 216 OutContext); 217 218 OutStreamer->emitValue(Expr, Size); 219 } 220 221 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { 222 RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget()); 223 } 224