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
15using namespace llvm;
16
17void 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(in&: Stream, str&: Line, delim: '\n'))
26 Lines.push_back(Elt: 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(NewCol: 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(pos: 0, n: ContIndicatorColumn);
42 if (!TmpSubStr.compare(pos: ContIndicatorColumn - 1, n1: 1, s: " "))
43 TmpSubStr.replace(pos: ContIndicatorColumn - 1, n1: 1, s: "X");
44
45 FOS << TmpSubStr;
46 FOS.PadToColumn(NewCol: 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(pos: Emitted, n: S.length());
54 else {
55 TmpSubStr = S.substr(pos: Emitted, n: ContLen);
56 if (!TmpSubStr.compare(pos: ContLen - 1, n1: 1, s: " "))
57 TmpSubStr.replace(pos: ContLen - 1, n1: 1, s: "X");
58 }
59 FOS.PadToColumn(NewCol: ContStartColumn);
60 FOS << TmpSubStr;
61 FOS.PadToColumn(NewCol: InstLimit);
62 FOS << "\n";
63 Emitted += ContLen - 1;
64 }
65 }
66 }
67 Str.clear();
68}
69
70void SystemZHLASMAsmStreamer::changeSection(MCSection *Section,
71 uint32_t Subsection) {
72 Section->printSwitchToSection(MAI: *MAI, T: getContext().getTargetTriple(), OS,
73 Subsection);
74 MCStreamer::changeSection(Section, Subsection);
75}
76
77void SystemZHLASMAsmStreamer::emitAlignmentDS(uint64_t ByteAlignment,
78 std::optional<int64_t> Value,
79 unsigned ValueSize,
80 unsigned MaxBytesToEmit) {
81 if (!isPowerOf2_64(Value: ByteAlignment))
82 report_fatal_error(reason: "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
108void SystemZHLASMAsmStreamer::AddComment(const Twine &T, bool EOL) {
109 if (!IsVerboseAsm)
110 return;
111
112 T.toVector(Out&: CommentToEmit);
113
114 if (EOL)
115 CommentToEmit.push_back(Elt: '\n'); // Place comment in a new line.
116}
117
118void 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(a: InstLimit - 2, b: Comments.find(C: '\n'));
128 FOS << MAI->getCommentString() << ' ' << Comments.substr(Start: 0, N: Position)
129 << '\n';
130
131 if (Comments[Position] == '\n')
132 Position++;
133 Comments = Comments.substr(Start: Position);
134 } while (!Comments.empty());
135
136 CommentToEmit.clear();
137}
138
139void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment,
140 int64_t Value,
141 unsigned ValueSize,
142 unsigned MaxBytesToEmit) {
143 emitAlignmentDS(ByteAlignment: Alignment.value(), Value, ValueSize, MaxBytesToEmit);
144}
145
146void SystemZHLASMAsmStreamer::emitCodeAlignment(Align Alignment,
147 const MCSubtargetInfo *STI,
148 unsigned MaxBytesToEmit) {
149 // Emit with a text fill value.
150 if (MAI->getTextAlignFillValue())
151 emitAlignmentDS(ByteAlignment: Alignment.value(), Value: MAI->getTextAlignFillValue(), ValueSize: 1,
152 MaxBytesToEmit);
153 else
154 emitAlignmentDS(ByteAlignment: Alignment.value(), Value: std::nullopt, ValueSize: 1, MaxBytesToEmit);
155}
156
157void 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(N: 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(Input: Chars) << '\'';
175
176 EmitEOL();
177}
178
179void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
180 const MCSubtargetInfo &STI) {
181
182 InstPrinter->printInst(MI: &Inst, Address: 0, Annot: "", STI, OS);
183 EmitEOL();
184}
185
186void 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
199void SystemZHLASMAsmStreamer::emitRawTextImpl(StringRef String) {
200 String.consume_back(Suffix: "\n");
201 OS << String;
202 EmitEOL();
203}
204
205// Slight duplicate of MCExpr::print due to HLASM only recognizing limited
206// arithmetic operators (+-*/).
207void SystemZHLASMAsmStreamer::emitHLASMValueImpl(const MCExpr *Value,
208 unsigned Size, bool Parens) {
209 switch (Value->getKind()) {
210 case MCExpr::Constant: {
211 OS << "XL" << Size << '\'';
212 MAI->printExpr(OS, *Value);
213 OS << '\'';
214 return;
215 }
216 case MCExpr::Binary: {
217 const MCBinaryExpr &BE = cast<MCBinaryExpr>(Val: *Value);
218 int64_t Const;
219 // Or is handled differently.
220 if (BE.getOpcode() == MCBinaryExpr::Or) {
221 emitHLASMValueImpl(Value: BE.getLHS(), Size, Parens: true);
222 OS << ',';
223 emitHLASMValueImpl(Value: BE.getRHS(), Size, Parens: true);
224 return;
225 }
226
227 if (Parens)
228 OS << "A(";
229 emitHLASMValueImpl(Value: BE.getLHS(), Size);
230
231 switch (BE.getOpcode()) {
232 case MCBinaryExpr::LShr: {
233 Const = cast<MCConstantExpr>(Val: 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(L: SMLoc(),
253 Msg: "Unrecognized HLASM arithmetic expression!");
254 }
255 emitHLASMValueImpl(Value: BE.getRHS(), Size);
256 if (Parens)
257 OS << ')';
258 return;
259 }
260 case MCExpr::Target:
261 MAI->printExpr(OS, *Value);
262 return;
263 default:
264 if (Parens)
265 OS << "A(";
266 MAI->printExpr(OS, *Value);
267 if (Parens)
268 OS << ')';
269 return;
270 }
271}
272
273void 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, Parens: true);
281 EmitEOL();
282}
283
284void SystemZHLASMAsmStreamer::emitEnd() {
285 OS << " END";
286 EmitEOL();
287}
288