]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/int.rs
Auto merge of #93530 - anonion0:pthread_sigmask_fix, r=JohnTitor
[rust.git] / compiler / rustc_codegen_gcc / src / int.rs
1 //! Module to handle integer operations.
2 //! This module exists because some integer types are not supported on some gcc platforms, e.g.
3 //! 128-bit integers on 32-bit platforms and thus require to be handled manually.
4
5 use std::convert::TryFrom;
6
7 use gccjit::{ComparisonOp, FunctionType, RValue, ToRValue, Type, UnaryOp, BinaryOp};
8 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
9 use rustc_codegen_ssa::traits::{BackendTypes, BaseTypeMethods, BuilderMethods, OverflowOp};
10 use rustc_middle::ty::Ty;
11
12 use crate::builder::ToGccComp;
13 use crate::{builder::Builder, common::{SignType, TypeReflection}, context::CodegenCx};
14
15 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
16     pub fn gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
17         // 128-bit unsigned %: __umodti3
18         self.multiplicative_operation(BinaryOp::Modulo, "mod", false, a, b)
19     }
20
21     pub fn gcc_srem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
22         // 128-bit signed %:   __modti3
23         self.multiplicative_operation(BinaryOp::Modulo, "mod", true, a, b)
24     }
25
26     pub fn gcc_not(&self, a: RValue<'gcc>) -> RValue<'gcc> {
27         let typ = a.get_type();
28         if self.is_native_int_type_or_bool(typ) {
29             let operation =
30                 if typ.is_bool() {
31                     UnaryOp::LogicalNegate
32                 }
33                 else {
34                     UnaryOp::BitwiseNegate
35                 };
36             self.cx.context.new_unary_op(None, operation, typ, a)
37         }
38         else {
39             // TODO(antoyo): use __negdi2 and __negti2 instead?
40             let element_type = typ.dyncast_array().expect("element type");
41             let values = [
42                 self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.low(a)),
43                 self.cx.context.new_unary_op(None, UnaryOp::BitwiseNegate, element_type, self.high(a)),
44             ];
45             self.cx.context.new_array_constructor(None, typ, &values)
46         }
47     }
48
49     pub fn gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc> {
50         let a_type = a.get_type();
51         if self.is_native_int_type(a_type) {
52             self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
53         }
54         else {
55             let param_a = self.context.new_parameter(None, a_type, "a");
56             let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a], "__negti2", false);
57             self.context.new_call(None, func, &[a])
58         }
59     }
60
61     pub fn gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
62         self.cx.bitwise_operation(BinaryOp::BitwiseAnd, a, b)
63     }
64
65     pub fn gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
66         let a_type = a.get_type();
67         let b_type = b.get_type();
68         let a_native = self.is_native_int_type(a_type);
69         let b_native = self.is_native_int_type(b_type);
70         if a_native && b_native {
71             // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by a signed number.
72             // TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
73             if a_type.is_signed(self) != b_type.is_signed(self) {
74                 let b = self.context.new_cast(None, b, a_type);
75                 a >> b
76             }
77             else {
78                 a >> b
79             }
80         }
81         else if a_native && !b_native {
82             self.gcc_lshr(a, self.gcc_int_cast(b, a_type))
83         }
84         else {
85             // NOTE: we cannot use the lshr builtin because it's calling hi() (to get the most
86             // significant half of the number) which uses lshr.
87
88             let native_int_type = a_type.dyncast_array().expect("get element type");
89
90             let func = self.current_func();
91             let then_block = func.new_block("then");
92             let else_block = func.new_block("else");
93             let after_block = func.new_block("after");
94             let b0_block = func.new_block("b0");
95             let actual_else_block = func.new_block("actual_else");
96
97             let result = func.new_local(None, a_type, "shiftResult");
98
99             let sixty_four = self.gcc_int(native_int_type, 64);
100             let sixty_three = self.gcc_int(native_int_type, 63);
101             let zero = self.gcc_zero(native_int_type);
102             let b = self.gcc_int_cast(b, native_int_type);
103             let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
104             self.llbb().end_with_conditional(None, condition, then_block, else_block);
105
106             // TODO(antoyo): take endianness into account.
107             let shift_value = self.gcc_sub(b, sixty_four);
108             let high = self.high(a);
109             let sign =
110                 if a_type.is_signed(self) {
111                     high >> sixty_three
112                 }
113                 else {
114                     zero
115                 };
116             let values = [
117                 high >> shift_value,
118                 sign,
119             ];
120             let array_value = self.context.new_array_constructor(None, a_type, &values);
121             then_block.add_assignment(None, result, array_value);
122             then_block.end_with_jump(None, after_block);
123
124             let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero);
125             else_block.end_with_conditional(None, condition, b0_block, actual_else_block);
126
127             b0_block.add_assignment(None, result, a);
128             b0_block.end_with_jump(None, after_block);
129
130             let shift_value = self.gcc_sub(sixty_four, b);
131             // NOTE: cast low to its unsigned type in order to perform a logical right shift.
132             let unsigned_type = native_int_type.to_unsigned(&self.cx);
133             let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
134             let shifted_low = casted_low >> self.context.new_cast(None, b, unsigned_type);
135             let shifted_low = self.context.new_cast(None, shifted_low, native_int_type);
136             let values = [
137                 (high << shift_value) | shifted_low,
138                 high >> b,
139             ];
140             let array_value = self.context.new_array_constructor(None, a_type, &values);
141             actual_else_block.add_assignment(None, result, array_value);
142             actual_else_block.end_with_jump(None, after_block);
143
144             // NOTE: since jumps were added in a place rustc does not expect, the current block in the
145             // state need to be updated.
146             self.switch_to_block(after_block);
147
148             result.to_rvalue()
149         }
150     }
151
152     fn additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
153         let a_type = a.get_type();
154         let b_type = b.get_type();
155         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
156             if a.get_type() != b.get_type() {
157                 b = self.context.new_cast(None, b, a.get_type());
158             }
159             self.context.new_binary_op(None, operation, a_type, a, b)
160         }
161         else {
162             let signed = a_type.is_compatible_with(self.i128_type);
163             let func_name =
164                 match (operation, signed) {
165                     (BinaryOp::Plus, true) => "__rust_i128_add",
166                     (BinaryOp::Plus, false) => "__rust_u128_add",
167                     (BinaryOp::Minus, true) => "__rust_i128_sub",
168                     (BinaryOp::Minus, false) => "__rust_u128_sub",
169                     _ => unreachable!("unexpected additive operation {:?}", operation),
170                 };
171             let param_a = self.context.new_parameter(None, a_type, "a");
172             let param_b = self.context.new_parameter(None, b_type, "b");
173             let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false);
174             self.context.new_call(None, func, &[a, b])
175         }
176     }
177
178     pub fn gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
179         self.additive_operation(BinaryOp::Plus, a, b)
180     }
181
182     pub fn gcc_mul(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
183         self.multiplicative_operation(BinaryOp::Mult, "mul", true, a, b)
184     }
185
186     pub fn gcc_sub(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
187         self.additive_operation(BinaryOp::Minus, a, b)
188     }
189
190     fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
191         let a_type = a.get_type();
192         let b_type = b.get_type();
193         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
194             self.context.new_binary_op(None, operation, a_type, a, b)
195         }
196         else {
197             let sign =
198                 if signed {
199                     ""
200                 }
201                 else {
202                     "u"
203                 };
204             let func_name = format!("__{}{}ti3", sign, operation_name);
205             let param_a = self.context.new_parameter(None, a_type, "a");
206             let param_b = self.context.new_parameter(None, b_type, "b");
207             let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false);
208             self.context.new_call(None, func, &[a, b])
209         }
210     }
211
212     pub fn gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
213         // TODO(antoyo): check if the types are signed?
214         // 128-bit, signed: __divti3
215         // TODO(antoyo): convert the arguments to signed?
216         self.multiplicative_operation(BinaryOp::Divide, "div", true, a, b)
217     }
218
219     pub fn gcc_udiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
220         // 128-bit, unsigned: __udivti3
221         self.multiplicative_operation(BinaryOp::Divide, "div", false, a, b)
222     }
223
224     pub fn gcc_checked_binop(&self, oop: OverflowOp, typ: Ty<'_>, lhs: <Self as BackendTypes>::Value, rhs: <Self as BackendTypes>::Value) -> (<Self as BackendTypes>::Value, <Self as BackendTypes>::Value) {
225         use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
226
227         let new_kind =
228             match typ.kind() {
229                 Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
230                 Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
231                 t @ (Uint(_) | Int(_)) => t.clone(),
232                 _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
233             };
234
235         // TODO(antoyo): remove duplication with intrinsic?
236         let name =
237             if self.is_native_int_type(lhs.get_type()) {
238                 match oop {
239                     OverflowOp::Add =>
240                         match new_kind {
241                             Int(I8) => "__builtin_add_overflow",
242                             Int(I16) => "__builtin_add_overflow",
243                             Int(I32) => "__builtin_sadd_overflow",
244                             Int(I64) => "__builtin_saddll_overflow",
245                             Int(I128) => "__builtin_add_overflow",
246
247                             Uint(U8) => "__builtin_add_overflow",
248                             Uint(U16) => "__builtin_add_overflow",
249                             Uint(U32) => "__builtin_uadd_overflow",
250                             Uint(U64) => "__builtin_uaddll_overflow",
251                             Uint(U128) => "__builtin_add_overflow",
252
253                             _ => unreachable!(),
254                         },
255                     OverflowOp::Sub =>
256                         match new_kind {
257                             Int(I8) => "__builtin_sub_overflow",
258                             Int(I16) => "__builtin_sub_overflow",
259                             Int(I32) => "__builtin_ssub_overflow",
260                             Int(I64) => "__builtin_ssubll_overflow",
261                             Int(I128) => "__builtin_sub_overflow",
262
263                             Uint(U8) => "__builtin_sub_overflow",
264                             Uint(U16) => "__builtin_sub_overflow",
265                             Uint(U32) => "__builtin_usub_overflow",
266                             Uint(U64) => "__builtin_usubll_overflow",
267                             Uint(U128) => "__builtin_sub_overflow",
268
269                             _ => unreachable!(),
270                         },
271                     OverflowOp::Mul =>
272                         match new_kind {
273                             Int(I8) => "__builtin_mul_overflow",
274                             Int(I16) => "__builtin_mul_overflow",
275                             Int(I32) => "__builtin_smul_overflow",
276                             Int(I64) => "__builtin_smulll_overflow",
277                             Int(I128) => "__builtin_mul_overflow",
278
279                             Uint(U8) => "__builtin_mul_overflow",
280                             Uint(U16) => "__builtin_mul_overflow",
281                             Uint(U32) => "__builtin_umul_overflow",
282                             Uint(U64) => "__builtin_umulll_overflow",
283                             Uint(U128) => "__builtin_mul_overflow",
284
285                             _ => unreachable!(),
286                         },
287                 }
288             }
289             else {
290                 match new_kind {
291                     Int(I128) | Uint(U128) => {
292                         let func_name =
293                             match oop {
294                                 OverflowOp::Add =>
295                                     match new_kind {
296                                         Int(I128) => "__rust_i128_addo",
297                                         Uint(U128) => "__rust_u128_addo",
298                                         _ => unreachable!(),
299                                     },
300                                 OverflowOp::Sub =>
301                                     match new_kind {
302                                         Int(I128) => "__rust_i128_subo",
303                                         Uint(U128) => "__rust_u128_subo",
304                                         _ => unreachable!(),
305                                     },
306                                 OverflowOp::Mul =>
307                                     match new_kind {
308                                         Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead?
309                                         Uint(U128) => "__rust_u128_mulo",
310                                         _ => unreachable!(),
311                                     },
312                             };
313                         let a_type = lhs.get_type();
314                         let b_type = rhs.get_type();
315                         let param_a = self.context.new_parameter(None, a_type, "a");
316                         let param_b = self.context.new_parameter(None, b_type, "b");
317                         let result_field = self.context.new_field(None, a_type, "result");
318                         let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
319                         let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
320                         let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
321                         let result = self.context.new_call(None, func, &[lhs, rhs]);
322                         let overflow = result.access_field(None, overflow_field);
323                         let int_result = result.access_field(None, result_field);
324                         return (int_result, overflow);
325                     },
326                     _ => {
327                         match oop {
328                             OverflowOp::Mul =>
329                                 match new_kind {
330                                     Int(I32) => "__mulosi4",
331                                     Int(I64) => "__mulodi4",
332                                     _ => unreachable!(),
333                                 },
334                             _ => unimplemented!("overflow operation for {:?}", new_kind),
335                         }
336                     }
337                 }
338             };
339
340         let intrinsic = self.context.get_builtin_function(&name);
341         let res = self.current_func()
342             // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
343             .new_local(None, rhs.get_type(), "binopResult")
344             .get_address(None);
345         let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
346         (res.dereference(None).to_rvalue(), overflow)
347     }
348
349     pub fn gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
350         let a_type = lhs.get_type();
351         let b_type = rhs.get_type();
352         if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) {
353             let signed = a_type.is_compatible_with(self.i128_type);
354             let sign =
355                 if signed {
356                     ""
357                 }
358                 else {
359                     "u"
360                 };
361             let func_name = format!("__{}cmpti2", sign);
362             let param_a = self.context.new_parameter(None, a_type, "a");
363             let param_b = self.context.new_parameter(None, b_type, "b");
364             let func = self.context.new_function(None, FunctionType::Extern, self.int_type, &[param_a, param_b], func_name, false);
365             let cmp = self.context.new_call(None, func, &[lhs, rhs]);
366             let (op, limit) =
367                 match op {
368                     IntPredicate::IntEQ => {
369                         return self.context.new_comparison(None, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type));
370                     },
371                     IntPredicate::IntNE => {
372                         return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type));
373                     },
374                     IntPredicate::IntUGT => (ComparisonOp::Equals, 2),
375                     IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1),
376                     IntPredicate::IntULT => (ComparisonOp::Equals, 0),
377                     IntPredicate::IntULE => (ComparisonOp::LessThanEquals, 1),
378                     IntPredicate::IntSGT => (ComparisonOp::Equals, 2),
379                     IntPredicate::IntSGE => (ComparisonOp::GreaterThanEquals, 1),
380                     IntPredicate::IntSLT => (ComparisonOp::Equals, 0),
381                     IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1),
382                 };
383             self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit))
384         }
385         else {
386             let left_type = lhs.get_type();
387             let right_type = rhs.get_type();
388             if left_type != right_type {
389                 // NOTE: because libgccjit cannot compare function pointers.
390                 if left_type.dyncast_function_ptr_type().is_some() && right_type.dyncast_function_ptr_type().is_some() {
391                     lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
392                     rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
393                 }
394                 // NOTE: hack because we try to cast a vector type to the same vector type.
395                 else if format!("{:?}", left_type) != format!("{:?}", right_type) {
396                     rhs = self.context.new_cast(None, rhs, left_type);
397                 }
398             }
399             self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
400         }
401     }
402
403     pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
404         let a_type = a.get_type();
405         let b_type = b.get_type();
406         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
407             a ^ b
408         }
409         else {
410             let values = [
411                 self.low(a) ^ self.low(b),
412                 self.high(a) ^ self.high(b),
413             ];
414             self.context.new_array_constructor(None, a_type, &values)
415         }
416     }
417
418     pub fn gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
419         let a_type = a.get_type();
420         let b_type = b.get_type();
421         let a_native = self.is_native_int_type(a_type);
422         let b_native = self.is_native_int_type(b_type);
423         if a_native && b_native {
424             // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
425             if a_type.is_unsigned(self) && b_type.is_signed(self) {
426                 let a = self.context.new_cast(None, a, b_type);
427                 let result = a << b;
428                 self.context.new_cast(None, result, a_type)
429             }
430             else if a_type.is_signed(self) && b_type.is_unsigned(self) {
431                 let b = self.context.new_cast(None, b, a_type);
432                 a << b
433             }
434             else {
435                 a << b
436             }
437         }
438         else if a_native && !b_native {
439             self.gcc_shl(a, self.gcc_int_cast(b, a_type))
440         }
441         else {
442             // NOTE: we cannot use the ashl builtin because it's calling widen_hi() which uses ashl.
443             let native_int_type = a_type.dyncast_array().expect("get element type");
444
445             let func = self.current_func();
446             let then_block = func.new_block("then");
447             let else_block = func.new_block("else");
448             let after_block = func.new_block("after");
449             let b0_block = func.new_block("b0");
450             let actual_else_block = func.new_block("actual_else");
451
452             let result = func.new_local(None, a_type, "shiftResult");
453
454             let b = self.gcc_int_cast(b, native_int_type);
455             let sixty_four = self.gcc_int(native_int_type, 64);
456             let zero = self.gcc_zero(native_int_type);
457             let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
458             self.llbb().end_with_conditional(None, condition, then_block, else_block);
459
460             // TODO(antoyo): take endianness into account.
461             let values = [
462                 zero,
463                 self.low(a) << (b - sixty_four),
464             ];
465             let array_value = self.context.new_array_constructor(None, a_type, &values);
466             then_block.add_assignment(None, result, array_value);
467             then_block.end_with_jump(None, after_block);
468
469             let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero);
470             else_block.end_with_conditional(None, condition, b0_block, actual_else_block);
471
472             b0_block.add_assignment(None, result, a);
473             b0_block.end_with_jump(None, after_block);
474
475             // NOTE: cast low to its unsigned type in order to perform a logical right shift.
476             let unsigned_type = native_int_type.to_unsigned(&self.cx);
477             let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
478             let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type);
479             let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type);
480             let values = [
481                 self.low(a) << b,
482                 (self.high(a) << b) | high_low,
483             ];
484
485             let array_value = self.context.new_array_constructor(None, a_type, &values);
486             actual_else_block.add_assignment(None, result, array_value);
487             actual_else_block.end_with_jump(None, after_block);
488
489             // NOTE: since jumps were added in a place rustc does not expect, the current block in the
490             // state need to be updated.
491             self.switch_to_block(after_block);
492
493             result.to_rvalue()
494         }
495     }
496
497     pub fn gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc> {
498         let arg_type = arg.get_type();
499         if !self.is_native_int_type(arg_type) {
500             let native_int_type = arg_type.dyncast_array().expect("get element type");
501             let lsb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 0)).to_rvalue();
502             let swapped_lsb = self.gcc_bswap(lsb, width / 2);
503             let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type);
504             let msb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 1)).to_rvalue();
505             let swapped_msb = self.gcc_bswap(msb, width / 2);
506             let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type);
507
508             // NOTE: we also need to swap the two elements here, in addition to swapping inside
509             // the elements themselves like done above.
510             return self.context.new_array_constructor(None, arg_type, &[swapped_msb, swapped_lsb]);
511         }
512
513         // TODO(antoyo): check if it's faster to use string literals and a
514         // match instead of format!.
515         let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width));
516         // FIXME(antoyo): this cast should not be necessary. Remove
517         // when having proper sized integer types.
518         let param_type = bswap.get_param(0).to_rvalue().get_type();
519         if param_type != arg_type {
520             arg = self.bitcast(arg, param_type);
521         }
522         self.cx.context.new_call(None, bswap, &[arg])
523     }
524 }
525
526 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
527     pub fn gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
528         if self.is_native_int_type_or_bool(typ) {
529             self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from"))
530         }
531         else {
532             // NOTE: set the sign in high.
533             self.from_low_high(typ, int, -(int.is_negative() as i64))
534         }
535     }
536
537     pub fn gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
538         if self.is_native_int_type_or_bool(typ) {
539             self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
540         }
541         else {
542             self.from_low_high(typ, int as i64, 0)
543         }
544     }
545
546     pub fn gcc_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
547         let low = num as u64;
548         let high = (num >> 64) as u64;
549         if num >> 64 != 0 {
550             // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
551             if self.is_native_int_type(typ) {
552                 let low = self.context.new_rvalue_from_long(self.u64_type, low as i64);
553                 let high = self.context.new_rvalue_from_long(typ, high as i64);
554
555                 let sixty_four = self.context.new_rvalue_from_long(typ, 64);
556                 let shift = high << sixty_four;
557                 shift | self.context.new_cast(None, low, typ)
558             }
559             else {
560                 self.from_low_high(typ, low as i64, high as i64)
561             }
562         }
563         else if typ.is_i128(self) {
564             let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
565             self.gcc_int_cast(num, typ)
566         }
567         else {
568             self.gcc_uint(typ, num as u64)
569         }
570     }
571
572     pub fn gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc> {
573         if self.is_native_int_type_or_bool(typ) {
574             self.context.new_rvalue_zero(typ)
575         }
576         else {
577             self.from_low_high(typ, 0, 0)
578         }
579     }
580
581     pub fn gcc_int_width(&self, typ: Type<'gcc>) -> u64 {
582         if self.is_native_int_type_or_bool(typ) {
583             typ.get_size() as u64 * 8
584         }
585         else {
586             // NOTE: the only unsupported types are u128 and i128.
587             128
588         }
589     }
590
591     fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
592         let a_type = a.get_type();
593         let b_type = b.get_type();
594         let a_native = self.is_native_int_type_or_bool(a_type);
595         let b_native = self.is_native_int_type_or_bool(b_type);
596         if a_native && b_native {
597             if a_type != b_type {
598                 b = self.context.new_cast(None, b, a_type);
599             }
600             self.context.new_binary_op(None, operation, a_type, a, b)
601         }
602         else {
603             assert!(!a_native && !b_native, "both types should either be native or non-native for or operation");
604             let native_int_type = a_type.dyncast_array().expect("get element type");
605             let values = [
606                 self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)),
607                 self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)),
608             ];
609             self.context.new_array_constructor(None, a_type, &values)
610         }
611     }
612
613     pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
614         self.bitwise_operation(BinaryOp::BitwiseOr, a, b)
615     }
616
617     // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead?
618     pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
619         let value_type = value.get_type();
620         if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) {
621             self.context.new_cast(None, value, dest_typ)
622         }
623         else if self.is_native_int_type_or_bool(dest_typ) {
624             self.context.new_cast(None, self.low(value), dest_typ)
625         }
626         else if self.is_native_int_type_or_bool(value_type) {
627             let dest_element_type = dest_typ.dyncast_array().expect("get element type");
628
629             // NOTE: set the sign of the value.
630             let zero = self.context.new_rvalue_zero(value_type);
631             let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero);
632             let is_negative = self.gcc_int_cast(is_negative, dest_element_type);
633             let values = [
634                 self.context.new_cast(None, value, dest_element_type),
635                 self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative),
636             ];
637             self.context.new_array_constructor(None, dest_typ, &values)
638         }
639         else {
640             // Since u128 and i128 are the only types that can be unsupported, we know the type of
641             // value and the destination type have the same size, so a bitcast is fine.
642             self.context.new_bitcast(None, value, dest_typ)
643         }
644     }
645
646     fn int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
647         let value_type = value.get_type();
648         if self.is_native_int_type_or_bool(value_type) {
649             return self.context.new_cast(None, value, dest_typ);
650         }
651
652         let name_suffix =
653             match self.type_kind(dest_typ) {
654                 TypeKind::Float => "tisf",
655                 TypeKind::Double => "tidf",
656                 kind => panic!("cannot cast a non-native integer to type {:?}", kind),
657             };
658         let sign =
659             if signed {
660                 ""
661             }
662             else {
663                 "un"
664             };
665         let func_name = format!("__float{}{}", sign, name_suffix);
666         let param = self.context.new_parameter(None, value_type, "n");
667         let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false);
668         self.context.new_call(None, func, &[value])
669     }
670
671     pub fn gcc_int_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
672         self.int_to_float_cast(true, value, dest_typ)
673     }
674
675     pub fn gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
676         self.int_to_float_cast(false, value, dest_typ)
677     }
678
679     fn float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
680         let value_type = value.get_type();
681         if self.is_native_int_type_or_bool(dest_typ) {
682             return self.context.new_cast(None, value, dest_typ);
683         }
684
685         let name_suffix =
686             match self.type_kind(value_type) {
687                 TypeKind::Float => "sfti",
688                 TypeKind::Double => "dfti",
689                 kind => panic!("cannot cast a {:?} to non-native integer", kind),
690             };
691         let sign =
692             if signed {
693                 ""
694             }
695             else {
696                 "uns"
697             };
698         let func_name = format!("__fix{}{}", sign, name_suffix);
699         let param = self.context.new_parameter(None, value_type, "n");
700         let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false);
701         self.context.new_call(None, func, &[value])
702     }
703
704     pub fn gcc_float_to_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
705         self.float_to_int_cast(true, value, dest_typ)
706     }
707
708     pub fn gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
709         self.float_to_int_cast(false, value, dest_typ)
710     }
711
712     fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> {
713         self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 1))
714             .to_rvalue()
715     }
716
717     fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> {
718         self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 0))
719             .to_rvalue()
720     }
721
722     fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> {
723         let native_int_type = typ.dyncast_array().expect("get element type");
724         let values = [
725             self.context.new_rvalue_from_long(native_int_type, low),
726             self.context.new_rvalue_from_long(native_int_type, high),
727         ];
728         self.context.new_array_constructor(None, typ, &values)
729     }
730 }