1 // WebAssemblyInstrInfo.td-Describe the WebAssembly Instructions-*- tablegen -*-
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
7 //===----------------------------------------------------------------------===//
10 /// WebAssembly Instruction definitions.
12 //===----------------------------------------------------------------------===//
14 //===----------------------------------------------------------------------===//
15 // WebAssembly Instruction Predicate Definitions.
16 //===----------------------------------------------------------------------===//
18 def IsPIC : Predicate<"TM.isPositionIndependent()">;
19 def IsNotPIC : Predicate<"!TM.isPositionIndependent()">;
21 def HasAddr32 : Predicate<"!Subtarget->hasAddr64()">;
23 def HasAddr64 : Predicate<"Subtarget->hasAddr64()">;
26 Predicate<"Subtarget->hasSIMD128()">,
27 AssemblerPredicate<(all_of FeatureSIMD128), "simd128">;
30 Predicate<"Subtarget->hasAtomics()">,
31 AssemblerPredicate<(all_of FeatureAtomics), "atomics">;
34 Predicate<"Subtarget->hasMultivalue()">,
35 AssemblerPredicate<(all_of FeatureMultivalue), "multivalue">;
37 def HasNontrappingFPToInt :
38 Predicate<"Subtarget->hasNontrappingFPToInt()">,
39 AssemblerPredicate<(all_of FeatureNontrappingFPToInt), "nontrapping-fptoint">;
41 def NotHasNontrappingFPToInt :
42 Predicate<"!Subtarget->hasNontrappingFPToInt()">,
43 AssemblerPredicate<(all_of (not FeatureNontrappingFPToInt)), "nontrapping-fptoint">;
46 Predicate<"Subtarget->hasSignExt()">,
47 AssemblerPredicate<(all_of FeatureSignExt), "sign-ext">;
50 Predicate<"Subtarget->hasTailCall()">,
51 AssemblerPredicate<(all_of FeatureTailCall), "tail-call">;
53 def HasExceptionHandling :
54 Predicate<"Subtarget->hasExceptionHandling()">,
55 AssemblerPredicate<(all_of FeatureExceptionHandling), "exception-handling">;
58 Predicate<"Subtarget->hasBulkMemory()">,
59 AssemblerPredicate<(all_of FeatureBulkMemory), "bulk-memory">;
61 def HasReferenceTypes :
62 Predicate<"Subtarget->hasReferenceTypes()">,
63 AssemblerPredicate<(all_of FeatureReferenceTypes), "reference-types">;
65 //===----------------------------------------------------------------------===//
66 // WebAssembly-specific DAG Node Types.
67 //===----------------------------------------------------------------------===//
69 def SDT_WebAssemblyCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>,
71 def SDT_WebAssemblyCallSeqEnd :
72 SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
73 def SDT_WebAssemblyBrTable : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
74 def SDT_WebAssemblyArgument : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>;
75 def SDT_WebAssemblyLocalGet : SDTypeProfile<1, 1, [SDTCisVT<1, i32>]>;
76 def SDT_WebAssemblyLocalSet : SDTypeProfile<0, 2, [SDTCisVT<0, i32>]>;
77 def SDT_WebAssemblyReturn : SDTypeProfile<0, -1, []>;
78 def SDT_WebAssemblyWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
80 def SDT_WebAssemblyWrapperPIC : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>,
82 def SDT_WebAssemblyGlobalGet : SDTypeProfile<1, 1, [SDTCisPtrTy<1>]>;
83 def SDT_WebAssemblyGlobalSet : SDTypeProfile<0, 2, [SDTCisPtrTy<1>]>;
85 //===----------------------------------------------------------------------===//
86 // WebAssembly-specific DAG Nodes.
87 //===----------------------------------------------------------------------===//
89 def WebAssemblycallseq_start :
90 SDNode<"ISD::CALLSEQ_START", SDT_WebAssemblyCallSeqStart,
91 [SDNPHasChain, SDNPOutGlue]>;
92 def WebAssemblycallseq_end :
93 SDNode<"ISD::CALLSEQ_END", SDT_WebAssemblyCallSeqEnd,
94 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
95 def WebAssemblybr_table : SDNode<"WebAssemblyISD::BR_TABLE",
96 SDT_WebAssemblyBrTable,
97 [SDNPHasChain, SDNPVariadic]>;
98 def WebAssemblyargument : SDNode<"WebAssemblyISD::ARGUMENT",
99 SDT_WebAssemblyArgument>;
100 def WebAssemblyreturn : SDNode<"WebAssemblyISD::RETURN",
101 SDT_WebAssemblyReturn,
102 [SDNPHasChain, SDNPVariadic]>;
103 def WebAssemblywrapper : SDNode<"WebAssemblyISD::Wrapper",
104 SDT_WebAssemblyWrapper>;
105 def WebAssemblywrapperPIC : SDNode<"WebAssemblyISD::WrapperPIC",
106 SDT_WebAssemblyWrapperPIC>;
107 def WebAssemblyglobal_get :
108 SDNode<"WebAssemblyISD::GLOBAL_GET", SDT_WebAssemblyGlobalGet,
109 [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>;
110 def WebAssemblyglobal_set :
111 SDNode<"WebAssemblyISD::GLOBAL_SET", SDT_WebAssemblyGlobalSet,
112 [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>;
113 def WebAssemblylocal_get :
114 SDNode<"WebAssemblyISD::LOCAL_GET", SDT_WebAssemblyLocalGet,
115 [SDNPHasChain, SDNPMayLoad]>;
116 def WebAssemblylocal_set :
117 SDNode<"WebAssemblyISD::LOCAL_SET", SDT_WebAssemblyLocalSet,
118 [SDNPHasChain, SDNPMayStore]>;
120 //===----------------------------------------------------------------------===//
121 // WebAssembly-specific Operands.
122 //===----------------------------------------------------------------------===//
124 // Default Operand has AsmOperandClass "Imm" which is for integers (and
125 // symbols), so specialize one for floats:
126 class FPImmAsmOperand<ValueType ty> : AsmOperandClass {
127 let Name = "FPImm" # ty;
128 let PredicateMethod = "isFPImm";
131 class FPOperand<ValueType ty> : Operand<ty> {
132 AsmOperandClass ParserMatchClass = FPImmAsmOperand<ty>;
135 let OperandNamespace = "WebAssembly" in {
137 let OperandType = "OPERAND_BASIC_BLOCK" in
138 def bb_op : Operand<OtherVT>;
140 let OperandType = "OPERAND_LOCAL" in
141 def local_op : Operand<i32>;
143 let OperandType = "OPERAND_GLOBAL" in {
144 // The operand to global instructions is always a 32-bit index.
145 def global_op32 : Operand<i32>;
146 // In PIC mode however, we temporarily represent this index as an external
147 // symbol, which to LLVM is a pointer, so in wasm64 mode it is easiest to
148 // pretend we use a 64-bit index for it.
149 def global_op64 : Operand<i64>;
152 let OperandType = "OPERAND_I32IMM" in
153 def i32imm_op : Operand<i32>;
155 let OperandType = "OPERAND_I64IMM" in
156 def i64imm_op : Operand<i64>;
158 let OperandType = "OPERAND_F32IMM" in
159 def f32imm_op : FPOperand<f32>;
161 let OperandType = "OPERAND_F64IMM" in
162 def f64imm_op : FPOperand<f64>;
164 let OperandType = "OPERAND_VEC_I8IMM" in
165 def vec_i8imm_op : Operand<i32>;
167 let OperandType = "OPERAND_VEC_I16IMM" in
168 def vec_i16imm_op : Operand<i32>;
170 let OperandType = "OPERAND_VEC_I32IMM" in
171 def vec_i32imm_op : Operand<i32>;
173 let OperandType = "OPERAND_VEC_I64IMM" in
174 def vec_i64imm_op : Operand<i64>;
176 let OperandType = "OPERAND_FUNCTION32" in
177 def function32_op : Operand<i32>;
179 let OperandType = "OPERAND_TABLE" in
180 def table32_op : Operand<i32>;
182 let OperandType = "OPERAND_OFFSET32" in
183 def offset32_op : Operand<i32>;
185 let OperandType = "OPERAND_OFFSET64" in
186 def offset64_op : Operand<i64>;
188 let OperandType = "OPERAND_P2ALIGN" in {
189 def P2Align : Operand<i32> {
190 let PrintMethod = "printWebAssemblyP2AlignOperand";
193 let OperandType = "OPERAND_TAG" in
194 def tag_op : Operand<i32>;
196 } // OperandType = "OPERAND_P2ALIGN"
198 let OperandType = "OPERAND_SIGNATURE" in
199 def Signature : Operand<i32> {
200 let PrintMethod = "printWebAssemblySignatureOperand";
203 let OperandType = "OPERAND_HEAPTYPE" in
204 def HeapType : Operand<i32> {
205 let PrintMethod = "printWebAssemblyHeapTypeOperand";
208 let OperandType = "OPERAND_TYPEINDEX" in
209 def TypeIndex : Operand<i32>;
211 } // OperandNamespace = "WebAssembly"
213 // TODO: Find more places to use this.
214 def bool_node : PatLeaf<(i32 I32:$cond), [{
215 return CurDAG->computeKnownBits(SDValue(N, 0)).countMinLeadingZeros() == 31;
218 //===----------------------------------------------------------------------===//
219 // WebAssembly Register to Stack instruction mapping
220 //===----------------------------------------------------------------------===//
223 def getStackOpcode : InstrMapping {
224 let FilterClass = "StackRel";
225 let RowFields = ["BaseName"];
226 let ColFields = ["StackBased"];
227 let KeyCol = ["false"];
228 let ValueCols = [["true"]];
231 //===----------------------------------------------------------------------===//
232 // WebAssembly Stack to Register instruction mapping
233 //===----------------------------------------------------------------------===//
236 def getRegisterOpcode : InstrMapping {
237 let FilterClass = "RegisterRel";
238 let RowFields = ["BaseName"];
239 let ColFields = ["StackBased"];
240 let KeyCol = ["true"];
241 let ValueCols = [["false"]];
244 //===----------------------------------------------------------------------===//
245 // WebAssembly 32 to 64-bit instruction mapping
246 //===----------------------------------------------------------------------===//
249 def getWasm64Opcode : InstrMapping {
250 let FilterClass = "Wasm64Rel";
251 let RowFields = ["Wasm32Name"];
252 let ColFields = ["IsWasm64"];
253 let KeyCol = ["false"];
254 let ValueCols = [["true"]];
257 //===----------------------------------------------------------------------===//
258 // WebAssembly Instruction Format Definitions.
259 //===----------------------------------------------------------------------===//
261 include "WebAssemblyInstrFormats.td"
263 //===----------------------------------------------------------------------===//
264 // Additional instructions.
265 //===----------------------------------------------------------------------===//
267 multiclass ARGUMENT<WebAssemblyRegClass rc, ValueType vt> {
268 let hasSideEffects = 1, isCodeGenOnly = 1, Defs = []<Register>,
269 Uses = [ARGUMENTS] in
271 I<(outs rc:$res), (ins i32imm:$argno), (outs), (ins i32imm:$argno),
272 [(set (vt rc:$res), (WebAssemblyargument timm:$argno))]>;
274 defm "": ARGUMENT<I32, i32>;
275 defm "": ARGUMENT<I64, i64>;
276 defm "": ARGUMENT<F32, f32>;
277 defm "": ARGUMENT<F64, f64>;
278 defm "": ARGUMENT<FUNCREF, funcref>;
279 defm "": ARGUMENT<EXTERNREF, externref>;
281 // local.get and local.set are not generated by instruction selection; they
282 // are implied by virtual register uses and defs.
283 multiclass LOCAL<WebAssemblyRegClass rc, Operand global_op> {
284 let hasSideEffects = 0 in {
285 // COPY is not an actual instruction in wasm, but since we allow local.get and
286 // local.set to be implicit during most of codegen, we can have a COPY which
287 // is actually a no-op because all the work is done in the implied local.get
288 // and local.set. COPYs are eliminated (and replaced with
289 // local.get/local.set) in the ExplicitLocals pass.
290 let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in
291 defm COPY_#rc : I<(outs rc:$res), (ins rc:$src), (outs), (ins), [],
292 "local.copy\t$res, $src", "local.copy">;
294 // TEE is similar to COPY, but writes two copies of its result. Typically
295 // this would be used to stackify one result and write the other result to a
297 let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in
298 defm TEE_#rc : I<(outs rc:$res, rc:$also), (ins rc:$src), (outs), (ins), [],
299 "local.tee\t$res, $also, $src", "local.tee">;
301 // This is the actual local.get instruction in wasm. These are made explicit
302 // by the ExplicitLocals pass. It has mayLoad because it reads from a wasm
303 // local, which is a side effect not otherwise modeled in LLVM.
304 let mayLoad = 1, isAsCheapAsAMove = 1 in
305 defm LOCAL_GET_#rc : I<(outs rc:$res), (ins local_op:$local),
306 (outs), (ins local_op:$local), [],
307 "local.get\t$res, $local", "local.get\t$local", 0x20>;
309 // This is the actual local.set instruction in wasm. These are made explicit
310 // by the ExplicitLocals pass. It has mayStore because it writes to a wasm
311 // local, which is a side effect not otherwise modeled in LLVM.
312 let mayStore = 1, isAsCheapAsAMove = 1 in
313 defm LOCAL_SET_#rc : I<(outs), (ins local_op:$local, rc:$src),
314 (outs), (ins local_op:$local), [],
315 "local.set\t$local, $src", "local.set\t$local", 0x21>;
317 // This is the actual local.tee instruction in wasm. TEEs are turned into
318 // LOCAL_TEEs by the ExplicitLocals pass. It has mayStore for the same reason
320 let mayStore = 1, isAsCheapAsAMove = 1 in
321 defm LOCAL_TEE_#rc : I<(outs rc:$res), (ins local_op:$local, rc:$src),
322 (outs), (ins local_op:$local), [],
323 "local.tee\t$res, $local, $src", "local.tee\t$local",
326 // Unused values must be dropped in some contexts.
327 defm DROP_#rc : I<(outs), (ins rc:$src), (outs), (ins), [],
328 "drop\t$src", "drop", 0x1a>;
331 defm GLOBAL_GET_#rc : I<(outs rc:$res), (ins global_op:$addr),
332 (outs), (ins global_op:$addr), [],
333 "global.get\t$res, $addr", "global.get\t$addr",
337 defm GLOBAL_SET_#rc : I<(outs), (ins global_op:$addr, rc:$src),
338 (outs), (ins global_op:$addr), [],
339 "global.set\t$addr, $src", "global.set\t$addr",
342 } // hasSideEffects = 0
343 foreach vt = rc.RegTypes in {
344 def : Pat<(vt (WebAssemblyglobal_get
345 (WebAssemblywrapper tglobaladdr:$addr))),
346 (!cast<NI>("GLOBAL_GET_" # rc) tglobaladdr:$addr)>;
347 def : Pat<(WebAssemblyglobal_set
348 vt:$src, (WebAssemblywrapper tglobaladdr:$addr)),
349 (!cast<NI>("GLOBAL_SET_" # rc) tglobaladdr:$addr, vt:$src)>;
350 def : Pat<(vt (WebAssemblylocal_get (i32 timm:$local))),
351 (!cast<NI>("LOCAL_GET_" # rc) timm:$local)>;
352 def : Pat<(WebAssemblylocal_set timm:$local, vt:$src),
353 (!cast<NI>("LOCAL_SET_" # rc) timm:$local, vt:$src)>;
356 defm "" : LOCAL<I32, global_op32>;
357 defm "" : LOCAL<I64, global_op64>; // 64-bit only needed for pointers.
358 defm "" : LOCAL<F32, global_op32>;
359 defm "" : LOCAL<F64, global_op32>;
360 defm "" : LOCAL<V128, global_op32>, Requires<[HasSIMD128]>;
361 defm "" : LOCAL<FUNCREF, global_op32>, Requires<[HasReferenceTypes]>;
362 defm "" : LOCAL<EXTERNREF, global_op32>, Requires<[HasReferenceTypes]>;
364 let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in {
365 defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm),
366 (outs), (ins i32imm_op:$imm),
367 [(set I32:$res, imm:$imm)],
368 "i32.const\t$res, $imm", "i32.const\t$imm", 0x41>;
369 defm CONST_I64 : I<(outs I64:$res), (ins i64imm_op:$imm),
370 (outs), (ins i64imm_op:$imm),
371 [(set I64:$res, imm:$imm)],
372 "i64.const\t$res, $imm", "i64.const\t$imm", 0x42>;
373 defm CONST_F32 : I<(outs F32:$res), (ins f32imm_op:$imm),
374 (outs), (ins f32imm_op:$imm),
375 [(set F32:$res, fpimm:$imm)],
376 "f32.const\t$res, $imm", "f32.const\t$imm", 0x43>;
377 defm CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm),
378 (outs), (ins f64imm_op:$imm),
379 [(set F64:$res, fpimm:$imm)],
380 "f64.const\t$res, $imm", "f64.const\t$imm", 0x44>;
381 } // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1
383 def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
384 (CONST_I32 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
385 def : Pat<(i64 (WebAssemblywrapper tglobaladdr:$addr)),
386 (CONST_I64 tglobaladdr:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
388 def : Pat<(i32 (WebAssemblywrapper tglobaladdr:$addr)),
389 (GLOBAL_GET_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
390 def : Pat<(i64 (WebAssemblywrapper tglobaladdr:$addr)),
391 (GLOBAL_GET_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>;
393 def : Pat<(i32 (WebAssemblywrapperPIC tglobaladdr:$addr)),
394 (CONST_I32 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr32]>;
395 def : Pat<(i64 (WebAssemblywrapperPIC tglobaladdr:$addr)),
396 (CONST_I64 tglobaladdr:$addr)>, Requires<[IsPIC, HasAddr64]>;
398 def : Pat<(i32 (WebAssemblywrapper tglobaltlsaddr:$addr)),
399 (CONST_I32 tglobaltlsaddr:$addr)>, Requires<[HasAddr32]>;
400 def : Pat<(i64 (WebAssemblywrapper tglobaltlsaddr:$addr)),
401 (CONST_I64 tglobaltlsaddr:$addr)>, Requires<[HasAddr64]>;
403 def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
404 (GLOBAL_GET_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
405 def : Pat<(i64 (WebAssemblywrapper texternalsym:$addr)),
406 (GLOBAL_GET_I64 texternalsym:$addr)>, Requires<[IsPIC, HasAddr64]>;
408 def : Pat<(i32 (WebAssemblywrapper texternalsym:$addr)),
409 (CONST_I32 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr32]>;
410 def : Pat<(i64 (WebAssemblywrapper texternalsym:$addr)),
411 (CONST_I64 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
413 def : Pat<(i32 (WebAssemblywrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
414 def : Pat<(i64 (WebAssemblywrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
416 //===----------------------------------------------------------------------===//
417 // Additional sets of instructions.
418 //===----------------------------------------------------------------------===//
420 include "WebAssemblyInstrMemory.td"
421 include "WebAssemblyInstrCall.td"
422 include "WebAssemblyInstrControl.td"
423 include "WebAssemblyInstrInteger.td"
424 include "WebAssemblyInstrConv.td"
425 include "WebAssemblyInstrFloat.td"
426 include "WebAssemblyInstrAtomics.td"
427 include "WebAssemblyInstrSIMD.td"
428 include "WebAssemblyInstrRef.td"
429 include "WebAssemblyInstrBulkMemory.td"
430 include "WebAssemblyInstrTable.td"