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