• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> {
gcc_urem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>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 
gcc_srem(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>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 
gcc_not(&self, a: RValue<'gcc>) -> RValue<'gcc>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 
gcc_neg(&self, a: RValue<'gcc>) -> RValue<'gcc>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 
gcc_and(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>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 
gcc_lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>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 
additive_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc>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_type != b_type {
157                 if a_type.is_vector() {
158                     // Vector types need to be bitcast.
159                     // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
160                     b = self.context.new_bitcast(None, b, a.get_type());
161                 }
162                 else {
163                     b = self.context.new_cast(None, b, a.get_type());
164                 }
165             }
166             self.context.new_binary_op(None, operation, a_type, a, b)
167         }
168         else {
169             let signed = a_type.is_compatible_with(self.i128_type);
170             let func_name =
171                 match (operation, signed) {
172                     (BinaryOp::Plus, true) => "__rust_i128_add",
173                     (BinaryOp::Plus, false) => "__rust_u128_add",
174                     (BinaryOp::Minus, true) => "__rust_i128_sub",
175                     (BinaryOp::Minus, false) => "__rust_u128_sub",
176                     _ => unreachable!("unexpected additive operation {:?}", operation),
177                 };
178             let param_a = self.context.new_parameter(None, a_type, "a");
179             let param_b = self.context.new_parameter(None, b_type, "b");
180             let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false);
181             self.context.new_call(None, func, &[a, b])
182         }
183     }
184 
gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>185     pub fn gcc_add(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
186         self.additive_operation(BinaryOp::Plus, a, b)
187     }
188 
gcc_mul(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>189     pub fn gcc_mul(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
190         self.multiplicative_operation(BinaryOp::Mult, "mul", true, a, b)
191     }
192 
gcc_sub(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>193     pub fn gcc_sub(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
194         self.additive_operation(BinaryOp::Minus, a, b)
195     }
196 
multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>197     fn multiplicative_operation(&self, operation: BinaryOp, operation_name: &str, signed: bool, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
198         let a_type = a.get_type();
199         let b_type = b.get_type();
200         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
201             self.context.new_binary_op(None, operation, a_type, a, b)
202         }
203         else {
204             let sign =
205                 if signed {
206                     ""
207                 }
208                 else {
209                     "u"
210                 };
211             let func_name = format!("__{}{}ti3", sign, operation_name);
212             let param_a = self.context.new_parameter(None, a_type, "a");
213             let param_b = self.context.new_parameter(None, b_type, "b");
214             let func = self.context.new_function(None, FunctionType::Extern, a_type, &[param_a, param_b], func_name, false);
215             self.context.new_call(None, func, &[a, b])
216         }
217     }
218 
gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>219     pub fn gcc_sdiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
220         // TODO(antoyo): check if the types are signed?
221         // 128-bit, signed: __divti3
222         // TODO(antoyo): convert the arguments to signed?
223         self.multiplicative_operation(BinaryOp::Divide, "div", true, a, b)
224     }
225 
gcc_udiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>226     pub fn gcc_udiv(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
227         // 128-bit, unsigned: __udivti3
228         self.multiplicative_operation(BinaryOp::Divide, "div", false, a, b)
229     }
230 
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)231     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) {
232         use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
233 
234         let new_kind =
235             match typ.kind() {
236                 Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
237                 Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
238                 t @ (Uint(_) | Int(_)) => t.clone(),
239                 _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
240             };
241 
242         // TODO(antoyo): remove duplication with intrinsic?
243         let name =
244             if self.is_native_int_type(lhs.get_type()) {
245                 match oop {
246                     OverflowOp::Add =>
247                         match new_kind {
248                             Int(I8) => "__builtin_add_overflow",
249                             Int(I16) => "__builtin_add_overflow",
250                             Int(I32) => "__builtin_sadd_overflow",
251                             Int(I64) => "__builtin_saddll_overflow",
252                             Int(I128) => "__builtin_add_overflow",
253 
254                             Uint(U8) => "__builtin_add_overflow",
255                             Uint(U16) => "__builtin_add_overflow",
256                             Uint(U32) => "__builtin_uadd_overflow",
257                             Uint(U64) => "__builtin_uaddll_overflow",
258                             Uint(U128) => "__builtin_add_overflow",
259 
260                             _ => unreachable!(),
261                         },
262                     OverflowOp::Sub =>
263                         match new_kind {
264                             Int(I8) => "__builtin_sub_overflow",
265                             Int(I16) => "__builtin_sub_overflow",
266                             Int(I32) => "__builtin_ssub_overflow",
267                             Int(I64) => "__builtin_ssubll_overflow",
268                             Int(I128) => "__builtin_sub_overflow",
269 
270                             Uint(U8) => "__builtin_sub_overflow",
271                             Uint(U16) => "__builtin_sub_overflow",
272                             Uint(U32) => "__builtin_usub_overflow",
273                             Uint(U64) => "__builtin_usubll_overflow",
274                             Uint(U128) => "__builtin_sub_overflow",
275 
276                             _ => unreachable!(),
277                         },
278                     OverflowOp::Mul =>
279                         match new_kind {
280                             Int(I8) => "__builtin_mul_overflow",
281                             Int(I16) => "__builtin_mul_overflow",
282                             Int(I32) => "__builtin_smul_overflow",
283                             Int(I64) => "__builtin_smulll_overflow",
284                             Int(I128) => "__builtin_mul_overflow",
285 
286                             Uint(U8) => "__builtin_mul_overflow",
287                             Uint(U16) => "__builtin_mul_overflow",
288                             Uint(U32) => "__builtin_umul_overflow",
289                             Uint(U64) => "__builtin_umulll_overflow",
290                             Uint(U128) => "__builtin_mul_overflow",
291 
292                             _ => unreachable!(),
293                         },
294                 }
295             }
296             else {
297                 match new_kind {
298                     Int(I128) | Uint(U128) => {
299                         let func_name =
300                             match oop {
301                                 OverflowOp::Add =>
302                                     match new_kind {
303                                         Int(I128) => "__rust_i128_addo",
304                                         Uint(U128) => "__rust_u128_addo",
305                                         _ => unreachable!(),
306                                     },
307                                 OverflowOp::Sub =>
308                                     match new_kind {
309                                         Int(I128) => "__rust_i128_subo",
310                                         Uint(U128) => "__rust_u128_subo",
311                                         _ => unreachable!(),
312                                     },
313                                 OverflowOp::Mul =>
314                                     match new_kind {
315                                         Int(I128) => "__rust_i128_mulo", // TODO(antoyo): use __muloti4d instead?
316                                         Uint(U128) => "__rust_u128_mulo",
317                                         _ => unreachable!(),
318                                     },
319                             };
320                         let a_type = lhs.get_type();
321                         let b_type = rhs.get_type();
322                         let param_a = self.context.new_parameter(None, a_type, "a");
323                         let param_b = self.context.new_parameter(None, b_type, "b");
324                         let result_field = self.context.new_field(None, a_type, "result");
325                         let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
326                         let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
327                         let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
328                         let result = self.context.new_call(None, func, &[lhs, rhs]);
329                         let overflow = result.access_field(None, overflow_field);
330                         let int_result = result.access_field(None, result_field);
331                         return (int_result, overflow);
332                     },
333                     _ => {
334                         match oop {
335                             OverflowOp::Mul =>
336                                 match new_kind {
337                                     Int(I32) => "__mulosi4",
338                                     Int(I64) => "__mulodi4",
339                                     _ => unreachable!(),
340                                 },
341                             _ => unimplemented!("overflow operation for {:?}", new_kind),
342                         }
343                     }
344                 }
345             };
346 
347         let intrinsic = self.context.get_builtin_function(&name);
348         let res = self.current_func()
349             // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
350             .new_local(None, rhs.get_type(), "binopResult")
351             .get_address(None);
352         let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
353         (res.dereference(None).to_rvalue(), overflow)
354     }
355 
gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc>356     pub fn gcc_icmp(&self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
357         let a_type = lhs.get_type();
358         let b_type = rhs.get_type();
359         if self.is_non_native_int_type(a_type) || self.is_non_native_int_type(b_type) {
360             let signed = a_type.is_compatible_with(self.i128_type);
361             let sign =
362                 if signed {
363                     ""
364                 }
365                 else {
366                     "u"
367                 };
368             let func_name = format!("__{}cmpti2", sign);
369             let param_a = self.context.new_parameter(None, a_type, "a");
370             let param_b = self.context.new_parameter(None, b_type, "b");
371             let func = self.context.new_function(None, FunctionType::Extern, self.int_type, &[param_a, param_b], func_name, false);
372             let cmp = self.context.new_call(None, func, &[lhs, rhs]);
373             let (op, limit) =
374                 match op {
375                     IntPredicate::IntEQ => {
376                         return self.context.new_comparison(None, ComparisonOp::Equals, cmp, self.context.new_rvalue_one(self.int_type));
377                     },
378                     IntPredicate::IntNE => {
379                         return self.context.new_comparison(None, ComparisonOp::NotEquals, cmp, self.context.new_rvalue_one(self.int_type));
380                     },
381                     IntPredicate::IntUGT => (ComparisonOp::Equals, 2),
382                     IntPredicate::IntUGE => (ComparisonOp::GreaterThanEquals, 1),
383                     IntPredicate::IntULT => (ComparisonOp::Equals, 0),
384                     IntPredicate::IntULE => (ComparisonOp::LessThanEquals, 1),
385                     IntPredicate::IntSGT => (ComparisonOp::Equals, 2),
386                     IntPredicate::IntSGE => (ComparisonOp::GreaterThanEquals, 1),
387                     IntPredicate::IntSLT => (ComparisonOp::Equals, 0),
388                     IntPredicate::IntSLE => (ComparisonOp::LessThanEquals, 1),
389                 };
390             self.context.new_comparison(None, op, cmp, self.context.new_rvalue_from_int(self.int_type, limit))
391         }
392         else if a_type.get_pointee().is_some() && b_type.get_pointee().is_some() {
393             // NOTE: gcc cannot compare pointers to different objects, but rustc does that, so cast them to usize.
394             lhs = self.context.new_bitcast(None, lhs, self.usize_type);
395             rhs = self.context.new_bitcast(None, rhs, self.usize_type);
396             self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
397         }
398         else {
399             if a_type != b_type {
400                 // NOTE: because libgccjit cannot compare function pointers.
401                 if a_type.dyncast_function_ptr_type().is_some() && b_type.dyncast_function_ptr_type().is_some() {
402                     lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
403                     rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
404                 }
405                 // NOTE: hack because we try to cast a vector type to the same vector type.
406                 else if format!("{:?}", a_type) != format!("{:?}", b_type) {
407                     rhs = self.context.new_cast(None, rhs, a_type);
408                 }
409             }
410             self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
411         }
412     }
413 
gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>414     pub fn gcc_xor(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
415         let a_type = a.get_type();
416         let b_type = b.get_type();
417         if self.is_native_int_type_or_bool(a_type) && self.is_native_int_type_or_bool(b_type) {
418             a ^ b
419         }
420         else {
421             let values = [
422                 self.low(a) ^ self.low(b),
423                 self.high(a) ^ self.high(b),
424             ];
425             self.context.new_array_constructor(None, a_type, &values)
426         }
427     }
428 
gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>429     pub fn gcc_shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
430         let a_type = a.get_type();
431         let b_type = b.get_type();
432         let a_native = self.is_native_int_type(a_type);
433         let b_native = self.is_native_int_type(b_type);
434         if a_native && b_native {
435             // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
436             if a_type.is_unsigned(self) && b_type.is_signed(self) {
437                 let a = self.context.new_cast(None, a, b_type);
438                 let result = a << b;
439                 self.context.new_cast(None, result, a_type)
440             }
441             else if a_type.is_signed(self) && b_type.is_unsigned(self) {
442                 let b = self.context.new_cast(None, b, a_type);
443                 a << b
444             }
445             else {
446                 a << b
447             }
448         }
449         else if a_native && !b_native {
450             self.gcc_shl(a, self.gcc_int_cast(b, a_type))
451         }
452         else {
453             // NOTE: we cannot use the ashl builtin because it's calling widen_hi() which uses ashl.
454             let native_int_type = a_type.dyncast_array().expect("get element type");
455 
456             let func = self.current_func();
457             let then_block = func.new_block("then");
458             let else_block = func.new_block("else");
459             let after_block = func.new_block("after");
460             let b0_block = func.new_block("b0");
461             let actual_else_block = func.new_block("actual_else");
462 
463             let result = func.new_local(None, a_type, "shiftResult");
464 
465             let b = self.gcc_int_cast(b, native_int_type);
466             let sixty_four = self.gcc_int(native_int_type, 64);
467             let zero = self.gcc_zero(native_int_type);
468             let condition = self.gcc_icmp(IntPredicate::IntNE, self.gcc_and(b, sixty_four), zero);
469             self.llbb().end_with_conditional(None, condition, then_block, else_block);
470 
471             // TODO(antoyo): take endianness into account.
472             let values = [
473                 zero,
474                 self.low(a) << (b - sixty_four),
475             ];
476             let array_value = self.context.new_array_constructor(None, a_type, &values);
477             then_block.add_assignment(None, result, array_value);
478             then_block.end_with_jump(None, after_block);
479 
480             let condition = self.gcc_icmp(IntPredicate::IntEQ, b, zero);
481             else_block.end_with_conditional(None, condition, b0_block, actual_else_block);
482 
483             b0_block.add_assignment(None, result, a);
484             b0_block.end_with_jump(None, after_block);
485 
486             // NOTE: cast low to its unsigned type in order to perform a logical right shift.
487             let unsigned_type = native_int_type.to_unsigned(&self.cx);
488             let casted_low = self.context.new_cast(None, self.low(a), unsigned_type);
489             let shift_value = self.context.new_cast(None, sixty_four - b, unsigned_type);
490             let high_low = self.context.new_cast(None, casted_low >> shift_value, native_int_type);
491             let values = [
492                 self.low(a) << b,
493                 (self.high(a) << b) | high_low,
494             ];
495 
496             let array_value = self.context.new_array_constructor(None, a_type, &values);
497             actual_else_block.add_assignment(None, result, array_value);
498             actual_else_block.end_with_jump(None, after_block);
499 
500             // NOTE: since jumps were added in a place rustc does not expect, the current block in the
501             // state need to be updated.
502             self.switch_to_block(after_block);
503 
504             result.to_rvalue()
505         }
506     }
507 
gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc>508     pub fn gcc_bswap(&mut self, mut arg: RValue<'gcc>, width: u64) -> RValue<'gcc> {
509         let arg_type = arg.get_type();
510         if !self.is_native_int_type(arg_type) {
511             let native_int_type = arg_type.dyncast_array().expect("get element type");
512             let lsb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 0)).to_rvalue();
513             let swapped_lsb = self.gcc_bswap(lsb, width / 2);
514             let swapped_lsb = self.context.new_cast(None, swapped_lsb, native_int_type);
515             let msb = self.context.new_array_access(None, arg, self.context.new_rvalue_from_int(self.int_type, 1)).to_rvalue();
516             let swapped_msb = self.gcc_bswap(msb, width / 2);
517             let swapped_msb = self.context.new_cast(None, swapped_msb, native_int_type);
518 
519             // NOTE: we also need to swap the two elements here, in addition to swapping inside
520             // the elements themselves like done above.
521             return self.context.new_array_constructor(None, arg_type, &[swapped_msb, swapped_lsb]);
522         }
523 
524         // TODO(antoyo): check if it's faster to use string literals and a
525         // match instead of format!.
526         let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width));
527         // FIXME(antoyo): this cast should not be necessary. Remove
528         // when having proper sized integer types.
529         let param_type = bswap.get_param(0).to_rvalue().get_type();
530         if param_type != arg_type {
531             arg = self.bitcast(arg, param_type);
532         }
533         self.cx.context.new_call(None, bswap, &[arg])
534     }
535 }
536 
537 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc>538     pub fn gcc_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
539         if self.is_native_int_type_or_bool(typ) {
540             self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from"))
541         }
542         else {
543             // NOTE: set the sign in high.
544             self.from_low_high(typ, int, -(int.is_negative() as i64))
545         }
546     }
547 
gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc>548     pub fn gcc_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
549         if self.is_native_int_type_or_bool(typ) {
550             self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
551         }
552         else {
553             self.from_low_high(typ, int as i64, 0)
554         }
555     }
556 
gcc_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc>557     pub fn gcc_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
558         let low = num as u64;
559         let high = (num >> 64) as u64;
560         if num >> 64 != 0 {
561             // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
562             if self.is_native_int_type(typ) {
563                 let low = self.context.new_rvalue_from_long(self.u64_type, low as i64);
564                 let high = self.context.new_rvalue_from_long(typ, high as i64);
565 
566                 let sixty_four = self.context.new_rvalue_from_long(typ, 64);
567                 let shift = high << sixty_four;
568                 shift | self.context.new_cast(None, low, typ)
569             }
570             else {
571                 self.from_low_high(typ, low as i64, high as i64)
572             }
573         }
574         else if typ.is_i128(self) {
575             let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
576             self.gcc_int_cast(num, typ)
577         }
578         else {
579             self.gcc_uint(typ, num as u64)
580         }
581     }
582 
gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc>583     pub fn gcc_zero(&self, typ: Type<'gcc>) -> RValue<'gcc> {
584         if self.is_native_int_type_or_bool(typ) {
585             self.context.new_rvalue_zero(typ)
586         }
587         else {
588             self.from_low_high(typ, 0, 0)
589         }
590     }
591 
gcc_int_width(&self, typ: Type<'gcc>) -> u64592     pub fn gcc_int_width(&self, typ: Type<'gcc>) -> u64 {
593         if self.is_native_int_type_or_bool(typ) {
594             typ.get_size() as u64 * 8
595         }
596         else {
597             // NOTE: the only unsupported types are u128 and i128.
598             128
599         }
600     }
601 
bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc>602     fn bitwise_operation(&self, operation: BinaryOp, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
603         let a_type = a.get_type();
604         let b_type = b.get_type();
605         let a_native = self.is_native_int_type_or_bool(a_type);
606         let b_native = self.is_native_int_type_or_bool(b_type);
607         if a_type.is_vector() && b_type.is_vector() {
608             self.context.new_binary_op(None, operation, a_type, a, b)
609         }
610         else if a_native && b_native {
611             if a_type != b_type {
612                 b = self.context.new_cast(None, b, a_type);
613             }
614             self.context.new_binary_op(None, operation, a_type, a, b)
615         }
616         else {
617             assert!(!a_native && !b_native, "both types should either be native or non-native for or operation");
618             let native_int_type = a_type.dyncast_array().expect("get element type");
619             let values = [
620                 self.context.new_binary_op(None, operation, native_int_type, self.low(a), self.low(b)),
621                 self.context.new_binary_op(None, operation, native_int_type, self.high(a), self.high(b)),
622             ];
623             self.context.new_array_constructor(None, a_type, &values)
624         }
625     }
626 
gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc>627     pub fn gcc_or(&self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
628         self.bitwise_operation(BinaryOp::BitwiseOr, a, b)
629     }
630 
631     // TODO(antoyo): can we use https://github.com/rust-lang/compiler-builtins/blob/master/src/int/mod.rs#L379 instead?
gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>632     pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
633         let value_type = value.get_type();
634         if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type) {
635             self.context.new_cast(None, value, dest_typ)
636         }
637         else if self.is_native_int_type_or_bool(dest_typ) {
638             self.context.new_cast(None, self.low(value), dest_typ)
639         }
640         else if self.is_native_int_type_or_bool(value_type) {
641             let dest_element_type = dest_typ.dyncast_array().expect("get element type");
642 
643             // NOTE: set the sign of the value.
644             let zero = self.context.new_rvalue_zero(value_type);
645             let is_negative = self.context.new_comparison(None, ComparisonOp::LessThan, value, zero);
646             let is_negative = self.gcc_int_cast(is_negative, dest_element_type);
647             let values = [
648                 self.context.new_cast(None, value, dest_element_type),
649                 self.context.new_unary_op(None, UnaryOp::Minus, dest_element_type, is_negative),
650             ];
651             self.context.new_array_constructor(None, dest_typ, &values)
652         }
653         else {
654             // Since u128 and i128 are the only types that can be unsupported, we know the type of
655             // value and the destination type have the same size, so a bitcast is fine.
656 
657             // TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
658             self.context.new_bitcast(None, value, dest_typ)
659         }
660     }
661 
int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>662     fn int_to_float_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
663         let value_type = value.get_type();
664         if self.is_native_int_type_or_bool(value_type) {
665             return self.context.new_cast(None, value, dest_typ);
666         }
667 
668         let name_suffix =
669             match self.type_kind(dest_typ) {
670                 TypeKind::Float => "tisf",
671                 TypeKind::Double => "tidf",
672                 kind => panic!("cannot cast a non-native integer to type {:?}", kind),
673             };
674         let sign =
675             if signed {
676                 ""
677             }
678             else {
679                 "un"
680             };
681         let func_name = format!("__float{}{}", sign, name_suffix);
682         let param = self.context.new_parameter(None, value_type, "n");
683         let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false);
684         self.context.new_call(None, func, &[value])
685     }
686 
gcc_int_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>687     pub fn gcc_int_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
688         self.int_to_float_cast(true, value, dest_typ)
689     }
690 
gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>691     pub fn gcc_uint_to_float_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
692         self.int_to_float_cast(false, value, dest_typ)
693     }
694 
float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>695     fn float_to_int_cast(&self, signed: bool, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
696         let value_type = value.get_type();
697         if self.is_native_int_type_or_bool(dest_typ) {
698             return self.context.new_cast(None, value, dest_typ);
699         }
700 
701         let name_suffix =
702             match self.type_kind(value_type) {
703                 TypeKind::Float => "sfti",
704                 TypeKind::Double => "dfti",
705                 kind => panic!("cannot cast a {:?} to non-native integer", kind),
706             };
707         let sign =
708             if signed {
709                 ""
710             }
711             else {
712                 "uns"
713             };
714         let func_name = format!("__fix{}{}", sign, name_suffix);
715         let param = self.context.new_parameter(None, value_type, "n");
716         let func = self.context.new_function(None, FunctionType::Extern, dest_typ, &[param], func_name, false);
717         self.context.new_call(None, func, &[value])
718     }
719 
gcc_float_to_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>720     pub fn gcc_float_to_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
721         self.float_to_int_cast(true, value, dest_typ)
722     }
723 
gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc>724     pub fn gcc_float_to_uint_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
725         self.float_to_int_cast(false, value, dest_typ)
726     }
727 
high(&self, value: RValue<'gcc>) -> RValue<'gcc>728     fn high(&self, value: RValue<'gcc>) -> RValue<'gcc> {
729         self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 1))
730             .to_rvalue()
731     }
732 
low(&self, value: RValue<'gcc>) -> RValue<'gcc>733     fn low(&self, value: RValue<'gcc>) -> RValue<'gcc> {
734         self.context.new_array_access(None, value, self.context.new_rvalue_from_int(self.int_type, 0))
735             .to_rvalue()
736     }
737 
from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc>738     fn from_low_high(&self, typ: Type<'gcc>, low: i64, high: i64) -> RValue<'gcc> {
739         let native_int_type = typ.dyncast_array().expect("get element type");
740         let values = [
741             self.context.new_rvalue_from_long(native_int_type, low),
742             self.context.new_rvalue_from_long(native_int_type, high),
743         ];
744         self.context.new_array_constructor(None, typ, &values)
745     }
746 }
747