Skip to content

Commit

Permalink
Jit: Threads: Add Fence, Wait, and Notify
Browse files Browse the repository at this point in the history
Add a few test cases with non-zero offsets

Signed-off-by: Máté Tokodi [email protected]
  • Loading branch information
matetokodi committed Sep 13, 2024
1 parent 01f5ac2 commit 815c9b5
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 65 deletions.
1 change: 1 addition & 0 deletions .github/workflows/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ jobs:
- name: Run Tests
run: |
$RUNNER --engine="$GITHUB_WORKSPACE/out/extended/walrus" wasm-test-extended
$RUNNER --jit --engine="$GITHUB_WORKSPACE/out/extended/walrus" wasm-test-extended
build-test-performance:
runs-on: ubuntu-latest
Expand Down
111 changes: 52 additions & 59 deletions src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ class FunctionType;
#define FOR_EACH_BYTECODE_ATOMIC_OTHER(F) \
F(MemoryAtomicNotify) \
F(MemoryAtomicWait32) \
F(MemoryAtomicWait64)
F(MemoryAtomicWait64) \
F(AtomicFence)
#else // Extended Features
#define FOR_EACH_BYTECODE_ATOMIC_LOAD_OP(F)
#define FOR_EACH_BYTECODE_ATOMIC_STORE_OP(F)
Expand Down Expand Up @@ -827,6 +828,33 @@ class Const128 : public ByteCode {
uint32_t m_value[4];
};

// dummy ByteCode for 3-input 1-output operation with offset
class TernaryOperationOffset : public ByteCode {
public:
TernaryOperationOffset(Opcode opcode, uint32_t offset, ByteCodeStackOffset src0, ByteCodeStackOffset src1, ByteCodeStackOffset src2, ByteCodeStackOffset dst)
: ByteCode(opcode)
, m_offset(offset)
, m_src0Offset(src0)
, m_src1Offset(src1)
, m_src2Offset(src2)
, m_dstOffset(dst)
{
}

uint32_t offset() const { return m_offset; }
ByteCodeStackOffset src0Offset() const { return m_src0Offset; }
ByteCodeStackOffset src1Offset() const { return m_src1Offset; }
ByteCodeStackOffset src2Offset() const { return m_src2Offset; }
ByteCodeStackOffset dstOffset() const { return m_dstOffset; }

protected:
uint32_t m_offset;
ByteCodeStackOffset m_src0Offset;
ByteCodeStackOffset m_src1Offset;
ByteCodeStackOffset m_src2Offset;
ByteCodeStackOffset m_dstOffset;
};

