Skip to content

Commit 7d33dec

Browse files
authored
Adds Flag Intrinsics for Aarch64, SPARC32, and SPARC64 (#565)
* added flag intrinsics aarch64 * hints for sparc32 * added cmov hints
1 parent e24243c commit 7d33dec

File tree

6 files changed

+84
-67
lines changed

6 files changed

+84
-67
lines changed

lib/Arch/AArch64/Semantics/BRANCH.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,42 @@ namespace {
1818

1919
// when '101' result = (PSTATE.N == PSTATE.V); // GE or LT
2020
static inline bool CondGE(const State &state) {
21-
return FLAG_N == FLAG_V;
21+
return __remill_compare_sge(FLAG_N == FLAG_V);
2222
}
2323

2424
// when '101' result = (PSTATE.N == PSTATE.V); // GE or LT
2525
static inline bool CondLT(const State &state) {
26-
return FLAG_N != FLAG_V;
26+
return __remill_compare_slt(FLAG_N != FLAG_V);
2727
}
2828

2929
// when '000' result = (PSTATE.Z == '1'); // EQ or NE
3030
static inline bool CondEQ(const State &state) {
31-
return FLAG_Z;
31+
return __remill_compare_eq(FLAG_Z);
3232
}
3333

3434
// when '000' result = (PSTATE.Z == '1'); // EQ or NE
3535
static inline bool CondNE(const State &state) {
36-
return !FLAG_Z;
36+
return __remill_compare_neq(!FLAG_Z);
3737
}
3838

3939
// when '110' result = (PSTATE.N == PSTATE.V && PSTATE.Z == '0'); // GT or LE
4040
static inline bool CondGT(const State &state) {
41-
return (FLAG_N == FLAG_V) && !FLAG_Z;
41+
return __remill_compare_sgt((FLAG_N == FLAG_V) && !FLAG_Z);
4242
}
4343

4444
// when '110' result = (PSTATE.N == PSTATE.V && PSTATE.Z == '0'); // GT or LE
4545
static inline bool CondLE(const State &state) {
46-
return (FLAG_N != FLAG_V) || FLAG_Z;
46+
return __remill_compare_sle((FLAG_N != FLAG_V) || FLAG_Z);
4747
}
4848

4949
// when '001' result = (PSTATE.C == '1'); // CS or CC
5050
static inline bool CondCS(const State &state) {
51-
return FLAG_C;
51+
return __remill_compare_uge(FLAG_C);
5252
}
5353

5454
// when '001' result = (PSTATE.C == '1'); // CS or CC
5555
static inline bool CondCC(const State &state) {
56-
return !FLAG_C;
56+
return __remill_compare_ult(!FLAG_C);
5757
}
5858

5959
// when '010' result = (PSTATE.N == '1'); // MI or PL
@@ -78,12 +78,12 @@ static inline bool CondVC(const State &state) {
7878

7979
// when '100' result = (PSTATE.C == '1' && PSTATE.Z == '0'); // HI or LS
8080
static inline bool CondHI(const State &state) {
81-
return FLAG_C && !FLAG_Z;
81+
return __remill_compare_ugt(FLAG_C && !FLAG_Z);
8282
}
8383

8484
// when '100' result = (PSTATE.C == '1' && PSTATE.Z == '0'); // HI or LS
8585
static inline bool CondLS(const State &state) {
86-
return !FLAG_C || FLAG_Z;
86+
return __remill_compare_ule(!FLAG_C || FLAG_Z);
8787
}
8888

8989
static inline bool CondAL(const State &state) {

lib/Arch/AArch64/Semantics/FLAGS.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@ enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U };
2323
// Zero flags, tells us whether or not a value is zero.
2424
template <typename T>
2525
[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) {
26-
return T(0) == res;
26+
return __remill_flag_computation_zero(T(0) == res, res);
2727
}
2828

2929
// Zero flags, tells us whether or not a value is zero.
3030
template <typename T>
3131
[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) {
32-
return T(0) != res;
32+
return !__remill_flag_computation_zero(T(0) == res, res);
3333
}
3434

3535
// Sign flag, tells us if a result is signed or unsigned.
3636
template <typename T>
3737
[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) {
38-
return 0 > Signed(res);
38+
return __remill_flag_computation_sign(0 > Signed(res), res);
3939
}
4040

4141
// Tests whether there is an even number of bits in the low order byte.
@@ -91,7 +91,8 @@ struct Overflow<tag_sub> {
9191
const T sign_lhs = lhs >> kSignShift;
9292
const T sign_rhs = rhs >> kSignShift;
9393
const T sign_res = res >> kSignShift;
94-
return 2 == (sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res);
94+
return __remill_flag_computation_overflow(
95+
2 == (sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res), lhs, rhs, res);
9596
}
9697
};
9798

@@ -103,10 +104,11 @@ struct Overflow<tag_mul> {
103104
// the operands.
104105
template <typename T, typename R>
105106
[[gnu::const]] ALWAYS_INLINE static bool
106-
Flag(T, T, R res,
107+
Flag(T lhs, T rhs, R res,
107108
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
108109

109-
return static_cast<R>(static_cast<T>(res)) != res;
110+
return __remill_flag_computation_overflow(
111+
static_cast<R>(static_cast<T>(res)) != res, lhs, rhs, res);
110112
}
111113

112114
// Signed integer multiplication overflow check, where the result is
@@ -132,18 +134,19 @@ struct Carry<tag_add> {
132134
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
133135
static_assert(std::is_unsigned<T>::value,
134136
"Invalid specialization of `Carry::Flag` for addition.");
135-
return res < lhs || res < rhs;
137+
return __remill_flag_computation_carry(res < lhs || res < rhs, lhs, rhs,
138+
res);
136139
}
137140
};
138141

139142
// Computes an carry flag when one number is subtracted from another.
140143
template <>
141144
struct Carry<tag_sub> {
142145
template <typename T>
143-
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
146+
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
144147
static_assert(std::is_unsigned<T>::value,
145148
"Invalid specialization of `Carry::Flag` for addition.");
146-
return lhs < rhs;
149+
return __remill_flag_computation_carry(lhs < rhs, lhs, rhs, res);
147150
}
148151
};
149152

lib/Arch/SPARC32/Semantics/COND.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,60 +12,60 @@
1212
static inline bool CondE_##cc(const State &state) { \
1313
const auto ccr = state.asr.ccr.cc; \
1414
const bool flag_zf = ccr.z; \
15-
return flag_zf; \
15+
return __remill_compare_eq(flag_zf); \
1616
} \
1717
static inline bool CondNE_##cc(const State &state) { \
1818
const auto ccr = state.asr.ccr.cc; \
1919
const bool flag_zf = ccr.z; \
20-
return !flag_zf; \
20+
return __remill_compare_neq(!flag_zf); \
2121
} \
2222
static inline bool CondG_##cc(const State &state) { \
2323
const auto ccr = state.asr.ccr.cc; \
2424
const bool flag_nf = ccr.n; \
2525
const bool flag_zf = ccr.z; \
2626
const bool flag_vf = ccr.v; \
27-
return (flag_nf == flag_vf) && !flag_zf; \
27+
return __remill_compare_sgt((flag_nf == flag_vf) && !flag_zf); \
2828
} \
2929
static inline bool CondLE_##cc(const State &state) { \
3030
const auto ccr = state.asr.ccr.cc; \
3131
const bool flag_nf = ccr.n; \
3232
const bool flag_zf = ccr.z; \
3333
const bool flag_vf = ccr.v; \
34-
return (flag_nf != flag_vf) || flag_zf; \
34+
return __remill_compare_sle((flag_nf != flag_vf) || flag_zf); \
3535
} \
3636
static inline bool CondGE_##cc(const State &state) { \
3737
const auto ccr = state.asr.ccr.cc; \
3838
const bool flag_nf = ccr.n; \
3939
const bool flag_vf = ccr.v; \
40-
return flag_nf == flag_vf; \
40+
return __remill_compare_sge(flag_nf == flag_vf); \
4141
} \
4242
static inline bool CondL_##cc(const State &state) { \
4343
const auto ccr = state.asr.ccr.cc; \
4444
const bool flag_nf = ccr.n; \
4545
const bool flag_vf = ccr.v; \
46-
return flag_nf != flag_vf; \
46+
return __remill_compare_slt(flag_nf != flag_vf); \
4747
} \
4848
static inline bool CondGU_##cc(const State &state) { \
4949
const auto ccr = state.asr.ccr.cc; \
5050
const bool flag_cf = ccr.c; \
5151
const bool flag_zf = ccr.z; \
52-
return !(flag_cf || flag_zf); \
52+
return __remill_compare_ugt(!(flag_cf || flag_zf)); \
5353
} \
5454
static inline bool CondLEU_##cc(const State &state) { \
5555
const auto ccr = state.asr.ccr.cc; \
5656
const bool flag_cf = ccr.c; \
5757
const bool flag_zf = ccr.z; \
58-
return flag_cf || flag_zf; \
58+
return __remill_compare_ule(flag_cf || flag_zf); \
5959
} \
6060
static inline bool CondCS_##cc(const State &state) { \
6161
const auto ccr = state.asr.ccr.cc; \
6262
const bool flag_cf = ccr.c; \
63-
return flag_cf; \
63+
return __remill_compare_ult(flag_cf); \
6464
} \
6565
static inline bool CondCC_##cc(const State &state) { \
6666
const auto ccr = state.asr.ccr.cc; \
6767
const bool flag_cf = ccr.c; \
68-
return !flag_cf; \
68+
return __remill_compare_uge(!flag_cf); \
6969
} \
7070
static inline bool CondPOS_##cc(const State &state) { \
7171
const auto ccr = state.asr.ccr.cc; \

