From 9135ec52c6afbb8c672f72684185b487808de569 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 9 Jul 2018 23:18:03 -0700 Subject: [PATCH] Add nowrap_{add|sub|mul|neg} intrinsics LLVM cannot deduce nsw/nuw for things like Range::next today, so add these so that my next PR can use them to improve what Range tells LLVM. --- src/libcore/intrinsics.rs | 22 ++++++++ src/librustc_codegen_llvm/intrinsic.rs | 27 +++++++++- src/librustc_typeck/check/intrinsic.rs | 7 +++ src/test/codegen/nowrap-intrinsic.rs | 70 ++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/test/codegen/nowrap-intrinsic.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 89fe2d941a350..f9d6bd67bae7d 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1367,4 +1367,26 @@ extern "rust-intrinsic" { /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); + + /// Add `a + b`, but with undefined behaviour if the sum overflows. + #[cfg(not(stage0))] + pub fn nowrap_add(a: T, b: T) -> T; + /// Subtract `a - b`, but with undefined behaviour if the difference overflows. + #[cfg(not(stage0))] + pub fn nowrap_sub(a: T, b: T) -> T; + /// Multiply `a * b`, but with undefined behaviour if the produce overflows. + #[cfg(not(stage0))] + pub fn nowrap_mul(a: T, b: T) -> T; + /// Negate `-a`, but with undefined behaviour if it the negation overflows. + #[cfg(not(stage0))] + pub fn nowrap_neg(a: T) -> T; } + +#[cfg(stage0)] +pub unsafe fn nowrap_add(a: T, b: T) -> T { add_with_overflow(a, b).0 } +#[cfg(stage0)] +pub unsafe fn nowrap_sub(a: T, b: T) -> T { sub_with_overflow(a, b).0 } +#[cfg(stage0)] +pub unsafe fn nowrap_mul(a: T, b: T) -> T { mul_with_overflow(a, b).0 } +#[cfg(stage0)] +pub unsafe fn nowrap_neg(a: T) -> T { nowrap_sub(T::default(), a) } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 6bb5456f9034f..52b5059735044 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -271,7 +271,8 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "bitreverse" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | - "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => { + "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" | + "nowrap_add" | "nowrap_sub" | "nowrap_mul" | "nowrap_neg" => { let ty = arg_tys[0]; match int_type_width_signed(ty, cx) { Some((width, signed)) => @@ -350,6 +351,30 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } else { bx.lshr(args[0].immediate(), args[1].immediate()) }, + "nowrap_add" => + if signed { + bx.nswadd(args[0].immediate(), args[1].immediate()) + } else { + bx.nuwadd(args[0].immediate(), args[1].immediate()) + }, + "nowrap_sub" => + if signed { + bx.nswsub(args[0].immediate(), args[1].immediate()) + } else { + bx.nuwsub(args[0].immediate(), args[1].immediate()) + }, + "nowrap_mul" => + if signed { + bx.nswmul(args[0].immediate(), args[1].immediate()) + } else { + bx.nuwmul(args[0].immediate(), args[1].immediate()) + }, + "nowrap_neg" => + if signed { + bx.nswneg(args[0].immediate()) + } else { + bx.nuwneg(args[0].immediate()) + }, _ => bug!(), }, None => { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index c93023edcea08..2c8a9207639c9 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -318,6 +318,13 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()) } + "nowrap_add" | "nowrap_sub" | "nowrap_mul" => { + (1, vec![param(0), param(0)], param(0)) + } + "nowrap_neg" => { + (1, vec![param(0)], param(0)) + } + ref other => { struct_span_err!(tcx.sess, it.span, E0093, "unrecognized intrinsic function: `{}`", diff --git a/src/test/codegen/nowrap-intrinsic.rs b/src/test/codegen/nowrap-intrinsic.rs new file mode 100644 index 0000000000000..8f21f6a994a9f --- /dev/null +++ b/src/test/codegen/nowrap-intrinsic.rs @@ -0,0 +1,70 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +// CHECK-LABEL: @nowrap_add_signed +#[no_mangle] +pub unsafe fn nowrap_add_signed(a: i32, b: i32) -> i32 { + // CHECK: add nsw + nowrap_add(a, b) +} + +// CHECK-LABEL: @nowrap_add_unsigned +#[no_mangle] +pub unsafe fn nowrap_add_unsigned(a: u32, b: u32) -> u32 { + // CHECK: add nuw + nowrap_add(a, b) +} + +// CHECK-LABEL: @nowrap_sub_signed +#[no_mangle] +pub unsafe fn nowrap_sub_signed(a: i32, b: i32) -> i32 { + // CHECK: sub nsw + nowrap_sub(a, b) +} + +// CHECK-LABEL: @nowrap_sub_unsigned +#[no_mangle] +pub unsafe fn nowrap_sub_unsigned(a: u32, b: u32) -> u32 { + // CHECK: sub nuw + nowrap_sub(a, b) +} + +// CHECK-LABEL: @nowrap_mul_signed +#[no_mangle] +pub unsafe fn nowrap_mul_signed(a: i32, b: i32) -> i32 { + // CHECK: mul nsw + nowrap_mul(a, b) +} + +// CHECK-LABEL: @nowrap_mul_unsigned +#[no_mangle] +pub unsafe fn nowrap_mul_unsigned(a: u32, b: u32) -> u32 { + // CHECK: mul nuw + nowrap_mul(a, b) +} + +// CHECK-LABEL: @nowrap_neg_signed +#[no_mangle] +pub unsafe fn nowrap_neg_signed(a: i32) -> i32 { + // CHECK: sub nsw i32 0, + nowrap_neg(a) +} + +// CHECK-LABEL: @nowrap_neg_unsigned +#[no_mangle] +pub unsafe fn nowrap_neg_unsigned(a: u32) -> u32 { + // CHECK: ret i32 0 + nowrap_neg(a) +}