Skip to content

Commit

Permalink
wasm2c: Add segue option to make exclusive use of the segment register
Browse files Browse the repository at this point in the history
  • Loading branch information
shravanrn committed Sep 19, 2024
1 parent 874caa4 commit 1c2b5bf
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ jobs:
env:
USE_NINJA: "1"
WASM2C_CC: "clang"
WASM2C_CFLAGS: "-DWASM_RT_USE_MMAP=1 -DWASM_RT_SKIP_SIGNAL_RECOVERY=1 -DWASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION=1 -DWASM2C_TEST_EMBEDDER_SIGNAL_HANDLING -DWASM_RT_ALLOW_SEGUE=1 -mfsgsbase -DWASM_RT_SANITY_CHECKS=1 -Wno-pass-failed"
WASM2C_CFLAGS: "-DWASM_RT_USE_MMAP=1 -DWASM_RT_SKIP_SIGNAL_RECOVERY=1 -DWASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION=1 -DWASM2C_TEST_EMBEDDER_SIGNAL_HANDLING -DWASM_RT_ALLOW_SEGUE=1 -DWASM_RT_SEGUE_FREE_SEGMENT=1 -mfsgsbase -DWASM_RT_SANITY_CHECKS=1 -Wno-pass-failed"
steps:
- uses: actions/setup-python@v1
with:
Expand Down
6 changes: 5 additions & 1 deletion src/c-writer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2449,7 +2449,9 @@ bool CWriter::IsSingleUnsharedMemory() {
void CWriter::InstallSegueBase(Memory* memory, bool save_old_value) {
NonIndented([&] { Write("#if WASM_RT_USE_SEGUE", Newline()); });
if (save_old_value) {
NonIndented([&] { Write("#if !WASM_RT_SEGUE_FREE_SEGMENT", Newline()); });
Write("void* segue_saved_base = wasm_rt_segue_read_base();", Newline());
NonIndented([&] { Write("#endif", Newline()); });
}
auto primary_memory =
ExternalInstanceRef(ModuleFieldType::Memory, memory->name);
Expand All @@ -2458,7 +2460,9 @@ void CWriter::InstallSegueBase(Memory* memory, bool save_old_value) {
}

void CWriter::RestoreSegueBase() {
NonIndented([&] { Write("#if WASM_RT_USE_SEGUE", Newline()); });
NonIndented([&] {
Write("#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT", Newline());
});
Write("wasm_rt_segue_write_base(segue_saved_base);", Newline());
NonIndented([&] { Write("#endif", Newline()); });
}
Expand Down
16 changes: 15 additions & 1 deletion src/prebuilt/wasm2c_source_declarations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,21 @@ R"w2c_template(}
)w2c_template"
R"w2c_template(static inline void wasm_rt_segue_write_base(void* base) {
)w2c_template"
R"w2c_template( if (wasm_rt_fsgsbase_inst_supported) {
R"w2c_template(#if WASM_RT_SEGUE_FREE_SEGMENT
)w2c_template"
R"w2c_template( if (wasm_rt_last_segment_val == base) {
)w2c_template"
R"w2c_template( return;
)w2c_template"
R"w2c_template( }
)w2c_template"
R"w2c_template(
wasm_rt_last_segment_val = base;
)w2c_template"
R"w2c_template(#endif
)w2c_template"
R"w2c_template(
if (wasm_rt_fsgsbase_inst_supported) {
)w2c_template"
R"w2c_template( __builtin_ia32_wrgsbase64((uintptr_t)base);
)w2c_template"
Expand Down
8 changes: 8 additions & 0 deletions src/template/wasm2c.declarations.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}

wasm_rt_last_segment_val = base;
#endif

