xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Lanai/LanaiAsmPrinter.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric //===-- LanaiAsmPrinter.cpp - Lanai LLVM assembly writer ------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a printer that converts from our internal representation
100b57cec5SDimitry Andric // of machine-dependent LLVM code to the Lanai assembly language.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "MCTargetDesc/LanaiInstPrinter.h"
150b57cec5SDimitry Andric #include "LanaiAluCode.h"
160b57cec5SDimitry Andric #include "LanaiCondCode.h"
170b57cec5SDimitry Andric #include "LanaiInstrInfo.h"
180b57cec5SDimitry Andric #include "LanaiMCInstLower.h"
190b57cec5SDimitry Andric #include "LanaiTargetMachine.h"
200b57cec5SDimitry Andric #include "TargetInfo/LanaiTargetInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
260b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
270b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
280b57cec5SDimitry Andric #include "llvm/IR/Mangler.h"
290b57cec5SDimitry Andric #include "llvm/IR/Module.h"
300b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
310b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
330b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
340b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
350b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h"
360b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric using namespace llvm;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric namespace {
430b57cec5SDimitry Andric class LanaiAsmPrinter : public AsmPrinter {
440b57cec5SDimitry Andric public:
450b57cec5SDimitry Andric   explicit LanaiAsmPrinter(TargetMachine &TM,
460b57cec5SDimitry Andric                            std::unique_ptr<MCStreamer> Streamer)
470b57cec5SDimitry Andric       : AsmPrinter(TM, std::move(Streamer)) {}
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   StringRef getPassName() const override { return "Lanai Assembly Printer"; }
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
520b57cec5SDimitry Andric   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
530b57cec5SDimitry Andric                        const char *ExtraCode, raw_ostream &O) override;
54*5ffd83dbSDimitry Andric   void emitInstruction(const MachineInstr *MI) override;
550b57cec5SDimitry Andric   bool isBlockOnlyReachableByFallthrough(
560b57cec5SDimitry Andric       const MachineBasicBlock *MBB) const override;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric private:
590b57cec5SDimitry Andric   void customEmitInstruction(const MachineInstr *MI);
600b57cec5SDimitry Andric   void emitCallInstruction(const MachineInstr *MI);
610b57cec5SDimitry Andric };
620b57cec5SDimitry Andric } // end of anonymous namespace
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
650b57cec5SDimitry Andric                                    raw_ostream &O) {
660b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(OpNum);
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   switch (MO.getType()) {
690b57cec5SDimitry Andric   case MachineOperand::MO_Register:
700b57cec5SDimitry Andric     O << LanaiInstPrinter::getRegisterName(MO.getReg());
710b57cec5SDimitry Andric     break;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   case MachineOperand::MO_Immediate:
740b57cec5SDimitry Andric     O << MO.getImm();
750b57cec5SDimitry Andric     break;
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
780b57cec5SDimitry Andric     O << *MO.getMBB()->getSymbol();
790b57cec5SDimitry Andric     break;
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   case MachineOperand::MO_GlobalAddress:
820b57cec5SDimitry Andric     O << *getSymbol(MO.getGlobal());
830b57cec5SDimitry Andric     break;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   case MachineOperand::MO_BlockAddress: {
860b57cec5SDimitry Andric     MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
870b57cec5SDimitry Andric     O << BA->getName();
880b57cec5SDimitry Andric     break;
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
920b57cec5SDimitry Andric     O << *GetExternalSymbolSymbol(MO.getSymbolName());
930b57cec5SDimitry Andric     break;
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
960b57cec5SDimitry Andric     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'
970b57cec5SDimitry Andric       << MO.getIndex();
980b57cec5SDimitry Andric     break;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
1010b57cec5SDimitry Andric     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
1020b57cec5SDimitry Andric       << MO.getIndex();
1030b57cec5SDimitry Andric     return;
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric   default:
1060b57cec5SDimitry Andric     llvm_unreachable("<unknown operand type>");
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric // PrintAsmOperand - Print out an operand for an inline asm expression.
1110b57cec5SDimitry Andric bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
1120b57cec5SDimitry Andric                                       const char *ExtraCode, raw_ostream &O) {
1130b57cec5SDimitry Andric   // Does this asm operand have a single letter operand modifier?
1140b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
1150b57cec5SDimitry Andric     if (ExtraCode[1])
1160b57cec5SDimitry Andric       return true; // Unknown modifier.
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     switch (ExtraCode[0]) {
1190b57cec5SDimitry Andric     // The highest-numbered register of a pair.
1200b57cec5SDimitry Andric     case 'H': {
1210b57cec5SDimitry Andric       if (OpNo == 0)
1220b57cec5SDimitry Andric         return true;
1230b57cec5SDimitry Andric       const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
1240b57cec5SDimitry Andric       if (!FlagsOP.isImm())
1250b57cec5SDimitry Andric         return true;
1260b57cec5SDimitry Andric       unsigned Flags = FlagsOP.getImm();
1270b57cec5SDimitry Andric       unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
1280b57cec5SDimitry Andric       if (NumVals != 2)
1290b57cec5SDimitry Andric         return true;
1300b57cec5SDimitry Andric       unsigned RegOp = OpNo + 1;
1310b57cec5SDimitry Andric       if (RegOp >= MI->getNumOperands())
1320b57cec5SDimitry Andric         return true;
1330b57cec5SDimitry Andric       const MachineOperand &MO = MI->getOperand(RegOp);
1340b57cec5SDimitry Andric       if (!MO.isReg())
1350b57cec5SDimitry Andric         return true;
1368bcb0991SDimitry Andric       Register Reg = MO.getReg();
1370b57cec5SDimitry Andric       O << LanaiInstPrinter::getRegisterName(Reg);
1380b57cec5SDimitry Andric       return false;
1390b57cec5SDimitry Andric     }
1400b57cec5SDimitry Andric     default:
1410b57cec5SDimitry Andric       return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
1420b57cec5SDimitry Andric     }
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric   printOperand(MI, OpNo, O);
1450b57cec5SDimitry Andric   return false;
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1490b57cec5SDimitry Andric void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
1500b57cec5SDimitry Andric   assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&
1510b57cec5SDimitry Andric          "Unsupported call function");
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   LanaiMCInstLower MCInstLowering(OutContext, *this);
1540b57cec5SDimitry Andric   MCSubtargetInfo STI = getSubtargetInfo();
1550b57cec5SDimitry Andric   // Insert save rca instruction immediately before the call.
1560b57cec5SDimitry Andric   // TODO: We should generate a pc-relative mov instruction here instead
1570b57cec5SDimitry Andric   // of pc + 16 (should be mov .+16 %rca).
158*5ffd83dbSDimitry Andric   OutStreamer->emitInstruction(MCInstBuilder(Lanai::ADD_I_LO)
1590b57cec5SDimitry Andric                                    .addReg(Lanai::RCA)
1600b57cec5SDimitry Andric                                    .addReg(Lanai::PC)
1610b57cec5SDimitry Andric                                    .addImm(16),
1620b57cec5SDimitry Andric                                STI);
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   // Push rca onto the stack.
1650b57cec5SDimitry Andric   //   st %rca, [--%sp]
166*5ffd83dbSDimitry Andric   OutStreamer->emitInstruction(MCInstBuilder(Lanai::SW_RI)
1670b57cec5SDimitry Andric                                    .addReg(Lanai::RCA)
1680b57cec5SDimitry Andric                                    .addReg(Lanai::SP)
1690b57cec5SDimitry Andric                                    .addImm(-4)
1700b57cec5SDimitry Andric                                    .addImm(LPAC::makePreOp(LPAC::ADD)),
1710b57cec5SDimitry Andric                                STI);
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   // Lower the call instruction.
1740b57cec5SDimitry Andric   if (MI->getOpcode() == Lanai::CALL) {
1750b57cec5SDimitry Andric     MCInst TmpInst;
1760b57cec5SDimitry Andric     MCInstLowering.Lower(MI, TmpInst);
1770b57cec5SDimitry Andric     TmpInst.setOpcode(Lanai::BT);
178*5ffd83dbSDimitry Andric     OutStreamer->emitInstruction(TmpInst, STI);
1790b57cec5SDimitry Andric   } else {
180*5ffd83dbSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(Lanai::ADD_R)
1810b57cec5SDimitry Andric                                      .addReg(Lanai::PC)
1820b57cec5SDimitry Andric                                      .addReg(MI->getOperand(0).getReg())
1830b57cec5SDimitry Andric                                      .addReg(Lanai::R0)
1840b57cec5SDimitry Andric                                      .addImm(LPCC::ICC_T),
1850b57cec5SDimitry Andric                                  STI);
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {
1900b57cec5SDimitry Andric   LanaiMCInstLower MCInstLowering(OutContext, *this);
1910b57cec5SDimitry Andric   MCSubtargetInfo STI = getSubtargetInfo();
1920b57cec5SDimitry Andric   MCInst TmpInst;
1930b57cec5SDimitry Andric   MCInstLowering.Lower(MI, TmpInst);
194*5ffd83dbSDimitry Andric   OutStreamer->emitInstruction(TmpInst, STI);
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric 
197*5ffd83dbSDimitry Andric void LanaiAsmPrinter::emitInstruction(const MachineInstr *MI) {
1980b57cec5SDimitry Andric   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
1990b57cec5SDimitry Andric   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   do {
2020b57cec5SDimitry Andric     if (I->isCall()) {
2030b57cec5SDimitry Andric       emitCallInstruction(&*I);
2040b57cec5SDimitry Andric       continue;
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric     customEmitInstruction(&*I);
2080b57cec5SDimitry Andric   } while ((++I != E) && I->isInsideBundle());
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric // isBlockOnlyReachableByFallthough - Return true if the basic block has
2120b57cec5SDimitry Andric // exactly one predecessor and the control transfer mechanism between
2130b57cec5SDimitry Andric // the predecessor and this block is a fall-through.
214*5ffd83dbSDimitry Andric // FIXME: could the overridden cases be handled in analyzeBranch?
2150b57cec5SDimitry Andric bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(
2160b57cec5SDimitry Andric     const MachineBasicBlock *MBB) const {
2170b57cec5SDimitry Andric   // The predecessor has to be immediately before this block.
2180b57cec5SDimitry Andric   const MachineBasicBlock *Pred = *MBB->pred_begin();
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // If the predecessor is a switch statement, assume a jump table
2210b57cec5SDimitry Andric   // implementation, so it is not a fall through.
2220b57cec5SDimitry Andric   if (const BasicBlock *B = Pred->getBasicBlock())
2230b57cec5SDimitry Andric     if (isa<SwitchInst>(B->getTerminator()))
2240b57cec5SDimitry Andric       return false;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   // Check default implementation
2270b57cec5SDimitry Andric   if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))
2280b57cec5SDimitry Andric     return false;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric   // Otherwise, check the last instruction.
2310b57cec5SDimitry Andric   // Check if the last terminator is an unconditional branch.
2320b57cec5SDimitry Andric   MachineBasicBlock::const_iterator I = Pred->end();
2330b57cec5SDimitry Andric   while (I != Pred->begin() && !(--I)->isTerminator()) {
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   return !I->isBarrier();
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric // Force static initialization.
240480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeLanaiAsmPrinter() {
2410b57cec5SDimitry Andric   RegisterAsmPrinter<LanaiAsmPrinter> X(getTheLanaiTarget());
2420b57cec5SDimitry Andric }
243