Skip to content
Merged
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
3 changes: 2 additions & 1 deletion src/binaryen-c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1351,7 +1351,8 @@ BinaryenExpressionRef BinaryenAtomicLoad(BinaryenModuleRef module,
offset,
(Expression*)ptr,
Type(type),
getMemoryName(module, memoryName)));
getMemoryName(module, memoryName),
MemoryOrder::SeqCst));
}
BinaryenExpressionRef BinaryenAtomicStore(BinaryenModuleRef module,
uint32_t bytes,
Expand Down
10 changes: 6 additions & 4 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,8 @@ struct NullInstrParserCtx {
int,
bool,
MemoryIdxT*,
MemargT) {
MemargT,
MemoryOrder) {
return Ok{};
}
Result<> makeStore(Index,
Expand Down Expand Up @@ -2235,12 +2236,13 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx>, AnnotationParserCtx {
int bytes,
bool isAtomic,
Name* mem,
Memarg memarg) {
Memarg memarg,
MemoryOrder order) {
auto m = getMemory(pos, mem);
CHECK_ERR(m);
if (isAtomic) {
return withLoc(pos,
irBuilder.makeAtomicLoad(bytes, memarg.offset, type, *m));
return withLoc(
pos, irBuilder.makeAtomicLoad(bytes, memarg.offset, type, *m, order));
}
return withLoc(pos,
irBuilder.makeLoad(
Expand Down
37 changes: 35 additions & 2 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ template<typename Ctx> Result<typename Ctx::MemTypeT> memtype(Ctx&);
template<typename Ctx>
Result<typename Ctx::MemTypeT> memtypeContinued(Ctx&, Type addressType);
template<typename Ctx> Result<MemoryOrder> memorder(Ctx&);
template<typename Ctx> MaybeResult<MemoryOrder> maybeMemOrder(Ctx&);
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx&);
template<typename Ctx>
Result<typename Ctx::TableTypeT> tabletypeContinued(Ctx&, Type addressType);
Expand Down Expand Up @@ -860,6 +861,18 @@ template<typename Ctx> Result<MemoryOrder> memorder(Ctx& ctx) {
return MemoryOrder::SeqCst;
}

// memorder ::= 'seqcst' | 'acqrel'
template<typename Ctx> MaybeResult<MemoryOrder> maybeMemOrder(Ctx& ctx) {
if (ctx.in.takeKeyword("seqcst"sv)) {
return MemoryOrder::SeqCst;
}
if (ctx.in.takeKeyword("acqrel"sv)) {
return MemoryOrder::AcqRel;
}

return {};
}

// tabletype ::= (limits32 | 'i32' limits32 | 'i64' limit64) reftype
template<typename Ctx> Result<typename Ctx::TableTypeT> tabletype(Ctx& ctx) {
Type addressType = Type::i32;
Expand Down Expand Up @@ -1737,12 +1750,32 @@ Result<> makeLoad(Ctx& ctx,
bool signed_,
int bytes,
bool isAtomic) {

auto mem = maybeMemidx(ctx);
CHECK_ERR(mem);

// We could only parse this when `isAtomic`, but this way gives a clearer
// error since `memIdx` can never be mistaken for a `memOrder`.
auto maybeOrder = maybeMemOrder(ctx);
CHECK_ERR(maybeOrder);

if (maybeOrder && !isAtomic) {
return Err{"Memory ordering can only be provided for atomic loads."};
}

auto arg = memarg(ctx, bytes);
CHECK_ERR(arg);
return ctx.makeLoad(
pos, annotations, type, signed_, bytes, isAtomic, mem.getPtr(), *arg);
return ctx.makeLoad(pos,
annotations,
type,
signed_,
bytes,
isAtomic,
mem.getPtr(),
*arg,
maybeOrder ? *maybeOrder
: isAtomic ? MemoryOrder::SeqCst
: MemoryOrder::Unordered);
}

template<typename Ctx>
Expand Down
39 changes: 24 additions & 15 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ struct PrintExpressionContents
}
restoreNormalColor(o);
printMemoryName(curr->memory, o, wasm);
printMemoryOrder(curr->order);
if (curr->offset) {
o << " offset=" << curr->offset;
}
Expand Down Expand Up @@ -2323,6 +2324,7 @@ struct PrintExpressionContents
o << index;
}
}

void printMemoryOrder(MemoryOrder order) {
switch (order) {
// Unordered should have a different base instruction, so there is nothing
Expand All @@ -2332,10 +2334,11 @@ struct PrintExpressionContents
case MemoryOrder::SeqCst:
break;
case MemoryOrder::AcqRel:
o << "acqrel ";
o << " acqrel";
break;
}
}

void visitStructGet(StructGet* curr) {
auto heapType = curr->ref->type.getHeapType();
const auto& field = heapType.getStruct().fields[curr->index];
Expand All @@ -2345,25 +2348,27 @@ struct PrintExpressionContents
}
if (field.type == Type::i32 && field.packedType != Field::not_packed) {
if (curr->signed_) {
printMedium(o, ".get_s ");
printMedium(o, ".get_s");
} else {
printMedium(o, ".get_u ");
printMedium(o, ".get_u");
}
} else {
printMedium(o, ".get ");
printMedium(o, ".get");
}
printMemoryOrder(curr->order);
o << ' ';
printHeapTypeName(heapType);
o << ' ';
printFieldName(heapType, curr->index);
}
void visitStructSet(StructSet* curr) {
if (curr->order == MemoryOrder::Unordered) {
printMedium(o, "struct.set ");
printMedium(o, "struct.set");
} else {
printMedium(o, "struct.atomic.set ");
printMedium(o, "struct.atomic.set");
}
printMemoryOrder(curr->order);
o << ' ';
auto heapType = curr->ref->type.getHeapType();
printHeapTypeName(heapType);
o << ' ';
Expand All @@ -2374,20 +2379,21 @@ struct PrintExpressionContents
o << "struct.atomic.rmw.";
printAtomicRMWOp(curr->op);
restoreNormalColor(o);
o << ' ';
printMemoryOrder(curr->order);
printMemoryOrder(curr->order);
o << ' ';
auto heapType = curr->ref->type.getHeapType();
printHeapTypeName(heapType);
o << ' ';
printFieldName(heapType, curr->index);
}
void visitStructCmpxchg(StructCmpxchg* curr) {
prepareColor(o);
o << "struct.atomic.rmw.cmpxchg ";
o << "struct.atomic.rmw.cmpxchg";
restoreNormalColor(o);
printMemoryOrder(curr->order);
printMemoryOrder(curr->order);
o << ' ';
auto heapType = curr->ref->type.getHeapType();
printHeapTypeName(heapType);
o << ' ';
Expand Down Expand Up @@ -2430,23 +2436,25 @@ struct PrintExpressionContents
}
if (element.type == Type::i32 && element.packedType != Field::not_packed) {
if (curr->signed_) {
printMedium(o, ".get_s ");
printMedium(o, ".get_s");
} else {
printMedium(o, ".get_u ");
printMedium(o, ".get_u");
}
} else {
printMedium(o, ".get ");
printMedium(o, ".get");
}
printMemoryOrder(curr->order);
o << ' ';
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArraySet(ArraySet* curr) {
if (curr->order == MemoryOrder::Unordered) {
printMedium(o, "array.set ");
printMedium(o, "array.set");
} else {
printMedium(o, "array.atomic.set ");
printMedium(o, "array.atomic.set");
}
printMemoryOrder(curr->order);
o << ' ';
printHeapTypeName(curr->ref->type.getHeapType());
}
void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); }
Expand Down Expand Up @@ -2477,18 +2485,19 @@ struct PrintExpressionContents
o << "array.atomic.rmw.";
printAtomicRMWOp(curr->op);
restoreNormalColor(o);
o << ' ';
printMemoryOrder(curr->order);
printMemoryOrder(curr->order);
o << ' ';
auto heapType = curr->ref->type.getHeapType();
printHeapTypeName(heapType);
}
void visitArrayCmpxchg(ArrayCmpxchg* curr) {
prepareColor(o);
o << "array.atomic.rmw.cmpxchg ";
o << "array.atomic.rmw.cmpxchg";
restoreNormalColor(o);
printMemoryOrder(curr->order);
printMemoryOrder(curr->order);
o << ' ';
auto heapType = curr->ref->type.getHeapType();
printHeapTypeName(heapType);
}
Expand Down
38 changes: 25 additions & 13 deletions src/passes/SafeHeap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ir/import-utils.h"
#include "ir/load-utils.h"
#include "pass.h"
#include "support/string.h"
#include "wasm-builder.h"
#include "wasm.h"

