Skip to content

Commit

Permalink
Futher attempts at 80-bit floats
Browse files Browse the repository at this point in the history
  • Loading branch information
artemdinaburg authored and kumarak committed Aug 16, 2021
1 parent 301aa06 commit 936db64
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 19 deletions.
2 changes: 2 additions & 0 deletions include/remill/Arch/Runtime/Intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ __remill_write_memory_f64(Memory *, addr_t, float64_t);

[[gnu::used, gnu::const]] extern float64_t __remill_undefined_f64(void);

[[gnu::used, gnu::const]] extern float80_t __remill_undefined_f80(void);

// Generic error.
[[gnu::used]] extern Memory *__remill_error(State &, addr_t addr, Memory *);

Expand Down
33 changes: 25 additions & 8 deletions include/remill/Arch/Runtime/Operators.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ ALWAYS_INLINE static float64_t _Read(Memory *, float64_t val) {
return val;
}

ALWAYS_INLINE static float80_t _Read(Memory *, float80_t val) {
return val;
}

ALWAYS_INLINE static float32_t _Read(Memory *, In<float32_t> imm) {
return reinterpret_cast<const float32_t &>(imm.val);
}
Expand All @@ -114,6 +118,10 @@ ALWAYS_INLINE static float64_t _Read(Memory *, In<float64_t> imm) {
return reinterpret_cast<const float64_t &>(imm.val);
}

ALWAYS_INLINE static float80_t _Read(Memory *, In<float80_t> imm) {
return reinterpret_cast<const float80_t &>(imm.val);
}

