Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d83d754
Fix 16-bit MOVSX MOVZX MOVSXD semantics
mrexodia May 22, 2026
e1442e2
Add BMI2 SARX and SHRX semantics
mrexodia May 22, 2026
651254d
Add BMI1 bit-low operation semantics
mrexodia May 22, 2026
9c88816
Canonicalize invalid SSE divide NaNs
mrexodia May 22, 2026
1ddc9d1
Add SSE packed min max and sqrt semantics
mrexodia May 22, 2026
5a1b388
Add SSE2 MOVMSKPD semantics
mrexodia May 22, 2026
37d8e80
Add SSE horizontal subtract semantics
mrexodia May 23, 2026
7dfa6ba
Add SSE blend semantics
mrexodia May 23, 2026
f00e89d
Add SSE4 insert and extract PS semantics
mrexodia May 23, 2026
a08d0ac
Mask legacy SSE compare predicates
mrexodia May 23, 2026
3bafb8a
Return x86 indefinite integers for invalid FP conversions
mrexodia May 23, 2026
ce2c8a5
Add SSE4 round semantics
mrexodia May 23, 2026
6d77129
Add SSE4 dot product semantics
mrexodia May 23, 2026
d000b5c
Fix MULX destination ordering
mrexodia May 23, 2026
5180828
Fix SHLD and SHRD wide-count semantics
mrexodia May 23, 2026
56f21a0
Add ADCX and ADOX semantics
mrexodia May 23, 2026
7db212d
Add MPSADBW semantics
mrexodia May 23, 2026
4277839
Add INSERTQ semantics
mrexodia May 23, 2026
298519c
Add AES-NI semantics
mrexodia May 23, 2026
a227ce9
Add SHA1MSG1 semantics
mrexodia May 23, 2026
253fd61
Add SHA1MSG2 semantics
mrexodia May 23, 2026
68a43a8
Add SHA1NEXTE semantics
mrexodia May 23, 2026
3fb9fdf
Add SHA1RNDS4 semantics
mrexodia May 23, 2026
0c80e8c
Add SHA256 message schedule semantics
mrexodia May 23, 2026
3b997da
Add SHA256RNDS2 semantics
mrexodia May 23, 2026
60cf744
Add RDFSBASE semantics
mrexodia May 23, 2026
2044e40
Model disabled RDSSP as no-op
mrexodia May 23, 2026
7faf30b
Add SMSW corpus semantics
mrexodia May 23, 2026
259dcc4
Normalize x87 status side effects
mrexodia May 23, 2026
4b46adc
Model corpus LAR and LSL descriptor probes
mrexodia May 23, 2026
8f0c541
Model 3975WX approximate SSE reciprocals
mrexodia May 23, 2026
6f6c240
Clear C1 for FXCH
mrexodia May 23, 2026
04a8247
Model FABS and FCHS as x87 sign operations
mrexodia May 23, 2026
d49aaa5
Model FXAM without host classification libcalls
mrexodia May 23, 2026
ad3f883
Model stable 16-bit LAR system selector bits
mrexodia May 23, 2026
f6aa35a
Copy x87 stack bytes for FST register form
mrexodia May 23, 2026
065c21c
Fix x86 memory bit-test register offsets
mrexodia Jun 15, 2026
d3b9855
Fix CMPXCHG8B accumulator updates
mrexodia Jun 15, 2026
d81c0bb
Fix 16-bit SHLD and SHRD wide counts
mrexodia Jun 15, 2026
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
85 changes: 79 additions & 6 deletions lib/Arch/X86/Semantics/BINARY.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,12 @@ DEF_SEM(MULX, D dst1, D dst2, const S2 src2) {
auto res_high = UShr(res, ZExt(BitSizeOf(src2)));

// In 64-bit, a 32-bit dest needs to zero-extend up to 64 bits because the
// write version of the reg will be the 64-bit version.
WriteZExt(dst1, TruncTo<S2>(res_high)); // High N bits.
// write version of the reg will be the 64-bit version. MULX writes its
// first explicit destination with the high half and its second explicit
// destination with the low half; write the second destination first so that
// aliasing destinations leave the architecturally observed high half.
WriteZExt(dst2, TruncTo<S2>(res)); // Low N bits.
WriteZExt(dst1, TruncTo<S2>(res_high)); // High N bits.
return memory;
}