Expand All @@ -37,18 +38,28 @@ static const Name SEGFAULT_IMPORT("segfault");
static const Name ALIGNFAULT_IMPORT("alignfault");

static Name getLoadName(Load* curr) {
std::string ret = "SAFE_HEAP_LOAD_";
ret += curr->type.toString();
ret += "_" + std::to_string(curr->bytes) + "_";
std::vector<std::string> parts{curr->type.toString(),
std::to_string(curr->bytes)};
if (LoadUtils::isSignRelevant(curr) && !curr->signed_) {
ret += "U_";
parts.push_back("U");
}
if (curr->isAtomic()) {
ret += "A";
} else {
ret += std::to_string(curr->align);

switch (curr->order) {
case MemoryOrder::Unordered: {
parts.push_back(std::to_string(curr->align));
break;
}
case MemoryOrder::SeqCst: {
parts.push_back("SC");
break;
}
case MemoryOrder::AcqRel: {
parts.push_back("AR");
break;
}
}
return ret;

return "SAFE_HEAP_LOAD_" + String::join(parts, "_");
}

static Name getStoreName(Store* curr) {
Expand Down Expand Up @@ -232,10 +243,11 @@ struct SafeHeap : public Pass {
if (align > bytes) {
continue;
}
for (auto isAtomic : {true, false}) {
load.order =
isAtomic ? MemoryOrder::SeqCst : MemoryOrder::Unordered;
if (isAtomic &&
for (auto memoryOrder : {MemoryOrder::Unordered,
MemoryOrder::AcqRel,
MemoryOrder::SeqCst}) {
load.order = memoryOrder;
if (load.isAtomic() &&
!isPossibleAtomicOperation(
align, bytes, module->memories[0]->shared, type)) {
continue;
Expand Down
17 changes: 17 additions & 0 deletions src/support/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ class Split : public std::vector<std::string> {
}
};

template<typename StringLike,
typename = std::enable_if_t<
std::is_convertible_v<StringLike, std::string_view>>>
std::string join(const std::vector<StringLike>& strs, std::string_view sep) {
if (strs.empty()) {
return "";
}

std::string ret = std::string(strs[0]);
for (size_t i = 1; i < strs.size(); i++) {
ret.append(sep);
ret.append(strs[i]);
}

return ret;
}

// Handles bracketing in a list initially split by ",", but the list may
// contain nested ","s. For example,
// void foo(int, double)
Expand Down
8 changes: 6 additions & 2 deletions src/tools/wasm-split/instrumenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,12 @@ void Instrumenter::addProfileExport(size_t numFuncs) {
getAddr(),
builder.makeBinary(
MulInt32, getFuncIdx(), builder.makeConst(uint32_t(4)))),
builder.makeAtomicLoad(
1, 0, getFuncIdx(), Type::i32, loadMemoryName),
builder.makeAtomicLoad(1,
0,
getFuncIdx(),
Type::i32,
loadMemoryName,
MemoryOrder::SeqCst),
Type::i32,
wasm->memories[0]->name),
builder.makeLocalSet(
Expand Down
8 changes: 7 additions & 1 deletion src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ enum BrOnCastFlag {

constexpr uint32_t ExactImport = 1 << 5;

constexpr uint32_t HasMemoryOrderMask = 1 << 5;
constexpr uint32_t HasMemoryIndexMask = 1 << 6;

enum EncodedType {
// value types
i32 = -0x1, // 0x7f
Expand Down Expand Up @@ -1728,7 +1731,10 @@ class WasmBinaryReader {
size_t inlineHintsLen = 0;
void readInlineHints(size_t payloadLen);

Index readMemoryAccess(Address& alignment, Address& offset);
std::tuple<Address, Address, Index, MemoryOrder>
readMemoryAccess(bool isAtomic, bool isRMW);
std::tuple<Name, Address, Address, MemoryOrder> getAtomicMemarg();
std::tuple<Name, Address, Address, MemoryOrder> getRMWMemarg();
std::tuple<Name, Address, Address> getMemarg();
MemoryOrder getMemoryOrder(bool isRMW = false);

Expand Down
13 changes: 10 additions & 3 deletions src/wasm-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,10 +384,17 @@ class Builder {
ret->finalize();
return ret;
}
Load* makeAtomicLoad(
unsigned bytes, Address offset, Expression* ptr, Type type, Name memory) {
Load* makeAtomicLoad(unsigned bytes,
Address offset,
Expression* ptr,
Type type,
Name memory,
MemoryOrder order) {
assert(order != MemoryOrder::Unordered &&
"Atomic loads can't be unordered");

Load* load = makeLoad(bytes, false, offset, bytes, ptr, type, memory);
load->order = MemoryOrder::SeqCst;
load->order = order;
return load;
}
AtomicWait* makeAtomicWait(Expression* ptr,
Expand Down
3 changes: 2 additions & 1 deletion src/wasm-ir-builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ class IRBuilder : public UnifiedExpressionVisitor<IRBuilder, Result<>> {
Name mem);
Result<> makeStore(
unsigned bytes, Address offset, unsigned align, Type type, Name mem);
Result<> makeAtomicLoad(unsigned bytes, Address offset, Type type, Name mem);
Result<> makeAtomicLoad(
unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order);
Result<> makeAtomicStore(unsigned bytes, Address offset, Type type, Name mem);
Result<> makeAtomicRMW(
AtomicRMWOp op, unsigned bytes, Address offset, Type type, Name mem);
Expand Down
Loading
Loading