template <typename T>
ALWAYS_INLINE static T _Read(Memory *, In<T> imm) {
return static_cast<T>(imm.val);
Expand Down Expand Up @@ -149,7 +157,7 @@ MAKE_MREAD(128, 128, uint, 128)

MAKE_MREAD(32, 32, float, f32)
MAKE_MREAD(64, 64, float, f64)
MAKE_MREAD(80, 64, float, f80)
MAKE_MREAD(80, 80, float, f80)

#undef MAKE_MREAD

Expand All @@ -174,6 +182,7 @@ MAKE_RWRITE(uint32_t)
MAKE_RWRITE(uint64_t)
MAKE_RWRITE(float32_t)
MAKE_RWRITE(float64_t)
MAKE_RWRITE(float80_t)

#undef MAKE_RWRITE

Expand All @@ -193,7 +202,7 @@ MAKE_MWRITE(128, 128, uint, uint, 128)

MAKE_MWRITE(32, 32, float, float, f32)
MAKE_MWRITE(64, 64, float, float, f64)
MAKE_MWRITE(80, 64, float, float, f80)
MAKE_MWRITE(80, 80, float, float, f80)

#undef MAKE_MWRITE

Expand Down Expand Up @@ -222,6 +231,7 @@ MAKE_READRV(S, 64, sqwords, int64_t)

MAKE_READRV(F, 32, floats, float32_t)
MAKE_READRV(F, 64, doubles, float64_t)
MAKE_READRV(F, 80, tdoubles, float80_t)

#undef MAKE_READRV

Expand Down Expand Up @@ -252,6 +262,7 @@ MAKE_READV(S, 128, sdqwords)

MAKE_READV(F, 32, floats)
MAKE_READV(F, 64, doubles)
MAKE_READV(F, 80, tdouble)

#undef MAKE_READV

Expand Down Expand Up @@ -295,6 +306,7 @@ MAKE_MREADV(S, 128, sdqwords, s128)

MAKE_MREADV(F, 32, floats, f32)
MAKE_MREADV(F, 64, doubles, f64)
MAKE_MREADV(F, 80, tdoubles, f80)

#undef MAKE_MREADV

Expand Down Expand Up @@ -343,6 +355,7 @@ MAKE_WRITEV(S, 128, sdqwords, VnW, int128_t)

MAKE_WRITEV(F, 32, floats, VnW, float32_t)
MAKE_WRITEV(F, 64, doubles, VnW, float64_t)
MAKE_WRITEV(F, 80, tdoubles, VnW, float80_t)

MAKE_WRITEV(U, 8, bytes, RVnW, uint8_t)
MAKE_WRITEV(U, 16, words, RVnW, uint16_t)
Expand All @@ -356,6 +369,7 @@ MAKE_WRITEV(S, 64, sqwords, RVnW, int64_t)

MAKE_WRITEV(F, 32, floats, RVnW, float32_t)
MAKE_WRITEV(F, 64, doubles, RVnW, float64_t)
MAKE_WRITEV(F, 80, tdoubles, RVnW, float80_t)

#undef MAKE_WRITEV

Expand Down Expand Up @@ -404,6 +418,7 @@ MAKE_MWRITEV(S, 128, sdqwords, s128, int128_t)

MAKE_MWRITEV(F, 32, floats, f32, float32_t)
MAKE_MWRITEV(F, 64, doubles, f64, float64_t)
MAKE_MWRITEV(F, 80, tdoubles, f80, float80_t)

#undef MAKE_MWRITEV

Expand All @@ -421,6 +436,7 @@ MAKE_WRITE_REF(uint64_t)
MAKE_WRITE_REF(uint128_t)
MAKE_WRITE_REF(float32_t)
MAKE_WRITE_REF(float64_t)
MAKE_WRITE_REF(float80_t)

#undef MAKE_WRITE_REF

Expand Down Expand Up @@ -903,12 +919,10 @@ ALWAYS_INLINE static auto TruncTo(T val) -> typename IntegerType<DT>::BT {
op) make_int_op(S##name, int128_t, int128_t, op) \
make_int_op(S##name##128, int128_t, int128_t, op) \
make_float_op(F##name, float32_t, float32_t, op) \
make_float_op( \
F##name##32, float32_t, float32_t, \
op) make_float_op(F##name, float64_t, \
float64_t, op) \
make_float_op(F##name##64, float64_t, \
float64_t, op)
make_float_op(F##name##32, float32_t, float32_t, op) \
make_float_op(F##name, float64_t, float64_t, op) \
make_float_op(F##name##64, float64_t, float64_t, op) \
make_float_op(F##name##80, float80_t, float80_t, op)

MAKE_OPS(Add, +, MAKE_BINOP, MAKE_BINOP)
MAKE_OPS(Sub, -, MAKE_BINOP, MAKE_BINOP)
Expand Down Expand Up @@ -1086,6 +1100,7 @@ MAKE_EXTRACTV(64, int64_t, qwords, Signed, S)
MAKE_EXTRACTV(128, int128_t, dqwords, Signed, S)
MAKE_EXTRACTV(32, float32_t, floats, Identity, F)
MAKE_EXTRACTV(64, float64_t, doubles, Identity, F)
MAKE_EXTRACTV(80, float80_t, tdoubles, Identity, F)

#undef MAKE_EXTRACTV

Expand Down Expand Up @@ -1158,6 +1173,7 @@ MAKE_INSERTV(S, 128, int128_t, sdqwords)

MAKE_INSERTV(F, 32, float32_t, floats)
MAKE_INSERTV(F, 64, float64_t, doubles)
MAKE_INSERTV(F, 80, float80_t, tdoubles)

#undef MAKE_INSERTV

Expand Down Expand Up @@ -1185,6 +1201,7 @@ MAKE_UPDATEV(S, 128, int128_t, sdqwords)

MAKE_UPDATEV(F, 32, float32_t, floats)
MAKE_UPDATEV(F, 64, float64_t, doubles)
MAKE_UPDATEV(F, 80, float80_t, tdoubles)

#undef MAKE_UPDATEV

Expand Down
34 changes: 34 additions & 0 deletions include/remill/Arch/Runtime/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include <cstdint>
#include <cstring>
#include <limits>
#include <type_traits>

Expand Down Expand Up @@ -70,6 +71,39 @@ static_assert(8 == sizeof(float128_t), "Invalid `float128_t` size.");
// TODO(pag): Assumes little endian.
struct float80_t final {
uint8_t data[10];
#if defined(__x86_64__) || defined(__i386__) || defined(_M_X86)
// convert a long double into an f80 representation on x86/x86-64
// this assumes long double uses the f80 format internally, but
// is simply aligned to an even boundary (hence size 12 or 16)
float80_t(long double ld) {
static_assert(12 == sizeof(long double) || 16 == sizeof(long double), "Invalid `long double` size.");
union ld_union {
long double ld_val;
struct {
char pad[sizeof(long double) - sizeof(float80_t)];
float80_t f80;
} __attribute__((packed)) f80_data;
};

ld_union ldu {.ld_val = ld};
std::memcpy(&data[0], &ldu.f80_data.f80.data[0], sizeof(data));
}

operator long double() const {
static_assert(12 == sizeof(long double) || 16 == sizeof(long double), "Invalid `long double` size.");
union ld_union {
long double ld_val;
struct {
char pad[sizeof(long double) - sizeof(float80_t)];
float80_t f80;
} __attribute__((packed)) f80_data;
};

ld_union ldu {0};
std::memcpy(&ldu.f80_data.f80.data[0], &data[0], sizeof(data));
return ldu.ld_val;
}
#endif
} __attribute__((packed));

static_assert(10 == sizeof(float80_t), "Invalid `float80_t` size.");
Expand Down
4 changes: 2 additions & 2 deletions include/remill/Arch/X86/Runtime/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,5 @@ typedef Rn<float64_t> RF64;
typedef RnW<float64_t> RF64W;

// Internally, we boil F80s down into F64s.
typedef Rn<float64_t> RF80;
typedef RnW<float64_t> RF80W;
typedef Rn<float80_t> RF80;
typedef RnW<float80_t> RF80W;
1 change: 1 addition & 0 deletions include/remill/BC/IntrinsicTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class IntrinsicTable {
llvm::Function *undefined_64;
llvm::Function *undefined_f32;
llvm::Function *undefined_f64;
llvm::Function *undefined_f80;

private:
IntrinsicTable(void) = delete;
Expand Down
1 change: 1 addition & 0 deletions lib/Arch/Runtime/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,5 @@ extern "C" void __remill_mark_as_used(const void *);
USED(__remill_undefined_64);
USED(__remill_undefined_f32);
USED(__remill_undefined_f64);
USED(__remill_undefined_f80);
}
16 changes: 8 additions & 8 deletions lib/Arch/X86/Semantics/MMX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1900,14 +1900,14 @@ DEF_SEM(DoEMMS) {
state.mmx.elems[6].val.qwords.elems[0] = __remill_undefined_64();
state.mmx.elems[7].val.qwords.elems[0] = __remill_undefined_64();

state.st.elems[0].val = __remill_undefined_f64();
state.st.elems[1].val = __remill_undefined_f64();
state.st.elems[2].val = __remill_undefined_f64();
state.st.elems[3].val = __remill_undefined_f64();
state.st.elems[4].val = __remill_undefined_f64();
state.st.elems[5].val = __remill_undefined_f64();
state.st.elems[6].val = __remill_undefined_f64();
state.st.elems[7].val = __remill_undefined_f64();
state.st.elems[0].val = __remill_undefined_f80();
state.st.elems[1].val = __remill_undefined_f80();
state.st.elems[2].val = __remill_undefined_f80();
state.st.elems[3].val = __remill_undefined_f80();
state.st.elems[4].val = __remill_undefined_f80();
state.st.elems[5].val = __remill_undefined_f80();
state.st.elems[6].val = __remill_undefined_f80();
state.st.elems[7].val = __remill_undefined_f80();

// TODO(pag): Add FPU tag word stuff to the `State` structure, and reset
// it here.
Expand Down
3 changes: 2 additions & 1 deletion lib/BC/IntrinsicTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ IntrinsicTable::IntrinsicTable(llvm::Module *module)
undefined_32(FindPureIntrinsic(module, "__remill_undefined_32")),
undefined_64(FindPureIntrinsic(module, "__remill_undefined_64")),
undefined_f32(FindPureIntrinsic(module, "__remill_undefined_f32")),
undefined_f64(FindPureIntrinsic(module, "__remill_undefined_f64")) {
undefined_f64(FindPureIntrinsic(module, "__remill_undefined_f64")),
undefined_f80(FindPureIntrinsic(module, "__remill_undefined_f80")) {

// Make sure to set the correct attributes on this to make sure that
// it's never optimized away.
Expand Down
4 changes: 4 additions & 0 deletions tests/AArch64/Run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,10 @@ float64_t __remill_undefined_f64(void) {
return 0.0;
}

float80_t __remill_undefined_f80(void) {
return {0};
}

// Marks `mem` as being used. This is used for making sure certain symbols are
// kept around through optimization, and makes sure that optimization doesn't
// perform dead-argument elimination on any of the intrinsics.
Expand Down
4 changes: 4 additions & 0 deletions tests/X86/Run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,10 @@ float64_t __remill_undefined_f64(void) {
return 0.0;
}

float80_t __remill_undefined_f80(void) {
return {0};
}

// Marks `mem` as being used. This is used for making sure certain symbols are
// kept around through optimization, and makes sure that optimization doesn't
// perform dead-argument elimination on any of the intrinsics.
Expand Down

0 comments on commit 936db64

Please sign in to comment.