| 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/MCGOFFStreamer.h" |
| 22 | #include "llvm/MC/MCObjectFileInfo.h" |
| 23 | #include "llvm/Support/ConvertEBCDIC.h" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | void SystemZTargetStreamer::emitConstantPools() { |
| 28 | // Emit EXRL target instructions. |
| 29 | if (EXRLTargets2Sym.empty()) |
| 30 | return; |
| 31 | // Switch to the .text section. |
| 32 | const MCObjectFileInfo &OFI = *Streamer.getContext().getObjectFileInfo(); |
| 33 | Streamer.switchSection(Section: OFI.getTextSection()); |
| 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 | |
| 42 | static 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 | |
| 134 | static 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 = 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 | |
| 157 | void SystemZTargetzOSStreamer::emitPPA1(PPA1Info &Info) { |
| 158 | assert(PPA2Sym != nullptr && "PPA2 Symbol not defined" ); |
| 159 | MCStreamer &OutStreamer = getStreamer(); |
| 160 | MCContext &OutContext = OutStreamer.getContext(); |
| 161 | |
| 162 | // Optional Argument Area Length. |
| 163 | // Note: This represents the length of the argument area that we reserve |
| 164 | // in our stack for setting up arguments for calls to other |
| 165 | // routines. If this optional field is not set, LE will reserve |
| 166 | // 128 bytes for the argument area. This optional field is |
| 167 | // created if greater than 128 bytes is required - to guarantee |
| 168 | // the required space is reserved on stack extension in the new |
| 169 | // extension. This optional field is also created if the |
| 170 | // routine has alloca(). This may reduce stack space |
| 171 | // if alloca() call causes a stack extension. |
| 172 | bool HasArgAreaLength = (Info.AllocaReg != 0) || (Info.CallFrameSize > 128); |
| 173 | |
| 174 | // The personality function is present if at least one of the displacements is |
| 175 | // larger than zero. |
| 176 | bool HasPersonalityFn = Info.PersonalityADADisp > 0 || Info.GCCEHADADisp > 0; |
| 177 | |
| 178 | // Emit PPA1 section. |
| 179 | OutStreamer.AddComment(T: "PPA1" ); |
| 180 | OutStreamer.emitLabel(Symbol: Info.PPA1); |
| 181 | OutStreamer.AddComment(T: "Version" ); |
| 182 | OutStreamer.emitInt8(Value: 0x02); // Version. |
| 183 | OutStreamer.AddComment(T: "LE Signature X'CE'" ); |
| 184 | OutStreamer.emitInt8(Value: 0xCE); // CEL signature. |
| 185 | OutStreamer.AddComment(T: "Saved GPR Mask" ); |
| 186 | OutStreamer.emitInt16(Value: Info.SavedGPRMask); |
| 187 | OutStreamer.AddComment(T: "Offset to PPA2" ); |
| 188 | OutStreamer.emitAbsoluteSymbolDiff(Hi: PPA2Sym, Lo: Info.PPA1, Size: 4); |
| 189 | |
| 190 | emitPPA1Flags(OutStreamer, VarArg: Info.IsVarArg, StackProtector: Info.HasStackProtector, |
| 191 | FPRMask: Info.SavedFPRMask != 0, VRMask: Info.SavedVRMask != 0, EHBlock: HasPersonalityFn, |
| 192 | HasArgAreaLength, HasName: Info.Name.size() > 0); |
| 193 | |
| 194 | OutStreamer.AddComment(T: "Length/4 of Parms" ); |
| 195 | OutStreamer.emitInt16( |
| 196 | Value: static_cast<uint16_t>(Info.SizeOfFnParams / 4)); // Parms/4. |
| 197 | |
| 198 | OutStreamer.AddComment(T: "Length/2 of Prolog " ); |
| 199 | if (Info.EndOfProlog) |
| 200 | OutStreamer.emitValue( |
| 201 | Value: createWordDiffExpr(Ctx&: OutContext, Hi: Info.EndOfProlog, Lo: Info.Fn), Size: 1); |
| 202 | else |
| 203 | OutStreamer.emitInt8(Value: 0); |
| 204 | |
| 205 | OutStreamer.AddComment(T: "Alloca Reg + Offset/2 to SP Update" ); |
| 206 | OutStreamer.AddComment( |
| 207 | T: Twine(" Bit 0-3: Register R" ).concat(Suffix: utostr(X: Info.AllocaReg)).str()); |
| 208 | OutStreamer.AddComment(T: " Bit 4-8: Offset " ); |
| 209 | const MCExpr *AllocaRegExpr = |
| 210 | MCConstantExpr::create(Value: Info.AllocaReg << 4, Ctx&: OutContext); |
| 211 | if (Info.StackUpdate) |
| 212 | OutStreamer.emitValue( |
| 213 | Value: MCBinaryExpr::createOr( |
| 214 | LHS: createWordDiffExpr(Ctx&: OutContext, Hi: Info.StackUpdate, Lo: Info.Fn), |
| 215 | RHS: AllocaRegExpr, Ctx&: OutContext), |
| 216 | Size: 1); |
| 217 | else |
| 218 | OutStreamer.emitValue(Value: AllocaRegExpr, Size: 1); |
| 219 | |
| 220 | OutStreamer.AddComment(T: "Length of Code" ); |
| 221 | OutStreamer.emitAbsoluteSymbolDiff(Hi: Info.FnEnd, Lo: Info.EPMarker, Size: 4); |
| 222 | |
| 223 | if (HasArgAreaLength) { |
| 224 | OutStreamer.AddComment(T: "Argument Area Length" ); |
| 225 | OutStreamer.emitInt32(Value: Info.CallFrameSize); |
| 226 | } |
| 227 | |
| 228 | // Emit saved FPR mask and offset to FPR save area (0x20 of flags 3). |
| 229 | if (Info.SavedFPRMask) { |
| 230 | OutStreamer.AddComment(T: "FPR mask" ); |
| 231 | OutStreamer.emitInt16(Value: Info.SavedFPRMask); |
| 232 | OutStreamer.AddComment(T: "AR mask" ); |
| 233 | OutStreamer.emitInt16(Value: 0); // AR Mask, unused currently. |
| 234 | OutStreamer.AddComment(T: "FPR Save Area Locator" ); |
| 235 | uint64_t FPRSaveAreaOffset = Info.OffsetFPR; |
| 236 | assert(FPRSaveAreaOffset < 0x10000000 && "Offset out of range" ); |
| 237 | FPRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits. |
| 238 | OutStreamer.AddComment( |
| 239 | T: Twine(" Bit 0-3: Register R" ).concat(Suffix: utostr(X: Info.FrameReg))); |
| 240 | OutStreamer.AddComment( |
| 241 | T: Twine(" Bit 4-31: Offset " ).concat(Suffix: utostr(X: FPRSaveAreaOffset))); |
| 242 | OutStreamer.emitInt32(Value: FPRSaveAreaOffset | |
| 243 | (Info.FrameReg << 28)); // Offset to FPR save area |
| 244 | // with register to add |
| 245 | // value to (alloca reg). |
| 246 | } |
| 247 | |
| 248 | // Emit saved VR mask to VR save area. |
| 249 | if (Info.SavedVRMask) { |
| 250 | OutStreamer.AddComment(T: "VR mask" ); |
| 251 | OutStreamer.emitInt8(Value: Info.SavedVRMask); |
| 252 | OutStreamer.emitInt8(Value: 0); // Reserved. |
| 253 | OutStreamer.emitInt16(Value: 0); // Also reserved. |
| 254 | uint64_t VRSaveAreaOffset = Info.OffsetVR; |
| 255 | assert(VRSaveAreaOffset < 0x10000000 && "Offset out of range" ); |
| 256 | VRSaveAreaOffset &= 0x0FFFFFFF; // Lose top 4 bits. |
| 257 | OutStreamer.AddComment(T: "VR Save Area Locator" ); |
| 258 | OutStreamer.AddComment( |
| 259 | T: Twine(" Bit 0-3: Register R" ).concat(Suffix: utostr(X: Info.FrameReg))); |
| 260 | OutStreamer.AddComment( |
| 261 | T: Twine(" Bit 4-31: Offset " ).concat(Suffix: utostr(X: VRSaveAreaOffset))); |
| 262 | OutStreamer.emitInt32(Value: VRSaveAreaOffset | (Info.FrameReg << 28)); |
| 263 | } |
| 264 | |
| 265 | // Emit C++ EH information block. |
| 266 | if (HasPersonalityFn) { |
| 267 | OutStreamer.AddComment(T: "Version" ); |
| 268 | OutStreamer.emitInt32(Value: 1); |
| 269 | OutStreamer.AddComment(T: "Flags" ); |
| 270 | OutStreamer.emitInt32(Value: 0); // LSDA field is a WAS offset |
| 271 | OutStreamer.AddComment(T: "Personality routine" ); |
| 272 | OutStreamer.emitInt64(Value: Info.PersonalityADADisp); |
| 273 | OutStreamer.AddComment(T: "LSDA location" ); |
| 274 | OutStreamer.emitInt64(Value: Info.GCCEHADADisp); |
| 275 | } |
| 276 | |
| 277 | // Emit name length and name optional section (0x01 of flags 4) |
| 278 | if (Info.Name.size() > 0) |
| 279 | emitPPA1Name(OutStreamer, OutName: Info.Name); |
| 280 | |
| 281 | // Emit offset to entry point optional section (0x80 of flags 4). |
| 282 | OutStreamer.emitAbsoluteSymbolDiff(Hi: Info.EPMarker, Lo: Info.PPA1, Size: 4); |
| 283 | } |
| 284 | |
| 285 | void SystemZTargetzOSStreamer::emitConstantPools() { |
| 286 | // Emit EXRL target instructions (base class prolog). |
| 287 | SystemZTargetStreamer::emitConstantPools(); |
| 288 | |
| 289 | // Emit deferred PPA1 blocks into the text section. |
| 290 | if (DeferredPPA1.empty()) |
| 291 | return; |
| 292 | const MCObjectFileInfo &OFI = *getStreamer().getContext().getObjectFileInfo(); |
| 293 | getStreamer().switchSection(Section: OFI.getTextSection()); |
| 294 | for (auto &Info : DeferredPPA1) |
| 295 | emitPPA1(Info); |
| 296 | } |
| 297 | |
| 298 | SystemZHLASMAsmStreamer &SystemZTargetHLASMStreamer::getHLASMStreamer() { |
| 299 | return static_cast<SystemZHLASMAsmStreamer &>(getStreamer()); |
| 300 | } |
| 301 | |
| 302 | // HLASM statements can only perform a single operation at a time |
| 303 | const MCExpr *SystemZTargetHLASMStreamer::createWordDiffExpr( |
| 304 | MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { |
| 305 | assert(Hi && Lo && "Symbols required to calculate expression" ); |
| 306 | MCSymbol *Temp = Ctx.createTempSymbol(); |
| 307 | OS << Temp->getName() << " EQU " ; |
| 308 | const MCBinaryExpr *TempExpr = MCBinaryExpr::createSub( |
| 309 | LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx), RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx), Ctx); |
| 310 | Ctx.getAsmInfo().printExpr(OS, *TempExpr); |
| 311 | OS << "\n" ; |
| 312 | return MCBinaryExpr::createLShr(LHS: MCSymbolRefExpr::create(Symbol: Temp, Ctx), |
| 313 | RHS: MCConstantExpr::create(Value: 1, Ctx), Ctx); |
| 314 | } |
| 315 | |
| 316 | const MCExpr *SystemZTargetGOFFStreamer::createWordDiffExpr( |
| 317 | MCContext &Ctx, const MCSymbol *Hi, const MCSymbol *Lo) { |
| 318 | assert(Hi && Lo && "Symbols required to calculate expression" ); |
| 319 | return MCBinaryExpr::createLShr( |
| 320 | LHS: MCBinaryExpr::createSub(LHS: MCSymbolRefExpr::create(Symbol: Hi, Ctx), |
| 321 | RHS: MCSymbolRefExpr::create(Symbol: Lo, Ctx), Ctx), |
| 322 | RHS: MCConstantExpr::create(Value: 1, Ctx), Ctx); |
| 323 | } |
| 324 | |