Skip to content

Commit 440a526

Browse files
committed
Set signext or zeroext for integer arguments on RISC-V
1 parent 9ba8053 commit 440a526

15 files changed

+210
-33
lines changed

Diff for: compiler/rustc_target/src/callconv/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
728728
let spec = cx.target_spec();
729729
match &spec.arch[..] {
730730
"x86" => x86::compute_rust_abi_info(cx, self, abi),
731+
"riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self, abi),
731732
_ => {}
732733
};
733734

Diff for: compiler/rustc_target/src/callconv/riscv.rs

+27
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use crate::abi::call::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform};
88
use crate::abi::{self, Abi, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
99
use crate::spec::HasTargetSpec;
10+
use crate::spec::abi::Abi as SpecAbi;
1011

1112
#[derive(Copy, Clone)]
1213
enum RegPassKind {
@@ -365,3 +366,29 @@ where
365366
);
366367
}
367368
}
369+
370+
pub(crate) fn compute_rust_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, abi: SpecAbi)
371+
where
372+
Ty: TyAbiInterface<'a, C> + Copy,
373+
C: HasDataLayout + HasTargetSpec,
374+
{
375+
if abi == SpecAbi::RustIntrinsic {
376+
return;
377+
}
378+
379+
let xlen = cx.data_layout().pointer_size.bits();
380+
381+
for arg in fn_abi.args.iter_mut() {
382+
if arg.is_ignore() {
383+
continue;
384+
}
385+
386+
// LLVM integers types do not differentiate between signed or unsigned integers.
387+
// Some RISC-V instructions do not have a `.w` suffix version, they use all the
388+
// XLEN bits. By explicitly setting the `signext` or `zeroext` attribute
389+
// according to signedness to avoid unnecessary integer extending instructions.
390+
//
391+
// See https://github.com/rust-lang/rust/issues/114508 for details.
392+
extend_integer_width(arg, xlen);
393+
}
394+
}

Diff for: tests/assembly/rust-abi-arg-attr.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//@ assembly-output: emit-asm
2+
//@ revisions: riscv64 riscv64-zbb
3+
//@ compile-flags: -C opt-level=3
4+
//@ [riscv64] only-riscv64
5+
//@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu
6+
//@ [riscv64] needs-llvm-components: riscv
7+
//@ [riscv64-zbb] only-riscv64
8+
//@ [riscv64-zbb] compile-flags: --target riscv64gc-unknown-linux-gnu
9+
//@ [riscv64-zbb] compile-flags: -C target-feature=+zbb
10+
//@ [riscv64-zbb] needs-llvm-components: riscv
11+
12+
#![crate_type = "lib"]
13+
14+
#[no_mangle]
15+
// CHECK-LABEL: issue_114508_u32:
16+
pub fn issue_114508_u32(a: u32, b: u32) -> u32 {
17+
// CHECK-NEXT: .cfi_startproc
18+
19+
// riscv64-NEXT: bltu a1, a0, .[[RET:.+]]
20+
// riscv64-NEXT: mv a0, a1
21+
// riscv64-NEXT: .[[RET]]:
22+
23+
// riscv64-zbb-NEXT: maxu a0, a0, a1
24+
25+
// CHECK-NEXT: ret
26+
u32::max(a, b)
27+
}
28+
29+
#[no_mangle]
30+
// CHECK-LABEL: issue_114508_i32:
31+
pub fn issue_114508_i32(a: i32, b: i32) -> i32 {
32+
// CHECK-NEXT: .cfi_startproc
33+
34+
// riscv64-NEXT: blt a1, a0, .[[RET:.+]]
35+
// riscv64-NEXT: mv a0, a1
36+
// riscv64-NEXT: .[[RET]]:
37+
38+
// riscv64-zbb-NEXT: max a0, a0, a1
39+
40+
// CHECK-NEXT: ret
41+
i32::max(a, b)
42+
}

