250 lines · cpp
1//===-- LanaiAsmPrinter.cpp - Lanai 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a printer that converts from our internal representation10// of machine-dependent LLVM code to the Lanai assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "LanaiAluCode.h"15#include "LanaiCondCode.h"16#include "LanaiMCInstLower.h"17#include "LanaiTargetMachine.h"18#include "MCTargetDesc/LanaiInstPrinter.h"19#include "TargetInfo/LanaiTargetInfo.h"20#include "llvm/CodeGen/AsmPrinter.h"21#include "llvm/CodeGen/MachineConstantPool.h"22#include "llvm/CodeGen/MachineInstr.h"23#include "llvm/IR/Mangler.h"24#include "llvm/MC/MCAsmInfo.h"25#include "llvm/MC/MCInst.h"26#include "llvm/MC/MCInstBuilder.h"27#include "llvm/MC/MCStreamer.h"28#include "llvm/MC/MCSymbol.h"29#include "llvm/MC/TargetRegistry.h"30#include "llvm/Support/Compiler.h"31#include "llvm/Support/raw_ostream.h"32 33#define DEBUG_TYPE "asm-printer"34 35using namespace llvm;36 37namespace {38class LanaiAsmPrinter : public AsmPrinter {39public:40 explicit LanaiAsmPrinter(TargetMachine &TM,41 std::unique_ptr<MCStreamer> Streamer)42 : AsmPrinter(TM, std::move(Streamer), ID) {}43 44 StringRef getPassName() const override { return "Lanai Assembly Printer"; }45 46 void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);47 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,48 const char *ExtraCode, raw_ostream &O) override;49 void emitInstruction(const MachineInstr *MI) override;50 bool isBlockOnlyReachableByFallthrough(51 const MachineBasicBlock *MBB) const override;52 53private:54 void customEmitInstruction(const MachineInstr *MI);55 void emitCallInstruction(const MachineInstr *MI);56 57public:58 static char ID;59};60} // end of anonymous namespace61 62void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,63 raw_ostream &O) {64 const MachineOperand &MO = MI->getOperand(OpNum);65 66 switch (MO.getType()) {67 case MachineOperand::MO_Register:68 O << LanaiInstPrinter::getRegisterName(MO.getReg());69 break;70 71 case MachineOperand::MO_Immediate:72 O << MO.getImm();73 break;74 75 case MachineOperand::MO_MachineBasicBlock:76 O << *MO.getMBB()->getSymbol();77 break;78 79 case MachineOperand::MO_GlobalAddress:80 O << *getSymbol(MO.getGlobal());81 break;82 83 case MachineOperand::MO_BlockAddress: {84 MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());85 O << BA->getName();86 break;87 }88 89 case MachineOperand::MO_ExternalSymbol:90 O << *GetExternalSymbolSymbol(MO.getSymbolName());91 break;92 93 case MachineOperand::MO_JumpTableIndex:94 O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'95 << MO.getIndex();96 break;97 98 case MachineOperand::MO_ConstantPoolIndex:99 O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'100 << MO.getIndex();101 return;102 103 default:104 llvm_unreachable("<unknown operand type>");105 }106}107 108// PrintAsmOperand - Print out an operand for an inline asm expression.109bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,110 const char *ExtraCode, raw_ostream &O) {111 // Does this asm operand have a single letter operand modifier?112 if (ExtraCode && ExtraCode[0]) {113 if (ExtraCode[1])114 return true; // Unknown modifier.115 116 switch (ExtraCode[0]) {117 // The highest-numbered register of a pair.118 case 'H': {119 if (OpNo == 0)120 return true;121 const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);122 if (!FlagsOP.isImm())123 return true;124 const InlineAsm::Flag Flags(FlagsOP.getImm());125 const unsigned NumVals = Flags.getNumOperandRegisters();126 if (NumVals != 2)127 return true;128 unsigned RegOp = OpNo + 1;129 if (RegOp >= MI->getNumOperands())130 return true;131 const MachineOperand &MO = MI->getOperand(RegOp);132 if (!MO.isReg())133 return true;134 Register Reg = MO.getReg();135 O << LanaiInstPrinter::getRegisterName(Reg);136 return false;137 }138 default:139 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);140 }141 }142 printOperand(MI, OpNo, O);143 return false;144}145 146//===----------------------------------------------------------------------===//147void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {148 assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&149 "Unsupported call function");150 151 LanaiMCInstLower MCInstLowering(OutContext, *this);152 MCSubtargetInfo STI = getSubtargetInfo();153 // Insert save rca instruction immediately before the call.154 // TODO: We should generate a pc-relative mov instruction here instead155 // of pc + 16 (should be mov .+16 %rca).156 OutStreamer->emitInstruction(MCInstBuilder(Lanai::ADD_I_LO)157 .addReg(Lanai::RCA)158 .addReg(Lanai::PC)159 .addImm(16),160 STI);161 162 // Push rca onto the stack.163 // st %rca, [--%sp]164 OutStreamer->emitInstruction(MCInstBuilder(Lanai::SW_RI)165 .addReg(Lanai::RCA)166 .addReg(Lanai::SP)167 .addImm(-4)168 .addImm(LPAC::makePreOp(LPAC::ADD)),169 STI);170 171 // Lower the call instruction.172 if (MI->getOpcode() == Lanai::CALL) {173 MCInst TmpInst;174 MCInstLowering.Lower(MI, TmpInst);175 TmpInst.setOpcode(Lanai::BT);176 OutStreamer->emitInstruction(TmpInst, STI);177 } else {178 OutStreamer->emitInstruction(MCInstBuilder(Lanai::ADD_R)179 .addReg(Lanai::PC)180 .addReg(MI->getOperand(0).getReg())181 .addReg(Lanai::R0)182 .addImm(LPCC::ICC_T),183 STI);184 }185}186 187void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {188 LanaiMCInstLower MCInstLowering(OutContext, *this);189 MCSubtargetInfo STI = getSubtargetInfo();190 MCInst TmpInst;191 MCInstLowering.Lower(MI, TmpInst);192 OutStreamer->emitInstruction(TmpInst, STI);193}194 195void LanaiAsmPrinter::emitInstruction(const MachineInstr *MI) {196 Lanai_MC::verifyInstructionPredicates(MI->getOpcode(),197 getSubtargetInfo().getFeatureBits());198 199 MachineBasicBlock::const_instr_iterator I = MI->getIterator();200 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();201 202 do {203 if (I->isCall()) {204 emitCallInstruction(&*I);205 continue;206 }207 208 customEmitInstruction(&*I);209 } while ((++I != E) && I->isInsideBundle());210}211 212// isBlockOnlyReachableByFallthough - Return true if the basic block has213// exactly one predecessor and the control transfer mechanism between214// the predecessor and this block is a fall-through.215// FIXME: could the overridden cases be handled in analyzeBranch?216bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(217 const MachineBasicBlock *MBB) const {218 // The predecessor has to be immediately before this block.219 const MachineBasicBlock *Pred = *MBB->pred_begin();220 221 // If the predecessor is a switch statement, assume a jump table222 // implementation, so it is not a fall through.223 if (const BasicBlock *B = Pred->getBasicBlock())224 if (isa<SwitchInst>(B->getTerminator()))225 return false;226 227 // Check default implementation228 if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))229 return false;230 231 // Otherwise, check the last instruction.232 // Check if the last terminator is an unconditional branch.233 MachineBasicBlock::const_iterator I = Pred->end();234 while (I != Pred->begin() && !(--I)->isTerminator()) {235 }236 237 return !I->isBarrier();238}239 240char LanaiAsmPrinter::ID = 0;241 242INITIALIZE_PASS(LanaiAsmPrinter, "lanai-asm-printer", "Lanai Assembly Printer",243 false, false)244 245// Force static initialization.246extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void247LLVMInitializeLanaiAsmPrinter() {248 RegisterAsmPrinter<LanaiAsmPrinter> X(getTheLanaiTarget());249}250