xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.cpp (revision 60d78908f57cf2100d5aeafa7db5d97cda3c5607)
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(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 Fill,
141                                                    uint8_t FillLen,
142                                                    unsigned MaxBytesToEmit) {
143   emitAlignmentDS(Alignment.value(), Fill, FillLen, 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     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 
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 
284 void SystemZHLASMAsmStreamer::emitEnd() {
285   OS << " END";
286   EmitEOL();
287 }
288