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