@@ -89,6 +89,8 @@ fn saturating_intrinsic_impl<'ll, 'tcx>(
89
89
is_add : bool ,
90
90
args : & [ OperandRef < ' tcx , & ' ll Value > ] ,
91
91
) -> & ' ll Value {
92
+ use crate :: intrinsic:: OverflowOp ;
93
+ use rustc_codegen_ssa:: common:: IntPredicate ;
92
94
use rustc_middle:: ty:: IntTy :: * ;
93
95
use rustc_middle:: ty:: UintTy :: * ;
94
96
@@ -107,65 +109,88 @@ fn saturating_intrinsic_impl<'ll, 'tcx>(
107
109
_ => unreachable ! ( ) ,
108
110
} ;
109
111
110
- // For 128-bit, we need to handle the constants differently
111
- if width == 128 {
112
- // For 128-bit saturating operations, use LLVM's saturating intrinsics directly
113
- let lhs = args[ 0 ] . immediate ( ) ;
114
- let rhs = args[ 1 ] . immediate ( ) ;
115
- let llvm_name = format ! (
116
- "llvm.{}{}.sat.i128" ,
117
- if signed { 's' } else { 'u' } ,
118
- if is_add { "add" } else { "sub" }
119
- ) ;
120
- return b. call_intrinsic ( & llvm_name, & [ lhs, rhs] ) ;
112
+ let llty = b. type_ix ( width as u64 ) ;
113
+ let a = args[ 0 ] . immediate ( ) ;
114
+ let c = args[ 1 ] . immediate ( ) ;
115
+
116
+ // Perform the operation and capture overflow flag
117
+ let ( val, ov_i1) = b. checked_binop (
118
+ if is_add {
119
+ OverflowOp :: Add
120
+ } else {
121
+ OverflowOp :: Sub
122
+ } ,
123
+ ty,
124
+ a,
125
+ c,
126
+ ) ;
127
+
128
+ // Common constants
129
+ let zero = b. const_int ( llty, 0 ) ;
130
+ let one = b. const_int ( llty, 1 ) ;
131
+ let all1 = b. const_int ( llty, -1 ) ;
132
+ let sh = b. const_int ( llty, ( width - 1 ) as i64 ) ;
133
+
134
+ // Convert overflow flag to mask: -1 if overflow, else 0
135
+ let ov_m = b. select ( ov_i1, all1, zero) ;
136
+
137
+ if !signed {
138
+ // MAX for add, 0 for sub
139
+ let clamp = if is_add { all1 } else { zero } ;
140
+
141
+ // Mask for non-overflow path
142
+ let keep = b. not ( ov_m) ;
143
+
144
+ // Overflow → clamp
145
+ let l = b. and ( ov_m, clamp) ;
146
+
147
+ // No overflow → result
148
+ let r = b. and ( keep, val) ;
149
+
150
+ return b. or ( l, r) ;
121
151
}
122
152
123
- let unsigned_max_value = match width {
124
- 8 => u8:: MAX as i64 ,
125
- 16 => u16:: MAX as i64 ,
126
- 32 => u32:: MAX as i64 ,
127
- 64 => u64:: MAX as i64 ,
128
- _ => unreachable ! ( ) ,
129
- } ;
153
+ // Compute INT_MIN = 1 << (w-1)
154
+ let int_min = b. shl ( one, sh) ;
130
155
131
- let ( min_value, max_value) = if signed {
132
- ( -( ( unsigned_max_value / 2 ) + 1 ) , ( unsigned_max_value / 2 ) )
133
- } else {
134
- ( 0 , unsigned_max_value)
135
- } ;
156
+ // Compute INT_MAX = INT_MIN - 1
157
+ let int_max = b. sub ( int_min, one) ;
158
+
159
+ // Mask for a < 0
160
+ let a_lt0 = b. icmp ( IntPredicate :: IntSLT , a, zero) ;
161
+ let a_neg = b. select ( a_lt0, all1, zero) ;
136
162
137
- let overflow_op = if is_add {
138
- OverflowOp :: Add
163
+ // Mask for a >= 0
164
+ let a_non = b. not ( a_neg) ;
165
+
166
+ // Mask for c < 0
167
+ let c_lt0 = b. icmp ( IntPredicate :: IntSLT , c, zero) ;
168
+ let c_neg = b. select ( c_lt0, all1, zero) ;
169
+
170
+ // Signed add overflow: a<0 → MIN, a>=0 → MAX
171
+ let sat = if is_add {
172
+ let p1 = b. and ( a_neg, int_min) ;
173
+ let p2 = b. and ( a_non, int_max) ;
174
+ b. or ( p1, p2)
139
175
} else {
140
- OverflowOp :: Sub
176
+ // Signed sub overflow: (a>=0 && c<0) → MAX, else MIN
177
+ let to_max = b. and ( a_non, c_neg) ;
178
+ let to_min = b. not ( to_max) ;
179
+ let p1 = b. and ( to_max, int_max) ;
180
+ let p2 = b. and ( to_min, int_min) ;
181
+ b. or ( p1, p2)
141
182
} ;
142
- let llty = b. type_ix ( width as u64 ) ;
143
- let lhs = args[ 0 ] . immediate ( ) ;
144
- let rhs = args[ 1 ] . immediate ( ) ;
145
183
146
- let ( val, overflowed) = b. checked_binop ( overflow_op, ty, lhs, rhs) ;
184
+ // Mask for non-overflow path
185
+ let keep = b. not ( ov_m) ;
147
186
148
- if !signed {
149
- let select_val = if is_add {
150
- b. const_int ( llty, -1 )
151
- } else {
152
- b. const_int ( llty, 0 )
153
- } ;
154
- b. select ( overflowed, select_val, val)
155
- } else {
156
- let const_val = b. const_int ( llty, ( width - 1 ) as i64 ) ;
157
- let first_val = if is_add {
158
- b. ashr ( rhs, const_val)
159
- } else {
160
- b. lshr ( rhs, const_val)
161
- } ;
162
- let second_val = if is_add {
163
- b. unchecked_uadd ( first_val, b. const_int ( llty, max_value) )
164
- } else {
165
- b. xor ( first_val, b. const_int ( llty, min_value) )
166
- } ;
167
- b. select ( overflowed, second_val, val)
168
- }
187
+ // Overflow → sat value
188
+ let l = b. and ( ov_m, sat) ;
189
+
190
+ // No overflow → result
191
+ let r = b. and ( keep, val) ;
192
+
193
+ b. or ( l, r)
169
194
}
170
195
171
196
fn get_simple_intrinsic < ' ll > (
0 commit comments