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 "MCTargetDesc/CSKYTargetStreamer.h" 20 #include "TargetInfo/CSKYTargetInfo.h" 21 #include "llvm/ADT/Statistic.h" 22 #include "llvm/CodeGen/AsmPrinter.h" 23 #include "llvm/CodeGen/MachineConstantPool.h" 24 #include "llvm/IR/DataLayout.h" 25 #include "llvm/MC/MCAsmInfo.h" 26 #include "llvm/MC/MCContext.h" 27 #include "llvm/MC/MCInstBuilder.h" 28 #include "llvm/MC/MCStreamer.h" 29 #include "llvm/MC/TargetRegistry.h" 30 31 using namespace llvm; 32 33 #define DEBUG_TYPE "csky-asm-printer" 34 35 STATISTIC(CSKYNumInstrsCompressed, 36 "Number of C-SKY Compressed instructions emitted"); 37 38 CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, 39 std::unique_ptr<llvm::MCStreamer> Streamer) 40 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} 41 42 bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 43 MCP = MF.getConstantPool(); 44 TII = MF.getSubtarget().getInstrInfo(); 45 46 // Set the current MCSubtargetInfo to a copy which has the correct 47 // feature bits for the current MachineFunction 48 MCSubtargetInfo &NewSTI = 49 OutStreamer->getContext().getSubtargetCopy(*TM.getMCSubtargetInfo()); 50 NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits()); 51 Subtarget = &NewSTI; 52 53 return AsmPrinter::runOnMachineFunction(MF); 54 } 55 56 #define GEN_COMPRESS_INSTR 57 #include "CSKYGenCompressInstEmitter.inc" 58 void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { 59 MCInst CInst; 60 bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext()); 61 if (Res) 62 ++CSKYNumInstrsCompressed; 63 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst); 64 } 65 66 // Simple pseudo-instructions have their lowering (with expansion to real 67 // instructions) auto-generated. 68 #include "CSKYGenMCPseudoLowering.inc" 69 70 void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) { 71 DebugLoc DL = MI->getDebugLoc(); 72 73 MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 74 Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + 75 "_" + Twine(MI->getOperand(3).getImm())); 76 77 OutStreamer->emitLabel(PCLabel); 78 79 auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32)) 80 .add(MI->getOperand(0)) 81 .add(MI->getOperand(2)); 82 MCInst LRWInst; 83 MCInstLowering.Lower(Instr, LRWInst); 84 EmitToStreamer(*OutStreamer, LRWInst); 85 86 Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32)) 87 .add(MI->getOperand(1)) 88 .addSym(PCLabel); 89 MCInst GRSInst; 90 MCInstLowering.Lower(Instr, GRSInst); 91 EmitToStreamer(*OutStreamer, GRSInst); 92 return; 93 } 94 95 void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) { 96 97 // This instruction represents a floating constant pool in the function. 98 // The first operand is the ID# for this instruction, the second is the 99 // index into the MachineConstantPool that this is, the third is the size 100 // in bytes of this constant pool entry. 101 // The required alignment is specified on the basic block holding this MI. 102 unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); 103 unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); 104 105 // If this is the first entry of the pool, mark it. 106 if (!InConstantPool) { 107 OutStreamer->emitValueToAlignment(4); 108 InConstantPool = true; 109 } 110 111 OutStreamer->emitLabel(GetCPISymbol(LabelId)); 112 113 const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; 114 if (MCPE.isMachineConstantPoolEntry()) 115 emitMachineConstantPoolValue(MCPE.Val.MachineCPVal); 116 else 117 emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); 118 return; 119 } 120 121 void CSKYAsmPrinter::emitFunctionBodyEnd() { 122 // Make sure to terminate any constant pools that were at the end 123 // of the function. 124 if (!InConstantPool) 125 return; 126 InConstantPool = false; 127 } 128 129 void CSKYAsmPrinter::emitStartOfAsmFile(Module &M) { 130 if (TM.getTargetTriple().isOSBinFormatELF()) 131 emitAttributes(); 132 } 133 134 void CSKYAsmPrinter::emitEndOfAsmFile(Module &M) { 135 CSKYTargetStreamer &CTS = 136 static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer()); 137 138 if (TM.getTargetTriple().isOSBinFormatELF()) 139 CTS.finishAttributeSection(); 140 } 141 142 void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { 143 // Do any auto-generated pseudo lowerings. 144 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 145 return; 146 147 // If we just ended a constant pool, mark it as such. 148 if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { 149 InConstantPool = false; 150 } 151 152 if (MI->getOpcode() == CSKY::PseudoTLSLA32) 153 return expandTLSLA(MI); 154 155 if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) 156 return emitCustomConstantPool(MI); 157 158 MCInst TmpInst; 159 MCInstLowering.Lower(MI, TmpInst); 160 EmitToStreamer(*OutStreamer, TmpInst); 161 } 162 163 // Convert a CSKY-specific constant pool modifier into the associated 164 // MCSymbolRefExpr variant kind. 165 static CSKYMCExpr::VariantKind 166 getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { 167 switch (Modifier) { 168 case CSKYCP::NO_MOD: 169 return CSKYMCExpr::VK_CSKY_None; 170 case CSKYCP::ADDR: 171 return CSKYMCExpr::VK_CSKY_ADDR; 172 case CSKYCP::GOT: 173 return CSKYMCExpr::VK_CSKY_GOT; 174 case CSKYCP::GOTOFF: 175 return CSKYMCExpr::VK_CSKY_GOTOFF; 176 case CSKYCP::PLT: 177 return CSKYMCExpr::VK_CSKY_PLT; 178 case CSKYCP::TLSGD: 179 return CSKYMCExpr::VK_CSKY_TLSGD; 180 case CSKYCP::TLSLE: 181 return CSKYMCExpr::VK_CSKY_TLSLE; 182 case CSKYCP::TLSIE: 183 return CSKYMCExpr::VK_CSKY_TLSIE; 184 } 185 llvm_unreachable("Invalid CSKYCPModifier!"); 186 } 187 188 void CSKYAsmPrinter::emitMachineConstantPoolValue( 189 MachineConstantPoolValue *MCPV) { 190 int Size = getDataLayout().getTypeAllocSize(MCPV->getType()); 191 CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV); 192 MCSymbol *MCSym; 193 194 if (CCPV->isBlockAddress()) { 195 const BlockAddress *BA = 196 cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress(); 197 MCSym = GetBlockAddressSymbol(BA); 198 } else if (CCPV->isGlobalValue()) { 199 const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV(); 200 MCSym = getSymbol(GV); 201 } else if (CCPV->isMachineBasicBlock()) { 202 const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB(); 203 MCSym = MBB->getSymbol(); 204 } else if (CCPV->isJT()) { 205 signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI(); 206 MCSym = GetJTISymbol(JTI); 207 } else { 208 assert(CCPV->isExtSymbol() && "unrecognized constant pool value"); 209 StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol(); 210 MCSym = GetExternalSymbolSymbol(Sym); 211 } 212 // Create an MCSymbol for the reference. 213 const MCExpr *Expr = 214 MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext); 215 216 if (CCPV->getPCAdjustment()) { 217 218 MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 219 Twine(MAI->getPrivateGlobalPrefix()) + "PC" + 220 Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); 221 222 const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext); 223 if (CCPV->mustAddCurrentAddress()) { 224 // We want "(<expr> - .)", but MC doesn't have a concept of the '.' 225 // label, so just emit a local label end reference that instead. 226 MCSymbol *DotSym = OutContext.createTempSymbol(); 227 OutStreamer->emitLabel(DotSym); 228 const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext); 229 PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext); 230 } 231 Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext); 232 } 233 234 // Create an MCSymbol for the reference. 235 Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()), 236 OutContext); 237 238 OutStreamer->emitValue(Expr, Size); 239 } 240 241 void CSKYAsmPrinter::emitAttributes() { 242 CSKYTargetStreamer &CTS = 243 static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer()); 244 245 const Triple &TT = TM.getTargetTriple(); 246 StringRef CPU = TM.getTargetCPU(); 247 StringRef FS = TM.getTargetFeatureString(); 248 const CSKYTargetMachine &CTM = static_cast<const CSKYTargetMachine &>(TM); 249 /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only 250 care about arch related features, so we can set TuneCPU as CPU. */ 251 const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM); 252 253 CTS.emitTargetAttributes(STI); 254 } 255 256 bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 257 const char *ExtraCode, raw_ostream &OS) { 258 // First try the generic code, which knows about modifiers like 'c' and 'n'. 259 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 260 return false; 261 262 const MachineOperand &MO = MI->getOperand(OpNo); 263 if (ExtraCode && ExtraCode[0]) { 264 if (ExtraCode[1] != 0) 265 return true; // Unknown modifier. 266 267 switch (ExtraCode[0]) { 268 default: 269 return true; // Unknown modifier. 270 case 'R': 271 if (MO.getType() == MachineOperand::MO_Register) { 272 OS << CSKYInstPrinter::getRegisterName(MO.getReg() + 1); 273 return false; 274 } 275 } 276 } 277 278 switch (MO.getType()) { 279 case MachineOperand::MO_Immediate: 280 OS << MO.getImm(); 281 return false; 282 case MachineOperand::MO_Register: 283 if (MO.getReg() == CSKY::C) 284 return false; 285 OS << CSKYInstPrinter::getRegisterName(MO.getReg()); 286 return false; 287 case MachineOperand::MO_GlobalAddress: 288 PrintSymbolOperand(MO, OS); 289 return false; 290 case MachineOperand::MO_BlockAddress: { 291 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); 292 Sym->print(OS, MAI); 293 return false; 294 } 295 default: 296 break; 297 } 298 299 return true; 300 } 301 302 bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 303 unsigned OpNo, const char *ExtraCode, 304 raw_ostream &OS) { 305 if (!ExtraCode) { 306 const MachineOperand &MO = MI->getOperand(OpNo); 307 // For now, we only support register memory operands in registers and 308 // assume there is no addend 309 if (!MO.isReg()) 310 return true; 311 312 OS << "(" << CSKYInstPrinter::getRegisterName(MO.getReg()) << ", 0)"; 313 return false; 314 } 315 316 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 317 } 318 319 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { 320 RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget()); 321 } 322