1 | //===-- SystemZAsmPrinter.cpp - SystemZ LLVM assembly printer -------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Streams SystemZ assembly language and associated data, in the form of |
10 | // MCInsts and MCExprs respectively. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "SystemZAsmPrinter.h" |
15 | #include "MCTargetDesc/SystemZInstPrinter.h" |
16 | #include "MCTargetDesc/SystemZMCExpr.h" |
17 | #include "SystemZConstantPoolValue.h" |
18 | #include "SystemZMCInstLower.h" |
19 | #include "TargetInfo/SystemZTargetInfo.h" |
20 | #include "llvm/ADT/StringExtras.h" |
21 | #include "llvm/BinaryFormat/ELF.h" |
22 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
23 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
24 | #include "llvm/IR/Mangler.h" |
25 | #include "llvm/MC/MCExpr.h" |
26 | #include "llvm/MC/MCInstBuilder.h" |
27 | #include "llvm/MC/MCSectionELF.h" |
28 | #include "llvm/MC/MCStreamer.h" |
29 | #include "llvm/MC/TargetRegistry.h" |
30 | #include "llvm/Support/Chrono.h" |
31 | #include "llvm/Support/ConvertEBCDIC.h" |
32 | #include "llvm/Support/FormatProviders.h" |
33 | #include "llvm/Support/FormatVariadic.h" |
34 | |
35 | using namespace llvm; |
36 | |
37 | // Return an RI instruction like MI with opcode Opcode, but with the |
38 | // GR64 register operands turned into GR32s. |
39 | static MCInst lowerRILow(const MachineInstr *MI, unsigned Opcode) { |
40 | if (MI->isCompare()) |
41 | return MCInstBuilder(Opcode) |
42 | .addReg(Reg: SystemZMC::getRegAsGR32(Reg: MI->getOperand(i: 0).getReg())) |
43 | .addImm(Val: MI->getOperand(i: 1).getImm()); |
44 | else |
45 | return MCInstBuilder(Opcode) |
46 | .addReg(Reg: SystemZMC::getRegAsGR32(Reg: MI->getOperand(i: 0).getReg())) |
47 | .addReg(Reg: SystemZMC::getRegAsGR32(Reg: MI->getOperand(i: 1).getReg())) |
48 | .addImm(Val: MI->getOperand(i: 2).getImm()); |
49 | } |
50 | |
51 | // Return an RI instruction like MI with opcode Opcode, but with the |
52 | // GR64 register operands turned into GRH32s. |
53 | static MCInst lowerRIHigh(const MachineInstr *MI, unsigned Opcode) { |
54 | if (MI->isCompare()) |
55 | return MCInstBuilder(Opcode) |
56 | .addReg(Reg: SystemZMC::getRegAsGRH32(Reg: MI->getOperand(i: 0).getReg())) |
57 | .addImm(Val: MI->getOperand(i: 1).getImm()); |
58 | else |
59 | return MCInstBuilder(Opcode) |
60 | .addReg(Reg: SystemZMC::getRegAsGRH32(Reg: MI->getOperand(i: 0).getReg())) |
61 | .addReg(Reg: SystemZMC::getRegAsGRH32(Reg: MI->getOperand(i: 1).getReg())) |
62 | .addImm(Val: MI->getOperand(i: 2).getImm()); |
63 | } |
64 | |
65 | // Return an RI instruction like MI with opcode Opcode, but with the |
66 | // R2 register turned into a GR64. |
67 | static MCInst lowerRIEfLow(const MachineInstr *MI, unsigned Opcode) { |
68 | return MCInstBuilder(Opcode) |
69 | .addReg(Reg: MI->getOperand(i: 0).getReg()) |
70 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
71 | .addReg(Reg: SystemZMC::getRegAsGR64(Reg: MI->getOperand(i: 2).getReg())) |
72 | .addImm(Val: MI->getOperand(i: 3).getImm()) |
73 | .addImm(Val: MI->getOperand(i: 4).getImm()) |
74 | .addImm(Val: MI->getOperand(i: 5).getImm()); |
75 | } |
76 | |
77 | static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) { |
78 | StringRef Name = "__tls_get_offset" ; |
79 | return MCSymbolRefExpr::create(Symbol: Context.getOrCreateSymbol(Name), |
80 | Kind: MCSymbolRefExpr::VK_PLT, |
81 | Ctx&: Context); |
82 | } |
83 | |
84 | static const MCSymbolRefExpr *getGlobalOffsetTable(MCContext &Context) { |
85 | StringRef Name = "_GLOBAL_OFFSET_TABLE_" ; |
86 | return MCSymbolRefExpr::create(Symbol: Context.getOrCreateSymbol(Name), |
87 | Kind: MCSymbolRefExpr::VK_None, |
88 | Ctx&: Context); |
89 | } |
90 | |
91 | // MI is an instruction that accepts an optional alignment hint, |
92 | // and which was already lowered to LoweredMI. If the alignment |
93 | // of the original memory operand is known, update LoweredMI to |
94 | // an instruction with the corresponding hint set. |
95 | static void lowerAlignmentHint(const MachineInstr *MI, MCInst &LoweredMI, |
96 | unsigned Opcode) { |
97 | if (MI->memoperands_empty()) |
98 | return; |
99 | |
100 | Align Alignment = Align(16); |
101 | for (MachineInstr::mmo_iterator MMOI = MI->memoperands_begin(), |
102 | EE = MI->memoperands_end(); MMOI != EE; ++MMOI) |
103 | if ((*MMOI)->getAlign() < Alignment) |
104 | Alignment = (*MMOI)->getAlign(); |
105 | |
106 | unsigned AlignmentHint = 0; |
107 | if (Alignment >= Align(16)) |
108 | AlignmentHint = 4; |
109 | else if (Alignment >= Align(8)) |
110 | AlignmentHint = 3; |
111 | if (AlignmentHint == 0) |
112 | return; |
113 | |
114 | LoweredMI.setOpcode(Opcode); |
115 | LoweredMI.addOperand(Op: MCOperand::createImm(Val: AlignmentHint)); |
116 | } |
117 | |
118 | // MI loads the high part of a vector from memory. Return an instruction |
119 | // that uses replicating vector load Opcode to do the same thing. |
120 | static MCInst lowerSubvectorLoad(const MachineInstr *MI, unsigned Opcode) { |
121 | return MCInstBuilder(Opcode) |
122 | .addReg(Reg: SystemZMC::getRegAsVR128(Reg: MI->getOperand(i: 0).getReg())) |
123 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
124 | .addImm(Val: MI->getOperand(i: 2).getImm()) |
125 | .addReg(Reg: MI->getOperand(i: 3).getReg()); |
126 | } |
127 | |
128 | // MI stores the high part of a vector to memory. Return an instruction |
129 | // that uses elemental vector store Opcode to do the same thing. |
130 | static MCInst lowerSubvectorStore(const MachineInstr *MI, unsigned Opcode) { |
131 | return MCInstBuilder(Opcode) |
132 | .addReg(Reg: SystemZMC::getRegAsVR128(Reg: MI->getOperand(i: 0).getReg())) |
133 | .addReg(Reg: MI->getOperand(i: 1).getReg()) |
134 | .addImm(Val: MI->getOperand(i: 2).getImm()) |
135 | .addReg(Reg: MI->getOperand(i: 3).getReg()) |
136 | .addImm(Val: 0); |
137 | } |
138 | |
139 | // The XPLINK ABI requires that a no-op encoding the call type is emitted after |
140 | // each call to a subroutine. This information can be used by the called |
141 | // function to determine its entry point, e.g. for generating a backtrace. The |
142 | // call type is encoded as a register number in the bcr instruction. See |
143 | // enumeration CallType for the possible values. |
144 | void SystemZAsmPrinter::emitCallInformation(CallType CT) { |
145 | EmitToStreamer(*OutStreamer, |
146 | MCInstBuilder(SystemZ::BCRAsm) |
147 | .addImm(0) |
148 | .addReg(SystemZMC::GR64Regs[static_cast<unsigned>(CT)])); |
149 | } |
150 | |
151 | uint32_t SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MCSymbol *Sym, |
152 | unsigned SlotKind) { |
153 | auto Key = std::make_pair(x&: Sym, y&: SlotKind); |
154 | auto It = Displacements.find(Key); |
155 | |
156 | if (It != Displacements.end()) |
157 | return (*It).second; |
158 | |
159 | // Determine length of descriptor. |
160 | uint32_t Length; |
161 | switch (SlotKind) { |
162 | case SystemZII::MO_ADA_DIRECT_FUNC_DESC: |
163 | Length = 2 * PointerSize; |
164 | break; |
165 | default: |
166 | Length = PointerSize; |
167 | break; |
168 | } |
169 | |
170 | uint32_t Displacement = NextDisplacement; |
171 | Displacements[std::make_pair(x&: Sym, y&: SlotKind)] = NextDisplacement; |
172 | NextDisplacement += Length; |
173 | |
174 | return Displacement; |
175 | } |
176 | |
177 | uint32_t |
178 | SystemZAsmPrinter::AssociatedDataAreaTable::insert(const MachineOperand MO) { |
179 | MCSymbol *Sym; |
180 | if (MO.getType() == MachineOperand::MO_GlobalAddress) { |
181 | const GlobalValue *GV = MO.getGlobal(); |
182 | Sym = MO.getParent()->getMF()->getTarget().getSymbol(GV); |
183 | assert(Sym && "No symbol" ); |
184 | } else if (MO.getType() == MachineOperand::MO_ExternalSymbol) { |
185 | const char *SymName = MO.getSymbolName(); |
186 | Sym = MO.getParent()->getMF()->getContext().getOrCreateSymbol(Name: SymName); |
187 | assert(Sym && "No symbol" ); |
188 | } else |
189 | llvm_unreachable("Unexpected operand type" ); |
190 | |
191 | unsigned ADAslotType = MO.getTargetFlags(); |
192 | return insert(Sym, SlotKind: ADAslotType); |
193 | } |
194 | |
195 | void SystemZAsmPrinter::emitInstruction(const MachineInstr *MI) { |
196 | SystemZ_MC::verifyInstructionPredicates(MI->getOpcode(), |
197 | getSubtargetInfo().getFeatureBits()); |
198 | |
199 | SystemZMCInstLower Lower(MF->getContext(), *this); |
200 | MCInst LoweredMI; |
201 | switch (MI->getOpcode()) { |
202 | case SystemZ::Return: |
203 | LoweredMI = MCInstBuilder(SystemZ::BR) |
204 | .addReg(SystemZ::Reg: R14D); |
205 | break; |
206 | |
207 | case SystemZ::Return_XPLINK: |
208 | LoweredMI = MCInstBuilder(SystemZ::B) |
209 | .addReg(SystemZ::R7D) |
210 | .addImm(2) |
211 | .addReg(0); |
212 | break; |
213 | |
214 | case SystemZ::CondReturn: |
215 | LoweredMI = MCInstBuilder(SystemZ::BCR) |
216 | .addImm(MI->getOperand(0).getImm()) |
217 | .addImm(MI->getOperand(1).getImm()) |
218 | .addReg(SystemZ::R14D); |
219 | break; |
220 | |
221 | case SystemZ::CondReturn_XPLINK: |
222 | LoweredMI = MCInstBuilder(SystemZ::BC) |
223 | .addImm(MI->getOperand(0).getImm()) |
224 | .addImm(MI->getOperand(1).getImm()) |
225 | .addReg(SystemZ::R7D) |
226 | .addImm(2) |
227 | .addReg(0); |
228 | break; |
229 | |
230 | case SystemZ::CRBReturn: |
231 | LoweredMI = MCInstBuilder(SystemZ::CRB) |
232 | .addReg(MI->getOperand(0).getReg()) |
233 | .addReg(MI->getOperand(1).getReg()) |
234 | .addImm(MI->getOperand(2).getImm()) |
235 | .addReg(SystemZ::R14D) |
236 | .addImm(0); |
237 | break; |
238 | |
239 | case SystemZ::CGRBReturn: |
240 | LoweredMI = MCInstBuilder(SystemZ::CGRB) |
241 | .addReg(MI->getOperand(0).getReg()) |
242 | .addReg(MI->getOperand(1).getReg()) |
243 | .addImm(MI->getOperand(2).getImm()) |
244 | .addReg(SystemZ::R14D) |
245 | .addImm(0); |
246 | break; |
247 | |
248 | case SystemZ::CIBReturn: |
249 | LoweredMI = MCInstBuilder(SystemZ::CIB) |
250 | .addReg(MI->getOperand(0).getReg()) |
251 | .addImm(MI->getOperand(1).getImm()) |
252 | .addImm(MI->getOperand(2).getImm()) |
253 | .addReg(SystemZ::R14D) |
254 | .addImm(0); |
255 | break; |
256 | |
257 | case SystemZ::CGIBReturn: |
258 | LoweredMI = MCInstBuilder(SystemZ::CGIB) |
259 | .addReg(MI->getOperand(0).getReg()) |
260 | .addImm(MI->getOperand(1).getImm()) |
261 | .addImm(MI->getOperand(2).getImm()) |
262 | .addReg(SystemZ::R14D) |
263 | .addImm(0); |
264 | break; |
265 | |
266 | case SystemZ::CLRBReturn: |
267 | LoweredMI = MCInstBuilder(SystemZ::CLRB) |
268 | .addReg(MI->getOperand(0).getReg()) |
269 | .addReg(MI->getOperand(1).getReg()) |
270 | .addImm(MI->getOperand(2).getImm()) |
271 | .addReg(SystemZ::R14D) |
272 | .addImm(0); |
273 | break; |
274 | |
275 | case SystemZ::CLGRBReturn: |
276 | LoweredMI = MCInstBuilder(SystemZ::CLGRB) |
277 | .addReg(MI->getOperand(0).getReg()) |
278 | .addReg(MI->getOperand(1).getReg()) |
279 | .addImm(MI->getOperand(2).getImm()) |
280 | .addReg(SystemZ::R14D) |
281 | .addImm(0); |
282 | break; |
283 | |
284 | case SystemZ::CLIBReturn: |
285 | LoweredMI = MCInstBuilder(SystemZ::CLIB) |
286 | .addReg(MI->getOperand(0).getReg()) |
287 | .addImm(MI->getOperand(1).getImm()) |
288 | .addImm(MI->getOperand(2).getImm()) |
289 | .addReg(SystemZ::R14D) |
290 | .addImm(0); |
291 | break; |
292 | |
293 | case SystemZ::CLGIBReturn: |
294 | LoweredMI = MCInstBuilder(SystemZ::CLGIB) |
295 | .addReg(MI->getOperand(0).getReg()) |
296 | .addImm(MI->getOperand(1).getImm()) |
297 | .addImm(MI->getOperand(2).getImm()) |
298 | .addReg(SystemZ::R14D) |
299 | .addImm(0); |
300 | break; |
301 | |
302 | case SystemZ::CallBRASL_XPLINK64: |
303 | EmitToStreamer(*OutStreamer, |
304 | MCInstBuilder(SystemZ::BRASL) |
305 | .addReg(SystemZ::R7D) |
306 | .addExpr(Lower.getExpr(MI->getOperand(0), |
307 | MCSymbolRefExpr::VK_PLT))); |
308 | emitCallInformation(CT: CallType::BRASL7); |
309 | return; |
310 | |
311 | case SystemZ::CallBASR_XPLINK64: |
312 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR) |
313 | .addReg(SystemZ::R7D) |
314 | .addReg(MI->getOperand(0).getReg())); |
315 | emitCallInformation(CT: CallType::BASR76); |
316 | return; |
317 | |
318 | case SystemZ::CallBASR_STACKEXT: |
319 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR) |
320 | .addReg(SystemZ::R3D) |
321 | .addReg(MI->getOperand(0).getReg())); |
322 | emitCallInformation(CT: CallType::BASR33); |
323 | return; |
324 | |
325 | case SystemZ::ADA_ENTRY_VALUE: |
326 | case SystemZ::ADA_ENTRY: { |
327 | const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>(); |
328 | const SystemZInstrInfo *TII = Subtarget.getInstrInfo(); |
329 | uint32_t Disp = ADATable.insert(MO: MI->getOperand(i: 1)); |
330 | Register TargetReg = MI->getOperand(i: 0).getReg(); |
331 | |
332 | Register ADAReg = MI->getOperand(i: 2).getReg(); |
333 | Disp += MI->getOperand(i: 3).getImm(); |
334 | bool LoadAddr = MI->getOpcode() == SystemZ::ADA_ENTRY; |
335 | |
336 | unsigned Op0 = LoadAddr ? SystemZ::LA : SystemZ::LG; |
337 | unsigned Op = TII->getOpcodeForOffset(Opcode: Op0, Offset: Disp); |
338 | |
339 | Register IndexReg = 0; |
340 | if (!Op) { |
341 | if (TargetReg != ADAReg) { |
342 | IndexReg = TargetReg; |
343 | // Use TargetReg to store displacement. |
344 | EmitToStreamer( |
345 | *OutStreamer, |
346 | MCInstBuilder(SystemZ::LLILF).addReg(TargetReg).addImm(Disp)); |
347 | } else |
348 | EmitToStreamer( |
349 | *OutStreamer, |
350 | MCInstBuilder(SystemZ::ALGFI).addReg(TargetReg).addImm(Disp)); |
351 | Disp = 0; |
352 | Op = Op0; |
353 | } |
354 | EmitToStreamer(S&: *OutStreamer, Inst: MCInstBuilder(Op) |
355 | .addReg(Reg: TargetReg) |
356 | .addReg(Reg: ADAReg) |
357 | .addImm(Val: Disp) |
358 | .addReg(Reg: IndexReg)); |
359 | |
360 | return; |
361 | } |
362 | case SystemZ::CallBRASL: |
363 | LoweredMI = MCInstBuilder(SystemZ::BRASL) |
364 | .addReg(SystemZ::R14D) |
365 | .addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_PLT)); |
366 | break; |
367 | |
368 | case SystemZ::CallBASR: |
369 | LoweredMI = MCInstBuilder(SystemZ::BASR) |
370 | .addReg(SystemZ::R14D) |
371 | .addReg(MI->getOperand(0).getReg()); |
372 | break; |
373 | |
374 | case SystemZ::CallJG: |
375 | LoweredMI = MCInstBuilder(SystemZ::JG) |
376 | .addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_PLT)); |
377 | break; |
378 | |
379 | case SystemZ::CallBRCL: |
380 | LoweredMI = MCInstBuilder(SystemZ::BRCL) |
381 | .addImm(MI->getOperand(0).getImm()) |
382 | .addImm(MI->getOperand(1).getImm()) |
383 | .addExpr(Lower.getExpr(MI->getOperand(2), MCSymbolRefExpr::VK_PLT)); |
384 | break; |
385 | |
386 | case SystemZ::CallBR: |
387 | LoweredMI = MCInstBuilder(SystemZ::BR) |
388 | .addReg(MI->getOperand(0).getReg()); |
389 | break; |
390 | |
391 | case SystemZ::CallBCR: |
392 | LoweredMI = MCInstBuilder(SystemZ::BCR) |
393 | .addImm(MI->getOperand(0).getImm()) |
394 | .addImm(MI->getOperand(1).getImm()) |
395 | .addReg(MI->getOperand(2).getReg()); |
396 | break; |
397 | |
398 | case SystemZ::CRBCall: |
399 | LoweredMI = MCInstBuilder(SystemZ::CRB) |
400 | .addReg(MI->getOperand(0).getReg()) |
401 | .addReg(MI->getOperand(1).getReg()) |
402 | .addImm(MI->getOperand(2).getImm()) |
403 | .addReg(MI->getOperand(3).getReg()) |
404 | .addImm(0); |
405 | break; |
406 | |
407 | case SystemZ::CGRBCall: |
408 | LoweredMI = MCInstBuilder(SystemZ::CGRB) |
409 | .addReg(MI->getOperand(0).getReg()) |
410 | .addReg(MI->getOperand(1).getReg()) |
411 | .addImm(MI->getOperand(2).getImm()) |
412 | .addReg(MI->getOperand(3).getReg()) |
413 | .addImm(0); |
414 | break; |
415 | |
416 | case SystemZ::CIBCall: |
417 | LoweredMI = MCInstBuilder(SystemZ::CIB) |
418 | .addReg(MI->getOperand(0).getReg()) |
419 | .addImm(MI->getOperand(1).getImm()) |
420 | .addImm(MI->getOperand(2).getImm()) |
421 | .addReg(MI->getOperand(3).getReg()) |
422 | .addImm(0); |
423 | break; |
424 | |
425 | case SystemZ::CGIBCall: |
426 | LoweredMI = MCInstBuilder(SystemZ::CGIB) |
427 | .addReg(MI->getOperand(0).getReg()) |
428 | .addImm(MI->getOperand(1).getImm()) |
429 | .addImm(MI->getOperand(2).getImm()) |
430 | .addReg(MI->getOperand(3).getReg()) |
431 | .addImm(0); |
432 | break; |
433 | |
434 | case SystemZ::CLRBCall: |
435 | LoweredMI = MCInstBuilder(SystemZ::CLRB) |
436 | .addReg(MI->getOperand(0).getReg()) |
437 | .addReg(MI->getOperand(1).getReg()) |
438 | .addImm(MI->getOperand(2).getImm()) |
439 | .addReg(MI->getOperand(3).getReg()) |
440 | .addImm(0); |
441 | break; |
442 | |
443 | case SystemZ::CLGRBCall: |
444 | LoweredMI = MCInstBuilder(SystemZ::CLGRB) |
445 | .addReg(MI->getOperand(0).getReg()) |
446 | .addReg(MI->getOperand(1).getReg()) |
447 | .addImm(MI->getOperand(2).getImm()) |
448 | .addReg(MI->getOperand(3).getReg()) |
449 | .addImm(0); |
450 | break; |
451 | |
452 | case SystemZ::CLIBCall: |
453 | LoweredMI = MCInstBuilder(SystemZ::CLIB) |
454 | .addReg(MI->getOperand(0).getReg()) |
455 | .addImm(MI->getOperand(1).getImm()) |
456 | .addImm(MI->getOperand(2).getImm()) |
457 | .addReg(MI->getOperand(3).getReg()) |
458 | .addImm(0); |
459 | break; |
460 | |
461 | case SystemZ::CLGIBCall: |
462 | LoweredMI = MCInstBuilder(SystemZ::CLGIB) |
463 | .addReg(MI->getOperand(0).getReg()) |
464 | .addImm(MI->getOperand(1).getImm()) |
465 | .addImm(MI->getOperand(2).getImm()) |
466 | .addReg(MI->getOperand(3).getReg()) |
467 | .addImm(0); |
468 | break; |
469 | |
470 | case SystemZ::TLS_GDCALL: |
471 | LoweredMI = MCInstBuilder(SystemZ::BRASL) |
472 | .addReg(SystemZ::R14D) |
473 | .addExpr(getTLSGetOffset(MF->getContext())) |
474 | .addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_TLSGD)); |
475 | break; |
476 | |
477 | case SystemZ::TLS_LDCALL: |
478 | LoweredMI = MCInstBuilder(SystemZ::BRASL) |
479 | .addReg(SystemZ::R14D) |
480 | .addExpr(getTLSGetOffset(MF->getContext())) |
481 | .addExpr(Lower.getExpr(MI->getOperand(0), MCSymbolRefExpr::VK_TLSLDM)); |
482 | break; |
483 | |
484 | case SystemZ::GOT: |
485 | LoweredMI = MCInstBuilder(SystemZ::LARL) |
486 | .addReg(MI->getOperand(0).getReg()) |
487 | .addExpr(getGlobalOffsetTable(MF->getContext())); |
488 | break; |
489 | |
490 | case SystemZ::IILF64: |
491 | LoweredMI = MCInstBuilder(SystemZ::IILF) |
492 | .addReg(SystemZMC::getRegAsGR32(MI->getOperand(0).getReg())) |
493 | .addImm(MI->getOperand(2).getImm()); |
494 | break; |
495 | |
496 | case SystemZ::IIHF64: |
497 | LoweredMI = MCInstBuilder(SystemZ::IIHF) |
498 | .addReg(SystemZMC::getRegAsGRH32(MI->getOperand(0).getReg())) |
499 | .addImm(MI->getOperand(2).getImm()); |
500 | break; |
501 | |
502 | case SystemZ::RISBHH: |
503 | case SystemZ::RISBHL: |
504 | LoweredMI = lowerRIEfLow(MI, SystemZ::RISBHG); |
505 | break; |
506 | |
507 | case SystemZ::RISBLH: |
508 | case SystemZ::RISBLL: |
509 | LoweredMI = lowerRIEfLow(MI, SystemZ::RISBLG); |
510 | break; |
511 | |
512 | case SystemZ::VLVGP32: |
513 | LoweredMI = MCInstBuilder(SystemZ::VLVGP) |
514 | .addReg(MI->getOperand(0).getReg()) |
515 | .addReg(SystemZMC::getRegAsGR64(MI->getOperand(1).getReg())) |
516 | .addReg(SystemZMC::getRegAsGR64(MI->getOperand(2).getReg())); |
517 | break; |
518 | |
519 | case SystemZ::VLR32: |
520 | case SystemZ::VLR64: |
521 | LoweredMI = MCInstBuilder(SystemZ::VLR) |
522 | .addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg())) |
523 | .addReg(SystemZMC::getRegAsVR128(MI->getOperand(1).getReg())); |
524 | break; |
525 | |
526 | case SystemZ::VL: |
527 | Lower.lower(MI, OutMI&: LoweredMI); |
528 | lowerAlignmentHint(MI, LoweredMI, SystemZ::VLAlign); |
529 | break; |
530 | |
531 | case SystemZ::VST: |
532 | Lower.lower(MI, OutMI&: LoweredMI); |
533 | lowerAlignmentHint(MI, LoweredMI, SystemZ::VSTAlign); |
534 | break; |
535 | |
536 | case SystemZ::VLM: |
537 | Lower.lower(MI, OutMI&: LoweredMI); |
538 | lowerAlignmentHint(MI, LoweredMI, SystemZ::VLMAlign); |
539 | break; |
540 | |
541 | case SystemZ::VSTM: |
542 | Lower.lower(MI, OutMI&: LoweredMI); |
543 | lowerAlignmentHint(MI, LoweredMI, SystemZ::VSTMAlign); |
544 | break; |
545 | |
546 | case SystemZ::VL32: |
547 | LoweredMI = lowerSubvectorLoad(MI, SystemZ::VLREPF); |
548 | break; |
549 | |
550 | case SystemZ::VL64: |
551 | LoweredMI = lowerSubvectorLoad(MI, SystemZ::VLREPG); |
552 | break; |
553 | |
554 | case SystemZ::VST32: |
555 | LoweredMI = lowerSubvectorStore(MI, SystemZ::VSTEF); |
556 | break; |
557 | |
558 | case SystemZ::VST64: |
559 | LoweredMI = lowerSubvectorStore(MI, SystemZ::VSTEG); |
560 | break; |
561 | |
562 | case SystemZ::LFER: |
563 | LoweredMI = MCInstBuilder(SystemZ::VLGVF) |
564 | .addReg(SystemZMC::getRegAsGR64(MI->getOperand(0).getReg())) |
565 | .addReg(SystemZMC::getRegAsVR128(MI->getOperand(1).getReg())) |
566 | .addReg(0).addImm(0); |
567 | break; |
568 | |
569 | case SystemZ::LEFR: |
570 | LoweredMI = MCInstBuilder(SystemZ::VLVGF) |
571 | .addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg())) |
572 | .addReg(SystemZMC::getRegAsVR128(MI->getOperand(0).getReg())) |
573 | .addReg(MI->getOperand(1).getReg()) |
574 | .addReg(0).addImm(0); |
575 | break; |
576 | |
577 | #define LOWER_LOW(NAME) \ |
578 | case SystemZ::NAME##64: LoweredMI = lowerRILow(MI, SystemZ::NAME); break |
579 | |
580 | LOWER_LOW(IILL); |
581 | LOWER_LOW(IILH); |
582 | LOWER_LOW(TMLL); |
583 | LOWER_LOW(TMLH); |
584 | LOWER_LOW(NILL); |
585 | LOWER_LOW(NILH); |
586 | LOWER_LOW(NILF); |
587 | LOWER_LOW(OILL); |
588 | LOWER_LOW(OILH); |
589 | LOWER_LOW(OILF); |
590 | LOWER_LOW(XILF); |
591 | |
592 | #undef LOWER_LOW |
593 | |
594 | #define LOWER_HIGH(NAME) \ |
595 | case SystemZ::NAME##64: LoweredMI = lowerRIHigh(MI, SystemZ::NAME); break |
596 | |
597 | LOWER_HIGH(IIHL); |
598 | LOWER_HIGH(IIHH); |
599 | LOWER_HIGH(TMHL); |
600 | LOWER_HIGH(TMHH); |
601 | LOWER_HIGH(NIHL); |
602 | LOWER_HIGH(NIHH); |
603 | LOWER_HIGH(NIHF); |
604 | LOWER_HIGH(OIHL); |
605 | LOWER_HIGH(OIHH); |
606 | LOWER_HIGH(OIHF); |
607 | LOWER_HIGH(XIHF); |
608 | |
609 | #undef LOWER_HIGH |
610 | |
611 | case SystemZ::Serialize: |
612 | if (MF->getSubtarget<SystemZSubtarget>().hasFastSerialization()) |
613 | LoweredMI = MCInstBuilder(SystemZ::BCRAsm) |
614 | .addImm(14).addReg(SystemZ::R0D); |
615 | else |
616 | LoweredMI = MCInstBuilder(SystemZ::BCRAsm) |
617 | .addImm(15).addReg(SystemZ::R0D); |
618 | break; |
619 | |
620 | // We want to emit "j .+2" for traps, jumping to the relative immediate field |
621 | // of the jump instruction, which is an illegal instruction. We cannot emit a |
622 | // "." symbol, so create and emit a temp label before the instruction and use |
623 | // that instead. |
624 | case SystemZ::Trap: { |
625 | MCSymbol *DotSym = OutContext.createTempSymbol(); |
626 | OutStreamer->emitLabel(Symbol: DotSym); |
627 | |
628 | const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Symbol: DotSym, Ctx&: OutContext); |
629 | const MCConstantExpr *ConstExpr = MCConstantExpr::create(Value: 2, Ctx&: OutContext); |
630 | LoweredMI = MCInstBuilder(SystemZ::J) |
631 | .addExpr(MCBinaryExpr::createAdd(Expr, ConstExpr, OutContext)); |
632 | } |
633 | break; |
634 | |
635 | // Conditional traps will create a branch on condition instruction that jumps |
636 | // to the relative immediate field of the jump instruction. (eg. "jo .+2") |
637 | case SystemZ::CondTrap: { |
638 | MCSymbol *DotSym = OutContext.createTempSymbol(); |
639 | OutStreamer->emitLabel(Symbol: DotSym); |
640 | |
641 | const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Symbol: DotSym, Ctx&: OutContext); |
642 | const MCConstantExpr *ConstExpr = MCConstantExpr::create(Value: 2, Ctx&: OutContext); |
643 | LoweredMI = MCInstBuilder(SystemZ::BRC) |
644 | .addImm(MI->getOperand(0).getImm()) |
645 | .addImm(MI->getOperand(1).getImm()) |
646 | .addExpr(MCBinaryExpr::createAdd(Expr, ConstExpr, OutContext)); |
647 | } |
648 | break; |
649 | |
650 | case TargetOpcode::FENTRY_CALL: |
651 | LowerFENTRY_CALL(MI: *MI, MCIL&: Lower); |
652 | return; |
653 | |
654 | case TargetOpcode::STACKMAP: |
655 | LowerSTACKMAP(MI: *MI); |
656 | return; |
657 | |
658 | case TargetOpcode::PATCHPOINT: |
659 | LowerPATCHPOINT(MI: *MI, Lower); |
660 | return; |
661 | |
662 | case SystemZ::EXRL_Pseudo: { |
663 | unsigned TargetInsOpc = MI->getOperand(i: 0).getImm(); |
664 | Register LenMinus1Reg = MI->getOperand(i: 1).getReg(); |
665 | Register DestReg = MI->getOperand(i: 2).getReg(); |
666 | int64_t DestDisp = MI->getOperand(i: 3).getImm(); |
667 | Register SrcReg = MI->getOperand(i: 4).getReg(); |
668 | int64_t SrcDisp = MI->getOperand(i: 5).getImm(); |
669 | |
670 | SystemZTargetStreamer *TS = getTargetStreamer(); |
671 | MCSymbol *DotSym = nullptr; |
672 | MCInst ET = MCInstBuilder(TargetInsOpc).addReg(Reg: DestReg) |
673 | .addImm(Val: DestDisp).addImm(Val: 1).addReg(Reg: SrcReg).addImm(Val: SrcDisp); |
674 | SystemZTargetStreamer::MCInstSTIPair ET_STI(ET, &MF->getSubtarget()); |
675 | SystemZTargetStreamer::EXRLT2SymMap::iterator I = |
676 | TS->EXRLTargets2Sym.find(x: ET_STI); |
677 | if (I != TS->EXRLTargets2Sym.end()) |
678 | DotSym = I->second; |
679 | else |
680 | TS->EXRLTargets2Sym[ET_STI] = DotSym = OutContext.createTempSymbol(); |
681 | const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(Symbol: DotSym, Ctx&: OutContext); |
682 | EmitToStreamer( |
683 | *OutStreamer, |
684 | MCInstBuilder(SystemZ::EXRL).addReg(LenMinus1Reg).addExpr(Dot)); |
685 | return; |
686 | } |
687 | |
688 | default: |
689 | Lower.lower(MI, OutMI&: LoweredMI); |
690 | break; |
691 | } |
692 | EmitToStreamer(S&: *OutStreamer, Inst: LoweredMI); |
693 | } |
694 | |
695 | // Emit the largest nop instruction smaller than or equal to NumBytes |
696 | // bytes. Return the size of nop emitted. |
697 | static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer, |
698 | unsigned NumBytes, const MCSubtargetInfo &STI) { |
699 | if (NumBytes < 2) { |
700 | llvm_unreachable("Zero nops?" ); |
701 | return 0; |
702 | } |
703 | else if (NumBytes < 4) { |
704 | OutStreamer.emitInstruction( |
705 | MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI); |
706 | return 2; |
707 | } |
708 | else if (NumBytes < 6) { |
709 | OutStreamer.emitInstruction( |
710 | MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0), |
711 | STI); |
712 | return 4; |
713 | } |
714 | else { |
715 | MCSymbol *DotSym = OutContext.createTempSymbol(); |
716 | const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(Symbol: DotSym, Ctx&: OutContext); |
717 | OutStreamer.emitLabel(Symbol: DotSym); |
718 | OutStreamer.emitInstruction( |
719 | MCInstBuilder(SystemZ::BRCLAsm).addImm(0).addExpr(Dot), STI); |
720 | return 6; |
721 | } |
722 | } |
723 | |
724 | void SystemZAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI, |
725 | SystemZMCInstLower &Lower) { |
726 | MCContext &Ctx = MF->getContext(); |
727 | if (MF->getFunction().hasFnAttribute(Kind: "mrecord-mcount" )) { |
728 | MCSymbol *DotSym = OutContext.createTempSymbol(); |
729 | OutStreamer->pushSection(); |
730 | OutStreamer->switchSection( |
731 | Section: Ctx.getELFSection(Section: "__mcount_loc" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_ALLOC)); |
732 | OutStreamer->emitSymbolValue(Sym: DotSym, Size: 8); |
733 | OutStreamer->popSection(); |
734 | OutStreamer->emitLabel(Symbol: DotSym); |
735 | } |
736 | |
737 | if (MF->getFunction().hasFnAttribute(Kind: "mnop-mcount" )) { |
738 | EmitNop(OutContext&: Ctx, OutStreamer&: *OutStreamer, NumBytes: 6, STI: getSubtargetInfo()); |
739 | return; |
740 | } |
741 | |
742 | MCSymbol *fentry = Ctx.getOrCreateSymbol(Name: "__fentry__" ); |
743 | const MCSymbolRefExpr *Op = |
744 | MCSymbolRefExpr::create(Symbol: fentry, Kind: MCSymbolRefExpr::VK_PLT, Ctx); |
745 | OutStreamer->emitInstruction( |
746 | MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R0D).addExpr(Op), |
747 | getSubtargetInfo()); |
748 | } |
749 | |
750 | void SystemZAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) { |
751 | auto *TII = MF->getSubtarget<SystemZSubtarget>().getInstrInfo(); |
752 | |
753 | unsigned NumNOPBytes = MI.getOperand(i: 1).getImm(); |
754 | |
755 | auto &Ctx = OutStreamer->getContext(); |
756 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
757 | OutStreamer->emitLabel(Symbol: MILabel); |
758 | |
759 | SM.recordStackMap(L: *MILabel, MI); |
760 | assert(NumNOPBytes % 2 == 0 && "Invalid number of NOP bytes requested!" ); |
761 | |
762 | // Scan ahead to trim the shadow. |
763 | unsigned ShadowBytes = 0; |
764 | const MachineBasicBlock &MBB = *MI.getParent(); |
765 | MachineBasicBlock::const_iterator MII(MI); |
766 | ++MII; |
767 | while (ShadowBytes < NumNOPBytes) { |
768 | if (MII == MBB.end() || |
769 | MII->getOpcode() == TargetOpcode::PATCHPOINT || |
770 | MII->getOpcode() == TargetOpcode::STACKMAP) |
771 | break; |
772 | ShadowBytes += TII->getInstSizeInBytes(MI: *MII); |
773 | if (MII->isCall()) |
774 | break; |
775 | ++MII; |
776 | } |
777 | |
778 | // Emit nops. |
779 | while (ShadowBytes < NumNOPBytes) |
780 | ShadowBytes += EmitNop(OutContext, OutStreamer&: *OutStreamer, NumBytes: NumNOPBytes - ShadowBytes, |
781 | STI: getSubtargetInfo()); |
782 | } |
783 | |
784 | // Lower a patchpoint of the form: |
785 | // [<def>], <id>, <numBytes>, <target>, <numArgs> |
786 | void SystemZAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI, |
787 | SystemZMCInstLower &Lower) { |
788 | auto &Ctx = OutStreamer->getContext(); |
789 | MCSymbol *MILabel = Ctx.createTempSymbol(); |
790 | OutStreamer->emitLabel(Symbol: MILabel); |
791 | |
792 | SM.recordPatchPoint(L: *MILabel, MI); |
793 | PatchPointOpers Opers(&MI); |
794 | |
795 | unsigned EncodedBytes = 0; |
796 | const MachineOperand &CalleeMO = Opers.getCallTarget(); |
797 | |
798 | if (CalleeMO.isImm()) { |
799 | uint64_t CallTarget = CalleeMO.getImm(); |
800 | if (CallTarget) { |
801 | unsigned ScratchIdx = -1; |
802 | unsigned ScratchReg = 0; |
803 | do { |
804 | ScratchIdx = Opers.getNextScratchIdx(StartIdx: ScratchIdx + 1); |
805 | ScratchReg = MI.getOperand(i: ScratchIdx).getReg(); |
806 | } while (ScratchReg == SystemZ::R0D); |
807 | |
808 | // Materialize the call target address |
809 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF) |
810 | .addReg(ScratchReg) |
811 | .addImm(CallTarget & 0xFFFFFFFF)); |
812 | EncodedBytes += 6; |
813 | if (CallTarget >> 32) { |
814 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF) |
815 | .addReg(ScratchReg) |
816 | .addImm(CallTarget >> 32)); |
817 | EncodedBytes += 6; |
818 | } |
819 | |
820 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR) |
821 | .addReg(SystemZ::R14D) |
822 | .addReg(ScratchReg)); |
823 | EncodedBytes += 2; |
824 | } |
825 | } else if (CalleeMO.isGlobal()) { |
826 | const MCExpr *Expr = Lower.getExpr(MO: CalleeMO, Kind: MCSymbolRefExpr::VK_PLT); |
827 | EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL) |
828 | .addReg(SystemZ::R14D) |
829 | .addExpr(Expr)); |
830 | EncodedBytes += 6; |
831 | } |
832 | |
833 | // Emit padding. |
834 | unsigned NumBytes = Opers.getNumPatchBytes(); |
835 | assert(NumBytes >= EncodedBytes && |
836 | "Patchpoint can't request size less than the length of a call." ); |
837 | assert((NumBytes - EncodedBytes) % 2 == 0 && |
838 | "Invalid number of NOP bytes requested!" ); |
839 | while (EncodedBytes < NumBytes) |
840 | EncodedBytes += EmitNop(OutContext, OutStreamer&: *OutStreamer, NumBytes: NumBytes - EncodedBytes, |
841 | STI: getSubtargetInfo()); |
842 | } |
843 | |
844 | // The *alignment* of 128-bit vector types is different between the software |
845 | // and hardware vector ABIs. If the there is an externally visible use of a |
846 | // vector type in the module it should be annotated with an attribute. |
847 | void SystemZAsmPrinter::emitAttributes(Module &M) { |
848 | if (M.getModuleFlag(Key: "s390x-visible-vector-ABI" )) { |
849 | bool HasVectorFeature = |
850 | TM.getMCSubtargetInfo()->hasFeature(SystemZ::FeatureVector); |
851 | OutStreamer->emitGNUAttribute(Tag: 8, Value: HasVectorFeature ? 2 : 1); |
852 | } |
853 | } |
854 | |
855 | // Convert a SystemZ-specific constant pool modifier into the associated |
856 | // MCSymbolRefExpr variant kind. |
857 | static MCSymbolRefExpr::VariantKind |
858 | getModifierVariantKind(SystemZCP::SystemZCPModifier Modifier) { |
859 | switch (Modifier) { |
860 | case SystemZCP::TLSGD: return MCSymbolRefExpr::VK_TLSGD; |
861 | case SystemZCP::TLSLDM: return MCSymbolRefExpr::VK_TLSLDM; |
862 | case SystemZCP::DTPOFF: return MCSymbolRefExpr::VK_DTPOFF; |
863 | case SystemZCP::NTPOFF: return MCSymbolRefExpr::VK_NTPOFF; |
864 | } |
865 | llvm_unreachable("Invalid SystemCPModifier!" ); |
866 | } |
867 | |
868 | void SystemZAsmPrinter::emitMachineConstantPoolValue( |
869 | MachineConstantPoolValue *MCPV) { |
870 | auto *ZCPV = static_cast<SystemZConstantPoolValue*>(MCPV); |
871 | |
872 | const MCExpr *Expr = |
873 | MCSymbolRefExpr::create(Symbol: getSymbol(GV: ZCPV->getGlobalValue()), |
874 | Kind: getModifierVariantKind(Modifier: ZCPV->getModifier()), |
875 | Ctx&: OutContext); |
876 | uint64_t Size = getDataLayout().getTypeAllocSize(Ty: ZCPV->getType()); |
877 | |
878 | OutStreamer->emitValue(Value: Expr, Size); |
879 | } |
880 | |
881 | static void printFormattedRegName(const MCAsmInfo *MAI, unsigned RegNo, |
882 | raw_ostream &OS) { |
883 | const char *RegName = SystemZInstPrinter::getRegisterName(Reg: RegNo); |
884 | if (MAI->getAssemblerDialect() == AD_HLASM) { |
885 | // Skip register prefix so that only register number is left |
886 | assert(isalpha(RegName[0]) && isdigit(RegName[1])); |
887 | OS << (RegName + 1); |
888 | } else |
889 | OS << '%' << RegName; |
890 | } |
891 | |
892 | static void printReg(unsigned Reg, const MCAsmInfo *MAI, raw_ostream &OS) { |
893 | if (!Reg) |
894 | OS << '0'; |
895 | else |
896 | printFormattedRegName(MAI, RegNo: Reg, OS); |
897 | } |
898 | |
899 | static void printOperand(const MCOperand &MCOp, const MCAsmInfo *MAI, |
900 | raw_ostream &OS) { |
901 | if (MCOp.isReg()) |
902 | printReg(Reg: MCOp.getReg(), MAI, OS); |
903 | else if (MCOp.isImm()) |
904 | OS << MCOp.getImm(); |
905 | else if (MCOp.isExpr()) |
906 | MCOp.getExpr()->print(OS, MAI); |
907 | else |
908 | llvm_unreachable("Invalid operand" ); |
909 | } |
910 | |
911 | static void printAddress(const MCAsmInfo *MAI, unsigned Base, |
912 | const MCOperand &DispMO, unsigned Index, |
913 | raw_ostream &OS) { |
914 | printOperand(MCOp: DispMO, MAI, OS); |
915 | if (Base || Index) { |
916 | OS << '('; |
917 | if (Index) { |
918 | printFormattedRegName(MAI, RegNo: Index, OS); |
919 | if (Base) |
920 | OS << ','; |
921 | } |
922 | if (Base) |
923 | printFormattedRegName(MAI, RegNo: Base, OS); |
924 | OS << ')'; |
925 | } |
926 | } |
927 | |
928 | bool SystemZAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
929 | const char *, |
930 | raw_ostream &OS) { |
931 | const MCRegisterInfo &MRI = *TM.getMCRegisterInfo(); |
932 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
933 | MCOperand MCOp; |
934 | if (ExtraCode) { |
935 | if (ExtraCode[0] == 'N' && !ExtraCode[1] && MO.isReg() && |
936 | SystemZ::GR128BitRegClass.contains(MO.getReg())) |
937 | MCOp = |
938 | MCOperand::createReg(MRI.getSubReg(MO.getReg(), SystemZ::subreg_l64)); |
939 | else |
940 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS); |
941 | } else { |
942 | SystemZMCInstLower Lower(MF->getContext(), *this); |
943 | MCOp = Lower.lowerOperand(MO); |
944 | } |
945 | printOperand(MCOp, MAI, OS); |
946 | return false; |
947 | } |
948 | |
949 | bool SystemZAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
950 | unsigned OpNo, |
951 | const char *, |
952 | raw_ostream &OS) { |
953 | if (ExtraCode && ExtraCode[0] && !ExtraCode[1]) { |
954 | switch (ExtraCode[0]) { |
955 | case 'A': |
956 | // Unlike EmitMachineNode(), EmitSpecialNode(INLINEASM) does not call |
957 | // setMemRefs(), so MI->memoperands() is empty and the alignment |
958 | // information is not available. |
959 | return false; |
960 | case 'O': |
961 | OS << MI->getOperand(i: OpNo + 1).getImm(); |
962 | return false; |
963 | case 'R': |
964 | ::printReg(Reg: MI->getOperand(i: OpNo).getReg(), MAI, OS); |
965 | return false; |
966 | } |
967 | } |
968 | printAddress(MAI, Base: MI->getOperand(i: OpNo).getReg(), |
969 | DispMO: MCOperand::createImm(Val: MI->getOperand(i: OpNo + 1).getImm()), |
970 | Index: MI->getOperand(i: OpNo + 2).getReg(), OS); |
971 | return false; |
972 | } |
973 | |
974 | void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { |
975 | auto TT = OutContext.getTargetTriple(); |
976 | if (TT.isOSzOS()) { |
977 | emitADASection(); |
978 | emitIDRLSection(M); |
979 | } |
980 | emitAttributes(M); |
981 | } |
982 | |
983 | void SystemZAsmPrinter::emitADASection() { |
984 | OutStreamer->pushSection(); |
985 | |
986 | const unsigned PointerSize = getDataLayout().getPointerSize(); |
987 | OutStreamer->switchSection(Section: getObjFileLowering().getADASection()); |
988 | |
989 | unsigned EmittedBytes = 0; |
990 | for (auto &Entry : ADATable.getTable()) { |
991 | const MCSymbol *Sym; |
992 | unsigned SlotKind; |
993 | std::tie(args&: Sym, args&: SlotKind) = Entry.first; |
994 | unsigned Offset = Entry.second; |
995 | assert(Offset == EmittedBytes && "Offset not as expected" ); |
996 | (void)EmittedBytes; |
997 | #define (Str) \ |
998 | OutStreamer->AddComment(Twine("Offset ") \ |
999 | .concat(utostr(Offset)) \ |
1000 | .concat(" " Str " ") \ |
1001 | .concat(Sym->getName())); |
1002 | switch (SlotKind) { |
1003 | case SystemZII::MO_ADA_DIRECT_FUNC_DESC: |
1004 | // Language Environment DLL logic requires function descriptors, for |
1005 | // imported functions, that are placed in the ADA to be 8 byte aligned. |
1006 | EMIT_COMMENT("function descriptor of" ); |
1007 | OutStreamer->emitValue( |
1008 | Value: SystemZMCExpr::create(Kind: SystemZMCExpr::VK_SystemZ_RCon, |
1009 | Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext), |
1010 | Ctx&: OutContext), |
1011 | Size: PointerSize); |
1012 | OutStreamer->emitValue( |
1013 | Value: SystemZMCExpr::create(Kind: SystemZMCExpr::VK_SystemZ_VCon, |
1014 | Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext), |
1015 | Ctx&: OutContext), |
1016 | Size: PointerSize); |
1017 | EmittedBytes += PointerSize * 2; |
1018 | break; |
1019 | case SystemZII::MO_ADA_DATA_SYMBOL_ADDR: |
1020 | EMIT_COMMENT("pointer to data symbol" ); |
1021 | OutStreamer->emitValue( |
1022 | Value: SystemZMCExpr::create(Kind: SystemZMCExpr::VK_SystemZ_None, |
1023 | Expr: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext), |
1024 | Ctx&: OutContext), |
1025 | Size: PointerSize); |
1026 | EmittedBytes += PointerSize; |
1027 | break; |
1028 | case SystemZII::MO_ADA_INDIRECT_FUNC_DESC: { |
1029 | MCSymbol *Alias = OutContext.createTempSymbol( |
1030 | Name: Twine(Sym->getName()).concat(Suffix: "@indirect" )); |
1031 | OutStreamer->emitAssignment(Symbol: Alias, |
1032 | Value: MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext)); |
1033 | OutStreamer->emitSymbolAttribute(Symbol: Alias, Attribute: MCSA_IndirectSymbol); |
1034 | |
1035 | EMIT_COMMENT("pointer to function descriptor" ); |
1036 | OutStreamer->emitValue( |
1037 | Value: SystemZMCExpr::create(Kind: SystemZMCExpr::VK_SystemZ_VCon, |
1038 | Expr: MCSymbolRefExpr::create(Symbol: Alias, Ctx&: OutContext), |
1039 | Ctx&: OutContext), |
1040 | Size: PointerSize); |
1041 | EmittedBytes += PointerSize; |
1042 | break; |
1043 | } |
1044 | default: |
1045 | llvm_unreachable("Unexpected slot kind" ); |
1046 | } |
1047 | #undef EMIT_COMMENT |
1048 | } |
1049 | OutStreamer->popSection(); |
1050 | } |
1051 | |
1052 | static std::string getProductID(Module &M) { |
1053 | std::string ProductID; |
1054 | if (auto *MD = M.getModuleFlag(Key: "zos_product_id" )) |
1055 | ProductID = cast<MDString>(Val: MD)->getString().str(); |
1056 | if (ProductID.empty()) |
1057 | ProductID = "LLVM" ; |
1058 | return ProductID; |
1059 | } |
1060 | |
1061 | static uint32_t getProductVersion(Module &M) { |
1062 | if (auto *VersionVal = mdconst::extract_or_null<ConstantInt>( |
1063 | MD: M.getModuleFlag(Key: "zos_product_major_version" ))) |
1064 | return VersionVal->getZExtValue(); |
1065 | return LLVM_VERSION_MAJOR; |
1066 | } |
1067 | |
1068 | static uint32_t getProductRelease(Module &M) { |
1069 | if (auto *ReleaseVal = mdconst::extract_or_null<ConstantInt>( |
1070 | MD: M.getModuleFlag(Key: "zos_product_minor_version" ))) |
1071 | return ReleaseVal->getZExtValue(); |
1072 | return LLVM_VERSION_MINOR; |
1073 | } |
1074 | |
1075 | static uint32_t getProductPatch(Module &M) { |
1076 | if (auto *PatchVal = mdconst::extract_or_null<ConstantInt>( |
1077 | MD: M.getModuleFlag(Key: "zos_product_patchlevel" ))) |
1078 | return PatchVal->getZExtValue(); |
1079 | return LLVM_VERSION_PATCH; |
1080 | } |
1081 | |
1082 | static time_t getTranslationTime(Module &M) { |
1083 | std::time_t Time = 0; |
1084 | if (auto *Val = mdconst::extract_or_null<ConstantInt>( |
1085 | MD: M.getModuleFlag(Key: "zos_translation_time" ))) { |
1086 | long SecondsSinceEpoch = Val->getSExtValue(); |
1087 | Time = static_cast<time_t>(SecondsSinceEpoch); |
1088 | } |
1089 | return Time; |
1090 | } |
1091 | |
1092 | void SystemZAsmPrinter::emitIDRLSection(Module &M) { |
1093 | OutStreamer->pushSection(); |
1094 | OutStreamer->switchSection(Section: getObjFileLowering().getIDRLSection()); |
1095 | constexpr unsigned IDRLDataLength = 30; |
1096 | std::time_t Time = getTranslationTime(M); |
1097 | |
1098 | uint32_t ProductVersion = getProductVersion(M); |
1099 | uint32_t ProductRelease = getProductRelease(M); |
1100 | |
1101 | std::string ProductID = getProductID(M); |
1102 | |
1103 | SmallString<IDRLDataLength + 1> TempStr; |
1104 | raw_svector_ostream O(TempStr); |
1105 | O << formatv(Fmt: "{0,-10}{1,0-2:d}{2,0-2:d}{3:%Y%m%d%H%M%S}{4,0-2}" , |
1106 | Vals: ProductID.substr(pos: 0, n: 10).c_str(), Vals&: ProductVersion, Vals&: ProductRelease, |
1107 | Vals: llvm::sys::toUtcTime(T: Time), Vals: "0" ); |
1108 | SmallString<IDRLDataLength> Data; |
1109 | ConverterEBCDIC::convertToEBCDIC(Source: TempStr, Result&: Data); |
1110 | |
1111 | OutStreamer->emitInt8(Value: 0); // Reserved. |
1112 | OutStreamer->emitInt8(Value: 3); // Format. |
1113 | OutStreamer->emitInt16(Value: IDRLDataLength); // Length. |
1114 | OutStreamer->emitBytes(Data: Data.str()); |
1115 | OutStreamer->popSection(); |
1116 | } |
1117 | |
1118 | void SystemZAsmPrinter::emitFunctionBodyEnd() { |
1119 | if (TM.getTargetTriple().isOSzOS()) { |
1120 | // Emit symbol for the end of function if the z/OS target streamer |
1121 | // is used. This is needed to calculate the size of the function. |
1122 | MCSymbol *FnEndSym = createTempSymbol(Name: "func_end" ); |
1123 | OutStreamer->emitLabel(Symbol: FnEndSym); |
1124 | |
1125 | OutStreamer->pushSection(); |
1126 | OutStreamer->switchSection(Section: getObjFileLowering().getPPA1Section()); |
1127 | emitPPA1(FnEndSym); |
1128 | OutStreamer->popSection(); |
1129 | |
1130 | CurrentFnPPA1Sym = nullptr; |
1131 | CurrentFnEPMarkerSym = nullptr; |
1132 | } |
1133 | } |
1134 | |
1135 | static void emitPPA1Flags(std::unique_ptr<MCStreamer> &OutStreamer, bool VarArg, |
1136 | bool StackProtector, bool FPRMask, bool VRMask, |
1137 | bool EHBlock, bool HasName) { |
1138 | enum class PPA1Flag1 : uint8_t { |
1139 | DSA64Bit = (0x80 >> 0), |
1140 | VarArg = (0x80 >> 7), |
1141 | LLVM_MARK_AS_BITMASK_ENUM(DSA64Bit) |
1142 | }; |
1143 | enum class PPA1Flag2 : uint8_t { |
1144 | ExternalProcedure = (0x80 >> 0), |
1145 | STACKPROTECTOR = (0x80 >> 3), |
1146 | LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure) |
1147 | }; |
1148 | enum class PPA1Flag3 : uint8_t { |
1149 | FPRMask = (0x80 >> 2), |
1150 | LLVM_MARK_AS_BITMASK_ENUM(FPRMask) |
1151 | }; |
1152 | enum class PPA1Flag4 : uint8_t { |
1153 | EPMOffsetPresent = (0x80 >> 0), |
1154 | VRMask = (0x80 >> 2), |
1155 | EHBlock = (0x80 >> 3), |
1156 | ProcedureNamePresent = (0x80 >> 7), |
1157 | LLVM_MARK_AS_BITMASK_ENUM(EPMOffsetPresent) |
1158 | }; |
1159 | |
1160 | // Declare optional section flags that can be modified. |
1161 | auto Flags1 = PPA1Flag1(0); |
1162 | auto Flags2 = PPA1Flag2::ExternalProcedure; |
1163 | auto Flags3 = PPA1Flag3(0); |
1164 | auto Flags4 = PPA1Flag4::EPMOffsetPresent; |
1165 | |
1166 | Flags1 |= PPA1Flag1::DSA64Bit; |
1167 | |
1168 | if (VarArg) |
1169 | Flags1 |= PPA1Flag1::VarArg; |
1170 | |
1171 | if (StackProtector) |
1172 | Flags2 |= PPA1Flag2::STACKPROTECTOR; |
1173 | |
1174 | // SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in. |
1175 | if (FPRMask) |
1176 | Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag. |
1177 | |
1178 | if (VRMask) |
1179 | Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag. |
1180 | |
1181 | if (EHBlock) |
1182 | Flags4 |= PPA1Flag4::EHBlock; // Add optional EH block. |
1183 | |
1184 | if (HasName) |
1185 | Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block. |
1186 | |
1187 | OutStreamer->AddComment(T: "PPA1 Flags 1" ); |
1188 | if ((Flags1 & PPA1Flag1::DSA64Bit) == PPA1Flag1::DSA64Bit) |
1189 | OutStreamer->AddComment(T: " Bit 0: 1 = 64-bit DSA" ); |
1190 | else |
1191 | OutStreamer->AddComment(T: " Bit 0: 0 = 32-bit DSA" ); |
1192 | if ((Flags1 & PPA1Flag1::VarArg) == PPA1Flag1::VarArg) |
1193 | OutStreamer->AddComment(T: " Bit 7: 1 = Vararg function" ); |
1194 | OutStreamer->emitInt8(Value: static_cast<uint8_t>(Flags1)); // Flags 1. |
1195 | |
1196 | OutStreamer->AddComment(T: "PPA1 Flags 2" ); |
1197 | if ((Flags2 & PPA1Flag2::ExternalProcedure) == PPA1Flag2::ExternalProcedure) |
1198 | OutStreamer->AddComment(T: " Bit 0: 1 = External procedure" ); |
1199 | if ((Flags2 & PPA1Flag2::STACKPROTECTOR) == PPA1Flag2::STACKPROTECTOR) |
1200 | OutStreamer->AddComment(T: " Bit 3: 1 = STACKPROTECT is enabled" ); |
1201 | else |
1202 | OutStreamer->AddComment(T: " Bit 3: 0 = STACKPROTECT is not enabled" ); |
1203 | OutStreamer->emitInt8(Value: static_cast<uint8_t>(Flags2)); // Flags 2. |
1204 | |
1205 | OutStreamer->AddComment(T: "PPA1 Flags 3" ); |
1206 | if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask) |
1207 | OutStreamer->AddComment(T: " Bit 2: 1 = FP Reg Mask is in optional area" ); |
1208 | OutStreamer->emitInt8( |
1209 | Value: static_cast<uint8_t>(Flags3)); // Flags 3 (optional sections). |
1210 | |
1211 | OutStreamer->AddComment(T: "PPA1 Flags 4" ); |
1212 | if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask) |
1213 | OutStreamer->AddComment(T: " Bit 2: 1 = Vector Reg Mask is in optional area" ); |
1214 | if ((Flags4 & PPA1Flag4::EHBlock) == PPA1Flag4::EHBlock) |
1215 | OutStreamer->AddComment(T: " Bit 3: 1 = C++ EH block" ); |
1216 | if ((Flags4 & PPA1Flag4::ProcedureNamePresent) == |
1217 | PPA1Flag4::ProcedureNamePresent) |
1218 | OutStreamer->AddComment(T: " Bit 7: 1 = Name Length and Name" ); |
1219 | OutStreamer->emitInt8(Value: static_cast<uint8_t>( |
1220 | Flags4)); // Flags 4 (optional sections, always emit these). |
1221 | } |
1222 | |
1223 | static void emitPPA1Name(std::unique_ptr<MCStreamer> &OutStreamer, |
1224 | StringRef OutName) { |
1225 | size_t NameSize = OutName.size(); |
1226 | uint16_t OutSize; |
1227 | if (NameSize < UINT16_MAX) { |
1228 | OutSize = static_cast<uint16_t>(NameSize); |
1229 | } else { |
1230 | OutName = OutName.substr(Start: 0, UINT16_MAX); |
1231 | OutSize = UINT16_MAX; |
1232 | } |
1233 | // Emit padding to ensure that the next optional field word-aligned. |
1234 | uint8_t = 4 - ((2 + OutSize) % 4); |
1235 | |
1236 | SmallString<512> OutnameConv; |
1237 | ConverterEBCDIC::convertToEBCDIC(Source: OutName, Result&: OutnameConv); |
1238 | OutName = OutnameConv.str(); |
1239 | |
1240 | OutStreamer->AddComment(T: "Length of Name" ); |
1241 | OutStreamer->emitInt16(Value: OutSize); |
1242 | OutStreamer->AddComment(T: "Name of Function" ); |
1243 | OutStreamer->emitBytes(Data: OutName); |
1244 | OutStreamer->emitZeros(NumBytes: ExtraZeros); |
1245 | } |
1246 | |
1247 | void SystemZAsmPrinter::emitPPA1(MCSymbol *FnEndSym) { |
1248 | assert(PPA2Sym != nullptr && "PPA2 Symbol not defined" ); |
1249 | |
1250 | const TargetRegisterInfo *TRI = MF->getRegInfo().getTargetRegisterInfo(); |
1251 | const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>(); |
1252 | const auto TargetHasVector = Subtarget.hasVector(); |
1253 | |
1254 | const SystemZMachineFunctionInfo *ZFI = |
1255 | MF->getInfo<SystemZMachineFunctionInfo>(); |
1256 | const auto *ZFL = static_cast<const SystemZXPLINKFrameLowering *>( |
1257 | Subtarget.getFrameLowering()); |
1258 | const MachineFrameInfo &MFFrame = MF->getFrameInfo(); |
1259 | |
1260 | // Get saved GPR/FPR/VPR masks. |
1261 | const std::vector<CalleeSavedInfo> &CSI = MFFrame.getCalleeSavedInfo(); |
1262 | uint16_t SavedGPRMask = 0; |
1263 | uint16_t SavedFPRMask = 0; |
1264 | uint8_t SavedVRMask = 0; |
1265 | int64_t OffsetFPR = 0; |
1266 | int64_t OffsetVR = 0; |
1267 | const int64_t TopOfStack = |
1268 | MFFrame.getOffsetAdjustment() + MFFrame.getStackSize(); |
1269 | |
1270 | // Loop over the spilled registers. The CalleeSavedInfo can't be used because |
1271 | // it does not contain all spilled registers. |
1272 | for (unsigned I = ZFI->getSpillGPRRegs().LowGPR, |
1273 | E = ZFI->getSpillGPRRegs().HighGPR; |
1274 | I && E && I <= E; ++I) { |
1275 | unsigned V = TRI->getEncodingValue(RegNo: (Register)I); |
1276 | assert(V < 16 && "GPR index out of range" ); |
1277 | SavedGPRMask |= 1 << (15 - V); |
1278 | } |
1279 | |
1280 | for (auto &CS : CSI) { |
1281 | unsigned Reg = CS.getReg(); |
1282 | unsigned I = TRI->getEncodingValue(RegNo: Reg); |
1283 | |
1284 | if (SystemZ::FP64BitRegClass.contains(Reg)) { |
1285 | assert(I < 16 && "FPR index out of range" ); |
1286 | SavedFPRMask |= 1 << (15 - I); |
1287 | int64_t Temp = MFFrame.getObjectOffset(ObjectIdx: CS.getFrameIdx()); |
1288 | if (Temp < OffsetFPR) |
1289 | OffsetFPR = Temp; |
1290 | } else if (SystemZ::VR128BitRegClass.contains(Reg)) { |
1291 | assert(I >= 16 && I <= 23 && "VPR index out of range" ); |
1292 | unsigned BitNum = I - 16; |
1293 | SavedVRMask |= 1 << (7 - BitNum); |
1294 | int64_t Temp = MFFrame.getObjectOffset(ObjectIdx: CS.getFrameIdx()); |
1295 | if (Temp < OffsetVR) |
1296 | OffsetVR = Temp; |
1297 | } |
1298 | } |
1299 | |
1300 | // Adjust the offset. |
1301 | OffsetFPR += (OffsetFPR < 0) ? TopOfStack : 0; |
1302 | OffsetVR += (OffsetVR < 0) ? TopOfStack : 0; |
1303 | |
1304 | // Get alloca register. |
1305 | uint8_t FrameReg = TRI->getEncodingValue(RegNo: TRI->getFrameRegister(MF: *MF)); |
1306 | uint8_t AllocaReg = ZFL->hasFP(MF: *MF) ? FrameReg : 0; |
1307 | assert(AllocaReg < 16 && "Can't have alloca register larger than 15" ); |
1308 | (void)AllocaReg; |
1309 | |
1310 | // Build FPR save area offset. |
1311 | uint32_t FrameAndFPROffset = 0; |
1312 | if (SavedFPRMask) { |
1313 | uint64_t FPRSaveAreaOffset = OffsetFPR; |
1314 | assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range" ); |
1315 | |
1316 | FrameAndFPROffset = FPRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits. |
1317 | FrameAndFPROffset |= FrameReg << 28; // Put into top 4 bits. |
1318 | } |
1319 | |
1320 | // Build VR save area offset. |
1321 | uint32_t FrameAndVROffset = 0; |
1322 | if (TargetHasVector && SavedVRMask) { |
1323 | uint64_t VRSaveAreaOffset = OffsetVR; |
1324 | assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range" ); |
1325 | |
1326 | FrameAndVROffset = VRSaveAreaOffset & 0x0FFFFFFF; // Lose top 4 bits. |
1327 | FrameAndVROffset |= FrameReg << 28; // Put into top 4 bits. |
1328 | } |
1329 | |
1330 | // Emit PPA1 section. |
1331 | OutStreamer->AddComment(T: "PPA1" ); |
1332 | OutStreamer->emitLabel(Symbol: CurrentFnPPA1Sym); |
1333 | OutStreamer->AddComment(T: "Version" ); |
1334 | OutStreamer->emitInt8(Value: 0x02); // Version. |
1335 | OutStreamer->AddComment(T: "LE Signature X'CE'" ); |
1336 | OutStreamer->emitInt8(Value: 0xCE); // CEL signature. |
1337 | OutStreamer->AddComment(T: "Saved GPR Mask" ); |
1338 | OutStreamer->emitInt16(Value: SavedGPRMask); |
1339 | OutStreamer->AddComment(T: "Offset to PPA2" ); |
1340 | OutStreamer->emitAbsoluteSymbolDiff(Hi: PPA2Sym, Lo: CurrentFnPPA1Sym, Size: 4); |
1341 | |
1342 | bool NeedEmitEHBlock = !MF->getLandingPads().empty(); |
1343 | |
1344 | bool HasName = |
1345 | MF->getFunction().hasName() && MF->getFunction().getName().size() > 0; |
1346 | |
1347 | emitPPA1Flags(OutStreamer, MF->getFunction().isVarArg(), |
1348 | MFFrame.hasStackProtectorIndex(), SavedFPRMask != 0, |
1349 | TargetHasVector && SavedVRMask != 0, NeedEmitEHBlock, HasName); |
1350 | |
1351 | OutStreamer->AddComment(T: "Length/4 of Parms" ); |
1352 | OutStreamer->emitInt16( |
1353 | Value: static_cast<uint16_t>(ZFI->getSizeOfFnParams() / 4)); // Parms/4. |
1354 | OutStreamer->AddComment(T: "Length of Code" ); |
1355 | OutStreamer->emitAbsoluteSymbolDiff(Hi: FnEndSym, Lo: CurrentFnEPMarkerSym, Size: 4); |
1356 | |
1357 | // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3). |
1358 | if (SavedFPRMask) { |
1359 | OutStreamer->AddComment(T: "FPR mask" ); |
1360 | OutStreamer->emitInt16(Value: SavedFPRMask); |
1361 | OutStreamer->AddComment(T: "AR mask" ); |
1362 | OutStreamer->emitInt16(Value: 0); // AR Mask, unused currently. |
1363 | OutStreamer->AddComment(T: "FPR Save Area Locator" ); |
1364 | OutStreamer->AddComment(T: Twine(" Bit 0-3: Register R" ) |
1365 | .concat(Suffix: utostr(X: FrameAndFPROffset >> 28)) |
1366 | .str()); |
1367 | OutStreamer->AddComment(T: Twine(" Bit 4-31: Offset " ) |
1368 | .concat(Suffix: utostr(X: FrameAndFPROffset & 0x0FFFFFFF)) |
1369 | .str()); |
1370 | OutStreamer->emitInt32(Value: FrameAndFPROffset); // Offset to FPR save area with |
1371 | // register to add value to |
1372 | // (alloca reg). |
1373 | } |
1374 | |
1375 | // Emit saved VR mask to VR save area. |
1376 | if (TargetHasVector && SavedVRMask) { |
1377 | OutStreamer->AddComment(T: "VR mask" ); |
1378 | OutStreamer->emitInt8(Value: SavedVRMask); |
1379 | OutStreamer->emitInt8(Value: 0); // Reserved. |
1380 | OutStreamer->emitInt16(Value: 0); // Also reserved. |
1381 | OutStreamer->AddComment(T: "VR Save Area Locator" ); |
1382 | OutStreamer->AddComment(T: Twine(" Bit 0-3: Register R" ) |
1383 | .concat(Suffix: utostr(X: FrameAndVROffset >> 28)) |
1384 | .str()); |
1385 | OutStreamer->AddComment(T: Twine(" Bit 4-31: Offset " ) |
1386 | .concat(Suffix: utostr(X: FrameAndVROffset & 0x0FFFFFFF)) |
1387 | .str()); |
1388 | OutStreamer->emitInt32(Value: FrameAndVROffset); |
1389 | } |
1390 | |
1391 | // Emit C++ EH information block |
1392 | const Function *Per = nullptr; |
1393 | if (NeedEmitEHBlock) { |
1394 | Per = dyn_cast<Function>( |
1395 | Val: MF->getFunction().getPersonalityFn()->stripPointerCasts()); |
1396 | MCSymbol *PersonalityRoutine = |
1397 | Per ? MF->getTarget().getSymbol(GV: Per) : nullptr; |
1398 | assert(PersonalityRoutine && "Missing personality routine" ); |
1399 | |
1400 | OutStreamer->AddComment(T: "Version" ); |
1401 | OutStreamer->emitInt32(Value: 1); |
1402 | OutStreamer->AddComment(T: "Flags" ); |
1403 | OutStreamer->emitInt32(Value: 0); // LSDA field is a WAS offset |
1404 | OutStreamer->AddComment(T: "Personality routine" ); |
1405 | OutStreamer->emitInt64(Value: ADATable.insert( |
1406 | Sym: PersonalityRoutine, SlotKind: SystemZII::MO_ADA_INDIRECT_FUNC_DESC)); |
1407 | OutStreamer->AddComment(T: "LSDA location" ); |
1408 | MCSymbol *GCCEH = MF->getContext().getOrCreateSymbol( |
1409 | Name: Twine("GCC_except_table" ) + Twine(MF->getFunctionNumber())); |
1410 | OutStreamer->emitInt64( |
1411 | Value: ADATable.insert(Sym: GCCEH, SlotKind: SystemZII::MO_ADA_DATA_SYMBOL_ADDR)); |
1412 | } |
1413 | |
1414 | // Emit name length and name optional section (0x01 of flags 4) |
1415 | if (HasName) |
1416 | emitPPA1Name(OutStreamer, OutName: MF->getFunction().getName()); |
1417 | |
1418 | // Emit offset to entry point optional section (0x80 of flags 4). |
1419 | OutStreamer->emitAbsoluteSymbolDiff(Hi: CurrentFnEPMarkerSym, Lo: CurrentFnPPA1Sym, |
1420 | Size: 4); |
1421 | } |
1422 | |
1423 | void SystemZAsmPrinter::emitStartOfAsmFile(Module &M) { |
1424 | if (TM.getTargetTriple().isOSzOS()) |
1425 | emitPPA2(M); |
1426 | AsmPrinter::emitStartOfAsmFile(M); |
1427 | } |
1428 | |
1429 | void SystemZAsmPrinter::emitPPA2(Module &M) { |
1430 | OutStreamer->pushSection(); |
1431 | OutStreamer->switchSection(Section: getObjFileLowering().getPPA2Section()); |
1432 | MCContext &OutContext = OutStreamer->getContext(); |
1433 | // Make CELQSTRT symbol. |
1434 | const char *StartSymbolName = "CELQSTRT" ; |
1435 | MCSymbol *CELQSTRT = OutContext.getOrCreateSymbol(Name: StartSymbolName); |
1436 | |
1437 | // Create symbol and assign to class field for use in PPA1. |
1438 | PPA2Sym = OutContext.createTempSymbol(Name: "PPA2" , AlwaysAddSuffix: false); |
1439 | MCSymbol *DateVersionSym = OutContext.createTempSymbol(Name: "DVS" , AlwaysAddSuffix: false); |
1440 | |
1441 | std::time_t Time = getTranslationTime(M); |
1442 | SmallString<15> CompilationTime; // 14 + null |
1443 | raw_svector_ostream O(CompilationTime); |
1444 | O << formatv(Fmt: "{0:%Y%m%d%H%M%S}" , Vals: llvm::sys::toUtcTime(T: Time)); |
1445 | |
1446 | uint32_t ProductVersion = getProductVersion(M), |
1447 | ProductRelease = getProductRelease(M), |
1448 | ProductPatch = getProductPatch(M); |
1449 | |
1450 | SmallString<7> Version; // 6 + null |
1451 | raw_svector_ostream ostr(Version); |
1452 | ostr << formatv(Fmt: "{0,0-2:d}{1,0-2:d}{2,0-2:d}" , Vals&: ProductVersion, Vals&: ProductRelease, |
1453 | Vals&: ProductPatch); |
1454 | |
1455 | // Drop 0 during conversion. |
1456 | SmallString<sizeof(CompilationTime) - 1> CompilationTimeStr; |
1457 | SmallString<sizeof(Version) - 1> VersionStr; |
1458 | |
1459 | ConverterEBCDIC::convertToEBCDIC(Source: CompilationTime, Result&: CompilationTimeStr); |
1460 | ConverterEBCDIC::convertToEBCDIC(Source: Version, Result&: VersionStr); |
1461 | |
1462 | enum class PPA2MemberId : uint8_t { |
1463 | // See z/OS Language Environment Vendor Interfaces v2r5, p.23, for |
1464 | // complete list. Only the C runtime is supported by this backend. |
1465 | LE_C_Runtime = 3, |
1466 | }; |
1467 | enum class PPA2MemberSubId : uint8_t { |
1468 | // List of languages using the LE C runtime implementation. |
1469 | C = 0x00, |
1470 | CXX = 0x01, |
1471 | Swift = 0x03, |
1472 | Go = 0x60, |
1473 | LLVMBasedLang = 0xe7, |
1474 | }; |
1475 | // PPA2 Flags |
1476 | enum class PPA2Flags : uint8_t { |
1477 | CompileForBinaryFloatingPoint = 0x80, |
1478 | CompiledWithXPLink = 0x01, |
1479 | CompiledUnitASCII = 0x04, |
1480 | HasServiceInfo = 0x20, |
1481 | }; |
1482 | |
1483 | PPA2MemberSubId MemberSubId = PPA2MemberSubId::LLVMBasedLang; |
1484 | if (auto *MD = M.getModuleFlag(Key: "zos_cu_language" )) { |
1485 | StringRef Language = cast<MDString>(Val: MD)->getString(); |
1486 | MemberSubId = StringSwitch<PPA2MemberSubId>(Language) |
1487 | .Case(S: "C" , Value: PPA2MemberSubId::C) |
1488 | .Case(S: "C++" , Value: PPA2MemberSubId::CXX) |
1489 | .Case(S: "Swift" , Value: PPA2MemberSubId::Swift) |
1490 | .Case(S: "Go" , Value: PPA2MemberSubId::Go) |
1491 | .Default(Value: PPA2MemberSubId::LLVMBasedLang); |
1492 | } |
1493 | |
1494 | // Emit PPA2 section. |
1495 | OutStreamer->emitLabel(Symbol: PPA2Sym); |
1496 | OutStreamer->emitInt8(Value: static_cast<uint8_t>(PPA2MemberId::LE_C_Runtime)); |
1497 | OutStreamer->emitInt8(Value: static_cast<uint8_t>(MemberSubId)); |
1498 | OutStreamer->emitInt8(Value: 0x22); // Member defined, c370_plist+c370_env |
1499 | OutStreamer->emitInt8(Value: 0x04); // Control level 4 (XPLink) |
1500 | OutStreamer->emitAbsoluteSymbolDiff(Hi: CELQSTRT, Lo: PPA2Sym, Size: 4); |
1501 | OutStreamer->emitInt32(Value: 0x00000000); |
1502 | OutStreamer->emitAbsoluteSymbolDiff(Hi: DateVersionSym, Lo: PPA2Sym, Size: 4); |
1503 | OutStreamer->emitInt32( |
1504 | Value: 0x00000000); // Offset to main entry point, always 0 (so says TR). |
1505 | uint8_t Flgs = static_cast<uint8_t>(PPA2Flags::CompileForBinaryFloatingPoint); |
1506 | Flgs |= static_cast<uint8_t>(PPA2Flags::CompiledWithXPLink); |
1507 | |
1508 | if (auto *MD = M.getModuleFlag(Key: "zos_le_char_mode" )) { |
1509 | const StringRef &CharMode = cast<MDString>(Val: MD)->getString(); |
1510 | if (CharMode == "ascii" ) { |
1511 | Flgs |= static_cast<uint8_t>( |
1512 | PPA2Flags::CompiledUnitASCII); // Setting bit for ASCII char. mode. |
1513 | } else if (CharMode != "ebcdic" ) { |
1514 | report_fatal_error( |
1515 | reason: "Only ascii or ebcdic are valid values for zos_le_char_mode " |
1516 | "metadata" ); |
1517 | } |
1518 | } |
1519 | |
1520 | OutStreamer->emitInt8(Value: Flgs); |
1521 | OutStreamer->emitInt8(Value: 0x00); // Reserved. |
1522 | // No MD5 signature before timestamp. |
1523 | // No FLOAT(AFP(VOLATILE)). |
1524 | // Remaining 5 flag bits reserved. |
1525 | OutStreamer->emitInt16(Value: 0x0000); // 16 Reserved flag bits. |
1526 | |
1527 | // Emit date and version section. |
1528 | OutStreamer->emitLabel(Symbol: DateVersionSym); |
1529 | OutStreamer->emitBytes(Data: CompilationTimeStr.str()); |
1530 | OutStreamer->emitBytes(Data: VersionStr.str()); |
1531 | |
1532 | OutStreamer->emitInt16(Value: 0x0000); // Service level string length. |
1533 | |
1534 | // The binder requires that the offset to the PPA2 be emitted in a different, |
1535 | // specially-named section. |
1536 | OutStreamer->switchSection(Section: getObjFileLowering().getPPA2ListSection()); |
1537 | // Emit 8 byte alignment. |
1538 | // Emit pointer to PPA2 label. |
1539 | OutStreamer->AddComment(T: "A(PPA2-CELQSTRT)" ); |
1540 | OutStreamer->emitAbsoluteSymbolDiff(Hi: PPA2Sym, Lo: CELQSTRT, Size: 8); |
1541 | OutStreamer->popSection(); |
1542 | } |
1543 | |
1544 | void SystemZAsmPrinter::emitFunctionEntryLabel() { |
1545 | const SystemZSubtarget &Subtarget = MF->getSubtarget<SystemZSubtarget>(); |
1546 | |
1547 | if (Subtarget.getTargetTriple().isOSzOS()) { |
1548 | MCContext &OutContext = OutStreamer->getContext(); |
1549 | |
1550 | // Save information for later use. |
1551 | std::string N(MF->getFunction().hasName() |
1552 | ? Twine(MF->getFunction().getName()).concat(Suffix: "_" ).str() |
1553 | : "" ); |
1554 | |
1555 | CurrentFnEPMarkerSym = |
1556 | OutContext.createTempSymbol(Name: Twine("EPM_" ).concat(Suffix: N).str(), AlwaysAddSuffix: true); |
1557 | CurrentFnPPA1Sym = |
1558 | OutContext.createTempSymbol(Name: Twine("PPA1_" ).concat(Suffix: N).str(), AlwaysAddSuffix: true); |
1559 | |
1560 | // EntryPoint Marker |
1561 | const MachineFrameInfo &MFFrame = MF->getFrameInfo(); |
1562 | bool IsUsingAlloca = MFFrame.hasVarSizedObjects(); |
1563 | uint32_t DSASize = MFFrame.getStackSize(); |
1564 | bool IsLeaf = DSASize == 0 && MFFrame.getCalleeSavedInfo().empty(); |
1565 | |
1566 | // Set Flags. |
1567 | uint8_t Flags = 0; |
1568 | if (IsLeaf) |
1569 | Flags |= 0x08; |
1570 | if (IsUsingAlloca) |
1571 | Flags |= 0x04; |
1572 | |
1573 | // Combine into top 27 bits of DSASize and bottom 5 bits of Flags. |
1574 | uint32_t DSAAndFlags = DSASize & 0xFFFFFFE0; // (x/32) << 5 |
1575 | DSAAndFlags |= Flags; |
1576 | |
1577 | // Emit entry point marker section. |
1578 | OutStreamer->AddComment(T: "XPLINK Routine Layout Entry" ); |
1579 | OutStreamer->emitLabel(Symbol: CurrentFnEPMarkerSym); |
1580 | OutStreamer->AddComment(T: "Eyecatcher 0x00C300C500C500" ); |
1581 | OutStreamer->emitIntValueInHex(Value: 0x00C300C500C500, Size: 7); // Eyecatcher. |
1582 | OutStreamer->AddComment(T: "Mark Type C'1'" ); |
1583 | OutStreamer->emitInt8(Value: 0xF1); // Mark Type. |
1584 | OutStreamer->AddComment(T: "Offset to PPA1" ); |
1585 | OutStreamer->emitAbsoluteSymbolDiff(Hi: CurrentFnPPA1Sym, Lo: CurrentFnEPMarkerSym, |
1586 | Size: 4); |
1587 | if (OutStreamer->isVerboseAsm()) { |
1588 | OutStreamer->AddComment(T: "DSA Size 0x" + Twine::utohexstr(Val: DSASize)); |
1589 | OutStreamer->AddComment(T: "Entry Flags" ); |
1590 | if (Flags & 0x08) |
1591 | OutStreamer->AddComment(T: " Bit 1: 1 = Leaf function" ); |
1592 | else |
1593 | OutStreamer->AddComment(T: " Bit 1: 0 = Non-leaf function" ); |
1594 | if (Flags & 0x04) |
1595 | OutStreamer->AddComment(T: " Bit 2: 1 = Uses alloca" ); |
1596 | else |
1597 | OutStreamer->AddComment(T: " Bit 2: 0 = Does not use alloca" ); |
1598 | } |
1599 | OutStreamer->emitInt32(Value: DSAAndFlags); |
1600 | } |
1601 | |
1602 | AsmPrinter::emitFunctionEntryLabel(); |
1603 | } |
1604 | |
1605 | // Force static initialization. |
1606 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZAsmPrinter() { |
1607 | RegisterAsmPrinter<SystemZAsmPrinter> X(getTheSystemZTarget()); |
1608 | } |
1609 | |