244 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- LanaiAsmPrinter.cpp - Lanai LLVM assembly writer ------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file contains a printer that converts from our internal representation
 | |
| // of machine-dependent LLVM code to the Lanai assembly language.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "InstPrinter/LanaiInstPrinter.h"
 | |
| #include "Lanai.h"
 | |
| #include "LanaiInstrInfo.h"
 | |
| #include "LanaiMCInstLower.h"
 | |
| #include "LanaiTargetMachine.h"
 | |
| #include "llvm/CodeGen/AsmPrinter.h"
 | |
| #include "llvm/CodeGen/MachineConstantPool.h"
 | |
| #include "llvm/CodeGen/MachineFunctionPass.h"
 | |
| #include "llvm/CodeGen/MachineInstr.h"
 | |
| #include "llvm/CodeGen/MachineModuleInfo.h"
 | |
| #include "llvm/IR/Constants.h"
 | |
| #include "llvm/IR/DerivedTypes.h"
 | |
| #include "llvm/IR/Mangler.h"
 | |
| #include "llvm/IR/Module.h"
 | |
| #include "llvm/MC/MCAsmInfo.h"
 | |
| #include "llvm/MC/MCInst.h"
 | |
| #include "llvm/MC/MCInstBuilder.h"
 | |
| #include "llvm/MC/MCStreamer.h"
 | |
| #include "llvm/MC/MCSymbol.h"
 | |
| #include "llvm/Support/TargetRegistry.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| #define DEBUG_TYPE "asm-printer"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| namespace {
 | |
| class LanaiAsmPrinter : public AsmPrinter {
 | |
| public:
 | |
|   explicit LanaiAsmPrinter(TargetMachine &TM,
 | |
|                            std::unique_ptr<MCStreamer> Streamer)
 | |
|       : AsmPrinter(TM, std::move(Streamer)) {}
 | |
| 
 | |
|   StringRef getPassName() const override { return "Lanai Assembly Printer"; }
 | |
| 
 | |
|   void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O);
 | |
|   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
 | |
|                        unsigned AsmVariant, const char *ExtraCode,
 | |
|                        raw_ostream &O) override;
 | |
|   void EmitInstruction(const MachineInstr *MI) override;
 | |
|   bool isBlockOnlyReachableByFallthrough(
 | |
|       const MachineBasicBlock *MBB) const override;
 | |
| 
 | |
| private:
 | |
|   void customEmitInstruction(const MachineInstr *MI);
 | |
|   void emitCallInstruction(const MachineInstr *MI);
 | |
| };
 | |
| } // end of anonymous namespace
 | |
| 
 | |
| void LanaiAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
 | |
|                                    raw_ostream &O) {
 | |
|   const MachineOperand &MO = MI->getOperand(OpNum);
 | |
| 
 | |
|   switch (MO.getType()) {
 | |
|   case MachineOperand::MO_Register:
 | |
|     O << LanaiInstPrinter::getRegisterName(MO.getReg());
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_Immediate:
 | |
|     O << MO.getImm();
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_MachineBasicBlock:
 | |
|     O << *MO.getMBB()->getSymbol();
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_GlobalAddress:
 | |
|     O << *getSymbol(MO.getGlobal());
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_BlockAddress: {
 | |
|     MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
 | |
|     O << BA->getName();
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   case MachineOperand::MO_ExternalSymbol:
 | |
|     O << *GetExternalSymbolSymbol(MO.getSymbolName());
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_JumpTableIndex:
 | |
|     O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() << '_'
 | |
|       << MO.getIndex();
 | |
|     break;
 | |
| 
 | |
|   case MachineOperand::MO_ConstantPoolIndex:
 | |
|     O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
 | |
|       << MO.getIndex();
 | |
|     return;
 | |
| 
 | |
|   default:
 | |
|     llvm_unreachable("<unknown operand type>");
 | |
|   }
 | |
| }
 | |
| 
 | |
| // PrintAsmOperand - Print out an operand for an inline asm expression.
 | |
| bool LanaiAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
 | |
|                                       unsigned /*AsmVariant*/,
 | |
|                                       const char *ExtraCode, raw_ostream &O) {
 | |
|   // Does this asm operand have a single letter operand modifier?
 | |
|   if (ExtraCode && ExtraCode[0]) {
 | |
|     if (ExtraCode[1])
 | |
|       return true; // Unknown modifier.
 | |
| 
 | |
|     switch (ExtraCode[0]) {
 | |
|     // The highest-numbered register of a pair.
 | |
|     case 'H': {
 | |
|       if (OpNo == 0)
 | |
|         return true;
 | |
|       const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
 | |
|       if (!FlagsOP.isImm())
 | |
|         return true;
 | |
|       unsigned Flags = FlagsOP.getImm();
 | |
|       unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
 | |
|       if (NumVals != 2)
 | |
|         return true;
 | |
|       unsigned RegOp = OpNo + 1;
 | |
|       if (RegOp >= MI->getNumOperands())
 | |
|         return true;
 | |
|       const MachineOperand &MO = MI->getOperand(RegOp);
 | |
|       if (!MO.isReg())
 | |
|         return true;
 | |
|       unsigned Reg = MO.getReg();
 | |
|       O << LanaiInstPrinter::getRegisterName(Reg);
 | |
|       return false;
 | |
|     }
 | |
|     default:
 | |
|       return true; // Unknown modifier.
 | |
|     }
 | |
|   }
 | |
|   printOperand(MI, OpNo, O);
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| void LanaiAsmPrinter::emitCallInstruction(const MachineInstr *MI) {
 | |
|   assert((MI->getOpcode() == Lanai::CALL || MI->getOpcode() == Lanai::CALLR) &&
 | |
|          "Unsupported call function");
 | |
| 
 | |
|   LanaiMCInstLower MCInstLowering(OutContext, *this);
 | |
|   MCSubtargetInfo STI = getSubtargetInfo();
 | |
|   // Insert save rca instruction immediately before the call.
 | |
|   // TODO: We should generate a pc-relative mov instruction here instead
 | |
|   // of pc + 16 (should be mov .+16 %rca).
 | |
|   OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_I_LO)
 | |
|                                    .addReg(Lanai::RCA)
 | |
|                                    .addReg(Lanai::PC)
 | |
|                                    .addImm(16),
 | |
|                                STI);
 | |
