[llvm] r205540 - ARM: tell LLVM about zext properties of ldrexb/ldrexh

Tim Northover tnorthover at apple.com
Thu Apr 3 08:10:35 PDT 2014


Author: tnorthover
Date: Thu Apr  3 10:10:35 2014
New Revision: 205540

URL: http://llvm.org/viewvc/llvm-project?rev=205540&view=rev
Log:
ARM: tell LLVM about zext properties of ldrexb/ldrexh

Implementing this via ComputeMaskedBits has two advantages:
  + It actually works. DAGISel doesn't deal with the chains properly
    in the previous pattern-based solution, so they never trigger.
  + The information can be used in other DAG combines, as well as the
    trivial "get rid of truncs". For example if the trunc is in a
    different basic block.

rdar://problem/16227836

Modified:
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
    llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
    llvm/trunk/test/CodeGen/ARM/atomic-ops-v8.ll
    llvm/trunk/test/CodeGen/ARM/ldaex-stlex.ll
    llvm/trunk/test/CodeGen/ARM/ldstrex.ll

Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=205540&r1=205539&r2=205540&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Thu Apr  3 10:10:35 2014
@@ -9964,6 +9964,20 @@ void ARMTargetLowering::computeMaskedBit
     KnownOne  &= KnownOneRHS;
     return;
   }
+  case ISD::INTRINSIC_W_CHAIN: {
+    ConstantSDNode *CN = cast<ConstantSDNode>(Op->getOperand(1));
+    Intrinsic::ID IntID = static_cast<Intrinsic::ID>(CN->getZExtValue());
+    switch (IntID) {
+    default: return;
+    case Intrinsic::arm_ldaex:
+    case Intrinsic::arm_ldrex: {
+      EVT VT = cast<MemIntrinsicSDNode>(Op)->getMemoryVT();
+      unsigned MemBits = VT.getScalarType().getSizeInBits();
+      KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - MemBits);
+      return;
+    }
+    }
+  }
   }
 }
 

Modified: llvm/trunk/lib/Target/ARM/ARMInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMInstrInfo.td?rev=205540&r1=205539&r2=205540&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMInstrInfo.td (original)
+++ llvm/trunk/lib/Target/ARM/ARMInstrInfo.td Thu Apr  3 10:10:35 2014
@@ -4476,19 +4476,11 @@ def CLREX : AXI<(outs), (ins), MiscFrm,
   let Inst{31-0} = 0b11110101011111111111000000011111;
 }
 
