1 //===-- WebAssemblyTypeUtilities.cpp - WebAssembly Type Utility Functions -===//
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 /// \file
10 /// This file implements several utility functions for WebAssembly type parsing.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "WebAssemblyTypeUtilities.h"
15 #include "llvm/ADT/StringSwitch.h"
16 
17 // Get register classes enum.
18 #define GET_REGINFO_ENUM
19 #include "WebAssemblyGenRegisterInfo.inc"
20 
21 using namespace llvm;
22 
23 Optional<wasm::ValType> WebAssembly::parseType(StringRef Type) {
24   // FIXME: can't use StringSwitch because wasm::ValType doesn't have a
25   // "invalid" value.
26   if (Type == "i32")
27     return wasm::ValType::I32;
28   if (Type == "i64")
29     return wasm::ValType::I64;
30   if (Type == "f32")
31     return wasm::ValType::F32;
32   if (Type == "f64")
33     return wasm::ValType::F64;
34   if (Type == "v128" || Type == "i8x16" || Type == "i16x8" || Type == "i32x4" ||
35       Type == "i64x2" || Type == "f32x4" || Type == "f64x2")
36     return wasm::ValType::V128;
37   if (Type == "funcref")
38     return wasm::ValType::FUNCREF;
39   if (Type == "externref")
40     return wasm::ValType::EXTERNREF;
41   return Optional<wasm::ValType>();
42 }
43 
44 WebAssembly::BlockType WebAssembly::parseBlockType(StringRef Type) {
45   // Multivalue block types are handled separately in parseSignature
46   return StringSwitch<WebAssembly::BlockType>(Type)
47       .Case("i32", WebAssembly::BlockType::I32)
48       .Case("i64", WebAssembly::BlockType::I64)
49       .Case("f32", WebAssembly::BlockType::F32)
50       .Case("f64", WebAssembly::BlockType::F64)
51       .Case("v128", WebAssembly::BlockType::V128)
52       .Case("funcref", WebAssembly::BlockType::Funcref)
53       .Case("externref", WebAssembly::BlockType::Externref)
54       .Case("void", WebAssembly::BlockType::Void)
55       .Default(WebAssembly::BlockType::Invalid);
56 }
57 
58 MVT WebAssembly::parseMVT(StringRef Type) {
59   return StringSwitch<MVT>(Type)
60       .Case("i32", MVT::i32)
61       .Case("i64", MVT::i64)
62       .Case("f32", MVT::f32)
63       .Case("f64", MVT::f64)
64       .Case("i64", MVT::i64)
65       .Case("v16i8", MVT::v16i8)
66       .Case("v8i16", MVT::v8i16)
67       .Case("v4i32", MVT::v4i32)
68       .Case("v2i64", MVT::v2i64)
69       .Case("funcref", MVT::funcref)
70       .Case("externref", MVT::externref)
71       .Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
72 }
73 
74 // We have various enums representing a subset of these types, use this
75 // function to convert any of them to text.
76 const char *WebAssembly::anyTypeToString(unsigned Type) {
77   switch (Type) {
78   case wasm::WASM_TYPE_I32:
79     return "i32";
80   case wasm::WASM_TYPE_I64:
81     return "i64";
82   case wasm::WASM_TYPE_F32:
83     return "f32";
84   case wasm::WASM_TYPE_F64:
85     return "f64";
86   case wasm::WASM_TYPE_V128:
87     return "v128";
88   case wasm::WASM_TYPE_FUNCREF:
89     return "funcref";
90   case wasm::WASM_TYPE_EXTERNREF:
91     return "externref";
92   case wasm::WASM_TYPE_FUNC:
93     return "func";
94   case wasm::WASM_TYPE_NORESULT:
95     return "void";
96   default:
97     return "invalid_type";
98   }
99 }
100 
101 const char *WebAssembly::typeToString(wasm::ValType Type) {
102   return anyTypeToString(static_cast<unsigned>(Type));
103 }
104 
105 std::string WebAssembly::typeListToString(ArrayRef<wasm::ValType> List) {
106   std::string S;
107   for (const auto &Type : List) {
108     if (&Type != &List[0])
109       S += ", ";
110     S += WebAssembly::typeToString(Type);
111   }
112   return S;
113 }
114 
115 std::string WebAssembly::signatureToString(const wasm::WasmSignature *Sig) {
116   std::string S("(");
117   S += typeListToString(Sig->Params);
118   S += ") -> (";
119   S += typeListToString(Sig->Returns);
120   S += ")";
121   return S;
122 }
123 
124 wasm::ValType WebAssembly::toValType(MVT Type) {
125   switch (Type.SimpleTy) {
126   case MVT::i32:
127     return wasm::ValType::I32;
128   case MVT::i64:
129     return wasm::ValType::I64;
130   case MVT::f32:
131     return wasm::ValType::F32;
132   case MVT::f64:
133     return wasm::ValType::F64;
134   case MVT::v16i8:
135   case MVT::v8i16:
136   case MVT::v4i32:
137   case MVT::v2i64:
138   case MVT::v4f32:
139   case MVT::v2f64:
140     return wasm::ValType::V128;
141   case MVT::funcref:
142     return wasm::ValType::FUNCREF;
143   case MVT::externref:
144     return wasm::ValType::EXTERNREF;
145   default:
146     llvm_unreachable("unexpected type");
147   }
148 }
149 
150 wasm::ValType WebAssembly::regClassToValType(unsigned RC) {
151   switch (RC) {
152   case WebAssembly::I32RegClassID:
153     return wasm::ValType::I32;
154   case WebAssembly::I64RegClassID:
155     return wasm::ValType::I64;
156   case WebAssembly::F32RegClassID:
157     return wasm::ValType::F32;
158   case WebAssembly::F64RegClassID:
159     return wasm::ValType::F64;
160   case WebAssembly::V128RegClassID:
161     return wasm::ValType::V128;
162   case WebAssembly::FUNCREFRegClassID:
163     return wasm::ValType::FUNCREF;
164   case WebAssembly::EXTERNREFRegClassID:
165     return wasm::ValType::EXTERNREF;
166   default:
167     llvm_unreachable("unexpected type");
168   }
169 }
170 
171 void WebAssembly::wasmSymbolSetType(MCSymbolWasm *Sym, const Type *GlobalVT,
172                                     const SmallVector<MVT, 1> &VTs) {
173   assert(!Sym->getType());
174 
175   // Tables are represented as Arrays in LLVM IR therefore
176   // they reach this point as aggregate Array types with an element type
177   // that is a reference type.
178   wasm::ValType Type;
179   bool IsTable = false;
180   if (GlobalVT->isArrayTy() &&
181       WebAssembly::isRefType(GlobalVT->getArrayElementType())) {
182     MVT VT;
183     IsTable = true;
184     switch (GlobalVT->getArrayElementType()->getPointerAddressSpace()) {
185     case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF:
186       VT = MVT::funcref;
187       break;
188     case WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF:
189       VT = MVT::externref;
190       break;
191     default:
192       report_fatal_error("unhandled address space type");
193     }
194     Type = WebAssembly::toValType(VT);
195   } else if (VTs.size() == 1) {
196     Type = WebAssembly::toValType(VTs[0]);
197   } else
198     report_fatal_error("Aggregate globals not yet implemented");
199 
200   if (IsTable) {
201     Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
202     Sym->setTableType(Type);
203   } else {
204     Sym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
205     Sym->setGlobalType(wasm::WasmGlobalType{uint8_t(Type), /*Mutable=*/true});
206   }
207 }
208