llvm.org GIT mirror llvm / d5561bb
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@205540 91177308-0d34-0410-b5e6-96231b3b80d8 Tim Northover 5 years ago
5 changed file(s) with 56 addition(s) and 28 deletion(s). Raw diff Collapse all Expand all
99639963 KnownOne &= KnownOneRHS;
99649964 return;
99659965 }
9966 case ISD::INTRINSIC_W_CHAIN: {
9967 ConstantSDNode *CN = cast(Op->getOperand(1));
9968 Intrinsic::ID IntID = static_cast(CN->getZExtValue());
9969 switch (IntID) {
9970 default: return;
9971 case Intrinsic::arm_ldaex:
9972 case Intrinsic::arm_ldrex: {
9973 EVT VT = cast(Op)->getMemoryVT();
9974 unsigned MemBits = VT.getScalarType().getSizeInBits();
9975 KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - MemBits);
9976 return;
9977 }
9978 }
9979 }
99669980 }
99679981 }
99689982
44754475 let Inst{31-0} = 0b11110101011111111111000000011111;
44764476 }
44774477
4478 def : ARMPat<(and (ldrex_1 addr_offset_none:$addr), 0xff),
4479 (LDREXB addr_offset_none:$addr)>;
4480 def : ARMPat<(and (ldrex_2 addr_offset_none:$addr), 0xffff),
4481 (LDREXH addr_offset_none:$addr)>;
44824478 def : ARMPat<(strex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
44834479 (STREXB GPR:$Rt, addr_offset_none:$addr)>;
44844480 def : ARMPat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
44854481 (STREXH GPR:$Rt, addr_offset_none:$addr)>;
44864482
4487 def : ARMPat<(and (ldaex_1 addr_offset_none:$addr), 0xff),
4488 (LDAEXB addr_offset_none:$addr)>;
4489 def : ARMPat<(and (ldaex_2 addr_offset_none:$addr), 0xffff),
4490 (LDAEXH addr_offset_none:$addr)>;
44914483 def : ARMPat<(stlex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
44924484 (STLEXB GPR:$Rt, addr_offset_none:$addr)>;
44934485 def : ARMPat<(stlex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
804804 ; CHECK: ldrexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
805805 ; r0 below is a reasonable guess but could change: it certainly comes into the
806806 ; function there.
807 ; CHECK-NEXT: uxtb r[[OLDX]], r[[OLD]]
808 ; CHECK-NEXT: cmp r[[OLDX]], r0
807 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
808 ; CHECK-NEXT: cmp r[[OLD]], r0
809809 ; Thumb mode: it ls
810810 ; CHECK: movls r[[NEW]], r[[OLD]]
811811 ; CHECK-NEXT: strexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
830830 ; CHECK: ldaexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
831831 ; r0 below is a reasonable guess but could change: it certainly comes into the
832832 ; function there.
833 ; CHECK-NEXT: uxth r[[OLDX]], r[[OLD]]
834 ; CHECK-NEXT: cmp r[[OLDX]], r0
833 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
834 ; CHECK-NEXT: cmp r[[OLD]], r0
835835 ; Thumb mode: it ls
836836 ; CHECK: movls r[[NEW]], r[[OLD]]
837837 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
918918 ; CHECK: ldaexb r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
919919 ; r0 below is a reasonable guess but could change: it certainly comes into the
920920 ; function there.
921 ; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
922 ; CHECK-NEXT: cmp r[[OLDX]], r0
921 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
922 ; CHECK-NEXT: cmp r[[OLD]], r0
923923 ; Thumb mode: it hi
924924 ; CHECK: movhi r[[NEW]], r[[OLD]]
925925 ; CHECK-NEXT: stlexb [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
944944 ; CHECK: ldrexh r[[OLD:[0-9]+]], {{.*}}[[ADDR]]
945945 ; r0 below is a reasonable guess but could change: it certainly comes into the
946946 ; function there.
947 ; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
948 ; CHECK-NEXT: cmp r[[OLDX]], r0
947 ; CHECK-NEXT: mov r[[NEW:[0-9]+]], r0
948 ; CHECK-NEXT: cmp r[[OLD]], r0
949949 ; Thumb mode: it hi
950950 ; CHECK: movhi r[[NEW]], r[[OLD]]
951951 ; CHECK-NEXT: strexh [[STATUS:r[0-9]+]], r[[NEW]], {{.*}}[[ADDR]]
10321032 ; CHECK: ldaexb r[[OLD:[0-9]+]], [r[[ADDR]]]
10331033 ; r0 below is a reasonable guess but could change: it certainly comes into the
10341034 ; function there.
1035 ; CHECK-NEXT: uxtb r[[OLDX:[0-9]+]], r[[OLD]]
1036 ; CHECK-NEXT: cmp r[[OLDX]], r0
1035 ; CHECK-NEXT: cmp r[[OLD]], r0
10371036 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
10381037 ; CHECK-NEXT: BB#2:
10391038 ; As above, r1 is a reasonable guess.
10591058 ; CHECK: ldaexh r[[OLD:[0-9]+]], [r[[ADDR]]]
10601059 ; r0 below is a reasonable guess but could change: it certainly comes into the
10611060 ; function there.
1062 ; CHECK-NEXT: uxth r[[OLDX:[0-9]+]], r[[OLD]]
1063 ; CHECK-NEXT: cmp r[[OLDX]], r0
1061 ; CHECK-NEXT: cmp r[[OLD]], r0
10641062 ; CHECK-NEXT: bne .LBB{{[0-9]+}}_3
10651063 ; CHECK-NEXT: BB#2:
10661064 ; As above, r1 is a reasonable guess.
3333 ; CHECK-LABEL: test_load_i8:
3434 ; CHECK: ldaexb r0, [r0]
3535 ; CHECK-NOT: uxtb
36 define i32 @test_load_i8(i8* %addr) {
36 ; CHECK-NOT: and
37 define zeroext i8 @test_load_i8(i8* %addr) {
3738 %val = call i32 @llvm.arm.ldaex.p0i8(i8* %addr)
38 ret i32 %val
39 %val8 = trunc i32 %val to i8
40 ret i8 %val8
3941 }
4042
4143 ; CHECK-LABEL: test_load_i16:
4244 ; CHECK: ldaexh r0, [r0]
4345 ; CHECK-NOT: uxth
44 define i32 @test_load_i16(i16* %addr) {
46 ; CHECK-NOT: and
47 define zeroext i16 @test_load_i16(i16* %addr) {
4548 %val = call i32 @llvm.arm.ldaex.p0i16(i16* %addr)
46 ret i32 %val
49 %val16 = trunc i32 %val to i16
50 ret i16 %val16
4751 }
4852
4953 ; CHECK-LABEL: test_load_i32:
3535 ; CHECK-LABEL: test_load_i8:
3636 ; CHECK: ldrexb r0, [r0]
3737 ; CHECK-NOT: uxtb
38 define i32 @test_load_i8(i8* %addr) {
38 ; CHECK-NOT: and
39 define zeroext i8 @test_load_i8(i8* %addr) {
3940 %val = call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
40 ret i32 %val
41 %val8 = trunc i32 %val to i8
42 ret i8 %val8
4143 }
4244
4345 ; CHECK-LABEL: test_load_i16:
4446 ; CHECK: ldrexh r0, [r0]
4547 ; CHECK-NOT: uxth
46 define i32 @test_load_i16(i16* %addr) {
48 ; CHECK-NOT: and
49 define zeroext i16 @test_load_i16(i16* %addr) {
4750 %val = call i32 @llvm.arm.ldrex.p0i16(i16* %addr)
48 ret i32 %val
51 %val16 = trunc i32 %val to i16
52 ret i16 %val16
4953 }
5054
5155 ; CHECK-LABEL: test_load_i32:
136140
137141 ret void
138142 }
143
144 ; LLVM should know, even across basic blocks, that ldrex is setting the high
145 ; bits of its i32 to 0. There should be no zero-extend operation.
146 define zeroext i8 @test_cross_block_zext_i8(i1 %tst, i8* %addr) {
147 ; CHECK: test_cross_block_zext_i8:
148 ; CHECK-NOT: uxtb
149 ; CHECK-NOT: and
150 ; CHECK: bx lr
151 %val = call i32 @llvm.arm.ldrex.p0i8(i8* %addr)
152 br i1 %tst, label %end, label %mid
153 mid:
154 ret i8 42
155 end:
156 %val8 = trunc i32 %val to i8
157 ret i8 %val8
158 }