Home | History | Annotate | Download | only in llvm2ice_tests
      1 ; This tests the optimization of atomic cmpxchg w/ following cmp + branches.
      2 
      3 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -O2 \
      4 ; RUN:   -allow-externally-defined-symbols | FileCheck --check-prefix=O2 %s
      5 ; RUN: %p2i -i %s --filetype=obj --disassemble --args -Om1 \
      6 ; RUN:   -allow-externally-defined-symbols | FileCheck --check-prefix=OM1 %s
      7 
      8 declare i32 @llvm.nacl.atomic.cmpxchg.i32(i32*, i32, i32, i32, i32)
      9 
     10 
     11 ; Test that a cmpxchg followed by icmp eq and branch can be optimized to
     12 ; reuse the flags set by the cmpxchg instruction itself.
     13 ; This is only expected to work w/ O2, based on lightweight liveness.
     14 ; (Or if we had other means to detect the only use).
     15 declare void @use_value(i32)
     16 
     17 define internal i32 @test_atomic_cmpxchg_loop(i32 %iptr, i32 %expected,
     18                                               i32 %desired) {
     19 entry:
     20   br label %loop
     21 
     22 loop:
     23   %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
     24   %succeeded_first_try = phi i32 [ 1, %entry ], [ 2, %loop ]
     25   %ptr = inttoptr i32 %iptr to i32*
     26   %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
     27                                                 i32 %desired, i32 6, i32 6)
     28   %success = icmp eq i32 %expected_loop, %old
     29   br i1 %success, label %done, label %loop
     30 
     31 done:
     32   call void @use_value(i32 %old)
     33   ret i32 %succeeded_first_try
     34 }
     35 ; O2-LABEL: test_atomic_cmpxchg_loop
     36 ; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
     37 ; O2-NEXT: j{{e|ne}}
     38 ; Make sure the call isn't accidentally deleted.
     39 ; O2: call
     40 ;
     41 ; Check that the unopt version does have a cmp
     42 ; OM1-LABEL: test_atomic_cmpxchg_loop
     43 ; OM1: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
     44 ; OM1: cmp
     45 ; OM1: sete
     46 ; OM1: call
     47 
     48 ; Still works if the compare operands are flipped.
     49 define internal i32 @test_atomic_cmpxchg_loop2(i32 %iptr, i32 %expected,
     50                                                i32 %desired) {
     51 entry:
     52   br label %loop
     53 
     54 loop:
     55   %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
     56   %ptr = inttoptr i32 %iptr to i32*
     57   %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
     58                                                 i32 %desired, i32 6, i32 6)
     59   %success = icmp eq i32 %old, %expected_loop
     60   br i1 %success, label %done, label %loop
     61 
     62 done:
     63   ret i32 %old
     64 }
     65 ; O2-LABEL: test_atomic_cmpxchg_loop2
     66 ; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
     67 ; O2-NOT: cmp
     68 ; O2: jne
     69 
     70 
     71 ; Still works if the compare operands are constants.
     72 define internal i32 @test_atomic_cmpxchg_loop_const(i32 %iptr, i32 %desired) {
     73 entry:
     74   br label %loop
     75 
     76 loop:
     77   %succeeded_first_try = phi i32 [ 1, %entry ], [ 0, %loop ]
     78   %ptr = inttoptr i32 %iptr to i32*
     79   %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 0,
     80                                                 i32 %desired, i32 6, i32 6)
     81   %success = icmp eq i32 %old, 0
     82   br i1 %success, label %done, label %loop
     83 
     84 done:
     85   ret i32 %succeeded_first_try
     86 }
     87 ; O2-LABEL: test_atomic_cmpxchg_loop_const
     88 ; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
     89 ; O2-NEXT: j{{e|ne}}
     90 
     91 ; This is a case where the flags cannot be reused (compare is for some
     92 ; other condition).
     93 define internal i32 @test_atomic_cmpxchg_no_opt(i32 %iptr, i32 %expected,
     94                                                 i32 %desired) {
     95 entry:
     96   br label %loop
     97 
     98 loop:
     99   %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
    100   %ptr = inttoptr i32 %iptr to i32*
    101   %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
    102                                                 i32 %desired, i32 6, i32 6)
    103   %success = icmp sgt i32 %old, %expected
    104   br i1 %success, label %done, label %loop
    105 
    106 done:
    107   ret i32 %old
    108 }
    109 ; O2-LABEL: test_atomic_cmpxchg_no_opt
    110 ; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
    111 ; O2: cmp
    112 ; O2: jle
    113 
    114 ; Another case where the flags cannot be reused (the comparison result
    115 ; is used somewhere else).
    116 define internal i32 @test_atomic_cmpxchg_no_opt2(i32 %iptr, i32 %expected,
    117                                                  i32 %desired) {
    118 entry:
    119   br label %loop
    120 
    121 loop:
    122   %expected_loop = phi i32 [ %expected, %entry ], [ %old, %loop ]
    123   %ptr = inttoptr i32 %iptr to i32*
    124   %old = call i32 @llvm.nacl.atomic.cmpxchg.i32(i32* %ptr, i32 %expected_loop,
    125                                                 i32 %desired, i32 6, i32 6)
    126   %success = icmp eq i32 %old, %expected
    127   br i1 %success, label %done, label %loop
    128 
    129 done:
    130   %r = zext i1 %success to i32
    131   ret i32 %r
    132 }
    133 ; O2-LABEL: test_atomic_cmpxchg_no_opt2
    134 ; O2: lock cmpxchg DWORD PTR [e{{[^a].}}],e{{[^a]}}
    135 ; O2: cmp
    136 ; O2: sete
    137