diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1977,7 +1977,7 @@ // If the destination type is narrow, that means the intermediate FP value // must be large enough to hold the source value exactly. // For example, (uint8_t)((float)(uint32_t 16777217) is undefined behavior. - int OutputSize = (int)DestType->getScalarSizeInBits() - IsOutputSigned; + int OutputSize = (int)DestType->getScalarSizeInBits(); if (OutputSize > OpI->getType()->getFPMantissaWidth()) return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/sitofp.ll b/llvm/test/Transforms/InstCombine/sitofp.ll --- a/llvm/test/Transforms/InstCombine/sitofp.ll +++ b/llvm/test/Transforms/InstCombine/sitofp.ll @@ -190,11 +190,13 @@ ret i32 %C } -; This can fold because the 54-bit output is signed and we discard the sign bit. +; This can't fold because the 54-bit output is big enough to hold an input +; that was rounded when converted to double. define i54 @test18(i64 %A) { ; CHECK-LABEL: @test18( -; CHECK-NEXT: [[C:%.*]] = trunc i64 [[A:%.*]] to i54 +; CHECK-NEXT: [[B:%.*]] = sitofp i64 [[A:%.*]] to double +; CHECK-NEXT: [[C:%.*]] = fptosi double [[B]] to i54 ; CHECK-NEXT: ret i54 [[C]] ; %B = sitofp i64 %A to double @@ -246,6 +248,8 @@ ret i25 %C } +; Output is small enough to ensure exact cast (overflow produces poison). + define i11 @s32_half_s11(i32 %x) { ; CHECK-LABEL: @s32_half_s11( ; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i11 @@ -256,6 +260,8 @@ ret i11 %r } +; Output is small enough to ensure exact cast (overflow produces poison). + define i11 @s32_half_u11(i32 %x) { ; CHECK-LABEL: @s32_half_u11( ; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i11 @@ -266,6 +272,8 @@ ret i11 %r } +; Output is small enough to ensure exact cast (overflow produces poison). + define i11 @u32_half_s11(i32 %x) { ; CHECK-LABEL: @u32_half_s11( ; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i11 @@ -276,6 +284,8 @@ ret i11 %r } +; Output is small enough to ensure exact cast (overflow produces poison). + define i11 @u32_half_u11(i32 %x) { ; CHECK-LABEL: @u32_half_u11( ; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i11 @@ -286,9 +296,12 @@ ret i11 %r } +; Too many bits in output to ensure exact cast. + define i12 @s32_half_s12(i32 %x) { ; CHECK-LABEL: @s32_half_s12( -; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i12 +; CHECK-NEXT: [[H:%.*]] = sitofp i32 [[X:%.*]] to half +; CHECK-NEXT: [[R:%.*]] = fptosi half [[H]] to i12 ; CHECK-NEXT: ret i12 [[R]] ; %h = sitofp i32 %x to half @@ -296,6 +309,8 @@ ret i12 %r } +; Too many bits in output to ensure exact cast. + define i12 @s32_half_u12(i32 %x) { ; CHECK-LABEL: @s32_half_u12( ; CHECK-NEXT: [[H:%.*]] = sitofp i32 [[X:%.*]] to half @@ -307,9 +322,12 @@ ret i12 %r } +; TODO: This is safe to convert to trunc. + define i12 @u32_half_s12(i32 %x) { ; CHECK-LABEL: @u32_half_s12( -; CHECK-NEXT: [[R:%.*]] = trunc i32 [[X:%.*]] to i12 +; CHECK-NEXT: [[H:%.*]] = uitofp i32 [[X:%.*]] to half +; CHECK-NEXT: [[R:%.*]] = fptosi half [[H]] to i12 ; CHECK-NEXT: ret i12 [[R]] ; %h = uitofp i32 %x to half @@ -317,6 +335,8 @@ ret i12 %r } +; Too many bits in output to ensure exact cast. + define i12 @u32_half_u12(i32 %x) { ; CHECK-LABEL: @u32_half_u12( ; CHECK-NEXT: [[H:%.*]] = uitofp i32 [[X:%.*]] to half