]> git.lizzy.rs Git - rust.git/blob - src/intrinsic/mod.rs
Merge branch 'master' into sync_from_rust2
[rust.git] / src / intrinsic / mod.rs
1 pub mod llvm;
2 mod simd;
3
4 use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType};
5 use rustc_codegen_ssa::MemFlags;
6 use rustc_codegen_ssa::base::wants_msvc_seh;
7 use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
8 use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
9 use rustc_codegen_ssa::mir::place::PlaceRef;
10 use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
11 use rustc_middle::bug;
12 use rustc_middle::ty::{self, Instance, Ty};
13 use rustc_middle::ty::layout::LayoutOf;
14 use rustc_span::{Span, Symbol, symbol::kw, sym};
15 use rustc_target::abi::HasDataLayout;
16 use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
17 use rustc_target::spec::PanicStrategy;
18
19 use crate::abi::GccType;
20 use crate::builder::Builder;
21 use crate::common::{SignType, TypeReflection};
22 use crate::context::CodegenCx;
23 use crate::type_of::LayoutGccExt;
24 use crate::intrinsic::simd::generic_simd_intrinsic;
25
26 fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option<Function<'gcc>> {
27     let gcc_name = match name {
28         sym::sqrtf32 => "sqrtf",
29         sym::sqrtf64 => "sqrt",
30         sym::powif32 => "__builtin_powif",
31         sym::powif64 => "__builtin_powi",
32         sym::sinf32 => "sinf",
33         sym::sinf64 => "sin",
34         sym::cosf32 => "cosf",
35         sym::cosf64 => "cos",
36         sym::powf32 => "powf",
37         sym::powf64 => "pow",
38         sym::expf32 => "expf",
39         sym::expf64 => "exp",
40         sym::exp2f32 => "exp2f",
41         sym::exp2f64 => "exp2",
42         sym::logf32 => "logf",
43         sym::logf64 => "log",
44         sym::log10f32 => "log10f",
45         sym::log10f64 => "log10",
46         sym::log2f32 => "log2f",
47         sym::log2f64 => "log2",
48         sym::fmaf32 => "fmaf",
49         sym::fmaf64 => "fma",
50         sym::fabsf32 => "fabsf",
51         sym::fabsf64 => "fabs",
52         sym::minnumf32 => "fminf",
53         sym::minnumf64 => "fmin",
54         sym::maxnumf32 => "fmaxf",
55         sym::maxnumf64 => "fmax",
56         sym::copysignf32 => "copysignf",
57         sym::copysignf64 => "copysign",
58         sym::floorf32 => "floorf",
59         sym::floorf64 => "floor",
60         sym::ceilf32 => "ceilf",
61         sym::ceilf64 => "ceil",
62         sym::truncf32 => "truncf",
63         sym::truncf64 => "trunc",
64         sym::rintf32 => "rintf",
65         sym::rintf64 => "rint",
66         sym::nearbyintf32 => "nearbyintf",
67         sym::nearbyintf64 => "nearbyint",
68         sym::roundf32 => "roundf",
69         sym::roundf64 => "round",
70         sym::abort => "abort",
71         _ => return None,
72     };
73     Some(cx.context.get_builtin_function(&gcc_name))
74 }
75
76 impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
77     fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) {
78         let tcx = self.tcx;
79         let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
80
81         let (def_id, substs) = match *callee_ty.kind() {
82             ty::FnDef(def_id, substs) => (def_id, substs),
83             _ => bug!("expected fn item type, found {}", callee_ty),
84         };
85
86         let sig = callee_ty.fn_sig(tcx);
87         let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
88         let arg_tys = sig.inputs();
89         let ret_ty = sig.output();
90         let name = tcx.item_name(def_id);
91         let name_str = name.as_str();
92
93         let llret_ty = self.layout_of(ret_ty).gcc_type(self, true);
94         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
95
96         let simple = get_simple_intrinsic(self, name);
97         let llval =
98             match name {
99                 _ if simple.is_some() => {
100                     // FIXME(antoyo): remove this cast when the API supports function.
101                     let func = unsafe { std::mem::transmute(simple.expect("simple")) };
102                     self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
103                 },
104                 sym::likely => {
105                     self.expect(args[0].immediate(), true)
106                 }
107                 sym::unlikely => {
108                     self.expect(args[0].immediate(), false)
109                 }
110                 kw::Try => {
111                     try_intrinsic(
112                         self,
113                         args[0].immediate(),
114                         args[1].immediate(),
115                         args[2].immediate(),
116                         llresult,
117                     );
118                     return;
119                 }
120                 sym::breakpoint => {
121                     unimplemented!();
122                 }
123                 sym::va_copy => {
124                     unimplemented!();
125                 }
126                 sym::va_arg => {
127                     unimplemented!();
128                 }
129
130                 sym::volatile_load | sym::unaligned_volatile_load => {
131                     let tp_ty = substs.type_at(0);
132                     let mut ptr = args[0].immediate();
133                     if let PassMode::Cast(ty) = fn_abi.ret.mode {
134                         ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
135                     }
136                     let load = self.volatile_load(ptr.get_type(), ptr);
137                     // TODO(antoyo): set alignment.
138                     self.to_immediate(load, self.layout_of(tp_ty))
139                 }
140                 sym::volatile_store => {
141                     let dst = args[0].deref(self.cx());
142                     args[1].val.volatile_store(self, dst);
143                     return;
144                 }
145                 sym::unaligned_volatile_store => {
146                     let dst = args[0].deref(self.cx());
147                     args[1].val.unaligned_volatile_store(self, dst);
148                     return;
149                 }
150                 sym::prefetch_read_data
151                     | sym::prefetch_write_data
152                     | sym::prefetch_read_instruction
153                     | sym::prefetch_write_instruction => {
154                         unimplemented!();
155                     }
156                 sym::ctlz
157                     | sym::ctlz_nonzero
158                     | sym::cttz
159                     | sym::cttz_nonzero
160                     | sym::ctpop
161                     | sym::bswap
162                     | sym::bitreverse
163                     | sym::rotate_left
164                     | sym::rotate_right
165                     | sym::saturating_add
166                     | sym::saturating_sub => {
167                         let ty = arg_tys[0];
168                         match int_type_width_signed(ty, self) {
169                             Some((width, signed)) => match name {
170                                 sym::ctlz | sym::cttz => {
171                                     let func = self.current_func.borrow().expect("func");
172                                     let then_block = func.new_block("then");
173                                     let else_block = func.new_block("else");
174                                     let after_block = func.new_block("after");
175
176                                     let arg = args[0].immediate();
177                                     let result = func.new_local(None, arg.get_type(), "zeros");
178                                     let zero = self.cx.gcc_zero(arg.get_type());
179                                     let cond = self.gcc_icmp(IntPredicate::IntEQ, arg, zero);
180                                     self.llbb().end_with_conditional(None, cond, then_block, else_block);
181
182                                     let zero_result = self.cx.gcc_uint(arg.get_type(), width);
183                                     then_block.add_assignment(None, result, zero_result);
184                                     then_block.end_with_jump(None, after_block);
185
186                                     // NOTE: since jumps were added in a place
187                                     // count_leading_zeroes() does not expect, the current block
188                                     // in the state need to be updated.
189                                     self.switch_to_block(else_block);
190
191                                     let zeros =
192                                         match name {
193                                             sym::ctlz => self.count_leading_zeroes(width, arg),
194                                             sym::cttz => self.count_trailing_zeroes(width, arg),
195                                             _ => unreachable!(),
196                                         };
197                                     self.llbb().add_assignment(None, result, zeros);
198                                     self.llbb().end_with_jump(None, after_block);
199
200                                     // NOTE: since jumps were added in a place rustc does not
201                                     // expect, the current block in the state need to be updated.
202                                     self.switch_to_block(after_block);
203
204                                     result.to_rvalue()
205                                 }
206                                 sym::ctlz_nonzero => {
207                                     self.count_leading_zeroes(width, args[0].immediate())
208                                 },
209                                 sym::cttz_nonzero => {
210                                     self.count_trailing_zeroes(width, args[0].immediate())
211                                 }
212                                 sym::ctpop => self.pop_count(args[0].immediate()),
213                                 sym::bswap => {
214                                     if width == 8 {
215                                         args[0].immediate() // byte swap a u8/i8 is just a no-op
216                                     }
217                                     else {
218                                         self.gcc_bswap(args[0].immediate(), width)
219                                     }
220                                 },
221                                 sym::bitreverse => self.bit_reverse(width, args[0].immediate()),
222                                 sym::rotate_left | sym::rotate_right => {
223                                     // TODO(antoyo): implement using algorithm from:
224                                     // https://blog.regehr.org/archives/1063
225                                     // for other platforms.
226                                     let is_left = name == sym::rotate_left;
227                                     let val = args[0].immediate();
228                                     let raw_shift = args[1].immediate();
229                                     if is_left {
230                                         self.rotate_left(val, raw_shift, width)
231                                     }
232                                     else {
233                                         self.rotate_right(val, raw_shift, width)
234                                     }
235                                 },
236                                 sym::saturating_add => {
237                                     self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width)
238                                 },
239                                 sym::saturating_sub => {
240                                     self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width)
241                                 },
242                                 _ => bug!(),
243                             },
244                             None => {
245                                 span_invalid_monomorphization_error(
246                                     tcx.sess,
247                                     span,
248                                     &format!(
249                                         "invalid monomorphization of `{}` intrinsic: \
250                                       expected basic integer type, found `{}`",
251                                       name, ty
252                                     ),
253                                 );
254                                 return;
255                             }
256                         }
257                     }
258
259                 sym::raw_eq => {
260                     use rustc_target::abi::Abi::*;
261                     let tp_ty = substs.type_at(0);
262                     let layout = self.layout_of(tp_ty).layout;
263                     let _use_integer_compare = match layout.abi() {
264                         Scalar(_) | ScalarPair(_, _) => true,
265                         Uninhabited | Vector { .. } => false,
266                         Aggregate { .. } => {
267                             // For rusty ABIs, small aggregates are actually passed
268                             // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
269                             // so we re-use that same threshold here.
270                             layout.size() <= self.data_layout().pointer_size * 2
271                         }
272                     };
273
274                     let a = args[0].immediate();
275                     let b = args[1].immediate();
276                     if layout.size().bytes() == 0 {
277                         self.const_bool(true)
278                     }
279                     /*else if use_integer_compare {
280                         let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits.
281                         let ptr_ty = self.type_ptr_to(integer_ty);
282                         let a_ptr = self.bitcast(a, ptr_ty);
283                         let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
284                         let b_ptr = self.bitcast(b, ptr_ty);
285                         let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
286                         self.icmp(IntPredicate::IntEQ, a_val, b_val)
287                     }*/
288                     else {
289                         let void_ptr_type = self.context.new_type::<*const ()>();
290                         let a_ptr = self.bitcast(a, void_ptr_type);
291                         let b_ptr = self.bitcast(b, void_ptr_type);
292                         let n = self.context.new_cast(None, self.const_usize(layout.size().bytes()), self.sizet_type);
293                         let builtin = self.context.get_builtin_function("memcmp");
294                         let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
295                         self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
296                     }
297                 }
298
299                 sym::black_box => {
300                     args[0].val.store(self, result);
301
302                     let block = self.llbb();
303                     let extended_asm = block.add_extended_asm(None, "");
304                     extended_asm.add_input_operand(None, "r", result.llval);
305                     extended_asm.add_clobber("memory");
306                     extended_asm.set_volatile_flag(true);
307
308                     // We have copied the value to `result` already.
309                     return;
310                 }
311
312                 _ if name_str.starts_with("simd_") => {
313                     match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
314                         Ok(llval) => llval,
315                         Err(()) => return,
316                     }
317                 }
318
319                 _ => bug!("unknown intrinsic '{}'", name),
320             };
321
322         if !fn_abi.ret.is_ignore() {
323             if let PassMode::Cast(ty) = fn_abi.ret.mode {
324                 let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
325                 let ptr = self.pointercast(result.llval, ptr_llty);
326                 self.store(llval, ptr, result.align);
327             }
328             else {
329                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
330                     .val
331                     .store(self, result);
332             }
333         }
334     }
335
336     fn abort(&mut self) {
337         let func = self.context.get_builtin_function("abort");
338         let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
339         self.call(self.type_void(), func, &[], None);
340     }
341
342     fn assume(&mut self, value: Self::Value) {
343         // TODO(antoyo): switch to assume when it exists.
344         // Or use something like this:
345         // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
346         self.expect(value, true);
347     }
348
349     fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value {
350         // TODO(antoyo)
351         cond
352     }
353
354     fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
355         // Unsupported.
356         self.context.new_rvalue_from_int(self.int_type, 0)
357     }
358
359     fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
360         unimplemented!();
361     }
362
363     fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
364         unimplemented!();
365     }
366 }
367
368 impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
369     fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) {
370         arg_abi.store_fn_arg(self, idx, dst)
371     }
372
373     fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
374         arg_abi.store(self, val, dst)
375     }
376
377     fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
378         arg_abi.memory_ty(self)
379     }
380 }
381
382 pub trait ArgAbiExt<'gcc, 'tcx> {
383     fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
384     fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>);
385     fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>);
386 }
387
388 impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
389     /// Gets the LLVM type for a place of the original Rust type of
390     /// this argument/return, i.e., the result of `type_of::type_of`.
391     fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
392         self.layout.gcc_type(cx, true)
393     }
394
395     /// Stores a direct/indirect value described by this ArgAbi into a
396     /// place for the original Rust type of this argument/return.
397     /// Can be used for both storing formal arguments into Rust variables
398     /// or results of call/invoke instructions into their destinations.
399     fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
400         if self.is_ignore() {
401             return;
402         }
403         if self.is_sized_indirect() {
404             OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
405         }
406         else if self.is_unsized_indirect() {
407             bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
408         }
409         else if let PassMode::Cast(cast) = self.mode {
410             // FIXME(eddyb): Figure out when the simpler Store is safe, clang
411             // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
412             let can_store_through_cast_ptr = false;
413             if can_store_through_cast_ptr {
414                 let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx));
415                 let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
416                 bx.store(val, cast_dst, self.layout.align.abi);
417             }
418             else {
419                 // The actual return type is a struct, but the ABI
420                 // adaptation code has cast it into some scalar type.  The
421                 // code that follows is the only reliable way I have
422                 // found to do a transform like i64 -> {i32,i32}.
423                 // Basically we dump the data onto the stack then memcpy it.
424                 //
425                 // Other approaches I tried:
426                 // - Casting rust ret pointer to the foreign type and using Store
427                 //   is (a) unsafe if size of foreign type > size of rust type and
428                 //   (b) runs afoul of strict aliasing rules, yielding invalid
429                 //   assembly under -O (specifically, the store gets removed).
430                 // - Truncating foreign type to correct integral type and then
431                 //   bitcasting to the struct type yields invalid cast errors.
432
433                 // We instead thus allocate some scratch space...
434                 let scratch_size = cast.size(bx);
435                 let scratch_align = cast.align(bx);
436                 let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align);
437                 bx.lifetime_start(llscratch, scratch_size);
438
439                 // ... where we first store the value...
440                 bx.store(val, llscratch, scratch_align);
441
442                 // ... and then memcpy it to the intended destination.
443                 bx.memcpy(
444                     dst.llval,
445                     self.layout.align.abi,
446                     llscratch,
447                     scratch_align,
448                     bx.const_usize(self.layout.size.bytes()),
449                     MemFlags::empty(),
450                 );
451
452                 bx.lifetime_end(llscratch, scratch_size);
453             }
454         }
455         else {
456             OperandValue::Immediate(val).store(bx, dst);
457         }
458     }
459
460     fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) {
461         let mut next = || {
462             let val = bx.current_func().get_param(*idx as i32);
463             *idx += 1;
464             val.to_rvalue()
465         };
466         match self.mode {
467             PassMode::Ignore => {},
468             PassMode::Pair(..) => {
469                 OperandValue::Pair(next(), next()).store(bx, dst);
470             },
471             PassMode::Indirect { extra_attrs: Some(_), .. } => {
472                 OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
473             },
474             PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => {
475                 let next_arg = next();
476                 self.store(bx, next_arg, dst);
477             },
478         }
479     }
480 }
481
482 fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> {
483     match ty.kind() {
484         ty::Int(t) => Some((
485             match t {
486                 rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width),
487                 rustc_middle::ty::IntTy::I8 => 8,
488                 rustc_middle::ty::IntTy::I16 => 16,
489                 rustc_middle::ty::IntTy::I32 => 32,
490                 rustc_middle::ty::IntTy::I64 => 64,
491                 rustc_middle::ty::IntTy::I128 => 128,
492             },
493             true,
494         )),
495         ty::Uint(t) => Some((
496             match t {
497                 rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width),
498                 rustc_middle::ty::UintTy::U8 => 8,
499                 rustc_middle::ty::UintTy::U16 => 16,
500                 rustc_middle::ty::UintTy::U32 => 32,
501                 rustc_middle::ty::UintTy::U64 => 64,
502                 rustc_middle::ty::UintTy::U128 => 128,
503             },
504             false,
505         )),
506         _ => None,
507     }
508 }
509
510 impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
511     fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> {
512         let result_type = value.get_type();
513         let typ = result_type.to_unsigned(self.cx);
514
515         let value =
516             if result_type.is_signed(self.cx) {
517                 self.gcc_int_cast(value, typ)
518             }
519             else {
520                 value
521             };
522
523         let context = &self.cx.context;
524         let result =
525             match width {
526                 8 => {
527                     // First step.
528                     let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0));
529                     let left = self.lshr(left, context.new_rvalue_from_int(typ, 4));
530                     let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F));
531                     let right = self.shl(right, context.new_rvalue_from_int(typ, 4));
532                     let step1 = self.or(left, right);
533
534                     // Second step.
535                     let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC));
536                     let left = self.lshr(left, context.new_rvalue_from_int(typ, 2));
537                     let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33));
538                     let right = self.shl(right, context.new_rvalue_from_int(typ, 2));
539                     let step2 = self.or(left, right);
540
541                     // Third step.
542                     let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA));
543                     let left = self.lshr(left, context.new_rvalue_from_int(typ, 1));
544                     let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55));
545                     let right = self.shl(right, context.new_rvalue_from_int(typ, 1));
546                     let step3 = self.or(left, right);
547
548                     step3
549                 },
550                 16 => {
551                     // First step.
552                     let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555));
553                     let left = self.shl(left, context.new_rvalue_from_int(typ, 1));
554                     let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA));
555                     let right = self.lshr(right, context.new_rvalue_from_int(typ, 1));
556                     let step1 = self.or(left, right);
557
558                     // Second step.
559                     let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333));
560                     let left = self.shl(left, context.new_rvalue_from_int(typ, 2));
561                     let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC));
562                     let right = self.lshr(right, context.new_rvalue_from_int(typ, 2));
563                     let step2 = self.or(left, right);
564
565                     // Third step.
566                     let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F));
567                     let left = self.shl(left, context.new_rvalue_from_int(typ, 4));
568                     let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0));
569                     let right = self.lshr(right, context.new_rvalue_from_int(typ, 4));
570                     let step3 = self.or(left, right);
571
572                     // Fourth step.
573                     let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF));
574                     let left = self.shl(left, context.new_rvalue_from_int(typ, 8));
575                     let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00));
576                     let right = self.lshr(right, context.new_rvalue_from_int(typ, 8));
577                     let step4 = self.or(left, right);
578
579                     step4
580                 },
581                 32 => {
582                     // TODO(antoyo): Refactor with other implementations.
583                     // First step.
584                     let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555));
585                     let left = self.shl(left, context.new_rvalue_from_long(typ, 1));
586                     let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA));
587                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 1));
588                     let step1 = self.or(left, right);
589
590                     // Second step.
591                     let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333));
592                     let left = self.shl(left, context.new_rvalue_from_long(typ, 2));
593                     let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC));
594                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 2));
595                     let step2 = self.or(left, right);
596
597                     // Third step.
598                     let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F));
599                     let left = self.shl(left, context.new_rvalue_from_long(typ, 4));
600                     let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0));
601                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 4));
602                     let step3 = self.or(left, right);
603
604                     // Fourth step.
605                     let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF));
606                     let left = self.shl(left, context.new_rvalue_from_long(typ, 8));
607                     let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00));
608                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 8));
609                     let step4 = self.or(left, right);
610
611                     // Fifth step.
612                     let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF));
613                     let left = self.shl(left, context.new_rvalue_from_long(typ, 16));
614                     let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000));
615                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 16));
616                     let step5 = self.or(left, right);
617
618                     step5
619                 },
620                 64 => {
621                     // First step.
622                     let left = self.shl(value, context.new_rvalue_from_long(typ, 32));
623                     let right = self.lshr(value, context.new_rvalue_from_long(typ, 32));
624                     let step1 = self.or(left, right);
625
626                     // Second step.
627                     let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF));
628                     let left = self.shl(left, context.new_rvalue_from_long(typ, 15));
629                     let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead?
630                     let right = self.lshr(right, context.new_rvalue_from_long(typ, 17));
631                     let step2 = self.or(left, right);
632
633                     // Third step.
634                     let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10));
635                     let left = self.xor(step2, left);
636                     let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F));
637
638                     let left = self.shl(temp, context.new_rvalue_from_long(typ, 10));
639                     let left = self.or(temp, left);
640                     let step3 = self.xor(left, step2);
641
642                     // Fourth step.
643                     let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4));
644                     let left = self.xor(step3, left);
645                     let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421));
646
647                     let left = self.shl(temp, context.new_rvalue_from_long(typ, 4));
648                     let left = self.or(temp, left);
649                     let step4 = self.xor(left, step3);
650
651                     // Fifth step.
652                     let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2));
653                     let left = self.xor(step4, left);
654                     let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842));
655
656                     let left = self.shl(temp, context.new_rvalue_from_long(typ, 2));
657                     let left = self.or(temp, left);
658                     let step5 = self.xor(left, step4);
659
660                     step5
661                 },
662                 128 => {
663                     // TODO(antoyo): find a more efficient implementation?
664                     let sixty_four = self.gcc_int(typ, 64);
665                     let right_shift = self.gcc_lshr(value, sixty_four);
666                     let high = self.gcc_int_cast(right_shift, self.u64_type);
667                     let low = self.gcc_int_cast(value, self.u64_type);
668
669                     let reversed_high = self.bit_reverse(64, high);
670                     let reversed_low = self.bit_reverse(64, low);
671
672                     let new_low = self.gcc_int_cast(reversed_high, typ);
673                     let new_high = self.shl(self.gcc_int_cast(reversed_low, typ), sixty_four);
674
675                     self.gcc_or(new_low, new_high)
676                 },
677                 _ => {
678                     panic!("cannot bit reverse with width = {}", width);
679                 },
680             };
681
682         self.gcc_int_cast(result, result_type)
683     }
684
685     fn count_leading_zeroes(&mut self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
686         // TODO(antoyo): use width?
687         let arg_type = arg.get_type();
688         let count_leading_zeroes =
689             // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here
690             // instead of using is_uint().
691             if arg_type.is_uint(&self.cx) {
692                 "__builtin_clz"
693             }
694             else if arg_type.is_ulong(&self.cx) {
695                 "__builtin_clzl"
696             }
697             else if arg_type.is_ulonglong(&self.cx) {
698                 "__builtin_clzll"
699             }
700             else if width == 128 {
701                 // Algorithm from: https://stackoverflow.com/a/28433850/389119
702                 let array_type = self.context.new_array_type(None, arg_type, 3);
703                 let result = self.current_func()
704                     .new_local(None, array_type, "count_loading_zeroes_results");
705
706                 let sixty_four = self.const_uint(arg_type, 64);
707                 let shift = self.lshr(arg, sixty_four);
708                 let high = self.gcc_int_cast(shift, self.u64_type);
709                 let low = self.gcc_int_cast(arg, self.u64_type);
710
711                 let zero = self.context.new_rvalue_zero(self.usize_type);
712                 let one = self.context.new_rvalue_one(self.usize_type);
713                 let two = self.context.new_rvalue_from_long(self.usize_type, 2);
714
715                 let clzll = self.context.get_builtin_function("__builtin_clzll");
716
717                 let first_elem = self.context.new_array_access(None, result, zero);
718                 let first_value = self.gcc_int_cast(self.context.new_call(None, clzll, &[high]), arg_type);
719                 self.llbb()
720                     .add_assignment(None, first_elem, first_value);
721
722                 let second_elem = self.context.new_array_access(None, result, one);
723                 let cast = self.gcc_int_cast(self.context.new_call(None, clzll, &[low]), arg_type);
724                 let second_value = self.add(cast, sixty_four);
725                 self.llbb()
726                     .add_assignment(None, second_elem, second_value);
727
728                 let third_elem = self.context.new_array_access(None, result, two);
729                 let third_value = self.const_uint(arg_type, 128);
730                 self.llbb()
731                     .add_assignment(None, third_elem, third_value);
732
733                 let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
734                 let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
735                 let not_low_and_not_high = not_low & not_high;
736                 let index = not_high + not_low_and_not_high;
737                 // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
738                 // gcc.
739                 // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
740                 // compilation stage.
741                 let index = self.context.new_cast(None, index, self.i32_type);
742
743                 let res = self.context.new_array_access(None, result, index);
744
745                 return self.gcc_int_cast(res.to_rvalue(), arg_type);
746             }
747             else {
748                 let count_leading_zeroes = self.context.get_builtin_function("__builtin_clzll");
749                 let arg = self.context.new_cast(None, arg, self.ulonglong_type);
750                 let diff = self.ulonglong_type.get_size() as i64 - arg_type.get_size() as i64;
751                 let diff = self.context.new_rvalue_from_long(self.int_type, diff * 8);
752                 let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff;
753                 return self.context.new_cast(None, res, arg_type);
754             };
755         let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes);
756         let res = self.context.new_call(None, count_leading_zeroes, &[arg]);
757         self.context.new_cast(None, res, arg_type)
758     }
759
760     fn count_trailing_zeroes(&mut self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
761         let result_type = arg.get_type();
762         let arg =
763             if result_type.is_signed(self.cx) {
764                 let new_type = result_type.to_unsigned(self.cx);
765                 self.gcc_int_cast(arg, new_type)
766             }
767             else {
768                 arg
769             };
770         let arg_type = arg.get_type();
771         let (count_trailing_zeroes, expected_type) =
772             // TODO(antoyo): write a new function Type::is_compatible_with(&Type) and use it here
773             // instead of using is_uint().
774             if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) {
775                 // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero.
776                 ("__builtin_ctz", self.cx.uint_type)
777             }
778             else if arg_type.is_ulong(&self.cx) {
779                 ("__builtin_ctzl", self.cx.ulong_type)
780             }
781             else if arg_type.is_ulonglong(&self.cx) {
782                 ("__builtin_ctzll", self.cx.ulonglong_type)
783             }
784             else if arg_type.is_u128(&self.cx) {
785                 // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119
786                 let array_type = self.context.new_array_type(None, arg_type, 3);
787                 let result = self.current_func()
788                     .new_local(None, array_type, "count_loading_zeroes_results");
789
790                 let sixty_four = self.gcc_int(arg_type, 64);
791                 let shift = self.gcc_lshr(arg, sixty_four);
792                 let high = self.gcc_int_cast(shift, self.u64_type);
793                 let low = self.gcc_int_cast(arg, self.u64_type);
794
795                 let zero = self.context.new_rvalue_zero(self.usize_type);
796                 let one = self.context.new_rvalue_one(self.usize_type);
797                 let two = self.context.new_rvalue_from_long(self.usize_type, 2);
798
799                 let ctzll = self.context.get_builtin_function("__builtin_ctzll");
800
801                 let first_elem = self.context.new_array_access(None, result, zero);
802                 let first_value = self.gcc_int_cast(self.context.new_call(None, ctzll, &[low]), arg_type);
803                 self.llbb()
804                     .add_assignment(None, first_elem, first_value);
805
806                 let second_elem = self.context.new_array_access(None, result, one);
807                 let second_value = self.gcc_add(self.gcc_int_cast(self.context.new_call(None, ctzll, &[high]), arg_type), sixty_four);
808                 self.llbb()
809                     .add_assignment(None, second_elem, second_value);
810
811                 let third_elem = self.context.new_array_access(None, result, two);
812                 let third_value = self.gcc_int(arg_type, 128);
813                 self.llbb()
814                     .add_assignment(None, third_elem, third_value);
815
816                 let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
817                 let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
818                 let not_low_and_not_high = not_low & not_high;
819                 let index = not_low + not_low_and_not_high;
820                 // NOTE: the following cast is necessary to avoid a GIMPLE verification failure in
821                 // gcc.
822                 // TODO(antoyo): do the correct verification in libgccjit to avoid an error at the
823                 // compilation stage.
824                 let index = self.context.new_cast(None, index, self.i32_type);
825
826                 let res = self.context.new_array_access(None, result, index);
827
828                 return self.gcc_int_cast(res.to_rvalue(), result_type);
829             }
830             else {
831                 let count_trailing_zeroes = self.context.get_builtin_function("__builtin_ctzll");
832                 let arg_size = arg_type.get_size();
833                 let casted_arg = self.context.new_cast(None, arg, self.ulonglong_type);
834                 let byte_diff = self.ulonglong_type.get_size() as i64 - arg_size as i64;
835                 let diff = self.context.new_rvalue_from_long(self.int_type, byte_diff * 8);
836                 let mask = self.context.new_rvalue_from_long(arg_type, -1); // To get the value with all bits set.
837                 let masked = mask & self.context.new_unary_op(None, UnaryOp::BitwiseNegate, arg_type, arg);
838                 let cond = self.context.new_comparison(None, ComparisonOp::Equals, masked, mask);
839                 let diff = diff * self.context.new_cast(None, cond, self.int_type);
840                 let res = self.context.new_call(None, count_trailing_zeroes, &[casted_arg]) - diff;
841                 return self.context.new_cast(None, res, result_type);
842             };
843         let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes);
844         let arg =
845             if arg_type != expected_type {
846                 self.context.new_cast(None, arg, expected_type)
847             }
848             else {
849                 arg
850             };
851         let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
852         self.context.new_cast(None, res, result_type)
853     }
854
855     fn pop_count(&mut self, value: RValue<'gcc>) -> RValue<'gcc> {
856         // TODO(antoyo): use the optimized version with fewer operations.
857         let result_type = value.get_type();
858         let value_type = result_type.to_unsigned(self.cx);
859
860         let value =
861             if result_type.is_signed(self.cx) {
862                 self.gcc_int_cast(value, value_type)
863             }
864             else {
865                 value
866             };
867
868         if value_type.is_u128(&self.cx) {
869             // TODO(antoyo): implement in the normal algorithm below to have a more efficient
870             // implementation (that does not require a call to __popcountdi2).
871             let popcount = self.context.get_builtin_function("__builtin_popcountll");
872             let sixty_four = self.gcc_int(value_type, 64);
873             let right_shift = self.gcc_lshr(value, sixty_four);
874             let high = self.gcc_int_cast(right_shift, self.cx.ulonglong_type);
875             let high = self.context.new_call(None, popcount, &[high]);
876             let low = self.gcc_int_cast(value, self.cx.ulonglong_type);
877             let low = self.context.new_call(None, popcount, &[low]);
878             let res = high + low;
879             return self.gcc_int_cast(res, result_type);
880         }
881
882         // First step.
883         let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
884         let left = value & mask;
885         let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
886         let right = shifted & mask;
887         let value = left + right;
888
889         // Second step.
890         let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
891         let left = value & mask;
892         let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
893         let right = shifted & mask;
894         let value = left + right;
895
896         // Third step.
897         let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
898         let left = value & mask;
899         let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
900         let right = shifted & mask;
901         let value = left + right;
902
903         if value_type.is_u8(&self.cx) {
904             return self.context.new_cast(None, value, result_type);
905         }
906
907         // Fourth step.
908         let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
909         let left = value & mask;
910         let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
911         let right = shifted & mask;
912         let value = left + right;
913
914         if value_type.is_u16(&self.cx) {
915             return self.context.new_cast(None, value, result_type);
916         }
917
918         // Fifth step.
919         let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
920         let left = value & mask;
921         let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
922         let right = shifted & mask;
923         let value = left + right;
924
925         if value_type.is_u32(&self.cx) {
926             return self.context.new_cast(None, value, result_type);
927         }
928
929         // Sixth step.
930         let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
931         let left = value & mask;
932         let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
933         let right = shifted & mask;
934         let value = left + right;
935
936         self.context.new_cast(None, value, result_type)
937     }
938
939     // Algorithm from: https://blog.regehr.org/archives/1063
940     fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
941         let max = self.const_uint(shift.get_type(), width);
942         let shift = self.urem(shift, max);
943         let lhs = self.shl(value, shift);
944         let result_neg = self.neg(shift);
945         let result_and =
946             self.and(
947                 result_neg,
948                 self.const_uint(shift.get_type(), width - 1),
949             );
950         let rhs = self.lshr(value, result_and);
951         self.or(lhs, rhs)
952     }
953
954     // Algorithm from: https://blog.regehr.org/archives/1063
955     fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
956         let max = self.const_uint(shift.get_type(), width);
957         let shift = self.urem(shift, max);
958         let lhs = self.lshr(value, shift);
959         let result_neg = self.neg(shift);
960         let result_and =
961             self.and(
962                 result_neg,
963                 self.const_uint(shift.get_type(), width - 1),
964             );
965         let rhs = self.shl(value, result_and);
966         self.or(lhs, rhs)
967     }
968
969     fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
970         let result_type = lhs.get_type();
971         if signed {
972             // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
973             let func = self.current_func.borrow().expect("func");
974             let res = func.new_local(None, result_type, "saturating_sum");
975             let supports_native_type = self.is_native_int_type(result_type);
976             let overflow =
977                 if supports_native_type {
978                     let func_name =
979                         match width {
980                             8 => "__builtin_add_overflow",
981                             16 => "__builtin_add_overflow",
982                             32 => "__builtin_sadd_overflow",
983                             64 => "__builtin_saddll_overflow",
984                             128 => "__builtin_add_overflow",
985                             _ => unreachable!(),
986                         };
987                     let overflow_func = self.context.get_builtin_function(func_name);
988                     self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None)
989                 }
990                 else {
991                     let func_name =
992                         match width {
993                             128 => "__rust_i128_addo",
994                             _ => unreachable!(),
995                         };
996                     let param_a = self.context.new_parameter(None, result_type, "a");
997                     let param_b = self.context.new_parameter(None, result_type, "b");
998                     let result_field = self.context.new_field(None, result_type, "result");
999                     let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
1000                     let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
1001                     let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
1002                     let result = self.context.new_call(None, func, &[lhs, rhs]);
1003                     let overflow = result.access_field(None, overflow_field);
1004                     let int_result = result.access_field(None, result_field);
1005                     self.llbb().add_assignment(None, res, int_result);
1006                     overflow
1007                 };
1008
1009             let then_block = func.new_block("then");
1010             let after_block = func.new_block("after");
1011
1012             // Return `result_type`'s maximum or minimum value on overflow
1013             // NOTE: convert the type to unsigned to have an unsigned shift.
1014             let unsigned_type = result_type.to_unsigned(&self.cx);
1015             let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1));
1016             let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0));
1017             let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1));
1018             then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type));
1019             then_block.end_with_jump(None, after_block);
1020
1021             self.llbb().end_with_conditional(None, overflow, then_block, after_block);
1022
1023             // NOTE: since jumps were added in a place rustc does not
1024             // expect, the current block in the state need to be updated.
1025             self.switch_to_block(after_block);
1026
1027             res.to_rvalue()
1028         }
1029         else {
1030             // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
1031             let res = self.gcc_add(lhs, rhs);
1032             let cond = self.gcc_icmp(IntPredicate::IntULT, res, lhs);
1033             let value = self.gcc_neg(self.gcc_int_cast(cond, result_type));
1034             self.gcc_or(res, value)
1035         }
1036     }
1037
1038     // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
1039     fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
1040         let result_type = lhs.get_type();
1041         if signed {
1042             // Based on algorithm from: https://stackoverflow.com/a/56531252/389119
1043             let func = self.current_func.borrow().expect("func");
1044             let res = func.new_local(None, result_type, "saturating_diff");
1045             let supports_native_type = self.is_native_int_type(result_type);
1046             let overflow =
1047                 if supports_native_type {
1048                     let func_name =
1049                         match width {
1050                             8 => "__builtin_sub_overflow",
1051                             16 => "__builtin_sub_overflow",
1052                             32 => "__builtin_ssub_overflow",
1053                             64 => "__builtin_ssubll_overflow",
1054                             128 => "__builtin_sub_overflow",
1055                             _ => unreachable!(),
1056                         };
1057                     let overflow_func = self.context.get_builtin_function(func_name);
1058                     self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None)
1059                 }
1060                 else {
1061                     let func_name =
1062                         match width {
1063                             128 => "__rust_i128_subo",
1064                             _ => unreachable!(),
1065                         };
1066                     let param_a = self.context.new_parameter(None, result_type, "a");
1067                     let param_b = self.context.new_parameter(None, result_type, "b");
1068                     let result_field = self.context.new_field(None, result_type, "result");
1069                     let overflow_field = self.context.new_field(None, self.bool_type, "overflow");
1070                     let return_type = self.context.new_struct_type(None, "result_overflow", &[result_field, overflow_field]);
1071                     let func = self.context.new_function(None, FunctionType::Extern, return_type.as_type(), &[param_a, param_b], func_name, false);
1072                     let result = self.context.new_call(None, func, &[lhs, rhs]);
1073                     let overflow = result.access_field(None, overflow_field);
1074                     let int_result = result.access_field(None, result_field);
1075                     self.llbb().add_assignment(None, res, int_result);
1076                     overflow
1077                 };
1078
1079             let then_block = func.new_block("then");
1080             let after_block = func.new_block("after");
1081
1082             // Return `result_type`'s maximum or minimum value on overflow
1083             // NOTE: convert the type to unsigned to have an unsigned shift.
1084             let unsigned_type = result_type.to_unsigned(&self.cx);
1085             let shifted = self.gcc_lshr(self.gcc_int_cast(lhs, unsigned_type), self.gcc_int(unsigned_type, width as i64 - 1));
1086             let uint_max = self.gcc_not(self.gcc_int(unsigned_type, 0));
1087             let int_max = self.gcc_lshr(uint_max, self.gcc_int(unsigned_type, 1));
1088             then_block.add_assignment(None, res, self.gcc_int_cast(self.gcc_add(shifted, int_max), result_type));
1089             then_block.end_with_jump(None, after_block);
1090
1091             self.llbb().end_with_conditional(None, overflow, then_block, after_block);
1092
1093             // NOTE: since jumps were added in a place rustc does not
1094             // expect, the current block in the state need to be updated.
1095             self.switch_to_block(after_block);
1096
1097             res.to_rvalue()
1098         }
1099         else {
1100             let res = self.gcc_sub(lhs, rhs);
1101             let comparison = self.gcc_icmp(IntPredicate::IntULE, res, lhs);
1102             let value = self.gcc_neg(self.gcc_int_cast(comparison, result_type));
1103             self.gcc_and(res, value)
1104         }
1105     }
1106 }
1107
1108 fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
1109     // NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too
1110     if bx.sess().panic_strategy() == PanicStrategy::Abort || true {
1111         // TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done.
1112         bx.call(bx.type_void(), try_func, &[data], None);
1113         // Return 0 unconditionally from the intrinsic call;
1114         // we can never unwind.
1115         let ret_align = bx.tcx.data_layout.i32_align.abi;
1116         bx.store(bx.const_i32(0), dest, ret_align);
1117     }
1118     else if wants_msvc_seh(bx.sess()) {
1119         unimplemented!();
1120     }
1121     else {
1122         unimplemented!();
1123     }
1124 }