318 lines · cpp
1//===- LoongArchAsmPrinter.cpp - LoongArch LLVM Assembly Printer -*- C++ -*--=//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a printer that converts from our internal representation10// of machine-dependent LLVM code to GAS-format LoongArch assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "LoongArchAsmPrinter.h"15#include "LoongArch.h"16#include "LoongArchMachineFunctionInfo.h"17#include "MCTargetDesc/LoongArchInstPrinter.h"18#include "MCTargetDesc/LoongArchMCTargetDesc.h"19#include "TargetInfo/LoongArchTargetInfo.h"20#include "llvm/CodeGen/AsmPrinter.h"21#include "llvm/CodeGen/MachineJumpTableInfo.h"22#include "llvm/CodeGen/MachineModuleInfoImpls.h"23#include "llvm/MC/MCAsmInfo.h"24#include "llvm/MC/MCContext.h"25#include "llvm/MC/MCInstBuilder.h"26#include "llvm/MC/MCSectionELF.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Support/Compiler.h"29 30using namespace llvm;31 32#define DEBUG_TYPE "loongarch-asm-printer"33 34cl::opt<bool> LArchAnnotateTableJump(35 "loongarch-annotate-tablejump", cl::Hidden,36 cl::desc(37 "Annotate table jump instruction to correlate it with the jump table."),38 cl::init(false));39 40// Simple pseudo-instructions have their lowering (with expansion to real41// instructions) auto-generated.42#include "LoongArchGenMCPseudoLowering.inc"43 44void LoongArchAsmPrinter::emitInstruction(const MachineInstr *MI) {45 LoongArch_MC::verifyInstructionPredicates(46 MI->getOpcode(), getSubtargetInfo().getFeatureBits());47 48 // Do any auto-generated pseudo lowerings.49 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {50 EmitToStreamer(*OutStreamer, OutInst);51 return;52 }53 54 switch (MI->getOpcode()) {55 case TargetOpcode::STATEPOINT:56 LowerSTATEPOINT(*MI);57 return;58 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:59 LowerPATCHABLE_FUNCTION_ENTER(*MI);60 return;61 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:62 LowerPATCHABLE_FUNCTION_EXIT(*MI);63 return;64 case TargetOpcode::PATCHABLE_TAIL_CALL:65 LowerPATCHABLE_TAIL_CALL(*MI);66 return;67 }68 69 MCInst TmpInst;70 if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this))71 EmitToStreamer(*OutStreamer, TmpInst);72}73 74bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,75 const char *ExtraCode,76 raw_ostream &OS) {77 // First try the generic code, which knows about modifiers like 'c' and 'n'.78 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))79 return false;80 81 const MachineOperand &MO = MI->getOperand(OpNo);82 if (ExtraCode && ExtraCode[0]) {83 if (ExtraCode[1] != 0)84 return true; // Unknown modifier.85 86 switch (ExtraCode[0]) {87 default:88 return true; // Unknown modifier.89 case 'z': // Print $zero register if zero, regular printing otherwise.90 if (MO.isImm() && MO.getImm() == 0) {91 OS << '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0);92 return false;93 }94 break;95 case 'u': // Print LASX registers.96 case 'w': // Print LSX registers.97 {98 // If the operand is an LASX, LSX or floating point register, print the99 // name of LASX or LSX register with the same index in that register100 // class.101 unsigned RegID = MO.getReg().id(), FirstReg;102 if (RegID >= LoongArch::XR0 && RegID <= LoongArch::XR31)103 FirstReg = LoongArch::XR0;104 else if (RegID >= LoongArch::VR0 && RegID <= LoongArch::VR31)105 FirstReg = LoongArch::VR0;106 else if (RegID >= LoongArch::F0_64 && RegID <= LoongArch::F31_64)107 FirstReg = LoongArch::F0_64;108 else if (RegID >= LoongArch::F0 && RegID <= LoongArch::F31)109 FirstReg = LoongArch::F0;110 else111 return true;112 OS << '$'113 << LoongArchInstPrinter::getRegisterName(114 RegID - FirstReg +115 (ExtraCode[0] == 'u' ? LoongArch::XR0 : LoongArch::VR0));116 return false;117 }118 // TODO: handle other extra codes if any.119 }120 }121 122 switch (MO.getType()) {123 case MachineOperand::MO_Immediate:124 OS << MO.getImm();125 return false;126 case MachineOperand::MO_Register:127 OS << '$' << LoongArchInstPrinter::getRegisterName(MO.getReg());128 return false;129 case MachineOperand::MO_GlobalAddress:130 PrintSymbolOperand(MO, OS);131 return false;132 default:133 llvm_unreachable("not implemented");134 }135 136 return true;137}138 139bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,140 unsigned OpNo,141 const char *ExtraCode,142 raw_ostream &OS) {143 // TODO: handle extra code.144 if (ExtraCode)145 return true;146 147 // We only support memory operands like "Base + Offset", where base must be a148 // register, and offset can be a register or an immediate value.149 const MachineOperand &BaseMO = MI->getOperand(OpNo);150 // Base address must be a register.151 if (!BaseMO.isReg())152 return true;153 // Print the base address register.154 OS << "$" << LoongArchInstPrinter::getRegisterName(BaseMO.getReg());155 // Print the offset operand.156 const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);157 MCOperand MCO;158 if (!lowerOperand(OffsetMO, MCO))159 return true;160 if (OffsetMO.isReg())161 OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());162 else if (OffsetMO.isImm())163 OS << ", " << OffsetMO.getImm();164 else if (OffsetMO.isGlobal() || OffsetMO.isBlockAddress() ||165 OffsetMO.isMCSymbol() || OffsetMO.isCPI()) {166 OS << ", ";167 MAI->printExpr(OS, *MCO.getExpr());168 } else169 return true;170 171 return false;172}173 174void LoongArchAsmPrinter::LowerSTATEPOINT(const MachineInstr &MI) {175 StatepointOpers SOpers(&MI);176 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {177 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");178 emitNops(PatchBytes / 4);179 } else {180 // Lower call target and choose correct opcode.181 const MachineOperand &CallTarget = SOpers.getCallTarget();182 MCOperand CallTargetMCOp;183 switch (CallTarget.getType()) {184 case MachineOperand::MO_GlobalAddress:185 case MachineOperand::MO_ExternalSymbol:186 lowerOperand(CallTarget, CallTargetMCOp);187 EmitToStreamer(*OutStreamer,188 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));189 break;190 case MachineOperand::MO_Immediate:191 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());192 EmitToStreamer(*OutStreamer,193 MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));194 break;195 case MachineOperand::MO_Register:196 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());197 EmitToStreamer(*OutStreamer, MCInstBuilder(LoongArch::JIRL)198 .addReg(LoongArch::R1)199 .addOperand(CallTargetMCOp)200 .addImm(0));201 break;202 default:203 llvm_unreachable("Unsupported operand type in statepoint call target");204 break;205 }206 }207 208 auto &Ctx = OutStreamer->getContext();209 MCSymbol *MILabel = Ctx.createTempSymbol();210 OutStreamer->emitLabel(MILabel);211 SM.recordStatepoint(*MILabel, MI);212}213 214void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(215 const MachineInstr &MI) {216 const Function &F = MF->getFunction();217 if (F.hasFnAttribute("patchable-function-entry")) {218 unsigned Num;219 if (F.getFnAttribute("patchable-function-entry")220 .getValueAsString()221 .getAsInteger(10, Num))222 return;223 emitNops(Num);224 return;225 }226 227 emitSled(MI, SledKind::FUNCTION_ENTER);228}229 230void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {231 emitSled(MI, SledKind::FUNCTION_EXIT);232}233 234void LoongArchAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {235 emitSled(MI, SledKind::TAIL_CALL);236}237 238void LoongArchAsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {239 // For loongarch64 we want to emit the following pattern:240 //241 // .Lxray_sled_beginN:242 // B .Lxray_sled_endN243 // 11 NOPs (44 bytes)244 // .Lxray_sled_endN:245 //246 // We need the extra bytes because at runtime they may be used for the247 // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.248 // The count here should be adjusted accordingly if the implementation249 // changes.250 const int8_t NoopsInSledCount = 11;251 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());252 MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_begin");253 MCSymbol *EndOfSled = OutContext.createTempSymbol("xray_sled_end");254 OutStreamer->emitLabel(BeginOfSled);255 EmitToStreamer(*OutStreamer,256 MCInstBuilder(LoongArch::B)257 .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));258 emitNops(NoopsInSledCount);259 OutStreamer->emitLabel(EndOfSled);260 recordSled(BeginOfSled, MI, Kind, 2);261}262 263void LoongArchAsmPrinter::emitJumpTableInfo() {264 AsmPrinter::emitJumpTableInfo();265 266 if (!LArchAnnotateTableJump)267 return;268 269 assert(TM.getTargetTriple().isOSBinFormatELF());270 271 auto *LAFI = MF->getInfo<LoongArchMachineFunctionInfo>();272 unsigned EntrySize = LAFI->getJumpInfoSize();273 auto JTI = MF->getJumpTableInfo();274 275 if (!JTI || 0 == EntrySize)276 return;277 278 unsigned Size = getDataLayout().getPointerSize();279 auto JT = JTI->getJumpTables();280 281 // Emit an additional section to store the correlation info as pairs of282 // addresses, each pair contains the address of a jump instruction (jr) and283 // the address of the jump table.284 OutStreamer->switchSection(MMI->getContext().getELFSection(285 ".discard.tablejump_annotate", ELF::SHT_PROGBITS, 0));286 287 for (unsigned Idx = 0; Idx < EntrySize; ++Idx) {288 int JTIIdx = LAFI->getJumpInfoJTIIndex(Idx);289 if (JT[JTIIdx].MBBs.empty())290 continue;291 OutStreamer->emitValue(292 MCSymbolRefExpr::create(LAFI->getJumpInfoJrMI(Idx)->getPreInstrSymbol(),293 OutContext),294 Size);295 OutStreamer->emitValue(296 MCSymbolRefExpr::create(GetJTISymbol(JTIIdx), OutContext), Size);297 }298}299 300bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {301 AsmPrinter::runOnMachineFunction(MF);302 // Emit the XRay table for this function.303 emitXRayTable();304 return true;305}306 307char LoongArchAsmPrinter::ID = 0;308 309INITIALIZE_PASS(LoongArchAsmPrinter, "loongarch-asm-printer",310 "LoongArch Assembly Printer", false, false)311 312// Force static initialization.313extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void314LLVMInitializeLoongArchAsmPrinter() {315 RegisterAsmPrinter<LoongArchAsmPrinter> X(getTheLoongArch32Target());316 RegisterAsmPrinter<LoongArchAsmPrinter> Y(getTheLoongArch64Target());317}318