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