
This pattern can be often met in Flang generated LLVM IR, for example, for the counts of the loops generated for array expressions like: `a(x:x+y)` or `a(x+z:x+z)` or their variations. In order to compute the loop count, Flang needs to subtract the lower bound of the array slice from the upper bound of the array slice. To avoid the sign wraps, it sign extends the original values (that may be of any user data type) to `i64`. This peephole is really helpful in CPU2017/548.exchange2, where we have multiple following statements like this: ``` block(row+1:row+2, 7:9, i7) = block(row+1:row+2, 7:9, i7) - 10 ``` While this is just a 2x3 iterations loop nest, LLVM cannot figure it out, ending up vectorizing the inner loop really hard (with a vector epilog and scalar remainder). This, in turn, causes problems for LSR that ends up creating too many loop-carried values in the loop containing the above statement, which are then causing too many spills/reloads. Alive2: https://alive2.llvm.org/ce/z/gLgfYX Related to #143219.
351 lines
12 KiB
LLVM
351 lines
12 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
define i64 @src_2add_2sext_sub_1(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_1(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_2(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_2(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %z, %x
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_3(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_3(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %y, %x
|
|
%add2 = add nsw i32 %z, %x
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_4(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_4(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %y, %x
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sextlike_sub(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sextlike_sub(
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = zext nneg i32 %add1 to i64
|
|
%sext2 = zext nneg i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_nsw(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_nsw(
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub nsw i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_nuw(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_nuw(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub nuw i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
declare void @use_i32(i32, i32)
|
|
declare void @use_i64(i64, i64)
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_1(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_1(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT1]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i64(i64 %sext1, i64 %sext1)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_2(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_2(
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT2]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i64(i64 %sext2, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_3(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_3(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i64(i64 %sext1, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_4(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_4(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD1]], i32 [[ADD2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add1, i32 %add2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_5(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_5(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z:%.*]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD1]], i32 [[ADD1]])
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT1]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add1, i32 %add1)
|
|
call void @use_i64(i64 %sext1, i64 %sext1)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_6(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_6(
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X:%.*]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[Z]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[TMP1]], [[TMP2]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD2]], i32 [[ADD2]])
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT2]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add2, i32 %add2)
|
|
call void @use_i64(i64 %sext2, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_7(i32 %x, i32 %y, i32 %z) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_7(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X]], [[Z:%.*]]
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD1]], i32 [[ADD2]])
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, %z
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add1, i32 %add2)
|
|
call void @use_i64(i64 %sext1, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_8(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_8(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X]], 1
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i64 [[SEXT1]], [[SEXT2]]
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD1]], i32 [[ADD2]])
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%add2 = add nsw i32 %x, 1
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add1, i32 %add2)
|
|
call void @use_i64(i64 %sext1, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_2add_2sext_sub_multiple_uses_9(i32 %x) {
|
|
; CHECK-LABEL: @src_2add_2sext_sub_multiple_uses_9(
|
|
; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[X:%.*]], 2
|
|
; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[X]], 1
|
|
; CHECK-NEXT: [[SEXT1:%.*]] = sext i32 [[ADD1]] to i64
|
|
; CHECK-NEXT: [[SEXT2:%.*]] = sext i32 [[ADD2]] to i64
|
|
; CHECK-NEXT: call void @use_i32(i32 [[ADD1]], i32 [[ADD2]])
|
|
; CHECK-NEXT: call void @use_i64(i64 [[SEXT1]], i64 [[SEXT2]])
|
|
; CHECK-NEXT: ret i64 1
|
|
;
|
|
%add1 = add nsw i32 %x, 2
|
|
%add2 = add nsw i32 %x, 1
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %add2 to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
call void @use_i32(i32 %add1, i32 %add2)
|
|
call void @use_i64(i64 %sext1, i64 %sext2)
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_x_add_2sext_sub_1(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_x_add_2sext_sub_1(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %x to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_x_add_2sext_sub_2(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_x_add_2sext_sub_2(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %y, %x
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %x to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_x_add_2sextlike_sub(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_x_add_2sextlike_sub(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%sext1 = zext nneg i32 %add1 to i64
|
|
%sext2 = zext nneg i32 %x to i64
|
|
%sub = sub i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_x_add_2sext_sub_nsw(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_x_add_2sext_sub_nsw(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %x to i64
|
|
%sub = sub nsw i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|
|
|
|
define i64 @src_x_add_2sext_sub_nuw(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @src_x_add_2sext_sub_nuw(
|
|
; CHECK-NEXT: [[SUB:%.*]] = sext i32 [[Y:%.*]] to i64
|
|
; CHECK-NEXT: ret i64 [[SUB]]
|
|
;
|
|
%add1 = add nsw i32 %x, %y
|
|
%sext1 = sext i32 %add1 to i64
|
|
%sext2 = sext i32 %x to i64
|
|
%sub = sub nuw i64 %sext1, %sext2
|
|
ret i64 %sub
|
|
}
|