WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 17)
WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 18)
WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)
+WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20)
def isVoid : ValueType<0 , 159>; // Produces no value
def untyped: ValueType<8 , 160>; // Produces an untyped value
def exnref : ValueType<0 , 161>; // WebAssembly's exnref type
+def funcref : ValueType<0 , 162>; // WebAssembly's funcref type
+def externref : ValueType<0 , 163>; // WebAssembly's externref type
+
def token : ValueType<0 , 248>; // TokenTy
def MetadataVT: ValueType<0, 249>; // Metadata
return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION;
}
+ bool isTypeTable() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE; }
+
bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; }
bool isTypeGlobal() const {
bool isValidEventIndex(uint32_t Index) const;
bool isDefinedEventIndex(uint32_t Index) const;
bool isValidFunctionSymbol(uint32_t Index) const;
+ bool isValidTableSymbol(uint32_t Index) const;
bool isValidGlobalSymbol(uint32_t Index) const;
bool isValidEventSymbol(uint32_t Index) const;
bool isValidDataSymbol(uint32_t Index) const;
// will be determined by the opcode.
exnref = 161, // WebAssembly's exnref type
+ funcref = 162, // WebAssembly's funcref type
+ externref = 163, // WebAssembly's externref type
FIRST_VALUETYPE = 1, // This is always the beginning of the list.
- LAST_VALUETYPE = 162, // This always remains at the end of the list.
+ LAST_VALUETYPE = 164, // This always remains at the end of the list.
// This is the current maximum for LAST_VALUETYPE.
// MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors
case v1024f32: return TypeSize::Fixed(32768);
case v2048i32:
case v2048f32: return TypeSize::Fixed(65536);
- case exnref: return TypeSize::Fixed(0); // opaque type
+ case exnref:
+ case funcref:
+ case externref: return TypeSize::Fixed(0); // opaque type
}
}
if (isFloatingPoint())
return "f" + utostr(getSizeInBits());
llvm_unreachable("Invalid EVT!");
- case MVT::bf16: return "bf16";
- case MVT::ppcf128: return "ppcf128";
- case MVT::isVoid: return "isVoid";
- case MVT::Other: return "ch";
- case MVT::Glue: return "glue";
- case MVT::x86mmx: return "x86mmx";
- case MVT::Metadata:return "Metadata";
- case MVT::Untyped: return "Untyped";
- case MVT::exnref : return "exnref";
+ case MVT::bf16: return "bf16";
+ case MVT::ppcf128: return "ppcf128";
+ case MVT::isVoid: return "isVoid";
+ case MVT::Other: return "ch";
+ case MVT::Glue: return "glue";
+ case MVT::x86mmx: return "x86mmx";
+ case MVT::Metadata: return "Metadata";
+ case MVT::Untyped: return "Untyped";
+ case MVT::exnref: return "exnref";
+ case MVT::funcref: return "funcref";
+ case MVT::externref: return "externref";
}
}
case wasm::R_WASM_GLOBAL_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
+ case wasm::R_WASM_TABLE_NUMBER_LEB:
// Provisional value is function/global/event Wasm index
assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
return WasmIndices[RelEntry.Symbol];
case wasm::R_WASM_GLOBAL_INDEX_LEB:
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_EVENT_INDEX_LEB:
+ case wasm::R_WASM_TABLE_NUMBER_LEB:
writePatchableLEB<5>(Stream, Value, Offset);
break;
case wasm::R_WASM_MEMORY_ADDR_LEB64:
case wasm::R_WASM_SECTION_OFFSET_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
+ case wasm::R_WASM_TABLE_NUMBER_LEB:
return true;
default:
return false;
case wasm::R_WASM_SECTION_OFFSET_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
+ case wasm::R_WASM_TABLE_NUMBER_LEB:
// For wasm section, its offset at 0 -- ignoring Value
return A;
default:
return make_error<GenericBinaryError>("Bad relocation function index",
object_error::parse_failed);
break;
+ case wasm::R_WASM_TABLE_NUMBER_LEB:
+ if (!isValidTableSymbol(Reloc.Index))
+ return make_error<GenericBinaryError>("Bad relocation table index",
+ object_error::parse_failed);
+ break;
case wasm::R_WASM_TYPE_INDEX_LEB:
if (Reloc.Index >= Signatures.size())
return make_error<GenericBinaryError>("Bad relocation type index",
return Index < Symbols.size() && Symbols[Index].isTypeFunction();
}
+bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeTable();
+}
+
bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
}
case WebAssembly::OPERAND_LOCAL:
case WebAssembly::OPERAND_GLOBAL:
case WebAssembly::OPERAND_FUNCTION32:
+ case WebAssembly::OPERAND_TABLE:
case WebAssembly::OPERAND_OFFSET32:
case WebAssembly::OPERAND_OFFSET64:
case WebAssembly::OPERAND_P2ALIGN:
PaddedSize = 10;
break;
case WebAssembly::OPERAND_FUNCTION32:
+ case WebAssembly::OPERAND_TABLE:
case WebAssembly::OPERAND_OFFSET32:
case WebAssembly::OPERAND_SIGNATURE:
case WebAssembly::OPERAND_TYPEINDEX:
OPERAND_EVENT,
/// A list of branch targets for br_list.
OPERAND_BRLIST,
+ /// 32-bit unsigned table number.
+ OPERAND_TABLE,
};
} // end namespace WebAssembly
return wasm::R_WASM_FUNCTION_INDEX_LEB;
if (SymA.isEvent())
return wasm::R_WASM_EVENT_INDEX_LEB;
+ if (SymA.isTable())
+ return wasm::R_WASM_TABLE_NUMBER_LEB;
return wasm::R_WASM_MEMORY_ADDR_LEB;
case WebAssembly::fixup_uleb128_i64:
assert(SymA.isData());
return WebAssembly::LOCAL_GET_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_GET_EXNREF;
+ if (RC == &WebAssembly::FUNCREFRegClass)
+ return WebAssembly::LOCAL_GET_FUNCREF;
+ if (RC == &WebAssembly::EXTERNREFRegClass)
+ return WebAssembly::LOCAL_GET_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
return WebAssembly::LOCAL_SET_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_SET_EXNREF;
+ if (RC == &WebAssembly::FUNCREFRegClass)
+ return WebAssembly::LOCAL_SET_FUNCREF;
+ if (RC == &WebAssembly::EXTERNREFRegClass)
+ return WebAssembly::LOCAL_SET_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
return WebAssembly::LOCAL_TEE_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_TEE_EXNREF;
+ if (RC == &WebAssembly::FUNCREFRegClass)
+ return WebAssembly::LOCAL_TEE_FUNCREF;
+ if (RC == &WebAssembly::EXTERNREFRegClass)
+ return WebAssembly::LOCAL_TEE_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
return MVT::v16i8;
if (RC == &WebAssembly::EXNREFRegClass)
return MVT::exnref;
+ if (RC == &WebAssembly::FUNCREFRegClass)
+ return MVT::funcref;
+ if (RC == &WebAssembly::EXTERNREFRegClass)
+ return MVT::externref;
llvm_unreachable("unrecognized register class");
}
case MVT::f32:
case MVT::f64:
case MVT::exnref:
+ case MVT::funcref:
+ case MVT::externref:
return VT;
case MVT::f16:
return MVT::f32;
case MVT::exnref:
ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
break;
+ case MVT::funcref:
+ ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
+ break;
+ case MVT::externref:
+ ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
+ break;
default:
return false;
}
let OperandType = "OPERAND_FUNCTION32" in
def function32_op : Operand<i32>;
+let OperandType = "OPERAND_TABLE" in
+def table32_op : Operand<i32>;
+
let OperandType = "OPERAND_OFFSET32" in
def offset32_op : Operand<i32>;
defm "": ARGUMENT<F32, f32>;
defm "": ARGUMENT<F64, f64>;
defm "": ARGUMENT<EXNREF, exnref>;
+defm "": ARGUMENT<FUNCREF, funcref>;
+defm "": ARGUMENT<EXTERNREF, externref>;
// local.get and local.set are not generated by instruction selection; they
// are implied by virtual register uses and defs.
defm "" : LOCAL<F64>;
defm "" : LOCAL<V128>, Requires<[HasSIMD128]>;
defm "" : LOCAL<EXNREF>, Requires<[HasExceptionHandling]>;
+defm "" : LOCAL<FUNCREF>, Requires<[HasReferenceTypes]>;
+defm "" : LOCAL<EXTERNREF>, Requires<[HasReferenceTypes]>;
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in {
defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm),
include "WebAssemblyInstrSIMD.td"
include "WebAssemblyInstrRef.td"
include "WebAssemblyInstrBulkMemory.td"
+include "WebAssemblyInstrTable.td"
--- /dev/null
+// WebAssemblyInstrTable.td - WebAssembly Table codegen support -*- tablegen -*-
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// WebAssembly Table operand code-gen constructs.
+/// Instructions that handle tables
+//===----------------------------------------------------------------------===//
+
+
+multiclass TABLE<WebAssemblyRegClass rt> {
+ defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table),
+ (outs), (ins table32_op:$table),
+ [],
+ "table.get\t$res, $table",
+ "table.get\t$table",
+ 0x25>;
+
+ defm TABLE_SET_#rt : I<(outs), (ins table32_op:$table, rt:$val, I32:$i),
+ (outs), (ins table32_op:$table),
+ [],
+ "table.set\t$table, $val, $i",
+ "table.set\t$table",
+ 0x26>;
+
+ defm TABLE_GROW_#rt : I<(outs I32:$sz), (ins table32_op:$table, I32:$n, rt:$val),
+ (outs), (ins table32_op:$table),
+ [],
+ "table.grow\t$sz, $table, $n, $val",
+ "table.grow\t$table",
+ 0xfc0f>;
+
+ defm TABLE_FILL_#rt : I<(outs), (ins table32_op:$table, I32:$n, rt:$val, I32:$i),
+ (outs), (ins table32_op:$table),
+ [],
+ "table.fill\t$table, $n, $val, $i",
+ "table.fill\t$table",
+ 0xfc11>;
+
+}
+
+defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
+defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
+
+defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
+ (outs), (ins table32_op:$table),
+ [],
+ "table.size\t$sz, $table",
+ "table.size\t$table",
+ 0xfc10>,
+ Requires<[HasReferenceTypes]>;
+
+
+defm TABLE_COPY : I<(outs), (ins table32_op:$table1, table32_op:$table2, I32:$n, I32:$s, I32:$d),
+ (outs), (ins table32_op:$table1, table32_op:$table2),
+ [],
+ "table.copy\t$table1, $table2, $n, $s, $d",
+ "table.copy\t$table1, $table2",
+ 0xfc0e>,
+ Requires<[HasReferenceTypes]>;
def V128_0: WebAssemblyReg<"%v128">;
def EXNREF_0 : WebAssemblyReg<"%exnref.0">;
+def FUNCREF_0 : WebAssemblyReg<"%funcref.0">;
+def EXTERNREF_0 : WebAssemblyReg<"%externref.0">;
// The value stack "register". This is an opaque entity which serves to order
// uses and defs that must remain in LIFO order.
def V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128,
(add V128_0)>;
def EXNREF : WebAssemblyRegClass<[exnref], 0, (add EXNREF_0)>;
+def FUNCREF : WebAssemblyRegClass<[funcref], 0, (add FUNCREF_0)>;
+def EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>;
-# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s
-# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck %s
+# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck -check-prefix=ENC %s
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
-# Test creating several empty tables
+# Creating several empty tables
-.tabletype foo, externref
+# CHECK: .tabletype foo, externref
+# CHECK: foo:
+ .tabletype foo, externref
foo:
+
+# CHECK: bar:
+# CHECK-NEXT: .tabletype bar, funcref
bar:
-.tabletype bar, funcref
+ .tabletype bar, funcref
-# CHECK: .tabletype foo, externref
-# CHECK: foo:
+table1:
+ .tabletype table1, funcref
+table2:
+ .tabletype table2, funcref
-# CHECK: bar:
-# CHECK-NEXT: .tabletype bar, funcref
+# Table instructions
+
+# CHECK: copy_tables:
+# CHECK-NEXT: .functype copy_tables (i32, i32) -> ()
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: local.get 1
+# CHECK: table.size table1
+# CHECK: table.copy table1, table2
+# CHECK-NEXT: end_function
+# CHECK-NEXT:.Ltmp0:
+# CHECK-NEXT: .size copy_tables, .Ltmp0-copy_tables
+copy_tables:
+ .functype copy_tables (i32, i32) -> ()
+ local.get 0
+ local.get 1
+
+ # ENC: table.size table1 # encoding: [0xfc,0x10,0x80'A',0x80'A',0x80'A',0x80'A',A]
+ table.size table1
+
+ # ENC: table.copy table1, table2 # encoding: [0xfc,0x0e,0x80'A',0x80'A',0x80'A',0x80'A',A,0x80'B',0x80'B',0x80'B',0x80'B',B]
+ table.copy table1, table2
+ end_function
+
+# CHECK: table_get:
+# CHECK-NEXT: .functype table_get (i32) -> (externref)
+# CHECK-NEXT: local.get 0
+# CHECK: table.get foo
+# CHECK-NEXT: end_function
+# CHECK-NEXT: .Ltmp1:
+# CHECK-NEXT: .size table_get, .Ltmp1-table_get
+table_get:
+ .functype table_get (i32) -> (externref)
+ local.get 0
+
+ # ENC: table.get foo # encoding: [0x25,0x80'A',0x80'A',0x80'A',0x80'A',A]
+ table.get foo
+ end_function
+
+# CHECK: table_set:
+# CHECK-NEXT: .functype table_set (i32, externref) -> ()
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: local.get 1
+# CHECK: table.set foo
+# CHECK-NEXT: end_function
+# CHECK-NEXT: .Ltmp2:
+# CHECK-NEXT: .size table_set, .Ltmp2-table_set
+table_set:
+ .functype table_set (i32, externref) -> ()
+ local.get 0
+ local.get 1
+
+ # ENC: table.set foo # encoding: [0x26,0x80'A',0x80'A',0x80'A',0x80'A',A]
+ table.set foo
+ end_function
+
+# CHECK: table_grow:
+# CHECK-NEXT: .functype table_grow (i32) -> (i32)
+# CHECK-NEXT: i32.const 0
+# CHECK-NEXT: table.get foo
+# CHECK-NEXT: local.get 0
+# CHECK: table.grow foo
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: i32.add
+# CHECK-NEXT: end_function
+# CHECK-NEXT: .Ltmp3:
+# CHECK-NEXT: .size table_grow, .Ltmp3-table_grow
+table_grow:
+ .functype table_grow (i32) -> (i32)
+ i32.const 0
+ table.get foo
+ local.get 0
+
+ # ENC: table.grow foo # encoding: [0xfc,0x0f,0x80'A',0x80'A',0x80'A',0x80'A',A]
+ table.grow foo
+ local.get 0
+ i32.add
+ end_function
+
+# CHECK: table_fill:
+# CHECK-NEXT: .functype table_fill (i32, i32) -> ()
+# CHECK-NEXT: local.get 0
+# CHECK-NEXT: i32.const 0
+# CHECK-NEXT: table.get table1
+# CHECK-NEXT: local.get 1
+# CHECK: table.fill table1
+# CHECK-NEXT: end_function
+# CHECK-NEXT: .Ltmp4:
+# CHECK-NEXT: .size table_fill, .Ltmp4-table_fill
+table_fill:
+ .functype table_fill (i32, i32) -> ()
+ local.get 0
+ i32.const 0
+ table.get table1
+ local.get 1
+
+ # ENC: table.fill table1 # encoding: [0xfc,0x11,0x80'A',0x80'A',0x80'A',0x80'A',A]
+ table.fill table1
+ end_function
# BIN: - Type: TABLE
# BIN-NEXT: Tables:
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x00000000
+# BIN: - Type: CODE
+# BIN-NEXT: Relocations:
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 2
+# BIN-NEXT: Offset: 0x00000009
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 2
+# BIN-NEXT: Offset: 0x00000010
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 3
+# BIN-NEXT: Offset: 0x00000015
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 0
+# BIN-NEXT: Offset: 0x00000020
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 0
+# BIN-NEXT: Offset: 0x0000002D
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 0
+# BIN-NEXT: Offset: 0x00000038
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 0
+# BIN-NEXT: Offset: 0x00000041
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 2
+# BIN-NEXT: Offset: 0x00000051
+# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT: Index: 2
+# BIN-NEXT: Offset: 0x0000005A
+# BIN-NEXT: Functions:
+# BIN-NEXT: - Index: 0
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 20002001FC108380808000FC0E838080800084808080000B
+# BIN-NEXT: - Index: 1
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 20002581808080000B
+# BIN-NEXT: - Index: 2
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 200020012681808080000B
+# BIN-NEXT: - Index: 3
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 41002581808080002000FC0F818080800020006A0B
+# BIN-NEXT: - Index: 4
+# BIN-NEXT: Locals: []
+# BIN-NEXT: Body: 200041002583808080002001FC1183808080000B
+
# BIN: - Type: CUSTOM
# BIN-NEXT: Name: linking
# BIN-NEXT: Version: 2
case MVT::nxv2bf16: return "MVT::nxv2bf16";
case MVT::nxv4bf16: return "MVT::nxv4bf16";
case MVT::nxv8bf16: return "MVT::nxv8bf16";
- case MVT::nxv1f32: return "MVT::nxv1f32";
- case MVT::nxv2f32: return "MVT::nxv2f32";
- case MVT::nxv4f32: return "MVT::nxv4f32";
- case MVT::nxv8f32: return "MVT::nxv8f32";
- case MVT::nxv16f32: return "MVT::nxv16f32";
- case MVT::nxv1f64: return "MVT::nxv1f64";
- case MVT::nxv2f64: return "MVT::nxv2f64";
- case MVT::nxv4f64: return "MVT::nxv4f64";
- case MVT::nxv8f64: return "MVT::nxv8f64";
- case MVT::token: return "MVT::token";
- case MVT::Metadata: return "MVT::Metadata";
- case MVT::iPTR: return "MVT::iPTR";
- case MVT::iPTRAny: return "MVT::iPTRAny";
- case MVT::Untyped: return "MVT::Untyped";
- case MVT::exnref: return "MVT::exnref";
+ case MVT::nxv1f32: return "MVT::nxv1f32";
+ case MVT::nxv2f32: return "MVT::nxv2f32";
+ case MVT::nxv4f32: return "MVT::nxv4f32";
+ case MVT::nxv8f32: return "MVT::nxv8f32";
+ case MVT::nxv16f32: return "MVT::nxv16f32";
+ case MVT::nxv1f64: return "MVT::nxv1f64";
+ case MVT::nxv2f64: return "MVT::nxv2f64";
+ case MVT::nxv4f64: return "MVT::nxv4f64";
+ case MVT::nxv8f64: return "MVT::nxv8f64";
+ case MVT::token: return "MVT::token";
+ case MVT::Metadata: return "MVT::Metadata";
+ case MVT::iPTR: return "MVT::iPTR";
+ case MVT::iPTRAny: return "MVT::iPTRAny";
+ case MVT::Untyped: return "MVT::Untyped";
+ case MVT::exnref: return "MVT::exnref";
+ case MVT::funcref: return "MVT::funcref";
+ case MVT::externref: return "MVT::externref";
default: llvm_unreachable("ILLEGAL VALUE TYPE!");
}
}