|
| 1 | +//===- SystemZHLASMAsmStreamer.cpp - HLASM Assembly Text Output -----------===// |
| 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 | +#include "SystemZHLASMAsmStreamer.h" |
| 10 | +#include "llvm/ADT/StringExtras.h" |
| 11 | +#include "llvm/Support/Casting.h" |
| 12 | +#include "llvm/Support/Signals.h" |
| 13 | +#include <sstream> |
| 14 | + |
| 15 | +#include <cmath> |
| 16 | + |
| 17 | +void SystemZHLASMAsmStreamer::EmitEOL() { |
| 18 | + // Comments are emitted on a new line before the instruction. |
| 19 | + if (IsVerboseAsm) |
| 20 | + EmitComment(); |
| 21 | + |
| 22 | + std::istringstream Stream(Str); |
| 23 | + SmallVector<std::string> Lines; |
| 24 | + std::string Line; |
| 25 | + while (std::getline(Stream, Line, '\n')) |
| 26 | + Lines.push_back(Line); |
| 27 | + |
| 28 | + for (auto S : Lines) { |
| 29 | + if (LLVM_LIKELY(S.length() < ContIndicatorColumn)) { |
| 30 | + FOS << S; |
| 31 | + // Each line in HLASM must fill the full 80 characters. |
| 32 | + FOS.PadToColumn(InstLimit); |
| 33 | + FOS << "\n"; |
| 34 | + } else { |
| 35 | + // If last character before end of the line is not a space |
| 36 | + // we must insert an additional non-space character that |
| 37 | + // is not part of the statement coding. We just reuse |
| 38 | + // the existing character by making the new substring start |
| 39 | + // 1 character sooner, thus "duplicating" that character |
| 40 | + // If The last character is a space. We insert an X instead. |
| 41 | + std::string TmpSubStr = S.substr(0, ContIndicatorColumn); |
| 42 | + if (!TmpSubStr.compare(ContIndicatorColumn - 1, 1, " ")) |
| 43 | + TmpSubStr.replace(ContIndicatorColumn - 1, 1, "X"); |
| 44 | + |
| 45 | + FOS << TmpSubStr; |
| 46 | + FOS.PadToColumn(InstLimit); |
| 47 | + FOS << "\n"; |
| 48 | + |
| 49 | + size_t Emitted = ContIndicatorColumn - 1; |
| 50 | + |
| 51 | + while (Emitted < S.length()) { |
| 52 | + if ((S.length() - Emitted) < ContLen) |
| 53 | + TmpSubStr = S.substr(Emitted, S.length()); |
| 54 | + else { |
| 55 | + TmpSubStr = S.substr(Emitted, ContLen); |
| 56 | + if (!TmpSubStr.compare(ContLen - 1, 1, " ")) |
| 57 | + TmpSubStr.replace(ContLen - 1, 1, "X"); |
| 58 | + } |
| 59 | + FOS.PadToColumn(ContStartColumn); |
| 60 | + FOS << TmpSubStr; |
| 61 | + FOS.PadToColumn(InstLimit); |
| 62 | + FOS << "\n"; |
| 63 | + Emitted += ContLen - 1; |
| 64 | + } |
| 65 | + } |
| 66 | + } |
| 67 | + Str.clear(); |
| 68 | +} |
| 69 | + |
| 70 | +void SystemZHLASMAsmStreamer::changeSection(MCSection *Section, |
| 71 | + uint32_t Subsection) { |
| 72 | + Section->printSwitchToSection(*MAI, getContext().getTargetTriple(), OS, |
| 73 | + Subsection); |
| 74 | + MCStreamer::changeSection(Section, Subsection); |
| 75 | +} |
| 76 | + |
| 77 | +void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment, |
| 78 | + std::optional<int64_t> Value, |
| 79 | + unsigned ValueSize, |
| 80 | + unsigned MaxBytesToEmit) { |
| 81 | + if (!isPowerOf2_64(ByteAlignment)) |
| 82 | + report_fatal_error("Only power-of-two alignments are supported "); |
| 83 | + |
| 84 | + OS << " DS 0"; |
| 85 | + switch (ValueSize) { |
| 86 | + default: |
| 87 | + llvm_unreachable("Invalid size for machine code value!"); |
| 88 | + case 1: |
| 89 | + OS << "B"; |
| 90 | + break; |
| 91 | + case 2: |
| 92 | + OS << "H"; |
| 93 | + break; |
| 94 | + case 4: |
| 95 | + OS << "F"; |
| 96 | + break; |
| 97 | + case 8: |
| 98 | + OS << "D"; |
| 99 | + break; |
| 100 | + case 16: |
| 101 | + OS << "Q"; |
| 102 | + break; |
| 103 | + } |
| 104 | + |
| 105 | + EmitEOL(); |
| 106 | +} |
| 107 | + |
| 108 | +void SystemZHLASMAsmStreamer::AddComment(const Twine &T, bool EOL) { |
| 109 | + if (!IsVerboseAsm) |
| 110 | + return; |
| 111 | + |
| 112 | + T.toVector(CommentToEmit); |
| 113 | + |
| 114 | + if (EOL) |
| 115 | + CommentToEmit.push_back('\n'); // Place comment in a new line. |
| 116 | +} |
| 117 | + |
| 118 | +void SystemZHLASMAsmStreamer::EmitComment() { |
| 119 | + if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) |
| 120 | + return; |
| 121 | + |
| 122 | + StringRef Comments = CommentToEmit; |
| 123 | + |
| 124 | + assert(Comments.back() == '\n' && "Comment array not newline terminated"); |
| 125 | + do { |
| 126 | + // Emit a line of comments, but not exceeding 80 characters. |
| 127 | + size_t Position = std::min(InstLimit - 2, Comments.find('\n')); |
| 128 | + FOS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) |
| 129 | + << '\n'; |
| 130 | + |
| 131 | + if (Comments[Position] == '\n') |
| 132 | + Position++; |
| 133 | + Comments = Comments.substr(Position); |
| 134 | + } while (!Comments.empty()); |
| 135 | + |
| 136 | + CommentToEmit.clear(); |
| 137 | +} |
| 138 | + |
| 139 | +void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment, |
| 140 | + int64_t Value, |
| 141 | + unsigned ValueSize, |
| 142 | + unsigned MaxBytesToEmit) { |
| 143 | + emitAlignmentDS(Alignment.value(), Value, ValueSize, MaxBytesToEmit); |
| 144 | +} |
| 145 | + |
| 146 | +void SystemZHLASMAsmStreamer::emitCodeAlignment(Align Alignment, |
| 147 | + const MCSubtargetInfo *STI, |
| 148 | + unsigned MaxBytesToEmit) { |
| 149 | + // Emit with a text fill value. |
| 150 | + if (MAI->getTextAlignFillValue()) |
| 151 | + emitAlignmentDS(Alignment.value(), MAI->getTextAlignFillValue(), 1, |
| 152 | + MaxBytesToEmit); |
| 153 | + else |
| 154 | + emitAlignmentDS(Alignment.value(), std::nullopt, 1, MaxBytesToEmit); |
| 155 | +} |
| 156 | + |
| 157 | +void SystemZHLASMAsmStreamer::emitBytes(StringRef Data) { |
| 158 | + assert(getCurrentSectionOnly() && |
| 159 | + "Cannot emit contents before setting section!"); |
| 160 | + if (Data.empty()) |
| 161 | + return; |
| 162 | + |
| 163 | + OS << " DC "; |
| 164 | + size_t Len = Data.size(); |
| 165 | + SmallVector<uint8_t> Chars; |
| 166 | + Chars.resize(Len); |
| 167 | + OS << "XL" << Len; |
| 168 | + uint32_t Index = 0; |
| 169 | + for (uint8_t C : Data) { |
| 170 | + Chars[Index] = C; |
| 171 | + Index++; |
| 172 | + } |
| 173 | + |
| 174 | + OS << '\'' << toHex(Chars) << '\''; |
| 175 | + |
| 176 | + EmitEOL(); |
| 177 | +} |
| 178 | + |
| 179 | +void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst, |
| 180 | + const MCSubtargetInfo &STI) { |
| 181 | + |
| 182 | + InstPrinter->printInst(&Inst, 0, "", STI, OS); |
| 183 | + EmitEOL(); |
| 184 | +} |
| 185 | + |
| 186 | +void SystemZHLASMAsmStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { |
| 187 | + |
| 188 | + MCStreamer::emitLabel(Symbol, Loc); |
| 189 | + |
| 190 | + Symbol->print(OS, MAI); |
| 191 | + // TODO Need to adjust this based on Label type |
| 192 | + OS << " DS 0H"; |
| 193 | + // TODO Update LabelSuffix in SystemZMCAsmInfoGOFF once tests have been |
| 194 | + // moved to HLASM syntax. |
| 195 | + // OS << MAI->getLabelSuffix(); |
| 196 | + EmitEOL(); |
| 197 | +} |
| 198 | + |
| 199 | +void SystemZHLASMAsmStreamer::emitRawTextImpl(StringRef String) { |
| 200 | + String.consume_back("\n"); |
| 201 | + OS << String; |
| 202 | + EmitEOL(); |
| 203 | +} |
| 204 | + |
| 205 | +// Slight duplicate of MCExpr::print due to HLASM only recognizing limited |
| 206 | +// arithmetic operators (+-*/). |
| 207 | +void SystemZHLASMAsmStreamer::emitHLASMValueImpl(const MCExpr *Value, |
| 208 | + unsigned Size, bool Parens) { |
| 209 | + switch (Value->getKind()) { |
| 210 | + case MCExpr::Constant: { |
| 211 | + OS << "XL" << Size << '\''; |
| 212 | + Value->print(OS, MAI); |
| 213 | + OS << '\''; |
| 214 | + return; |
| 215 | + } |
| 216 | + case MCExpr::Binary: { |
| 217 | + const MCBinaryExpr &BE = cast<MCBinaryExpr>(*Value); |
| 218 | + int64_t Const; |
| 219 | + // Or is handled differently. |
| 220 | + if (BE.getOpcode() == MCBinaryExpr::Or) { |
| 221 | + emitHLASMValueImpl(BE.getLHS(), Size, true); |
| 222 | + OS << ','; |
| 223 | + emitHLASMValueImpl(BE.getRHS(), Size, true); |
| 224 | + return; |
| 225 | + } |
| 226 | + |
| 227 | + if (Parens) |
| 228 | + OS << "A("; |
| 229 | + emitHLASMValueImpl(BE.getLHS(), Size); |
| 230 | + |
| 231 | + switch (BE.getOpcode()) { |
| 232 | + case MCBinaryExpr::LShr: { |
| 233 | + Const = cast<MCConstantExpr>(BE.getRHS())->getValue(); |
| 234 | + OS << '/' << (1 << Const); |
| 235 | + if (Parens) |
| 236 | + OS << ')'; |
| 237 | + return; |
| 238 | + } |
| 239 | + case MCBinaryExpr::Add: |
| 240 | + OS << '+'; |
| 241 | + break; |
| 242 | + case MCBinaryExpr::Div: |
| 243 | + OS << '/'; |
| 244 | + break; |
| 245 | + case MCBinaryExpr::Mul: |
| 246 | + OS << '*'; |
| 247 | + break; |
| 248 | + case MCBinaryExpr::Sub: |
| 249 | + OS << '-'; |
| 250 | + break; |
| 251 | + default: |
| 252 | + getContext().reportError(SMLoc(), |
| 253 | + "Unrecognized HLASM arithmetic expression!"); |
| 254 | + } |
| 255 | + emitHLASMValueImpl(BE.getRHS(), Size); |
| 256 | + if (Parens) |
| 257 | + OS << ')'; |
| 258 | + return; |
| 259 | + } |
| 260 | + case MCExpr::Target: |
| 261 | + Value->print(OS, MAI); |
| 262 | + return; |
| 263 | + default: |
| 264 | + if (Parens) |
| 265 | + OS << "A("; |
| 266 | + Value->print(OS, MAI); |
| 267 | + if (Parens) |
| 268 | + OS << ')'; |
| 269 | + return; |
| 270 | + } |
| 271 | +} |
| 272 | + |
| 273 | +void SystemZHLASMAsmStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, |
| 274 | + SMLoc Loc) { |
| 275 | + assert(Size <= 8 && "Invalid size"); |
| 276 | + assert(getCurrentSectionOnly() && |
| 277 | + "Cannot emit contents before setting section!"); |
| 278 | + |
| 279 | + OS << " DC "; |
| 280 | + emitHLASMValueImpl(Value, Size, true); |
| 281 | + EmitEOL(); |
| 282 | +} |
0 commit comments