// dummy ByteCode for binary operation
class BinaryOperation : public ByteCodeOffset3 {
public:
Expand Down Expand Up @@ -1741,99 +1769,48 @@ class AtomicRmw : public ByteCode {
ByteCodeStackOffset m_dstOffset;
};

class AtomicRmwCmpxchg : public ByteCode {
class AtomicRmwCmpxchg : public TernaryOperationOffset {
public:
AtomicRmwCmpxchg(Opcode opcode, uint32_t offset, ByteCodeStackOffset src0, ByteCodeStackOffset src1, ByteCodeStackOffset src2, ByteCodeStackOffset dst)
: ByteCode(opcode)
, m_offset(offset)
, m_src0Offset(src0)
, m_src1Offset(src1)
, m_src2Offset(src2)
, m_dstOffset(dst)
: TernaryOperationOffset(opcode, offset, src0, src1, src2, dst)

{
}

uint32_t offset() const { return m_offset; }
ByteCodeStackOffset src0Offset() const { return m_src0Offset; }
ByteCodeStackOffset src1Offset() const { return m_src1Offset; }
ByteCodeStackOffset src2Offset() const { return m_src2Offset; }
ByteCodeStackOffset dstOffset() const { return m_dstOffset; }

#if !defined(NDEBUG)
void dump(size_t pos)
{
}
#endif
protected:
uint32_t m_offset;
ByteCodeStackOffset m_src0Offset;
ByteCodeStackOffset m_src1Offset;
ByteCodeStackOffset m_src2Offset;
ByteCodeStackOffset m_dstOffset;
};

class MemoryAtomicWait32 : public ByteCode {
class MemoryAtomicWait32 : public TernaryOperationOffset {
public:
MemoryAtomicWait32(uint32_t offset, ByteCodeStackOffset src0, ByteCodeStackOffset src1, ByteCodeStackOffset src2, ByteCodeStackOffset dst)
: ByteCode(Opcode::MemoryAtomicWait32Opcode)
, m_offset(offset)
, m_src0Offset(src0)
, m_src1Offset(src1)
, m_src2Offset(src2)
, m_dstOffset(dst)
: TernaryOperationOffset(Opcode::MemoryAtomicWait32Opcode, offset, src0, src1, src2, dst)
{
}

uint32_t offset() const { return m_offset; }
ByteCodeStackOffset src0Offset() const { return m_src0Offset; }
ByteCodeStackOffset src1Offset() const { return m_src1Offset; }
ByteCodeStackOffset src2Offset() const { return m_src2Offset; }
ByteCodeStackOffset dstOffset() const { return m_dstOffset; }

#if !defined(NDEBUG)
void dump(size_t pos)
{
printf("MemoryAtomicWait32 src0: %" PRIu32 " src1: %" PRIu32 " src2: %" PRIu32 " dst: %" PRIu32 " offset: %" PRIu32, (uint32_t)m_src0Offset, (uint32_t)m_src1Offset, (uint32_t)m_src2Offset, (uint32_t)m_dstOffset, (uint32_t)m_offset);
}
#endif
protected:
uint32_t m_offset;
ByteCodeStackOffset m_src0Offset;
ByteCodeStackOffset m_src1Offset;
ByteCodeStackOffset m_src2Offset;
ByteCodeStackOffset m_dstOffset;
};

class MemoryAtomicWait64 : public ByteCode {
class MemoryAtomicWait64 : public TernaryOperationOffset {
public:
MemoryAtomicWait64(uint32_t offset, ByteCodeStackOffset src0, ByteCodeStackOffset src1, ByteCodeStackOffset src2, ByteCodeStackOffset dst)
: ByteCode(Opcode::MemoryAtomicWait64Opcode)
, m_offset(offset)
, m_src0Offset(src0)
, m_src1Offset(src1)
, m_src2Offset(src2)
, m_dstOffset(dst)
: TernaryOperationOffset(Opcode::MemoryAtomicWait64Opcode, offset, src0, src1, src2, dst)
{
}

uint32_t offset() const { return m_offset; }
ByteCodeStackOffset src0Offset() const { return m_src0Offset; }
ByteCodeStackOffset src1Offset() const { return m_src1Offset; }
ByteCodeStackOffset src2Offset() const { return m_src2Offset; }
ByteCodeStackOffset dstOffset() const { return m_dstOffset; }

#if !defined(NDEBUG)
void dump(size_t pos)
{
printf("MemoryAtomicWait64 src0: %" PRIu32 " src1: %" PRIu32 " src2: %" PRIu32 " dst: %" PRIu32 " offset: %" PRIu32, (uint32_t)m_src0Offset, (uint32_t)m_src1Offset, (uint32_t)m_src2Offset, (uint32_t)m_dstOffset, (uint32_t)m_offset);
}
#endif
protected:
uint32_t m_offset;
ByteCodeStackOffset m_src0Offset;
ByteCodeStackOffset m_src1Offset;
ByteCodeStackOffset m_src2Offset;
ByteCodeStackOffset m_dstOffset;
};

class MemoryAtomicNotify : public ByteCode {
Expand Down Expand Up @@ -1864,6 +1841,22 @@ class MemoryAtomicNotify : public ByteCode {
ByteCodeStackOffset m_src1Offset;
ByteCodeStackOffset m_dstOffset;
};

class AtomicFence : public ByteCode {
public:
AtomicFence()
: ByteCode(Opcode::AtomicFenceOpcode)
{
}

#if !defined(NDEBUG)
void dump(size_t pos)
{
}
#endif
protected:
uint32_t m_offset;
};
#endif

#if !defined(NDEBUG)
Expand Down
7 changes: 7 additions & 0 deletions src/interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,13 @@ ByteCodeStackOffset* Interpreter::interpret(ExecutionState& state,
ADD_PROGRAM_COUNTER(MemoryAtomicNotify);
NEXT_INSTRUCTION();
}
DEFINE_OPCODE(AtomicFence)
:
{
// FIXME do nothing
ADD_PROGRAM_COUNTER(AtomicFence);
NEXT_INSTRUCTION();
}
#endif

// FOR_EACH_BYTECODE_SIMD_ETC_OP
Expand Down
12 changes: 12 additions & 0 deletions src/jit/Backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,18 @@ void JITCompiler::compileFunction(JITFunction* jitFunc, bool isExternal)
emitAtomic(m_compiler, item->asInstruction());
break;
}
case Instruction::AtomicFence: {
emitAtomicFence(m_compiler);
break;
}
case Instruction::AtomicWait: {
emitAtomicWait(m_compiler, item->asInstruction());
break;
}
case Instruction::AtomicNotify: {
emitAtomicNotify(m_compiler, item->asInstruction());
break;
}
#endif /* ENABLE_EXTENDED_FEATURES */
default: {
switch (item->asInstruction()->opcode()) {
Expand Down
42 changes: 41 additions & 1 deletion src/jit/ByteCodeParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,10 @@ static bool isFloatGlobal(uint32_t globalIndex, Module* module)
OL5(OTAtomicRmwI32, /* SSDTT */ I32, I32, I32 | TMP, PTR, I32 | S1) \
OL5(OTAtomicRmwI64, /* SSDTT */ I32, I64, I64 | TMP, PTR, I64 | S1) \
OL6(OTAtomicRmwCmpxchgI32, /* SSSDTT */ I32, I32, I32, I32 | TMP, PTR, I32 | S1) \
OL6(OTAtomicRmwCmpxchgI64, /* SSSDTT */ I32, I64, I64, I64 | TMP, PTR, I64 | S1)
OL6(OTAtomicRmwCmpxchgI64, /* SSSDTT */ I32, I64, I64, I64 | TMP, PTR, I64 | S1) \
OL6(OTAtomicWaitI32, /* SSSDTT */ I32, I32, I64, I32 | TMP, PTR, I32 | S0) \
OL6(OTAtomicWaitI64, /* SSSDTT */ I32, I64, I64, I32 | TMP, PTR, I64 | S0) \
OL5(OTAtomicNotify, /* SSDTT */ I32, I32, I32 | TMP, PTR, I32 | S0)
#else /* !ENABLE_EXTENDED_FEATURES */
#define OPERAND_TYPE_LIST_EXTENDED
#endif /* ENABLE_EXTENDED_FEATURES */
Expand Down Expand Up @@ -1343,6 +1346,12 @@ static void compileFunction(JITCompiler* compiler)
instr->addInfo(Instruction::kIsCallback);
break;
}
#if defined(ENABLE_EXTENDED_FEATURES)
case ByteCode::AtomicFenceOpcode: {
group = Instruction::AtomicFence;
FALLTHROUGH;
}
#endif /* ENABLE_EXTENDED_FEATURES */
case ByteCode::UnreachableOpcode: {
compiler->append(byteCode, group, opcode, 0, 0);
break;
Expand Down Expand Up @@ -1958,6 +1967,37 @@ static void compileFunction(JITCompiler* compiler)
operands[3] = STACK_OFFSET(atomicRmwCmpxchg->dstOffset());
break;
}
case ByteCode::MemoryAtomicWait64Opcode: {
requiredInit = OTAtomicWaitI64;
FALLTHROUGH;
}
case ByteCode::MemoryAtomicWait32Opcode: {
Instruction* instr = compiler->append(byteCode, Instruction::AtomicWait, opcode, 3, 1);
instr->addInfo(Instruction::kIsCallback);

TernaryOperationOffset* memoryAtomicWait = reinterpret_cast<TernaryOperationOffset*>(byteCode);
Operand* operands = instr->operands();
instr->setRequiredRegsDescriptor(requiredInit != OTNone ? requiredInit : OTAtomicWaitI32);

operands[0] = STACK_OFFSET(memoryAtomicWait->src0Offset());
operands[1] = STACK_OFFSET(memoryAtomicWait->src1Offset());
operands[2] = STACK_OFFSET(memoryAtomicWait->src2Offset());
operands[3] = STACK_OFFSET(memoryAtomicWait->dstOffset());
break;
}
case ByteCode::MemoryAtomicNotifyOpcode: {
Instruction* instr = compiler->append(byteCode, Instruction::AtomicNotify, opcode, 2, 1);
instr->addInfo(Instruction::kIsCallback);

MemoryAtomicNotify* memoryAtomicNotify = reinterpret_cast<MemoryAtomicNotify*>(byteCode);
Operand* operands = instr->operands();
instr->setRequiredRegsDescriptor(OTAtomicNotify);

operands[0] = STACK_OFFSET(memoryAtomicNotify->src0Offset());
operands[1] = STACK_OFFSET(memoryAtomicNotify->src1Offset());
operands[2] = STACK_OFFSET(memoryAtomicNotify->dstOffset());
break;
}
#endif /* ENABLE_EXTENDED_FEATURES */
default: {
ASSERT_NOT_REACHED();
Expand Down
4 changes: 4 additions & 0 deletions src/jit/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class InstructionListItem {
#if defined(ENABLE_EXTENDED_FEATURES)
// Atomic memory operations (e.g. I32AtomicRmwAdd, I64AtomicRmw16OrU)
Atomic,
// Special types for thread synchronization operations
AtomicFence,
AtomicWait,
AtomicNotify,
#endif /* ENABLE_EXTENDED_FEATURES */
};

Expand Down
Loading

0 comments on commit 815c9b5

Please sign in to comment.