Suspected LLVM miscompilation of bool to int cast
cbeuw opened this issue · comments
The reproduction is fuzzer-generated custom MIR then (somewhat) minimised. I couldn't rewrite it into surface Rust as there are back edges to non-dominating basic blocks (they can't be turned into surface Rust loops). It's possible that rustc considers such control flow invalid, though this is likely an LLVM miscompilation and such control flow is valid at LLVM IR level. Miri also does not complain.
The actual execution flow has no loops, all statements are executed only once. Indented BBs are not taken, but still required for the reproduction.
#![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
pub fn print_var(x: usize) {
println!("{x}");
}
#[custom_mir(dialect = "runtime", phase = "initial")]
pub fn fn1(){
mir! {
let _2: i128;
let _3: i16;
let _4: usize;
let _6: (u32, f64);
let _7: (u32, f64);
let _8: f64;
let _9: isize;
let _10: *mut (u8,);
let _12: *mut i8;
let _15: (u32, *mut (u8,));
let _16: isize;
let _17: usize;
let _18: (u128, u8, bool, u32, char, i8, u32, i32);
let _18_ptr: *mut (u128, u8, bool, u32, char, i8, u32, i32);
let _24: (i32, ([f32; 6],));
let _26: f32;
let _27: f32;
let _30: *mut i8;
let _31: isize;
let _32: isize;
let _33: u8;
let _34: u64;
let _40: f32;
let _41: bool;
let _45: f64;
let _51: *mut (u32, f64);
let _52: *mut i8;
let _55: u32;
let _60: u64;
let _62: (u8,);
let _64: usize;
let _68: *mut (u32, f64);
let _85: *mut (u32, f64);
let _88: (u8,);
let _98: (u8,);
let _106: f32;
let _109: (u8,);
let _111: *mut i8;
let _113: i16;
let _115: u64;
let _335: ();
{
_2 = 0;
_4 = 0;
_6 = (0, 0.);
_7 = _6;
_15.0 = _6.0;
_18_ptr = core::ptr::addr_of_mut!(_18);
_12 = core::ptr::addr_of_mut!((*_18_ptr).5);
(*_18_ptr).7 = 36514_u16 as i32;
_17 = !_4;
Goto(bb2)
}
bb2 = {
_16 = _17 as isize;
_26 = _7.1 as f32;
_27 = _26;
_8 = _6.1 + _7.1;
Goto(bb3)
}
bb3 = {
_24.0 = (*_18_ptr).7;
(*_18_ptr).1 = 170_u8;
*_12 = 49;
(*_18_ptr).7 = -221108602_i32;
Goto(bb6)
}
bb4 = {
_27 = _26;
Goto(bb3)
}
bb5 = {
_12 = core::ptr::addr_of_mut!((*_18_ptr).5);
Goto(bb2)
}
bb6 = {
_3 = 18339_i16;
_31 = _6.1 as isize;
Goto(bb7)
}
bb7 = {
match (*_18_ptr).5 {
0 => bb8,
49 => bb10,
_ => ret
}
}
bb8 = {
_31 = _9 << _15.0;
Goto(bb7)
}
bb10 = {
match (*_18_ptr).1 {
1 => bb2,
2 => bb3,
3 => bb4,
4 => bb5,
6 => bb7,
170 => bb12,
_ => ret
}
}
bb12 = {
_32 = _31;
match (*_18_ptr).7 {
-221108602 => bb13,
_ => bb9
}
}
bb9 = {
_17 = _4;
Goto(bb3)
}
bb13 = {
_30 = core::ptr::addr_of_mut!((*_18_ptr).5);
Goto(bb20)
}
bb16 = {
match (*_18_ptr).1 {
2 => bb3,
3 => bb4,
6 => bb7,
170 => bb12,
_ => ret
}
}
bb19 = {
match (*_18_ptr).5 {
0 => bb8,
49 => bb10,
_ => bb9
}
}
bb20 = {
match _3 {
0 => bb6,
18339 => bb23,
_ => bb19
}
}
bb23 = {
_51 = core::ptr::addr_of_mut!(_6);
_52 = _12;
(*_18_ptr).0 = 66683941810808954240874936259049749206_u128;
(*_18_ptr).3 = 3241810161_u32;
match (*_18_ptr).3 {
3241810161 => bb25,
_ => bb5
}
}
bb25 = {
_34 = 2204794180844018677_u64;
_33 = (*_18_ptr).0 as u8;
(*_51).1 = _7.1 / f64::NAN;
Goto(bb27)
}
bb27 = {
_7.1 = _6.1;
(*_18_ptr).7 = _24.0;
(*_51) = _7;
_40 = _26 - _26;
Goto(bb28)
}
bb28 = {
_12 = _52;
_55 = _40 as u32;
(*_18_ptr).1 = _33;
Goto(bb29)
}
bb29 = {
match (*_18_ptr).3 {
3241810161 => bb31,
_ => bb30
}
}
bb30 = {
match (*_18_ptr).7 {
3 => bb16,
-221108602 => bb20,
_ => bb19
}
}
bb31 = {
_10 = core::ptr::addr_of_mut!(_62);
(*_12) = 115_i8;
_68 = core::ptr::addr_of_mut!(_7);
_51 = _68;
match _34 {
2204794180844018677 => bb33,
_ => bb23
}
}
bb33 = {
(*_68).0 = _55;
(*_10).0 = _33;
_45 = (*_68).1;
(*_68).1 = _8;
_106 = _27;
_85 = core::ptr::addr_of_mut!(_6);
_60 = _34;
_111 = _12;
_41 = _45 != (*_68).1;
Goto(bb52)
}
bb52 = {
_98 = *_10;
_113 = _106 as i16;
_33 = !_98.0;
_26 = _106 / f32::NAN;
_52 = _30;
_3 = _113 >> (*_111);
Goto(bb67)
}
bb67 = {
*_51 = *_85;
_109.0 = (*_10).0 | _33;
_115 = _60 << (*_18_ptr).3;
_88 = _109;
(*_18_ptr) = (169547000073183258424114496411693076442_u128, 225_u8, true, 3440650345_u32, '\u{f03a2}', (-32_i8), 1579607197_u32, (-460487397_i32));
(*_10).0 = _2 as u8;
match *_111 {
1 => bb27,
3 => bb67,
-32 => bb75,
_ => bb19
}
}
bb75 = {
(*_10) = _88;
_34 = !_115;
_51 = _85;
(*_18_ptr).5 = -20;
Goto(bb138)
}
bb138 = {
match *_12 {
0 => bb28,
2 => bb52,
3 => bb155,
-20 => bb158,
_ => ret
}
}
bb155 = {
_12 = _52;
Goto(bb138)
}
bb158 = {
_64 = _41 as usize; // _41 is a boolean so this has to print 0 or 1
Call(_335, ret, print_var(Move(_64)))
}
ret = {
Return()
}
}
}
pub fn main() {
fn1();
}
In Miri, the program is UB-free under both Stacked Borrows and Tree Borrows. The correct result is 1
$ rustc -Zmir-opt-level=0 -Copt-level=1 255118.rs && ./255118
1
at -Copt-level>=2
, it prints 255, which is clearly wrong as the value came from a bool to int cast.
$ rustc -Zmir-opt-level=0 -Copt-level=2 255118.rs && ./255118
255
-Zmir-opt-level>=1
prevents the miscompilation, -Cno-prepopulate-passes
also does. Implying either the generated IR has UB or this is a bug in LLVM
$ rustc -Zmir-opt-level=1 -Copt-level=3 255118.rs && ./255118
1
$ rustc -Zmir-opt-level=0 -Copt-level=3 -Cno-prepopulate-passes 255118.rs && ./255118
1
Only reproducible on x86_64 Linux, not Apple Silicon macOS
(This is still reproducible even with llvm/llvm-project@97f0e7b applied, so it's a separate bug)
I tried to get a standalone LLVM IR file using @Nilstrieb's approach in https://github.com/Nilstrieb/rlo-issue-112061 by having print_var
in helper C code, but I couldn't reproduce the misoptimisation with llc
since the pre-populated passes from rustc are required for the reproduction, which llc -On
does not replicate (or not in the same order)
cc @nikic
Cleaned up input IR:
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
declare void @print_var(i64 noundef %0)
define void @test() nounwind {
start:
%_37 = alloca i8, align 1
%_30 = alloca i8, align 1
%_27 = alloca ptr, align 8
%_26 = alloca ptr, align 8
%_22 = alloca i64, align 8
%_21 = alloca i8, align 1
%_19 = alloca i64, align 8
%_17 = alloca float, align 4
%_16 = alloca float, align 4
%_15 = alloca { i32, { [6 x float] } }, align 4
%_13 = alloca { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, align 8
%_12 = alloca i64, align 8
%_10 = alloca { i32, ptr }, align 8
%_9 = alloca ptr, align 8
%_7 = alloca i64, align 8
%_5 = alloca { i32, double }, align 8
%_4 = alloca { i32, double }, align 8
%_2 = alloca i16, align 2
store i32 0, ptr %_4, align 8
%0 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
store double 0.000000e+00, ptr %0, align 8
%1 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 0
%2 = load i32, ptr %1, align 8
%3 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
%4 = load double, ptr %3, align 8
%5 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 0
store i32 %2, ptr %5, align 8
%6 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
store double %4, ptr %6, align 8
%7 = load i32, ptr %_4, align 8
store i32 %7, ptr %_10, align 8
%8 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
store ptr %8, ptr %_9, align 8
%9 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
store i32 36514, ptr %9, align 8
store i64 -1, ptr %_12, align 8
br label %bb1
bb1: ; preds = %bb4, %bb8, %start
%_11 = load i64, ptr %_12, align 8
%10 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%11 = load double, ptr %10, align 8
%12 = fptrunc double %11 to float
store float %12, ptr %_16, align 4
%13 = load float, ptr %_16, align 4
store float %13, ptr %_17, align 4
%14 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
%15 = load double, ptr %14, align 8
%16 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%17 = load double, ptr %16, align 8
%_6 = fadd double %15, %17
br label %bb2
bb2: ; preds = %bb3, %bb10, %bb12, %bb8, %bb1
%18 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
%19 = load i32, ptr %18, align 8
store i32 %19, ptr %_15, align 4
%20 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 4
store i8 -86, ptr %20, align 4
%21 = load ptr, ptr %_9, align 8
store i8 49, ptr %21, align 1
%22 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
store i32 -221108602, ptr %22, align 8
br label %bb5
bb5: ; preds = %bb14, %bb2
store i16 18339, ptr %_2, align 2
%23 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
%24 = load double, ptr %23, align 8
%25 = call i64 @llvm.fptosi.sat.i64.f64(double %24)
store i64 %25, ptr %_19, align 8
br label %bb6
bb6: ; preds = %bb7, %bb12, %bb8, %bb5
%26 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
%27 = load i8, ptr %26, align 1
switch i8 %27, label %bb28 [
i8 0, label %bb7
i8 49, label %bb8
]
bb28: ; preds = %bb27, %bb25, %bb12, %bb8, %bb6
ret void
bb7: ; preds = %bb13, %bb6
%28 = load i64, ptr %_7, align 8
%29 = load i32, ptr %_10, align 8
%30 = zext i32 %29 to i64
%31 = and i64 %30, 63
%32 = shl i64 %28, %31
store i64 %32, ptr %_19, align 8
br label %bb6
bb8: ; preds = %bb13, %bb6
%33 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 4
%34 = load i8, ptr %33, align 4
switch i8 %34, label %bb28 [
i8 1, label %bb1
i8 2, label %bb2
i8 3, label %bb3
i8 4, label %bb4
i8 6, label %bb6
i8 -86, label %bb9
]
bb3: ; preds = %bb12, %bb8
%35 = load float, ptr %_16, align 4
store float %35, ptr %_17, align 4
br label %bb2
bb4: ; preds = %bb15, %bb8
%36 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
store ptr %36, ptr %_9, align 8
br label %bb1
bb9: ; preds = %bb12, %bb8
%_20 = load i64, ptr %_19, align 8
%37 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
%38 = load i32, ptr %37, align 8
%39 = icmp eq i32 %38, -221108602
br i1 %39, label %bb11, label %bb10
bb11: ; preds = %bb9
%_18 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
br label %bb14
bb10: ; preds = %bb13, %bb9
store i64 0, ptr %_12, align 8
br label %bb2
bb14: ; preds = %bb19, %bb11
%40 = load i16, ptr %_2, align 2
switch i16 %40, label %bb13 [
i16 0, label %bb5
i16 18339, label %bb15
]
bb13: ; preds = %bb23, %bb19, %bb14
%41 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
%42 = load i8, ptr %41, align 1
switch i8 %42, label %bb10 [
i8 0, label %bb7
i8 49, label %bb8
]
bb15: ; preds = %bb20, %bb14
store ptr %_4, ptr %_26, align 8
%43 = load ptr, ptr %_9, align 8
store ptr %43, ptr %_27, align 8
store i128 66683941810808954240874936259049749206, ptr %_13, align 8
%44 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 1
store i32 -1053157135, ptr %44, align 8
%45 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 1
%46 = load i32, ptr %45, align 8
%47 = icmp eq i32 %46, -1053157135
br i1 %47, label %bb16, label %bb4
bb16: ; preds = %bb15
store i64 2204794180844018677, ptr %_22, align 8
%48 = load i128, ptr %_13, align 8
%49 = trunc i128 %48 to i8
store i8 %49, ptr %_21, align 1
%50 = load ptr, ptr %_26, align 8
%51 = getelementptr inbounds { i32, double }, ptr %50, i32 0, i32 1
%52 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%53 = load double, ptr %52, align 8
%54 = fdiv double %53, 0x7FF8000000000000
store double %54, ptr %51, align 8
br label %bb17
bb17: ; preds = %bb23, %bb16
%55 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%56 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
%57 = load double, ptr %56, align 8
store double %57, ptr %55, align 8
%58 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
%59 = load i32, ptr %_15, align 4
store i32 %59, ptr %58, align 8
%60 = load ptr, ptr %_26, align 8
%61 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 0
%62 = load i32, ptr %61, align 8
%63 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%64 = load double, ptr %63, align 8
%65 = getelementptr inbounds { i32, double }, ptr %60, i32 0, i32 0
store i32 %62, ptr %65, align 8
%66 = getelementptr inbounds { i32, double }, ptr %60, i32 0, i32 1
store double %64, ptr %66, align 8
%67 = load float, ptr %_16, align 4
%68 = load float, ptr %_16, align 4
%_23 = fsub float %67, %68
br label %bb18
bb18: ; preds = %bb25, %bb17
%69 = load ptr, ptr %_27, align 8
store ptr %69, ptr %_9, align 8
%_28 = call i32 @llvm.fptoui.sat.i32.f32(float %_23)
%70 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 4
%71 = load i8, ptr %_21, align 1
store i8 %71, ptr %70, align 4
%72 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 1
%73 = load i32, ptr %72, align 8
%74 = icmp eq i32 %73, -1053157135
br i1 %74, label %bb20, label %bb19
bb20: ; preds = %bb18
%75 = load ptr, ptr %_9, align 8
store i8 115, ptr %75, align 1
store ptr %_5, ptr %_26, align 8
%76 = load i64, ptr %_22, align 8
%77 = icmp eq i64 %76, 2204794180844018677
br i1 %77, label %bb21, label %bb15
bb19: ; preds = %bb18
%78 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
%79 = load i32, ptr %78, align 8
switch i32 %79, label %bb13 [
i32 3, label %bb12
i32 -221108602, label %bb14
]
bb12: ; preds = %bb19
%80 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 4
%81 = load i8, ptr %80, align 4
switch i8 %81, label %bb28 [
i8 2, label %bb2
i8 3, label %bb3
i8 6, label %bb6
i8 -86, label %bb9
]
bb21: ; preds = %bb20
store i32 %_28, ptr %_5, align 8
%82 = load i8, ptr %_21, align 1
store i8 %82, ptr %_30, align 1
%83 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%_25 = load double, ptr %83, align 8
%84 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
store double %_6, ptr %84, align 8
%_36 = load float, ptr %_17, align 4
%_29 = load i64, ptr %_22, align 8
%_38 = load ptr, ptr %_9, align 8
%85 = getelementptr inbounds { i32, double }, ptr %_5, i32 0, i32 1
%86 = load double, ptr %85, align 8
%_24 = fcmp une double %_25, %86
br label %bb22
bb22: ; preds = %bb25, %bb21
%_35 = load i8, ptr %_30, align 1
%_39 = call i16 @llvm.fptosi.sat.i16.f32(float %_36)
%87 = xor i8 %_35, -1
store i8 %87, ptr %_21, align 1
%88 = fdiv float %_36, 0x7FF8000000000000
store float %88, ptr %_16, align 4
store ptr %_18, ptr %_27, align 8
%89 = load i8, ptr %_38, align 1
%90 = zext i8 %89 to i16
%91 = and i16 %90, 15
%92 = ashr i16 %_39, %91
store i16 %92, ptr %_2, align 2
br label %bb23
bb23: ; preds = %bb23, %bb22
%93 = load ptr, ptr %_26, align 8
%94 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 0
%95 = load i32, ptr %94, align 8
%96 = getelementptr inbounds { i32, double }, ptr %_4, i32 0, i32 1
%97 = load double, ptr %96, align 8
%98 = getelementptr inbounds { i32, double }, ptr %93, i32 0, i32 0
store i32 %95, ptr %98, align 8
%99 = getelementptr inbounds { i32, double }, ptr %93, i32 0, i32 1
store double %97, ptr %99, align 8
%100 = load i8, ptr %_30, align 1
%101 = load i8, ptr %_21, align 1
%102 = or i8 %100, %101
store i8 %102, ptr %_37, align 1
%103 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 1
%104 = load i32, ptr %103, align 8
%105 = zext i32 %104 to i64
%106 = and i64 %105, 63
%_40 = shl i64 %_29, %106
%_34 = load i8, ptr %_37, align 1
store i128 169547000073183258424114496411693076442, ptr %_13, align 8
%107 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 4
store i8 -31, ptr %107, align 4
%108 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 6
store i8 1, ptr %108, align 2
%109 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 1
store i32 -854316951, ptr %109, align 8
%110 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 3
store i32 983970, ptr %110, align 8
%111 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
store i8 -32, ptr %111, align 1
%112 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 2
store i32 1579607197, ptr %112, align 4
%113 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 8
store i32 -460487397, ptr %113, align 8
store i8 0, ptr %_30, align 1
%114 = load i8, ptr %_38, align 1
switch i8 %114, label %bb13 [
i8 1, label %bb17
i8 3, label %bb23
i8 -32, label %bb24
]
bb24: ; preds = %bb23
store i8 %_34, ptr %_30, align 1
%115 = xor i64 %_40, -1
store i64 %115, ptr %_22, align 8
store ptr %_4, ptr %_26, align 8
%116 = getelementptr inbounds { i128, i32, i32, i32, i8, i8, i8, [1 x i8], i32, [1 x i32] }, ptr %_13, i32 0, i32 5
store i8 -20, ptr %116, align 1
br label %bb25
bb25: ; preds = %bb26, %bb24
%117 = load ptr, ptr %_9, align 8
%118 = load i8, ptr %117, align 1
switch i8 %118, label %bb28 [
i8 0, label %bb18
i8 2, label %bb22
i8 3, label %bb26
i8 -20, label %bb27
]
bb26: ; preds = %bb25
%119 = load ptr, ptr %_27, align 8
store ptr %119, ptr %_9, align 8
br label %bb25
bb27: ; preds = %bb25
%_31 = zext i1 %_24 to i64
call void @print_var(i64 noundef %_31)
br label %bb28
}
declare i64 @llvm.fptosi.sat.i64.f64(double) #4
declare i32 @llvm.fptoui.sat.i32.f32(float) #4
declare i16 @llvm.fptosi.sat.i16.f32(float) #4
After opt -O2
:
; ModuleID = 'test622.ll'
source_filename = "test622.ll"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
declare void @print_var(i64 noundef) local_unnamed_addr
; Function Attrs: nounwind
define void @test() local_unnamed_addr #0 {
start:
%_5.sroa.0 = alloca i32, align 8
%_5.sroa.4 = alloca double, align 8
%_4.sroa.0 = alloca i32, align 8
%_4.sroa.3 = alloca double, align 8
store double 0.000000e+00, ptr %_4.sroa.3, align 8
store i32 0, ptr %_5.sroa.0, align 8
store double 0.000000e+00, ptr %_5.sroa.4, align 8
%0 = fptrunc double 0.000000e+00 to float
%_6 = fadd double 0.000000e+00, 0.000000e+00
br label %bb2.outer1463
bb2.outer1463: ; preds = %bb2.outer1463, %start
%_13.sroa.25.1.ph1464 = phi i32 [ 36514, %start ], [ -221108602, %bb2.outer1463 ]
%_16.0.ph1465 = phi float [ %0, %start ], [ %_16.0.ph1465, %bb2.outer1463 ]
%1 = icmp eq i32 -221108602, -221108602
br i1 %1, label %bb15.preheader, label %bb2.outer1463
bb15.preheader: ; preds = %bb2.outer1463
store double 0x7FF8000000000000, ptr %_5.sroa.4, align 8
%_5.sroa.0.0._5.sroa.0.0. = load i32, ptr %_5.sroa.0, align 8
store i32 %_5.sroa.0.0._5.sroa.0.0., ptr %_4.sroa.0, align 8
store double 0x7FF8000000000000, ptr %_4.sroa.3, align 8
%_23332 = fsub float %_16.0.ph1465, %_16.0.ph1465
%_28333 = tail call i32 @llvm.fptoui.sat.i32.f32(float %_23332)
store i32 %_28333, ptr %_5.sroa.0, align 8
%_5.sroa.4.0._5.sroa.4.8._25 = load double, ptr %_5.sroa.4, align 8
store double %_6, ptr %_5.sroa.4, align 8
%_4.sroa.0.0._4.sroa.0.0. = load i32, ptr %_4.sroa.0, align 8
%_4.sroa.3.0._4.sroa.3.8. = load double, ptr %_4.sroa.3, align 8
store i32 %_4.sroa.0.0._4.sroa.0.0., ptr %_5.sroa.0, align 8
store double %_4.sroa.3.0._4.sroa.3.8., ptr %_5.sroa.4, align 8
%_24.le = fcmp une double %_5.sroa.4.0._5.sroa.4.8._25, %_6
%_31 = zext i1 %_24.le to i64
tail call void @print_var(i64 noundef %_31) #0
ret void
}
; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i32 @llvm.fptoui.sat.i32.f32(float) #1
attributes #0 = { nounwind }
attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) }
After llc:
.text
.file "test622.ll"
.globl test # -- Begin function test
.p2align 4, 0x90
.type test,@function
test: # @test
# %bb.0: # %start
movq $0, -24(%rsp)
movl $0, -32(%rsp)
movq $0, -8(%rsp)
xorl %eax, %eax
.p2align 4, 0x90
.LBB0_1: # %bb2.outer1463
# =>This Inner Loop Header: Depth=1
testb %al, %al
jne .LBB0_1
# %bb.2: # %bb15.preheader
movl -32(%rsp), %eax
movl %eax, -16(%rsp)
movabsq $9221120237041090560, %rax # imm = 0x7FF8000000000000
movq %rax, -24(%rsp)
movq %rax, -8(%rsp)
movl $255, %edi
jmp print_var@PLT # TAILCALL
.Lfunc_end0:
.size test, .Lfunc_end0-test
# -- End function
.section ".note.GNU-stack","",@progbits
So this looks like a backend bug.
Yes it's an x86 backend bug llvm/llvm-project#63055
WG-prioritization assigning priority (Zulip discussion).
@rustbot label -I-prioritize +P-high +T-compiler
Is this a regression (from-stable-to-stable?)
@nagisa Since the Rust reproduction is in custom MIR, it's hard to test using older nightlies as a lot of expressions are only parsable recently. But on the LLVM side the bug existed since LLVM 9: https://godbolt.org/z/bvGWdvfvn, which Rust started using from 1.38.0