Skip to content

Commit 9a0197c

Browse files
authored
[EarlyCSE] Check attributes for commutative intrinsics (#142610)
Commutative intrinsics go through a separate code path, which did not check for attribute compatibility, resulting in a later assertion failure. Fixes #142462.
1 parent 4c64490 commit 9a0197c

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

llvm/lib/Transforms/Scalar/EarlyCSE.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,9 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) {
400400
return LII->getArgOperand(0) == RII->getArgOperand(1) &&
401401
LII->getArgOperand(1) == RII->getArgOperand(0) &&
402402
std::equal(LII->arg_begin() + 2, LII->arg_end(),
403-
RII->arg_begin() + 2, RII->arg_end());
403+
RII->arg_begin() + 2, RII->arg_end()) &&
404+
LII->hasSameSpecialState(RII, /*IgnoreAlignment=*/false,
405+
/*IntersectAttrs=*/true);
404406
}
405407

406408
// See comment above in `getHashValue()`.

llvm/test/Transforms/EarlyCSE/replace-calls-def-attrs.ll

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ declare i8 @buz.fp(float, float)
1313
define i8 @same_parent_combine_diff_attrs(i8 %x, i8 %y) {
1414
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs(
1515
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
16-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0:[0-9]+]]
16+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1:[0-9]+]]
1717
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C1]], i8 [[C1]])
1818
; CHECK-NEXT: ret i8 [[R]]
1919
;
@@ -27,7 +27,7 @@ define i8 @same_parent_combine_diff_attrs(i8 %x, i8 %y) {
2727
define i8 @same_parent_combine_diff_attrs_needs_intersect(i8 %x, i8 %y) {
2828
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_needs_intersect(
2929
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
30-
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
30+
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
3131
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.ptr(ptr [[C1]], ptr [[C1]])
3232
; CHECK-NEXT: ret i8 [[R]]
3333
;
@@ -41,7 +41,7 @@ define i8 @same_parent_combine_diff_attrs_needs_intersect(i8 %x, i8 %y) {
4141
define i8 @same_parent_combine_diff_attrs_fmf(float %x, float %y) {
4242
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_fmf(
4343
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
44-
; CHECK-NEXT: [[C1:%.*]] = call nnan float @baz.fp(float [[X]], float noundef [[Y]]) #[[ATTR1:[0-9]+]]
44+
; CHECK-NEXT: [[C1:%.*]] = call nnan float @baz.fp(float [[X]], float noundef [[Y]]) #[[ATTR2:[0-9]+]]
4545
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.fp(float [[C1]], float [[C1]])
4646
; CHECK-NEXT: ret i8 [[R]]
4747
;
@@ -55,7 +55,7 @@ define i8 @same_parent_combine_diff_attrs_fmf(float %x, float %y) {
5555
define i8 @same_parent_combine_diff_attrs_fmf2(float %x, float %y) {
5656
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_fmf2(
5757
; CHECK-SAME: float [[X:%.*]], float [[Y:%.*]]) {
58-
; CHECK-NEXT: [[C1:%.*]] = call nnan float @baz.fp(float [[X]], float noundef [[Y]]) #[[ATTR0]]
58+
; CHECK-NEXT: [[C1:%.*]] = call nnan float @baz.fp(float [[X]], float noundef [[Y]]) #[[ATTR1]]
5959
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.fp(float [[C1]], float [[C1]])
6060
; CHECK-NEXT: ret i8 [[R]]
6161
;
@@ -69,7 +69,7 @@ define i8 @same_parent_combine_diff_attrs_fmf2(float %x, float %y) {
6969
define i8 @same_parent_combine_diff_attrs_needs_intersect2(i8 %x, i8 %y) {
7070
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_needs_intersect2(
7171
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
72-
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
72+
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR2]]
7373
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.ptr(ptr [[C1]], ptr [[C1]])
7474
; CHECK-NEXT: ret i8 [[R]]
7575
;
@@ -83,7 +83,7 @@ define i8 @same_parent_combine_diff_attrs_needs_intersect2(i8 %x, i8 %y) {
8383
define i8 @same_parent_combine_diff_attrs_really_needs_intersect(i8 %x, i8 %y) {
8484
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_really_needs_intersect(
8585
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
86-
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
86+
; CHECK-NEXT: [[C1:%.*]] = call ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR2]]
8787
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.ptr(ptr [[C1]], ptr noundef [[C1]])
8888
; CHECK-NEXT: ret i8 [[R]]
8989
;
@@ -112,7 +112,7 @@ define i8 @same_parent_combine_diff_attrs_fail_side_effects(i8 %x, i8 %y) {
112112
define i8 @same_parent_combine_diff_attrs_quasi_side_effects2(i8 %x, i8 %y) {
113113
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_quasi_side_effects2(
114114
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
115-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR0]]
115+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR1]]
116116
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]])
117117
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
118118
; CHECK-NEXT: ret i8 [[R]]
@@ -127,10 +127,10 @@ define i8 @same_parent_combine_diff_attrs_quasi_side_effects2(i8 %x, i8 %y) {
127127
define i8 @diff_parent_combine_diff_attrs(i1 %c, i8 %x, i8 %y) {
128128
; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs(
129129
; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
130-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
130+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
131131
; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
132132
; CHECK: [[T]]:
133-
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR1]]
133+
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR2]]
134134
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
135135
; CHECK-NEXT: ret i8 [[R]]
136136
; CHECK: [[F]]:
@@ -151,7 +151,7 @@ F:
151151
define i8 @diff_parent_combine_diff_attrs_preserves_return_attrs(i1 %c, i8 %x, i8 %y) {
152152
; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs_preserves_return_attrs(
153153
; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
154-
; CHECK-NEXT: [[C1:%.*]] = call nonnull ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
154+
; CHECK-NEXT: [[C1:%.*]] = call nonnull ptr @baz.ptr(i8 [[X]], i8 noundef [[Y]]) #[[ATTR2]]
155155
; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
156156
; CHECK: [[T]]:
157157
; CHECK-NEXT: [[R:%.*]] = call i8 @buz.ptr(ptr [[C1]], ptr noundef [[C1]])
@@ -172,8 +172,8 @@ F:
172172
define i8 @same_parent_combine_diff_attrs_todo(i8 %x, i8 %y) {
173173
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_todo(
174174
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
175-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
176-
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR2:[0-9]+]]
175+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
176+
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR3:[0-9]+]]
177177
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
178178
; CHECK-NEXT: ret i8 [[R]]
179179
;
@@ -187,8 +187,8 @@ define i8 @same_parent_combine_diff_attrs_todo(i8 %x, i8 %y) {
187187
define i8 @same_parent_combine_diff_attrs_fail(i8 %x, i8 %y) {
188188
; CHECK-LABEL: define i8 @same_parent_combine_diff_attrs_fail(
189189
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
190-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
191-
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR3:[0-9]+]]
190+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
191+
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR4:[0-9]+]]
192192
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
193193
; CHECK-NEXT: ret i8 [[R]]
194194
;
@@ -202,10 +202,10 @@ define i8 @same_parent_combine_diff_attrs_fail(i8 %x, i8 %y) {
202202
define i8 @diff_parent_combine_diff_attrs_todo(i1 %c, i8 %x, i8 %y) {
203203
; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs_todo(
204204
; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
205-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
205+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
206206
; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
207207
; CHECK: [[T]]:
208-
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR4:[0-9]+]]
208+
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR5:[0-9]+]]
209209
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
210210
; CHECK-NEXT: ret i8 [[R]]
211211
; CHECK: [[F]]:
@@ -226,10 +226,10 @@ F:
226226
define i8 @diff_parent_combine_diff_attrs_fail(i1 %c, i8 %x, i8 %y) {
227227
; CHECK-LABEL: define i8 @diff_parent_combine_diff_attrs_fail(
228228
; CHECK-SAME: i1 [[C:%.*]], i8 [[X:%.*]], i8 [[Y:%.*]]) {
229-
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR0]]
229+
; CHECK-NEXT: [[C1:%.*]] = call i8 @baz(i8 [[X]], i8 noundef [[Y]]) #[[ATTR1]]
230230
; CHECK-NEXT: br i1 [[C]], label %[[T:.*]], label %[[F:.*]]
231231
; CHECK: [[T]]:
232-
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR3]]
232+
; CHECK-NEXT: [[C0:%.*]] = call i8 @baz(i8 noundef [[X]], i8 noundef [[Y]]) #[[ATTR4]]
233233
; CHECK-NEXT: [[R:%.*]] = call i8 @buz(i8 [[C0]], i8 [[C1]])
234234
; CHECK-NEXT: ret i8 [[R]]
235235
; CHECK: [[F]]:
@@ -247,10 +247,26 @@ F:
247247
ret i8 %r2
248248
}
249249

250+
define i32 @commutative_intrinsic_intersection_failure(i32 %arg, i32 %arg1) {
251+
; CHECK-LABEL: define i32 @commutative_intrinsic_intersection_failure(
252+
; CHECK-SAME: i32 [[ARG:%.*]], i32 [[ARG1:%.*]]) {
253+
; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.smin.i32(i32 [[ARG]], i32 [[ARG1]]) #[[ATTR6:[0-9]+]]
254+
; CHECK-NEXT: [[CALL2:%.*]] = call i32 @llvm.smin.i32(i32 [[ARG1]], i32 [[ARG]])
255+
; CHECK-NEXT: [[OR:%.*]] = or i32 [[CALL2]], [[CALL]]
256+
; CHECK-NEXT: ret i32 [[OR]]
257+
;
258+
%call = call i32 @llvm.smin.i32(i32 %arg, i32 %arg1) strictfp
259+
%call2 = call i32 @llvm.smin.i32(i32 %arg1, i32 %arg)
260+
%or = or i32 %call2, %call
261+
ret i32 %or
262+
}
263+
250264
;.
251-
; CHECK: attributes #[[ATTR0]] = { memory(none) }
252-
; CHECK: attributes #[[ATTR1]] = { memory(read) }
253-
; CHECK: attributes #[[ATTR2]] = { alwaysinline memory(none) }
254-
; CHECK: attributes #[[ATTR3]] = { strictfp memory(none) }
255-
; CHECK: attributes #[[ATTR4]] = { noinline optnone memory(none) }
265+
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
266+
; CHECK: attributes #[[ATTR1]] = { memory(none) }
267+
; CHECK: attributes #[[ATTR2]] = { memory(read) }
268+
; CHECK: attributes #[[ATTR3]] = { alwaysinline memory(none) }
269+
; CHECK: attributes #[[ATTR4]] = { strictfp memory(none) }
270+
; CHECK: attributes #[[ATTR5]] = { noinline optnone memory(none) }
271+
; CHECK: attributes #[[ATTR6]] = { strictfp }
256272
;.

0 commit comments

Comments
 (0)