Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions src/interpreter/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ struct ExpressionInterpreter : OverriddenVisitor<ExpressionInterpreter, Flow> {
Flow visitArrayNewFixed(ArrayNewFixed* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayGet(ArrayGet* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArraySet(ArraySet* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayStore(ArrayStore* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayLen(ArrayLen* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayCopy(ArrayCopy* curr) { WASM_UNREACHABLE("TODO"); }
Flow visitArrayFill(ArrayFill* curr) { WASM_UNREACHABLE("TODO"); }
Expand Down
1 change: 1 addition & 0 deletions src/ir/ReFinalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ void ReFinalize::visitArrayNewElem(ArrayNewElem* curr) { curr->finalize(); }
void ReFinalize::visitArrayNewFixed(ArrayNewFixed* curr) { curr->finalize(); }
void ReFinalize::visitArrayGet(ArrayGet* curr) { curr->finalize(); }
void ReFinalize::visitArraySet(ArraySet* curr) { curr->finalize(); }
void ReFinalize::visitArrayStore(ArrayStore* curr) { curr->finalize(); }
void ReFinalize::visitArrayLen(ArrayLen* curr) { curr->finalize(); }
void ReFinalize::visitArrayCopy(ArrayCopy* curr) { curr->finalize(); }
void ReFinalize::visitArrayFill(ArrayFill* curr) { curr->finalize(); }
Expand Down
16 changes: 16 additions & 0 deletions src/ir/child-typer.h
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,22 @@ template<typename Subtype> struct ChildTyper : OverriddenVisitor<Subtype> {
note(&curr->value, type);
}

void visitArrayStore(ArrayStore* curr,
std::optional<HeapType> ht = std::nullopt) {
// TODO Figure out if this is correct. This is copied from visitArraySet.
if (!ht) {
if (!curr->ref->type.isRef()) {
self().noteUnknown();
return;
}
ht = curr->ref->type.getHeapType();
}
auto type = ht->getArray().element.type;
note(&curr->ref, Type(*ht, Nullable));
note(&curr->index, Type::i32);
note(&curr->value, type);
}

void visitArrayLen(ArrayLen* curr) {
note(&curr->ref, Type(HeapType::array, Nullable));
}
Expand Down
4 changes: 4 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -745,6 +745,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, CostType> {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->index) + visit(curr->value);
}
CostType visitArrayStore(ArrayStore* curr) {
return 2 + nullCheckCost(curr->ref) + visit(curr->ref) +
visit(curr->index) + visit(curr->value);
}
CostType visitArrayLen(ArrayLen* curr) {
return 1 + nullCheckCost(curr->ref) + visit(curr->ref);
}
Expand Down
9 changes: 9 additions & 0 deletions src/ir/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,15 @@ class EffectAnalyzer {
// traps when the arg is null or the index out of bounds
parent.implicitTrap = true;
}
void visitArrayStore(ArrayStore* curr) {
if (curr->ref->type.isNull()) {
parent.trap = true;
return;
}
parent.writesArray = true;
// traps when the arg is null or the index out of bounds
parent.implicitTrap = true;
}
void visitArrayLen(ArrayLen* curr) {
if (curr->ref->type.isNull()) {
parent.trap = true;
Expand Down
8 changes: 8 additions & 0 deletions src/ir/possible-contents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,13 @@ struct InfoCollector
addChildParentLink(curr->ref, curr);
addChildParentLink(curr->value, curr);
}
void visitArrayStore(ArrayStore* curr) {
if (curr->ref->type == Type::unreachable) {
return;
}
addChildParentLink(curr->ref, curr);
addChildParentLink(curr->value, curr);
}

void visitArrayLen(ArrayLen* curr) {
// TODO: optimize when possible (perhaps we can infer a Literal for the
Expand Down Expand Up @@ -1696,6 +1703,7 @@ void TNHOracle::scan(Function* func,
}
void visitArrayGet(ArrayGet* curr) { notePossibleTrap(curr->ref); }
void visitArraySet(ArraySet* curr) { notePossibleTrap(curr->ref); }
void visitArrayStore(ArrayStore* curr) { notePossibleTrap(curr->ref); }
void visitArrayLen(ArrayLen* curr) { notePossibleTrap(curr->ref); }
void visitArrayCopy(ArrayCopy* curr) {
notePossibleTrap(curr->srcRef);
Expand Down
7 changes: 7 additions & 0 deletions src/ir/subtype-exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,13 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
auto array = curr->ref->type.getHeapType().getArray();
self()->noteSubtype(curr->value, array.element.type);
}
void visitArrayStore(ArrayStore* curr) {
if (!curr->ref->type.isArray()) {
return;
}
auto array = curr->ref->type.getHeapType().getArray();
self()->noteSubtype(curr->value, array.element.type);
}
void visitArrayLen(ArrayLen* curr) {}
void visitArrayCopy(ArrayCopy* curr) {
if (!curr->srcRef->type.isArray() || !curr->destRef->type.isArray()) {
Expand Down
9 changes: 7 additions & 2 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,8 @@ struct NullInstrParserCtx {
int,
bool,
MemoryIdxT*,
MemargT) {
MemargT,
BackingType) {
return Ok{};
}
Result<> makeAtomicRMW(Index,
Expand Down Expand Up @@ -2245,7 +2246,11 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
int bytes,
bool isAtomic,
Name* mem,
Memarg memarg) {
Memarg memarg,
BackingType backingType) {
if (backingType == BackingType::Array) {
return withLoc(pos, irBuilder.makeArrayStore(bytes, type));
}
auto m = getMemory(pos, mem);
CHECK_ERR(m);
if (isAtomic) {
Expand Down
15 changes: 14 additions & 1 deletion src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,8 @@ Result<> makeLoad(Ctx& ctx,
bool signed_,
int bytes,
bool isAtomic) {
auto backing = backingType(ctx);
CHECK_ERR(backing);
auto mem = maybeMemidx(ctx);
CHECK_ERR(mem);
auto arg = memarg(ctx, bytes);
Expand All @@ -1752,12 +1754,14 @@ Result<> makeStore(Ctx& ctx,
Type type,
int bytes,
bool isAtomic) {
auto backing = backingType(ctx);
CHECK_ERR(backing);
auto mem = maybeMemidx(ctx);
CHECK_ERR(mem);
auto arg = memarg(ctx, bytes);
CHECK_ERR(arg);
return ctx.makeStore(
pos, annotations, type, bytes, isAtomic, mem.getPtr(), *arg);
pos, annotations, type, bytes, isAtomic, mem.getPtr(), *arg, *backing);
}

template<typename Ctx>
Expand Down Expand Up @@ -2853,6 +2857,15 @@ MaybeResult<typename Ctx::TableIdxT> maybeTableuse(Ctx& ctx) {
return *idx;
}

template<typename Ctx> Result<BackingType> backingType(Ctx& ctx) {
// TODO this should probably parse out the "type" and value separately, but
// for now this works for a prototype.
if (ctx.in.takeKeyword("type=array"sv)) {
return BackingType::Array;
}
return BackingType::Memory;
}

// memidx ::= x:u32 => x
// | v:id => x (if memories[x] = v)
template<typename Ctx>
Expand Down
42 changes: 27 additions & 15 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,25 @@ struct PrintExpressionContents
return parent.printBlockType(sig);
}

std::ostream& printStorePostfix(uint8_t bytes, Type valueType) {
if (bytes < 4 || (valueType == Type::i64 && bytes < 8)) {
if (bytes == 1) {
o << '8';
} else if (bytes == 2) {
if (valueType == Type::f32) {
o << "_f16";
} else {
o << "16";
}
} else if (bytes == 4) {
o << "32";
} else {
abort();
}
}
return o;
}

void visitBlock(Block* curr) {
printMedium(o, "block");
if (curr->name.is()) {
Expand Down Expand Up @@ -587,21 +606,7 @@ struct PrintExpressionContents
o << ".atomic";
}
o << ".store";
if (curr->bytes < 4 || (curr->valueType == Type::i64 && curr->bytes < 8)) {
if (curr->bytes == 1) {
o << '8';
} else if (curr->bytes == 2) {
if (curr->valueType == Type::f32) {
o << "_f16";
} else {
o << "16";
}
} else if (curr->bytes == 4) {
o << "32";
} else {
abort();
}
}
printStorePostfix(curr->bytes, curr->valueType);
restoreNormalColor(o);
printMemoryName(curr->memory, o, wasm);
if (curr->offset) {
Expand Down Expand Up @@ -2446,6 +2451,13 @@ struct PrintExpressionContents
printMemoryOrder(curr->order);
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArrayStore(ArrayStore* curr) {
prepareColor(o) << forceConcrete(curr->valueType);
o << ".store";
printStorePostfix(curr->bytes, curr->valueType);
restoreNormalColor(o);
o << " type=array";
}
void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); }
void visitArrayCopy(ArrayCopy* curr) {
printMedium(o, "array.copy ");
Expand Down
2 changes: 2 additions & 0 deletions src/passes/TypeGeneralizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,8 @@ struct TransferFn : OverriddenVisitor<TransferFn> {
}
}

void visitArrayStore(ArrayStore* curr) { WASM_UNREACHABLE("TODO"); }

void visitArrayLen(ArrayLen* curr) {
// The input must be an array.
push(Type(HeapType::array, Nullable));
Expand Down
4 changes: 3 additions & 1 deletion src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,9 @@ class WasmBinaryReader {
size_t inlineHintsLen = 0;
void readInlineHints(size_t payloadLen);

Index readMemoryAccess(Address& alignment, Address& offset);
Index
readMemoryAccess(Address& alignment, Address& offset, BackingType& backing);
std::tuple<Name, Address, Address, BackingType> getMemargWithBacking();
std::tuple<Name, Address, Address> getMemarg();
MemoryOrder getMemoryOrder(bool isRMW = false);

Expand Down
15 changes: 15 additions & 0 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,21 @@ class Builder {
ret->finalize();
return ret;
}
ArrayStore* makeArrayStore(unsigned bytes,
Type valueType,
Expression* ref,
Expression* index,
Expression* value) {
auto* ret = wasm.allocator.alloc<ArrayStore>();
ret->bytes = bytes;
ret->valueType = valueType;
ret->ref = ref;
ret->index = index;
ret->value = value;
// ret->order = order needed???
ret->finalize();
return ret;
}
ArrayLen* makeArrayLen(Expression* ref) {
auto* ret = wasm.allocator.alloc<ArrayLen>();
ret->ref = ref;
Expand Down
9 changes: 9 additions & 0 deletions src/wasm-delegations-fields.def
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,15 @@ DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArraySet, ref)
DELEGATE_FIELD_INT(ArraySet, order)
DELEGATE_FIELD_CASE_END(ArraySet)

DELEGATE_FIELD_CASE_START(ArrayStore)
DELEGATE_FIELD_CHILD(ArrayStore, value)
DELEGATE_FIELD_CHILD(ArrayStore, index)
DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayStore, ref)
DELEGATE_FIELD_INT(ArrayStore, bytes)
DELEGATE_FIELD_TYPE(ArrayStore, valueType)
DELEGATE_FIELD_INT(ArrayStore, order)
DELEGATE_FIELD_CASE_END(ArrayStore)

DELEGATE_FIELD_CASE_START(ArrayLen)
DELEGATE_FIELD_CHILD(ArrayLen, ref)
DELEGATE_FIELD_CASE_END(ArrayLen)
Expand Down
1 change: 1 addition & 0 deletions src/wasm-delegations.def
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ DELEGATE(ArrayNewElem);
DELEGATE(ArrayNewFixed);
DELEGATE(ArrayGet);
DELEGATE(ArraySet);
DELEGATE(ArrayStore);
DELEGATE(ArrayLen);
DELEGATE(ArrayCopy);
DELEGATE(ArrayFill);
Expand Down
55 changes: 55 additions & 0 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,15 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
return Literal(allocation);
}

// TODO find a better spot for this or see if a helper already exists.
template<typename T>
void writeBytes(T value, int numBytes, size_t index, Literals& values) {
for (int i = 0; i < numBytes; ++i) {
values[index + i] =
Literal(static_cast<int32_t>((value >> (i * 8)) & 0xff));
}
}

public:
// Indicates no limit of maxDepth or maxLoopIterations.
static const Index NO_LIMIT = 0;
Expand Down Expand Up @@ -2291,6 +2300,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
if (!data) {
trap("null ref");
}

Index i = index.getSingleValue().geti32();
if (i >= data->values.size()) {
trap("array oob");
Expand All @@ -2299,6 +2309,51 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
data->values[i] = truncateForPacking(value.getSingleValue(), field);
return Flow();
}
Flow visitArrayStore(ArrayStore* curr) {
VISIT(ref, curr->ref)
VISIT(index, curr->index)
VISIT(value, curr->value)
auto data = ref.getSingleValue().getGCData();
if (!data) {
trap("null ref");
}

Index i = index.getSingleValue().geti32();
size_t size = data->values.size();
// Use subtraction to avoid overflow.
if (i >= size || curr->bytes > (size - i)) {
trap("array oob");
}
switch (curr->valueType.getBasic()) {
case Type::i32:
writeBytes(
value.getSingleValue().geti32(), curr->bytes, i, data->values);
break;
case Type::i64:
writeBytes(
value.getSingleValue().geti64(), curr->bytes, i, data->values);
break;
case Type::f32:
writeBytes(value.getSingleValue().reinterpreti32(),
curr->bytes,
i,
data->values);
break;
case Type::f64:
writeBytes(value.getSingleValue().reinterpreti64(),
curr->bytes,
i,
data->values);
break;
case Type::v128:
// TODO
WASM_UNREACHABLE("todo");
case Type::none:
case Type::unreachable:
WASM_UNREACHABLE("unimp basic type");
}
return Flow();
}
Flow visitArrayLen(ArrayLen* curr) {
VISIT(ref, curr->ref)
auto data = ref.getSingleValue().getGCData();
Expand Down
7 changes: 7 additions & 0 deletions src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
Name mem);
Result<> makeStore(
unsigned bytes, Address offset, unsigned align, Type type, Name mem);
Result<> makeStore(BackingType backing,
unsigned bytes,
Address offset,
unsigned align,
Type type,
Name mem);
Result<> makeAtomicLoad(unsigned bytes, Address offset, Type type, Name mem);
Result<> makeAtomicStore(unsigned bytes, Address offset, Type type, Name mem);
Result<> makeAtomicRMW(
Expand Down Expand Up @@ -244,6 +250,7 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
Result<> makeArrayNewFixed(HeapType type, uint32_t arity);
Result<> makeArrayGet(HeapType type, bool signed_, MemoryOrder order);
Result<> makeArraySet(HeapType type, MemoryOrder order);
Result<> makeArrayStore(unsigned bytes, Type type);
Result<> makeArrayLen();
Result<> makeArrayCopy(HeapType destType, HeapType srcType);
Result<> makeArrayFill(HeapType type);
Expand Down
1 change: 1 addition & 0 deletions src/wasm-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class BinaryInstWriter : public OverriddenVisitor<BinaryInstWriter> {
size_t bytes,
uint64_t offset,
Name memory);
void emitStore(uint8_t bytes, Type ValueType);
int32_t getBreakIndex(Name name);

WasmBinaryWriter& parent;
Expand Down
Loading
Loading