Expand Down Expand Up @@ -534,23 +537,63 @@ IF_64BIT(DEF_ISEL(DIV_GPRv_64) = DIVrdxrax<R64>;)

namespace {

ALWAYS_INLINE static float32_t X86IndefiniteQNaN(float32_t) {
nan32_t ret = {};
ret.flat = 0xFFC00000U;
return ret.f;
}

ALWAYS_INLINE static float64_t X86IndefiniteQNaN(float64_t) {
nan64_t ret = {};
ret.flat = 0xFFF8000000000000ULL;
return ret.d;
}

template <typename T>
ALWAYS_INLINE static T X86Div(T lhs, T rhs) {
auto quot = FDiv(lhs, rhs);
if ((IsZero(lhs) && IsZero(rhs)) ||
(IsInfinite(lhs) && IsInfinite(rhs))) {
return X86IndefiniteQNaN(lhs);
}
return quot;
}

template <typename V>
ALWAYS_INLINE static V X86DivV32(V lhs, V rhs) {
auto res = lhs;
_Pragma("unroll") for (addr_t i = 0; i < NumVectorElems(lhs); ++i) {
res = FInsertV32(res, i, X86Div(FExtractV32(lhs, i), FExtractV32(rhs, i)));
}
return res;
}

template <typename V>
ALWAYS_INLINE static V X86DivV64(V lhs, V rhs) {
auto res = lhs;
_Pragma("unroll") for (addr_t i = 0; i < NumVectorElems(lhs); ++i) {
res = FInsertV64(res, i, X86Div(FExtractV64(lhs, i), FExtractV64(rhs, i)));
}
return res;
}

template <typename D, typename S1, typename S2>
DEF_SEM(DIVPS, D dst, S1 src1, S2 src2) {
FWriteV32(dst, FDivV32(FReadV32(src1), FReadV32(src2)));
FWriteV32(dst, X86DivV32(FReadV32(src1), FReadV32(src2)));
return memory;
}

template <typename D, typename S1, typename S2>
DEF_SEM(DIVPD, D dst, const S1 src1, const S2 src2) {
FWriteV64(dst, FDivV64(FReadV64(src1), FReadV64(src2)));
FWriteV64(dst, X86DivV64(FReadV64(src1), FReadV64(src2)));
return memory;
}

template <typename D, typename S1, typename S2>
DEF_SEM(DIVSS, D dst, S1 src1, S2 src2) {
auto lhs = FReadV32(src1);
auto rhs = FReadV32(src2);
auto quot = FDiv(FExtractV32(lhs, 0), FExtractV32(rhs, 0));
auto quot = X86Div(FExtractV32(lhs, 0), FExtractV32(rhs, 0));
auto res = FInsertV32(lhs, 0, quot);
FWriteV32(dst, res); // SSE: Writes to XMM, AVX: Zero-extends XMM.
return memory;
Expand All @@ -560,7 +603,7 @@ template <typename D, typename S1, typename S2>
DEF_SEM(DIVSD, D dst, S1 src1, S2 src2) {
auto lhs = FReadV64(src1);
auto rhs = FReadV64(src2);
auto quot = FDiv(FExtractV64(lhs, 0), FExtractV64(rhs, 0));
auto quot = X86Div(FExtractV64(lhs, 0), FExtractV64(rhs, 0));
auto res = FInsertV64(lhs, 0, quot);
FWriteV64(dst, res); // SSE: Writes to XMM, AVX: Zero-extends XMM.
return memory;
Expand Down Expand Up @@ -665,6 +708,30 @@ DEF_SEM(ADC, D dst, S1 src1, S2 src2) {
return memory;
}

template <typename D, typename S1, typename S2>
DEF_SEM(ADCX, D dst, S1 src1, S2 src2) {
auto lhs = Read(src1);
auto rhs = Read(src2);
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_CF)));
auto sum = UAdd(lhs, rhs);
auto res = UAdd(sum, carry);
WriteZExt(dst, res);
Write(FLAG_CF, CarryFlag<tag_add>(lhs, rhs, sum, carry, res));
return memory;
}

