Skip to content
Merged
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
65 changes: 56 additions & 9 deletions thread/thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,53 @@ namespace photon
static_assert(offsetof(thread, start) == 0x48, "...");
#pragma GCC diagnostic pop

// switch_context() and switch_context_defer() hide a function call inside
// an asm statement, so the compiler can not see what happens across it:
// other photon threads run in between, and they may change any register
// and any memory. So, besides the GPRs, the asm statements must declare
// as clobbered all the vector / mask / flag registers that are not
// preserved by the switch, as well as "memory". Otherwise the compiler
// may keep a value in e.g. %xmm0 across the switch, and get garbage back.
//
// Note that the ABI's caller-saved (volatile) registers, e.g. all xmm on
// x86-64 SysV, are NOT implied clobbered here, as the compiler does not
// treat an asm statement as a call. Nor does the C++ call of these inline
// functions help: once inlined, there is no call boundary at all; and
// even if not, -fipa-ra (enabled at -O2) lets the caller keep values in
// the volatile registers that the callee, as told by these very clobber
// lists, does not use. On the other hand, the callee-saved ones (xmm6-15
// on Win64, v8-v15 on aarch64) must be listed too, as the switch does not
// save them like a real callee would do.
//
// See the GCC manual, Extended Asm, "Clobbers and Scratch Registers", and
// Optimize Options, "-fipa-ra".
#if defined(__x86_64__)
#ifdef __AVX512F__
#define VECTOR_CLOBBERS_AVX512 \
"xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", \
"xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", \
"k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7",
#else
#define VECTOR_CLOBBERS_AVX512
#endif
#define VECTOR_CLOBBERS VECTOR_CLOBBERS_AVX512 \
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", \
"xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
#elif defined(__aarch64__) || defined(__arm64__)
#ifdef __ARM_FEATURE_SVE
#define VECTOR_CLOBBERS_SVE \
"p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7", \
"p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15",
#else
#define VECTOR_CLOBBERS_SVE
#endif
#define VECTOR_CLOBBERS VECTOR_CLOBBERS_SVE \
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", \
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", \
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", \
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
#endif

#if defined(__x86_64__)
#if !defined(_WIN64)
asm(
Expand Down Expand Up @@ -808,7 +855,7 @@ R"(
: "+r"(t), "+r"(f)
: // "0"(t), "1"(f)
: "rax", "rbx", "rcx", "rdx", "r8", "r9", "r10", "r11",
"r12", "r13", "r14", "r15");
"r12", "r13", "r14", "r15", VECTOR_CLOBBERS, "memory");
}

inline void switch_context_defer(thread* from, thread* to,
Expand All @@ -825,7 +872,7 @@ R"(
: "+r"(t), "+r"(f), "+r"(a), "+r"(d)
: // "0"(t), "1"(f), "2"(a), "3"(d)
: "rax", "rbx", "r8", "r9", "r10", "r11", "r12", "r13", "r14",
"r15");
"r15", VECTOR_CLOBBERS, "memory");
}
#else // _WIN64
asm(
Expand All @@ -851,9 +898,11 @@ R"(
jmp *%rdx
)"

// Reserve 32 bytes of shadow space for the calls to
// the thread entry and _photon_thread_die.
DEF_ASM_FUNC(_photon_thread_stub)
R"(
call _asan_start
sub $32, %rsp
mov 0x40(%rbp), %rcx
movq $0, 0x40(%rbp)
call *0x48(%rbp)
Expand All @@ -874,8 +923,7 @@ R"(
: // "0"(t), "1"(f)
: "rax", "rbx", "rsi", "rdi", "r8", "r9",
"r10", "r11", "r12", "r13", "r14", "r15",
"xmm6", "xmm7", "xmm8", "xmm9", "xmm10",
"xmm11", "xmm12", "xmm13", "xmm14", "xmm15");
VECTOR_CLOBBERS, "memory");
}

inline void switch_context_defer(thread* from, thread* to,
Expand All @@ -893,8 +941,7 @@ R"(
: // "0"(t), "1"(f), "2"(a), "3"(d)
: "rax", "rbx", "rsi", "rdi", "r10",
"r11", "r12", "r13", "r14", "r15",
"xmm6", "xmm7", "xmm8", "xmm9", "xmm10",
"xmm11", "xmm12", "xmm13", "xmm14", "xmm15");
VECTOR_CLOBBERS, "memory");
}
#endif // _WIN64

Expand Down Expand Up @@ -960,7 +1007,7 @@ R"(
"x2", "x3", "x4", "x5", "x6", "x7", "x8",
// Corouptable register, may change ,should save
"x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16",
"x17", "x18");
"x17", "x18", VECTOR_CLOBBERS, "cc", "memory");
}

inline void switch_context_defer(thread* from, thread* to,
Expand All @@ -978,7 +1025,7 @@ R"(
: "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26",
"x27", "x28", "x29", "x30", "x4", "x5", "x6", "x7", "x8",
"x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16",
"x17", "x18");
"x17", "x18", VECTOR_CLOBBERS, "cc", "memory");
}
#ifdef __clang__
#pragma GCC diagnostic pop
Expand Down
Loading