1 //===-- WebAssemblyAsmPrinter.cpp - WebAssembly LLVM assembly writer ------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// \brief This file contains a printer that converts from our internal 12 /// representation of machine-dependent LLVM code to the WebAssembly assembly 13 /// language. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #include "WebAssembly.h" 18 #include "WebAssemblyMachineFunctionInfo.h" 19 #include "WebAssemblyRegisterInfo.h" 20 #include "WebAssemblySubtarget.h" 21 #include "InstPrinter/WebAssemblyInstPrinter.h" 22 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 23 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/StringExtras.h" 26 #include "llvm/CodeGen/Analysis.h" 27 #include "llvm/CodeGen/AsmPrinter.h" 28 #include "llvm/CodeGen/MachineConstantPool.h" 29 #include "llvm/CodeGen/MachineInstr.h" 30 #include "llvm/IR/DataLayout.h" 31 #include "llvm/IR/DebugInfo.h" 32 #include "llvm/MC/MCStreamer.h" 33 #include "llvm/MC/MCSymbol.h" 34 #include "llvm/Support/Debug.h" 35 #include "llvm/Support/TargetRegistry.h" 36 #include "llvm/Support/raw_ostream.h" 37 38 using namespace llvm; 39 40 #define DEBUG_TYPE "asm-printer" 41 42 namespace { 43 44 class WebAssemblyAsmPrinter final : public AsmPrinter { 45 const WebAssemblyInstrInfo *TII; 46 const MachineRegisterInfo *MRI; 47 unsigned NumArgs; 48 49 public: 50 WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 51 : AsmPrinter(TM, std::move(Streamer)), TII(nullptr), MRI(nullptr) {} 52 53 private: 54 const char *getPassName() const override { 55 return "WebAssembly Assembly Printer"; 56 } 57 58 //===------------------------------------------------------------------===// 59 // MachineFunctionPass Implementation. 60 //===------------------------------------------------------------------===// 61 62 void getAnalysisUsage(AnalysisUsage &AU) const override { 63 AsmPrinter::getAnalysisUsage(AU); 64 } 65 66 bool runOnMachineFunction(MachineFunction &MF) override { 67 const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>(); 68 TII = Subtarget.getInstrInfo(); 69 MRI = &MF.getRegInfo(); 70 NumArgs = MF.getInfo<WebAssemblyFunctionInfo>()->getParams().size(); 71 return AsmPrinter::runOnMachineFunction(MF); 72 } 73 74 //===------------------------------------------------------------------===// 75 // AsmPrinter Implementation. 76 //===------------------------------------------------------------------===// 77 78 void EmitJumpTableInfo() override; 79 void EmitConstantPool() override; 80 void EmitFunctionBodyStart() override; 81 void EmitInstruction(const MachineInstr *MI) override; 82 void EmitEndOfAsmFile(Module &M) override; 83 84 std::string getRegTypeName(unsigned RegNo) const; 85 static std::string toString(const APFloat &APF); 86 const char *toString(MVT VT) const; 87 std::string regToString(const MachineOperand &MO); 88 std::string argToString(const MachineOperand &MO); 89 }; 90 91 } // end anonymous namespace 92 93 //===----------------------------------------------------------------------===// 94 // Helpers. 95 //===----------------------------------------------------------------------===// 96 97 // Operand type (if any), followed by the lower-case version of the opcode's 98 // name matching the names WebAssembly opcodes are expected to have. The 99 // tablegen names are uppercase and suffixed with their type (after an 100 // underscore). Conversions are additionally prefixed with their input type 101 // (before a double underscore). 102 static std::string OpcodeName(const WebAssemblyInstrInfo *TII, 103 const MachineInstr *MI) { 104 std::string N(StringRef(TII->getName(MI->getOpcode())).lower()); 105 std::string::size_type Len = N.length(); 106 std::string::size_type Under = N.rfind('_'); 107 bool HasType = std::string::npos != Under; 108 std::string::size_type NameEnd = HasType ? Under : Len; 109 std::string Name(&N[0], &N[NameEnd]); 110 if (!HasType) 111 return Name; 112 for (const char *typelessOpcode : { "return", "call", "br_if" }) 113 if (Name == typelessOpcode) 114 return Name; 115 std::string Type(&N[NameEnd + 1], &N[Len]); 116 std::string::size_type DoubleUnder = Name.find("__"); 117 bool IsConv = std::string::npos != DoubleUnder; 118 if (!IsConv) 119 return Type + '.' + Name; 120 std::string InType(&Name[0], &Name[DoubleUnder]); 121 return Type + '.' + std::string(&Name[DoubleUnder + 2], &Name[NameEnd]) + 122 '/' + InType; 123 } 124 125 static std::string toSymbol(StringRef S) { return ("$" + S).str(); } 126 127 std::string WebAssemblyAsmPrinter::getRegTypeName(unsigned RegNo) const { 128 const TargetRegisterClass *TRC = MRI->getRegClass(RegNo); 129 for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64}) 130 if (TRC->hasType(T)) 131 return EVT(T).getEVTString(); 132 DEBUG(errs() << "Unknown type for register number: " << RegNo); 133 llvm_unreachable("Unknown register type"); 134 return "?"; 135 } 136 137 std::string WebAssemblyAsmPrinter::toString(const APFloat &FP) { 138 static const size_t BufBytes = 128; 139 char buf[BufBytes]; 140 if (FP.isNaN()) 141 assert((FP.bitwiseIsEqual(APFloat::getQNaN(FP.getSemantics())) || 142 FP.bitwiseIsEqual( 143 APFloat::getQNaN(FP.getSemantics(), /*Negative=*/true))) && 144 "convertToHexString handles neither SNaN nor NaN payloads"); 145 // Use C99's hexadecimal floating-point representation. 146 auto Written = FP.convertToHexString( 147 buf, /*hexDigits=*/0, /*upperCase=*/false, APFloat::rmNearestTiesToEven); 148 (void)Written; 149 assert(Written != 0); 150 assert(Written < BufBytes); 151 return buf; 152 } 153 154 std::string WebAssemblyAsmPrinter::regToString(const MachineOperand &MO) { 155 unsigned RegNo = MO.getReg(); 156 if (TargetRegisterInfo::isPhysicalRegister(RegNo)) 157 return WebAssemblyInstPrinter::getRegisterName(RegNo); 158 159 // WebAssembly arguments and local variables are in the same index space, and 160 // there are no explicit varargs, so we just add the number of arguments to 161 // the virtual register number to get the local variable number. 162 return utostr(TargetRegisterInfo::virtReg2Index(RegNo) + NumArgs); 163 } 164 165 std::string WebAssemblyAsmPrinter::argToString(const MachineOperand &MO) { 166 unsigned ArgNo = MO.getImm(); 167 // Same as above, but we don't need to add NumArgs here. 168 return utostr(ArgNo); 169 } 170 171 const char *WebAssemblyAsmPrinter::toString(MVT VT) const { 172 switch (VT.SimpleTy) { 173 default: 174 break; 175 case MVT::f32: 176 return "f32"; 177 case MVT::f64: 178 return "f64"; 179 case MVT::i32: 180 return "i32"; 181 case MVT::i64: 182 return "i64"; 183 } 184 DEBUG(dbgs() << "Invalid type " << EVT(VT).getEVTString() << '\n'); 185 llvm_unreachable("invalid type"); 186 return "<invalid>"; 187 } 188 189 //===----------------------------------------------------------------------===// 190 // WebAssemblyAsmPrinter Implementation. 191 //===----------------------------------------------------------------------===// 192 193 void WebAssemblyAsmPrinter::EmitConstantPool() { 194 assert(MF->getConstantPool()->getConstants().empty() && 195 "WebAssembly disables constant pools"); 196 } 197 198 void WebAssemblyAsmPrinter::EmitJumpTableInfo() { 199 // Nothing to do; jump tables are incorporated into the instruction stream. 200 } 201 202 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { 203 SmallString<128> Str; 204 raw_svector_ostream OS(Str); 205 206 for (MVT VT : MF->getInfo<WebAssemblyFunctionInfo>()->getParams()) 207 OS << "\t" ".param " 208 << toString(VT) << '\n'; 209 for (MVT VT : MF->getInfo<WebAssemblyFunctionInfo>()->getResults()) 210 OS << "\t" ".result " 211 << toString(VT) << '\n'; 212 213 bool FirstVReg = true; 214 for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) { 215 unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx); 216 // FIXME: Don't skip dead virtual registers for now: that would require 217 // remapping all locals' numbers. 218 // if (!MRI->use_empty(VReg)) { 219 if (FirstVReg) 220 OS << "\t" ".local "; 221 else 222 OS << ", "; 223 OS << getRegTypeName(VReg); 224 FirstVReg = false; 225 //} 226 } 227 if (!FirstVReg) 228 OS << '\n'; 229 230 // EmitRawText appends a newline, so strip off the last newline. 231 StringRef Text = OS.str(); 232 if (!Text.empty()) 233 OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1)); 234 AsmPrinter::EmitFunctionBodyStart(); 235 } 236 237 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { 238 DEBUG(dbgs() << "EmitInstruction: " << *MI << '\n'); 239 SmallString<128> Str; 240 raw_svector_ostream OS(Str); 241 242 unsigned NumDefs = MI->getDesc().getNumDefs(); 243 assert(NumDefs <= 1 && 244 "Instructions with multiple result values not implemented"); 245 246 OS << '\t'; 247 248 switch (MI->getOpcode()) { 249 case TargetOpcode::COPY: 250 OS << "get_local push, " << regToString(MI->getOperand(1)); 251 break; 252 case WebAssembly::ARGUMENT_I32: 253 case WebAssembly::ARGUMENT_I64: 254 case WebAssembly::ARGUMENT_F32: 255 case WebAssembly::ARGUMENT_F64: 256 OS << "get_local push, " << argToString(MI->getOperand(1)); 257 break; 258 default: { 259 OS << OpcodeName(TII, MI); 260 bool NeedComma = false; 261 bool DefsPushed = false; 262 if (NumDefs != 0 && !MI->isCall()) { 263 OS << " push"; 264 NeedComma = true; 265 DefsPushed = true; 266 } 267 for (const MachineOperand &MO : MI->uses()) { 268 if (MO.isReg() && MO.isImplicit()) 269 continue; 270 if (NeedComma) 271 OS << ','; 272 NeedComma = true; 273 OS << ' '; 274 switch (MO.getType()) { 275 default: 276 llvm_unreachable("unexpected machine operand type"); 277 case MachineOperand::MO_Register: 278 OS << "(get_local " << regToString(MO) << ')'; 279 break; 280 case MachineOperand::MO_Immediate: 281 OS << MO.getImm(); 282 break; 283 case MachineOperand::MO_FPImmediate: 284 OS << toString(MO.getFPImm()->getValueAPF()); 285 break; 286 case MachineOperand::MO_GlobalAddress: 287 OS << toSymbol(MO.getGlobal()->getName()); 288 break; 289 case MachineOperand::MO_MachineBasicBlock: 290 OS << toSymbol(MO.getMBB()->getSymbol()->getName()); 291 break; 292 } 293 if (NumDefs != 0 && !DefsPushed) { 294 // Special-case for calls; print the push after the callee. 295 assert(MI->isCall()); 296 OS << ", push"; 297 DefsPushed = true; 298 } 299 } 300 break; 301 } 302 } 303 304 OutStreamer->EmitRawText(OS.str()); 305 306 if (NumDefs != 0) { 307 SmallString<128> Str; 308 raw_svector_ostream OS(Str); 309 const MachineOperand &Operand = MI->getOperand(0); 310 OS << "\tset_local " << regToString(Operand) << ", pop"; 311 OutStreamer->EmitRawText(OS.str()); 312 } 313 } 314 315 static void ComputeLegalValueVTs(LLVMContext &Context, 316 const WebAssemblyTargetLowering &TLI, 317 const DataLayout &DL, Type *Ty, 318 SmallVectorImpl<MVT> &ValueVTs) { 319 SmallVector<EVT, 4> VTs; 320 ComputeValueVTs(TLI, DL, Ty, VTs); 321 322 for (EVT VT : VTs) { 323 unsigned NumRegs = TLI.getNumRegisters(Context, VT); 324 MVT RegisterVT = TLI.getRegisterType(Context, VT); 325 for (unsigned i = 0; i != NumRegs; ++i) 326 ValueVTs.push_back(RegisterVT); 327 } 328 } 329 330 void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { 331 const DataLayout &DL = M.getDataLayout(); 332 333 SmallString<128> Str; 334 raw_svector_ostream OS(Str); 335 for (const Function &F : M) 336 if (F.isDeclarationForLinker()) { 337 assert(F.hasName() && "imported functions must have a name"); 338 if (F.isIntrinsic()) 339 continue; 340 if (Str.empty()) 341 OS << "\t.imports\n"; 342 343 OS << "\t.import " << toSymbol(F.getName()) << " \"\" \"" << F.getName() 344 << "\""; 345 346 const WebAssemblyTargetLowering &TLI = 347 *TM.getSubtarget<WebAssemblySubtarget>(F).getTargetLowering(); 348 349 // If we need to legalize the return type, it'll get converted into 350 // passing a pointer. 351 bool SawParam = false; 352 SmallVector<MVT, 4> ResultVTs; 353 ComputeLegalValueVTs(M.getContext(), TLI, DL, F.getReturnType(), 354 ResultVTs); 355 if (ResultVTs.size() > 1) { 356 ResultVTs.clear(); 357 OS << " (param " << toString(TLI.getPointerTy(DL)); 358 SawParam = true; 359 } 360 361 for (const Argument &A : F.args()) { 362 SmallVector<MVT, 4> ParamVTs; 363 ComputeLegalValueVTs(M.getContext(), TLI, DL, A.getType(), ParamVTs); 364 for (EVT VT : ParamVTs) { 365 if (!SawParam) { 366 OS << " (param"; 367 SawParam = true; 368 } 369 OS << ' ' << toString(VT.getSimpleVT()); 370 } 371 } 372 if (SawParam) 373 OS << ')'; 374 375 for (EVT VT : ResultVTs) 376 OS << " (result " << toString(VT.getSimpleVT()) << ')'; 377 378 OS << '\n'; 379 } 380 381 StringRef Text = OS.str(); 382 if (!Text.empty()) 383 OutStreamer->EmitRawText(Text.substr(0, Text.size() - 1)); 384 } 385 386 // Force static initialization. 387 extern "C" void LLVMInitializeWebAssemblyAsmPrinter() { 388 RegisterAsmPrinter<WebAssemblyAsmPrinter> X(TheWebAssemblyTarget32); 389 RegisterAsmPrinter<WebAssemblyAsmPrinter> Y(TheWebAssemblyTarget64); 390 } 391