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); 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(Align(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 CSKY_MC::verifyInstructionPredicates(MI->getOpcode(), 145 getSubtargetInfo().getFeatureBits()); 146 147 // Do any auto-generated pseudo lowerings. 148 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 149 return; 150 151 // If we just ended a constant pool, mark it as such. 152 if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { 153 InConstantPool = false; 154 } 155 156 if (MI->getOpcode() == CSKY::PseudoTLSLA32) 157 return expandTLSLA(MI); 158 159 if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) 160 return emitCustomConstantPool(MI); 161 162 MCInst TmpInst; 163 MCInstLowering.Lower(MI, TmpInst); 164 EmitToStreamer(*OutStreamer, TmpInst); 165 } 166 167 // Convert a CSKY-specific constant pool modifier into the associated 168 // MCSymbolRefExpr variant kind. 169 static CSKYMCExpr::VariantKind 170 getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { 171 switch (Modifier) { 172 case CSKYCP::NO_MOD: 173 return CSKYMCExpr::VK_CSKY_None; 174 case CSKYCP::ADDR: 175 return CSKYMCExpr::VK_CSKY_ADDR; 176 case CSKYCP::GOT: 177 return CSKYMCExpr::VK_CSKY_GOT; 178 case CSKYCP::GOTOFF: 179 return CSKYMCExpr::VK_CSKY_GOTOFF; 180 case CSKYCP::PLT: 181 return CSKYMCExpr::VK_CSKY_PLT; 182 case CSKYCP::TLSGD: 183 return CSKYMCExpr::VK_CSKY_TLSGD; 184 case CSKYCP::TLSLE: 185 return CSKYMCExpr::VK_CSKY_TLSLE; 186 case CSKYCP::TLSIE: 187 return CSKYMCExpr::VK_CSKY_TLSIE; 188 } 189 llvm_unreachable("Invalid CSKYCPModifier!"); 190 } 191 192 void CSKYAsmPrinter::emitMachineConstantPoolValue( 193 MachineConstantPoolValue *MCPV) { 194 int Size = getDataLayout().getTypeAllocSize(MCPV->getType()); 195 CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV); 196 MCSymbol *MCSym; 197 198 if (CCPV->isBlockAddress()) { 199 const BlockAddress *BA = 200 cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress(); 201 MCSym = GetBlockAddressSymbol(BA); 202 } else if (CCPV->isGlobalValue()) { 203 const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV(); 204 MCSym = getSymbol(GV); 205 } else if (CCPV->isMachineBasicBlock()) { 206 const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB(); 207 MCSym = MBB->getSymbol(); 208 } else if (CCPV->isJT()) { 209 signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI(); 210 MCSym = GetJTISymbol(JTI); 211 } else if (CCPV->isConstPool()) { 212 const Constant *C = cast<CSKYConstantPoolConstant>(CCPV)->getConstantPool(); 213 MCSym = GetCPISymbol(MCP->getConstantPoolIndex(C, Align(4))); 214 } else { 215 assert(CCPV->isExtSymbol() && "unrecognized constant pool value"); 216 StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol(); 217 MCSym = GetExternalSymbolSymbol(Sym); 218 } 219 // Create an MCSymbol for the reference. 220 const MCExpr *Expr = 221 MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext); 222 223 if (CCPV->getPCAdjustment()) { 224 225 MCSymbol *PCLabel = OutContext.getOrCreateSymbol( 226 Twine(MAI->getPrivateGlobalPrefix()) + "PC" + 227 Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); 228 229 const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext); 230 if (CCPV->mustAddCurrentAddress()) { 231 // We want "(<expr> - .)", but MC doesn't have a concept of the '.' 232 // label, so just emit a local label end reference that instead. 233 MCSymbol *DotSym = OutContext.createTempSymbol(); 234 OutStreamer->emitLabel(DotSym); 235 const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext); 236 PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext); 237 } 238 Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext); 239 } 240 241 // Create an MCSymbol for the reference. 242 Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()), 243 OutContext); 244 245 OutStreamer->emitValue(Expr, Size); 246 } 247 248 void CSKYAsmPrinter::emitAttributes() { 249 CSKYTargetStreamer &CTS = 250 static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer()); 251 252 const Triple &TT = TM.getTargetTriple(); 253 StringRef CPU = TM.getTargetCPU(); 254 StringRef FS = TM.getTargetFeatureString(); 255 const CSKYTargetMachine &CTM = static_cast<const CSKYTargetMachine &>(TM); 256 /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only 257 care about arch related features, so we can set TuneCPU as CPU. */ 258 const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM); 259 260 CTS.emitTargetAttributes(STI); 261 } 262 263 bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 264 const char *ExtraCode, raw_ostream &OS) { 265 // First try the generic code, which knows about modifiers like 'c' and 'n'. 266 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) 267 return false; 268 269 const MachineOperand &MO = MI->getOperand(OpNo); 270 if (ExtraCode && ExtraCode[0]) { 271 if (ExtraCode[1] != 0) 272 return true; // Unknown modifier. 273 274 switch (ExtraCode[0]) { 275 default: 276 return true; // Unknown modifier. 277 case 'R': 278 if (MO.getType() == MachineOperand::MO_Register) { 279 OS << CSKYInstPrinter::getRegisterName(MO.getReg() + 1); 280 return false; 281 } 282 } 283 } 284 285 switch (MO.getType()) { 286 case MachineOperand::MO_Immediate: 287 OS << MO.getImm(); 288 return false; 289 case MachineOperand::MO_Register: 290 if (MO.getReg() == CSKY::C) 291 return false; 292 OS << CSKYInstPrinter::getRegisterName(MO.getReg()); 293 return false; 294 case MachineOperand::MO_GlobalAddress: 295 PrintSymbolOperand(MO, OS); 296 return false; 297 case MachineOperand::MO_BlockAddress: { 298 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); 299 Sym->print(OS, MAI); 300 return false; 301 } 302 default: 303 break; 304 } 305 306 return true; 307 } 308 309 bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 310 unsigned OpNo, const char *ExtraCode, 311 raw_ostream &OS) { 312 if (!ExtraCode) { 313 const MachineOperand &MO = MI->getOperand(OpNo); 314 // For now, we only support register memory operands in registers and 315 // assume there is no addend 316 if (!MO.isReg()) 317 return true; 318 319 OS << "(" << CSKYInstPrinter::getRegisterName(MO.getReg()) << ", 0)"; 320 return false; 321 } 322 323 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); 324 } 325 326 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { 327 RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget()); 328 } 329