Skip to content

Add new compound Signature, Struct and Array types #3012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 57 commits into from
Aug 24, 2020
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
927bd6d
Refactor types to represent arbitrary complex types
dcodeIO Aug 1, 2020
e84664f
fix
dcodeIO Aug 1, 2020
185f887
fix
dcodeIO Aug 1, 2020
415353f
I know nothing
dcodeIO Aug 1, 2020
941bde4
layers
dcodeIO Aug 1, 2020
37eb81f
unify printing
dcodeIO Aug 1, 2020
f4067bd
tuple terminology, Tuple::toString via wrapping
dcodeIO Aug 2, 2020
5146da2
make nullable a conditional property of specific TypeDefs
dcodeIO Aug 2, 2020
7299028
remove now unused function parameters
dcodeIO Aug 2, 2020
a8dce05
move 'null' to TypeDef when printing
dcodeIO Aug 2, 2020
e006f21
ValueType -> ID, efficient lookups
dcodeIO Aug 2, 2020
a41c3d5
Extract kind
tlively Aug 3, 2020
2764af7
rename Type::ID to Type::BasicID
dcodeIO Aug 3, 2020
8e159d1
rename ID -> BasicID in other comments
dcodeIO Aug 3, 2020
f1a25a4
avoid using default cases
dcodeIO Aug 3, 2020
1e901fc
Merge remote-tracking branch 'tlively/dcodeIO-gc-extract-kind' into g…
dcodeIO Aug 3, 2020
34c2b55
fix, remove getKind
dcodeIO Aug 3, 2020
b4ffb98
pass Signature by value
dcodeIO Aug 3, 2020
12183ec
packed field types
dcodeIO Aug 4, 2020
e2f3281
copy assignment for TupleDef
dcodeIO Aug 4, 2020
fbb0897
remove unnecessary Field constructor
dcodeIO Aug 4, 2020
cda1056
add isNullable predicate
dcodeIO Aug 4, 2020
5ba1afc
use Type instead of BasicID in isPacked check
dcodeIO Aug 4, 2020
8bf1906
document TypeDefs of lists of a single type
dcodeIO Aug 4, 2020
eb11e41
fix copy assignment as suggested
dcodeIO Aug 4, 2020
3761ed5
revert separate printing of Field::PackedType
dcodeIO Aug 4, 2020
7da7012
simplify TypeDef copy assignment
dcodeIO Aug 5, 2020
c2cf485
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 15, 2020
06cb1a3
use wasm::hash
dcodeIO Aug 15, 2020
dac491d
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 17, 2020
656f0a3
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 17, 2020
adb4332
drop extra Tuple wrapper, clarify nested Ref concept
dcodeIO Aug 18, 2020
7e46013
Update src/wasm-type.h
dcodeIO Aug 18, 2020
8aa4b5d
Update src/wasm-type.h
dcodeIO Aug 18, 2020
4ed19aa
Update src/wasm-type.h
dcodeIO Aug 18, 2020
fc05734
Update src/wasm/wasm-type.cpp
dcodeIO Aug 18, 2020
94e2f61
Update src/wasm/wasm-type.cpp
dcodeIO Aug 18, 2020
959aba1
Update src/wasm/wasm-type.cpp
dcodeIO Aug 18, 2020
e7eeb50
add getDef for readability, remove PackedType storage type
dcodeIO Aug 18, 2020
b72890c
fix
dcodeIO Aug 18, 2020
a9affcf
keep getDef internal as suggested
dcodeIO Aug 18, 2020
40f3a1a
move TypeDef definition to wasm-type.cpp
dcodeIO Aug 18, 2020
accd33d
initial test
dcodeIO Aug 18, 2020
d92e416
parens it is
dcodeIO Aug 18, 2020
e8e111d
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 20, 2020
9517da1
Update src/wasm-type.h
dcodeIO Aug 20, 2020
c20b61f
add an assert
dcodeIO Aug 20, 2020
f6b9f83
revert Tuple move constructor until expert feedback
dcodeIO Aug 20, 2020
0de9d01
remove unnecessary this reference
dcodeIO Aug 20, 2020
0cdc596
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 20, 2020
85fb78f
move remains of TypeDef to wasm-type.cpp, rename to TypeInfo and impl…
dcodeIO Aug 21, 2020
cecf38a
apply dangerous half-knowledge
dcodeIO Aug 21, 2020
fa620d9
interesting tests
dcodeIO Aug 21, 2020
9d206af
revert dangerous half-knowledge
dcodeIO Aug 23, 2020
b8d6faf
Update src/wasm-type.h
dcodeIO Aug 24, 2020
fd81477
Update src/wasm-type.h
dcodeIO Aug 24, 2020
5d617c9
Merge branch 'master' into gc-type-refactor
dcodeIO Aug 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/asmjs/asm_v_wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ std::string getSig(Function* func) {
}

