Skip to content

Commit 9135ec5

Browse files
committed
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.
1 parent fb97bb5 commit 9135ec5

File tree

4 files changed

+125
-1
lines changed

4 files changed

+125
-1
lines changed

src/libcore/intrinsics.rs

+22
Original file line numberDiff line numberDiff line change
@@ -1367,4 +1367,26 @@ extern "rust-intrinsic" {
13671367
/// Emits a `!nontemporal` store according to LLVM (see their docs).
13681368
/// Probably will never become stable.
13691369
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
1370+
1371+
/// Add `a + b`, but with undefined behaviour if the sum overflows.
1372+
#[cfg(not(stage0))]
1373+
pub fn nowrap_add<T>(a: T, b: T) -> T;
1374+
/// Subtract `a - b`, but with undefined behaviour if the difference overflows.
1375+
#[cfg(not(stage0))]
1376+
pub fn nowrap_sub<T>(a: T, b: T) -> T;
1377+
/// Multiply `a * b`, but with undefined behaviour if the produce overflows.
1378+
#[cfg(not(stage0))]
1379+
pub fn nowrap_mul<T>(a: T, b: T) -> T;
1380+
/// Negate `-a`, but with undefined behaviour if it the negation overflows.
1381+
#[cfg(not(stage0))]
1382+
pub fn nowrap_neg<T>(a: T) -> T;
13701383
}
1384+
1385+
#[cfg(stage0)]
1386+
pub unsafe fn nowrap_add<T>(a: T, b: T) -> T { add_with_overflow(a, b).0 }
1387+
#[cfg(stage0)]
1388+
pub unsafe fn nowrap_sub<T>(a: T, b: T) -> T { sub_with_overflow(a, b).0 }
1389+
#[cfg(stage0)]
1390+
pub unsafe fn nowrap_mul<T>(a: T, b: T) -> T { mul_with_overflow(a, b).0 }
1391+
#[cfg(stage0)]
1392+
pub unsafe fn nowrap_neg<T: Default>(a: T) -> T { nowrap_sub(T::default(), a) }

src/librustc_codegen_llvm/intrinsic.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
271271
"ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
272272
"bitreverse" | "add_with_overflow" | "sub_with_overflow" |
273273
"mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
274-
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" => {
274+
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" | "exact_div" |
275+
"nowrap_add" | "nowrap_sub" | "nowrap_mul" | "nowrap_neg" => {
275276
let ty = arg_tys[0];
276277
match int_type_width_signed(ty, cx) {
277278
Some((width, signed)) =>
@@ -350,6 +351,30 @@ pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
350351
} else {
351352
bx.lshr(args[0].immediate(), args[1].immediate())
352353
},
354+
"nowrap_add" =>
355+
if signed {
356+
bx.nswadd(args[0].immediate(), args[1].immediate())
357+
} else {
358+
bx.nuwadd(args[0].immediate(), args[1].immediate())
359+
},
360+
"nowrap_sub" =>
361+
if signed {
362+
bx.nswsub(args[0].immediate(), args[1].immediate())
363+
} else {
364+
bx.nuwsub(args[0].immediate(), args[1].immediate())
365+
},
366+
"nowrap_mul" =>
367+
if signed {
368+
bx.nswmul(args[0].immediate(), args[1].immediate())
369+
} else {
370+
bx.nuwmul(args[0].immediate(), args[1].immediate())
371+
},
372+
"nowrap_neg" =>
373+
if signed {
374+
bx.nswneg(args[0].immediate())
375+
} else {
376+
bx.nuwneg(args[0].immediate())
377+
},
353378
_ => bug!(),
354379
},
355380
None => {

src/librustc_typeck/check/intrinsic.rs

+7
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,13 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
318318
(1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil())
319319
}
320320

321+
"nowrap_add" | "nowrap_sub" | "nowrap_mul" => {
322+
(1, vec![param(0), param(0)], param(0))
323+
}
324+
"nowrap_neg" => {
325+
(1, vec![param(0)], param(0))
326+
}
327+
321328
ref other => {
322329
struct_span_err!(tcx.sess, it.span, E0093,
323330
"unrecognized intrinsic function: `{}`",

src/test/codegen/nowrap-intrinsic.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type = "lib"]
12+
#![feature(core_intrinsics)]
13+
14+
use std::intrinsics::*;
15+
16+
// CHECK-LABEL: @nowrap_add_signed
17+
#[no_mangle]
18+
pub unsafe fn nowrap_add_signed(a: i32, b: i32) -> i32 {
19+
// CHECK: add nsw
20+
nowrap_add(a, b)
21+
}
22+
23+
// CHECK-LABEL: @nowrap_add_unsigned
24+
#[no_mangle]
25+
pub unsafe fn nowrap_add_unsigned(a: u32, b: u32) -> u32 {
26+
// CHECK: add nuw
27+
nowrap_add(a, b)
28+
}
29+
30+
// CHECK-LABEL: @nowrap_sub_signed
31+
#[no_mangle]
32+
pub unsafe fn nowrap_sub_signed(a: i32, b: i32) -> i32 {
33+
// CHECK: sub nsw
34+
nowrap_sub(a, b)
35+
}
36+
37+
// CHECK-LABEL: @nowrap_sub_unsigned
38+
#[no_mangle]
39+
pub unsafe fn nowrap_sub_unsigned(a: u32, b: u32) -> u32 {
40+
// CHECK: sub nuw
41+
nowrap_sub(a, b)
42+
}
43+
44+
// CHECK-LABEL: @nowrap_mul_signed
45+
#[no_mangle]
46+
pub unsafe fn nowrap_mul_signed(a: i32, b: i32) -> i32 {
47+
// CHECK: mul nsw
48+
nowrap_mul(a, b)
49+
}
50+
51+
// CHECK-LABEL: @nowrap_mul_unsigned
52+
#[no_mangle]
53+
pub unsafe fn nowrap_mul_unsigned(a: u32, b: u32) -> u32 {
54+
// CHECK: mul nuw
55+
nowrap_mul(a, b)
56+
}
57+
58+
// CHECK-LABEL: @nowrap_neg_signed
59+
#[no_mangle]
60+
pub unsafe fn nowrap_neg_signed(a: i32) -> i32 {
61+
// CHECK: sub nsw i32 0,
62+
nowrap_neg(a)
63+
}
64+
65+
// CHECK-LABEL: @nowrap_neg_unsigned
66+
#[no_mangle]
67+
pub unsafe fn nowrap_neg_unsigned(a: u32) -> u32 {
68+
// CHECK: ret i32 0
69+
nowrap_neg(a)
70+
}

0 commit comments

Comments
 (0)