| 
 | |
|   // Push rca onto the stack.
 | |
|   //   st %rca, [--%sp]
 | |
|   OutStreamer->EmitInstruction(MCInstBuilder(Lanai::SW_RI)
 | |
|                                    .addReg(Lanai::RCA)
 | |
|                                    .addReg(Lanai::SP)
 | |
|                                    .addImm(-4)
 | |
|                                    .addImm(LPAC::makePreOp(LPAC::ADD)),
 | |
|                                STI);
 | |
| 
 | |
|   // Lower the call instruction.
 | |
|   if (MI->getOpcode() == Lanai::CALL) {
 | |
|     MCInst TmpInst;
 | |
|     MCInstLowering.Lower(MI, TmpInst);
 | |
|     TmpInst.setOpcode(Lanai::BT);
 | |
|     OutStreamer->EmitInstruction(TmpInst, STI);
 | |
|   } else {
 | |
|     OutStreamer->EmitInstruction(MCInstBuilder(Lanai::ADD_R)
 | |
|                                      .addReg(Lanai::PC)
 | |
|                                      .addReg(MI->getOperand(0).getReg())
 | |
|                                      .addReg(Lanai::R0)
 | |
|                                      .addImm(LPCC::ICC_T),
 | |
|                                  STI);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void LanaiAsmPrinter::customEmitInstruction(const MachineInstr *MI) {
 | |
|   LanaiMCInstLower MCInstLowering(OutContext, *this);
 | |
|   MCSubtargetInfo STI = getSubtargetInfo();
 | |
|   MCInst TmpInst;
 | |
|   MCInstLowering.Lower(MI, TmpInst);
 | |
|   OutStreamer->EmitInstruction(TmpInst, STI);
 | |
| }
 | |
| 
 | |
| void LanaiAsmPrinter::EmitInstruction(const MachineInstr *MI) {
 | |
|   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
 | |
|   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
 | |
| 
 | |
|   do {
 | |
|     if (I->isCall()) {
 | |
|       emitCallInstruction(&*I);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     customEmitInstruction(&*I);
 | |
|   } while ((++I != E) && I->isInsideBundle());
 | |
| }
 | |
| 
 | |
| // isBlockOnlyReachableByFallthough - Return true if the basic block has
 | |
| // exactly one predecessor and the control transfer mechanism between
 | |
| // the predecessor and this block is a fall-through.
 | |
| // FIXME: could the overridden cases be handled in AnalyzeBranch?
 | |
| bool LanaiAsmPrinter::isBlockOnlyReachableByFallthrough(
 | |
|     const MachineBasicBlock *MBB) const {
 | |
|   // The predecessor has to be immediately before this block.
 | |
|   const MachineBasicBlock *Pred = *MBB->pred_begin();
 | |
| 
 | |
|   // If the predecessor is a switch statement, assume a jump table
 | |
|   // implementation, so it is not a fall through.
 | |
|   if (const BasicBlock *B = Pred->getBasicBlock())
 | |
|     if (isa<SwitchInst>(B->getTerminator()))
 | |
|       return false;
 | |
| 
 | |
|   // Check default implementation
 | |
|   if (!AsmPrinter::isBlockOnlyReachableByFallthrough(MBB))
 | |
|     return false;
 | |
| 
 | |
|   // Otherwise, check the last instruction.
 | |
|   // Check if the last terminator is an unconditional branch.
 | |
|   MachineBasicBlock::const_iterator I = Pred->end();
 | |
|   while (I != Pred->begin() && !(--I)->isTerminator()) {
 | |
|   }
 | |
| 
 | |
|   return !I->isBarrier();
 | |
| }
 | |
| 
 | |
| // Force static initialization.
 | |
| extern "C" void LLVMInitializeLanaiAsmPrinter() {
 | |
|   RegisterAsmPrinter<LanaiAsmPrinter> X(getTheLanaiTarget());
 | |
| }
 |