LLVM 24.0.0git
SystemZELFAsmPrinter.cpp
Go to the documentation of this file.
1//===-- SystemZELFAsmPrinter.cpp - SystemZ ELF asm 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// This file implements the SystemZELFAsmPrinter class.
10//
11//===----------------------------------------------------------------------===//
12
16#include "SystemZMCInstLower.h"
17#include "SystemZSubtarget.h"
21#include "llvm/IR/Module.h"
22#include "llvm/MC/MCExpr.h"
25#include "llvm/MC/MCStreamer.h"
26
27using namespace llvm;
28
29// Emit the largest nop instruction smaller than or equal to NumBytes
30// bytes. Return the size of nop emitted.
31static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer,
32 unsigned NumBytes, const MCSubtargetInfo &STI) {
33 if (NumBytes < 2) {
34 llvm_unreachable("Zero nops?");
35 return 0;
36 } else if (NumBytes < 4) {
37 OutStreamer.emitInstruction(
38 MCInstBuilder(SystemZ::BCRAsm).addImm(0).addReg(SystemZ::R0D), STI);
39 return 2;
40 } else if (NumBytes < 6) {
41 OutStreamer.emitInstruction(
42 MCInstBuilder(SystemZ::BCAsm).addImm(0).addReg(0).addImm(0).addReg(0),
43 STI);
44 return 4;
45 } else {
46 MCSymbol *DotSym = OutContext.createTempSymbol();
47 const MCSymbolRefExpr *Dot = MCSymbolRefExpr::create(DotSym, OutContext);
48 OutStreamer.emitLabel(DotSym);
49 OutStreamer.emitInstruction(
50 MCInstBuilder(SystemZ::BRCLAsm).addImm(0).addExpr(Dot), STI);
51 return 6;
52 }
53}
54
55static const MCSymbolRefExpr *getTLSGetOffset(MCContext &Context) {
56 StringRef Name = "__tls_get_offset";
57 return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name),
58 SystemZ::S_PLT, Context);
59}
60
62 StringRef Name = "_GLOBAL_OFFSET_TABLE_";
63 return MCSymbolRefExpr::create(Context.getOrCreateSymbol(Name), Context);
64}
65
69
71 SystemZMCInstLower Lower(MF->getContext(), *this);
72
73 switch (MI->getOpcode()) {
74 case TargetOpcode::FENTRY_CALL:
75 LowerFENTRY_CALL(*MI, Lower);
76 return;
77 case TargetOpcode::STACKMAP:
78 LowerSTACKMAP(*MI);
79 return;
80 case TargetOpcode::PATCHPOINT:
81 LowerPATCHPOINT(*MI, Lower);
82 return;
83 case TargetOpcode::PATCHABLE_FUNCTION_ENTER:
84 LowerPATCHABLE_FUNCTION_ENTER(*MI, Lower);
85 return;
86 case TargetOpcode::PATCHABLE_RET:
87 LowerPATCHABLE_RET(*MI, Lower);
88 return;
89 case SystemZ::CallBASR:
91 .addReg(SystemZ::R14D)
92 .addReg(MI->getOperand(0).getReg()));
93 return;
94 case SystemZ::CallBRASL:
96 .addReg(SystemZ::R14D)
97 .addExpr(Lower.getExpr(MI->getOperand(0),
99 return;
100 case SystemZ::CallJG:
102 .addExpr(Lower.getExpr(MI->getOperand(0),
104 return;
105 case SystemZ::CallBRCL:
107 .addImm(MI->getOperand(0).getImm())
108 .addImm(MI->getOperand(1).getImm())
109 .addExpr(Lower.getExpr(MI->getOperand(2),
111 return;
112 case SystemZ::TLS_GDCALL:
114 .addReg(SystemZ::R14D)
115 .addExpr(getTLSGetOffset(MF->getContext()))
116 .addExpr(Lower.getExpr(MI->getOperand(0),
118 return;
119 case SystemZ::TLS_LDCALL:
122 MCInstBuilder(SystemZ::BRASL)
123 .addReg(SystemZ::R14D)
124 .addExpr(getTLSGetOffset(MF->getContext()))
125 .addExpr(Lower.getExpr(MI->getOperand(0), SystemZ::S_TLSLDM)));
126 return;
127 case SystemZ::GOT:
129 MCInstBuilder(SystemZ::LARL)
130 .addReg(MI->getOperand(0).getReg())
131 .addExpr(getGlobalOffsetTable(MF->getContext())));
132 return;
133 case SystemZ::LOAD_TLS_BLOCK_ADDR:
134 lowerLOAD_TLS_BLOCK_ADDR(*MI, Lower);
135 return;
136 case SystemZ::LOAD_GLOBAL_STACKGUARD_ADDR:
137 lowerLOAD_GLOBAL_STACKGUARD_ADDR(*MI, Lower);
138 return;
139 default:
141 return;
142 }
143}
144
145void SystemZELFAsmPrinter::LowerFENTRY_CALL(const MachineInstr &MI,
147 MCContext &Ctx = MF->getContext();
148 if (MF->getFunction().hasFnAttribute("mrecord-mcount")) {
150 OutStreamer->pushSection();
151 OutStreamer->switchSection(
152 Ctx.getELFSection("__mcount_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
153 OutStreamer->emitSymbolValue(DotSym, 8);
154 OutStreamer->popSection();
155 OutStreamer->emitLabel(DotSym);
156 }
157
158 if (MF->getFunction().hasFnAttribute("mnop-mcount")) {
160 return;
161 }
162
163 MCSymbol *fentry = Ctx.getOrCreateSymbol("__fentry__");
164 const MCSymbolRefExpr *Op =
166 OutStreamer->emitInstruction(
167 MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R0D).addExpr(Op),
169}
170
171void SystemZELFAsmPrinter::LowerSTACKMAP(const MachineInstr &MI) {
172 auto *TII = MF->getSubtarget<SystemZSubtarget>().getInstrInfo();
173
174 unsigned NumNOPBytes = MI.getOperand(1).getImm();
175
176 auto &Ctx = OutStreamer->getContext();
177 MCSymbol *MILabel = Ctx.createTempSymbol();
178 OutStreamer->emitLabel(MILabel);
179
180 SM.recordStackMap(*MILabel, MI);
181 assert(NumNOPBytes % 2 == 0 && "Invalid number of NOP bytes requested!");
182
183 // Scan ahead to trim the shadow.
184 unsigned ShadowBytes = 0;
185 const MachineBasicBlock &MBB = *MI.getParent();
187 ++MII;
188 while (ShadowBytes < NumNOPBytes) {
189 if (MII == MBB.end() || MII->getOpcode() == TargetOpcode::PATCHPOINT ||
190 MII->getOpcode() == TargetOpcode::STACKMAP)
191 break;
192 ShadowBytes += TII->getInstSizeInBytes(*MII);
193 if (MII->isCall())
194 break;
195 ++MII;
196 }
197
198 // Emit nops.
199 while (ShadowBytes < NumNOPBytes)
200 ShadowBytes += EmitNop(OutContext, *OutStreamer, NumNOPBytes - ShadowBytes,
202}
203
204// Lower a patchpoint of the form:
205// [<def>], <id>, <numBytes>, <target>, <numArgs>
206void SystemZELFAsmPrinter::LowerPATCHPOINT(const MachineInstr &MI,
208 auto &Ctx = OutStreamer->getContext();
209 MCSymbol *MILabel = Ctx.createTempSymbol();
210 OutStreamer->emitLabel(MILabel);
211
212 SM.recordPatchPoint(*MILabel, MI);
213 PatchPointOpers Opers(&MI);
214
215 unsigned EncodedBytes = 0;
216 const MachineOperand &CalleeMO = Opers.getCallTarget();
217
218 if (CalleeMO.isImm()) {
219 uint64_t CallTarget = CalleeMO.getImm();
220 if (CallTarget) {
221 unsigned ScratchIdx = -1;
222 unsigned ScratchReg = 0;
223 do {
224 ScratchIdx = Opers.getNextScratchIdx(ScratchIdx + 1);
225 ScratchReg = MI.getOperand(ScratchIdx).getReg();
226 } while (ScratchReg == SystemZ::R0D);
227
228 // Materialize the call target address
229 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LLILF)
230 .addReg(ScratchReg)
231 .addImm(CallTarget & 0xFFFFFFFF));
232 EncodedBytes += 6;
233 if (CallTarget >> 32) {
234 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::IIHF)
235 .addReg(ScratchReg)
236 .addImm(CallTarget >> 32));
237 EncodedBytes += 6;
238 }
239
240 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BASR)
241 .addReg(SystemZ::R14D)
242 .addReg(ScratchReg));
243 EncodedBytes += 2;
244 }
245 } else if (CalleeMO.isGlobal()) {
246 const MCExpr *Expr = Lower.getExpr(CalleeMO, SystemZ::S_PLT);
249 MCInstBuilder(SystemZ::BRASL).addReg(SystemZ::R14D).addExpr(Expr));
250 EncodedBytes += 6;
251 }
252
253 // Emit padding.
254 unsigned NumBytes = Opers.getNumPatchBytes();
255 assert(NumBytes >= EncodedBytes &&
256 "Patchpoint can't request size less than the length of a call.");
257 assert((NumBytes - EncodedBytes) % 2 == 0 &&
258 "Invalid number of NOP bytes requested!");
259 while (EncodedBytes < NumBytes)
260 EncodedBytes += EmitNop(OutContext, *OutStreamer, NumBytes - EncodedBytes,
262}
263
264void SystemZELFAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(
266 const MachineFunction &MF = *(MI.getParent()->getParent());
267 const Function &F = MF.getFunction();
268
269 // If patchable-function-entry is set, emit in-function nops here.
270 if (F.hasFnAttribute("patchable-function-entry")) {
271 unsigned Num = F.getFnAttributeAsParsedInteger("patchable-function-entry");
272 for (unsigned I = 0; I < Num; ++I)
273 EmitToStreamer(*OutStreamer, MF.getSubtarget().getInstrInfo()->getNop());
274 return;
275 }
276 // Otherwise, emit xray sled.
277 // .begin:
278 // j .end # -> stmg %r2, %r15, 16(%r15)
279 // nop
280 // llilf %2, FuncID
281 // brasl %r14, __xray_FunctionEntry@GOT
282 // .end:
283 //
284 // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
285 // of instructions change.
286 bool HasVectorFeature =
287 TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
288 !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
289 MCSymbol *FuncEntry = OutContext.getOrCreateSymbol(
290 HasVectorFeature ? "__xray_FunctionEntryVec" : "__xray_FunctionEntry");
291 MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
292 MCSymbol *EndOfSled = OutContext.createTempSymbol();
293 OutStreamer->emitLabel(BeginOfSled);
295 MCInstBuilder(SystemZ::J)
296 .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));
299 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
300 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRASL)
301 .addReg(SystemZ::R14D)
303 FuncEntry, SystemZ::S_PLT, OutContext)));
304 OutStreamer->emitLabel(EndOfSled);
305 recordSled(BeginOfSled, MI, SledKind::FUNCTION_ENTER, 2);
306}
307
308void SystemZELFAsmPrinter::LowerPATCHABLE_RET(const MachineInstr &MI,
310 unsigned OpCode = MI.getOperand(0).getImm();
311 MCSymbol *FallthroughLabel = nullptr;
312 if (OpCode == SystemZ::CondReturn) {
313 FallthroughLabel = OutContext.createTempSymbol();
314 int64_t Cond0 = MI.getOperand(1).getImm();
315 int64_t Cond1 = MI.getOperand(2).getImm();
316 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::BRC)
317 .addImm(Cond0)
318 .addImm(Cond1 ^ Cond0)
320 FallthroughLabel, OutContext)));
321 }
322 // .begin:
323 // br %r14 # -> stmg %r2, %r15, 24(%r15)
324 // nop
325 // nop
326 // llilf %2,FuncID
327 // j __xray_FunctionExit@GOT
328 //
329 // Update compiler-rt/lib/xray/xray_s390x.cpp accordingly when number
330 // of instructions change.
331 bool HasVectorFeature =
332 TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector) &&
333 !TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureSoftFloat);
334 MCSymbol *FuncExit = OutContext.getOrCreateSymbol(
335 HasVectorFeature ? "__xray_FunctionExitVec" : "__xray_FunctionExit");
336 MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_", true);
337 OutStreamer->emitLabel(BeginOfSled);
339 MCInstBuilder(SystemZ::BR).addReg(SystemZ::R14D));
342 MCInstBuilder(SystemZ::LLILF).addReg(SystemZ::R2D).addImm(0));
343 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::J)
345 FuncExit, SystemZ::S_PLT, OutContext)));
346 if (FallthroughLabel)
347 OutStreamer->emitLabel(FallthroughLabel);
348 recordSled(BeginOfSled, MI, SledKind::FUNCTION_EXIT, 2);
349}
350
351void SystemZELFAsmPrinter::lowerLOAD_TLS_BLOCK_ADDR(const MachineInstr &MI,
353 Register AddrReg = MI.getOperand(0).getReg();
354 const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
355
356 // EAR can only load the low subregister so use a shift for %a0 to produce
357 // the GR containing %a0 and %a1.
358 const Register Reg32 =
359 MRI.getTargetRegisterInfo()->getSubReg(AddrReg, SystemZ::subreg_l32);
360
361 // ear <reg>, %a0
363 MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A0));
364
365 // sllg <reg>, <reg>, 32
366 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::SLLG)
367 .addReg(AddrReg)
368 .addReg(AddrReg)
369 .addReg(0)
370 .addImm(32));
371
372 // ear <reg>, %a1
374 MCInstBuilder(SystemZ::EAR).addReg(Reg32).addReg(SystemZ::A1));
375}
376
377void SystemZELFAsmPrinter::lowerLOAD_GLOBAL_STACKGUARD_ADDR(
379 Register AddrReg = MI.getOperand(0).getReg();
380 const MachineFunction &MF = *(MI.getParent()->getParent());
381 const Module *M = MF.getFunction().getParent();
382 const TargetLowering *TLI = MF.getSubtarget().getTargetLowering();
383
384 // Obtain the global value (assert if stack guard variable can't be found).
385 const GlobalVariable *GV = cast<GlobalVariable>(
387
388 // If configured, emit the `__stack_protector_loc` entry
389 if (M->hasStackProtectorGuardRecord()) {
390 MCSymbol *Sym = OutContext.createTempSymbol();
391 OutStreamer->pushSection();
392 OutStreamer->switchSection(OutContext.getELFSection(
393 "__stack_protector_loc", ELF::SHT_PROGBITS, ELF::SHF_ALLOC));
394 OutStreamer->emitSymbolValue(Sym, getDataLayout().getPointerSize());
395 OutStreamer->popSection();
396 OutStreamer->emitLabel(Sym);
397 }
398 // Emit the address load.
399 if (M->getPICLevel() == PICLevel::NotPIC) {
400 EmitToStreamer(*OutStreamer, MCInstBuilder(SystemZ::LARL)
401 .addReg(AddrReg)
403 getSymbol(GV), OutContext)));
404 } else {
406 MCInstBuilder(SystemZ::LGRL)
407 .addReg(AddrReg)
410 }
411}
412
413// The *alignment* of 128-bit vector types is different between the software
414// and hardware vector ABIs. If there is an externally visible use of a
415// vector type in the module it should be annotated with an attribute.
416void SystemZELFAsmPrinter::emitAttributes(Module &M) {
417 if (M.getModuleFlag("s390x-visible-vector-ABI")) {
418 bool HasVectorFeature =
419 TM.getMCSubtargetInfo().hasFeature(SystemZ::FeatureVector);
420 OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1);
421 }
422}
423
424// Convert a SystemZ-specific constant pool modifier into the associated
425// specifier.
427 switch (Modifier) {
428 case SystemZCP::TLSGD:
429 return SystemZ::S_TLSGD;
431 return SystemZ::S_TLSLDM;
433 return SystemZ::S_DTPOFF;
435 return SystemZ::S_NTPOFF;
436 }
437 llvm_unreachable("Invalid SystemCPModifier!");
438}
439
442 auto *ZCPV = static_cast<SystemZConstantPoolValue *>(MCPV);
443
444 const MCExpr *Expr = MCSymbolRefExpr::create(
445 getSymbol(ZCPV->getGlobalValue()),
446 getSpecifierFromModifier(ZCPV->getModifier()), OutContext);
447 uint64_t Size = getDataLayout().getTypeAllocSize(ZCPV->getType());
448
449 OutStreamer->emitValue(Expr, Size);
450}
451
452void SystemZELFAsmPrinter::emitEndOfAsmFile(Module &M) { emitAttributes(M); }
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
MachineBasicBlock & MBB
static const Function * getParent(const Value *V)
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Promote Memory to Register
Definition Mem2Reg.cpp:110
std::unique_ptr< MCStreamer > && Streamer
static uint8_t getSpecifierFromModifier(SystemZCP::SystemZCPModifier Modifier)
static const MCSymbolRefExpr * getGlobalOffsetTable(MCContext &Context)
static const MCSymbolRefExpr * getTLSGetOffset(MCContext &Context)
static unsigned EmitNop(MCContext &OutContext, MCStreamer &OutStreamer, unsigned NumBytes, const MCSubtargetInfo &STI)
MCSymbol * getSymbol(const GlobalValue *GV) const
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
TargetMachine & TM
Target machine description.
Definition AsmPrinter.h:94
MachineFunction * MF
The current machine function.
Definition AsmPrinter.h:109
void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind, uint8_t Version=0)
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition AsmPrinter.h:101
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition AsmPrinter.h:106
unsigned getPointerSize() const
Return the pointer size from the TargetMachine.
const DataLayout & getDataLayout() const
Return information about data layout.
const MCSubtargetInfo & getSubtargetInfo() const
Return information about subtarget.
LLVM_ABI TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition Function.cpp:727
Context object for machine code objects.
Definition MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
LLVM_ABI MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
MCInstBuilder & addImm(int64_t Val)
Add a new integer immediate operand.
MCInstBuilder & addExpr(const MCExpr *Val)
Add a new MCExpr operand.
MCRegister getSubReg(MCRegister Reg, unsigned Idx) const
Returns the physical register number of sub-register "Index" for physical register RegNo.
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
Generic base class for all target subtargets.
Represent a reference to a symbol from inside an expression.
Definition MCExpr.h:190
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
MachineInstrBundleIterator< const MachineInstr > const_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
Abstract base class for all machine specific constantpool value subclasses.
MCContext & getContext() const
Function & getFunction()
Return the LLVM function that this machine code represents.
Representation of each machine instruction.
int64_t getImm() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
const TargetRegisterInfo * getTargetRegisterInfo() const
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
void emitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
SystemZAsmPrinter(TargetMachine &TM, std::unique_ptr< MCStreamer > Streamer)
A SystemZ-specific constant pool value.
void emitEndOfAsmFile(Module &M) override
This virtual method can be overridden by targets that want to emit something at the end of their file...
SystemZELFAsmPrinter(TargetMachine &TM, std::unique_ptr< MCStreamer > Streamer)
void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override
void emitInstruction(const MachineInstr *MI) override
Targets should implement this to emit instructions.
const LibcallLoweringInfo & getLibcallLoweringInfo() const
virtual Value * getSDagStackGuard(const Module &M, const LibcallLoweringInfo &Libcalls) const
Return the variable that's previously inserted by insertSSPDeclarations, if any, otherwise return nul...
Primary interface to the complete machine description for the target machine.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHF_ALLOC
Definition ELF.h:1259
@ SHT_PROGBITS
Definition ELF.h:1157
This is an optimization pass for GlobalISel generic memory operations.
DWARFExpression::Operation Op
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878