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 | using namespace llvm; |
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(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 | |
70 | void 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 | |
77 | void 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 | |
108 | void SystemZHLASMAsmStreamer::(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 | |
118 | void SystemZHLASMAsmStreamer::() { |
119 | if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) |
120 | return; |
121 | |
122 | StringRef = 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 | |
139 | void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment, |
140 | int64_t Value, |
141 | unsigned ValueSize, |
142 | unsigned MaxBytesToEmit) { |
143 | emitAlignmentDS(ByteAlignment: 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(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 | |
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(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 | |
179 | void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst, |
180 | const MCSubtargetInfo &STI) { |
181 | |
182 | InstPrinter->printInst(MI: &Inst, Address: 0, Annot: "" , 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(Suffix: "\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 | 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 | |
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, Parens: true); |
281 | EmitEOL(); |
282 | } |
283 | |
284 | void SystemZHLASMAsmStreamer::emitEnd() { |
285 | OS << " END" ; |
286 | EmitEOL(); |
287 | } |
288 | |