template <typename D, typename S1, typename S2>
DEF_SEM(ADOX, D dst, S1 src1, S2 src2) {
auto lhs = Read(src1);
auto rhs = Read(src2);
auto carry = ZExtTo<S1>(Unsigned(Read(FLAG_OF)));
auto sum = UAdd(lhs, rhs);
auto res = UAdd(sum, carry);
WriteZExt(dst, res);
Write(FLAG_OF, CarryFlag<tag_add>(lhs, rhs, sum, carry, res));
return memory;
}

template <typename D, typename S1, typename S2>
DEF_SEM(SBB, D dst, S1 src1, S2 src2) {
auto lhs = Read(src1);
Expand Down Expand Up @@ -717,3 +784,9 @@ DEF_ISEL_RnW_Rn_Mn(ADC_GPRv_MEMv, ADC);
DEF_ISEL_RnW_Rn_Rn(ADC_GPRv_GPRv_13, ADC);
DEF_ISEL(ADC_AL_IMMb) = ADC<R8W, R8, I8>;
DEF_ISEL_RnW_Rn_In(ADC_OrAX_IMMz, ADC);

DEF_ISEL(ADCX_GPR32d_GPR32d) = ADCX<R32W, R32, R32>;
IF_64BIT(DEF_ISEL(ADCX_GPR64q_GPR64q) = ADCX<R64W, R64, R64>;)

DEF_ISEL(ADOX_GPR32d_GPR32d) = ADOX<R32W, R32, R32>;
IF_64BIT(DEF_ISEL(ADOX_GPR64q_GPR64q) = ADOX<R64W, R64, R64>;)
94 changes: 90 additions & 4 deletions lib/Arch/X86/Semantics/BITBYTE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,21 @@ namespace {
UndefFlag(pf); \
} while (false)

template <typename S1, typename S2>
ALWAYS_INLINE static auto BTMemoryIndex(Memory *&memory, S1, S2 src2) {
using ElementT = typename BaseType<S1>::BT;
constexpr unsigned kBitIndexShift = sizeof(ElementT) == 8 ? 6u :
sizeof(ElementT) == 4 ? 5u :
sizeof(ElementT) == 2 ? 4u : 3u;
auto signed_index = SShr(SExtTo<S1>(Read(src2)), SLiteral<S1>(kBitIndexShift));
return static_cast<addr_t>(signed_index);
}

template <typename S1, typename T>
ALWAYS_INLINE static addr_t BTMemoryIndex(Memory *&, S1, In<T>) {
return 0;
}

template <typename S1, typename S2>
DEF_SEM(BTreg, S1 src1, S2 src2) {
auto val = Read(src1);
Expand All @@ -174,7 +189,7 @@ template <typename S1, typename S2>
DEF_SEM(BTmem, S1 src1, S2 src2) {
auto bit = ZExtTo<S1>(Read(src2));
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
auto index = UDiv(bit, BitSizeOf(src1));
auto index = BTMemoryIndex(memory, src1, src2);
auto val = Read(GetElementPtr(src1, index));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
_BTClearUndefFlags();
Expand All @@ -196,7 +211,7 @@ template <typename D, typename S1, typename S2>
DEF_SEM(BTSmem, D dst, S1 src1, S2 src2) {
auto bit = ZExtTo<S1>(Read(src2));
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
auto index = UDiv(bit, BitSizeOf(src1));
auto index = BTMemoryIndex(memory, src1, src2);
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UOr(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
Expand All @@ -219,7 +234,7 @@ template <typename D, typename S1, typename S2>
DEF_SEM(BTRmem, D dst, S1 src1, S2 src2) {
auto bit = ZExtTo<S1>(Read(src2));
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
auto index = UDiv(bit, BitSizeOf(src1));
auto index = BTMemoryIndex(memory, src1, src2);
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UAnd(val, UNot(bit_mask)));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
Expand All @@ -242,7 +257,7 @@ template <typename D, typename S1, typename S2>
DEF_SEM(BTCmem, D dst, S1 src1, S2 src2) {
auto bit = ZExtTo<S1>(Read(src2));
auto bit_mask = UShl(Literal<S1>(1), URem(bit, BitSizeOf(src1)));
auto index = UDiv(bit, BitSizeOf(src1));
auto index = BTMemoryIndex(memory, src1, src2);
auto val = Read(GetElementPtr(src1, index));
Write(GetElementPtr(dst, index), UXor(val, bit_mask));
Write(FLAG_CF, UCmpNeq(UAnd(val, bit_mask), Literal<S1>(0)));
Expand Down Expand Up @@ -410,6 +425,50 @@ DEF_SEM(BZHI, D dst, S1 src1, S2 src2) {
return memory;
}

// BMI1 bit-low operations write CF/ZF/SF/OF, leave AF/PF undefined, and do
// not read flags.
template <typename D, typename S>
DEF_SEM(BLSI, D dst, S src) {
auto val = Read(src);
auto res = UAnd(val, USub(Literal<S>(0), val));
WriteZExt(dst, res);
Write(FLAG_CF, UCmpNeq(val, Literal<S>(0)));
Write(FLAG_ZF, ZeroFlag(res));
Write(FLAG_SF, SignFlag(res));
Write(FLAG_OF, false);
UndefFlag(af);
UndefFlag(pf);
return memory;
}

template <typename D, typename S>
DEF_SEM(BLSR, D dst, S src) {
auto val = Read(src);
auto res = UAnd(val, USub(val, Literal<S>(1)));
WriteZExt(dst, res);
Write(FLAG_CF, ZeroFlag(val));
Write(FLAG_ZF, ZeroFlag(res));
Write(FLAG_SF, SignFlag(res));
Write(FLAG_OF, false);
UndefFlag(af);
UndefFlag(pf);
return memory;
}

template <typename D, typename S>
DEF_SEM(BLSMSK, D dst, S src) {
auto val = Read(src);
auto res = UXor(val, USub(val, Literal<S>(1)));
WriteZExt(dst, res);
Write(FLAG_CF, ZeroFlag(val));
Write(FLAG_ZF, ZeroFlag(res));
Write(FLAG_SF, SignFlag(res));
Write(FLAG_OF, false);
UndefFlag(af);
UndefFlag(pf);
return memory;
}

template <typename D, typename S>
DEF_SEM(POPCNT, D dst, S src) {
auto val = Read(src);
Expand Down Expand Up @@ -508,6 +567,33 @@ IF_64BIT(DEF_ISEL(BZHI_GPR64q_GPR64q_GPR64q) = BZHI<R64W, R64, R64>;)
IF_64BIT(DEF_ISEL(BZHI_VGPR64q_MEMq_VGPR64q) = BZHI<R64W, M64, R64>;)
IF_64BIT(DEF_ISEL(BZHI_VGPR64q_VGPR64q_VGPR64q) = BZHI<R64W, R64, R64>;)

DEF_ISEL(BLSI_GPR32d_MEMd) = BLSI<R32W, M32>;
DEF_ISEL(BLSI_GPR32d_GPR32d) = BLSI<R32W, R32>;
DEF_ISEL(BLSI_VGPR32d_MEMd) = BLSI<R32W, M32>;
DEF_ISEL(BLSI_VGPR32d_VGPR32d) = BLSI<R32W, R32>;
IF_64BIT(DEF_ISEL(BLSI_GPR64q_MEMq) = BLSI<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSI_GPR64q_GPR64q) = BLSI<R64W, R64>;)
IF_64BIT(DEF_ISEL(BLSI_VGPR64q_MEMq) = BLSI<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSI_VGPR64q_VGPR64q) = BLSI<R64W, R64>;)

DEF_ISEL(BLSR_GPR32d_MEMd) = BLSR<R32W, M32>;
DEF_ISEL(BLSR_GPR32d_GPR32d) = BLSR<R32W, R32>;
DEF_ISEL(BLSR_VGPR32d_MEMd) = BLSR<R32W, M32>;
DEF_ISEL(BLSR_VGPR32d_VGPR32d) = BLSR<R32W, R32>;
IF_64BIT(DEF_ISEL(BLSR_GPR64q_MEMq) = BLSR<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSR_GPR64q_GPR64q) = BLSR<R64W, R64>;)
IF_64BIT(DEF_ISEL(BLSR_VGPR64q_MEMq) = BLSR<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSR_VGPR64q_VGPR64q) = BLSR<R64W, R64>;)

DEF_ISEL(BLSMSK_GPR32d_MEMd) = BLSMSK<R32W, M32>;
DEF_ISEL(BLSMSK_GPR32d_GPR32d) = BLSMSK<R32W, R32>;
DEF_ISEL(BLSMSK_VGPR32d_MEMd) = BLSMSK<R32W, M32>;
DEF_ISEL(BLSMSK_VGPR32d_VGPR32d) = BLSMSK<R32W, R32>;
IF_64BIT(DEF_ISEL(BLSMSK_GPR64q_MEMq) = BLSMSK<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSMSK_GPR64q_GPR64q) = BLSMSK<R64W, R64>;)
IF_64BIT(DEF_ISEL(BLSMSK_VGPR64q_MEMq) = BLSMSK<R64W, M64>;)
IF_64BIT(DEF_ISEL(BLSMSK_VGPR64q_VGPR64q) = BLSMSK<R64W, R64>;)

DEF_ISEL_RnW_Mn(POPCNT_GPRv_MEMv, POPCNT);
DEF_ISEL_RnW_Rn(POPCNT_GPRv_GPRv, POPCNT);

Expand Down
54 changes: 48 additions & 6 deletions lib/Arch/X86/Semantics/CONVERT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,48 @@ DEF_SEM(CVTDQ2PD, D dst, S1 src) {
typedef float32_t (*FloatConv32)(float32_t);
typedef float64_t (*FloatConv64)(float64_t);

ALWAYS_INLINE static bool IsInvalidInt32Result(float32_t val) {
return IsNaN(val) || val >= 2147483648.0f || val < -2147483648.0f;
}

ALWAYS_INLINE static bool IsInvalidInt32Result(float64_t val) {
return IsNaN(val) || val >= 2147483648.0 || val < -2147483648.0;
}

ALWAYS_INLINE static bool IsInvalidInt64Result(float32_t val) {
return IsNaN(val) || val >= 9223372036854775808.0f ||
val < -9223372036854775808.0f;
}

ALWAYS_INLINE static bool IsInvalidInt64Result(float64_t val) {
return IsNaN(val) || val >= 9223372036854775808.0 ||
val < -9223372036854775808.0;
}

ALWAYS_INLINE static int32_t X86FloatToInt32(float32_t val) {
return Select<int32_t>(IsInvalidInt32Result(val),
static_cast<int32_t>(0x80000000U),
Float32ToInt32(val));
}

ALWAYS_INLINE static int32_t X86FloatToInt32(float64_t val) {
return Select<int32_t>(IsInvalidInt32Result(val),
static_cast<int32_t>(0x80000000U),
Float64ToInt32(val));
}

ALWAYS_INLINE static int64_t X86FloatToInt64(float32_t val) {
return Select<int64_t>(IsInvalidInt64Result(val),
static_cast<int64_t>(0x8000000000000000ULL),
Float32ToInt64(val));
}

ALWAYS_INLINE static int64_t X86FloatToInt64(float64_t val) {
return Select<int64_t>(IsInvalidInt64Result(val),
static_cast<int64_t>(0x8000000000000000ULL),
Float64ToInt64(val));
}

} // namespace

DEF_ISEL(CVTDQ2PD_XMMpd_MEMq) = CVTDQ2PD<V128W, MV64, 2>;
Expand Down Expand Up @@ -154,7 +196,7 @@ DEF_SEM(CVTPD2DQ, D dst, S1 src) {
auto dst_vec = SClearV32(SReadV32(dst));
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
float64_t rounded_elem = FRound(FExtractV64(src_vec, i));
auto entry = Float64ToInt32(rounded_elem);
auto entry = X86FloatToInt32(rounded_elem);
dst_vec = SInsertV32(dst_vec, i, entry);
}
SWriteV32(dst, dst_vec);
Expand Down Expand Up @@ -190,7 +232,7 @@ DEF_SEM(CVTPS2DQ, D dst, S1 src) {
auto dst_vec = SClearV32(SReadV32(dst));
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
float32_t rounded_elem = FRound(FExtractV32(src_vec, i));
dst_vec = SInsertV32(dst_vec, i, Float32ToInt32(rounded_elem));
dst_vec = SInsertV32(dst_vec, i, X86FloatToInt32(rounded_elem));
}
SWriteV32(dst, dst_vec);
return memory;
Expand Down Expand Up @@ -221,15 +263,15 @@ namespace {
template <typename S, FloatConv32 FRound = FRoundUsingMode32>
DEF_SEM(CVTSS2SI_32, R32W dst, S src) {
float32_t rounded_val = FRound(FExtractV32(FReadV32(src), 0));
WriteZExt(dst, Unsigned(Float32ToInt32(rounded_val)));
WriteZExt(dst, Unsigned(X86FloatToInt32(rounded_val)));
return memory;
}

#if 64 == ADDRESS_SIZE_BITS
template <typename S, FloatConv32 FRound = FRoundUsingMode32>
DEF_SEM(CVTSS2SI_64, R64W dst, S src) {
float32_t rounded_val = FRound(FExtractV32(FReadV32(src), 0));
Write(dst, Unsigned(Float32ToInt64(rounded_val)));
Write(dst, Unsigned(X86FloatToInt64(rounded_val)));
return memory;
}
#endif // ADDRESS_SIZE_BITS
Expand Down Expand Up @@ -265,15 +307,15 @@ namespace {
template <typename S, FloatConv64 FRound = FRoundUsingMode64>
DEF_SEM(CVTSD2SI_32, R32W dst, S src) {
auto rounded_val = FRound(FExtractV64(FReadV64(src), 0));
WriteZExt(dst, Unsigned(Float64ToInt32(rounded_val)));
WriteZExt(dst, Unsigned(X86FloatToInt32(rounded_val)));
return memory;
}

#if 64 == ADDRESS_SIZE_BITS
template <typename S, FloatConv64 FRound = FRoundUsingMode64>
DEF_SEM(CVTSD2SI_64, R64W dst, S src) {
auto rounded_val = FRound(FExtractV64(FReadV64(src), 0));
Write(dst, Unsigned(Float64ToInt64(rounded_val)));
Write(dst, Unsigned(X86FloatToInt64(rounded_val)));
return memory;
}
#endif // ADDRESS_SIZE_BITS
Expand Down
Loading
Loading