-def : ARMPat<(and (ldrex_1 addr_offset_none:$addr), 0xff),
-             (LDREXB addr_offset_none:$addr)>;
-def : ARMPat<(and (ldrex_2 addr_offset_none:$addr), 0xffff),
-             (LDREXH addr_offset_none:$addr)>;
 def : ARMPat<(strex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
              (STREXB GPR:$Rt, addr_offset_none:$addr)>;
 def : ARMPat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
              (STREXH GPR:$Rt, addr_offset_none:$addr)>;
 
-def : ARMPat<(and (ldaex_1 addr_offset_none:$addr), 0xff),
-             (LDAEXB addr_offset_none:$addr)>;
-def : ARMPat<(and (ldaex_2 addr_offset_none:$addr), 0xffff),
-             (LDAEXH addr_offset_none:$addr)>;
 def : ARMPat<(stlex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
              (STLEXB GPR:$Rt, addr_offset_none:$addr)>;
 def : ARMPat<(stlex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),

Modified: llvm/trunk/test/CodeGen/ARM/atomic-ops-v8.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/atomic-ops-v8.ll?rev=205540&r1=205539&r2=205540&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/atomic-ops-v8.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/atomic-ops-v8.ll Thu Apr  3 10:10:35 2014
@@ -805,8 +805,8 @@ define i8 @test_atomic_load_umin_i8(i8 z
 ; CHECK: ldrexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxtb r[[OLDX]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; Thumb mode: it ls
 ; CHECK:      movls r[[NEW]], r[[OLD]]
 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
@@ -831,8 +831,8 @@ define i16 @test_atomic_load_umin_i16(i1
 ; CHECK: ldaexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxth r[[OLDX]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; Thumb mode: it ls
 ; CHECK:      movls r[[NEW]], r[[OLD]]
 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
@@ -919,8 +919,8 @@ define i8 @test_atomic_load_umax_i8(i8 z
 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; Thumb mode: it hi
 ; CHECK:      movhi r[[NEW]], r[[OLD]]
 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
@@ -945,8 +945,8 @@ define i16 @test_atomic_load_umax_i16(i1
 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; Thumb mode: it hi
 ; CHECK:      movhi r[[NEW]], r[[OLD]]
 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
@@ -1033,8 +1033,7 @@ define i8 @test_atomic_cmpxchg_i8(i8 zer
 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
 ; CHECK-NEXT: BB#2:
   ; As above, r1 is a reasonable guess.
@@ -1060,8 +1059,7 @@ define i16 @test_atomic_cmpxchg_i16(i16
 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
   ; r0 below is a reasonable guess but could change: it certainly comes into the
   ;  function there.
-; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
-; CHECK-NEXT: cmp r[[OLDX]], r0
+; CHECK-NEXT: cmp r[[OLD]], r0
 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
 ; CHECK-NEXT: BB#2:
   ; As above, r1 is a reasonable guess.

Modified: llvm/trunk/test/CodeGen/ARM/ldaex-stlex.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldaex-stlex.ll?rev=205540&r1=205539&r2=205540&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/ldaex-stlex.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/ldaex-stlex.ll Thu Apr  3 10:10:35 2014
@@ -34,17 +34,21 @@ declare i32 @llvm.arm.stlexd(i32, i32, i
 ; CHECK-LABEL: test_load_i8:
 ; CHECK: ldaexb r0, [r0]
 ; CHECK-NOT: uxtb
-define i32 @test_load_i8(i8* %addr) {
+; CHECK-NOT: and
+define zeroext i8 @test_load_i8(i8* %addr) {
   %val = call i32 @llvm.arm.ldaex.p0i8(i8* %addr)
-  ret i32 %val
+  %val8 = trunc i32 %val to i8
+  ret i8 %val8
 }
 
 ; CHECK-LABEL: test_load_i16:
 ; CHECK: ldaexh r0, [r0]
 ; CHECK-NOT: uxth
-define i32 @test_load_i16(i16* %addr) {
+; CHECK-NOT: and
+define zeroext i16 @test_load_i16(i16* %addr) {
   %val = call i32 @llvm.arm.ldaex.p0i16(i16* %addr)
-  ret i32 %val
+  %val16 = trunc i32 %val to i16
+  ret i16 %val16
 }
 
 ; CHECK-LABEL: test_load_i32:

Modified: llvm/trunk/test/CodeGen/ARM/ldstrex.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/ldstrex.ll?rev=205540&r1=205539&r2=205540&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/ldstrex.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/ldstrex.ll Thu Apr  3 10:10:35 2014
@@ -36,17 +36,21 @@ declare i32 @llvm.arm.strexd(i32, i32, i
 ; CHECK-LABEL: test_load_i8:
 ; CHECK: ldrexb r0, [r0]
 ; CHECK-NOT: uxtb
-define i32 @test_load_i8(i8* %addr) {
+; CHECK-NOT: and
+define zeroext i8 @test_load_i8(i8* %addr) {
   %val = call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
-  ret i32 %val
+  %val8 = trunc i32 %val to i8
+  ret i8 %val8
 }
 
 ; CHECK-LABEL: test_load_i16:
 ; CHECK: ldrexh r0, [r0]
 ; CHECK-NOT: uxth
-define i32 @test_load_i16(i16* %addr) {
+; CHECK-NOT: and
+define zeroext i16 @test_load_i16(i16* %addr) {
   %val = call i32 @llvm.arm.ldrex.p0i16(i16* %addr)
-  ret i32 %val
+  %val16 = trunc i32 %val to i16
+  ret i16 %val16
 }
 
 ; CHECK-LABEL: test_load_i32:
@@ -137,3 +141,19 @@ define void @excl_addrmode() {
 
   ret void
 }
+
+; LLVM should know, even across basic blocks, that ldrex is setting the high
+; bits of its i32 to 0. There should be no zero-extend operation.
+define zeroext i8 @test_cross_block_zext_i8(i1 %tst, i8* %addr) {
+; CHECK: test_cross_block_zext_i8:
+; CHECK-NOT: uxtb
+; CHECK-NOT: and
+; CHECK: bx lr
+  %val = call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
+  br i1 %tst, label %end, label %mid
+mid:
+  ret i8 42
+end:
+  %val8 = trunc i32 %val to i8
+  ret i8 %val8
+}





More information about the llvm-commits mailing list