host-utils: Introduce signed saturation primitives
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Richard Henderson committed
Apr 29, 2026 at 04:32 UTC
16495533131af2eb94019e32c72688ea5e1b2742
2 files changed
+64
-16
accel/tcg/tcg-runtime-gvec.c
+4
-16
@@ -1109,10 +1109,7 @@ void HELPER(gvec_ssadd32)(void *d, void *a, void *b, uint32_t desc)
1109
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
1110
int32_t ai = *(int32_t *)(a + i);
1111
int32_t bi = *(int32_t *)(b + i);
1112
- int32_t di;
1113
- if (sadd32_overflow(ai, bi, &di)) {
1114
- di = (di < 0 ? INT32_MAX : INT32_MIN);
1115
- }
1112
+ int32_t di = sadd32_saturate(ai, bi);
1113
*(int32_t *)(d + i) = di;
1114
}
1115
clear_high(d, oprsz, desc);
@@ -1126,10 +1123,7 @@ void HELPER(gvec_ssadd64)(void *d, void *a, void *b, uint32_t desc)
1123
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
1124
int64_t ai = *(int64_t *)(a + i);
1125
int64_t bi = *(int64_t *)(b + i);
1129
- int64_t di;
1130
- if (sadd64_overflow(ai, bi, &di)) {
1131
- di = (di < 0 ? INT64_MAX : INT64_MIN);
1132
- }
1126
+ int64_t di = sadd64_saturate(ai, bi);
1127
*(int64_t *)(d + i) = di;
1128
}
1129
clear_high(d, oprsz, desc);
@@ -1177,10 +1171,7 @@ void HELPER(gvec_sssub32)(void *d, void *a, void *b, uint32_t desc)
1171
for (i = 0; i < oprsz; i += sizeof(int32_t)) {
1172
int32_t ai = *(int32_t *)(a + i);
1173
int32_t bi = *(int32_t *)(b + i);
1180
- int32_t di;
1181
- if (ssub32_overflow(ai, bi, &di)) {
1182
- di = (di < 0 ? INT32_MAX : INT32_MIN);
1183
- }
1174
+ int32_t di = ssub32_saturate(ai, bi);
1175
*(int32_t *)(d + i) = di;
1176
}
1177
clear_high(d, oprsz, desc);
@@ -1194,10 +1185,7 @@ void HELPER(gvec_sssub64)(void *d, void *a, void *b, uint32_t desc)
1185
for (i = 0; i < oprsz; i += sizeof(int64_t)) {
1186
int64_t ai = *(int64_t *)(a + i);
1187
int64_t bi = *(int64_t *)(b + i);
1197
- int64_t di;
1198
- if (ssub64_overflow(ai, bi, &di)) {
1199
- di = (di < 0 ? INT64_MAX : INT64_MIN);
1200
- }
1188
+ int64_t di = ssub64_saturate(ai, bi);
1189
*(int64_t *)(d + i) = di;
1190
}
1191
clear_high(d, oprsz, desc);
include/qemu/host-utils.h
+60
@@ -606,6 +606,66 @@ static inline bool umul64_overflow(uint64_t x, uint64_t y, uint64_t *ret)
606
return __builtin_mul_overflow(x, y, ret);
607
}
608
609
+/**
610
+ * sadd32_saturate - addition with saturation
611
+ * @x, @y: addends
612
+ *
613
+ * Computes @x + @y, and saturates rathern than truncating the result.
614
+ */
615
+static inline int32_t sadd32_saturate(int32_t x, int32_t y)
616
+{
617
+ int32_t ret;
618
+ if (sadd32_overflow(x, y, &ret)) {
619
+ ret = y < 0 ? INT32_MIN : INT32_MAX;
620
+ }
621
+ return ret;
622
+}
623
+
624
+/**
625
+ * sadd64_saturate - addition with saturation
626
+ * @x, @y: addends
627
+ *
628
+ * Computes @x + @y, and saturates rathern than truncating the result.
629
+ */
630
+static inline int64_t sadd64_saturate(int64_t x, int64_t y)
631
+{
632
+ int64_t ret;
633
+ if (sadd64_overflow(x, y, &ret)) {
634
+ ret = y < 0 ? INT64_MIN : INT64_MAX;
635
+ }
636
+ return ret;
637
+}
638
+
639
+/**
640
+ * ssub32_saturate - subtraction with saturation
641
+ * @x, @y: addends
642
+ *
643
+ * Computes @x + @y, and saturates rathern than truncating the result.
644
+ */
645
+static inline bool ssub32_saturate(int32_t x, int32_t y)
646
+{
647
+ int32_t ret;
648
+ if (ssub32_overflow(x, y, &ret)) {
649
+ ret = x < 0 ? INT32_MAX : INT32_MIN;
650
+ }
651
+ return ret;
652
+}
653
+
654
+/**
655
+ * ssub64_saturate - subtraction with saturation
656
+ * @x, @y: addends
657
+ *
658
+ * Computes @x + @y, and saturates rathern than truncating the result.
659
+ */
660
+static inline bool ssub64_saturate(int64_t x, int64_t y)
661
+{
662
+ int64_t ret;
663
+ if (ssub64_overflow(x, y, &ret)) {
664
+ ret = x < 0 ? INT64_MAX : INT64_MIN;
665
+ }
666
+ return ret;
667
+}
668
+
669
/*
670
* Unsigned 128x64 multiplication.
671
* Returns true if the result got truncated to 128 bits.