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