; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -passes=separate-const-offset-from-gep < %s | FileCheck %s declare void @use.i32(i32 noundef) declare void @allow.undef.use.i32(i32) declare void @use.v2i32(<2 x i32> noundef) declare void @allow.undef.use.v2i32(<2 x i32>) declare void @use.i64(i64 noundef) ; Should fold out the 64-bit add define i64 @add_sext__dominating_add_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NSW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nsw) ret i64 %add.sext } ; Should fold out the 64-bit sub define i64 @sub_sext__dominating_sub_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sext i32 [[SUB_NSW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; Should fold out the 64-bit add. The 64-bit add has commuted operands ; compared to the original. define i64 @add_sext__dominating_add_nsw_commuted(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nsw_commuted ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NSW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg1.sext, %arg0.sext call void @use.i32(i32 %add.nsw) ret i64 %add.sext } ; The second sub has commuted operands define i64 @sub_sext__dominating_sub_nsw_commuted(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nsw_commuted ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG1_SEXT]], [[ARG0_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg1.sext, %arg0.sext call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; Missing nsw on the add i32, can't do anything define i64 @add_sext__dominating_add(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nsw) ret i64 %add.sext } ; Missing nsw on the sub i32, can't do anything define i64 @sub_sext__dominating_sub(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; The use of the 32-bit add allows poison, so can't fold. define i64 @add_sext__dominating_add_nsw_defined(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nsw_defined ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @allow.undef.use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @allow.undef.use.i32(i32 %add.nsw) ret i64 %add.sext } ; The use of the 32-bit sub allows poison, so can't fold. define i64 @sub_sext__dominating_sub_nsw_defined(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nsw_defined ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @allow.undef.use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @allow.undef.use.i32(i32 %sub.nsw) ret i64 %sub.sext } define i64 @add_sext__dominating_add_nsw_multi_use_sext0(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nsw_multi_use_sext0 ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i64(i64 [[ARG0_SEXT]]) ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i64(i64 %arg0.sext) call void @use.i32(i32 %add.nsw) ret i64 %add.sext } define i64 @add_sext__dominating_add_nsw_multi_use_sext1(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nsw_multi_use_sext1 ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i64(i64 [[ARG1_SEXT]]) ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i64(i64 %arg1.sext) call void @use.i32(i32 %add.nsw) ret i64 %add.sext } define i64 @sub_sext__dominating_sub_nsw_multi_use_sext0(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nsw_multi_use_sext0 ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i64(i64 [[ARG0_SEXT]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i64(i64 %arg0.sext) call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } define i64 @sub_sext__dominating_sub_nsw_multi_use_sext1(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nsw_multi_use_sext1 ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i64(i64 [[ARG1_SEXT]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i64(i64 %arg1.sext) call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; -------------------------------------------------------------------- ; Vector handling ; -------------------------------------------------------------------- ; Should fold out the 64-bit add define <2 x i64> @add_sext__dominating_add_nsw_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @add_sext__dominating_add_nsw_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext <2 x i32> [[ADD_NSW]] to <2 x i64> ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]] ; entry: %add.nsw = add nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %add.sext = add <2 x i64> %arg0.sext, %arg1.sext call void @use.v2i32(<2 x i32> %add.nsw) ret <2 x i64> %add.sext } ; Should fold out the 64-bit sub define <2 x i64> @sub_sext__dominating_sub_nsw_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @sub_sext__dominating_sub_nsw_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sext <2 x i32> [[SUB_NSW]] to <2 x i64> ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[SUB_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %sub.sext = sub <2 x i64> %arg0.sext, %arg1.sext call void @use.v2i32(<2 x i32> %sub.nsw) ret <2 x i64> %sub.sext } ; Should fold out the 64-bit add. The 64-bit add has commuted operands ; compared to the original. define <2 x i64> @add_sext__dominating_add_nsw_commuted_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @add_sext__dominating_add_nsw_commuted_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext <2 x i32> [[ADD_NSW]] to <2 x i64> ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]] ; entry: %add.nsw = add nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %add.sext = add <2 x i64> %arg1.sext, %arg0.sext call void @use.v2i32(<2 x i32> %add.nsw) ret <2 x i64> %add.sext } ; The second sub has commuted operands define <2 x i64> @sub_sext__dominating_sub_nsw_commuted_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @sub_sext__dominating_sub_nsw_commuted_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub <2 x i64> [[ARG1_SEXT]], [[ARG0_SEXT]] ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[SUB_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %sub.sext = sub <2 x i64> %arg1.sext, %arg0.sext call void @use.v2i32(<2 x i32> %sub.nsw) ret <2 x i64> %sub.sext } ; Missing nsw on the add <2 x i32>, can't do anything define <2 x i64> @add_sext__dominating_add_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @add_sext__dominating_add_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]] ; entry: %add.nsw = add <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %add.sext = add <2 x i64> %arg0.sext, %arg1.sext call void @use.v2i32(<2 x i32> %add.nsw) ret <2 x i64> %add.sext } ; Missing nsw on the sub <2 x i32>, can't do anything define <2 x i64> @sub_sext__dominating_sub_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @sub_sext__dominating_sub_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[SUB_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[SUB_SEXT]] ; entry: %sub.nsw = sub <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %sub.sext = sub <2 x i64> %arg0.sext, %arg1.sext call void @use.v2i32(<2 x i32> %sub.nsw) ret <2 x i64> %sub.sext } ; The use of the 32-bit add allows poison, so can't fold. define <2 x i64> @add_sext__dominating_add_nsw_defined_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @add_sext__dominating_add_nsw_defined_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @allow.undef.use.v2i32(<2 x i32> [[ADD_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[ADD_SEXT]] ; entry: %add.nsw = add nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %add.sext = add <2 x i64> %arg0.sext, %arg1.sext call void @allow.undef.use.v2i32(<2 x i32> %add.nsw) ret <2 x i64> %add.sext } ; The use of the 32-bit sub allows poison, so can't fold. define <2 x i64> @sub_sext__dominating_sub_nsw_defined_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @sub_sext__dominating_sub_nsw_defined_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub <2 x i64> [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @allow.undef.use.v2i32(<2 x i32> [[SUB_NSW]]) ; CHECK-NEXT: ret <2 x i64> [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw <2 x i32> %arg0, %arg1 %arg0.sext = sext <2 x i32> %arg0 to <2 x i64> %arg1.sext = sext <2 x i32> %arg1 to <2 x i64> %sub.sext = sub <2 x i64> %arg0.sext, %arg1.sext call void @allow.undef.use.v2i32(<2 x i32> %sub.nsw) ret <2 x i64> %sub.sext } ; -------------------------------------------------------------------- ; Zext x nsw ; -------------------------------------------------------------------- ; Want sext, not zext define i64 @add_zext__dominating_add_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_zext__dominating_add_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = zext i32 %arg0 to i64 %arg1.sext = zext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nsw) ret i64 %add.sext } ; Want sext, not zext define i64 @sub_zext__dominating_add_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_zext__dominating_add_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = zext i32 %arg0 to i64 %arg1.sext = zext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; -------------------------------------------------------------------- ; sext x nuw ; -------------------------------------------------------------------- ; Want nsw, not nuw define i64 @add_sext__dominating_add_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nuw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW:%.*]] = add nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nuw = add nuw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nuw) ret i64 %add.sext } ; Want nsw, not nuw define i64 @sub_sext__dominating_sub_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nuw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nuw = sub nuw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nuw) ret i64 %sub.sext } ; -------------------------------------------------------------------- ; Misc negative tests ; -------------------------------------------------------------------- ; Opcode mismatch 1 define i64 @add_sext__dominating_sub_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_sub_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nsw) ret i64 %sub.sext } ; Opcode mismatch 2 define i64 @sub_sext__dominating_add_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_add_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nsw) ret i64 %sub.sext } ; Both nsw add and sub coexist for the same inputs define void @add_sext__dominating_add_nsw_sub_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define void @add_sext__dominating_add_nsw_sub_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NSW]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: call void @use.i64(i64 [[ADD_SEXT]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_SEXT]]) ; CHECK-NEXT: ret void ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nsw) call void @use.i32(i32 %sub.nsw) call void @use.i64(i64 %add.sext) call void @use.i64(i64 %sub.sext) ret void } ; Both nsw add and sub coexist for the same inputs, but commuted define void @add_sext__dominating_add_nsw_sub_nsw_swapped(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define void @add_sext__dominating_add_nsw_sub_nsw_swapped ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG1]], [[ARG0]] ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NSW]] to i64 ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG1_SEXT]], [[ARG0_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: call void @use.i64(i64 [[ADD_SEXT]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_SEXT]]) ; CHECK-NEXT: ret void ; entry: %add.nsw = add nsw i32 %arg0, %arg1 %sub.nsw = sub nsw i32 %arg1, %arg0 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext %sub.sext = sub i64 %arg1.sext, %arg0.sext call void @use.i32(i32 %add.nsw) call void @use.i32(i32 %sub.nsw) call void @use.i64(i64 %add.sext) call void @use.i64(i64 %sub.sext) ret void } ; -------------------------------------------------------------------- ; zext x nuw ; -------------------------------------------------------------------- ; Should fold out the add i64 define i64 @add_zext__dominating_add_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_zext__dominating_add_nuw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW:%.*]] = add nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_ZEXT:%.*]] = add i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW]]) ; CHECK-NEXT: ret i64 [[ADD_ZEXT]] ; entry: %add.nuw = add nuw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %add.zext = add i64 %arg0.zext, %arg1.zext call void @use.i32(i32 %add.nuw) ret i64 %add.zext } ; Should fold out the sub i64 define i64 @sub_zext__dominating_sub_nuw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_zext__dominating_sub_nuw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_ZEXT:%.*]] = sub i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: ret i64 [[SUB_ZEXT]] ; entry: %sub.nuw = sub nuw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %sub.zext = sub i64 %arg0.zext, %arg1.zext call void @use.i32(i32 %sub.nuw) ret i64 %sub.zext } ; Should fold out the add <2 x i64> define <2 x i64> @add_zext__dominating_add_nuw_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @add_zext__dominating_add_nuw_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW:%.*]] = add nuw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[ADD_ZEXT:%.*]] = add <2 x i64> [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[ADD_NUW]]) ; CHECK-NEXT: ret <2 x i64> [[ADD_ZEXT]] ; entry: %add.nuw = add nuw <2 x i32> %arg0, %arg1 %arg0.zext = zext <2 x i32> %arg0 to <2 x i64> %arg1.zext = zext <2 x i32> %arg1 to <2 x i64> %add.zext = add <2 x i64> %arg0.zext, %arg1.zext call void @use.v2i32(<2 x i32> %add.nuw) ret <2 x i64> %add.zext } ; Should fold out the sub <2 x i64> define <2 x i64> @sub_zext__dominating_sub_nuw_vector(<2 x i32> %arg0, <2 x i32> %arg1) { ; CHECK-LABEL: define <2 x i64> @sub_zext__dominating_sub_nuw_vector ; CHECK-SAME: (<2 x i32> [[ARG0:%.*]], <2 x i32> [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw <2 x i32> [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext <2 x i32> [[ARG0]] to <2 x i64> ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext <2 x i32> [[ARG1]] to <2 x i64> ; CHECK-NEXT: [[SUB_ZEXT:%.*]] = sub <2 x i64> [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.v2i32(<2 x i32> [[SUB_NUW]]) ; CHECK-NEXT: ret <2 x i64> [[SUB_ZEXT]] ; entry: %sub.nuw = sub nuw <2 x i32> %arg0, %arg1 %arg0.zext = zext <2 x i32> %arg0 to <2 x i64> %arg1.zext = zext <2 x i32> %arg1 to <2 x i64> %sub.zext = sub <2 x i64> %arg0.zext, %arg1.zext call void @use.v2i32(<2 x i32> %sub.nuw) ret <2 x i64> %sub.zext } ; Both nuw and nsw exist define void @add_zext_add_sext__dominating_add_nuw_add_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define void @add_zext_add_sext__dominating_add_nuw_add_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW:%.*]] = add nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_NSW:%.*]] = add nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_ZEXT:%.*]] = add i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = add i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW]]) ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NSW]]) ; CHECK-NEXT: call void @use.i64(i64 [[ADD_ZEXT]]) ; CHECK-NEXT: call void @use.i64(i64 [[ADD_SEXT]]) ; CHECK-NEXT: ret void ; entry: %add.nuw = add nuw i32 %arg0, %arg1 %add.nsw = add nsw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.zext = add i64 %arg0.zext, %arg1.zext %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nuw) call void @use.i32(i32 %add.nsw) call void @use.i64(i64 %add.zext) call void @use.i64(i64 %add.sext) ret void } ; Both exist define void @sub_zext_sub_sext__dominating_sub_nuw_sub_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define void @sub_zext_sub_sext__dominating_sub_nuw_sub_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_ZEXT:%.*]] = sub i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_ZEXT]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_SEXT]]) ; CHECK-NEXT: ret void ; entry: %sub.nuw = sub nuw i32 %arg0, %arg1 %sub.nsw = sub nsw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.zext = sub i64 %arg0.zext, %arg1.zext %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nuw) call void @use.i32(i32 %sub.nsw) call void @use.i64(i64 %sub.zext) call void @use.i64(i64 %sub.sext) ret void } ; Both exist with commuted operands from each other define void @sub_zext_sub_sext__dominating_sub_nuw_sub_nsw_commuted(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define void @sub_zext_sub_sext__dominating_sub_nuw_sub_nsw_commuted ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_NSW:%.*]] = sub nsw i32 [[ARG1]], [[ARG0]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ARG0_SEXT:%.*]] = sext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_SEXT:%.*]] = sext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_ZEXT:%.*]] = sub i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sub i64 [[ARG0_SEXT]], [[ARG1_SEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NSW]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_ZEXT]]) ; CHECK-NEXT: call void @use.i64(i64 [[SUB_SEXT]]) ; CHECK-NEXT: ret void ; entry: %sub.nuw = sub nuw i32 %arg0, %arg1 %sub.nsw = sub nsw i32 %arg1, %arg0 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.zext = sub i64 %arg0.zext, %arg1.zext %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nuw) call void @use.i32(i32 %sub.nsw) call void @use.i64(i64 %sub.zext) call void @use.i64(i64 %sub.sext) ret void } ; -------------------------------------------------------------------- ; zext x nuw+nsw ; -------------------------------------------------------------------- ; Should fold out the add i64 define i64 @add_zext__dominating_add_nuw_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_zext__dominating_add_nuw_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW_NSW:%.*]] = add nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_ZEXT:%.*]] = add i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_ZEXT]] ; entry: %add.nuw.nsw = add nuw nsw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %add.zext = add i64 %arg0.zext, %arg1.zext call void @use.i32(i32 %add.nuw.nsw) ret i64 %add.zext } ; Should fold out the add i64 define i64 @add_zext__dominating_add_nuw_nsw_commute(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_zext__dominating_add_nuw_nsw_commute ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW_NSW:%.*]] = add nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[ADD_ZEXT:%.*]] = add i64 [[ARG1_ZEXT]], [[ARG0_ZEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_ZEXT]] ; entry: %add.nuw.nsw = add nuw nsw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %add.zext = add i64 %arg1.zext, %arg0.zext call void @use.i32(i32 %add.nuw.nsw) ret i64 %add.zext } ; Should fold out the sub i64 define i64 @sub_zext__dominating_sub_nuw_esw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_zext__dominating_sub_nuw_esw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ARG0_ZEXT:%.*]] = zext i32 [[ARG0]] to i64 ; CHECK-NEXT: [[ARG1_ZEXT:%.*]] = zext i32 [[ARG1]] to i64 ; CHECK-NEXT: [[SUB_ZEXT:%.*]] = sub i64 [[ARG0_ZEXT]], [[ARG1_ZEXT]] ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: ret i64 [[SUB_ZEXT]] ; entry: %sub.nuw = sub nuw nsw i32 %arg0, %arg1 %arg0.zext = zext i32 %arg0 to i64 %arg1.zext = zext i32 %arg1 to i64 %sub.zext = sub i64 %arg0.zext, %arg1.zext call void @use.i32(i32 %sub.nuw) ret i64 %sub.zext } ; -------------------------------------------------------------------- ; sext x nuw+nsw ; -------------------------------------------------------------------- ; Should fold out the add i64 define i64 @add_sext__dominating_add_nuw_nsw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nuw_nsw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW_NSW:%.*]] = add nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NUW_NSW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nuw.nsw = add nuw nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %add.nuw.nsw) ret i64 %add.sext } ; Should fold out the add i64 define i64 @add_sext__dominating_add_nuw_nsw_commute(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @add_sext__dominating_add_nuw_nsw_commute ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ADD_NUW_NSW:%.*]] = add nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[ADD_SEXT:%.*]] = sext i32 [[ADD_NUW_NSW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[ADD_NUW_NSW]]) ; CHECK-NEXT: ret i64 [[ADD_SEXT]] ; entry: %add.nuw.nsw = add nuw nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %add.sext = add i64 %arg1.sext, %arg0.sext call void @use.i32(i32 %add.nuw.nsw) ret i64 %add.sext } ; Should fold out the sub i64 define i64 @sub_sext__dominating_sub_nuw_esw(i32 %arg0, i32 %arg1) { ; CHECK-LABEL: define i64 @sub_sext__dominating_sub_nuw_esw ; CHECK-SAME: (i32 [[ARG0:%.*]], i32 [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[SUB_NUW:%.*]] = sub nuw nsw i32 [[ARG0]], [[ARG1]] ; CHECK-NEXT: [[SUB_SEXT:%.*]] = sext i32 [[SUB_NUW]] to i64 ; CHECK-NEXT: call void @use.i32(i32 [[SUB_NUW]]) ; CHECK-NEXT: ret i64 [[SUB_SEXT]] ; entry: %sub.nuw = sub nuw nsw i32 %arg0, %arg1 %arg0.sext = sext i32 %arg0 to i64 %arg1.sext = sext i32 %arg1 to i64 %sub.sext = sub i64 %arg0.sext, %arg1.sext call void @use.i32(i32 %sub.nuw) ret i64 %sub.sext }