lib/Arch/SPARC32/Semantics/FLAGS.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ namespace {
2121
// Zero flags, tells us whether or not a value is zero.
2222
template <typename T>
2323
[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) {
24-
return T(0) == res;
24+
return __remill_flag_computation_zero(T(0) == res, res);
2525
}
2626

2727
// Zero flags, tells us whether or not a value is zero.
2828
template <typename T>
2929
[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) {
30-
return T(0) != res;
30+
return !__remill_flag_computation_zero(T(0) == res);
3131
}
3232

3333
// Sign flag, tells us if a result is signed or unsigned.
3434
template <typename T>
3535
[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) {
36-
return 0 > Signed(res);
36+
return __remill_flag_computation_sign(0 > Signed(res), res);
3737
}
3838

3939
// Tests whether there is an even number of bits in the low order byte.
@@ -76,7 +76,8 @@ struct Overflow<tag_add> {
7676
const T sign_lhs = lhs >> kSignShift;
7777
const T sign_rhs = rhs >> kSignShift;
7878
const T sign_res = res >> kSignShift;
79-
return 2 == ((sign_lhs ^ sign_res) + (sign_rhs ^ sign_res));
79+
return __remill_flag_computation_overflow(
80+
2 == ((sign_lhs ^ sign_res) + (sign_rhs ^ sign_res)), lhs, rhs, res);
8081
}
8182
};
8283

