llvm.org GIT mirror llvm / 5811c15
Re-commit r289955: [X86] Fold (setcc (cmp (atomic_load_add x, -C) C), COND) to (setcc (LADD x, -C), COND) (PR31367) This was reverted because it would miscompile code where the cmp had multiple uses. That was due to a deficiency in the existing code, which was fixed in r291630 (see the PR for details). This re-commit includes an extra test for the kind of code that got miscompiled: @test_sub_1_setcc_jcc. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291640 91177308-0d34-0410-b5e6-96231b3b80d8 Hans Wennborg 3 years ago
2 changed file(s) with 86 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
2939029390 return SDValue();
2939129391 }
2939229392
29393 /// Combine:
29393 /// Combine brcond/cmov/setcc/.. based on comparing the result of
29394 /// atomic_load_add to use EFLAGS produced by the addition
29395 /// directly if possible. For example:
29396 ///
29397 /// (setcc (cmp (atomic_load_add x, -C) C), COND_E)
29398 /// becomes:
29399 /// (setcc (LADD x, -C), COND_E)
29400 ///
29401 /// and
2939429402 /// (brcond/cmov/setcc .., (cmp (atomic_load_add x, 1), 0), COND_S)
29395 /// to:
29403 /// becomes:
2939629404 /// (brcond/cmov/setcc .., (LADD x, 1), COND_LE)
29397 /// i.e., reusing the EFLAGS produced by the LOCKed instruction.
29405 ///
2939829406 /// Note that this is only legal for some op/cc combinations.
2939929407 static SDValue combineSetCCAtomicArith(SDValue Cmp, X86::CondCode &CC,
2940029408 SelectionDAG &DAG) {
2940929417 if (!Cmp.hasOneUse())
2941029418 return SDValue();
2941129419
29412 // This only applies to variations of the common case:
29420 // This applies to variations of the common case:
2941329421 // (icmp slt x, 0) -> (icmp sle (add x, 1), 0)
2941429422 // (icmp sge x, 0) -> (icmp sgt (add x, 1), 0)
2941529423 // (icmp sle x, 0) -> (icmp slt (sub x, 1), 0)
2942829436 return SDValue();
2942929437
2943029438 auto *CmpRHSC = dyn_cast(CmpRHS);
29431 if (!CmpRHSC || CmpRHSC->getZExtValue() != 0)
29439 if (!CmpRHSC)
2943229440 return SDValue();
29441 APInt Comparand = CmpRHSC->getAPIntValue();
2943329442
2943429443 const unsigned Opc = CmpLHS.getOpcode();
2943529444
2944529454 if (Opc == ISD::ATOMIC_LOAD_SUB)
2944629455 Addend = -Addend;
2944729456
29448 if (CC == X86::COND_S && Addend == 1)
29457 if (Comparand == -Addend) {
29458 // No change to CC.
29459 } else if (CC == X86::COND_S && Comparand == 0 && Addend == 1) {
2944929460 CC = X86::COND_LE;
29450 else if (CC == X86::COND_NS && Addend == 1)
29461 } else if (CC == X86::COND_NS && Comparand == 0 && Addend == 1) {
2945129462 CC = X86::COND_G;
29452 else if (CC == X86::COND_G && Addend == -1)
29463 } else if (CC == X86::COND_G && Comparand == 0 && Addend == -1) {
2945329464 CC = X86::COND_GE;
29454 else if (CC == X86::COND_LE && Addend == -1)
29465 } else if (CC == X86::COND_LE && Comparand == 0 && Addend == -1) {
2945529466 CC = X86::COND_L;
29456 else
29467 } else {
2945729468 return SDValue();
29469 }
2945829470
2945929471 SDValue LockOp = lowerAtomicArithWithLOCK(CmpLHS, DAG);
2946029472 DAG.ReplaceAllUsesOfValueWith(CmpLHS.getValue(0),
191191 ret i8 %s2
192192 }
193193
194 define i8 @test_sub_1_setcc_eq(i64* %p) #0 {
195 ; CHECK-LABEL: test_sub_1_setcc_eq:
196 ; CHECK: # BB#0: # %entry
197 ; CHECK-NEXT: lock decq (%rdi)
198 ; CHECK-NEXT: sete %al
199 ; CHECK-NEXT: retq
200 entry:
201 %tmp0 = atomicrmw sub i64* %p, i64 1 seq_cst
202 %tmp1 = icmp eq i64 %tmp0, 1
203 %tmp2 = zext i1 %tmp1 to i8
204 ret i8 %tmp2
205 }
206
207 define i8 @test_add_5_setcc_ne(i64* %p) #0 {
208 ; CHECK-LABEL: test_add_5_setcc_ne:
209 ; CHECK: # BB#0: # %entry
210 ; CHECK-NEXT: lock addq $5, (%rdi)
211 ; CHECK-NEXT: setne %al
212 ; CHECK-NEXT: retq
213 entry:
214 %tmp0 = atomicrmw add i64* %p, i64 5 seq_cst
215 %tmp1 = icmp ne i64 %tmp0, -5
216 %tmp2 = zext i1 %tmp1 to i8
217 ret i8 %tmp2
218 }
219
220 define i8 @test_add_5_setcc_ne_comparand_mismatch(i64* %p) #0 {
221 ; CHECK-LABEL: test_add_5_setcc_ne_comparand_mismatch:
222 ; CHECK: # BB#0: # %entry
223 ; CHECK-NEXT: movl $5, %eax
224 ; CHECK-NEXT: lock xaddq %rax, (%rdi)
225 ; CHECK-NEXT: testq %rax, %rax
226 ; CHECK-NEXT: setne %al
227 ; CHECK-NEXT: retq
228 entry:
229 %tmp0 = atomicrmw add i64* %p, i64 5 seq_cst
230 %tmp1 = icmp ne i64 %tmp0, 0
231 %tmp2 = zext i1 %tmp1 to i8
232 ret i8 %tmp2
233 }
234
235 declare void @g()
236 define zeroext i1 @test_sub_1_setcc_jcc(i64* %p) local_unnamed_addr #0 {
237 ; TODO: It's possible to use "lock dec" here, but both uses of the cmp need to
238 ; be updated.
239 ; CHECK-LABEL: test_sub_1_setcc_jcc:
240 ; CHECK: # BB#0: # %entry
241 ; CHECK: movq $-1, %rax
242 ; CHECK-NEXT: lock xaddq %rax, (%rdi)
243 ; CHECK-NEXT: cmpq $1, %rax
244 ; CHECK-NEXT: sete %bl
245 ; CHECK-NEXT: jne
246 entry:
247 %add = atomicrmw volatile add i64* %p, i64 -1 seq_cst
248 %cmp = icmp ne i64 %add, 1
249 %not = xor i1 %cmp, true
250 br i1 %cmp, label %else, label %then
251 then:
252 tail call void @g()
253 br label %else
254 else:
255 ret i1 %not
256 }
257
194258 attributes #0 = { nounwind }