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