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