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