std::string getSig(Type results, Type params) {
assert(!results.isMulti());
assert(!results.isTuple());
std::string sig;
sig += getSig(results);
for (Type t : params.expand()) {
Expand Down
2 changes: 1 addition & 1 deletion src/ir/module-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ collectSignatures(Module& wasm,
counts[call->sig]++;
} else if (Properties::isControlFlowStructure(curr)) {
// TODO: Allow control flow to have input types as well
if (curr->type.isMulti()) {
if (curr->type.isTuple()) {
counts[Signature(Type::none, curr->type)]++;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ struct SExprType {

static std::ostream& operator<<(std::ostream& o, const SExprType& localType) {
Type type = localType.type;
if (type.isMulti()) {
if (type.isTuple()) {
const std::vector<Type>& types = type.expand();
o << '(' << types[0];
for (size_t i = 1; i < types.size(); ++i) {
Expand Down
2 changes: 1 addition & 1 deletion src/passes/RemoveUnusedBrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
// be further optimizable, and if select does not branch we also
// avoid one branch.
// Multivalue selects are not supported
if (br->value && br->value->type.isMulti()) {
if (br->value && br->value->type.isTuple()) {
return;
}
// If running the br's condition unconditionally is too expensive,
Expand Down
14 changes: 7 additions & 7 deletions src/tools/fuzzing.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ class TranslateToFuzzReader {
double getDouble() { return Literal(get64()).reinterpretf64(); }

Type getSubType(Type type) {
if (type.isMulti()) {
if (type.isTuple()) {
std::vector<Type> types;
for (auto t : type.expand()) {
types.push_back(getSubType(t));
Expand Down Expand Up @@ -850,7 +850,7 @@ class TranslateToFuzzReader {

Expression* _makeConcrete(Type type) {
bool canMakeControlFlow =
!type.isMulti() || wasm.features.has(FeatureSet::Multivalue);
!type.isTuple() || wasm.features.has(FeatureSet::Multivalue);
using Self = TranslateToFuzzReader;
FeatureOptions<Expression* (Self::*)(Type)> options;
using WeightedOption = decltype(options)::WeightedOption;
Expand Down Expand Up @@ -886,7 +886,7 @@ class TranslateToFuzzReader {
if (type == Type::i32) {
options.add(FeatureSet::ReferenceTypes, &Self::makeRefIsNull);
}
if (type.isMulti()) {
if (type.isTuple()) {
options.add(FeatureSet::Multivalue, &Self::makeTupleMake);
}
return (this->*pick(options))(type);
Expand Down Expand Up @@ -1265,7 +1265,7 @@ class TranslateToFuzzReader {

Expression* makeTupleMake(Type type) {
assert(wasm.features.hasMultivalue());
assert(type.isMulti());
assert(type.isTuple());
std::vector<Expression*> elements;
for (auto t : type.expand()) {
elements.push_back(make(t));
Expand Down Expand Up @@ -1764,7 +1764,7 @@ class TranslateToFuzzReader {
}
return builder.makeRefNull();
}
if (type.isMulti()) {
if (type.isTuple()) {
std::vector<Expression*> operands;
for (auto t : type.expand()) {
operands.push_back(makeConst(t));
Expand All @@ -1782,7 +1782,7 @@ class TranslateToFuzzReader {
}

Expression* makeUnary(Type type) {
assert(!type.isMulti());
assert(!type.isTuple());
if (type == Type::unreachable) {
if (auto* unary = makeUnary(getSingleConcreteType())->dynCast<Unary>()) {
return builder.makeUnary(unary->op, make(Type::unreachable));
Expand Down Expand Up @@ -2003,7 +2003,7 @@ class TranslateToFuzzReader {
}

Expression* makeBinary(Type type) {
assert(!type.isMulti());
assert(!type.isTuple());
if (type == Type::unreachable) {
if (auto* binary =
makeBinary(getSingleConcreteType())->dynCast<Binary>()) {
Expand Down
2 changes: 1 addition & 1 deletion src/tools/wasm-reduce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,7 @@ struct Reducer
RefNull* n = builder->makeRefNull();
return tryToReplaceCurrent(n);
}
if (curr->type.isMulti()) {
if (curr->type.isTuple()) {
Expression* n =
builder->makeConstantExpression(Literal::makeZero(curr->type));
return tryToReplaceCurrent(n);
Expand Down
2 changes: 1 addition & 1 deletion src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ class Builder {
// minimal contents. as a replacement, this may reuse the
// input node
template<typename T> Expression* replaceWithIdenticalType(T* curr) {
if (curr->type.isMulti()) {
if (curr->type.isTuple()) {
return makeConstantExpression(Literal::makeZero(curr->type));
}
Literal value;
Expand Down
167 changes: 127 additions & 40 deletions src/wasm-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,29 @@
// Signature, Struct and Array types that will be single but not basic. To
// prepare for this change, the following macro marks affected code locations.
#define TODO_SINGLE_COMPOUND(type) \
assert(!type.isMulti() && "Unexpected multi-value type"); \
assert(!type.isTuple() && "Unexpected tuple type"); \
assert(!type.isCompound() && "TODO: handle compound types");

namespace wasm {

class Type;
struct TypeDef;
struct Tuple;
struct Signature;
struct Struct;
struct Array;

typedef std::vector<Type> TypeList;

class Type {
// The `id` uniquely represents each type, so type equality is just a
// comparison of the ids. For basic types the `id` is just the `ValueType`
// comparison of the ids. For basic types the `id` is just the `BasicID`
// enum value below, and for constructed types the `id` is the address of the
// canonical representation of the type, making lookups cheap for all types.
uintptr_t id;
void init(const std::vector<Type>&);

public:
enum ValueType : uint32_t {
enum BasicID : uint32_t {
none,
unreachable,
i32,
Expand All @@ -52,24 +60,35 @@ class Type {
externref,
nullref,
exnref,
_last_value_type = exnref
_last_basic_id = exnref
};

Type() = default;

// ValueType can be implicitly upgraded to Type
constexpr Type(ValueType id) : id(id){};
// BasicID can be implicitly upgraded to Type
constexpr Type(BasicID id) : id(id){};

// But converting raw uint32_t is more dangerous, so make it explicit
explicit Type(uint64_t id) : id(id){};

// Construct from lists of elementary types
Type(std::initializer_list<Type> types);
explicit Type(const std::vector<Type>& types);
// Construct tuple from a list of single types
Type(std::initializer_list<Type>);

// Construct from tuple description
explicit Type(const Tuple&);

// Construct from signature description
explicit Type(const Signature, bool nullable);

// Construct from struct description
explicit Type(const Struct&, bool nullable);

// Construct from array description
explicit Type(const Array&, bool nullable);

// Accessors
size_t size() const;
const std::vector<Type>& expand() const;
const TypeList& expand() const;

// Predicates
// Compound Concrete
Expand All @@ -89,30 +108,22 @@ class Type {
// │ nullref ║ x │ │ x │ x │ │ │
// │ exnref ║ x │ │ x │ x │ │ │
// ├─────────────╫───┼───┼───┼───┤───────┤ │
// │ Signature ║ │ x │ x │ x │ f │ │
// │ Struct ║ │ x │ x │ x │ │ │ │ TODO (GC)
// │ Array ║ │ x │ x │ x │ │ ┘
// │ Multi ║ │ x │ │ x │ │
// │ Signature ║ │ x │ x │ x │ f │ │
// │ Struct ║ │ x │ x │ x │ │ │
// │ Array ║ │ x │ x │ x │ │ ┘
// │ Tuple ║ │ x │ │ x │ │
// └─────────────╨───┴───┴───┴───┴───────┘
constexpr bool isBasic() const { return id <= _last_value_type; }
constexpr bool isCompound() const { return id > _last_value_type; }
constexpr bool isSingle() const {
// TODO: Compound types Signature, Struct and Array are single
return id >= i32 && id <= _last_value_type;
}
constexpr bool isMulti() const {
// TODO: Compound types Signature, Struct and Array are not multi
return id > _last_value_type;
}
constexpr bool isBasic() const { return id <= _last_basic_id; }
constexpr bool isCompound() const { return id > _last_basic_id; }
constexpr bool isConcrete() const { return id >= i32; }
constexpr bool isInteger() const { return id == i32 || id == i64; }
constexpr bool isFloat() const { return id == f32 || id == f64; }
constexpr bool isVector() const { return id == v128; };
constexpr bool isNumber() const { return id >= i32 && id <= v128; }
constexpr bool isRef() const {
// TODO: Compound types Signature, Struct and Array are ref
return id >= funcref && id <= exnref;
}
bool isTuple() const;
bool isSingle() const { return isConcrete() && !isTuple(); }
bool isRef() const;
bool isNullable() const;

private:
template<bool (Type::*pred)() const> bool hasPredicate() {
Expand All @@ -129,18 +140,18 @@ class Type {
bool hasRef() { return hasPredicate<&Type::isRef>(); }

constexpr uint64_t getID() const { return id; }
constexpr ValueType getBasic() const {
constexpr BasicID getBasic() const {
assert(isBasic() && "Basic type expected");
return static_cast<ValueType>(id);
return static_cast<BasicID>(id);
}

// (In)equality must be defined for both Type and ValueType because it is
// (In)equality must be defined for both Type and BasicID because it is
// otherwise ambiguous whether to convert both this and other to int or
// convert other to Type.
bool operator==(const Type& other) const { return id == other.id; }
bool operator==(const ValueType& other) const { return id == other; }
bool operator==(const BasicID& other) const { return id == other; }
bool operator!=(const Type& other) const { return id != other.id; }
bool operator!=(const ValueType& other) const { return id != other; }
bool operator!=(const BasicID& other) const { return id != other; }

// Order types by some notion of simplicity
bool operator<(const Type& other) const;
Expand Down Expand Up @@ -193,6 +204,16 @@ struct ResultType {
std::string toString() const;
};

struct Tuple {
TypeList types;
Tuple() : types() {}
Tuple(std::initializer_list<Type> types) : types(types) {}
Tuple(TypeList types) : types(types) {}
bool operator==(const Tuple& other) const { return types == other.types; }
bool operator!=(const Tuple& other) const { return !(*this == other); }
std::string toString() const;
};

struct Signature {
Type params;
Type results;
Expand All @@ -203,25 +224,91 @@ struct Signature {
}
bool operator!=(const Signature& other) const { return !(*this == other); }
bool operator<(const Signature& other) const;
std::string toString() const;
};

std::ostream& operator<<(std::ostream& os, Type t);
std::ostream& operator<<(std::ostream& os, ParamType t);
std::ostream& operator<<(std::ostream& os, ResultType t);
std::ostream& operator<<(std::ostream& os, Signature t);
struct Field {
Type type;
enum PackedType {
not_packed,
i8,
i16,
} packedType; // applicable iff type=i32
bool mutable_;

Field(Type type, bool mutable_ = false)
: type(type), packedType(not_packed), mutable_(mutable_) {}
Field(PackedType packedType, bool mutable_ = false)
: type(Type::i32), packedType(packedType), mutable_(mutable_) {}

constexpr bool isPacked() const {
if (packedType != not_packed) {
assert(type == Type::i32 && "unexpected type");
return true;
}
return false;
}

bool operator==(const Field& other) const {
return type == other.type && packedType == other.packedType &&
mutable_ == other.mutable_;
}
bool operator!=(const Field& other) const { return !(*this == other); }
std::string toString() const;
};

typedef std::vector<Field> FieldList;

struct Struct {
FieldList fields;
Struct(const Struct& other) : fields(other.fields) {}
Struct(FieldList fields) : fields(fields) {}
bool operator==(const Struct& other) const { return fields == other.fields; }
bool operator!=(const Struct& other) const { return !(*this == other); }
std::string toString() const;
};

struct Array {
Field element;
Array(const Array& other) : element(other.element) {}
Array(Field element) : element(element) {}
bool operator==(const Array& other) const { return element == other.element; }
bool operator!=(const Array& other) const { return !(*this == other); }
std::string toString() const;
};

std::ostream& operator<<(std::ostream&, Type);
std::ostream& operator<<(std::ostream&, ParamType);
std::ostream& operator<<(std::ostream&, ResultType);
std::ostream& operator<<(std::ostream&, Tuple);
std::ostream& operator<<(std::ostream&, Signature);
std::ostream& operator<<(std::ostream&, Field);
std::ostream& operator<<(std::ostream&, Struct);
std::ostream& operator<<(std::ostream&, Array);
std::ostream& operator<<(std::ostream&, TypeDef);

} // namespace wasm

namespace std {

template<> class hash<wasm::Type> {
public:
size_t operator()(const wasm::Type& type) const;
size_t operator()(const wasm::Type&) const;
};

template<> class hash<wasm::Signature> {
public:
size_t operator()(const wasm::Signature& sig) const;
size_t operator()(const wasm::Signature&) const;
};

template<> class hash<wasm::Field> {
public:
size_t operator()(const wasm::Field&) const;
};

template<> class hash<wasm::TypeDef> {
public:
size_t operator()(const wasm::TypeDef&) const;
};

} // namespace std
Expand Down
3 changes: 1 addition & 2 deletions src/wasm/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1435,8 +1435,7 @@ Literal Literal::shuffleV8x16(const Literal& other,
return Literal(bytes);
}

template<Type::ValueType Ty, int Lanes>
static Literal splat(const Literal& val) {
template<Type::BasicID Ty, int Lanes> static Literal splat(const Literal& val) {
assert(val.type == Ty);
LaneArray<Lanes> lanes;
lanes.fill(val);
Expand Down
Loading