[InstCombine] failed to narrow multiplication for trunc_M((iX * iY) >> K) to trunc_M(trunc_{K+M}(iX) * trunc_{K+M}(iY) >> K)
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
noticed this pattern while retrying to simplify #206379's original code after #220347. gcc can narrow multiplication, but LLVM cannot.
https://godbolt.org/z/x5Kqx4Kf5
https://alive2.llvm.org/ce/z/ZyMnif
```c
#include
void autovec(uint64_t *restrict a, uint64_t *restrict b, uint8_t *restrict c){
for(int i=0;i<8;i++){
c[i]=a[i]*b[i]>>8;
}
}
void autovec_tgt(uint64_t *restrict a, uint64_t *restrict b, uint8_t *restrict c){
for(int i=0;i<8;i++){
c[i]=(uint16_t)a[i]*(uint16_t)b[i]>>8;
}
}
void autovec2(uint64_t *restrict a, uint64_t *restrict b, uint8_t *restrict c){
for(int i=0;i<8;i++){
c[i]=a[i]*b[i]>>16;
}
}
void autovec2_tgt(uint64_t *restrict a, uint64_t *restrict b, uint8_t *restrict c){
for(int i=0;i<8;i++){
c[i]=(uint32_t)a[i]*(uint32_t)b[i]>>16;
}
}
void autovec3(uint64_t *restrict a, uint64_t *restrict b, uint16_t *restrict c){
for(int i=0;i<8;i++){
c[i]=a[i]*b[i]>>8;
}
}
void autovec3_tgt(uint64_t *restrict a, uint64_t *restrict b, uint16_t *restrict c){
for(int i=0;i<8;i++){
c[i]=(uint32_t)a[i]*(uint32_t)b[i]>>8;
}
}
void autovec4(uint64_t *restrict a, uint64_t *restrict b, uint16_t *restrict c){
for(int i=0;i<8;i++){
c[i]=a[i]*b[i]>>16;
}
}
void autovec4_tgt(uint64_t *restrict a, uint64_t *restrict b, uint16_t *restrict c){
for(int i=0;i<8;i++){
c[i]=(uint32_t)a[i]*(uint32_t)b[i]>>16;
}
}
typedef uint8_t u8 [[gnu::vector_size(8)]];
typedef uint16_t u16 [[gnu::vector_size(16)]];
typedef uint32_t u32 [[gnu::vector_size(32)]];
typedef uint64_t u64 [[gnu::vector_size(64)]];
u8 src(u64 a , u64 b){
return __builtin_convertvector(a * b >> 8 ,u8);
}
u8 tgt(u64 a , u64 b){
return __builtin_convertvector(__builtin_convertvector(a, u16) * __builtin_convertvector(b, u16) >> 8 ,u8);
}
u8 src2(u64 a , u64 b){
return __builtin_convertvector(a * b >> 16 ,u8);
}
u8 tgt2(u64 a , u64 b){
return __builtin_convertvector(__builtin_convertvector(a, u32) * __builtin_convertvector(b, u32) >> 16 ,u8);
}
u16 src3(u64 a , u64 b){
return __builtin_convertvector(a * b >> 8 ,u16);
}
u16 tgt3(u64 a , u64 b){
return __builtin_convertvector(__builtin_convertvector(a, u32) * __builtin_convertvector(b, u32) >> 8 ,u16);
}
u16 src4(u64 a , u64 b){
return __builtin_convertvector(a * b >> 16 ,u16);
}
u16 tgt4(u64 a , u64 b){
return __builtin_convertvector(__builtin_convertvector(a, u32) * __builtin_convertvector(b, u32) >> 16 ,u16);
}
```
IR
```llvm
define dso_local void @autovec(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 8)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = load <8 x i64>, ptr %b, align 8
%2 = mul <8 x i64> %1, %0
%3 = lshr <8 x i64> %2, splat (i64 8)
%4 = trunc <8 x i64> %3 to <8 x i8>
store <8 x i8> %4, ptr %c, align 1
ret void
}
define dso_local void @autovec_tgt(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 8)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = trunc <8 x i64> %0 to <8 x i16>
%2 = load <8 x i64>, ptr %b, align 8
%3 = trunc <8 x i64> %2 to <8 x i16>
%4 = mul <8 x i16> %3, %1
%5 = lshr <8 x i16> %4, splat (i16 8)
%6 = trunc nuw <8 x i16> %5 to <8 x i8>
store <8 x i8> %6, ptr %c, align 1
ret void
}
define dso_local void @autovec2(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 8)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = load <8 x i64>, ptr %b, align 8
%2 = mul <8 x i64> %1, %0
%3 = lshr <8 x i64> %2, splat (i64 16)
%4 = trunc <8 x i64> %3 to <8 x i8>
store <8 x i8> %4, ptr %c, align 1
ret void
}
define dso_local void @autovec2_tgt(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 8)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = trunc <8 x i64> %0 to <8 x i32>
%2 = load <8 x i64>, ptr %b, align 8
%3 = trunc <8 x i64> %2 to <8 x i32>
%4 = mul <8 x i32> %3, %1
%5 = lshr <8 x i32> %4, splat (i32 16)
%6 = trunc <8 x i32> %5 to <8 x i8>
store <8 x i8> %6, ptr %c, align 1
ret void
}
define dso_local void @autovec3(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 16)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = load <8 x i64>, ptr %b, align 8
%2 = mul <8 x i64> %1, %0
%3 = lshr <8 x i64> %2, splat (i64 8)
%4 = trunc <8 x i64> %3 to <8 x i16>
store <8 x i16> %4, ptr %c, align 2
ret void
}
define dso_local void @autovec3_tgt(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 16)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = trunc <8 x i64> %0 to <8 x i32>
%2 = load <8 x i64>, ptr %b, align 8
%3 = trunc <8 x i64> %2 to <8 x i32>
%4 = mul <8 x i32> %3, %1
%5 = lshr <8 x i32> %4, splat (i32 8)
%6 = trunc <8 x i32> %5 to <8 x i16>
store <8 x i16> %6, ptr %c, align 2
ret void
}
define dso_local void @autovec4(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 16)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = load <8 x i64>, ptr %b, align 8
%2 = mul <8 x i64> %1, %0
%3 = lshr <8 x i64> %2, splat (i64 16)
%4 = trunc <8 x i64> %3 to <8 x i16>
store <8 x i16> %4, ptr %c, align 2
ret void
}
define dso_local void @autovec4_tgt(ptr noalias nofree noundef readonly captures(none) %a, ptr noalias nofree noundef readonly captures(none) %b, ptr noalias nofree noundef writeonly captures(none) initializes((0, 16)) %c) local_unnamed_addr {
entry:
%0 = load <8 x i64>, ptr %a, align 8
%1 = trunc <8 x i64> %0 to <8 x i32>
%2 = load <8 x i64>, ptr %b, align 8
%3 = trunc <8 x i64> %2 to <8 x i32>
%4 = mul <8 x i32> %3, %1
%5 = lshr <8 x i32> %4, splat (i32 16)
%6 = trunc nuw <8 x i32> %5 to <8 x i16>
store <8 x i16> %6, ptr %c, align 2
ret void
}
define dso_local noundef double @src(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%mul = mul <8 x i64> %b, %a
%shr = lshr <8 x i64> %mul, splat (i64 8)
%conv = trunc <8 x i64> %shr to <8 x i8>
%0 = bitcast <8 x i8> %conv to double
ret double %0
}
define dso_local double @tgt(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%conv = trunc <8 x i64> %a to <8 x i16>
%conv1 = trunc <8 x i64> %b to <8 x i16>
%mul = mul <8 x i16> %conv1, %conv
%shr = lshr <8 x i16> %mul, splat (i16 8)
%conv2 = trunc nuw <8 x i16> %shr to <8 x i8>
%0 = bitcast <8 x i8> %conv2 to double
ret double %0
}
define dso_local noundef double @src2(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%mul = mul <8 x i64> %b, %a
%shr = lshr <8 x i64> %mul, splat (i64 16)
%conv = trunc <8 x i64> %shr to <8 x i8>
%0 = bitcast <8 x i8> %conv to double
ret double %0
}
define dso_local noundef double @tgt2(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%conv = trunc <8 x i64> %a to <8 x i32>
%conv1 = trunc <8 x i64> %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, splat (i32 16)
%conv2 = trunc <8 x i32> %shr to <8 x i8>
%0 = bitcast <8 x i8> %conv2 to double
ret double %0
}
define dso_local noundef <8 x i16> @src3(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%mul = mul <8 x i64> %b, %a
%shr = lshr <8 x i64> %mul, splat (i64 8)
%conv = trunc <8 x i64> %shr to <8 x i16>
ret <8 x i16> %conv
}
define dso_local noundef <8 x i16> @tgt3(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%conv = trunc <8 x i64> %a to <8 x i32>
%conv1 = trunc <8 x i64> %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, splat (i32 8)
%conv2 = trunc <8 x i32> %shr to <8 x i16>
ret <8 x i16> %conv2
}
define dso_local noundef <8 x i16> @src4(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%mul = mul <8 x i64> %b, %a
%shr = lshr <8 x i64> %mul, splat (i64 16)
%conv = trunc <8 x i64> %shr to <8 x i16>
ret <8 x i16> %conv
}
define dso_local <8 x i16> @tgt4(<8 x i64> noundef %a, <8 x i64> noundef %b) local_unnamed_addr {
entry:
%conv = trunc <8 x i64> %a to <8 x i32>
%conv1 = trunc <8 x i64> %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, splat (i32 16)
%conv2 = trunc nuw <8 x i32> %shr to <8 x i16>
ret <8 x i16> %conv2
}
```
clang codegen
```asm
autovec:
vmovdqu64 zmm0, zmmword ptr [rsi]
vpmullq zmm0, zmm0, zmmword ptr [rdi]
vpsrlq zmm0, zmm0, 8
vpmovqb qword ptr [rdx], zmm0
vzeroupper
ret
autovec_tgt:
vmovdqu64 zmm0, zmmword ptr [rdi]
vpmovqw xmm0, zmm0
vmovdqu64 zmm1, zmmword ptr [rsi]
vpmovqw xmm1, zmm1
vpmullw xmm0, xmm1, xmm0
vpsrlw xmm0, xmm0, 8
vpmovwb qword ptr [rdx], xmm0
vzeroupper
ret
autovec2:
vmovdqu64 zmm0, zmmword ptr [rsi]
vpmullq zmm0, zmm0, zmmword ptr [rdi]
vpsrlq zmm0, zmm0, 16
vpmovqb qword ptr [rdx], zmm0
vzeroupper
ret
autovec2_tgt:
vmovdqu64 zmm0, zmmword ptr [rdi]
vpmovqd ymm0, zmm0
vmovdqu64 zmm1, zmmword ptr [rsi]
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 16
vpmovdb qword ptr [rdx], ymm0
vzeroupper
ret
autovec3:
vmovdqu64 zmm0, zmmword ptr [rsi]
vpmullq zmm0, zmm0, zmmword ptr [rdi]
vpsrlq zmm0, zmm0, 8
vpmovqw xmmword ptr [rdx], zmm0
vzeroupper
ret
autovec3_tgt:
vmovdqu64 zmm0, zmmword ptr [rdi]
vpmovqd ymm0, zmm0
vmovdqu64 zmm1, zmmword ptr [rsi]
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 8
vpmovdw xmmword ptr [rdx], ymm0
vzeroupper
ret
autovec4:
vmovdqu64 zmm0, zmmword ptr [rsi]
vpmullq zmm0, zmm0, zmmword ptr [rdi]
vpsrlq zmm0, zmm0, 16
vpmovqw xmmword ptr [rdx], zmm0
vzeroupper
ret
autovec4_tgt:
vmovdqu64 zmm0, zmmword ptr [rdi]
vpmovqd ymm0, zmm0
vmovdqu64 zmm1, zmmword ptr [rsi]
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 16
vpmovdw xmmword ptr [rdx], ymm0
vzeroupper
ret
src:
vpmullq zmm0, zmm1, zmm0
vpsrlq zmm0, zmm0, 8
vpmovqb xmm0, zmm0
vzeroupper
ret
.LCPI9_0:
.byte 1
.byte 3
.byte 5
.byte 7
.byte 9
.byte 11
.byte 13
.byte 15
.zero 1
.zero 1
.zero 1
.zero 1
.zero 1
.zero 1
.zero 1
.zero 1
tgt:
vpmovqw xmm0, zmm0
vpmovqw xmm1, zmm1
vpmullw xmm0, xmm1, xmm0
vpshufb xmm0, xmm0, xmmword ptr [rip + .LCPI9_0]
vzeroupper
ret
src2:
vpmullq zmm0, zmm1, zmm0
vpsrlq zmm0, zmm0, 16
vpmovqb xmm0, zmm0
vzeroupper
ret
tgt2:
vpmovqd ymm0, zmm0
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 16
vpmovdb xmm0, ymm0
vzeroupper
ret
src3:
vpmullq zmm0, zmm1, zmm0
vpsrlq zmm0, zmm0, 8
vpmovqw xmm0, zmm0
vzeroupper
ret
tgt3:
vpmovqd ymm0, zmm0
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 8
vpmovdw xmm0, ymm0
vzeroupper
ret
src4:
vpmullq zmm0, zmm1, zmm0
vpsrlq zmm0, zmm0, 16
vpmovqw xmm0, zmm0
vzeroupper
ret
tgt4:
vpmovqd ymm0, zmm0
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm1, ymm0
vpsrld ymm0, ymm0, 16
vpmovdw xmm0, ymm0
vzeroupper
ret
```
gcc codegen
```asm
"autovec":
vmovdqu64 zmm0, ZMMWORD PTR [rdi]
vmovdqu64 zmm1, ZMMWORD PTR [rsi]
vpmovqw xmm0, zmm0
vpmovqw xmm1, zmm1
vpmullw xmm0, xmm0, xmm1
vpsrlw xmm0, xmm0, 8
vpmovwb QWORD PTR [rdx], xmm0
vzeroupper
ret
"autovec_tgt":
vmovdqu64 zmm0, ZMMWORD PTR [rsi]
vmovdqu64 zmm1, ZMMWORD PTR [rdi]
vpmovqw xmm0, zmm0
vpmovqw xmm1, zmm1
vpmullw xmm0, xmm0, xmm1
vpsraw xmm0, xmm0, 8
vpmovwb QWORD PTR [rdx], xmm0
vzeroupper
ret
"autovec2":
vmovdqu64 zmm0, ZMMWORD PTR [rdi]
vmovdqu64 zmm1, ZMMWORD PTR [rsi]
vpmovqd ymm0, zmm0
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm0, ymm1
vpsrld ymm0, ymm0, 16
vpmovdb QWORD PTR [rdx], ymm0
vzeroupper
ret
"autovec2_tgt":
vmovdqu64 zmm0, ZMMWORD PTR [rsi]
vmovdqu64 zmm1, ZMMWORD PTR [rdi]
vpmovqd ymm0, zmm0
vpmovqd ymm1, zmm1
vpmulld ymm0, ymm0, ymm1
vpsrld ymm0, ymm0, 16
vpmovdb QWORD PTR [rdx], ymm0
vzeroupper
ret
"autovec3":
vmovdqu xmm0, XMMWORD PTR [rdi]
vmovdqu xmm1, XMMWORD PTR [rsi]
vshufps xmm0, xmm0, XMMWORD PTR [rdi+16], 136
vshufps xmm1, xmm1, XMMWORD PTR [rsi+16], 136
vmovdqu xmm2, XMMWORD PTR [rsi+32]
vshufps xmm2, xmm2, XMMWORD PTR [rsi+48], 136
vpmulld xmm0, xmm0, xmm1
vmovdqu xmm1, XMMWORD PTR [rdi+32]
vshufps xmm1, xmm1, XMMWORD PTR [rdi+48], 136
vpsrld xmm0, xmm0, 8
vpmulld xmm1, xmm1, xmm2
vmovdqa xmm2, XMMWORD PTR .LC0[rip]
vpsrld xmm1, xmm1, 8
vpermt2w xmm0, xmm2, xmm1
vmovdqu XMMWORD PTR [rdx], xmm0
ret
"autovec3_tgt":
vmovdqu xmm0, XMMWORD PTR [rdi]
vmovdqu xmm1, XMMWORD PTR [rsi]
vshufps xmm0, xmm0, XMMWORD PTR [rdi+16], 136
vshufps xmm1, xmm1, XMMWORD PTR [rsi+16], 136
vmovdqu xmm2, XMMWORD PTR [rsi+32]
vshufps xmm2, xmm2, XMMWORD PTR [rsi+48], 136
vpmulld xmm0, xmm0, xmm1
vmovdqu xmm1, XMMWORD PTR [rdi+32]
vshufps xmm1, xmm1, XMMWORD PTR [rdi+48], 136
vpsrld xmm0, xmm0, 8
vpmulld xmm1, xmm1, xmm2
vmovdqa xmm2, XMMWORD PTR .LC0[rip]
vpsrld xmm1, xmm1, 8
vpermt2w xmm0, xmm2, xmm1
vmovdqu XMMWORD PTR [rdx], xmm0
ret
"autovec4":
vmovdqu xmm0, XMMWORD PTR [rdi]
vmovdqu xmm1, XMMWORD PTR [rsi]
vshufps xmm0, xmm0, XMMWORD PTR [rdi+16], 136
vshufps xmm1, xmm1, XMMWORD PTR [rsi+16], 136
vmovdqu xmm2, XMMWORD PTR [rsi+32]
vshufps xmm2, xmm2, XMMWORD PTR [rsi+48], 136
vpmulld xmm0, xmm0, xmm1
vmovdqu xmm1, XMMWORD PTR [rdi+32]
vshufps xmm1, xmm1, XMMWORD PTR [rdi+48], 136
vpsrld xmm0, xmm0, 16
vpmulld xmm1, xmm1, xmm2
vmovdqa xmm2, XMMWORD PTR .LC0[rip]
vpsrld xmm1, xmm1, 16
vpermt2w xmm0, xmm2, xmm1
vmovdqu XMMWORD PTR [rdx], xmm0
ret
"autovec4_tgt":
vmovdqu xmm0, XMMWORD PTR [rdi]
vmovdqu xmm1, XMMWORD PTR [rsi]
vshufps xmm0, xmm0, XMMWORD PTR [rdi+16], 136
vshufps xmm1, xmm1, XMMWORD PTR [rsi+16], 136
vmovdqu xmm2, XMMWORD PTR [rsi+32]
vshufps xmm2, xmm2, XMMWORD PTR [rsi+48], 136
vpmulld xmm0, xmm0, xmm1
vmovdqu xmm1, XMMWORD PTR [rdi+32]
vshufps xmm1, xmm1, XMMWORD PTR [rdi+48], 136
vpsrld xmm0, xmm0, 16
vpmulld xmm1, xmm1, xmm2
vmovdqa xmm2, XMMWORD PTR .LC0[rip]
vpsrld xmm1, xmm1, 16
vpermt2w xmm0, xmm2, xmm1
vmovdqu XMMWORD PTR [rdx], xmm0
ret
"src":
vpmullq zmm0, zmm0, zmm1
vpsrlq zmm0, zmm0, 8
vpmovqb xmm0, zmm0
ret
"tgt":
vpmovqw xmm1, zmm1
vpmovqw xmm0, zmm0
vpmullw xmm0, xmm0, xmm1
vpsrlw xmm0, xmm0, 8
vpmovwb xmm0, xmm0
ret
"src2":
vpmullq zmm0, zmm0, zmm1
vpsrlq zmm0, zmm0, 16
vpmovqb xmm0, zmm0
ret
"tgt2":
vpmovqd ymm1, zmm1
vpmovqd ymm0, zmm0
vpmulld ymm0, ymm0, ymm1
vpsrld ymm0, ymm0, 16
vpmovdb xmm0, ymm0
ret
"src3":
vpmullq zmm0, zmm0, zmm1
vpsrlq zmm0, zmm0, 8
vpmovqw xmm0, zmm0
ret
"tgt3":
vpmovqd ymm1, zmm1
vpmovqd ymm0, zmm0
vpmulld ymm0, ymm0, ymm1
vpsrld ymm0, ymm0, 8
vpmovdw xmm0, ymm0
ret
"src4":
vpmullq zmm0, zmm0, zmm1
vpsrlq zmm0, zmm0, 16
vpmovqw xmm0, zmm0
ret
"tgt4":
vpmovqd ymm1, zmm1
vpmovqd ymm0, zmm0
vpmulld ymm0, ymm0, ymm1
vpsrld ymm0, ymm0, 16
vpmovdw xmm0, ymm0
ret
.LC0:
.value 0
.value 2
.value 4
.value 6
.value 8
.value 10
.value 12
.value 14
.value 14
```
alive2
```llvm
----------------------------------------
define double @src(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%mul = mul <8 x i64> noundef %b, noundef %a
%shr = lshr <8 x i64> %mul, { 8, 8, 8, 8, 8, 8, 8, 8 }
%conv = trunc <8 x i64> %shr to <8 x i8>
%#0 = bitcast <8 x i8> %conv to double
ret double %#0
}
=>
define double @tgt(<8 x i64> noundef %a, <8 x i64> noundef %b) {
entry:
%conv = trunc <8 x i64> noundef %a to <8 x i16>
%conv1 = trunc <8 x i64> noundef %b to <8 x i16>
%mul = mul <8 x i16> %conv1, %conv
%shr = lshr <8 x i16> %mul, { 8, 8, 8, 8, 8, 8, 8, 8 }
%conv2 = trunc nuw <8 x i16> %shr to <8 x i8>
%#0 = bitcast <8 x i8> %conv2 to double
ret double %#0
}
Transformation seems to be correct!
----------------------------------------
define double @src2(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%mul = mul <8 x i64> noundef %b, noundef %a
%shr = lshr <8 x i64> %mul, { 16, 16, 16, 16, 16, 16, 16, 16 }
%conv = trunc <8 x i64> %shr to <8 x i8>
%#0 = bitcast <8 x i8> %conv to double
ret double %#0
}
=>
define double @tgt2(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%conv = trunc <8 x i64> noundef %a to <8 x i32>
%conv1 = trunc <8 x i64> noundef %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, { 16, 16, 16, 16, 16, 16, 16, 16 }
%conv2 = trunc <8 x i32> %shr to <8 x i8>
%#0 = bitcast <8 x i8> %conv2 to double
ret double %#0
}
Transformation seems to be correct!
----------------------------------------
define <8 x i16> @src3(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%mul = mul <8 x i64> noundef %b, noundef %a
%shr = lshr <8 x i64> %mul, { 8, 8, 8, 8, 8, 8, 8, 8 }
%conv = trunc <8 x i64> %shr to <8 x i16>
ret <8 x i16> %conv
}
=>
define <8 x i16> @tgt3(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%conv = trunc <8 x i64> noundef %a to <8 x i32>
%conv1 = trunc <8 x i64> noundef %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, { 8, 8, 8, 8, 8, 8, 8, 8 }
%conv2 = trunc <8 x i32> %shr to <8 x i16>
ret <8 x i16> %conv2
}
Transformation seems to be correct!
----------------------------------------
define <8 x i16> @src4(<8 x i64> noundef %a, <8 x i64> noundef %b) noundef {
entry:
%mul = mul <8 x i64> noundef %b, noundef %a
%shr = lshr <8 x i64> %mul, { 16, 16, 16, 16, 16, 16, 16, 16 }
%conv = trunc <8 x i64> %shr to <8 x i16>
ret <8 x i16> %conv
}
=>
define <8 x i16> @tgt4(<8 x i64> noundef %a, <8 x i64> noundef %b) {
entry:
%conv = trunc <8 x i64> noundef %a to <8 x i32>
%conv1 = trunc <8 x i64> noundef %b to <8 x i32>
%mul = mul <8 x i32> %conv1, %conv
%shr = lshr <8 x i32> %mul, { 16, 16, 16, 16, 16, 16, 16, 16 }
%conv2 = trunc nuw <8 x i32> %shr to <8 x i16>
ret <8 x i16> %conv2
}
Transformation seems to be correct!
Summary:
4 correct transformations
0 incorrect transformations
0 failed-to-prove transformations
0 Alive2 errors
```
Contributor guide
Research direction
Start by comparing the src and tgt examples on Godbolt and checking the Alive2 proof linked in the issue. Trace the InstCombine handling for truncation, multiplication, and logical shift right; done means the equivalent narrowed multiplication form is recognized without changing the results shown by the examples.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100