[cmake] enable clang-cl and WoA builds (#348)

Compilation and CMake fixes for both Windows on ARM and clang-cl, meaning Windows can now be built on both MSVC and clang on both amd64 and aarch64.

Compiling on clang is *dramatically* faster so this should be useful for CI.

Co-authored-by: crueter <crueter@eden-emu.dev>
Co-authored-by: crueter <crueter@crueter.xyz>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/348
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie
2025-09-09 20:47:49 +02:00
committed by crueter
parent 428f136a75
commit 9d2681ecc9
276 changed files with 973 additions and 1010 deletions
+3 -3
View File
@@ -103,7 +103,7 @@ if (MSVC)
/WX)
endif()
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
if (CXX_CLANG)
list(APPEND DYNARMIC_CXX_FLAGS
-Qunused-arguments
-Wno-missing-braces)
@@ -131,7 +131,7 @@ else()
-Wfatal-errors)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if (CXX_GCC)
# GCC produces bogus -Warray-bounds warnings from xbyak headers for code paths that are not
# actually reachable. Specifically, it happens in cases where some code casts an Operand&
# to Address& after first checking isMEM(), and that code is inlined in a situation where
@@ -141,7 +141,7 @@ else()
list(APPEND DYNARMIC_CXX_FLAGS -Wstack-usage=4096)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "[Cc]lang")
if (CXX_CLANG)
# Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
# And this in turns limits the size of a std::array.
list(APPEND DYNARMIC_CXX_FLAGS -fbracket-depth=1024)
@@ -277,7 +277,7 @@ void EmitX64::EmitNZCVFromPackedFlags(EmitContext& ctx, IR::Inst* inst) {
}
void EmitX64::EmitAddCycles(size_t cycles) {
ASSERT(cycles < std::numeric_limits<s32>::max());
ASSERT(cycles < (std::numeric_limits<s32>::max)());
code.sub(qword[rsp + ABI_SHADOW_SPACE + offsetof(StackLayout, cycles_remaining)], static_cast<u32>(cycles));
}
@@ -38,7 +38,7 @@ void EmitSignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst)
Xbyak::Reg addend = ctx.reg_alloc.UseGpr(args[1]).changeBit(size);
Xbyak::Reg overflow = ctx.reg_alloc.ScratchGpr().changeBit(size);
constexpr u64 int_max = static_cast<u64>(std::numeric_limits<mcl::signed_integer_of_size<size>>::max());
constexpr u64 int_max = static_cast<u64>((std::numeric_limits<mcl::signed_integer_of_size<size>>::max)());
if constexpr (size < 64) {
code.xor_(overflow.cvt32(), overflow.cvt32());
code.bt(result.cvt32(), size - 1);
@@ -82,7 +82,7 @@ void EmitUnsignedSaturatedOp(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst
Xbyak::Reg op_result = ctx.reg_alloc.UseScratchGpr(args[0]).changeBit(size);
Xbyak::Reg addend = ctx.reg_alloc.UseScratchGpr(args[1]).changeBit(size);
constexpr u64 boundary = op == Op::Add ? std::numeric_limits<mcl::unsigned_integer_of_size<size>>::max() : 0;
constexpr u64 boundary = op == Op::Add ? (std::numeric_limits<mcl::unsigned_integer_of_size<size>>::max)() : 0;
if constexpr (op == Op::Add) {
code.add(op_result, addend);
@@ -548,7 +548,7 @@ void EmitX64::EmitVectorArithmeticShiftRight32(EmitContext& ctx, IR::Inst* inst)
void EmitX64::EmitVectorArithmeticShiftRight64(EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
const u8 shift_amount = std::min(args[1].GetImmediateU8(), u8(63));
const u8 shift_amount = (std::min)(args[1].GetImmediateU8(), u8(63));
if (code.HasHostFeature(HostFeature::AVX512_Ortho)) {
code.vpsraq(result, result, shift_amount);
@@ -2139,7 +2139,7 @@ void EmitX64::EmitVectorMaxS64(EmitContext& ctx, IR::Inst* inst) {
}
EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray<s64>& result, const VectorArray<s64>& a, const VectorArray<s64>& b) {
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return std::max(x, y); });
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::max)(x, y); });
});
}
@@ -2201,7 +2201,7 @@ void EmitX64::EmitVectorMaxU64(EmitContext& ctx, IR::Inst* inst) {
}
EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray<u64>& result, const VectorArray<u64>& a, const VectorArray<u64>& b) {
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return std::max(x, y); });
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::max)(x, y); });
});
}
@@ -2259,7 +2259,7 @@ void EmitX64::EmitVectorMinS64(EmitContext& ctx, IR::Inst* inst) {
}
EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray<s64>& result, const VectorArray<s64>& a, const VectorArray<s64>& b) {
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return std::min(x, y); });
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::min)(x, y); });
});
}
@@ -2321,7 +2321,7 @@ void EmitX64::EmitVectorMinU64(EmitContext& ctx, IR::Inst* inst) {
}
EmitTwoArgumentFallback(code, ctx, inst, [](VectorArray<u64>& result, const VectorArray<u64>& a, const VectorArray<u64>& b) {
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return std::min(x, y); });
std::transform(a.begin(), a.end(), b.begin(), result.begin(), [](auto x, auto y) { return (std::min)(x, y); });
});
}
@@ -2837,22 +2837,22 @@ static void LowerPairedOperation(VectorArray<T>& result, const VectorArray<T>& x
template<typename T>
static void PairedMax(VectorArray<T>& result, const VectorArray<T>& x, const VectorArray<T>& y) {
PairedOperation(result, x, y, [](auto a, auto b) { return std::max(a, b); });
PairedOperation(result, x, y, [](auto a, auto b) { return (std::max)(a, b); });
}
template<typename T>
static void PairedMin(VectorArray<T>& result, const VectorArray<T>& x, const VectorArray<T>& y) {
PairedOperation(result, x, y, [](auto a, auto b) { return std::min(a, b); });
PairedOperation(result, x, y, [](auto a, auto b) { return (std::min)(a, b); });
}
template<typename T>
static void LowerPairedMax(VectorArray<T>& result, const VectorArray<T>& x, const VectorArray<T>& y) {
LowerPairedOperation(result, x, y, [](auto a, auto b) { return std::max(a, b); });
LowerPairedOperation(result, x, y, [](auto a, auto b) { return (std::max)(a, b); });
}
template<typename T>
static void LowerPairedMin(VectorArray<T>& result, const VectorArray<T>& x, const VectorArray<T>& y) {
LowerPairedOperation(result, x, y, [](auto a, auto b) { return std::min(a, b); });
LowerPairedOperation(result, x, y, [](auto a, auto b) { return (std::min)(a, b); });
}
template<typename Function>
@@ -4933,7 +4933,7 @@ static bool VectorSignedSaturatedShiftLeft(VectorArray<T>& dst, const VectorArra
for (size_t i = 0; i < dst.size(); i++) {
const T element = data[i];
const T shift = std::clamp<T>(static_cast<T>(mcl::bit::sign_extend<8>(static_cast<U>(shift_values[i] & 0xFF))),
-static_cast<T>(bit_size_minus_one), std::numeric_limits<T>::max());
-static_cast<T>(bit_size_minus_one), (std::numeric_limits<T>::max)());
if (element == 0) {
dst[i] = 0;
@@ -4995,7 +4995,7 @@ static bool VectorSignedSaturatedShiftLeftUnsigned(VectorArray<T>& dst, const Ve
const U shifted_test = shifted >> static_cast<U>(shift);
if (shifted_test != static_cast<U>(element)) {
dst[i] = static_cast<T>(std::numeric_limits<U>::max());
dst[i] = static_cast<T>((std::numeric_limits<U>::max)());
qc_flag = true;
} else {
dst[i] = shifted;
@@ -5845,11 +5845,11 @@ static bool EmitVectorUnsignedSaturatedAccumulateSigned(VectorArray<U>& result,
const s64 y = static_cast<s64>(static_cast<std::make_unsigned_t<U>>(rhs[i]));
const s64 sum = x + y;
if (sum > std::numeric_limits<U>::max()) {
result[i] = std::numeric_limits<U>::max();
if (sum > (std::numeric_limits<U>::max)()) {
result[i] = (std::numeric_limits<U>::max)();
qc_flag = true;
} else if (sum < 0) {
result[i] = std::numeric_limits<U>::min();
result[i] = (std::numeric_limits<U>::min)();
qc_flag = true;
} else {
result[i] = static_cast<U>(sum);
@@ -5947,20 +5947,20 @@ static bool VectorUnsignedSaturatedShiftLeft(VectorArray<T>& dst, const VectorAr
for (size_t i = 0; i < dst.size(); i++) {
const T element = data[i];
const S shift = std::clamp(static_cast<S>(mcl::bit::sign_extend<8>(static_cast<T>(shift_values[i] & 0xFF))),
negative_bit_size, std::numeric_limits<S>::max());
negative_bit_size, (std::numeric_limits<S>::max)());
if (element == 0 || shift <= negative_bit_size) {
dst[i] = 0;
} else if (shift < 0) {
dst[i] = static_cast<T>(element >> -shift);
} else if (shift >= static_cast<S>(bit_size)) {
dst[i] = std::numeric_limits<T>::max();
dst[i] = (std::numeric_limits<T>::max)();
qc_flag = true;
} else {
const T shifted = element << shift;
if ((shifted >> shift) != element) {
dst[i] = std::numeric_limits<T>::max();
dst[i] = (std::numeric_limits<T>::max)();
qc_flag = true;
} else {
dst[i] = shifted;
@@ -2116,7 +2116,7 @@ void EmitFPVectorToFixed(BlockOfCode& code, EmitContext& ctx, IR::Inst* inst) {
}
} else {
using FPT = mcl::unsigned_integer_of_size<fsize>; // WORKAROUND: For issue 678 on MSVC
constexpr u64 integer_max = static_cast<FPT>(std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max());
constexpr u64 integer_max = static_cast<FPT>((std::numeric_limits<std::conditional_t<unsigned_, FPT, std::make_signed_t<FPT>>>::max)());
code.movaps(xmm0, GetVectorOf<fsize, float_upper_limit_signed>(code));
FCODE(cmplep)(xmm0, src);
@@ -85,7 +85,7 @@ void HostLocInfo::ReleaseOne() noexcept {
if (current_references == 0)
return;
ASSERT(size_t(accumulated_uses) + 1 < std::numeric_limits<uint16_t>::max());
ASSERT(size_t(accumulated_uses) + 1 < (std::numeric_limits<uint16_t>::max)());
accumulated_uses++;
current_references--;
@@ -116,7 +116,7 @@ void HostLocInfo::AddValue(IR::Inst* inst) noexcept {
values.clear();
}
values.push_back(inst);
ASSERT(size_t(total_uses) + inst->UseCount() < std::numeric_limits<uint16_t>::max());
ASSERT(size_t(total_uses) + inst->UseCount() < (std::numeric_limits<uint16_t>::max)());
total_uses += inst->UseCount();
max_bit_width = std::max<uint8_t>(max_bit_width, GetBitWidth(inst->GetType()));
}
@@ -400,14 +400,14 @@ void RegAlloc::HostCall(IR::Inst* result_def,
}
void RegAlloc::AllocStackSpace(const size_t stack_space) noexcept {
ASSERT(stack_space < size_t(std::numeric_limits<s32>::max()));
ASSERT(stack_space < size_t((std::numeric_limits<s32>::max)()));
ASSERT(reserved_stack_space == 0);
reserved_stack_space = stack_space;
code->sub(code->rsp, u32(stack_space));
}
void RegAlloc::ReleaseStackSpace(const size_t stack_space) noexcept {
ASSERT(stack_space < size_t(std::numeric_limits<s32>::max()));
ASSERT(stack_space < size_t((std::numeric_limits<s32>::max)()));
ASSERT(reserved_stack_space == stack_space);
reserved_stack_space = 0;
code->add(code->rsp, u32(stack_space));
@@ -52,18 +52,18 @@ public:
is_set_last_use = true;
}
inline void ReadLock() noexcept {
ASSERT(size_t(is_being_used_count) + 1 < std::numeric_limits<uint16_t>::max());
ASSERT(size_t(is_being_used_count) + 1 < (std::numeric_limits<uint16_t>::max)());
ASSERT(!is_scratch);
is_being_used_count++;
}
inline void WriteLock() noexcept {
ASSERT(size_t(is_being_used_count) + 1 < std::numeric_limits<uint16_t>::max());
ASSERT(size_t(is_being_used_count) + 1 < (std::numeric_limits<uint16_t>::max)());
ASSERT(is_being_used_count == 0);
is_being_used_count++;
is_scratch = true;
}
inline void AddArgReference() noexcept {
ASSERT(size_t(current_references) + 1 < std::numeric_limits<uint16_t>::max());
ASSERT(size_t(current_references) + 1 < (std::numeric_limits<uint16_t>::max)());
current_references++;
ASSERT(accumulated_uses + current_references <= total_uses);
}
@@ -106,6 +106,7 @@ inline size_t RegNumber(ExtReg reg) {
}
ASSERT_MSG(false, "Invalid extended register");
return 0;
}
inline Reg operator+(Reg reg, size_t number) {