if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down
8 changes: 8 additions & 0 deletions test/wasm2c/add.txt
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down
12 changes: 11 additions & 1 deletion test/wasm2c/check-imports.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down Expand Up @@ -825,11 +833,13 @@ void wasm2c_test_instantiate(w2c_test* instance, struct w2c_env* w2c_env_instanc
init_tables(instance);
init_memories(instance);
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_env_0x5F_linear_memory).data);
#endif
init_elem_instances(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
Expand Down
32 changes: 26 additions & 6 deletions test/wasm2c/export-names.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down Expand Up @@ -796,59 +804,69 @@ static void init_memories(w2c_test* instance) {
/* export: '' */
void w2c_test_(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
w2c_test__0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
/* export: '*\2F' */
void w2c_test_0x2A0x2F(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
w2c_test__0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
/* export: '\3F\3F\2F' */
void w2c_test_0x3F0x3F0x2F(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
w2c_test__0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
/* export: '\0A' */
void w2c_test_0x0A(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
w2c_test__0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
/* export: '\E2\9D\A4\EF\B8\8F' */
void w2c_test_0xE20x9D0xA40xEF0xB80x8F(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
w2c_test__0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
Expand All @@ -866,10 +884,12 @@ void wasm2c_test_instantiate(w2c_test* instance, struct w2c_0x5Cmodule* w2c_0x5C
init_instance_import(instance, w2c_0x5Cmodule_instance);
init_memories(instance);
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base((*instance->w2c_0x5Cmodule_import0x200x2A0x2F).data);
#endif
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
Expand Down
16 changes: 14 additions & 2 deletions test/wasm2c/hello.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down Expand Up @@ -833,11 +841,13 @@ wasm_rt_memory_t* w2c_test_memory(w2c_test* instance) {
/* export: '_start' */
void w2c_test_0x5Fstart(w2c_test* instance) {
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base(instance->w2c_memory.data);
#endif
w2c_test_0x5Fstart_0(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
Expand All @@ -852,12 +862,14 @@ void wasm2c_test_instantiate(w2c_test* instance, struct w2c_wasi__snapshot__prev
init_tables(instance);
init_memories(instance);
#if WASM_RT_USE_SEGUE
#if !WASM_RT_SEGUE_FREE_SEGMENT
void* segue_saved_base = wasm_rt_segue_read_base();
#endif
wasm_rt_segue_write_base(instance->w2c_memory.data);
#endif
init_elem_instances(instance);
init_data_instances(instance);
#if WASM_RT_USE_SEGUE
#if WASM_RT_USE_SEGUE && !WASM_RT_SEGUE_FREE_SEGMENT
wasm_rt_segue_write_base(segue_saved_base);
#endif
}
Expand Down
8 changes: 8 additions & 0 deletions test/wasm2c/minimal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down
8 changes: 8 additions & 0 deletions test/wasm2c/tail-calls.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ static inline void* wasm_rt_segue_read_base() {
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}
wasm_rt_last_segment_val = base;
#endif
if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
Expand Down
11 changes: 9 additions & 2 deletions wasm2c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ high performance overhead, and is thus only recommended for debug builds.

Wasm2c can use the "Segue" optimization if allowed. The segue optimization uses
an x86 segment register to store the location of Wasm's linear memory, when
compiling a Wasm module with clang, running on x86_64 Linux, and the macro
`WASM_RT_ALLOW_SEGUE` is defined. Segue is not used if
compiling a Wasm module with clang, running on x86_64 Linux, the macro
`WASM_RT_ALLOW_SEGUE` is defined, and the flag `-mfsgsbase` is passed to clang.
Segue is not used if

1. The Wasm module uses a more than a single unshared imported or exported
memory
Expand All @@ -173,6 +174,12 @@ However, any host functions written in assembly that clobber the free segment
register must restore the value of this register prior to executing or returning
control to wasm2c generated code.

As an additional optimization, if the host program does not use the `%gs`
segment register for any other purpose (which is typically the case in most
programs), you can additionally allow wasm2c to unconditionally overwrite the
value of the `%gs` register without restoring the old value. This can be done
defining the macro `WASM_RT_SEGUE_FREE_SEGMENT`.

You can test the performance of the Segue optimization by running Dhrystone with
and without Segue:

Expand Down
34 changes: 17 additions & 17 deletions wasm2c/examples/fac/fac.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,16 @@
// for accessing pointers, and supports memcpy on pointers with custom
// "address namespaces". GCC does not support the memcpy requirement, so
// this leaves only clang for now.
// (5) The OS doesn't replace the segment register on context switch which
// (5) The OS provides a way to query if (rd|wr)gsbase is allowed by the kernel
// or the implementation has to use a syscall for this.
// (6) The OS doesn't replace the segment register on context switch which
// eliminates windows for now
//
// While more OS can be supported in the future, we only support linux for now
#if WASM_RT_ALLOW_SEGUE && !WABT_BIG_ENDIAN && \
(defined(__x86_64__) || defined(_M_X64)) && IS_SINGLE_UNSHARED_MEMORY && \
__clang__ && __has_builtin(__builtin_ia32_wrgsbase64) && !defined(_WIN32)
__clang__ && __has_builtin(__builtin_ia32_wrgsbase64) && \
!defined(_WIN32) && defined(__linux__)
#define WASM_RT_USE_SEGUE 1
#else
#define WASM_RT_USE_SEGUE 0
Expand All @@ -64,31 +69,26 @@

#if WASM_RT_USE_SEGUE
// POSIX uses FS for TLS, GS is free
#include <asm/prctl.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>

static inline void* wasm_rt_segue_read_base() {
if (wasm_rt_fsgsbase_inst_supported) {
return (void*)__builtin_ia32_rdgsbase64();
} else {
void* base;
if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0) {
perror("Syscall SYS_arch_prctl error");
abort();
}
return base;
return wasm_rt_syscall_get_segue_base();
}
}
static inline void wasm_rt_segue_write_base(void* base) {
#if WASM_RT_SEGUE_FREE_SEGMENT
if (wasm_rt_last_segment_val == base) {
return;
}

wasm_rt_last_segment_val = base;
#endif

if (wasm_rt_fsgsbase_inst_supported) {
__builtin_ia32_wrgsbase64((uintptr_t)base);
} else {
if (syscall(SYS_arch_prctl, ARCH_SET_GS, (uintptr_t)base) != 0) {
perror("Syscall SYS_arch_prctl error");
abort();
}
wasm_rt_syscall_set_segue_base(base);
}
}
#define MEM_ADDR_MEMOP(mem, addr, n) ((uint8_t __seg_gs*)(uintptr_t)addr)
Expand Down
4 changes: 4 additions & 0 deletions wasm2c/wasm-rt-impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ bool wasm_rt_fsgsbase_inst_supported = false;
#include <unistd.h> // For syscall
#endif

#if WASM_RT_SEGUE_FREE_SEGMENT
WASM_RT_THREAD_LOCAL void* wasm_rt_last_segment_val = NULL;
#endif

#if WASM_RT_STACK_DEPTH_COUNT
WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth;
WASM_RT_THREAD_LOCAL uint32_t wasm_rt_saved_call_stack_depth;
Expand Down
Loading

0 comments on commit 1c2b5bf

Please sign in to comment.