]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- XCoreAsmPrinter.cpp - XCore 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 XAS-format XCore assembly language. | |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
223e47cc | 15 | #include "XCore.h" |
970d7e83 | 16 | #include "InstPrinter/XCoreInstPrinter.h" |
223e47cc | 17 | #include "XCoreInstrInfo.h" |
970d7e83 | 18 | #include "XCoreMCInstLower.h" |
223e47cc LB |
19 | #include "XCoreSubtarget.h" |
20 | #include "XCoreTargetMachine.h" | |
1a4d82fc | 21 | #include "XCoreTargetStreamer.h" |
970d7e83 LB |
22 | #include "llvm/ADT/SmallString.h" |
23 | #include "llvm/ADT/StringExtras.h" | |
223e47cc | 24 | #include "llvm/CodeGen/AsmPrinter.h" |
223e47cc | 25 | #include "llvm/CodeGen/MachineConstantPool.h" |
970d7e83 | 26 | #include "llvm/CodeGen/MachineFunctionPass.h" |
223e47cc LB |
27 | #include "llvm/CodeGen/MachineInstr.h" |
28 | #include "llvm/CodeGen/MachineJumpTableInfo.h" | |
970d7e83 | 29 | #include "llvm/CodeGen/MachineModuleInfo.h" |
970d7e83 LB |
30 | #include "llvm/IR/Constants.h" |
31 | #include "llvm/IR/DataLayout.h" | |
1a4d82fc | 32 | #include "llvm/IR/DebugInfo.h" |
970d7e83 | 33 | #include "llvm/IR/DerivedTypes.h" |
1a4d82fc | 34 | #include "llvm/IR/Mangler.h" |
970d7e83 | 35 | #include "llvm/IR/Module.h" |
223e47cc | 36 | #include "llvm/MC/MCAsmInfo.h" |
1a4d82fc | 37 | #include "llvm/MC/MCExpr.h" |
970d7e83 | 38 | #include "llvm/MC/MCInst.h" |
223e47cc LB |
39 | #include "llvm/MC/MCStreamer.h" |
40 | #include "llvm/MC/MCSymbol.h" | |
223e47cc LB |
41 | #include "llvm/Support/ErrorHandling.h" |
42 | #include "llvm/Support/TargetRegistry.h" | |
43 | #include "llvm/Support/raw_ostream.h" | |
970d7e83 | 44 | #include "llvm/Target/TargetLoweringObjectFile.h" |
223e47cc LB |
45 | #include <algorithm> |
46 | #include <cctype> | |
47 | using namespace llvm; | |
48 | ||
1a4d82fc | 49 | #define DEBUG_TYPE "asm-printer" |
223e47cc LB |
50 | |
51 | namespace { | |
52 | class XCoreAsmPrinter : public AsmPrinter { | |
53 | const XCoreSubtarget &Subtarget; | |
970d7e83 | 54 | XCoreMCInstLower MCInstLowering; |
1a4d82fc JJ |
55 | XCoreTargetStreamer &getTargetStreamer(); |
56 | ||
223e47cc LB |
57 | public: |
58 | explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) | |
970d7e83 LB |
59 | : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()), |
60 | MCInstLowering(*this) {} | |
223e47cc | 61 | |
1a4d82fc | 62 | const char *getPassName() const override { |
223e47cc LB |
63 | return "XCore Assembly Printer"; |
64 | } | |
65 | ||
223e47cc LB |
66 | void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, |
67 | const std::string &directive = ".jmptable"); | |
68 | void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) { | |
69 | printInlineJT(MI, opNum, O, ".jmptable32"); | |
70 | } | |
71 | void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); | |
72 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | |
73 | unsigned AsmVariant, const char *ExtraCode, | |
1a4d82fc JJ |
74 | raw_ostream &O) override; |
75 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, | |
76 | unsigned AsmVariant, const char *ExtraCode, | |
77 | raw_ostream &O) override; | |
223e47cc LB |
78 | |
79 | void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV); | |
1a4d82fc | 80 | void EmitGlobalVariable(const GlobalVariable *GV) override; |
223e47cc | 81 | |
1a4d82fc JJ |
82 | void EmitFunctionEntryLabel() override; |
83 | void EmitInstruction(const MachineInstr *MI) override; | |
84 | void EmitFunctionBodyStart() override; | |
85 | void EmitFunctionBodyEnd() override; | |
223e47cc LB |
86 | }; |
87 | } // end of anonymous namespace | |
88 | ||
1a4d82fc JJ |
89 | XCoreTargetStreamer &XCoreAsmPrinter::getTargetStreamer() { |
90 | return static_cast<XCoreTargetStreamer&>(*OutStreamer.getTargetStreamer()); | |
91 | } | |
92 | ||
223e47cc | 93 | void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { |
1a4d82fc JJ |
94 | assert( ( GV->hasExternalLinkage() || GV->hasWeakLinkage() || |
95 | GV->hasLinkOnceLinkage() || GV->hasCommonLinkage() ) && | |
96 | "Unexpected linkage"); | |
223e47cc | 97 | if (ArrayType *ATy = dyn_cast<ArrayType>( |
1a4d82fc JJ |
98 | cast<PointerType>(GV->getType())->getElementType())) { |
99 | ||
100 | MCSymbol *SymGlob = OutContext.GetOrCreateSymbol( | |
101 | Twine(Sym->getName() + StringRef(".globound"))); | |
102 | OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Global); | |
103 | OutStreamer.EmitAssignment(SymGlob, | |
104 | MCConstantExpr::Create(ATy->getNumElements(), | |
105 | OutContext)); | |
106 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || | |
107 | GV->hasCommonLinkage()) { | |
223e47cc | 108 | // TODO Use COMDAT groups for LinkOnceLinkage |
1a4d82fc | 109 | OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Weak); |
223e47cc LB |
110 | } |
111 | } | |
112 | } | |
113 | ||
114 | void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { | |
115 | // Check to see if this is a special global used by LLVM, if so, emit it. | |
116 | if (!GV->hasInitializer() || | |
117 | EmitSpecialLLVMGlobal(GV)) | |
118 | return; | |
119 | ||
1a4d82fc JJ |
120 | const DataLayout *TD = TM.getSubtargetImpl()->getDataLayout(); |
121 | OutStreamer.SwitchSection( | |
122 | getObjFileLowering().SectionForGlobal(GV, *Mang, TM)); | |
223e47cc | 123 | |
1a4d82fc | 124 | MCSymbol *GVSym = getSymbol(GV); |
223e47cc LB |
125 | const Constant *C = GV->getInitializer(); |
126 | unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType()); | |
127 | ||
128 | // Mark the start of the global | |
1a4d82fc | 129 | getTargetStreamer().emitCCTopData(GVSym->getName()); |
223e47cc LB |
130 | |
131 | switch (GV->getLinkage()) { | |
132 | case GlobalValue::AppendingLinkage: | |
133 | report_fatal_error("AppendingLinkage is not supported by this target!"); | |
134 | case GlobalValue::LinkOnceAnyLinkage: | |
135 | case GlobalValue::LinkOnceODRLinkage: | |
136 | case GlobalValue::WeakAnyLinkage: | |
137 | case GlobalValue::WeakODRLinkage: | |
138 | case GlobalValue::ExternalLinkage: | |
1a4d82fc | 139 | case GlobalValue::CommonLinkage: |
223e47cc LB |
140 | emitArrayBound(GVSym, GV); |
141 | OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); | |
142 | ||
143 | // TODO Use COMDAT groups for LinkOnceLinkage | |
1a4d82fc JJ |
144 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || |
145 | GV->hasCommonLinkage()) | |
223e47cc LB |
146 | OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak); |
147 | // FALL THROUGH | |
148 | case GlobalValue::InternalLinkage: | |
149 | case GlobalValue::PrivateLinkage: | |
150 | break; | |
223e47cc LB |
151 | default: |
152 | llvm_unreachable("Unknown linkage type!"); | |
153 | } | |
154 | ||
155 | EmitAlignment(Align > 2 ? Align : 2, GV); | |
156 | ||
223e47cc | 157 | if (GV->isThreadLocal()) { |
1a4d82fc | 158 | report_fatal_error("TLS is not supported by this target!"); |
223e47cc | 159 | } |
1a4d82fc | 160 | unsigned Size = TD->getTypeAllocSize(C->getType()); |
223e47cc LB |
161 | if (MAI->hasDotTypeDotSizeDirective()) { |
162 | OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject); | |
1a4d82fc | 163 | OutStreamer.EmitELFSize(GVSym, MCConstantExpr::Create(Size, OutContext)); |
223e47cc LB |
164 | } |
165 | OutStreamer.EmitLabel(GVSym); | |
166 | ||
167 | EmitGlobalConstant(C); | |
223e47cc LB |
168 | // The ABI requires that unsigned scalar types smaller than 32 bits |
169 | // are padded to 32 bits. | |
170 | if (Size < 4) | |
970d7e83 | 171 | OutStreamer.EmitZeros(4 - Size); |
223e47cc LB |
172 | |
173 | // Mark the end of the global | |
1a4d82fc | 174 | getTargetStreamer().emitCCBottomData(GVSym->getName()); |
223e47cc LB |
175 | } |
176 | ||
970d7e83 LB |
177 | void XCoreAsmPrinter::EmitFunctionBodyStart() { |
178 | MCInstLowering.Initialize(Mang, &MF->getContext()); | |
179 | } | |
180 | ||
223e47cc LB |
181 | /// EmitFunctionBodyEnd - Targets can override this to emit stuff after |
182 | /// the last basic block in the function. | |
183 | void XCoreAsmPrinter::EmitFunctionBodyEnd() { | |
184 | // Emit function end directives | |
1a4d82fc | 185 | getTargetStreamer().emitCCBottomFunction(CurrentFnSym->getName()); |
223e47cc LB |
186 | } |
187 | ||
188 | void XCoreAsmPrinter::EmitFunctionEntryLabel() { | |
189 | // Mark the start of the function | |
1a4d82fc | 190 | getTargetStreamer().emitCCTopFunction(CurrentFnSym->getName()); |
223e47cc LB |
191 | OutStreamer.EmitLabel(CurrentFnSym); |
192 | } | |
193 | ||
223e47cc LB |
194 | void XCoreAsmPrinter:: |
195 | printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, | |
196 | const std::string &directive) { | |
197 | unsigned JTI = MI->getOperand(opNum).getIndex(); | |
198 | const MachineFunction *MF = MI->getParent()->getParent(); | |
199 | const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); | |
200 | const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); | |
201 | const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; | |
202 | O << "\t" << directive << " "; | |
203 | for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { | |
204 | MachineBasicBlock *MBB = JTBBs[i]; | |
205 | if (i > 0) | |
206 | O << ","; | |
207 | O << *MBB->getSymbol(); | |
208 | } | |
209 | } | |
210 | ||
211 | void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, | |
212 | raw_ostream &O) { | |
1a4d82fc | 213 | const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); |
223e47cc LB |
214 | const MachineOperand &MO = MI->getOperand(opNum); |
215 | switch (MO.getType()) { | |
216 | case MachineOperand::MO_Register: | |
970d7e83 | 217 | O << XCoreInstPrinter::getRegisterName(MO.getReg()); |
223e47cc LB |
218 | break; |
219 | case MachineOperand::MO_Immediate: | |
220 | O << MO.getImm(); | |
221 | break; | |
222 | case MachineOperand::MO_MachineBasicBlock: | |
223 | O << *MO.getMBB()->getSymbol(); | |
224 | break; | |
225 | case MachineOperand::MO_GlobalAddress: | |
1a4d82fc | 226 | O << *getSymbol(MO.getGlobal()); |
223e47cc LB |
227 | break; |
228 | case MachineOperand::MO_ConstantPoolIndex: | |
1a4d82fc | 229 | O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() |
223e47cc LB |
230 | << '_' << MO.getIndex(); |
231 | break; | |
232 | case MachineOperand::MO_BlockAddress: | |
233 | O << *GetBlockAddressSymbol(MO.getBlockAddress()); | |
234 | break; | |
235 | default: | |
236 | llvm_unreachable("not implemented"); | |
237 | } | |
238 | } | |
239 | ||
240 | /// PrintAsmOperand - Print out an operand for an inline asm expression. | |
241 | /// | |
242 | bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | |
243 | unsigned AsmVariant,const char *ExtraCode, | |
244 | raw_ostream &O) { | |
1a4d82fc JJ |
245 | // Print the operand if there is no operand modifier. |
246 | if (!ExtraCode || !ExtraCode[0]) { | |
247 | printOperand(MI, OpNo, O); | |
248 | return false; | |
249 | } | |
223e47cc | 250 | |
1a4d82fc JJ |
251 | // Otherwise fallback on the default implementation. |
252 | return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); | |
223e47cc LB |
253 | } |
254 | ||
1a4d82fc JJ |
255 | bool XCoreAsmPrinter:: |
256 | PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, | |
257 | unsigned AsmVariant, const char *ExtraCode, | |
258 | raw_ostream &O) { | |
259 | if (ExtraCode && ExtraCode[0]) { | |
260 | return true; // Unknown modifier. | |
261 | } | |
262 | printOperand(MI, OpNum, O); | |
263 | O << '['; | |
264 | printOperand(MI, OpNum + 1, O); | |
265 | O << ']'; | |
266 | return false; | |
223e47cc LB |
267 | } |
268 | ||
269 | void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { | |
270 | SmallString<128> Str; | |
271 | raw_svector_ostream O(Str); | |
272 | ||
273 | switch (MI->getOpcode()) { | |
1a4d82fc JJ |
274 | case XCore::DBG_VALUE: |
275 | llvm_unreachable("Should be handled target independently"); | |
223e47cc LB |
276 | case XCore::ADD_2rus: |
277 | if (MI->getOperand(2).getImm() == 0) { | |
970d7e83 LB |
278 | O << "\tmov " |
279 | << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", " | |
280 | << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()); | |
223e47cc LB |
281 | OutStreamer.EmitRawText(O.str()); |
282 | return; | |
283 | } | |
284 | break; | |
970d7e83 LB |
285 | case XCore::BR_JT: |
286 | case XCore::BR_JT32: | |
287 | O << "\tbru " | |
288 | << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n'; | |
289 | if (MI->getOpcode() == XCore::BR_JT) | |
290 | printInlineJT(MI, 0, O); | |
291 | else | |
292 | printInlineJT32(MI, 0, O); | |
293 | O << '\n'; | |
294 | OutStreamer.EmitRawText(O.str()); | |
295 | return; | |
223e47cc | 296 | } |
970d7e83 LB |
297 | |
298 | MCInst TmpInst; | |
299 | MCInstLowering.Lower(MI, TmpInst); | |
300 | ||
1a4d82fc | 301 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
302 | } |
303 | ||
304 | // Force static initialization. | |
305 | extern "C" void LLVMInitializeXCoreAsmPrinter() { | |
306 | RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget); | |
307 | } |