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