]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// |
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 GAS-format ARM assembly language. | |
12 | // | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
223e47cc LB |
15 | #include "ARMAsmPrinter.h" |
16 | #include "ARM.h" | |
223e47cc | 17 | #include "ARMConstantPoolValue.h" |
1a4d82fc | 18 | #include "ARMFPUName.h" |
223e47cc LB |
19 | #include "ARMMachineFunctionInfo.h" |
20 | #include "ARMTargetMachine.h" | |
21 | #include "ARMTargetObjectFile.h" | |
22 | #include "InstPrinter/ARMInstPrinter.h" | |
23 | #include "MCTargetDesc/ARMAddressingModes.h" | |
24 | #include "MCTargetDesc/ARMMCExpr.h" | |
970d7e83 LB |
25 | #include "llvm/ADT/SetVector.h" |
26 | #include "llvm/ADT/SmallString.h" | |
223e47cc LB |
27 | #include "llvm/CodeGen/MachineFunctionPass.h" |
28 | #include "llvm/CodeGen/MachineJumpTableInfo.h" | |
970d7e83 | 29 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
970d7e83 LB |
30 | #include "llvm/IR/Constants.h" |
31 | #include "llvm/IR/DataLayout.h" | |
1a4d82fc JJ |
32 | #include "llvm/IR/DebugInfo.h" |
33 | #include "llvm/IR/Mangler.h" | |
970d7e83 LB |
34 | #include "llvm/IR/Module.h" |
35 | #include "llvm/IR/Type.h" | |
223e47cc LB |
36 | #include "llvm/MC/MCAsmInfo.h" |
37 | #include "llvm/MC/MCAssembler.h" | |
38 | #include "llvm/MC/MCContext.h" | |
970d7e83 | 39 | #include "llvm/MC/MCELFStreamer.h" |
223e47cc | 40 | #include "llvm/MC/MCInst.h" |
970d7e83 | 41 | #include "llvm/MC/MCInstBuilder.h" |
223e47cc | 42 | #include "llvm/MC/MCObjectStreamer.h" |
970d7e83 | 43 | #include "llvm/MC/MCSectionMachO.h" |
223e47cc LB |
44 | #include "llvm/MC/MCStreamer.h" |
45 | #include "llvm/MC/MCSymbol.h" | |
1a4d82fc JJ |
46 | #include "llvm/Support/ARMBuildAttributes.h" |
47 | #include "llvm/Support/COFF.h" | |
223e47cc LB |
48 | #include "llvm/Support/CommandLine.h" |
49 | #include "llvm/Support/Debug.h" | |
970d7e83 | 50 | #include "llvm/Support/ELF.h" |
223e47cc LB |
51 | #include "llvm/Support/ErrorHandling.h" |
52 | #include "llvm/Support/TargetRegistry.h" | |
53 | #include "llvm/Support/raw_ostream.h" | |
970d7e83 | 54 | #include "llvm/Target/TargetMachine.h" |
223e47cc LB |
55 | #include <cctype> |
56 | using namespace llvm; | |
57 | ||
1a4d82fc | 58 | #define DEBUG_TYPE "asm-printer" |
223e47cc LB |
59 | |
60 | void ARMAsmPrinter::EmitFunctionBodyEnd() { | |
61 | // Make sure to terminate any constant pools that were at the end | |
62 | // of the function. | |
63 | if (!InConstantPool) | |
64 | return; | |
65 | InConstantPool = false; | |
66 | OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); | |
67 | } | |
68 | ||
69 | void ARMAsmPrinter::EmitFunctionEntryLabel() { | |
70 | if (AFI->isThumbFunction()) { | |
71 | OutStreamer.EmitAssemblerFlag(MCAF_Code16); | |
72 | OutStreamer.EmitThumbFunc(CurrentFnSym); | |
73 | } | |
74 | ||
75 | OutStreamer.EmitLabel(CurrentFnSym); | |
76 | } | |
77 | ||
78 | void ARMAsmPrinter::EmitXXStructor(const Constant *CV) { | |
1a4d82fc JJ |
79 | uint64_t Size = |
80 | TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(CV->getType()); | |
223e47cc LB |
81 | assert(Size && "C++ constructor pointer had zero size!"); |
82 | ||
83 | const GlobalValue *GV = dyn_cast<GlobalValue>(CV->stripPointerCasts()); | |
84 | assert(GV && "C++ constructor pointer was not a GlobalValue!"); | |
85 | ||
1a4d82fc JJ |
86 | const MCExpr *E = MCSymbolRefExpr::Create(GetARMGVSymbol(GV, |
87 | ARMII::MO_NO_FLAG), | |
88 | (Subtarget->isTargetELF() | |
89 | ? MCSymbolRefExpr::VK_ARM_TARGET1 | |
90 | : MCSymbolRefExpr::VK_None), | |
223e47cc | 91 | OutContext); |
1a4d82fc | 92 | |
223e47cc LB |
93 | OutStreamer.EmitValue(E, Size); |
94 | } | |
95 | ||
96 | /// runOnMachineFunction - This uses the EmitInstruction() | |
97 | /// method to print assembly for each instruction. | |
98 | /// | |
99 | bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { | |
100 | AFI = MF.getInfo<ARMFunctionInfo>(); | |
101 | MCP = MF.getConstantPool(); | |
102 | ||
1a4d82fc JJ |
103 | SetupMachineFunction(MF); |
104 | ||
105 | if (Subtarget->isTargetCOFF()) { | |
106 | bool Internal = MF.getFunction()->hasInternalLinkage(); | |
107 | COFF::SymbolStorageClass Scl = Internal ? COFF::IMAGE_SYM_CLASS_STATIC | |
108 | : COFF::IMAGE_SYM_CLASS_EXTERNAL; | |
109 | int Type = COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT; | |
110 | ||
111 | OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); | |
112 | OutStreamer.EmitCOFFSymbolStorageClass(Scl); | |
113 | OutStreamer.EmitCOFFSymbolType(Type); | |
114 | OutStreamer.EndCOFFSymbolDef(); | |
115 | } | |
116 | ||
117 | // Have common code print out the function header with linkage info etc. | |
118 | EmitFunctionHeader(); | |
119 | ||
120 | // Emit the rest of the function body. | |
121 | EmitFunctionBody(); | |
122 | ||
85aaf69f SL |
123 | // If we need V4T thumb mode Register Indirect Jump pads, emit them. |
124 | // These are created per function, rather than per TU, since it's | |
125 | // relatively easy to exceed the thumb branch range within a TU. | |
126 | if (! ThumbIndirectPads.empty()) { | |
127 | OutStreamer.EmitAssemblerFlag(MCAF_Code16); | |
128 | EmitAlignment(1); | |
129 | for (unsigned i = 0, e = ThumbIndirectPads.size(); i < e; i++) { | |
130 | OutStreamer.EmitLabel(ThumbIndirectPads[i].second); | |
131 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBX) | |
132 | .addReg(ThumbIndirectPads[i].first) | |
133 | // Add predicate operands. | |
134 | .addImm(ARMCC::AL) | |
135 | .addReg(0)); | |
136 | } | |
137 | ThumbIndirectPads.clear(); | |
138 | } | |
139 | ||
1a4d82fc JJ |
140 | // We didn't modify anything. |
141 | return false; | |
223e47cc LB |
142 | } |
143 | ||
144 | void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, | |
145 | raw_ostream &O, const char *Modifier) { | |
146 | const MachineOperand &MO = MI->getOperand(OpNum); | |
147 | unsigned TF = MO.getTargetFlags(); | |
148 | ||
149 | switch (MO.getType()) { | |
150 | default: llvm_unreachable("<unknown operand type>"); | |
151 | case MachineOperand::MO_Register: { | |
152 | unsigned Reg = MO.getReg(); | |
153 | assert(TargetRegisterInfo::isPhysicalRegister(Reg)); | |
154 | assert(!MO.getSubReg() && "Subregs should be eliminated!"); | |
970d7e83 LB |
155 | if(ARM::GPRPairRegClass.contains(Reg)) { |
156 | const MachineFunction &MF = *MI->getParent()->getParent(); | |
1a4d82fc | 157 | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); |
970d7e83 LB |
158 | Reg = TRI->getSubReg(Reg, ARM::gsub_0); |
159 | } | |
223e47cc LB |
160 | O << ARMInstPrinter::getRegisterName(Reg); |
161 | break; | |
162 | } | |
163 | case MachineOperand::MO_Immediate: { | |
164 | int64_t Imm = MO.getImm(); | |
165 | O << '#'; | |
166 | if ((Modifier && strcmp(Modifier, "lo16") == 0) || | |
167 | (TF == ARMII::MO_LO16)) | |
168 | O << ":lower16:"; | |
169 | else if ((Modifier && strcmp(Modifier, "hi16") == 0) || | |
170 | (TF == ARMII::MO_HI16)) | |
171 | O << ":upper16:"; | |
172 | O << Imm; | |
173 | break; | |
174 | } | |
175 | case MachineOperand::MO_MachineBasicBlock: | |
176 | O << *MO.getMBB()->getSymbol(); | |
177 | return; | |
178 | case MachineOperand::MO_GlobalAddress: { | |
179 | const GlobalValue *GV = MO.getGlobal(); | |
180 | if ((Modifier && strcmp(Modifier, "lo16") == 0) || | |
181 | (TF & ARMII::MO_LO16)) | |
182 | O << ":lower16:"; | |
183 | else if ((Modifier && strcmp(Modifier, "hi16") == 0) || | |
184 | (TF & ARMII::MO_HI16)) | |
185 | O << ":upper16:"; | |
1a4d82fc | 186 | O << *GetARMGVSymbol(GV, TF); |
223e47cc LB |
187 | |
188 | printOffset(MO.getOffset(), O); | |
189 | if (TF == ARMII::MO_PLT) | |
190 | O << "(PLT)"; | |
191 | break; | |
192 | } | |
223e47cc LB |
193 | case MachineOperand::MO_ConstantPoolIndex: |
194 | O << *GetCPISymbol(MO.getIndex()); | |
195 | break; | |
223e47cc LB |
196 | } |
197 | } | |
198 | ||
199 | //===--------------------------------------------------------------------===// | |
200 | ||
223e47cc LB |
201 | MCSymbol *ARMAsmPrinter:: |
202 | GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const { | |
1a4d82fc | 203 | const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); |
223e47cc | 204 | SmallString<60> Name; |
1a4d82fc | 205 | raw_svector_ostream(Name) << DL->getPrivateGlobalPrefix() << "JTI" |
223e47cc LB |
206 | << getFunctionNumber() << '_' << uid << '_' << uid2; |
207 | return OutContext.GetOrCreateSymbol(Name.str()); | |
208 | } | |
209 | ||
210 | ||
970d7e83 | 211 | MCSymbol *ARMAsmPrinter::GetARMSJLJEHLabel() const { |
1a4d82fc | 212 | const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); |
223e47cc | 213 | SmallString<60> Name; |
1a4d82fc | 214 | raw_svector_ostream(Name) << DL->getPrivateGlobalPrefix() << "SJLJEH" |
223e47cc LB |
215 | << getFunctionNumber(); |
216 | return OutContext.GetOrCreateSymbol(Name.str()); | |
217 | } | |
218 | ||
219 | bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, | |
220 | unsigned AsmVariant, const char *ExtraCode, | |
221 | raw_ostream &O) { | |
222 | // Does this asm operand have a single letter operand modifier? | |
223 | if (ExtraCode && ExtraCode[0]) { | |
224 | if (ExtraCode[1] != 0) return true; // Unknown modifier. | |
225 | ||
226 | switch (ExtraCode[0]) { | |
227 | default: | |
228 | // See if this is a generic print operand | |
229 | return AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O); | |
230 | case 'a': // Print as a memory address. | |
231 | if (MI->getOperand(OpNum).isReg()) { | |
232 | O << "[" | |
233 | << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg()) | |
234 | << "]"; | |
235 | return false; | |
236 | } | |
237 | // Fallthrough | |
238 | case 'c': // Don't print "#" before an immediate operand. | |
239 | if (!MI->getOperand(OpNum).isImm()) | |
240 | return true; | |
241 | O << MI->getOperand(OpNum).getImm(); | |
242 | return false; | |
243 | case 'P': // Print a VFP double precision register. | |
244 | case 'q': // Print a NEON quad precision register. | |
245 | printOperand(MI, OpNum, O); | |
246 | return false; | |
247 | case 'y': // Print a VFP single precision register as indexed double. | |
248 | if (MI->getOperand(OpNum).isReg()) { | |
249 | unsigned Reg = MI->getOperand(OpNum).getReg(); | |
1a4d82fc | 250 | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); |
223e47cc LB |
251 | // Find the 'd' register that has this 's' register as a sub-register, |
252 | // and determine the lane number. | |
253 | for (MCSuperRegIterator SR(Reg, TRI); SR.isValid(); ++SR) { | |
254 | if (!ARM::DPRRegClass.contains(*SR)) | |
255 | continue; | |
256 | bool Lane0 = TRI->getSubReg(*SR, ARM::ssub_0) == Reg; | |
257 | O << ARMInstPrinter::getRegisterName(*SR) << (Lane0 ? "[0]" : "[1]"); | |
258 | return false; | |
259 | } | |
260 | } | |
261 | return true; | |
262 | case 'B': // Bitwise inverse of integer or symbol without a preceding #. | |
263 | if (!MI->getOperand(OpNum).isImm()) | |
264 | return true; | |
265 | O << ~(MI->getOperand(OpNum).getImm()); | |
266 | return false; | |
267 | case 'L': // The low 16 bits of an immediate constant. | |
268 | if (!MI->getOperand(OpNum).isImm()) | |
269 | return true; | |
270 | O << (MI->getOperand(OpNum).getImm() & 0xffff); | |
271 | return false; | |
272 | case 'M': { // A register range suitable for LDM/STM. | |
273 | if (!MI->getOperand(OpNum).isReg()) | |
274 | return true; | |
275 | const MachineOperand &MO = MI->getOperand(OpNum); | |
276 | unsigned RegBegin = MO.getReg(); | |
277 | // This takes advantage of the 2 operand-ness of ldm/stm and that we've | |
278 | // already got the operands in registers that are operands to the | |
279 | // inline asm statement. | |
1a4d82fc JJ |
280 | O << "{"; |
281 | if (ARM::GPRPairRegClass.contains(RegBegin)) { | |
282 | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); | |
283 | unsigned Reg0 = TRI->getSubReg(RegBegin, ARM::gsub_0); | |
284 | O << ARMInstPrinter::getRegisterName(Reg0) << ", "; | |
285 | RegBegin = TRI->getSubReg(RegBegin, ARM::gsub_1); | |
286 | } | |
287 | O << ARMInstPrinter::getRegisterName(RegBegin); | |
223e47cc LB |
288 | |
289 | // FIXME: The register allocator not only may not have given us the | |
290 | // registers in sequence, but may not be in ascending registers. This | |
291 | // will require changes in the register allocator that'll need to be | |
292 | // propagated down here if the operands change. | |
293 | unsigned RegOps = OpNum + 1; | |
294 | while (MI->getOperand(RegOps).isReg()) { | |
295 | O << ", " | |
296 | << ARMInstPrinter::getRegisterName(MI->getOperand(RegOps).getReg()); | |
297 | RegOps++; | |
298 | } | |
299 | ||
300 | O << "}"; | |
301 | ||
302 | return false; | |
303 | } | |
304 | case 'R': // The most significant register of a pair. | |
305 | case 'Q': { // The least significant register of a pair. | |
306 | if (OpNum == 0) | |
307 | return true; | |
308 | const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); | |
309 | if (!FlagsOP.isImm()) | |
310 | return true; | |
311 | unsigned Flags = FlagsOP.getImm(); | |
1a4d82fc JJ |
312 | |
313 | // This operand may not be the one that actually provides the register. If | |
314 | // it's tied to a previous one then we should refer instead to that one | |
315 | // for registers and their classes. | |
316 | unsigned TiedIdx; | |
317 | if (InlineAsm::isUseOperandTiedToDef(Flags, TiedIdx)) { | |
318 | for (OpNum = InlineAsm::MIOp_FirstOperand; TiedIdx; --TiedIdx) { | |
319 | unsigned OpFlags = MI->getOperand(OpNum).getImm(); | |
320 | OpNum += InlineAsm::getNumOperandRegisters(OpFlags) + 1; | |
321 | } | |
322 | Flags = MI->getOperand(OpNum).getImm(); | |
323 | ||
324 | // Later code expects OpNum to be pointing at the register rather than | |
325 | // the flags. | |
326 | OpNum += 1; | |
327 | } | |
328 | ||
223e47cc | 329 | unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); |
1a4d82fc JJ |
330 | unsigned RC; |
331 | InlineAsm::hasRegClassConstraint(Flags, RC); | |
332 | if (RC == ARM::GPRPairRegClassID) { | |
333 | if (NumVals != 1) | |
334 | return true; | |
335 | const MachineOperand &MO = MI->getOperand(OpNum); | |
336 | if (!MO.isReg()) | |
337 | return true; | |
338 | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); | |
339 | unsigned Reg = TRI->getSubReg(MO.getReg(), ExtraCode[0] == 'Q' ? | |
340 | ARM::gsub_0 : ARM::gsub_1); | |
341 | O << ARMInstPrinter::getRegisterName(Reg); | |
342 | return false; | |
343 | } | |
223e47cc LB |
344 | if (NumVals != 2) |
345 | return true; | |
346 | unsigned RegOp = ExtraCode[0] == 'Q' ? OpNum : OpNum + 1; | |
347 | if (RegOp >= MI->getNumOperands()) | |
348 | return true; | |
349 | const MachineOperand &MO = MI->getOperand(RegOp); | |
350 | if (!MO.isReg()) | |
351 | return true; | |
352 | unsigned Reg = MO.getReg(); | |
353 | O << ARMInstPrinter::getRegisterName(Reg); | |
354 | return false; | |
355 | } | |
356 | ||
357 | case 'e': // The low doubleword register of a NEON quad register. | |
358 | case 'f': { // The high doubleword register of a NEON quad register. | |
359 | if (!MI->getOperand(OpNum).isReg()) | |
360 | return true; | |
361 | unsigned Reg = MI->getOperand(OpNum).getReg(); | |
362 | if (!ARM::QPRRegClass.contains(Reg)) | |
363 | return true; | |
1a4d82fc | 364 | const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); |
223e47cc LB |
365 | unsigned SubReg = TRI->getSubReg(Reg, ExtraCode[0] == 'e' ? |
366 | ARM::dsub_0 : ARM::dsub_1); | |
367 | O << ARMInstPrinter::getRegisterName(SubReg); | |
368 | return false; | |
369 | } | |
370 | ||
371 | // This modifier is not yet supported. | |
372 | case 'h': // A range of VFP/NEON registers suitable for VLD1/VST1. | |
373 | return true; | |
374 | case 'H': { // The highest-numbered register of a pair. | |
375 | const MachineOperand &MO = MI->getOperand(OpNum); | |
376 | if (!MO.isReg()) | |
377 | return true; | |
223e47cc | 378 | const MachineFunction &MF = *MI->getParent()->getParent(); |
1a4d82fc | 379 | const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); |
970d7e83 LB |
380 | unsigned Reg = MO.getReg(); |
381 | if(!ARM::GPRPairRegClass.contains(Reg)) | |
382 | return false; | |
383 | Reg = TRI->getSubReg(Reg, ARM::gsub_1); | |
223e47cc LB |
384 | O << ARMInstPrinter::getRegisterName(Reg); |
385 | return false; | |
386 | } | |
387 | } | |
388 | } | |
389 | ||
390 | printOperand(MI, OpNum, O); | |
391 | return false; | |
392 | } | |
393 | ||
394 | bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, | |
395 | unsigned OpNum, unsigned AsmVariant, | |
396 | const char *ExtraCode, | |
397 | raw_ostream &O) { | |
398 | // Does this asm operand have a single letter operand modifier? | |
399 | if (ExtraCode && ExtraCode[0]) { | |
400 | if (ExtraCode[1] != 0) return true; // Unknown modifier. | |
401 | ||
402 | switch (ExtraCode[0]) { | |
403 | case 'A': // A memory operand for a VLD1/VST1 instruction. | |
404 | default: return true; // Unknown modifier. | |
405 | case 'm': // The base register of a memory operand. | |
406 | if (!MI->getOperand(OpNum).isReg()) | |
407 | return true; | |
408 | O << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg()); | |
409 | return false; | |
410 | } | |
411 | } | |
412 | ||
413 | const MachineOperand &MO = MI->getOperand(OpNum); | |
414 | assert(MO.isReg() && "unexpected inline asm memory operand"); | |
415 | O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()) << "]"; | |
416 | return false; | |
417 | } | |
418 | ||
1a4d82fc JJ |
419 | static bool isThumb(const MCSubtargetInfo& STI) { |
420 | return (STI.getFeatureBits() & ARM::ModeThumb) != 0; | |
421 | } | |
422 | ||
423 | void ARMAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, | |
424 | const MCSubtargetInfo *EndInfo) const { | |
425 | // If either end mode is unknown (EndInfo == NULL) or different than | |
426 | // the start mode, then restore the start mode. | |
427 | const bool WasThumb = isThumb(StartInfo); | |
428 | if (!EndInfo || WasThumb != isThumb(*EndInfo)) { | |
429 | OutStreamer.EmitAssemblerFlag(WasThumb ? MCAF_Code16 : MCAF_Code32); | |
430 | } | |
431 | } | |
432 | ||
223e47cc | 433 | void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { |
1a4d82fc | 434 | if (Subtarget->isTargetMachO()) { |
223e47cc LB |
435 | Reloc::Model RelocM = TM.getRelocationModel(); |
436 | if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) { | |
437 | // Declare all the text sections up front (before the DWARF sections | |
438 | // emitted by AsmPrinter::doInitialization) so the assembler will keep | |
439 | // them together at the beginning of the object file. This helps | |
440 | // avoid out-of-range branches that are due a fundamental limitation of | |
441 | // the way symbol offsets are encoded with the current Darwin ARM | |
442 | // relocations. | |
443 | const TargetLoweringObjectFileMachO &TLOFMacho = | |
444 | static_cast<const TargetLoweringObjectFileMachO &>( | |
445 | getObjFileLowering()); | |
970d7e83 LB |
446 | |
447 | // Collect the set of sections our functions will go into. | |
448 | SetVector<const MCSection *, SmallVector<const MCSection *, 8>, | |
449 | SmallPtrSet<const MCSection *, 8> > TextSections; | |
450 | // Default text section comes first. | |
451 | TextSections.insert(TLOFMacho.getTextSection()); | |
452 | // Now any user defined text sections from function attributes. | |
453 | for (Module::iterator F = M.begin(), e = M.end(); F != e; ++F) | |
454 | if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage()) | |
1a4d82fc | 455 | TextSections.insert(TLOFMacho.SectionForGlobal(F, *Mang, TM)); |
970d7e83 LB |
456 | // Now the coalescable sections. |
457 | TextSections.insert(TLOFMacho.getTextCoalSection()); | |
458 | TextSections.insert(TLOFMacho.getConstTextCoalSection()); | |
459 | ||
460 | // Emit the sections in the .s file header to fix the order. | |
461 | for (unsigned i = 0, e = TextSections.size(); i != e; ++i) | |
462 | OutStreamer.SwitchSection(TextSections[i]); | |
463 | ||
223e47cc LB |
464 | if (RelocM == Reloc::DynamicNoPIC) { |
465 | const MCSection *sect = | |
466 | OutContext.getMachOSection("__TEXT", "__symbol_stub4", | |
1a4d82fc | 467 | MachO::S_SYMBOL_STUBS, |
223e47cc LB |
468 | 12, SectionKind::getText()); |
469 | OutStreamer.SwitchSection(sect); | |
470 | } else { | |
471 | const MCSection *sect = | |
472 | OutContext.getMachOSection("__TEXT", "__picsymbolstub4", | |
1a4d82fc | 473 | MachO::S_SYMBOL_STUBS, |
223e47cc LB |
474 | 16, SectionKind::getText()); |
475 | OutStreamer.SwitchSection(sect); | |
476 | } | |
477 | const MCSection *StaticInitSect = | |
478 | OutContext.getMachOSection("__TEXT", "__StaticInit", | |
1a4d82fc JJ |
479 | MachO::S_REGULAR | |
480 | MachO::S_ATTR_PURE_INSTRUCTIONS, | |
223e47cc LB |
481 | SectionKind::getText()); |
482 | OutStreamer.SwitchSection(StaticInitSect); | |
483 | } | |
1a4d82fc JJ |
484 | |
485 | // Compiling with debug info should not affect the code | |
486 | // generation. Ensure the cstring section comes before the | |
487 | // optional __DWARF secion. Otherwise, PC-relative loads would | |
488 | // have to use different instruction sequences at "-g" in order to | |
489 | // reach global data in the same object file. | |
490 | OutStreamer.SwitchSection(getObjFileLowering().getCStringSection()); | |
223e47cc LB |
491 | } |
492 | ||
493 | // Use unified assembler syntax. | |
494 | OutStreamer.EmitAssemblerFlag(MCAF_SyntaxUnified); | |
495 | ||
496 | // Emit ARM Build Attributes | |
497 | if (Subtarget->isTargetELF()) | |
498 | emitAttributes(); | |
1a4d82fc JJ |
499 | |
500 | if (!M.getModuleInlineAsm().empty() && Subtarget->isThumb()) | |
501 | OutStreamer.EmitAssemblerFlag(MCAF_Code16); | |
502 | } | |
503 | ||
504 | static void | |
505 | emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, | |
506 | MachineModuleInfoImpl::StubValueTy &MCSym) { | |
507 | // L_foo$stub: | |
508 | OutStreamer.EmitLabel(StubLabel); | |
509 | // .indirect_symbol _foo | |
510 | OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol); | |
511 | ||
512 | if (MCSym.getInt()) | |
513 | // External to current translation unit. | |
514 | OutStreamer.EmitIntValue(0, 4/*size*/); | |
515 | else | |
516 | // Internal to current translation unit. | |
517 | // | |
518 | // When we place the LSDA into the TEXT section, the type info | |
519 | // pointers need to be indirect and pc-rel. We accomplish this by | |
520 | // using NLPs; however, sometimes the types are local to the file. | |
521 | // We need to fill in the value for the NLP in those cases. | |
522 | OutStreamer.EmitValue( | |
523 | MCSymbolRefExpr::Create(MCSym.getPointer(), OutStreamer.getContext()), | |
524 | 4 /*size*/); | |
223e47cc LB |
525 | } |
526 | ||
527 | ||
528 | void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { | |
1a4d82fc | 529 | if (Subtarget->isTargetMachO()) { |
223e47cc LB |
530 | // All darwin targets use mach-o. |
531 | const TargetLoweringObjectFileMachO &TLOFMacho = | |
532 | static_cast<const TargetLoweringObjectFileMachO &>(getObjFileLowering()); | |
533 | MachineModuleInfoMachO &MMIMacho = | |
534 | MMI->getObjFileInfo<MachineModuleInfoMachO>(); | |
535 | ||
536 | // Output non-lazy-pointers for external and common global variables. | |
537 | MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); | |
538 | ||
539 | if (!Stubs.empty()) { | |
540 | // Switch with ".non_lazy_symbol_pointer" directive. | |
541 | OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); | |
542 | EmitAlignment(2); | |
1a4d82fc JJ |
543 | |
544 | for (auto &Stub : Stubs) | |
545 | emitNonLazySymbolPointer(OutStreamer, Stub.first, Stub.second); | |
223e47cc LB |
546 | |
547 | Stubs.clear(); | |
548 | OutStreamer.AddBlankLine(); | |
549 | } | |
550 | ||
551 | Stubs = MMIMacho.GetHiddenGVStubList(); | |
552 | if (!Stubs.empty()) { | |
1a4d82fc | 553 | OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); |
223e47cc | 554 | EmitAlignment(2); |
1a4d82fc JJ |
555 | |
556 | for (auto &Stub : Stubs) | |
557 | emitNonLazySymbolPointer(OutStreamer, Stub.first, Stub.second); | |
223e47cc LB |
558 | |
559 | Stubs.clear(); | |
560 | OutStreamer.AddBlankLine(); | |
561 | } | |
562 | ||
563 | // Funny Darwin hack: This flag tells the linker that no global symbols | |
564 | // contain code that falls through to other global symbols (e.g. the obvious | |
565 | // implementation of multiple entry points). If this doesn't occur, the | |
566 | // linker can safely perform dead code stripping. Since LLVM never | |
567 | // generates code that does this, it is always safe to set. | |
568 | OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); | |
569 | } | |
1a4d82fc JJ |
570 | |
571 | // Emit a .data.rel section containing any stubs that were created. | |
572 | if (Subtarget->isTargetELF()) { | |
573 | const TargetLoweringObjectFileELF &TLOFELF = | |
574 | static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); | |
575 | ||
576 | MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); | |
577 | ||
578 | // Output stubs for external and common global variables. | |
579 | MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); | |
580 | if (!Stubs.empty()) { | |
581 | OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); | |
582 | const DataLayout *TD = TM.getSubtargetImpl()->getDataLayout(); | |
583 | ||
584 | for (auto &stub: Stubs) { | |
585 | OutStreamer.EmitLabel(stub.first); | |
586 | OutStreamer.EmitSymbolValue(stub.second.getPointer(), | |
587 | TD->getPointerSize(0)); | |
588 | } | |
589 | Stubs.clear(); | |
590 | } | |
591 | } | |
223e47cc LB |
592 | } |
593 | ||
594 | //===----------------------------------------------------------------------===// | |
595 | // Helper routines for EmitStartOfAsmFile() and EmitEndOfAsmFile() | |
596 | // FIXME: | |
597 | // The following seem like one-off assembler flags, but they actually need | |
598 | // to appear in the .ARM.attributes section in ELF. | |
599 | // Instead of subclassing the MCELFStreamer, we do the work here. | |
600 | ||
1a4d82fc JJ |
601 | static ARMBuildAttrs::CPUArch getArchForCPU(StringRef CPU, |
602 | const ARMSubtarget *Subtarget) { | |
603 | if (CPU == "xscale") | |
604 | return ARMBuildAttrs::v5TEJ; | |
605 | ||
606 | if (Subtarget->hasV8Ops()) | |
607 | return ARMBuildAttrs::v8; | |
608 | else if (Subtarget->hasV7Ops()) { | |
609 | if (Subtarget->isMClass() && Subtarget->hasThumb2DSP()) | |
610 | return ARMBuildAttrs::v7E_M; | |
611 | return ARMBuildAttrs::v7; | |
970d7e83 | 612 | } else if (Subtarget->hasV6T2Ops()) |
1a4d82fc JJ |
613 | return ARMBuildAttrs::v6T2; |
614 | else if (Subtarget->hasV6MOps()) | |
615 | return ARMBuildAttrs::v6S_M; | |
970d7e83 | 616 | else if (Subtarget->hasV6Ops()) |
1a4d82fc | 617 | return ARMBuildAttrs::v6; |
970d7e83 | 618 | else if (Subtarget->hasV5TEOps()) |
1a4d82fc | 619 | return ARMBuildAttrs::v5TE; |
970d7e83 | 620 | else if (Subtarget->hasV5TOps()) |
1a4d82fc | 621 | return ARMBuildAttrs::v5T; |
970d7e83 | 622 | else if (Subtarget->hasV4TOps()) |
1a4d82fc JJ |
623 | return ARMBuildAttrs::v4T; |
624 | else | |
625 | return ARMBuildAttrs::v4; | |
626 | } | |
223e47cc | 627 | |
1a4d82fc JJ |
628 | void ARMAsmPrinter::emitAttributes() { |
629 | MCTargetStreamer &TS = *OutStreamer.getTargetStreamer(); | |
630 | ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS); | |
631 | ||
85aaf69f SL |
632 | ATS.emitTextAttribute(ARMBuildAttrs::conformance, "2.09"); |
633 | ||
1a4d82fc JJ |
634 | ATS.switchVendor("aeabi"); |
635 | ||
636 | std::string CPUString = Subtarget->getCPUString(); | |
637 | ||
638 | // FIXME: remove krait check when GNU tools support krait cpu | |
639 | if (CPUString != "generic" && CPUString != "krait") | |
640 | ATS.emitTextAttribute(ARMBuildAttrs::CPU_name, CPUString); | |
641 | ||
642 | ATS.emitAttribute(ARMBuildAttrs::CPU_arch, | |
643 | getArchForCPU(CPUString, Subtarget)); | |
644 | ||
645 | // Tag_CPU_arch_profile must have the default value of 0 when "Architecture | |
646 | // profile is not applicable (e.g. pre v7, or cross-profile code)". | |
647 | if (Subtarget->hasV7Ops()) { | |
648 | if (Subtarget->isAClass()) { | |
649 | ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile, | |
650 | ARMBuildAttrs::ApplicationProfile); | |
651 | } else if (Subtarget->isRClass()) { | |
652 | ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile, | |
653 | ARMBuildAttrs::RealTimeProfile); | |
654 | } else if (Subtarget->isMClass()) { | |
655 | ATS.emitAttribute(ARMBuildAttrs::CPU_arch_profile, | |
656 | ARMBuildAttrs::MicroControllerProfile); | |
657 | } | |
223e47cc LB |
658 | } |
659 | ||
1a4d82fc JJ |
660 | ATS.emitAttribute(ARMBuildAttrs::ARM_ISA_use, Subtarget->hasARMOps() ? |
661 | ARMBuildAttrs::Allowed : ARMBuildAttrs::Not_Allowed); | |
662 | if (Subtarget->isThumb1Only()) { | |
663 | ATS.emitAttribute(ARMBuildAttrs::THUMB_ISA_use, | |
664 | ARMBuildAttrs::Allowed); | |
665 | } else if (Subtarget->hasThumb2()) { | |
666 | ATS.emitAttribute(ARMBuildAttrs::THUMB_ISA_use, | |
667 | ARMBuildAttrs::AllowThumb32); | |
223e47cc LB |
668 | } |
669 | ||
223e47cc | 670 | if (Subtarget->hasNEON()) { |
1a4d82fc JJ |
671 | /* NEON is not exactly a VFP architecture, but GAS emit one of |
672 | * neon/neon-fp-armv8/neon-vfpv4/vfpv3/vfpv2 for .fpu parameters */ | |
673 | if (Subtarget->hasFPARMv8()) { | |
674 | if (Subtarget->hasCrypto()) | |
675 | ATS.emitFPU(ARM::CRYPTO_NEON_FP_ARMV8); | |
676 | else | |
677 | ATS.emitFPU(ARM::NEON_FP_ARMV8); | |
678 | } | |
679 | else if (Subtarget->hasVFP4()) | |
680 | ATS.emitFPU(ARM::NEON_VFPV4); | |
681 | else | |
682 | ATS.emitFPU(ARM::NEON); | |
683 | // Emit Tag_Advanced_SIMD_arch for ARMv8 architecture | |
684 | if (Subtarget->hasV8Ops()) | |
685 | ATS.emitAttribute(ARMBuildAttrs::Advanced_SIMD_arch, | |
686 | ARMBuildAttrs::AllowNeonARMv8); | |
687 | } else { | |
688 | if (Subtarget->hasFPARMv8()) | |
689 | // FPv5 and FP-ARMv8 have the same instructions, so are modeled as one | |
690 | // FPU, but there are two different names for it depending on the CPU. | |
691 | ATS.emitFPU(Subtarget->hasD16() ? ARM::FPV5_D16 : ARM::FP_ARMV8); | |
692 | else if (Subtarget->hasVFP4()) | |
693 | ATS.emitFPU(Subtarget->hasD16() ? ARM::VFPV4_D16 : ARM::VFPV4); | |
694 | else if (Subtarget->hasVFP3()) | |
695 | ATS.emitFPU(Subtarget->hasD16() ? ARM::VFPV3_D16 : ARM::VFPV3); | |
696 | else if (Subtarget->hasVFP2()) | |
697 | ATS.emitFPU(ARM::VFPV2); | |
698 | } | |
699 | ||
700 | if (TM.getRelocationModel() == Reloc::PIC_) { | |
701 | // PIC specific attributes. | |
702 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data, | |
703 | ARMBuildAttrs::AddressRWPCRel); | |
704 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RO_data, | |
705 | ARMBuildAttrs::AddressROPCRel); | |
706 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use, | |
707 | ARMBuildAttrs::AddressGOT); | |
708 | } else { | |
709 | // Allow direct addressing of imported data for all other relocation models. | |
710 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use, | |
711 | ARMBuildAttrs::AddressDirect); | |
223e47cc LB |
712 | } |
713 | ||
714 | // Signal various FP modes. | |
715 | if (!TM.Options.UnsafeFPMath) { | |
85aaf69f SL |
716 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal, |
717 | ARMBuildAttrs::IEEEDenormals); | |
1a4d82fc JJ |
718 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_exceptions, |
719 | ARMBuildAttrs::Allowed); | |
85aaf69f SL |
720 | |
721 | // If the user has permitted this code to choose the IEEE 754 | |
722 | // rounding at run-time, emit the rounding attribute. | |
723 | if (TM.Options.HonorSignDependentRoundingFPMathOption) | |
724 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_rounding, | |
725 | ARMBuildAttrs::Allowed); | |
726 | } else { | |
727 | if (!Subtarget->hasVFP2()) { | |
728 | // When the target doesn't have an FPU (by design or | |
729 | // intention), the assumptions made on the software support | |
730 | // mirror that of the equivalent hardware support *if it | |
731 | // existed*. For v7 and better we indicate that denormals are | |
732 | // flushed preserving sign, and for V6 we indicate that | |
733 | // denormals are flushed to positive zero. | |
734 | if (Subtarget->hasV7Ops()) | |
735 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal, | |
736 | ARMBuildAttrs::PreserveFPSign); | |
737 | } else if (Subtarget->hasVFP3()) { | |
738 | // In VFPv4, VFPv4U, VFPv3, or VFPv3U, it is preserved. That is, | |
739 | // the sign bit of the zero matches the sign bit of the input or | |
740 | // result that is being flushed to zero. | |
741 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_denormal, | |
742 | ARMBuildAttrs::PreserveFPSign); | |
743 | } | |
744 | // For VFPv2 implementations it is implementation defined as | |
745 | // to whether denormals are flushed to positive zero or to | |
746 | // whatever the sign of zero is (ARM v7AR ARM 2.7.5). Historically | |
747 | // LLVM has chosen to flush this to positive zero (most likely for | |
748 | // GCC compatibility), so that's the chosen value here (the | |
749 | // absence of its emission implies zero). | |
223e47cc LB |
750 | } |
751 | ||
85aaf69f SL |
752 | // TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath is the |
753 | // equivalent of GCC's -ffinite-math-only flag. | |
223e47cc | 754 | if (TM.Options.NoInfsFPMath && TM.Options.NoNaNsFPMath) |
1a4d82fc JJ |
755 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model, |
756 | ARMBuildAttrs::Allowed); | |
223e47cc | 757 | else |
1a4d82fc JJ |
758 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_number_model, |
759 | ARMBuildAttrs::AllowIEE754); | |
223e47cc | 760 | |
85aaf69f SL |
761 | if (Subtarget->allowsUnalignedMem()) |
762 | ATS.emitAttribute(ARMBuildAttrs::CPU_unaligned_access, | |
763 | ARMBuildAttrs::Allowed); | |
764 | else | |
765 | ATS.emitAttribute(ARMBuildAttrs::CPU_unaligned_access, | |
766 | ARMBuildAttrs::Not_Allowed); | |
767 | ||
1a4d82fc | 768 | // FIXME: add more flags to ARMBuildAttributes.h |
223e47cc | 769 | // 8-bytes alignment stuff. |
1a4d82fc JJ |
770 | ATS.emitAttribute(ARMBuildAttrs::ABI_align_needed, 1); |
771 | ATS.emitAttribute(ARMBuildAttrs::ABI_align_preserved, 1); | |
223e47cc | 772 | |
1a4d82fc JJ |
773 | // ABI_HardFP_use attribute to indicate single precision FP. |
774 | if (Subtarget->isFPOnlySP()) | |
775 | ATS.emitAttribute(ARMBuildAttrs::ABI_HardFP_use, | |
776 | ARMBuildAttrs::HardFPSinglePrecision); | |
223e47cc | 777 | |
1a4d82fc JJ |
778 | // Hard float. Use both S and D registers and conform to AAPCS-VFP. |
779 | if (Subtarget->isAAPCS_ABI() && TM.Options.FloatABIType == FloatABI::Hard) | |
780 | ATS.emitAttribute(ARMBuildAttrs::ABI_VFP_args, ARMBuildAttrs::HardFPAAPCS); | |
223e47cc | 781 | |
1a4d82fc | 782 | // FIXME: Should we signal R9 usage? |
223e47cc | 783 | |
1a4d82fc JJ |
784 | if (Subtarget->hasFP16()) |
785 | ATS.emitAttribute(ARMBuildAttrs::FP_HP_extension, ARMBuildAttrs::AllowHPFP); | |
786 | ||
85aaf69f SL |
787 | // FIXME: To support emitting this build attribute as GCC does, the |
788 | // -mfp16-format option and associated plumbing must be | |
789 | // supported. For now the __fp16 type is exposed by default, so this | |
790 | // attribute should be emitted with value 1. | |
791 | ATS.emitAttribute(ARMBuildAttrs::ABI_FP_16bit_format, | |
792 | ARMBuildAttrs::FP16FormatIEEE); | |
793 | ||
1a4d82fc JJ |
794 | if (Subtarget->hasMPExtension()) |
795 | ATS.emitAttribute(ARMBuildAttrs::MPextension_use, ARMBuildAttrs::AllowMP); | |
796 | ||
797 | // Hardware divide in ARM mode is part of base arch, starting from ARMv8. | |
798 | // If only Thumb hwdiv is present, it must also be in base arch (ARMv7-R/M). | |
799 | // It is not possible to produce DisallowDIV: if hwdiv is present in the base | |
800 | // arch, supplying -hwdiv downgrades the effective arch, via ClearImpliedBits. | |
801 | // AllowDIVExt is only emitted if hwdiv isn't available in the base arch; | |
802 | // otherwise, the default value (AllowDIVIfExists) applies. | |
803 | if (Subtarget->hasDivideInARMMode() && !Subtarget->hasV8Ops()) | |
804 | ATS.emitAttribute(ARMBuildAttrs::DIV_use, ARMBuildAttrs::AllowDIVExt); | |
805 | ||
806 | if (MMI) { | |
807 | if (const Module *SourceModule = MMI->getModule()) { | |
808 | // ABI_PCS_wchar_t to indicate wchar_t width | |
809 | // FIXME: There is no way to emit value 0 (wchar_t prohibited). | |
85aaf69f | 810 | if (auto WCharWidthValue = mdconst::extract_or_null<ConstantInt>( |
1a4d82fc JJ |
811 | SourceModule->getModuleFlag("wchar_size"))) { |
812 | int WCharWidth = WCharWidthValue->getZExtValue(); | |
813 | assert((WCharWidth == 2 || WCharWidth == 4) && | |
814 | "wchar_t width must be 2 or 4 bytes"); | |
815 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_wchar_t, WCharWidth); | |
816 | } | |
223e47cc | 817 | |
1a4d82fc JJ |
818 | // ABI_enum_size to indicate enum width |
819 | // FIXME: There is no way to emit value 0 (enums prohibited) or value 3 | |
820 | // (all enums contain a value needing 32 bits to encode). | |
85aaf69f | 821 | if (auto EnumWidthValue = mdconst::extract_or_null<ConstantInt>( |
1a4d82fc JJ |
822 | SourceModule->getModuleFlag("min_enum_size"))) { |
823 | int EnumWidth = EnumWidthValue->getZExtValue(); | |
824 | assert((EnumWidth == 1 || EnumWidth == 4) && | |
825 | "Minimum enum width must be 1 or 4 bytes"); | |
826 | int EnumBuildAttr = EnumWidth == 1 ? 1 : 2; | |
827 | ATS.emitAttribute(ARMBuildAttrs::ABI_enum_size, EnumBuildAttr); | |
828 | } | |
829 | } | |
830 | } | |
223e47cc | 831 | |
1a4d82fc JJ |
832 | // TODO: We currently only support either reserving the register, or treating |
833 | // it as another callee-saved register, but not as SB or a TLS pointer; It | |
834 | // would instead be nicer to push this from the frontend as metadata, as we do | |
835 | // for the wchar and enum size tags | |
836 | if (Subtarget->isR9Reserved()) | |
837 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, | |
838 | ARMBuildAttrs::R9Reserved); | |
839 | else | |
840 | ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, | |
841 | ARMBuildAttrs::R9IsGPR); | |
842 | ||
843 | if (Subtarget->hasTrustZone() && Subtarget->hasVirtualization()) | |
844 | ATS.emitAttribute(ARMBuildAttrs::Virtualization_use, | |
845 | ARMBuildAttrs::AllowTZVirtualization); | |
846 | else if (Subtarget->hasTrustZone()) | |
847 | ATS.emitAttribute(ARMBuildAttrs::Virtualization_use, | |
848 | ARMBuildAttrs::AllowTZ); | |
849 | else if (Subtarget->hasVirtualization()) | |
850 | ATS.emitAttribute(ARMBuildAttrs::Virtualization_use, | |
851 | ARMBuildAttrs::AllowVirtualization); | |
852 | ||
853 | ATS.finishAttributeSection(); | |
223e47cc LB |
854 | } |
855 | ||
856 | //===----------------------------------------------------------------------===// | |
857 | ||
858 | static MCSymbol *getPICLabel(const char *Prefix, unsigned FunctionNumber, | |
859 | unsigned LabelId, MCContext &Ctx) { | |
860 | ||
861 | MCSymbol *Label = Ctx.GetOrCreateSymbol(Twine(Prefix) | |
862 | + "PC" + Twine(FunctionNumber) + "_" + Twine(LabelId)); | |
863 | return Label; | |
864 | } | |
865 | ||
866 | static MCSymbolRefExpr::VariantKind | |
867 | getModifierVariantKind(ARMCP::ARMCPModifier Modifier) { | |
868 | switch (Modifier) { | |
869 | case ARMCP::no_modifier: return MCSymbolRefExpr::VK_None; | |
1a4d82fc JJ |
870 | case ARMCP::TLSGD: return MCSymbolRefExpr::VK_TLSGD; |
871 | case ARMCP::TPOFF: return MCSymbolRefExpr::VK_TPOFF; | |
872 | case ARMCP::GOTTPOFF: return MCSymbolRefExpr::VK_GOTTPOFF; | |
873 | case ARMCP::GOT: return MCSymbolRefExpr::VK_GOT; | |
874 | case ARMCP::GOTOFF: return MCSymbolRefExpr::VK_GOTOFF; | |
223e47cc LB |
875 | } |
876 | llvm_unreachable("Invalid ARMCPModifier!"); | |
877 | } | |
878 | ||
1a4d82fc JJ |
879 | MCSymbol *ARMAsmPrinter::GetARMGVSymbol(const GlobalValue *GV, |
880 | unsigned char TargetFlags) { | |
881 | if (Subtarget->isTargetMachO()) { | |
882 | bool IsIndirect = (TargetFlags & ARMII::MO_NONLAZY) && | |
883 | Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); | |
884 | ||
885 | if (!IsIndirect) | |
886 | return getSymbol(GV); | |
887 | ||
888 | // FIXME: Remove this when Darwin transition to @GOT like syntax. | |
889 | MCSymbol *MCSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); | |
890 | MachineModuleInfoMachO &MMIMachO = | |
891 | MMI->getObjFileInfo<MachineModuleInfoMachO>(); | |
892 | MachineModuleInfoImpl::StubValueTy &StubSym = | |
893 | GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(MCSym) | |
894 | : MMIMachO.getGVStubEntry(MCSym); | |
895 | if (!StubSym.getPointer()) | |
896 | StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV), | |
897 | !GV->hasInternalLinkage()); | |
898 | return MCSym; | |
899 | } else if (Subtarget->isTargetCOFF()) { | |
900 | assert(Subtarget->isTargetWindows() && | |
901 | "Windows is the only supported COFF target"); | |
902 | ||
903 | bool IsIndirect = (TargetFlags & ARMII::MO_DLLIMPORT); | |
904 | if (!IsIndirect) | |
905 | return getSymbol(GV); | |
906 | ||
907 | SmallString<128> Name; | |
908 | Name = "__imp_"; | |
909 | getNameWithPrefix(Name, GV); | |
910 | ||
911 | return OutContext.GetOrCreateSymbol(Name); | |
912 | } else if (Subtarget->isTargetELF()) { | |
913 | return getSymbol(GV); | |
914 | } | |
915 | llvm_unreachable("unexpected target"); | |
223e47cc LB |
916 | } |
917 | ||
918 | void ARMAsmPrinter:: | |
919 | EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { | |
1a4d82fc JJ |
920 | const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); |
921 | int Size = | |
922 | TM.getSubtargetImpl()->getDataLayout()->getTypeAllocSize(MCPV->getType()); | |
223e47cc LB |
923 | |
924 | ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV); | |
925 | ||
926 | MCSymbol *MCSym; | |
927 | if (ACPV->isLSDA()) { | |
928 | SmallString<128> Str; | |
929 | raw_svector_ostream OS(Str); | |
1a4d82fc | 930 | OS << DL->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); |
223e47cc LB |
931 | MCSym = OutContext.GetOrCreateSymbol(OS.str()); |
932 | } else if (ACPV->isBlockAddress()) { | |
933 | const BlockAddress *BA = | |
934 | cast<ARMConstantPoolConstant>(ACPV)->getBlockAddress(); | |
935 | MCSym = GetBlockAddressSymbol(BA); | |
936 | } else if (ACPV->isGlobalValue()) { | |
937 | const GlobalValue *GV = cast<ARMConstantPoolConstant>(ACPV)->getGV(); | |
1a4d82fc JJ |
938 | |
939 | // On Darwin, const-pool entries may get the "FOO$non_lazy_ptr" mangling, so | |
940 | // flag the global as MO_NONLAZY. | |
941 | unsigned char TF = Subtarget->isTargetMachO() ? ARMII::MO_NONLAZY : 0; | |
942 | MCSym = GetARMGVSymbol(GV, TF); | |
223e47cc LB |
943 | } else if (ACPV->isMachineBasicBlock()) { |
944 | const MachineBasicBlock *MBB = cast<ARMConstantPoolMBB>(ACPV)->getMBB(); | |
945 | MCSym = MBB->getSymbol(); | |
946 | } else { | |
947 | assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); | |
948 | const char *Sym = cast<ARMConstantPoolSymbol>(ACPV)->getSymbol(); | |
949 | MCSym = GetExternalSymbolSymbol(Sym); | |
950 | } | |
951 | ||
952 | // Create an MCSymbol for the reference. | |
953 | const MCExpr *Expr = | |
954 | MCSymbolRefExpr::Create(MCSym, getModifierVariantKind(ACPV->getModifier()), | |
955 | OutContext); | |
956 | ||
957 | if (ACPV->getPCAdjustment()) { | |
1a4d82fc | 958 | MCSymbol *PCLabel = getPICLabel(DL->getPrivateGlobalPrefix(), |
223e47cc LB |
959 | getFunctionNumber(), |
960 | ACPV->getLabelId(), | |
961 | OutContext); | |
962 | const MCExpr *PCRelExpr = MCSymbolRefExpr::Create(PCLabel, OutContext); | |
963 | PCRelExpr = | |
964 | MCBinaryExpr::CreateAdd(PCRelExpr, | |
965 | MCConstantExpr::Create(ACPV->getPCAdjustment(), | |
966 | OutContext), | |
967 | OutContext); | |
968 | if (ACPV->mustAddCurrentAddress()) { | |
969 | // We want "(<expr> - .)", but MC doesn't have a concept of the '.' | |
970 | // label, so just emit a local label end reference that instead. | |
971 | MCSymbol *DotSym = OutContext.CreateTempSymbol(); | |
972 | OutStreamer.EmitLabel(DotSym); | |
973 | const MCExpr *DotExpr = MCSymbolRefExpr::Create(DotSym, OutContext); | |
974 | PCRelExpr = MCBinaryExpr::CreateSub(PCRelExpr, DotExpr, OutContext); | |
975 | } | |
976 | Expr = MCBinaryExpr::CreateSub(Expr, PCRelExpr, OutContext); | |
977 | } | |
978 | OutStreamer.EmitValue(Expr, Size); | |
979 | } | |
980 | ||
981 | void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) { | |
982 | unsigned Opcode = MI->getOpcode(); | |
983 | int OpNum = 1; | |
984 | if (Opcode == ARM::BR_JTadd) | |
985 | OpNum = 2; | |
986 | else if (Opcode == ARM::BR_JTm) | |
987 | OpNum = 3; | |
988 | ||
989 | const MachineOperand &MO1 = MI->getOperand(OpNum); | |
990 | const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id | |
991 | unsigned JTI = MO1.getIndex(); | |
992 | ||
993 | // Emit a label for the jump table. | |
994 | MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); | |
995 | OutStreamer.EmitLabel(JTISymbol); | |
996 | ||
997 | // Mark the jump table as data-in-code. | |
998 | OutStreamer.EmitDataRegion(MCDR_DataRegionJT32); | |
999 | ||
1000 | // Emit each entry of the table. | |
1001 | const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); | |
1002 | const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); | |
1003 | const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; | |
1004 | ||
1005 | for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { | |
1006 | MachineBasicBlock *MBB = JTBBs[i]; | |
1007 | // Construct an MCExpr for the entry. We want a value of the form: | |
1008 | // (BasicBlockAddr - TableBeginAddr) | |
1009 | // | |
1010 | // For example, a table with entries jumping to basic blocks BB0 and BB1 | |
1011 | // would look like: | |
1012 | // LJTI_0_0: | |
1013 | // .word (LBB0 - LJTI_0_0) | |
1014 | // .word (LBB1 - LJTI_0_0) | |
1015 | const MCExpr *Expr = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); | |
1016 | ||
1017 | if (TM.getRelocationModel() == Reloc::PIC_) | |
1018 | Expr = MCBinaryExpr::CreateSub(Expr, MCSymbolRefExpr::Create(JTISymbol, | |
1019 | OutContext), | |
1020 | OutContext); | |
1021 | // If we're generating a table of Thumb addresses in static relocation | |
1022 | // model, we need to add one to keep interworking correctly. | |
1023 | else if (AFI->isThumbFunction()) | |
1024 | Expr = MCBinaryExpr::CreateAdd(Expr, MCConstantExpr::Create(1,OutContext), | |
1025 | OutContext); | |
1026 | OutStreamer.EmitValue(Expr, 4); | |
1027 | } | |
1028 | // Mark the end of jump table data-in-code region. | |
1029 | OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); | |
1030 | } | |
1031 | ||
1032 | void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) { | |
1033 | unsigned Opcode = MI->getOpcode(); | |
1034 | int OpNum = (Opcode == ARM::t2BR_JT) ? 2 : 1; | |
1035 | const MachineOperand &MO1 = MI->getOperand(OpNum); | |
1036 | const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id | |
1037 | unsigned JTI = MO1.getIndex(); | |
1038 | ||
1039 | MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); | |
1040 | OutStreamer.EmitLabel(JTISymbol); | |
1041 | ||
1042 | // Emit each entry of the table. | |
1043 | const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); | |
1044 | const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); | |
1045 | const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; | |
1046 | unsigned OffsetWidth = 4; | |
1047 | if (MI->getOpcode() == ARM::t2TBB_JT) { | |
1048 | OffsetWidth = 1; | |
1049 | // Mark the jump table as data-in-code. | |
1050 | OutStreamer.EmitDataRegion(MCDR_DataRegionJT8); | |
1051 | } else if (MI->getOpcode() == ARM::t2TBH_JT) { | |
1052 | OffsetWidth = 2; | |
1053 | // Mark the jump table as data-in-code. | |
1054 | OutStreamer.EmitDataRegion(MCDR_DataRegionJT16); | |
1055 | } | |
1056 | ||
1057 | for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { | |
1058 | MachineBasicBlock *MBB = JTBBs[i]; | |
1059 | const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::Create(MBB->getSymbol(), | |
1a4d82fc | 1060 | OutContext); |
223e47cc LB |
1061 | // If this isn't a TBB or TBH, the entries are direct branch instructions. |
1062 | if (OffsetWidth == 4) { | |
1a4d82fc | 1063 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::t2B) |
970d7e83 LB |
1064 | .addExpr(MBBSymbolExpr) |
1065 | .addImm(ARMCC::AL) | |
1066 | .addReg(0)); | |
223e47cc LB |
1067 | continue; |
1068 | } | |
1069 | // Otherwise it's an offset from the dispatch instruction. Construct an | |
1070 | // MCExpr for the entry. We want a value of the form: | |
1071 | // (BasicBlockAddr - TableBeginAddr) / 2 | |
1072 | // | |
1073 | // For example, a TBB table with entries jumping to basic blocks BB0 and BB1 | |
1074 | // would look like: | |
1075 | // LJTI_0_0: | |
1076 | // .byte (LBB0 - LJTI_0_0) / 2 | |
1077 | // .byte (LBB1 - LJTI_0_0) / 2 | |
1078 | const MCExpr *Expr = | |
1079 | MCBinaryExpr::CreateSub(MBBSymbolExpr, | |
1080 | MCSymbolRefExpr::Create(JTISymbol, OutContext), | |
1081 | OutContext); | |
1082 | Expr = MCBinaryExpr::CreateDiv(Expr, MCConstantExpr::Create(2, OutContext), | |
1083 | OutContext); | |
1084 | OutStreamer.EmitValue(Expr, OffsetWidth); | |
1085 | } | |
1086 | // Mark the end of jump table data-in-code region. 32-bit offsets use | |
1087 | // actual branch instructions here, so we don't mark those as a data-region | |
1088 | // at all. | |
1089 | if (OffsetWidth != 4) | |
1090 | OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); | |
1091 | } | |
1092 | ||
223e47cc LB |
1093 | void ARMAsmPrinter::EmitUnwindingInstruction(const MachineInstr *MI) { |
1094 | assert(MI->getFlag(MachineInstr::FrameSetup) && | |
1095 | "Only instruction which are involved into frame setup code are allowed"); | |
1096 | ||
1a4d82fc JJ |
1097 | MCTargetStreamer &TS = *OutStreamer.getTargetStreamer(); |
1098 | ARMTargetStreamer &ATS = static_cast<ARMTargetStreamer &>(TS); | |
223e47cc | 1099 | const MachineFunction &MF = *MI->getParent()->getParent(); |
1a4d82fc | 1100 | const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); |
223e47cc LB |
1101 | const ARMFunctionInfo &AFI = *MF.getInfo<ARMFunctionInfo>(); |
1102 | ||
1103 | unsigned FramePtr = RegInfo->getFrameRegister(MF); | |
1104 | unsigned Opc = MI->getOpcode(); | |
1105 | unsigned SrcReg, DstReg; | |
1106 | ||
1107 | if (Opc == ARM::tPUSH || Opc == ARM::tLDRpci) { | |
1108 | // Two special cases: | |
1109 | // 1) tPUSH does not have src/dst regs. | |
1110 | // 2) for Thumb1 code we sometimes materialize the constant via constpool | |
1111 | // load. Yes, this is pretty fragile, but for now I don't see better | |
1112 | // way... :( | |
1113 | SrcReg = DstReg = ARM::SP; | |
1114 | } else { | |
1115 | SrcReg = MI->getOperand(1).getReg(); | |
1116 | DstReg = MI->getOperand(0).getReg(); | |
1117 | } | |
1118 | ||
1119 | // Try to figure out the unwinding opcode out of src / dst regs. | |
1120 | if (MI->mayStore()) { | |
1121 | // Register saves. | |
1122 | assert(DstReg == ARM::SP && | |
1123 | "Only stack pointer as a destination reg is supported"); | |
1124 | ||
1125 | SmallVector<unsigned, 4> RegList; | |
1126 | // Skip src & dst reg, and pred ops. | |
1127 | unsigned StartOp = 2 + 2; | |
1128 | // Use all the operands. | |
1129 | unsigned NumOffset = 0; | |
1130 | ||
1131 | switch (Opc) { | |
1132 | default: | |
1133 | MI->dump(); | |
1134 | llvm_unreachable("Unsupported opcode for unwinding information"); | |
1135 | case ARM::tPUSH: | |
1136 | // Special case here: no src & dst reg, but two extra imp ops. | |
1137 | StartOp = 2; NumOffset = 2; | |
1138 | case ARM::STMDB_UPD: | |
1139 | case ARM::t2STMDB_UPD: | |
1140 | case ARM::VSTMDDB_UPD: | |
1141 | assert(SrcReg == ARM::SP && | |
1142 | "Only stack pointer as a source reg is supported"); | |
1143 | for (unsigned i = StartOp, NumOps = MI->getNumOperands() - NumOffset; | |
1144 | i != NumOps; ++i) { | |
1145 | const MachineOperand &MO = MI->getOperand(i); | |
1146 | // Actually, there should never be any impdef stuff here. Skip it | |
1147 | // temporary to workaround PR11902. | |
1148 | if (MO.isImplicit()) | |
1149 | continue; | |
1150 | RegList.push_back(MO.getReg()); | |
1151 | } | |
1152 | break; | |
1153 | case ARM::STR_PRE_IMM: | |
1154 | case ARM::STR_PRE_REG: | |
1155 | case ARM::t2STR_PRE: | |
1156 | assert(MI->getOperand(2).getReg() == ARM::SP && | |
1157 | "Only stack pointer as a source reg is supported"); | |
1158 | RegList.push_back(SrcReg); | |
1159 | break; | |
1160 | } | |
1a4d82fc JJ |
1161 | if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) |
1162 | ATS.emitRegSave(RegList, Opc == ARM::VSTMDDB_UPD); | |
223e47cc LB |
1163 | } else { |
1164 | // Changes of stack / frame pointer. | |
1165 | if (SrcReg == ARM::SP) { | |
1166 | int64_t Offset = 0; | |
1167 | switch (Opc) { | |
1168 | default: | |
1169 | MI->dump(); | |
1170 | llvm_unreachable("Unsupported opcode for unwinding information"); | |
1171 | case ARM::MOVr: | |
1172 | case ARM::tMOVr: | |
1173 | Offset = 0; | |
1174 | break; | |
1175 | case ARM::ADDri: | |
1176 | Offset = -MI->getOperand(2).getImm(); | |
1177 | break; | |
1178 | case ARM::SUBri: | |
1179 | case ARM::t2SUBri: | |
1180 | Offset = MI->getOperand(2).getImm(); | |
1181 | break; | |
1182 | case ARM::tSUBspi: | |
1183 | Offset = MI->getOperand(2).getImm()*4; | |
1184 | break; | |
1185 | case ARM::tADDspi: | |
1186 | case ARM::tADDrSPi: | |
1187 | Offset = -MI->getOperand(2).getImm()*4; | |
1188 | break; | |
1189 | case ARM::tLDRpci: { | |
1190 | // Grab the constpool index and check, whether it corresponds to | |
1191 | // original or cloned constpool entry. | |
1192 | unsigned CPI = MI->getOperand(1).getIndex(); | |
1193 | const MachineConstantPool *MCP = MF.getConstantPool(); | |
1194 | if (CPI >= MCP->getConstants().size()) | |
1195 | CPI = AFI.getOriginalCPIdx(CPI); | |
1196 | assert(CPI != -1U && "Invalid constpool index"); | |
1197 | ||
1198 | // Derive the actual offset. | |
1199 | const MachineConstantPoolEntry &CPE = MCP->getConstants()[CPI]; | |
1200 | assert(!CPE.isMachineConstantPoolEntry() && "Invalid constpool entry"); | |
1201 | // FIXME: Check for user, it should be "add" instruction! | |
1202 | Offset = -cast<ConstantInt>(CPE.Val.ConstVal)->getSExtValue(); | |
1203 | break; | |
1204 | } | |
1205 | } | |
1206 | ||
1a4d82fc JJ |
1207 | if (MAI->getExceptionHandlingType() == ExceptionHandling::ARM) { |
1208 | if (DstReg == FramePtr && FramePtr != ARM::SP) | |
1209 | // Set-up of the frame pointer. Positive values correspond to "add" | |
1210 | // instruction. | |
1211 | ATS.emitSetFP(FramePtr, ARM::SP, -Offset); | |
1212 | else if (DstReg == ARM::SP) { | |
1213 | // Change of SP by an offset. Positive values correspond to "sub" | |
1214 | // instruction. | |
1215 | ATS.emitPad(Offset); | |
1216 | } else { | |
1217 | // Move of SP to a register. Positive values correspond to an "add" | |
1218 | // instruction. | |
1219 | ATS.emitMovSP(DstReg, -Offset); | |
1220 | } | |
223e47cc LB |
1221 | } |
1222 | } else if (DstReg == ARM::SP) { | |
223e47cc LB |
1223 | MI->dump(); |
1224 | llvm_unreachable("Unsupported opcode for unwinding information"); | |
1225 | } | |
1226 | else { | |
1227 | MI->dump(); | |
1228 | llvm_unreachable("Unsupported opcode for unwinding information"); | |
1229 | } | |
1230 | } | |
1231 | } | |
1232 | ||
223e47cc LB |
1233 | // Simple pseudo-instructions have their lowering (with expansion to real |
1234 | // instructions) auto-generated. | |
1235 | #include "ARMGenMCPseudoLowering.inc" | |
1236 | ||
1237 | void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { | |
1a4d82fc JJ |
1238 | const DataLayout *DL = TM.getSubtargetImpl()->getDataLayout(); |
1239 | ||
223e47cc LB |
1240 | // If we just ended a constant pool, mark it as such. |
1241 | if (InConstantPool && MI->getOpcode() != ARM::CONSTPOOL_ENTRY) { | |
1242 | OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); | |
1243 | InConstantPool = false; | |
1244 | } | |
1245 | ||
1246 | // Emit unwinding stuff for frame-related instructions | |
1a4d82fc JJ |
1247 | if (Subtarget->isTargetEHABICompatible() && |
1248 | MI->getFlag(MachineInstr::FrameSetup)) | |
223e47cc LB |
1249 | EmitUnwindingInstruction(MI); |
1250 | ||
1251 | // Do any auto-generated pseudo lowerings. | |
1252 | if (emitPseudoExpansionLowering(OutStreamer, MI)) | |
1253 | return; | |
1254 | ||
1255 | assert(!convertAddSubFlagsOpcode(MI->getOpcode()) && | |
1256 | "Pseudo flag setting opcode should be expanded early"); | |
1257 | ||
1258 | // Check for manual lowerings. | |
1259 | unsigned Opc = MI->getOpcode(); | |
1260 | switch (Opc) { | |
1261 | case ARM::t2MOVi32imm: llvm_unreachable("Should be lowered by thumb2it pass"); | |
1a4d82fc | 1262 | case ARM::DBG_VALUE: llvm_unreachable("Should be handled by generic printing"); |
223e47cc LB |
1263 | case ARM::LEApcrel: |
1264 | case ARM::tLEApcrel: | |
1265 | case ARM::t2LEApcrel: { | |
1266 | // FIXME: Need to also handle globals and externals | |
970d7e83 | 1267 | MCSymbol *CPISymbol = GetCPISymbol(MI->getOperand(1).getIndex()); |
1a4d82fc | 1268 | EmitToStreamer(OutStreamer, MCInstBuilder(MI->getOpcode() == |
970d7e83 LB |
1269 | ARM::t2LEApcrel ? ARM::t2ADR |
1270 | : (MI->getOpcode() == ARM::tLEApcrel ? ARM::tADR | |
1271 | : ARM::ADR)) | |
1272 | .addReg(MI->getOperand(0).getReg()) | |
1273 | .addExpr(MCSymbolRefExpr::Create(CPISymbol, OutContext)) | |
1274 | // Add predicate operands. | |
1275 | .addImm(MI->getOperand(2).getImm()) | |
1276 | .addReg(MI->getOperand(3).getReg())); | |
223e47cc LB |
1277 | return; |
1278 | } | |
1279 | case ARM::LEApcrelJT: | |
1280 | case ARM::tLEApcrelJT: | |
1281 | case ARM::t2LEApcrelJT: { | |
970d7e83 LB |
1282 | MCSymbol *JTIPICSymbol = |
1283 | GetARMJTIPICJumpTableLabel2(MI->getOperand(1).getIndex(), | |
1284 | MI->getOperand(2).getImm()); | |
1a4d82fc | 1285 | EmitToStreamer(OutStreamer, MCInstBuilder(MI->getOpcode() == |
970d7e83 LB |
1286 | ARM::t2LEApcrelJT ? ARM::t2ADR |
1287 | : (MI->getOpcode() == ARM::tLEApcrelJT ? ARM::tADR | |
1288 | : ARM::ADR)) | |
1289 | .addReg(MI->getOperand(0).getReg()) | |
1290 | .addExpr(MCSymbolRefExpr::Create(JTIPICSymbol, OutContext)) | |
1291 | // Add predicate operands. | |
1292 | .addImm(MI->getOperand(3).getImm()) | |
1293 | .addReg(MI->getOperand(4).getReg())); | |
223e47cc LB |
1294 | return; |
1295 | } | |
1296 | // Darwin call instructions are just normal call instructions with different | |
1297 | // clobber semantics (they clobber R9). | |
1298 | case ARM::BX_CALL: { | |
1a4d82fc | 1299 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVr) |
970d7e83 LB |
1300 | .addReg(ARM::LR) |
1301 | .addReg(ARM::PC) | |
223e47cc | 1302 | // Add predicate operands. |
970d7e83 LB |
1303 | .addImm(ARMCC::AL) |
1304 | .addReg(0) | |
223e47cc | 1305 | // Add 's' bit operand (always reg0 for this) |
970d7e83 LB |
1306 | .addReg(0)); |
1307 | ||
1a4d82fc | 1308 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::BX) |
970d7e83 | 1309 | .addReg(MI->getOperand(0).getReg())); |
223e47cc LB |
1310 | return; |
1311 | } | |
1312 | case ARM::tBX_CALL: { | |
85aaf69f SL |
1313 | if (Subtarget->hasV5TOps()) |
1314 | llvm_unreachable("Expected BLX to be selected for v5t+"); | |
1315 | ||
1316 | // On ARM v4t, when doing a call from thumb mode, we need to ensure | |
1317 | // that the saved lr has its LSB set correctly (the arch doesn't | |
1318 | // have blx). | |
1319 | // So here we generate a bl to a small jump pad that does bx rN. | |
1320 | // The jump pads are emitted after the function body. | |
1321 | ||
1322 | unsigned TReg = MI->getOperand(0).getReg(); | |
1323 | MCSymbol *TRegSym = nullptr; | |
1324 | for (unsigned i = 0, e = ThumbIndirectPads.size(); i < e; i++) { | |
1325 | if (ThumbIndirectPads[i].first == TReg) { | |
1326 | TRegSym = ThumbIndirectPads[i].second; | |
1327 | break; | |
1328 | } | |
1329 | } | |
970d7e83 | 1330 | |
85aaf69f SL |
1331 | if (!TRegSym) { |
1332 | TRegSym = OutContext.CreateTempSymbol(); | |
1333 | ThumbIndirectPads.push_back(std::make_pair(TReg, TRegSym)); | |
1334 | } | |
1335 | ||
1336 | // Create a link-saving branch to the Reg Indirect Jump Pad. | |
1337 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBL) | |
1338 | // Predicate comes first here. | |
1339 | .addImm(ARMCC::AL).addReg(0) | |
1340 | .addExpr(MCSymbolRefExpr::Create(TRegSym, OutContext))); | |
223e47cc LB |
1341 | return; |
1342 | } | |
1343 | case ARM::BMOVPCRX_CALL: { | |
1a4d82fc | 1344 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVr) |
970d7e83 LB |
1345 | .addReg(ARM::LR) |
1346 | .addReg(ARM::PC) | |
223e47cc | 1347 | // Add predicate operands. |
970d7e83 LB |
1348 | .addImm(ARMCC::AL) |
1349 | .addReg(0) | |
223e47cc | 1350 | // Add 's' bit operand (always reg0 for this) |
970d7e83 LB |
1351 | .addReg(0)); |
1352 | ||
1a4d82fc | 1353 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVr) |
970d7e83 LB |
1354 | .addReg(ARM::PC) |
1355 | .addReg(MI->getOperand(0).getReg()) | |
223e47cc | 1356 | // Add predicate operands. |
970d7e83 LB |
1357 | .addImm(ARMCC::AL) |
1358 | .addReg(0) | |
223e47cc | 1359 | // Add 's' bit operand (always reg0 for this) |
970d7e83 | 1360 | .addReg(0)); |
223e47cc LB |
1361 | return; |
1362 | } | |
1363 | case ARM::BMOVPCB_CALL: { | |
1a4d82fc | 1364 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVr) |
970d7e83 LB |
1365 | .addReg(ARM::LR) |
1366 | .addReg(ARM::PC) | |
223e47cc | 1367 | // Add predicate operands. |
970d7e83 LB |
1368 | .addImm(ARMCC::AL) |
1369 | .addReg(0) | |
223e47cc | 1370 | // Add 's' bit operand (always reg0 for this) |
970d7e83 LB |
1371 | .addReg(0)); |
1372 | ||
1a4d82fc JJ |
1373 | const MachineOperand &Op = MI->getOperand(0); |
1374 | const GlobalValue *GV = Op.getGlobal(); | |
1375 | const unsigned TF = Op.getTargetFlags(); | |
1376 | MCSymbol *GVSym = GetARMGVSymbol(GV, TF); | |
970d7e83 | 1377 | const MCExpr *GVSymExpr = MCSymbolRefExpr::Create(GVSym, OutContext); |
1a4d82fc | 1378 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::Bcc) |
970d7e83 | 1379 | .addExpr(GVSymExpr) |
223e47cc | 1380 | // Add predicate operands. |
970d7e83 LB |
1381 | .addImm(ARMCC::AL) |
1382 | .addReg(0)); | |
223e47cc LB |
1383 | return; |
1384 | } | |
1385 | case ARM::MOVi16_ga_pcrel: | |
1386 | case ARM::t2MOVi16_ga_pcrel: { | |
1387 | MCInst TmpInst; | |
1388 | TmpInst.setOpcode(Opc == ARM::MOVi16_ga_pcrel? ARM::MOVi16 : ARM::t2MOVi16); | |
1389 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); | |
1390 | ||
1391 | unsigned TF = MI->getOperand(1).getTargetFlags(); | |
223e47cc | 1392 | const GlobalValue *GV = MI->getOperand(1).getGlobal(); |
1a4d82fc | 1393 | MCSymbol *GVSym = GetARMGVSymbol(GV, TF); |
223e47cc | 1394 | const MCExpr *GVSymExpr = MCSymbolRefExpr::Create(GVSym, OutContext); |
1a4d82fc JJ |
1395 | |
1396 | MCSymbol *LabelSym = getPICLabel(DL->getPrivateGlobalPrefix(), | |
1397 | getFunctionNumber(), | |
1398 | MI->getOperand(2).getImm(), OutContext); | |
1399 | const MCExpr *LabelSymExpr= MCSymbolRefExpr::Create(LabelSym, OutContext); | |
1400 | unsigned PCAdj = (Opc == ARM::MOVi16_ga_pcrel) ? 8 : 4; | |
1401 | const MCExpr *PCRelExpr = | |
1402 | ARMMCExpr::CreateLower16(MCBinaryExpr::CreateSub(GVSymExpr, | |
1403 | MCBinaryExpr::CreateAdd(LabelSymExpr, | |
223e47cc | 1404 | MCConstantExpr::Create(PCAdj, OutContext), |
1a4d82fc | 1405 | OutContext), OutContext), OutContext); |
223e47cc | 1406 | TmpInst.addOperand(MCOperand::CreateExpr(PCRelExpr)); |
223e47cc LB |
1407 | |
1408 | // Add predicate operands. | |
1409 | TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); | |
1410 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1411 | // Add 's' bit operand (always reg0 for this) | |
1412 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1a4d82fc | 1413 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
1414 | return; |
1415 | } | |
1416 | case ARM::MOVTi16_ga_pcrel: | |
1417 | case ARM::t2MOVTi16_ga_pcrel: { | |
1418 | MCInst TmpInst; | |
1419 | TmpInst.setOpcode(Opc == ARM::MOVTi16_ga_pcrel | |
1420 | ? ARM::MOVTi16 : ARM::t2MOVTi16); | |
1421 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); | |
1422 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); | |
1423 | ||
1424 | unsigned TF = MI->getOperand(2).getTargetFlags(); | |
223e47cc | 1425 | const GlobalValue *GV = MI->getOperand(2).getGlobal(); |
1a4d82fc | 1426 | MCSymbol *GVSym = GetARMGVSymbol(GV, TF); |
223e47cc | 1427 | const MCExpr *GVSymExpr = MCSymbolRefExpr::Create(GVSym, OutContext); |
1a4d82fc JJ |
1428 | |
1429 | MCSymbol *LabelSym = getPICLabel(DL->getPrivateGlobalPrefix(), | |
1430 | getFunctionNumber(), | |
1431 | MI->getOperand(3).getImm(), OutContext); | |
1432 | const MCExpr *LabelSymExpr= MCSymbolRefExpr::Create(LabelSym, OutContext); | |
1433 | unsigned PCAdj = (Opc == ARM::MOVTi16_ga_pcrel) ? 8 : 4; | |
1434 | const MCExpr *PCRelExpr = | |
223e47cc LB |
1435 | ARMMCExpr::CreateUpper16(MCBinaryExpr::CreateSub(GVSymExpr, |
1436 | MCBinaryExpr::CreateAdd(LabelSymExpr, | |
1437 | MCConstantExpr::Create(PCAdj, OutContext), | |
1438 | OutContext), OutContext), OutContext); | |
1439 | TmpInst.addOperand(MCOperand::CreateExpr(PCRelExpr)); | |
223e47cc LB |
1440 | // Add predicate operands. |
1441 | TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); | |
1442 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1443 | // Add 's' bit operand (always reg0 for this) | |
1444 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1a4d82fc | 1445 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
1446 | return; |
1447 | } | |
1448 | case ARM::tPICADD: { | |
1449 | // This is a pseudo op for a label + instruction sequence, which looks like: | |
1450 | // LPC0: | |
1451 | // add r0, pc | |
1452 | // This adds the address of LPC0 to r0. | |
1453 | ||
1454 | // Emit the label. | |
1a4d82fc | 1455 | OutStreamer.EmitLabel(getPICLabel(DL->getPrivateGlobalPrefix(), |
223e47cc LB |
1456 | getFunctionNumber(), MI->getOperand(2).getImm(), |
1457 | OutContext)); | |
1458 | ||
1459 | // Form and emit the add. | |
1a4d82fc | 1460 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tADDhirr) |
970d7e83 LB |
1461 | .addReg(MI->getOperand(0).getReg()) |
1462 | .addReg(MI->getOperand(0).getReg()) | |
1463 | .addReg(ARM::PC) | |
1464 | // Add predicate operands. | |
1465 | .addImm(ARMCC::AL) | |
1466 | .addReg(0)); | |
223e47cc LB |
1467 | return; |
1468 | } | |
1469 | case ARM::PICADD: { | |
1470 | // This is a pseudo op for a label + instruction sequence, which looks like: | |
1471 | // LPC0: | |
1472 | // add r0, pc, r0 | |
1473 | // This adds the address of LPC0 to r0. | |
1474 | ||
1475 | // Emit the label. | |
1a4d82fc | 1476 | OutStreamer.EmitLabel(getPICLabel(DL->getPrivateGlobalPrefix(), |
223e47cc LB |
1477 | getFunctionNumber(), MI->getOperand(2).getImm(), |
1478 | OutContext)); | |
1479 | ||
1480 | // Form and emit the add. | |
1a4d82fc | 1481 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::ADDrr) |
970d7e83 LB |
1482 | .addReg(MI->getOperand(0).getReg()) |
1483 | .addReg(ARM::PC) | |
1484 | .addReg(MI->getOperand(1).getReg()) | |
1485 | // Add predicate operands. | |
1486 | .addImm(MI->getOperand(3).getImm()) | |
1487 | .addReg(MI->getOperand(4).getReg()) | |
1488 | // Add 's' bit operand (always reg0 for this) | |
1489 | .addReg(0)); | |
223e47cc LB |
1490 | return; |
1491 | } | |
1492 | case ARM::PICSTR: | |
1493 | case ARM::PICSTRB: | |
1494 | case ARM::PICSTRH: | |
1495 | case ARM::PICLDR: | |
1496 | case ARM::PICLDRB: | |
1497 | case ARM::PICLDRH: | |
1498 | case ARM::PICLDRSB: | |
1499 | case ARM::PICLDRSH: { | |
1500 | // This is a pseudo op for a label + instruction sequence, which looks like: | |
1501 | // LPC0: | |
1502 | // OP r0, [pc, r0] | |
1503 | // The LCP0 label is referenced by a constant pool entry in order to get | |
1504 | // a PC-relative address at the ldr instruction. | |
1505 | ||
1506 | // Emit the label. | |
1a4d82fc | 1507 | OutStreamer.EmitLabel(getPICLabel(DL->getPrivateGlobalPrefix(), |
223e47cc LB |
1508 | getFunctionNumber(), MI->getOperand(2).getImm(), |
1509 | OutContext)); | |
1510 | ||
1511 | // Form and emit the load | |
1512 | unsigned Opcode; | |
1513 | switch (MI->getOpcode()) { | |
1514 | default: | |
1515 | llvm_unreachable("Unexpected opcode!"); | |
1516 | case ARM::PICSTR: Opcode = ARM::STRrs; break; | |
1517 | case ARM::PICSTRB: Opcode = ARM::STRBrs; break; | |
1518 | case ARM::PICSTRH: Opcode = ARM::STRH; break; | |
1519 | case ARM::PICLDR: Opcode = ARM::LDRrs; break; | |
1520 | case ARM::PICLDRB: Opcode = ARM::LDRBrs; break; | |
1521 | case ARM::PICLDRH: Opcode = ARM::LDRH; break; | |
1522 | case ARM::PICLDRSB: Opcode = ARM::LDRSB; break; | |
1523 | case ARM::PICLDRSH: Opcode = ARM::LDRSH; break; | |
1524 | } | |
1a4d82fc | 1525 | EmitToStreamer(OutStreamer, MCInstBuilder(Opcode) |
970d7e83 LB |
1526 | .addReg(MI->getOperand(0).getReg()) |
1527 | .addReg(ARM::PC) | |
1528 | .addReg(MI->getOperand(1).getReg()) | |
1529 | .addImm(0) | |
1530 | // Add predicate operands. | |
1531 | .addImm(MI->getOperand(3).getImm()) | |
1532 | .addReg(MI->getOperand(4).getReg())); | |
223e47cc LB |
1533 | |
1534 | return; | |
1535 | } | |
1536 | case ARM::CONSTPOOL_ENTRY: { | |
1537 | /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool | |
1538 | /// in the function. The first operand is the ID# for this instruction, the | |
1539 | /// second is the index into the MachineConstantPool that this is, the third | |
1540 | /// is the size in bytes of this constant pool entry. | |
1541 | /// The required alignment is specified on the basic block holding this MI. | |
1542 | unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); | |
1543 | unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); | |
1544 | ||
1545 | // If this is the first entry of the pool, mark it. | |
1546 | if (!InConstantPool) { | |
1547 | OutStreamer.EmitDataRegion(MCDR_DataRegion); | |
1548 | InConstantPool = true; | |
1549 | } | |
1550 | ||
1551 | OutStreamer.EmitLabel(GetCPISymbol(LabelId)); | |
1552 | ||
1553 | const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; | |
1554 | if (MCPE.isMachineConstantPoolEntry()) | |
1555 | EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); | |
1556 | else | |
1557 | EmitGlobalConstant(MCPE.Val.ConstVal); | |
1558 | return; | |
1559 | } | |
1560 | case ARM::t2BR_JT: { | |
1561 | // Lower and emit the instruction itself, then the jump table following it. | |
1a4d82fc | 1562 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVr) |
970d7e83 LB |
1563 | .addReg(ARM::PC) |
1564 | .addReg(MI->getOperand(0).getReg()) | |
1565 | // Add predicate operands. | |
1566 | .addImm(ARMCC::AL) | |
1567 | .addReg(0)); | |
1568 | ||
223e47cc LB |
1569 | // Output the data for the jump table itself |
1570 | EmitJump2Table(MI); | |
1571 | return; | |
1572 | } | |
1573 | case ARM::t2TBB_JT: { | |
1574 | // Lower and emit the instruction itself, then the jump table following it. | |
1a4d82fc | 1575 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::t2TBB) |
970d7e83 LB |
1576 | .addReg(ARM::PC) |
1577 | .addReg(MI->getOperand(0).getReg()) | |
1578 | // Add predicate operands. | |
1579 | .addImm(ARMCC::AL) | |
1580 | .addReg(0)); | |
223e47cc | 1581 | |
223e47cc LB |
1582 | // Output the data for the jump table itself |
1583 | EmitJump2Table(MI); | |
1584 | // Make sure the next instruction is 2-byte aligned. | |
1585 | EmitAlignment(1); | |
1586 | return; | |
1587 | } | |
1588 | case ARM::t2TBH_JT: { | |
1589 | // Lower and emit the instruction itself, then the jump table following it. | |
1a4d82fc | 1590 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::t2TBH) |
970d7e83 LB |
1591 | .addReg(ARM::PC) |
1592 | .addReg(MI->getOperand(0).getReg()) | |
1593 | // Add predicate operands. | |
1594 | .addImm(ARMCC::AL) | |
1595 | .addReg(0)); | |
223e47cc | 1596 | |
223e47cc LB |
1597 | // Output the data for the jump table itself |
1598 | EmitJump2Table(MI); | |
1599 | return; | |
1600 | } | |
1601 | case ARM::tBR_JTr: | |
1602 | case ARM::BR_JTr: { | |
1603 | // Lower and emit the instruction itself, then the jump table following it. | |
1604 | // mov pc, target | |
1605 | MCInst TmpInst; | |
1606 | unsigned Opc = MI->getOpcode() == ARM::BR_JTr ? | |
1607 | ARM::MOVr : ARM::tMOVr; | |
1608 | TmpInst.setOpcode(Opc); | |
1609 | TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); | |
1610 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); | |
1611 | // Add predicate operands. | |
1612 | TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); | |
1613 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1614 | // Add 's' bit operand (always reg0 for this) | |
1615 | if (Opc == ARM::MOVr) | |
1616 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1a4d82fc | 1617 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
1618 | |
1619 | // Make sure the Thumb jump table is 4-byte aligned. | |
1620 | if (Opc == ARM::tMOVr) | |
1621 | EmitAlignment(2); | |
1622 | ||
1623 | // Output the data for the jump table itself | |
1624 | EmitJumpTable(MI); | |
1625 | return; | |
1626 | } | |
1627 | case ARM::BR_JTm: { | |
1628 | // Lower and emit the instruction itself, then the jump table following it. | |
1629 | // ldr pc, target | |
1630 | MCInst TmpInst; | |
1631 | if (MI->getOperand(1).getReg() == 0) { | |
1632 | // literal offset | |
1633 | TmpInst.setOpcode(ARM::LDRi12); | |
1634 | TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); | |
1635 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); | |
1636 | TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); | |
1637 | } else { | |
1638 | TmpInst.setOpcode(ARM::LDRrs); | |
1639 | TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); | |
1640 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); | |
1641 | TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); | |
1642 | TmpInst.addOperand(MCOperand::CreateImm(0)); | |
1643 | } | |
1644 | // Add predicate operands. | |
1645 | TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); | |
1646 | TmpInst.addOperand(MCOperand::CreateReg(0)); | |
1a4d82fc | 1647 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
1648 | |
1649 | // Output the data for the jump table itself | |
1650 | EmitJumpTable(MI); | |
1651 | return; | |
1652 | } | |
1653 | case ARM::BR_JTadd: { | |
1654 | // Lower and emit the instruction itself, then the jump table following it. | |
1655 | // add pc, target, idx | |
1a4d82fc | 1656 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::ADDrr) |
970d7e83 LB |
1657 | .addReg(ARM::PC) |
1658 | .addReg(MI->getOperand(0).getReg()) | |
1659 | .addReg(MI->getOperand(1).getReg()) | |
1660 | // Add predicate operands. | |
1661 | .addImm(ARMCC::AL) | |
1662 | .addReg(0) | |
1663 | // Add 's' bit operand (always reg0 for this) | |
1664 | .addReg(0)); | |
223e47cc LB |
1665 | |
1666 | // Output the data for the jump table itself | |
1667 | EmitJumpTable(MI); | |
1668 | return; | |
1669 | } | |
85aaf69f SL |
1670 | case ARM::SPACE: |
1671 | OutStreamer.EmitZeros(MI->getOperand(1).getImm()); | |
1672 | return; | |
223e47cc LB |
1673 | case ARM::TRAP: { |
1674 | // Non-Darwin binutils don't yet support the "trap" mnemonic. | |
1675 | // FIXME: Remove this special case when they do. | |
1a4d82fc | 1676 | if (!Subtarget->isTargetMachO()) { |
223e47cc LB |
1677 | //.long 0xe7ffdefe @ trap |
1678 | uint32_t Val = 0xe7ffdefeUL; | |
1679 | OutStreamer.AddComment("trap"); | |
1680 | OutStreamer.EmitIntValue(Val, 4); | |
1681 | return; | |
1682 | } | |
1683 | break; | |
1684 | } | |
970d7e83 LB |
1685 | case ARM::TRAPNaCl: { |
1686 | //.long 0xe7fedef0 @ trap | |
1687 | uint32_t Val = 0xe7fedef0UL; | |
1688 | OutStreamer.AddComment("trap"); | |
1689 | OutStreamer.EmitIntValue(Val, 4); | |
1690 | return; | |
1691 | } | |
223e47cc LB |
1692 | case ARM::tTRAP: { |
1693 | // Non-Darwin binutils don't yet support the "trap" mnemonic. | |
1694 | // FIXME: Remove this special case when they do. | |
1a4d82fc | 1695 | if (!Subtarget->isTargetMachO()) { |
223e47cc LB |
1696 | //.short 57086 @ trap |
1697 | uint16_t Val = 0xdefe; | |
1698 | OutStreamer.AddComment("trap"); | |
1699 | OutStreamer.EmitIntValue(Val, 2); | |
1700 | return; | |
1701 | } | |
1702 | break; | |
1703 | } | |
1704 | case ARM::t2Int_eh_sjlj_setjmp: | |
1705 | case ARM::t2Int_eh_sjlj_setjmp_nofp: | |
1706 | case ARM::tInt_eh_sjlj_setjmp: { | |
1707 | // Two incoming args: GPR:$src, GPR:$val | |
1708 | // mov $val, pc | |
1709 | // adds $val, #7 | |
1710 | // str $val, [$src, #4] | |
1711 | // movs r0, #0 | |
1712 | // b 1f | |
1713 | // movs r0, #1 | |
1714 | // 1: | |
1715 | unsigned SrcReg = MI->getOperand(0).getReg(); | |
1716 | unsigned ValReg = MI->getOperand(1).getReg(); | |
1717 | MCSymbol *Label = GetARMSJLJEHLabel(); | |
970d7e83 | 1718 | OutStreamer.AddComment("eh_setjmp begin"); |
1a4d82fc | 1719 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVr) |
970d7e83 LB |
1720 | .addReg(ValReg) |
1721 | .addReg(ARM::PC) | |
223e47cc | 1722 | // Predicate. |
970d7e83 LB |
1723 | .addImm(ARMCC::AL) |
1724 | .addReg(0)); | |
1725 | ||
1a4d82fc | 1726 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tADDi3) |
970d7e83 | 1727 | .addReg(ValReg) |
223e47cc | 1728 | // 's' bit operand |
970d7e83 LB |
1729 | .addReg(ARM::CPSR) |
1730 | .addReg(ValReg) | |
1731 | .addImm(7) | |
223e47cc | 1732 | // Predicate. |
970d7e83 LB |
1733 | .addImm(ARMCC::AL) |
1734 | .addReg(0)); | |
1735 | ||
1a4d82fc | 1736 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tSTRi) |
970d7e83 LB |
1737 | .addReg(ValReg) |
1738 | .addReg(SrcReg) | |
223e47cc LB |
1739 | // The offset immediate is #4. The operand value is scaled by 4 for the |
1740 | // tSTR instruction. | |
970d7e83 | 1741 | .addImm(1) |
223e47cc | 1742 | // Predicate. |
970d7e83 LB |
1743 | .addImm(ARMCC::AL) |
1744 | .addReg(0)); | |
1745 | ||
1a4d82fc | 1746 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVi8) |
970d7e83 LB |
1747 | .addReg(ARM::R0) |
1748 | .addReg(ARM::CPSR) | |
1749 | .addImm(0) | |
223e47cc | 1750 | // Predicate. |
970d7e83 LB |
1751 | .addImm(ARMCC::AL) |
1752 | .addReg(0)); | |
1753 | ||
1754 | const MCExpr *SymbolExpr = MCSymbolRefExpr::Create(Label, OutContext); | |
1a4d82fc | 1755 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tB) |
970d7e83 LB |
1756 | .addExpr(SymbolExpr) |
1757 | .addImm(ARMCC::AL) | |
1758 | .addReg(0)); | |
1759 | ||
1760 | OutStreamer.AddComment("eh_setjmp end"); | |
1a4d82fc | 1761 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVi8) |
970d7e83 LB |
1762 | .addReg(ARM::R0) |
1763 | .addReg(ARM::CPSR) | |
1764 | .addImm(1) | |
223e47cc | 1765 | // Predicate. |
970d7e83 LB |
1766 | .addImm(ARMCC::AL) |
1767 | .addReg(0)); | |
1768 | ||
223e47cc LB |
1769 | OutStreamer.EmitLabel(Label); |
1770 | return; | |
1771 | } | |
1772 | ||
1773 | case ARM::Int_eh_sjlj_setjmp_nofp: | |
1774 | case ARM::Int_eh_sjlj_setjmp: { | |
1775 | // Two incoming args: GPR:$src, GPR:$val | |
1776 | // add $val, pc, #8 | |
1777 | // str $val, [$src, #+4] | |
1778 | // mov r0, #0 | |
1779 | // add pc, pc, #0 | |
1780 | // mov r0, #1 | |
1781 | unsigned SrcReg = MI->getOperand(0).getReg(); | |
1782 | unsigned ValReg = MI->getOperand(1).getReg(); | |
1783 | ||
970d7e83 | 1784 | OutStreamer.AddComment("eh_setjmp begin"); |
1a4d82fc | 1785 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::ADDri) |
970d7e83 LB |
1786 | .addReg(ValReg) |
1787 | .addReg(ARM::PC) | |
1788 | .addImm(8) | |
223e47cc | 1789 | // Predicate. |
970d7e83 LB |
1790 | .addImm(ARMCC::AL) |
1791 | .addReg(0) | |
223e47cc | 1792 | // 's' bit operand (always reg0 for this). |
970d7e83 LB |
1793 | .addReg(0)); |
1794 | ||
1a4d82fc | 1795 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::STRi12) |
970d7e83 LB |
1796 | .addReg(ValReg) |
1797 | .addReg(SrcReg) | |
1798 | .addImm(4) | |
223e47cc | 1799 | // Predicate. |
970d7e83 LB |
1800 | .addImm(ARMCC::AL) |
1801 | .addReg(0)); | |
1802 | ||
1a4d82fc | 1803 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVi) |
970d7e83 LB |
1804 | .addReg(ARM::R0) |
1805 | .addImm(0) | |
223e47cc | 1806 | // Predicate. |
970d7e83 LB |
1807 | .addImm(ARMCC::AL) |
1808 | .addReg(0) | |
223e47cc | 1809 | // 's' bit operand (always reg0 for this). |
970d7e83 LB |
1810 | .addReg(0)); |
1811 | ||
1a4d82fc | 1812 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::ADDri) |
970d7e83 LB |
1813 | .addReg(ARM::PC) |
1814 | .addReg(ARM::PC) | |
1815 | .addImm(0) | |
223e47cc | 1816 | // Predicate. |
970d7e83 LB |
1817 | .addImm(ARMCC::AL) |
1818 | .addReg(0) | |
223e47cc | 1819 | // 's' bit operand (always reg0 for this). |
970d7e83 LB |
1820 | .addReg(0)); |
1821 | ||
1822 | OutStreamer.AddComment("eh_setjmp end"); | |
1a4d82fc | 1823 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::MOVi) |
970d7e83 LB |
1824 | .addReg(ARM::R0) |
1825 | .addImm(1) | |
223e47cc | 1826 | // Predicate. |
970d7e83 LB |
1827 | .addImm(ARMCC::AL) |
1828 | .addReg(0) | |
223e47cc | 1829 | // 's' bit operand (always reg0 for this). |
970d7e83 | 1830 | .addReg(0)); |
223e47cc LB |
1831 | return; |
1832 | } | |
1833 | case ARM::Int_eh_sjlj_longjmp: { | |
1834 | // ldr sp, [$src, #8] | |
1835 | // ldr $scratch, [$src, #4] | |
1836 | // ldr r7, [$src] | |
1837 | // bx $scratch | |
1838 | unsigned SrcReg = MI->getOperand(0).getReg(); | |
1839 | unsigned ScratchReg = MI->getOperand(1).getReg(); | |
1a4d82fc | 1840 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::LDRi12) |
970d7e83 LB |
1841 | .addReg(ARM::SP) |
1842 | .addReg(SrcReg) | |
1843 | .addImm(8) | |
223e47cc | 1844 | // Predicate. |
970d7e83 LB |
1845 | .addImm(ARMCC::AL) |
1846 | .addReg(0)); | |
1847 | ||
1a4d82fc | 1848 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::LDRi12) |
970d7e83 LB |
1849 | .addReg(ScratchReg) |
1850 | .addReg(SrcReg) | |
1851 | .addImm(4) | |
223e47cc | 1852 | // Predicate. |
970d7e83 LB |
1853 | .addImm(ARMCC::AL) |
1854 | .addReg(0)); | |
1855 | ||
1a4d82fc | 1856 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::LDRi12) |
970d7e83 LB |
1857 | .addReg(ARM::R7) |
1858 | .addReg(SrcReg) | |
1859 | .addImm(0) | |
223e47cc | 1860 | // Predicate. |
970d7e83 LB |
1861 | .addImm(ARMCC::AL) |
1862 | .addReg(0)); | |
1863 | ||
1a4d82fc | 1864 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::BX) |
970d7e83 | 1865 | .addReg(ScratchReg) |
223e47cc | 1866 | // Predicate. |
970d7e83 LB |
1867 | .addImm(ARMCC::AL) |
1868 | .addReg(0)); | |
223e47cc LB |
1869 | return; |
1870 | } | |
1871 | case ARM::tInt_eh_sjlj_longjmp: { | |
1872 | // ldr $scratch, [$src, #8] | |
1873 | // mov sp, $scratch | |
1874 | // ldr $scratch, [$src, #4] | |
1875 | // ldr r7, [$src] | |
1876 | // bx $scratch | |
1877 | unsigned SrcReg = MI->getOperand(0).getReg(); | |
1878 | unsigned ScratchReg = MI->getOperand(1).getReg(); | |
1a4d82fc | 1879 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tLDRi) |
970d7e83 LB |
1880 | .addReg(ScratchReg) |
1881 | .addReg(SrcReg) | |
223e47cc LB |
1882 | // The offset immediate is #8. The operand value is scaled by 4 for the |
1883 | // tLDR instruction. | |
970d7e83 | 1884 | .addImm(2) |
223e47cc | 1885 | // Predicate. |
970d7e83 LB |
1886 | .addImm(ARMCC::AL) |
1887 | .addReg(0)); | |
1888 | ||
1a4d82fc | 1889 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tMOVr) |
970d7e83 LB |
1890 | .addReg(ARM::SP) |
1891 | .addReg(ScratchReg) | |
223e47cc | 1892 | // Predicate. |
970d7e83 LB |
1893 | .addImm(ARMCC::AL) |
1894 | .addReg(0)); | |
1895 | ||
1a4d82fc | 1896 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tLDRi) |
970d7e83 LB |
1897 | .addReg(ScratchReg) |
1898 | .addReg(SrcReg) | |
1899 | .addImm(1) | |
223e47cc | 1900 | // Predicate. |
970d7e83 LB |
1901 | .addImm(ARMCC::AL) |
1902 | .addReg(0)); | |
1903 | ||
1a4d82fc | 1904 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tLDRi) |
970d7e83 LB |
1905 | .addReg(ARM::R7) |
1906 | .addReg(SrcReg) | |
1907 | .addImm(0) | |
223e47cc | 1908 | // Predicate. |
970d7e83 LB |
1909 | .addImm(ARMCC::AL) |
1910 | .addReg(0)); | |
1911 | ||
1a4d82fc | 1912 | EmitToStreamer(OutStreamer, MCInstBuilder(ARM::tBX) |
970d7e83 | 1913 | .addReg(ScratchReg) |
223e47cc | 1914 | // Predicate. |
970d7e83 LB |
1915 | .addImm(ARMCC::AL) |
1916 | .addReg(0)); | |
223e47cc LB |
1917 | return; |
1918 | } | |
1919 | } | |
1920 | ||
1921 | MCInst TmpInst; | |
1922 | LowerARMMachineInstrToMCInst(MI, TmpInst, *this); | |
1923 | ||
1a4d82fc | 1924 | EmitToStreamer(OutStreamer, TmpInst); |
223e47cc LB |
1925 | } |
1926 | ||
1927 | //===----------------------------------------------------------------------===// | |
1928 | // Target Registry Stuff | |
1929 | //===----------------------------------------------------------------------===// | |
1930 | ||
1931 | // Force static initialization. | |
1932 | extern "C" void LLVMInitializeARMAsmPrinter() { | |
1a4d82fc JJ |
1933 | RegisterAsmPrinter<ARMAsmPrinter> X(TheARMLETarget); |
1934 | RegisterAsmPrinter<ARMAsmPrinter> Y(TheARMBETarget); | |
1935 | RegisterAsmPrinter<ARMAsmPrinter> A(TheThumbLETarget); | |
1936 | RegisterAsmPrinter<ARMAsmPrinter> B(TheThumbBETarget); | |
223e47cc | 1937 | } |