forked from kozorizki/binaryen
Add support for extended-const proposal (#4529)
See https://github.com/WebAssembly/extended-const
This commit is contained in:
parent
88c2e4377d
commit
d2f54b40e7
@ -252,6 +252,9 @@ BinaryenFeatures BinaryenFeatureTypedFunctionReferences(void) {
|
||||
BinaryenFeatures BinaryenFeatureRelaxedSIMD(void) {
|
||||
return static_cast<BinaryenFeatures>(FeatureSet::RelaxedSIMD);
|
||||
}
|
||||
BinaryenFeatures BinaryenFeatureExtendedConst(void) {
|
||||
return static_cast<BinaryenFeatures>(FeatureSet::ExtendedConst);
|
||||
}
|
||||
BinaryenFeatures BinaryenFeatureAll(void) {
|
||||
return static_cast<BinaryenFeatures>(FeatureSet::All);
|
||||
}
|
||||
|
@ -162,6 +162,7 @@ BINARYEN_API BinaryenFeatures BinaryenFeatureGC(void);
|
||||
BINARYEN_API BinaryenFeatures BinaryenFeatureMemory64(void);
|
||||
BINARYEN_API BinaryenFeatures BinaryenFeatureTypedFunctionReferences(void);
|
||||
BINARYEN_API BinaryenFeatures BinaryenFeatureRelaxedSIMD(void);
|
||||
BINARYEN_API BinaryenFeatures BinaryenFeatureExtendedConst(void);
|
||||
BINARYEN_API BinaryenFeatures BinaryenFeatureAll(void);
|
||||
|
||||
// Modules
|
||||
|
@ -53,20 +53,18 @@ getGlobalInitializedToImport(Module& wasm, Name module, Name base) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline bool canInitializeGlobal(Expression* curr) {
|
||||
inline bool canInitializeGlobal(Expression* curr, FeatureSet features) {
|
||||
if (auto* tuple = curr->dynCast<TupleMake>()) {
|
||||
for (auto* op : tuple->operands) {
|
||||
if (!canInitializeGlobal(op)) {
|
||||
if (!canInitializeGlobal(op, features)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (Properties::isSingleConstantExpression(curr) || curr->is<GlobalGet>() ||
|
||||
curr->is<RttCanon>() || curr->is<RttSub>() || curr->is<StructNew>() ||
|
||||
curr->is<ArrayNew>() || curr->is<ArrayInit>() || curr->is<I31New>()) {
|
||||
if (Properties::isValidInConstantExpression(curr, features)) {
|
||||
for (auto* child : ChildIterator(curr)) {
|
||||
if (!canInitializeGlobal(child)) {
|
||||
if (!canInitializeGlobal(child, features)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +414,26 @@ inline bool canEmitSelectWithArms(Expression* ifTrue, Expression* ifFalse) {
|
||||
//
|
||||
bool isGenerative(Expression* curr, FeatureSet features);
|
||||
|
||||
inline bool isValidInConstantExpression(Expression* expr, FeatureSet features) {
|
||||
if (isSingleConstantExpression(expr) || expr->is<GlobalGet>() ||
|
||||
expr->is<RttCanon>() || expr->is<RttSub>() || expr->is<StructNew>() ||
|
||||
expr->is<ArrayNew>() || expr->is<ArrayInit>() || expr->is<I31New>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (features.hasExtendedConst()) {
|
||||
if (expr->is<Binary>()) {
|
||||
auto bin = static_cast<Binary*>(expr);
|
||||
if (bin->op == AddInt64 || bin->op == SubInt64 || bin->op == MulInt64 ||
|
||||
bin->op == AddInt32 || bin->op == SubInt32 || bin->op == MulInt32) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace wasm::Properties
|
||||
|
||||
#endif // wasm_ir_properties_h
|
||||
|
@ -149,6 +149,7 @@ function initializeConstants() {
|
||||
'Memory64',
|
||||
'TypedFunctionReferences',
|
||||
'RelaxedSIMD',
|
||||
'ExtendedConst',
|
||||
'All'
|
||||
].forEach(name => {
|
||||
Module['Features'][name] = Module['_BinaryenFeature' + name]();
|
||||
|
@ -93,6 +93,7 @@ struct ToolOptions : public Options {
|
||||
"typed function references")
|
||||
.addFeature(FeatureSet::GCNNLocals, "GC non-null locals")
|
||||
.addFeature(FeatureSet::RelaxedSIMD, "relaxed SIMD")
|
||||
.addFeature(FeatureSet::ExtendedConst, "extended const expressions")
|
||||
.add("--no-validation",
|
||||
"-n",
|
||||
"Disables validation, assumes inputs are correct",
|
||||
|
@ -425,6 +425,7 @@ extern const char* GCFeature;
|
||||
extern const char* Memory64Feature;
|
||||
extern const char* TypedFunctionReferencesFeature;
|
||||
extern const char* RelaxedSIMDFeature;
|
||||
extern const char* ExtendedConstFeature;
|
||||
|
||||
enum Subsection {
|
||||
NameModule = 0,
|
||||
|
@ -42,7 +42,8 @@ struct FeatureSet {
|
||||
// TODO: Remove this feature when the wasm spec stabilizes.
|
||||
GCNNLocals = 1 << 13,
|
||||
RelaxedSIMD = 1 << 14,
|
||||
All = (1 << 15) - 1
|
||||
ExtendedConst = 1 << 15,
|
||||
All = (1 << 16) - 1
|
||||
};
|
||||
|
||||
static std::string toString(Feature f) {
|
||||
@ -77,6 +78,8 @@ struct FeatureSet {
|
||||
return "gc-nn-locals";
|
||||
case RelaxedSIMD:
|
||||
return "relaxed-simd";
|
||||
case ExtendedConst:
|
||||
return "extended-const";
|
||||
default:
|
||||
WASM_UNREACHABLE("unexpected feature");
|
||||
}
|
||||
@ -122,6 +125,7 @@ struct FeatureSet {
|
||||
}
|
||||
bool hasGCNNLocals() const { return (features & GCNNLocals) != 0; }
|
||||
bool hasRelaxedSIMD() const { return (features & RelaxedSIMD) != 0; }
|
||||
bool hasExtendedConst() const { return (features & ExtendedConst) != 0; }
|
||||
bool hasAll() const { return (features & All) != 0; }
|
||||
|
||||
void set(FeatureSet f, bool v = true) {
|
||||
@ -144,6 +148,7 @@ struct FeatureSet {
|
||||
}
|
||||
void setGCNNLocals(bool v = true) { set(GCNNLocals, v); }
|
||||
void setRelaxedSIMD(bool v = true) { set(RelaxedSIMD, v); }
|
||||
void setExtendedConst(bool v = true) { set(ExtendedConst, v); }
|
||||
void setMVP() { features = MVP; }
|
||||
void setAll() {
|
||||
// Do not set GCNNLocals, which forces the user to opt in to that feature
|
||||
|
@ -1084,6 +1084,8 @@ void WasmBinaryWriter::writeFeaturesSection() {
|
||||
return BinaryConsts::UserSections::TypedFunctionReferencesFeature;
|
||||
case FeatureSet::RelaxedSIMD:
|
||||
return BinaryConsts::UserSections::RelaxedSIMDFeature;
|
||||
case FeatureSet::ExtendedConst:
|
||||
return BinaryConsts::UserSections::ExtendedConstFeature;
|
||||
default:
|
||||
WASM_UNREACHABLE("unexpected feature flag");
|
||||
}
|
||||
@ -3350,6 +3352,8 @@ void WasmBinaryBuilder::readFeatures(size_t payloadLen) {
|
||||
feature = FeatureSet::TypedFunctionReferences;
|
||||
} else if (name == BinaryConsts::UserSections::RelaxedSIMDFeature) {
|
||||
feature = FeatureSet::RelaxedSIMD;
|
||||
} else if (name == BinaryConsts::UserSections::ExtendedConstFeature) {
|
||||
feature = FeatureSet::ExtendedConst;
|
||||
} else {
|
||||
// Silently ignore unknown features (this may be and old binaryen running
|
||||
// on a new wasm).
|
||||
|
@ -2767,13 +2767,21 @@ void FunctionValidator::visitFunction(Function* curr) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkSegmentOffset(Expression* curr, Address add, Address max) {
|
||||
if (curr->is<GlobalGet>()) {
|
||||
return true;
|
||||
static bool checkSegmentOffset(Expression* curr,
|
||||
Address add,
|
||||
Address max,
|
||||
FeatureSet features) {
|
||||
if (!Properties::isValidInConstantExpression(curr, features)) {
|
||||
return false;
|
||||
}
|
||||
auto* c = curr->dynCast<Const>();
|
||||
if (!c) {
|
||||
return false;
|
||||
// Unless the instruction is actually a const instruction, we don't
|
||||
// currently try to evaluate it.
|
||||
// TODO: Attempt to evaluate other expressions that might also be const
|
||||
// such as `global.get` or more complex instruction sequences involving
|
||||
// add/sub/mul/etc.
|
||||
return true;
|
||||
}
|
||||
uint64_t raw = c->value.getInteger();
|
||||
if (raw > std::numeric_limits<Address::address32_t>::max()) {
|
||||
@ -2999,9 +3007,10 @@ static void validateGlobals(Module& module, ValidationInfo& info) {
|
||||
info.shouldBeTrue(
|
||||
curr->init != nullptr, curr->name, "global init must be non-null");
|
||||
assert(curr->init);
|
||||
info.shouldBeTrue(GlobalUtils::canInitializeGlobal(curr->init),
|
||||
curr->name,
|
||||
"global init must be valid");
|
||||
info.shouldBeTrue(
|
||||
GlobalUtils::canInitializeGlobal(curr->init, module.features),
|
||||
curr->name,
|
||||
"global init must be valid");
|
||||
|
||||
if (!info.shouldBeSubType(curr->init->type,
|
||||
curr->type,
|
||||
@ -3066,7 +3075,8 @@ static void validateMemory(Module& module, ValidationInfo& info) {
|
||||
}
|
||||
info.shouldBeTrue(checkSegmentOffset(segment.offset,
|
||||
segment.data.size(),
|
||||
curr.initial * Memory::kPageSize),
|
||||
curr.initial * Memory::kPageSize,
|
||||
module.features),
|
||||
segment.offset,
|
||||
"memory segment offset should be reasonable");
|
||||
if (segment.offset->is<Const>()) {
|
||||
@ -3171,7 +3181,8 @@ static void validateTables(Module& module, ValidationInfo& info) {
|
||||
"element segment offset should be i32");
|
||||
info.shouldBeTrue(checkSegmentOffset(segment->offset,
|
||||
segment->data.size(),
|
||||
table->initial * Table::kPageSize),
|
||||
table->initial * Table::kPageSize,
|
||||
module.features),
|
||||
segment->offset,
|
||||
"table segment offset should be reasonable");
|
||||
if (module.features.hasTypedFunctionReferences()) {
|
||||
|
@ -49,6 +49,7 @@ const char* GCFeature = "gc";
|
||||
const char* Memory64Feature = "memory64";
|
||||
const char* TypedFunctionReferencesFeature = "typed-function-references";
|
||||
const char* RelaxedSIMDFeature = "relaxed-simd";
|
||||
const char* ExtendedConstFeature = "extended-const";
|
||||
} // namespace UserSections
|
||||
} // namespace BinaryConsts
|
||||
|
||||
|
@ -116,6 +116,7 @@ function test_features() {
|
||||
console.log("Features.Memory64: " + binaryen.Features.Memory64);
|
||||
console.log("Features.TypedFunctionReferences: " + binaryen.Features.TypedFunctionReferences);
|
||||
console.log("Features.RelaxedSIMD: " + binaryen.Features.RelaxedSIMD);
|
||||
console.log("Features.ExtendedConst: " + binaryen.Features.ExtendedConst);
|
||||
console.log("Features.All: " + binaryen.Features.All);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,8 @@ Features.GC: 1024
|
||||
Features.Memory64: 2048
|
||||
Features.TypedFunctionReferences: 4096
|
||||
Features.RelaxedSIMD: 16384
|
||||
Features.All: 32767
|
||||
Features.ExtendedConst: 32768
|
||||
Features.All: 65535
|
||||
InvalidId: 0
|
||||
BlockId: 1
|
||||
IfId: 2
|
||||
|
@ -303,6 +303,7 @@ void test_features() {
|
||||
printf("BinaryenFeatureTypedFunctionReferences: %d\n",
|
||||
BinaryenFeatureTypedFunctionReferences());
|
||||
printf("BinaryenFeatureRelaxedSIMD: %d\n", BinaryenFeatureRelaxedSIMD());
|
||||
printf("BinaryenFeatureExtendedConst: %d\n", BinaryenFeatureExtendedConst());
|
||||
printf("BinaryenFeatureAll: %d\n", BinaryenFeatureAll());
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,8 @@ BinaryenFeatureGC: 1024
|
||||
BinaryenFeatureMemory64: 2048
|
||||
BinaryenFeatureTypedFunctionReferences: 4096
|
||||
BinaryenFeatureRelaxedSIMD: 16384
|
||||
BinaryenFeatureAll: 32767
|
||||
BinaryenFeatureExtendedConst: 32768
|
||||
BinaryenFeatureAll: 65535
|
||||
(f32.neg
|
||||
(f32.const -33.61199951171875)
|
||||
)
|
||||
|
@ -100,6 +100,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -104,6 +104,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -93,6 +93,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -143,6 +143,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -141,6 +141,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -593,6 +593,12 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const
|
||||
;; CHECK-NEXT: expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const
|
||||
;; CHECK-NEXT: expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes
|
||||
;; CHECK-NEXT: inputs are correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -129,6 +129,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -187,6 +187,10 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes inputs are
|
||||
;; CHECK-NEXT: correct
|
||||
;; CHECK-NEXT:
|
||||
|
@ -555,6 +555,12 @@
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-relaxed-simd Disable relaxed SIMD
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --enable-extended-const Enable extended const
|
||||
;; CHECK-NEXT: expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --disable-extended-const Disable extended const
|
||||
;; CHECK-NEXT: expressions
|
||||
;; CHECK-NEXT:
|
||||
;; CHECK-NEXT: --no-validation,-n Disables validation, assumes
|
||||
;; CHECK-NEXT: inputs are correct
|
||||
;; CHECK-NEXT:
|
||||
|
24
test/lit/validation/extended-const.wast
Normal file
24
test/lit/validation/extended-const.wast
Normal file
@ -0,0 +1,24 @@
|
||||
;; Test that shared memory requires atomics
|
||||
|
||||
;; RUN: not wasm-opt %s 2>&1 | filecheck %s --check-prefix NO-EXTENDED
|
||||
;; RUN: wasm-opt %s --enable-extended-const -o - -S | filecheck %s --check-prefix EXTENDED
|
||||
|
||||
;; NO-EXTENDED: unexpected false: global init must be valid
|
||||
;; NO-EXTENDED: unexpected false: memory segment offset should be reasonable
|
||||
|
||||
;; EXTENDED: (import "env" "global" (global $gimport$0 i32))
|
||||
;; EXTENDED: (global $1 i32 (i32.add
|
||||
;; EXTENDED: (global.get $gimport$0)
|
||||
;; EXTENDED: (i32.const 42)
|
||||
;; EXTENDED: ))
|
||||
;; EXTENDED: (data (i32.sub
|
||||
;; EXTENDED: (global.get $gimport$0)
|
||||
;; EXTENDED: (i32.const 10)
|
||||
;; EXTENDED: ) "hello world")
|
||||
|
||||
(module
|
||||
(memory 1 1)
|
||||
(import "env" "global" (global i32))
|
||||
(global i32 (i32.add (global.get 0) (i32.const 42)))
|
||||
(data (i32.sub (global.get 0) (i32.const 10)) "hello world")
|
||||
)
|
@ -12,6 +12,7 @@
|
||||
--enable-memory64
|
||||
--enable-typed-function-references
|
||||
--enable-relaxed-simd
|
||||
--enable-extended-const
|
||||
(module
|
||||
(type $none_=>_v128_externref (func (result v128 externref)))
|
||||
(func $foo (result v128 externref)
|
||||
|
@ -397,4 +397,5 @@ class TargetFeaturesSectionTest(utils.BinaryenTestCase):
|
||||
'--enable-memory64',
|
||||
'--enable-typed-function-references',
|
||||
'--enable-relaxed-simd',
|
||||
'--enable-extended-const',
|
||||
], p2.stdout.splitlines())
|
||||
|
Loading…
x
Reference in New Issue
Block a user