Diff for: tests/codegen/checked_ilog.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Ensure that when val < base, we do not divide or multiply.
66

77
// CHECK-LABEL: @checked_ilog
8-
// CHECK-SAME: (i16 noundef %val, i16 noundef %base)
8+
// CHECK-SAME: (i16{{.*}} %val, i16{{.*}} %base)
99
#[no_mangle]
1010
pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
1111
// CHECK-NOT: udiv

Diff for: tests/codegen/checked_math.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// Thanks to poison semantics, this doesn't even need branches.
99

1010
// CHECK-LABEL: @checked_sub_unsigned
11-
// CHECK-SAME: (i16 noundef %a, i16 noundef %b)
11+
// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
1212
#[no_mangle]
1313
pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> {
1414
// CHECK-DAG: %[[IS_SOME:.+]] = icmp uge i16 %a, %b
@@ -26,7 +26,7 @@ pub fn checked_sub_unsigned(a: u16, b: u16) -> Option<u16> {
2626
// looking for no-wrap flags, we just need there to not be any masking.
2727

2828
// CHECK-LABEL: @checked_shl_unsigned
29-
// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
29+
// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
3030
#[no_mangle]
3131
pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> {
3232
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -41,7 +41,7 @@ pub fn checked_shl_unsigned(a: u32, b: u32) -> Option<u32> {
4141
}
4242

4343
// CHECK-LABEL: @checked_shr_unsigned
44-
// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
44+
// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
4545
#[no_mangle]
4646
pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> {
4747
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -56,7 +56,7 @@ pub fn checked_shr_unsigned(a: u32, b: u32) -> Option<u32> {
5656
}
5757

5858
// CHECK-LABEL: @checked_shl_signed
59-
// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
59+
// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
6060
#[no_mangle]
6161
pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> {
6262
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -71,7 +71,7 @@ pub fn checked_shl_signed(a: i32, b: u32) -> Option<i32> {
7171
}
7272

7373
// CHECK-LABEL: @checked_shr_signed
74-
// CHECK-SAME: (i32 noundef %a, i32 noundef %b)
74+
// CHECK-SAME: (i32{{.*}} %a, i32{{.*}} %b)
7575
#[no_mangle]
7676
pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
7777
// CHECK-DAG: %[[IS_SOME:.+]] = icmp ult i32 %b, 32
@@ -86,7 +86,7 @@ pub fn checked_shr_signed(a: i32, b: u32) -> Option<i32> {
8686
}
8787

8888
// CHECK-LABEL: @checked_add_one_unwrap_unsigned
89-
// CHECK-SAME: (i32 noundef %x)
89+
// CHECK-SAME: (i32{{.*}} %x)
9090
#[no_mangle]
9191
pub fn checked_add_one_unwrap_unsigned(x: u32) -> u32 {
9292
// CHECK: %[[IS_MAX:.+]] = icmp eq i32 %x, -1

Diff for: tests/codegen/comparison-operators-newtype.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::cmp::Ordering;
1212
pub struct Foo(u16);
1313

1414
// CHECK-LABEL: @check_lt
15-
// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
15+
// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
1616
#[no_mangle]
1717
pub fn check_lt(a: Foo, b: Foo) -> bool {
1818
// CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
@@ -21,7 +21,7 @@ pub fn check_lt(a: Foo, b: Foo) -> bool {
2121
}
2222

2323
// CHECK-LABEL: @check_le
24-
// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
24+
// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
2525
#[no_mangle]
2626
pub fn check_le(a: Foo, b: Foo) -> bool {
2727
// CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
@@ -30,7 +30,7 @@ pub fn check_le(a: Foo, b: Foo) -> bool {
3030
}
3131

3232
// CHECK-LABEL: @check_gt
33-
// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
33+
// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
3434
#[no_mangle]
3535
pub fn check_gt(a: Foo, b: Foo) -> bool {
3636
// CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
@@ -39,7 +39,7 @@ pub fn check_gt(a: Foo, b: Foo) -> bool {
3939
}
4040

4141
// CHECK-LABEL: @check_ge
42-
// CHECK-SAME: (i16 noundef %[[A:.+]], i16 noundef %[[B:.+]])
42+
// CHECK-SAME: (i16{{.*}} %[[A:.+]], i16{{.*}} %[[B:.+]])
4343
#[no_mangle]
4444
pub fn check_ge(a: Foo, b: Foo) -> bool {
4545
// CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]

Diff for: tests/codegen/fewer-names.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
#[no_mangle]
88
pub fn sum(x: u32, y: u32) -> u32 {
9-
// YES-LABEL: define{{.*}}i32 @sum(i32 noundef %0, i32 noundef %1)
9+
// YES-LABEL: define{{.*}}i32 @sum(i32{{.*}} %0, i32{{.*}} %1)
1010
// YES-NEXT: %3 = add i32 %1, %0
1111
// YES-NEXT: ret i32 %3
1212

13-
// NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y)
13+
// NO-LABEL: define{{.*}}i32 @sum(i32{{.*}} %x, i32{{.*}} %y)
1414
// NO-NEXT: start:
1515
// NO-NEXT: %z = add i32 %y, %x
1616
// NO-NEXT: ret i32 %z

Diff for: tests/codegen/function-arguments.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn boolean(x: bool) -> bool {
3232
x
3333
}
3434

35-
// CHECK: i8 @maybeuninit_boolean(i8 %x)
35+
// CHECK: i8 @maybeuninit_boolean(i8{{.*}} %x)
3636
#[no_mangle]
3737
pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
3838
x
@@ -44,19 +44,19 @@ pub fn enum_bool(x: MyBool) -> MyBool {
4444
x
4545
}
4646

47-
// CHECK: i8 @maybeuninit_enum_bool(i8 %x)
47+
// CHECK: i8 @maybeuninit_enum_bool(i8{{.*}} %x)
4848
#[no_mangle]
4949
pub fn maybeuninit_enum_bool(x: MaybeUninit<MyBool>) -> MaybeUninit<MyBool> {
5050
x
5151
}
5252

53-
// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32 noundef{{( range\(i32 0, 1114112\))?}} %x)
53+
// CHECK: noundef{{( range\(i32 0, 1114112\))?}} i32 @char(i32{{.*}}{{( range\(i32 0, 1114112\))?}} %x)
5454
#[no_mangle]
5555
pub fn char(x: char) -> char {
5656
x
5757
}
5858

59-
// CHECK: i32 @maybeuninit_char(i32 %x)
59+
// CHECK: i32 @maybeuninit_char(i32{{.*}} %x)
6060
#[no_mangle]
6161
pub fn maybeuninit_char(x: MaybeUninit<char>) -> MaybeUninit<char> {
6262
x

Diff for: tests/codegen/intrinsics/three_way_compare.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ use std::intrinsics::three_way_compare;
1010

1111
#[no_mangle]
1212
// CHECK-LABEL: @signed_cmp
13-
// DEBUG-SAME: (i16 %a, i16 %b)
14-
// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
13+
// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
1514
pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
1615
// DEBUG: %[[GT:.+]] = icmp sgt i16 %a, %b
1716
// DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8
@@ -29,8 +28,7 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering {
2928

3029
#[no_mangle]
3130
// CHECK-LABEL: @unsigned_cmp
32-
// DEBUG-SAME: (i16 %a, i16 %b)
33-
// OPTIM-SAME: (i16 noundef %a, i16 noundef %b)
31+
// CHECK-SAME: (i16{{.*}} %a, i16{{.*}} %b)
3432
pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering {
3533
// DEBUG: %[[GT:.+]] = icmp ugt i16 %a, %b
3634
// DEBUG: %[[ZGT:.+]] = zext i1 %[[GT]] to i8

Diff for: tests/codegen/mir-aggregate-no-alloca.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#[repr(transparent)]
1010
pub struct Transparent32(u32);
1111

12-
// CHECK: i32 @make_transparent(i32 noundef %x)
12+
// CHECK: i32 @make_transparent(i32{{.*}} %x)
1313
#[no_mangle]
1414
pub fn make_transparent(x: u32) -> Transparent32 {
1515
// CHECK-NOT: alloca
@@ -18,7 +18,7 @@ pub fn make_transparent(x: u32) -> Transparent32 {
1818
a
1919
}
2020

21-
// CHECK: i32 @make_closure(i32 noundef %x)
21+
// CHECK: i32 @make_closure(i32{{.*}} %x)
2222
#[no_mangle]
2323
pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 {
2424
// CHECK-NOT: alloca
@@ -40,7 +40,7 @@ pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair {
4040
a
4141
}
4242

43-
// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x)
43+
// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32{{.*}} %x)
4444
#[no_mangle]
4545
pub fn make_2_tuple(x: u32) -> (u32, u32) {
4646
// CHECK-NOT: alloca
@@ -59,7 +59,7 @@ pub fn make_cell_of_bool(b: bool) -> std::cell::Cell<bool> {
5959
std::cell::Cell::new(b)
6060
}
6161

62-
// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s)
62+
// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16{{.*}} %s)
6363
#[no_mangle]
6464
pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
6565
// CHECK-NOT: alloca
@@ -92,7 +92,7 @@ pub fn make_struct_0() -> Struct0 {
9292

9393
pub struct Struct1(i32);
9494

95-
// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a)
95+
// CHECK-LABEL: i32 @make_struct_1(i32{{.*}} %a)
9696
#[no_mangle]
9797
pub fn make_struct_1(a: i32) -> Struct1 {
9898
// CHECK: ret i32 %a
@@ -104,7 +104,7 @@ pub struct Struct2Asc(i16, i64);
104104

105105
// bit32-LABEL: void @make_struct_2_asc({{.*}} sret({{[^,]*}}) {{.*}} %s,
106106
// bit64-LABEL: { i64, i16 } @make_struct_2_asc(
107-
// CHECK-SAME: i16 noundef %a, i64 noundef %b)
107+
// CHECK-SAME: i16{{.*}} %a, i64 noundef %b)
108108
#[no_mangle]
109109
pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc {
110110
// CHECK-NOT: alloca
@@ -122,7 +122,7 @@ pub struct Struct2Desc(i64, i16);
122122

123123
// bit32-LABEL: void @make_struct_2_desc({{.*}} sret({{[^,]*}}) {{.*}} %s,
124124
// bit64-LABEL: { i64, i16 } @make_struct_2_desc(
125-
// CHECK-SAME: i64 noundef %a, i16 noundef %b)
125+
// CHECK-SAME: i64 noundef %a, i16{{.*}} %b)
126126
#[no_mangle]
127127
pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc {
128128
// CHECK-NOT: alloca

Diff for: tests/codegen/range-attribute.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub fn nonzero_int(x: NonZero<u128>) -> NonZero<u128> {
2424
x
2525
}
2626

27-
// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8 noundef range(i8 0, 3) %x)
27+
// CHECK: noundef range(i8 0, 3) i8 @optional_bool(i8{{.*}} range(i8 0, 3) %x)
2828
#[no_mangle]
2929
pub fn optional_bool(x: Option<bool>) -> Option<bool> {
3030
x
@@ -36,7 +36,7 @@ pub enum Enum0 {
3636
C,
3737
}
3838

39-
// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8 noundef range(i8 0, 4) %x)
39+
// CHECK: noundef range(i8 0, 4) i8 @enum0_value(i8{{.*}} range(i8 0, 4) %x)
4040
#[no_mangle]
4141
pub fn enum0_value(x: Enum0) -> Enum0 {
4242
x

0 commit comments

Comments
 (0)