Skip to content

Commit c1f9dbe

Browse files
Added support for FADD
1 parent 2d24f1f commit c1f9dbe

File tree

3 files changed

+47
-8
lines changed

3 files changed

+47
-8
lines changed

lib/Arch/X86/Semantics/SSE.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,8 +1637,11 @@ IF_AVX(DEF_ISEL(VMOVDDUP_XMMdq_XMMq) = MOVDDUP<VV128W, V128>;)
16371637

16381638
namespace {
16391639

1640+
// NOTE(xed2025): XED 2025+ marks SSE scalar operations as reading the destination
1641+
// register because they preserve the upper bits. The _nop_read parameter handles
1642+
// this extra operand but we don't use it since we already read from dst.
16401643
template <typename D, typename S1>
1641-
DEF_SEM(SQRTSS, D dst, S1 src1) {
1644+
DEF_SEM(SQRTSS, D dst, D _nop_read, S1 src1) {
16421645

16431646
// Extract a "single-precision" (32-bit) float from [31:0] of src1 vector:
16441647
auto src_float = FExtractV32(FReadV32(src1), 0);
@@ -1653,8 +1656,11 @@ DEF_SEM(SQRTSS, D dst, S1 src1) {
16531656
return memory;
16541657
}
16551658

1659+
// NOTE(xed2025): XED 2025+ marks SSE scalar operations as reading the destination
1660+
// register because they preserve the upper bits. The _nop_read parameter handles
1661+
// this extra operand but we don't use it since we already read from dst.
16561662
template <typename D, typename S1>
1657-
DEF_SEM(RSQRTSS, D dst, S1 src1) {
1663+
DEF_SEM(RSQRTSS, D dst, D _nop_read, S1 src1) {
16581664

16591665
// Extract a "single-precision" (32-bit) float from [31:0] of src1 vector:
16601666
auto src_float = FExtractV32(FReadV32(src1), 0);
@@ -1756,8 +1762,11 @@ DEF_HELPER(SquareRoot64, float64_t src_float)->float64_t {
17561762
return square_root;
17571763
}
17581764

1765+
// NOTE(xed2025): XED 2025+ marks SSE scalar operations as reading the destination
1766+
// register because they preserve the upper bits. The _nop_read parameter handles
1767+
// this extra operand but we don't use it since we already read from dst.
17591768
template <typename D, typename S1>
1760-
DEF_SEM(SQRTSD, D dst, S1 src1) {
1769+
DEF_SEM(SQRTSD, D dst, D _nop_read, S1 src1) {
17611770

17621771
// Extract a "double-precision" (64-bit) float from [63:0] of src1 vector:
17631772
auto src_float = FExtractV64(FReadV64(src1), 0);

lib/Arch/X86/Semantics/X87.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,22 @@ DEF_FPU_SEM(FADDmem, RF80W dst, RF80W src1, T src2) {
558558
return FADD(memory, state, dst, src1, src2, pc, fop);
559559
}
560560

561+
// NOTE(xed2025): XED 2025 changed iform names from FADD_ST0_MEMxxx to FADD_MEMxxx
562+
// and marks ST0 as suppressed. This version accesses ST0 directly via X87_ST0.
563+
template <typename T>
564+
DEF_FPU_SEM(FADDmem_ST0_implicit, T src) {
565+
SetFPUIpOp();
566+
SetFPUDp(src);
567+
auto st0 = Read(X87_ST0);
568+
auto result = CheckedFloatBinOp(state, FAdd80, st0, Float80(Read(src)));
569+
Write(X87_ST0, result);
570+
571+
state.sw.c0 = UUndefined8();
572+
state.sw.c2 = UUndefined8();
573+
state.sw.c3 = UUndefined8();
574+
return memory;
575+
}
576+
561577
template <typename T>
562578
DEF_FPU_SEM(FADDP, RF80W dst, RF80W src1, T src2) {
563579
memory = FADD<T>(memory, state, dst, src1, src2, pc, fop);
@@ -584,6 +600,10 @@ DEF_ISEL(FADDP_X87_ST0) = FADDP<RF80W>;
584600
DEF_ISEL(FIADD_ST0_MEMmem32int) = FIADD<M32>;
585601
DEF_ISEL(FIADD_ST0_MEMmem16int) = FIADD<M16>;
586602

603+
// NOTE(xed2025): XED 2025 renamed FADD_ST0_MEMxxx to FADD_MEMxxx
604+
DEF_ISEL(FADD_MEMmem32real) = FADDmem_ST0_implicit<MF32>;
605+
DEF_ISEL(FADD_MEMm64real) = FADDmem_ST0_implicit<MF64>;
606+
587607
namespace {
588608

589609
template <typename T>

lib/BC/InstructionLifter.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -593,17 +593,23 @@ llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst,
593593
auto arg_size = data_layout.getTypeAllocSizeInBits(arg_type);
594594

595595
if (val_size < arg_size) {
596-
// Because of using the latest version of Intex XED we support (which is currently v2025.06.08),
597-
// it reports XMM/YMM registers as vectors instead of integers. When remills tries to extend/truncate
598-
// these values we'll bitcast those vectors into integers
596+
// NOTE(xed2025): XED 2025 reports XMM/YMM/ZMM registers as LLVM vector types
597+
// (e.g., <4 x float>) instead of integers. When remill needs to zero-extend
598+
// these values to a larger integer type, we must first bitcast the vector
599+
// to an integer of the same bit width, then perform the extension.
599600
if (arg_type->isIntegerTy()) {
600601
if (val_type->isVectorTy()) {
602+
// Vector types can be directly bitcast to integers of the same size.
601603
auto int_type = llvm::Type::getIntNTy(module->getContext(), val_size);
602604
val = new llvm::BitCastInst(val, int_type, llvm::Twine::createNull(), block);
603605

604606
val_type = int_type;
605607
} else if (val_type->isArrayTy()) {
606-
// Arrays cannot be bitcast directly. Store to memory, bitcast pointer, then load.
608+
// NOTE(xed2025): Some register types in remill's State structure are
609+
// represented as arrays (e.g., X87 FPU stack entries as [10 x i8]).
610+
// LLVM does not allow direct bitcast of array types to integers.
611+
// Workaround: store array to stack, bitcast the pointer to int*, then load.
612+
// This gets optimized away by LLVM but satisfies the type system.
607613
auto int_type = llvm::Type::getIntNTy(module->getContext(), val_size);
608614
auto temp_alloca = new llvm::AllocaInst(val_type, 0, llvm::Twine::createNull(), block);
609615
new llvm::StoreInst(val, temp_alloca, block);
@@ -633,14 +639,18 @@ llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst,
633639
}
634640

635641
} else if (val_size > arg_size) {
642+
// NOTE(xed2025): Same type conversion issue as above, but for truncation.
643+
// XED 2025 may report registers as vectors/arrays that need conversion
644+
// to integers before we can truncate them to the smaller argument size.
636645
if (arg_type->isIntegerTy()) {
637646
if (val_type->isVectorTy()) {
647+
// Vector types can be directly bitcast to integers of the same size.
638648
auto int_type = llvm::Type::getIntNTy(module->getContext(), val_size);
639649
val = new llvm::BitCastInst(val, int_type, llvm::Twine::createNull(), block);
640650

641651
val_type = int_type;
642652
} else if (val_type->isArrayTy()) {
643-
// Arrays cannot be bitcast directly. Store to memory, bitcast pointer, then load.
653+
// Array types require store-bitcast-load pattern (see comment above).
644654
auto int_type = llvm::Type::getIntNTy(module->getContext(), val_size);
645655
auto temp_alloca = new llvm::AllocaInst(val_type, 0, llvm::Twine::createNull(), block);
646656
new llvm::StoreInst(val, temp_alloca, block);

0 commit comments

Comments
 (0)