|
13 | 13 | use attributes;
|
14 | 14 | use intrinsics::{self, Intrinsic};
|
15 | 15 | use llvm::{self, TypeKind};
|
| 16 | +use llvm_util; |
16 | 17 | use abi::{Abi, FnType, LlvmType, PassMode};
|
17 | 18 | use mir::place::PlaceRef;
|
18 | 19 | use mir::operand::{OperandRef, OperandValue};
|
@@ -284,7 +285,8 @@ pub fn codegen_intrinsic_call(
|
284 | 285 | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
|
285 | 286 | "bitreverse" | "add_with_overflow" | "sub_with_overflow" |
|
286 | 287 | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
|
287 |
| - "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => { |
| 288 | + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" | |
| 289 | + "rotate_left" | "rotate_right" => { |
288 | 290 | let ty = arg_tys[0];
|
289 | 291 | match int_type_width_signed(ty, cx) {
|
290 | 292 | Some((width, signed)) =>
|
@@ -363,6 +365,27 @@ pub fn codegen_intrinsic_call(
|
363 | 365 | } else {
|
364 | 366 | bx.lshr(args[0].immediate(), args[1].immediate())
|
365 | 367 | },
|
| 368 | + "rotate_left" | "rotate_right" => { |
| 369 | + let is_left = name == "rotate_left"; |
| 370 | + let val = args[0].immediate(); |
| 371 | + let raw_shift = args[1].immediate(); |
| 372 | + if llvm_util::get_major_version() >= 7 { |
| 373 | + // rotate = funnel shift with first two args the same |
| 374 | + let llvm_name = &format!("llvm.fsh{}.i{}", |
| 375 | + if is_left { 'l' } else { 'r' }, width); |
| 376 | + let llfn = cx.get_intrinsic(llvm_name); |
| 377 | + bx.call(llfn, &[val, val, raw_shift], None) |
| 378 | + } else { |
| 379 | + // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW)) |
| 380 | + // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW)) |
| 381 | + let width = C_uint(Type::ix(cx, width), width); |
| 382 | + let shift = bx.urem(raw_shift, width); |
| 383 | + let inv_shift = bx.urem(bx.sub(width, raw_shift), width); |
| 384 | + let shift1 = bx.shl(val, if is_left { shift } else { inv_shift }); |
| 385 | + let shift2 = bx.lshr(val, if !is_left { shift } else { inv_shift }); |
| 386 | + bx.or(shift1, shift2) |
| 387 | + } |
| 388 | + }, |
366 | 389 | _ => bug!(),
|
367 | 390 | },
|
368 | 391 | None => {
|
|
0 commit comments