Skip to content

Commit a85097e

Browse files
jrtc27resistor
authored andcommitted
[CHERI-Generic] Pre-commit a new test showing missed immediate use
1 parent 569203f commit a85097e

File tree

8 files changed

+602
-3
lines changed

8 files changed

+602
-3
lines changed

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,14 @@ class SelectionDAG {
20722072
/// We use this predicate to simplify operations downstream.
20732073
LLVM_ABI bool SignBitIsZero(SDValue Op, unsigned Depth = 0) const;
20742074

2075+
/// Return true if the sign bit of Op is known to be one.
2076+
/// We use this predicate to simplify operations downstream.
2077+
bool SignBitIsOne(SDValue Op, unsigned Depth = 0) const;
2078+
2079+
/// Return true if the sign bits of N0 and N1 are known to be the same.
2080+
/// We use this predicate to simplify operations downstream.
2081+
bool SignBitIsSame(SDValue N0, SDValue N1, unsigned Depth = 0) const;
2082+
20752083
/// Return true if 'Op & Mask' is known to be zero. We
20762084
/// use this predicate to simplify operations downstream. Op and Mask are
20772085
/// known to be the same type.

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,12 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
27212721
if (isNullConstant(N1))
27222722
return N0;
27232723

2724+
auto GetPTRADD2 = [this, &DL](SDValue &Base, SDValue &Off1, SDValue &Off2) {
2725+
SDValue Base2 = DAG.getMemBasePlusOffset(Base, Off1, DL);
2726+
AddToWorklist(Base2.getNode());
2727+
return DAG.getMemBasePlusOffset(Base2, Off2, DL);
2728+
};
2729+
27242730
// fold (ptradd 0, x) -> x
27252731
if (PtrVT == IntVT && isNullConstant(N0))
27262732
return N1;
@@ -2779,7 +2785,6 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
27792785
// For now each architecture that wants this fold must implement it in the
27802786
// target-specific code (see e.g. SITargetLowering::performPtrAddCombine)
27812787

2782-
27832788
// Reassociate: (ptradd (ptradd x, y), z) -> (ptradd x, (add y, z)) if:
27842789
// * x is a null pointer; or
27852790
// * the add can be constant-folded; or
@@ -2792,6 +2797,14 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
27922797
// patterns. Once we represent that with PTRMASK that will be less of a
27932798
// concern, though we might still want to detect code not using the builtins
27942799
// and canonicalise it to a PTRMASK.
2800+
//
2801+
// Commute: (ptradd (ptradd x, y), z) -> (ptradd (ptradd x, z), y) if:
2802+
// * y and z have the same sign and y is a constant.
2803+
//
2804+
// This allows immediate addressing modes to be used. Note that we need to be
2805+
// careful to ensure we don't transiently become unrepresentable if the
2806+
// original DAG does not already do so, and this is the case if both PTRADDs
2807+
// have the same sign.
27952808
if (N0.getOpcode() == ISD::PTRADD &&
27962809
!reassociationCanBreakAddressingModePattern(ISD::PTRADD, DL, N, N0, N1)) {
27972810
SDValue X = N0.getOperand(0);
@@ -2822,6 +2835,27 @@ SDValue DAGCombiner::visitPTRADD(SDNode *N) {
28222835
(N0.hasOneUse() && Z.hasOneUse() &&
28232836
!DAG.isConstantIntBuildVectorOrConstantInt(Z)))
28242837
return DAG.getMemBasePlusOffset(X, Add, DL);
2838+
if (DAG.SignBitIsSame(Y, Z) && DAG.isConstantIntBuildVectorOrConstantInt(Y))
2839+
return GetPTRADD2(X, Z, Y);
2840+
}
2841+
2842+
// Transform: (ptradd x, (add y, z)) -> (ptradd (ptradd x, y), z) if:
2843+
// * both y and z have the same sign and z is a constant.
2844+
//
2845+
// Transform: (ptradd x, (add y, z)) -> (ptradd (ptradd x, z), y) if:
2846+
// * both y and z have the same sign and y is a constant.
2847+
//
2848+
// As above, this allows for immediate addressing modes.
2849+
if (N1.getOpcode() == ISD::ADD) {
2850+
SDValue X = N0;
2851+
SDValue Y = N1.getOperand(0);
2852+
SDValue Z = N1.getOperand(1);
2853+
if (DAG.SignBitIsSame(Y, Z)) {
2854+
if (DAG.isConstantIntBuildVectorOrConstantInt(Y))
2855+
return GetPTRADD2(X, Z, Y);
2856+
if (DAG.isConstantIntBuildVectorOrConstantInt(Z))
2857+
return GetPTRADD2(X, Y, Z);
2858+
}
28252859
}
28262860

28272861
return SDValue();

llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2964,6 +2964,20 @@ bool SelectionDAG::SignBitIsZero(SDValue Op, unsigned Depth) const {
29642964
return MaskedValueIsZero(Op, APInt::getSignMask(BitWidth), Depth);
29652965
}
29662966

2967+
/// SignBitIsOne - Return true if the sign bit of Op is known to be one. We
2968+
/// use this predicate to simplify operations downstream.
2969+
bool SelectionDAG::SignBitIsOne(SDValue Op, unsigned Depth) const {
2970+
unsigned BitWidth = Op.getScalarValueSizeInBits();
2971+
return MaskedValueIsAllOnes(Op, APInt::getSignMask(BitWidth), Depth);
2972+
}
2973+
2974+
/// SignBitIsSame - Return true if the sign bits of N0 and N1 are known to be
2975+
/// the same. We use this predicate to simplify operations downstream.
2976+
bool SelectionDAG::SignBitIsSame(SDValue N0, SDValue N1, unsigned Depth) const {
2977+
return (SignBitIsZero(N0, Depth) && SignBitIsZero(N1, Depth)) ||
2978+
(SignBitIsOne(N0, Depth) && SignBitIsOne(N1, Depth));
2979+
}
2980+
29672981
/// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use
29682982
/// this predicate to simplify operations downstream. Mask is known to be zero
29692983
/// for bits that V cannot have.

llvm/test/CodeGen/AArch64/cpa-selectiondag.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -683,11 +683,10 @@ define hidden void @multidim() {
683683
; CHECK-CPA-O3-NEXT: add x10, x10, :lo12:a
684684
; CHECK-CPA-O3-NEXT: ldrh w8, [x8, :lo12:b]
685685
; CHECK-CPA-O3-NEXT: lsl x9, x8, #1
686-
; CHECK-CPA-O3-NEXT: add x8, x8, #1
687686
; CHECK-CPA-O3-NEXT: add x9, x9, #2
688687
; CHECK-CPA-O3-NEXT: addpt x9, x10, x9
689688
; CHECK-CPA-O3-NEXT: addpt x8, x9, x8
690-
; CHECK-CPA-O3-NEXT: ldrb w8, [x8]
689+
; CHECK-CPA-O3-NEXT: ldrb w8, [x8, #1]
691690
; CHECK-CPA-O3-NEXT: cbz w8, .LBB14_2
692691
; CHECK-CPA-O3-NEXT: // %bb.1:
693692
; CHECK-CPA-O3-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
; RUN: llc @PURECAP_HARDFLOAT_ARGS@ < %s | FileCheck %s --check-prefix=PURECAP
2+
;; Hybrid baseline to compare against
3+
; RUN: sed 's/addrspace(200)//g' %s | llc @HYBRID_HARDFLOAT_ARGS@ | FileCheck %s --check-prefix=HYBRID
4+
5+
;; If both offsets are known to be non-negative it is safe to commute them and
6+
;; use an immediate load.
7+
define i32 @nneg_nneg(ptr addrspace(200) %p, i16 %x) {
8+
%x.ext = zext i16 %x to i64
9+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x.ext
10+
%ret = load i32, ptr addrspace(200) %q
11+
ret i32 %ret
12+
}
13+
14+
;; If both offsets are known to be negative it is safe to commute them and use
15+
;; an immediate load.
16+
define i32 @neg_neg(ptr addrspace(200) %p, i16 %x) {
17+
%x.ext = zext i16 %x to i64
18+
%x.pos = or i64 %x.ext, 1
19+
%x.neg = sub i64 0, %x.pos
20+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x.neg
21+
%ret = load i32, ptr addrspace(200) %q
22+
ret i32 %ret
23+
}
24+
25+
;; If one offset is known to be non-negative and the other negative it is not in
26+
;; general safe to commute them and use an immediate load.
27+
define i32 @nneg_neg(ptr addrspace(200) %p, i16 %x) {
28+
%x.ext = zext i16 %x to i64
29+
%x.pos = or i64 %x.ext, 1
30+
%x.neg = sub i64 0, %x.pos
31+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x.neg
32+
%ret = load i32, ptr addrspace(200) %q
33+
ret i32 %ret
34+
}
35+
36+
;; If one offset is known to be non-negative and the other negative it is not in
37+
;; general safe to commute them and use an immediate load.
38+
define i32 @neg_nneg(ptr addrspace(200) %p, i16 %x) {
39+
%x.ext = zext i16 %x to i64
40+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x.ext
41+
%ret = load i32, ptr addrspace(200) %q
42+
ret i32 %ret
43+
}
44+
45+
;; If we do not know the sign of one offset it is not in general safe to
46+
;; commute them and use an immediate load.
47+
define i32 @nneg_unknown(ptr addrspace(200) %p, i64 %x) {
48+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x
49+
%ret = load i32, ptr addrspace(200) %q
50+
ret i32 %ret
51+
}
52+
53+
;; If we do not know the sign of one offset it is not in general safe to
54+
;; commute them and use an immediate load.
55+
define i32 @neg_unknown(ptr addrspace(200) %p, i64 %x) {
56+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x
57+
%ret = load i32, ptr addrspace(200) %q
58+
ret i32 %ret
59+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/ptradd-immediate.ll
3+
; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap < %s | FileCheck %s --check-prefix=PURECAP
4+
;; Hybrid baseline to compare against
5+
; RUN: sed 's/addrspace(200)//g' %s | llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi n64 | FileCheck %s --check-prefix=HYBRID
6+
7+
;; If both offsets are known to be non-negative it is safe to commute them and
8+
;; use an immediate load.
9+
define i32 @nneg_nneg(ptr addrspace(200) %p, i16 %x) {
10+
; PURECAP-LABEL: nneg_nneg:
11+
; PURECAP: # %bb.0:
12+
; PURECAP-NEXT: andi $1, $4, 65535
13+
; PURECAP-NEXT: dsll $1, $1, 2
14+
; PURECAP-NEXT: clw $2, $1, 4($c3)
15+
; PURECAP-NEXT: cjr $c17
16+
; PURECAP-NEXT: nop
17+
;
18+
; HYBRID-LABEL: nneg_nneg:
19+
; HYBRID: # %bb.0:
20+
; HYBRID-NEXT: andi $1, $5, 65535
21+
; HYBRID-NEXT: dsll $1, $1, 2
22+
; HYBRID-NEXT: daddu $1, $4, $1
23+
; HYBRID-NEXT: lw $2, 4($1)
24+
; HYBRID-NEXT: jr $ra
25+
; HYBRID-NEXT: nop
26+
%x.ext = zext i16 %x to i64
27+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x.ext
28+
%ret = load i32, ptr addrspace(200) %q
29+
ret i32 %ret
30+
}
31+
32+
;; If both offsets are known to be negative it is safe to commute them and use
33+
;; an immediate load.
34+
define i32 @neg_neg(ptr addrspace(200) %p, i16 %x) {
35+
; PURECAP-LABEL: neg_neg:
36+
; PURECAP: # %bb.0:
37+
; PURECAP-NEXT: daddiu $1, $zero, -1
38+
; PURECAP-NEXT: xor $1, $4, $1
39+
; PURECAP-NEXT: daddiu $2, $zero, 1
40+
; PURECAP-NEXT: dsll $3, $2, 46
41+
; PURECAP-NEXT: daddiu $3, $3, -1
42+
; PURECAP-NEXT: dsll $3, $3, 16
43+
; PURECAP-NEXT: or $1, $1, $3
44+
; PURECAP-NEXT: dsll $2, $2, 62
45+
; PURECAP-NEXT: daddiu $2, $2, -2
46+
; PURECAP-NEXT: and $1, $1, $2
47+
; PURECAP-NEXT: dsll $1, $1, 2
48+
; PURECAP-NEXT: clw $2, $1, 0($c3)
49+
; PURECAP-NEXT: cjr $c17
50+
; PURECAP-NEXT: nop
51+
;
52+
; HYBRID-LABEL: neg_neg:
53+
; HYBRID: # %bb.0:
54+
; HYBRID-NEXT: andi $1, $5, 65534
55+
; HYBRID-NEXT: dsll $1, $1, 2
56+
; HYBRID-NEXT: ori $1, $1, 4
57+
; HYBRID-NEXT: dsubu $1, $4, $1
58+
; HYBRID-NEXT: lw $2, -4($1)
59+
; HYBRID-NEXT: jr $ra
60+
; HYBRID-NEXT: nop
61+
%x.ext = zext i16 %x to i64
62+
%x.pos = or i64 %x.ext, 1
63+
%x.neg = sub i64 0, %x.pos
64+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x.neg
65+
%ret = load i32, ptr addrspace(200) %q
66+
ret i32 %ret
67+
}
68+
69+
;; If one offset is known to be non-negative and the other negative it is not in
70+
;; general safe to commute them and use an immediate load.
71+
define i32 @nneg_neg(ptr addrspace(200) %p, i16 %x) {
72+
; PURECAP-LABEL: nneg_neg:
73+
; PURECAP: # %bb.0:
74+
; PURECAP-NEXT: andi $1, $4, 65534
75+
; PURECAP-NEXT: dsll $1, $1, 2
76+
; PURECAP-NEXT: ori $1, $1, 4
77+
; PURECAP-NEXT: daddiu $2, $zero, 4
78+
; PURECAP-NEXT: dsubu $1, $2, $1
79+
; PURECAP-NEXT: clw $2, $1, 0($c3)
80+
; PURECAP-NEXT: cjr $c17
81+
; PURECAP-NEXT: nop
82+
;
83+
; HYBRID-LABEL: nneg_neg:
84+
; HYBRID: # %bb.0:
85+
; HYBRID-NEXT: andi $1, $5, 65534
86+
; HYBRID-NEXT: dsll $1, $1, 2
87+
; HYBRID-NEXT: ori $1, $1, 4
88+
; HYBRID-NEXT: dsubu $1, $4, $1
89+
; HYBRID-NEXT: lw $2, 4($1)
90+
; HYBRID-NEXT: jr $ra
91+
; HYBRID-NEXT: nop
92+
%x.ext = zext i16 %x to i64
93+
%x.pos = or i64 %x.ext, 1
94+
%x.neg = sub i64 0, %x.pos
95+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x.neg
96+
%ret = load i32, ptr addrspace(200) %q
97+
ret i32 %ret
98+
}
99+
100+
;; If one offset is known to be non-negative and the other negative it is not in
101+
;; general safe to commute them and use an immediate load.
102+
define i32 @neg_nneg(ptr addrspace(200) %p, i16 %x) {
103+
; PURECAP-LABEL: neg_nneg:
104+
; PURECAP: # %bb.0:
105+
; PURECAP-NEXT: andi $1, $4, 65535
106+
; PURECAP-NEXT: dsll $1, $1, 2
107+
; PURECAP-NEXT: clw $2, $1, -4($c3)
108+
; PURECAP-NEXT: cjr $c17
109+
; PURECAP-NEXT: nop
110+
;
111+
; HYBRID-LABEL: neg_nneg:
112+
; HYBRID: # %bb.0:
113+
; HYBRID-NEXT: andi $1, $5, 65535
114+
; HYBRID-NEXT: dsll $1, $1, 2
115+
; HYBRID-NEXT: daddu $1, $4, $1
116+
; HYBRID-NEXT: lw $2, -4($1)
117+
; HYBRID-NEXT: jr $ra
118+
; HYBRID-NEXT: nop
119+
%x.ext = zext i16 %x to i64
120+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x.ext
121+
%ret = load i32, ptr addrspace(200) %q
122+
ret i32 %ret
123+
}
124+
125+
;; If we do not know the sign of one offset it is not in general safe to
126+
;; commute them and use an immediate load.
127+
define i32 @nneg_unknown(ptr addrspace(200) %p, i64 %x) {
128+
; PURECAP-LABEL: nneg_unknown:
129+
; PURECAP: # %bb.0:
130+
; PURECAP-NEXT: dsll $1, $4, 2
131+
; PURECAP-NEXT: clw $2, $1, 4($c3)
132+
; PURECAP-NEXT: cjr $c17
133+
; PURECAP-NEXT: nop
134+
;
135+
; HYBRID-LABEL: nneg_unknown:
136+
; HYBRID: # %bb.0:
137+
; HYBRID-NEXT: dsll $1, $5, 2
138+
; HYBRID-NEXT: daddu $1, $4, $1
139+
; HYBRID-NEXT: lw $2, 4($1)
140+
; HYBRID-NEXT: jr $ra
141+
; HYBRID-NEXT: nop
142+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 1, i64 %x
143+
%ret = load i32, ptr addrspace(200) %q
144+
ret i32 %ret
145+
}
146+
147+
;; If we do not know the sign of one offset it is not in general safe to
148+
;; commute them and use an immediate load.
149+
define i32 @neg_unknown(ptr addrspace(200) %p, i64 %x) {
150+
; PURECAP-LABEL: neg_unknown:
151+
; PURECAP: # %bb.0:
152+
; PURECAP-NEXT: dsll $1, $4, 2
153+
; PURECAP-NEXT: clw $2, $1, -4($c3)
154+
; PURECAP-NEXT: cjr $c17
155+
; PURECAP-NEXT: nop
156+
;
157+
; HYBRID-LABEL: neg_unknown:
158+
; HYBRID: # %bb.0:
159+
; HYBRID-NEXT: dsll $1, $5, 2
160+
; HYBRID-NEXT: daddu $1, $4, $1
161+
; HYBRID-NEXT: lw $2, -4($1)
162+
; HYBRID-NEXT: jr $ra
163+
; HYBRID-NEXT: nop
164+
%q = getelementptr [1 x i32], ptr addrspace(200) %p, i64 -1, i64 %x
165+
%ret = load i32, ptr addrspace(200) %q
166+
ret i32 %ret
167+
}

0 commit comments

Comments
 (0)