@@ -96,7 +97,8 @@ struct Overflow<tag_sub> {
9697
const T sign_lhs = lhs >> kSignShift;
9798
const T sign_rhs = rhs >> kSignShift;
9899
const T sign_res = res >> kSignShift;
99-
return 2 == ((sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res));
100+
return __remill_flag_computation_overflow(
101+
2 == ((sign_lhs ^ sign_rhs) + (sign_lhs ^ sign_res)), lhs, rhs, res);
100102
}
101103
};
102104

@@ -108,10 +110,11 @@ struct Overflow<tag_mul> {
108110
// the operands.
109111
template <typename T, typename R>
110112
[[gnu::const]] ALWAYS_INLINE static bool
111-
Flag(T, T, R res,
113+
Flag(T lhs, T rhs, R res,
112114
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
113115

114-
return static_cast<R>(static_cast<T>(res)) != res;
116+
return __remill_flag_computation_overflow(
117+
static_cast<R>(static_cast<T>(res)) != res, lhs, rhs, res);
115118
}
116119

117120
// Signed integer multiplication overflow check, where the result is
@@ -131,12 +134,14 @@ template <>
131134
struct Overflow<tag_sdiv> {
132135
template <typename T, typename R>
133136
[[gnu::const]] ALWAYS_INLINE static bool
134-
Flag(T, T, R res,
137+
Flag(T lhs, T rhs, R res,
135138
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
136139

137140
enum { kSignShift = sizeof(T) * 8 - 1 };
138141

139-
return (SExt(res << kSignShift) > 0) || (SExt(res << kSignShift) < -1);
142+
return __remill_flag_computation_overflow(
143+
(SExt(res << kSignShift) > 0) || (SExt(res << kSignShift) < -1), lhs,
144+
rhs, res);
140145
}
141146

142147
template <typename T, typename R>
@@ -162,12 +167,13 @@ template <>
162167
struct Overflow<tag_udiv> {
163168
template <typename T, typename R>
164169
[[gnu::const]] ALWAYS_INLINE static bool
165-
Flag(T, T, R res,
170+
Flag(T lhs, T rhs, R res,
166171
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
167172

168173
enum { kShift = sizeof(T) * 8 };
169174

170-
return (SExt(res << kShift) > 0);
175+
return __remill_flag_computation_overflow((SExt(res << kShift) > 0), lhs,
176+
rhs, res);
171177
}
172178

173179
template <typename T, typename R>
@@ -198,18 +204,19 @@ struct Carry<tag_add> {
198204
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
199205
static_assert(std::is_unsigned<T>::value,
200206
"Invalid specialization of `Carry::Flag` for addition.");
201-
return res < lhs || res < rhs;
207+
return __remill_flag_computation_carry(res < lhs || res < rhs, lhs, rhs,
208+
res);
202209
}
203210
};
204211

205212
// Computes an carry flag when one number is subtracted from another.
206213
template <>
207214
struct Carry<tag_sub> {
208215
template <typename T>
209-
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
216+
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
210217
static_assert(std::is_unsigned<T>::value,
211218
"Invalid specialization of `Carry::Flag` for addition.");
212-
return lhs < rhs;
219+
return __remill_flag_computation_carry(lhs < rhs, lhs, rhs, res);
213220
}
214221
};
215222

0 commit comments

Comments
 (0)