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
EmitEOL()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
changeSection(MCSection * Section,uint32_t Subsection)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
emitAlignmentDS(uint64_t ByteAlignment,std::optional<int64_t> Value,unsigned ValueSize,unsigned MaxBytesToEmit)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
AddComment(const Twine & T,bool EOL)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
EmitComment()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
emitValueToAlignment(Align Alignment,int64_t Fill,uint8_t FillLen,unsigned MaxBytesToEmit)139 void SystemZHLASMAsmStreamer::emitValueToAlignment(Align Alignment,
140 int64_t Fill,
141 uint8_t FillLen,
142 unsigned MaxBytesToEmit) {
143 emitAlignmentDS(Alignment.value(), Fill, FillLen, MaxBytesToEmit);
144 }
145
emitCodeAlignment(Align Alignment,const MCSubtargetInfo * STI,unsigned MaxBytesToEmit)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
emitBytes(StringRef Data)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
emitInstruction(const MCInst & Inst,const MCSubtargetInfo & STI)179 void SystemZHLASMAsmStreamer::emitInstruction(const MCInst &Inst,
180 const MCSubtargetInfo &STI) {
181
182 InstPrinter->printInst(&Inst, 0, "", STI, OS);
183 EmitEOL();
184 }
185
emitLabel(MCSymbol * Symbol,SMLoc Loc)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
emitRawTextImpl(StringRef String)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 (+-*/).
emitHLASMValueImpl(const MCExpr * Value,unsigned Size,bool Parens)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>(*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 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
emitValueImpl(const MCExpr * Value,unsigned Size,SMLoc Loc)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 }
283
emitEnd()284 void SystemZHLASMAsmStreamer::emitEnd() {
285 OS << " END";
286 EmitEOL();
287 }
288