1//==-- SystemZTargetStreamer.cpp - SystemZ Target Streamer Methods ----------=//
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/// \file
10/// This file defines SystemZ-specific target streamer classes.
11/// These are for implementing support for target-specific assembly directives.
12///
13//===----------------------------------------------------------------------===//
14
15#include "SystemZTargetStreamer.h"
16#include "SystemZHLASMAsmStreamer.h"
17#include "llvm/ADT/BitmaskEnum.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/ADT/Twine.h"
20#include "llvm/MC/MCAsmInfo.h"
21#include "llvm/MC/MCObjectFileInfo.h"
22#include "llvm/Support/ConvertEBCDIC.h"
23
24using namespace llvm;
25
26void SystemZTargetStreamer::emitConstantPools() {
27 // Emit EXRL target instructions.
28 if (EXRLTargets2Sym.empty())
29 return;
30 // Switch to the .text section.
31 const MCObjectFileInfo &OFI = *Streamer.getContext().getObjectFileInfo();
32 Streamer.switchSection(Section: OFI.getTextSection());
33 Streamer.emitValueToAlignment(Alignment: Align(2));
34 for (auto &I : EXRLTargets2Sym) {
35 Streamer.emitLabel(Symbol: I.second);
36 const MCInstSTIPair &MCI_STI = I.first;
37 Streamer.emitInstruction(Inst: MCI_STI.first, STI: *MCI_STI.second);
38 }
39 EXRLTargets2Sym.clear();
40}
41
42static void emitPPA1Flags(MCStreamer &OutStreamer, bool VarArg,
43 bool StackProtector, bool FPRMask, bool VRMask,
44 bool EHBlock, bool HasArgAreaLength, bool HasName) {
45 enum class PPA1Flag1 : uint8_t {
46 DSA64Bit = (0x80 >> 0),
47 VarArg = (0x80 >> 7),
48 LLVM_MARK_AS_BITMASK_ENUM(DSA64Bit)
49 };
50 enum class PPA1Flag2 : uint8_t {
51 ExternalProcedure = (0x80 >> 0),
52 STACKPROTECTOR = (0x80 >> 3),
53 LLVM_MARK_AS_BITMASK_ENUM(ExternalProcedure)
54 };
55 enum class PPA1Flag3 : uint8_t {
56 HasArgAreaLength = (0x80 >> 1),
57 FPRMask = (0x80 >> 2),
58 LLVM_MARK_AS_BITMASK_ENUM(HasArgAreaLength)
59 };
60 enum class PPA1Flag4 : uint8_t {
61 EPMOffsetPresent = (0x80 >> 0),
62 VRMask = (0x80 >> 2),
63 EHBlock = (0x80 >> 3),
64 ProcedureNamePresent = (0x80 >> 7),
65 LLVM_MARK_AS_BITMASK_ENUM(EPMOffsetPresent)
66 };
67
68 // Declare optional section flags that can be modified.
69 auto Flags1 = PPA1Flag1(0);
70 auto Flags2 = PPA1Flag2::ExternalProcedure;
71 auto Flags3 = PPA1Flag3(0);
72 auto Flags4 = PPA1Flag4::EPMOffsetPresent;
73
74 Flags1 |= PPA1Flag1::DSA64Bit;
75
76 if (VarArg)
77 Flags1 |= PPA1Flag1::VarArg;
78
79 if (StackProtector)
80 Flags2 |= PPA1Flag2::STACKPROTECTOR;
81
82 if (HasArgAreaLength)
83 Flags3 |= PPA1Flag3::HasArgAreaLength; // Add emit ArgAreaLength flag.
84
85 // SavedGPRMask, SavedFPRMask, and SavedVRMask are precomputed in.
86 if (FPRMask)
87 Flags3 |= PPA1Flag3::FPRMask; // Add emit FPR mask flag.
88
89 if (VRMask)
90 Flags4 |= PPA1Flag4::VRMask; // Add emit VR mask flag.
91
92 if (EHBlock)
93 Flags4 |= PPA1Flag4::EHBlock; // Add optional EH block.
94
95 if (HasName)
96 Flags4 |= PPA1Flag4::ProcedureNamePresent; // Add optional name block.
97
98 OutStreamer.AddComment(T: "PPA1 Flags 1");
99 OutStreamer.AddComment(T: " Bit 0: 1 = 64-bit DSA");
100 if ((Flags1 & PPA1Flag1::VarArg) == PPA1Flag1::VarArg)
101 OutStreamer.AddComment(T: " Bit 7: 1 = Vararg function");
102 OutStreamer.emitInt8(Value: static_cast<uint8_t>(Flags1)); // Flags 1.
103
104 OutStreamer.AddComment(T: "PPA1 Flags 2");
105 if ((Flags2 & PPA1Flag2::ExternalProcedure) == PPA1Flag2::ExternalProcedure)
106 OutStreamer.AddComment(T: " Bit 0: 1 = External procedure");
107 if ((Flags2 & PPA1Flag2::STACKPROTECTOR) == PPA1Flag2::STACKPROTECTOR)
108 OutStreamer.AddComment(T: " Bit 3: 1 = STACKPROTECT is enabled");
109 else
110 OutStreamer.AddComment(T: " Bit 3: 0 = STACKPROTECT is not enabled");
111 OutStreamer.emitInt8(Value: static_cast<uint8_t>(Flags2)); // Flags 2.
112
113 OutStreamer.AddComment(T: "PPA1 Flags 3");
114 if ((Flags3 & PPA1Flag3::HasArgAreaLength) == PPA1Flag3::HasArgAreaLength)
115 OutStreamer.AddComment(
116 T: " Bit 1: 1 = Argument Area Length is in optional area");
117 if ((Flags3 & PPA1Flag3::FPRMask) == PPA1Flag3::FPRMask)
118 OutStreamer.AddComment(T: " Bit 2: 1 = FP Reg Mask is in optional area");
119 OutStreamer.emitInt8(
120 Value: static_cast<uint8_t>(Flags3)); // Flags 3 (optional sections).
121
122 OutStreamer.AddComment(T: "PPA1 Flags 4");
123 if ((Flags4 & PPA1Flag4::VRMask) == PPA1Flag4::VRMask)
124 OutStreamer.AddComment(T: " Bit 2: 1 = Vector Reg Mask is in optional area");
125 if ((Flags4 & PPA1Flag4::EHBlock) == PPA1Flag4::EHBlock)
126 OutStreamer.AddComment(T: " Bit 3: 1 = C++ EH block");
127 if ((Flags4 & PPA1Flag4::ProcedureNamePresent) ==
128 PPA1Flag4::ProcedureNamePresent)
129 OutStreamer.AddComment(T: " Bit 7: 1 = Name Length and Name");
130 OutStreamer.emitInt8(Value: static_cast<uint8_t>(
131 Flags4)); // Flags 4 (optional sections, always emit these).
132}
133
134static void emitPPA1Name(MCStreamer &OutStreamer, StringRef OutName) {
135 size_t NameSize = OutName.size();
136 uint16_t OutSize;
137 if (NameSize < UINT16_MAX) {
138 OutSize = static_cast<uint16_t>(NameSize);
139 } else {
140 OutName = OutName.substr(Start: 0, UINT16_MAX);
141 OutSize = UINT16_MAX;
142 }
143 // Emit padding to ensure that the next optional field word-aligned.
144 uint8_t ExtraZeros = 4 - ((2 + OutSize) % 4);
145
146 SmallString<512> OutnameConv;
147 ConverterEBCDIC::convertToEBCDIC(Source: OutName, Result&: OutnameConv);
148 OutName = OutnameConv.str();
149
150 OutStreamer.AddComment(T: "Length of Name");
151 OutStreamer.emitInt16(Value: OutSize);
152 OutStreamer.AddComment(T: "Name of Function");
153 OutStreamer.emitBytes(Data: OutName);
154 OutStreamer.emitZeros(NumBytes: ExtraZeros);
155}
156
157void SystemZTargetzOSStreamer::emitPPA1(PPA1Info &Info) {
158 assert(PPA2Sym != nullptr && "PPA2 Symbol not defined");
159 MCStreamer &OutStreamer = getStreamer();
160 MCContext &OutContext = OutStreamer.getContext();
161 OutStreamer.emitValueToAlignment(Alignment: Align(2));
162
163 // Optional Argument Area Length.
164 // Note: This represents the length of the argument area that we reserve
165 // in our stack for setting up arguments for calls to other
166 // routines. If this optional field is not set, LE will reserve
167 // 128 bytes for the argument area. This optional field is
168 // created if greater than 128 bytes is required - to guarantee
169 // the required space is reserved on stack extension in the new
170 // extension. This optional field is also created if the
171 // routine has alloca(). This may reduce stack space
172 // if alloca() call causes a stack extension.
173 bool HasArgAreaLength = (Info.AllocaReg != 0) || (Info.CallFrameSize > 128);
174
175 // The personality function is present if at least one of the displacements is
176 // larger than zero.
177 bool HasPersonalityFn = Info.PersonalityADADisp > 0 || Info.GCCEHADADisp > 0;
178
179 // Emit PPA1 section.
180 OutStreamer.AddComment(T: "PPA1");
181 OutStreamer.emitLabel(Symbol: Info.PPA1);
182 OutStreamer.AddComment(T: "Version");
183 OutStreamer.emitInt8(Value: 0x02); // Version.
184 OutStreamer.AddComment(T: "LE Signature X'CE'");
185 OutStreamer.emitInt8(Value: 0xCE); // CEL signature.
186 OutStreamer.AddComment(T: "Saved GPR Mask");
187 OutStreamer.emitInt16(Value: Info.SavedGPRMask);
188 OutStreamer.AddComment(T: "Offset to PPA2");
189 OutStreamer.emitAbsoluteSymbolDiff(Hi: PPA2Sym, Lo: Info.PPA1, Size: 4);
190
191 emitPPA1Flags(OutStreamer, VarArg: Info.IsVarArg, StackProtector: Info.HasStackProtector,
192 FPRMask: Info.SavedFPRMask != 0, VRMask: Info.SavedVRMask != 0, EHBlock: HasPersonalityFn,
193 HasArgAreaLength, HasName: Info.Name.size() > 0);
194
195 OutStreamer.AddComment(T: "Length/4 of Parms");
196 OutStreamer.emitInt16(
197 Value: static_cast<uint16_t>(Info.SizeOfFnParams / 4)); // Parms/4.
198
199 OutStreamer.AddComment(T: "Length/2 of Prolog ");
200 if (Info.EndOfProlog)
201 OutStreamer.emitValue(
202 Value: createWordDiffExpr(Ctx&: OutContext, Hi: Info.EndOfProlog, Lo: Info.Fn), Size: 1);
203 else
204 OutStreamer.emitInt8(Value: 0);
205
206 OutStreamer.AddComment(T: "Alloca Reg + Offset/2 to SP Update");
207 OutStreamer.AddComment(
208 T: Twine(" Bit 0-3: Register R").concat(Suffix: utostr(X: Info.AllocaReg)).str());
209 OutStreamer.AddComment(T: " Bit 4-8: Offset ");
210 const MCExpr *AllocaRegExpr =
211 MCConstantExpr::create(Value: Info.AllocaReg << 4, Ctx&: OutContext);
212 if (Info.StackUpdate)
213 OutStreamer.emitValue(
214 Value: MCBinaryExpr::createOr(
215 LHS: createWordDiffExpr(Ctx&: OutContext, Hi: Info.StackUpdate, Lo: Info.Fn),
216 RHS: AllocaRegExpr, Ctx&: OutContext),
217 Size: 1);
218 else
219 OutStreamer.emitValue(Value: AllocaRegExpr, Size: 1);
220
221 OutStreamer.AddComment(T: "Length of Code");
222 OutStreamer.emitAbsoluteSymbolDiff(Hi: Info.FnEnd, Lo: Info.EPMarker, Size: 4);
223
224 if (HasArgAreaLength) {
225 OutStreamer.AddComment(T: "Argument Area Length");
226 OutStreamer.emitInt32(Value: Info.CallFrameSize);
227 }
228
229 // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3).
230 if (Info.SavedFPRMask) {
231 OutStreamer.AddComment(T: "FPR mask");
232 OutStreamer.emitInt16(Value: Info.SavedFPRMask);
233 OutStreamer.AddComment(T: "AR mask");
234 OutStreamer.emitInt16(Value: 0); // AR Mask, unused currently.
235 OutStreamer.AddComment(T: "FPR Save Area Locator");
236 uint64_t FPRSaveAreaOffset = Info.OffsetFPR;
237 assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range");
238 FPRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits.
239 OutStreamer.AddComment(
240 T: Twine(" Bit 0-3: Register R").concat(Suffix: utostr(X: Info.FrameReg)));
241 OutStreamer.AddComment(
242 T: Twine(" Bit 4-31: Offset ").concat(Suffix: utostr(X: FPRSaveAreaOffset)));
243 OutStreamer.emitInt32(Value: FPRSaveAreaOffset |
244 (Info.FrameReg << 28)); // Offset to FPR save area
245 // with register to add
246 // value to (alloca reg).
247 }
248
249 // Emit saved VR mask to VR save area.
250 if (Info.SavedVRMask) {
251 OutStreamer.AddComment(T: "VR mask");
252 OutStreamer.emitInt8(Value: Info.SavedVRMask);
253 OutStreamer.emitInt8(Value: 0); // Reserved.
254 OutStreamer.emitInt16(Value: 0); // Also reserved.
255 uint64_t VRSaveAreaOffset = Info.OffsetVR;
256 assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range");
257 VRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits.
258 OutStreamer.AddComment(T: "VR Save Area Locator");
259 OutStreamer.AddComment(
260 T: Twine(" Bit 0-3: Register R").concat(Suffix: utostr(X: Info.FrameReg)));
261 OutStreamer.AddComment(
262 T: Twine(" Bit 4-31: Offset ").concat(Suffix: utostr(X: VRSaveAreaOffset)));
263 OutStreamer.emitInt32(Value: VRSaveAreaOffset | (Info.FrameReg << 28));
264 }
265
266 // Emit C++ EH information block.
267 if (HasPersonalityFn) {
268 OutStreamer.AddComment(T: "Version");
269 OutStreamer.emitInt32(Value: 1);
270 OutStreamer.AddComment(T: "Flags");
271 OutStreamer.emitInt32(Value: 0); // LSDA field is a WAS offset
272 OutStreamer.AddComment(T: "Personality routine");
273 OutStreamer.emitInt64(Value: Info.PersonalityADADisp);
274 OutStreamer.AddComment(T: "LSDA location");
275 OutStreamer.emitInt64(Value: Info.GCCEHADADisp);
276 }
277
278 // Emit name length and name optional section (0x01 of flags 4)
279 if (Info.Name.size() > 0)
280 emitPPA1Name(OutStreamer, OutName: Info.Name);
281
282 // Emit offset to entry point optional section (0x80 of flags 4).
283 OutStreamer.emitAbsoluteSymbolDiff(Hi: Info.EPMarker, Lo: Info.PPA1, Size: 4);
284}
285
286void SystemZTargetzOSStreamer::emitConstantPools() {
287 // Emit EXRL target instructions (base class prolog).
288 SystemZTargetStreamer::emitConstantPools();
289
290 // Emit deferred PPA1 blocks into the text section.
291 if (DeferredPPA1.empty())
292 return;
293 const MCObjectFileInfo &OFI = *getStreamer().getContext().getObjectFileInfo();
294 getStreamer().switchSection(Section: OFI.getTextSection());
295 for (auto &Info : DeferredPPA1)
296 emitPPA1(Info);
297}
298
299SystemZHLASMAsmStreamer &SystemZTargetHLASMStreamer::getHLASMStreamer() {
300 return static_cast<SystemZHLASMAsmStreamer &>(getStreamer());
301}
302
303// HLASM statements can only perform a single operation at a time
304const MCExpr *SystemZTargetHLASMStreamer::createWordDiffExpr(
305 MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) {
306 assert(Hi && Lo && "Symbols required to calculate expression");
307 MCSymbol *Temp = Ctx.createTempSymbol();
308 OS << Temp->getName() << " EQU ";
309 const MCBinaryExpr *TempExpr = MCBinaryExpr::createSub(
310 LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx), RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx), Ctx);
311 Ctx.getAsmInfo().printExpr(OS, *TempExpr);
312 OS << "\n";
313 return MCBinaryExpr::createLShr(LHS: MCSymbolRefExpr::create(Symbol: Temp, Ctx),
314 RHS: MCConstantExpr::create(Value: 1, Ctx), Ctx);
315}
316
317const MCExpr *SystemZTargetGOFFStreamer::createWordDiffExpr(
318 MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) {
319 assert(Hi && Lo && "Symbols required to calculate expression");
320 return MCBinaryExpr::createLShr(
321 LHS: MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx),
322 RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx), Ctx),
323 RHS: MCConstantExpr::create(Value: 1, Ctx), Ctx);
324}
325