Skip to content
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

Jit: Threads: Add Fence, Wait, and Notify #285

Merged
merged 1 commit into from
Sep 23, 2024
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
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After this patch, does the extension director work with jit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by extension director?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all tests will pass with jit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes they do.


build-test-performance:
runs-on: ubuntu-latest
Expand Down
123 changes: 58 additions & 65 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 @@ -733,6 +734,33 @@ class ByteCodeOffset2Value : public ByteCode {
uint32_t m_value;
};

class ByteCodeOffset4Value : public ByteCode {
public:
ByteCodeOffset4Value(Opcode opcode, ByteCodeStackOffset src0Offset, ByteCodeStackOffset src1Offset, ByteCodeStackOffset src2Offset, ByteCodeStackOffset dstOffset, uint32_t value)
: ByteCode(opcode)
, m_stackOffset1(src0Offset)
, m_stackOffset2(src1Offset)
, m_stackOffset3(src2Offset)
, m_stackOffset4(dstOffset)
, m_value(value)
{
}

ByteCodeStackOffset src0Offset() const { return m_stackOffset1; }
ByteCodeStackOffset src1Offset() const { return m_stackOffset2; }
ByteCodeStackOffset src2Offset() const { return m_stackOffset3; }
ByteCodeStackOffset dstOffset() const { return m_stackOffset4; }
uint32_t offset() const { return m_value; }

protected:
ByteCodeStackOffset m_stackOffset1;
ByteCodeStackOffset m_stackOffset2;
ByteCodeStackOffset m_stackOffset3;
ByteCodeStackOffset m_stackOffset4;
uint32_t m_value;
};


class ByteCodeTable {
public:
ByteCodeTable();
Expand Down Expand Up @@ -1741,99 +1769,48 @@ class AtomicRmw : public ByteCode {
ByteCodeStackOffset m_dstOffset;
};

class AtomicRmwCmpxchg : public ByteCode {
class AtomicRmwCmpxchg : public ByteCodeOffset4Value {
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)
: ByteCodeOffset4Value(opcode, src0, src1, src2, dst, offset)

{
}

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 ByteCodeOffset4Value {
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)
: ByteCodeOffset4Value(Opcode::MemoryAtomicWait32Opcode, src0, src1, src2, dst, offset)
{
}

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);
printf("MemoryAtomicWait32 src0: %" PRIu32 " src1: %" PRIu32 " src2: %" PRIu32 " dst: %" PRIu32 " offset: %" PRIu32, (uint32_t)m_stackOffset1, (uint32_t)m_stackOffset2, (uint32_t)m_stackOffset3, (uint32_t)m_stackOffset4, (uint32_t)m_value);
}
#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 ByteCodeOffset4Value {
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)
: ByteCodeOffset4Value(Opcode::MemoryAtomicWait64Opcode, src0, src1, src2, dst, offset)
{
}

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);
printf("MemoryAtomicWait64 src0: %" PRIu32 " src1: %" PRIu32 " src2: %" PRIu32 " dst: %" PRIu32 " offset: %" PRIu32, (uint32_t)m_stackOffset1, (uint32_t)m_stackOffset2, (uint32_t)m_stackOffset3, (uint32_t)m_stackOffset4, (uint32_t)m_value);
}
#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 All @@ -1887,10 +1880,10 @@ class MemoryAtomicNotify : public ByteCode {
};

#if !defined(NDEBUG)
#define DEFINE_RMW_CMPXCHG_BYTECODE_DUMP(name) \
void dump(size_t pos) \
{ \
printf(#name " 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); \
#define DEFINE_RMW_CMPXCHG_BYTECODE_DUMP(name) \
void dump(size_t pos) \
{ \
printf(#name " src0: %" PRIu32 " src1: %" PRIu32 " src2: %" PRIu32 " dst: %" PRIu32 " offset: %" PRIu32, (uint32_t)m_stackOffset1, (uint32_t)m_stackOffset2, (uint32_t)m_stackOffset3, (uint32_t)m_stackOffset4, (uint32_t)m_value); \
}
#else
#define DEFINE_RMW_CMPXCHG_BYTECODE_DUMP(name)
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 @@ -1246,6 +1246,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);

ByteCodeOffset4Value* memoryAtomicWait = reinterpret_cast<ByteCodeOffset4Value*>(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
Loading