Skip to content

Commit ed80c86

Browse files
committed
[PatternMatch] Add m_APInt/m_APFloat matchers accepting undef
The current m_APInt() and m_APFloat() matchers do not accept splats that include undefs (unlike m_Zero() and other matchers for specific values). We can't simply change the default behavior, as there are existing transforms that would not be safe with undefs. For this reason, I'm introducing new m_APIntAllowUndef() and m_APFloatAllowUndef() matchers, that allow splats with undefs. Additionally, m_APIntForbidUndef() and m_APFloatForbidUndef() are added. These have the same behavior as the existing m_APInt() and m_APFloat(), but serve as an explicit indication that undefs were considered and found unsound for this transform. This helps distinguish them from existing uses of m_APInt() where we do not know whether undefs can or cannot be allowed without additional review. Differential Revision: https://reviews.llvm.org/D72975
1 parent 90f58ea commit ed80c86

File tree

2 files changed

+114
-6
lines changed

2 files changed

+114
-6
lines changed

llvm/include/llvm/IR/PatternMatch.h

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,10 @@ inline match_combine_and<LTy, RTy> m_CombineAnd(const LTy &L, const RTy &R) {
153153

154154
struct apint_match {
155155
const APInt *&Res;
156+
bool AllowUndef;
156157

157-
apint_match(const APInt *&R) : Res(R) {}
158+
apint_match(const APInt *&Res, bool AllowUndef)
159+
: Res(Res), AllowUndef(AllowUndef) {}
158160

159161
template <typename ITy> bool match(ITy *V) {
160162
if (auto *CI = dyn_cast<ConstantInt>(V)) {
@@ -163,7 +165,8 @@ struct apint_match {
163165
}
164166
if (V->getType()->isVectorTy())
165167
if (const auto *C = dyn_cast<Constant>(V))
166-
if (auto *CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue())) {
168+
if (auto *CI = dyn_cast_or_null<ConstantInt>(
169+
C->getSplatValue(AllowUndef))) {
167170
Res = &CI->getValue();
168171
return true;
169172
}
@@ -175,15 +178,20 @@ struct apint_match {
175178
// function for both apint/apfloat.
176179
struct apfloat_match {
177180
const APFloat *&Res;
178-
apfloat_match(const APFloat *&R) : Res(R) {}
181+
bool AllowUndef;
182+
183+
apfloat_match(const APFloat *&Res, bool AllowUndef)
184+
: Res(Res), AllowUndef(AllowUndef) {}
185+
179186
template <typename ITy> bool match(ITy *V) {
180187
if (auto *CI = dyn_cast<ConstantFP>(V)) {
181188
Res = &CI->getValueAPF();
182189
return true;
183190
}
184191
if (V->getType()->isVectorTy())
185192
if (const auto *C = dyn_cast<Constant>(V))
186-
if (auto *CI = dyn_cast_or_null<ConstantFP>(C->getSplatValue())) {
193+
if (auto *CI = dyn_cast_or_null<ConstantFP>(
194+
C->getSplatValue(AllowUndef))) {
187195
Res = &CI->getValueAPF();
188196
return true;
189197
}
@@ -193,11 +201,37 @@ struct apfloat_match {
193201

194202
/// Match a ConstantInt or splatted ConstantVector, binding the
195203
/// specified pointer to the contained APInt.
196-
inline apint_match m_APInt(const APInt *&Res) { return Res; }
204+
inline apint_match m_APInt(const APInt *&Res) {
205+
// Forbid undefs by default to maintain previous behavior.
206+
return apint_match(Res, /* AllowUndef */ false);
207+
}
208+
209+
/// Match APInt while allowing undefs in splat vector constants.
210+
inline apint_match m_APIntAllowUndef(const APInt *&Res) {
211+
return apint_match(Res, /* AllowUndef */ true);
212+
}
213+
214+
/// Match APInt while forbidding undefs in splat vector constants.
215+
inline apint_match m_APIntForbidUndef(const APInt *&Res) {
216+
return apint_match(Res, /* AllowUndef */ false);
217+
}
197218

198219
/// Match a ConstantFP or splatted ConstantVector, binding the
199220
/// specified pointer to the contained APFloat.
200-
inline apfloat_match m_APFloat(const APFloat *&Res) { return Res; }
221+
inline apfloat_match m_APFloat(const APFloat *&Res) {
222+
// Forbid undefs by default to maintain previous behavior.
223+
return apfloat_match(Res, /* AllowUndef */ false);
224+
}
225+
226+
/// Match APFloat while allowing undefs in splat vector constants.
227+
inline apfloat_match m_APFloatAllowUndef(const APFloat *&Res) {
228+
return apfloat_match(Res, /* AllowUndef */ true);
229+
}
230+
231+
/// Match APFloat while forbidding undefs in splat vector constants.
232+
inline apfloat_match m_APFloatForbidUndef(const APFloat *&Res) {
233+
return apfloat_match(Res, /* AllowUndef */ false);
234+
}
201235

202236
template <int64_t Val> struct constantint_match {
203237
template <typename ITy> bool match(ITy *V) {

llvm/unittests/IR/PatternMatch.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,43 @@ TEST_F(PatternMatchTest, VectorUndefInt) {
10451045
EXPECT_TRUE(match(ScalarZero, m_Zero()));
10461046
EXPECT_TRUE(match(VectorZero, m_Zero()));
10471047
EXPECT_TRUE(match(VectorZeroUndef, m_Zero()));
1048+
1049+
const APInt *C;
1050+
// Regardless of whether undefs are allowed,
1051+
// a fully undef constant does not match.
1052+
EXPECT_FALSE(match(ScalarUndef, m_APInt(C)));
1053+
EXPECT_FALSE(match(ScalarUndef, m_APIntForbidUndef(C)));
1054+
EXPECT_FALSE(match(ScalarUndef, m_APIntAllowUndef(C)));
1055+
EXPECT_FALSE(match(VectorUndef, m_APInt(C)));
1056+
EXPECT_FALSE(match(VectorUndef, m_APIntForbidUndef(C)));
1057+
EXPECT_FALSE(match(VectorUndef, m_APIntAllowUndef(C)));
1058+
1059+
// We can always match simple constants and simple splats.
1060+
C = nullptr;
1061+
EXPECT_TRUE(match(ScalarZero, m_APInt(C)));
1062+
EXPECT_TRUE(C->isNullValue());
1063+
C = nullptr;
1064+
EXPECT_TRUE(match(ScalarZero, m_APIntForbidUndef(C)));
1065+
EXPECT_TRUE(C->isNullValue());
1066+
C = nullptr;
1067+
EXPECT_TRUE(match(ScalarZero, m_APIntAllowUndef(C)));
1068+
EXPECT_TRUE(C->isNullValue());
1069+
C = nullptr;
1070+
EXPECT_TRUE(match(VectorZero, m_APInt(C)));
1071+
EXPECT_TRUE(C->isNullValue());
1072+
C = nullptr;
1073+
EXPECT_TRUE(match(VectorZero, m_APIntForbidUndef(C)));
1074+
EXPECT_TRUE(C->isNullValue());
1075+
C = nullptr;
1076+
EXPECT_TRUE(match(VectorZero, m_APIntAllowUndef(C)));
1077+
EXPECT_TRUE(C->isNullValue());
1078+
1079+
// Whether splats with undef can be matched depends on the matcher.
1080+
EXPECT_FALSE(match(VectorZeroUndef, m_APInt(C)));
1081+
EXPECT_FALSE(match(VectorZeroUndef, m_APIntForbidUndef(C)));
1082+
C = nullptr;
1083+
EXPECT_TRUE(match(VectorZeroUndef, m_APIntAllowUndef(C)));
1084+
EXPECT_TRUE(C->isNullValue());
10481085
}
10491086

10501087
TEST_F(PatternMatchTest, VectorUndefFloat) {
@@ -1073,6 +1110,43 @@ TEST_F(PatternMatchTest, VectorUndefFloat) {
10731110
EXPECT_TRUE(match(ScalarZero, m_AnyZeroFP()));
10741111
EXPECT_TRUE(match(VectorZero, m_AnyZeroFP()));
10751112
EXPECT_TRUE(match(VectorZeroUndef, m_AnyZeroFP()));
1113+
1114+
const APFloat *C;
1115+
// Regardless of whether undefs are allowed,
1116+
// a fully undef constant does not match.
1117+
EXPECT_FALSE(match(ScalarUndef, m_APFloat(C)));
1118+
EXPECT_FALSE(match(ScalarUndef, m_APFloatForbidUndef(C)));
1119+
EXPECT_FALSE(match(ScalarUndef, m_APFloatAllowUndef(C)));
1120+
EXPECT_FALSE(match(VectorUndef, m_APFloat(C)));
1121+
EXPECT_FALSE(match(VectorUndef, m_APFloatForbidUndef(C)));
1122+
EXPECT_FALSE(match(VectorUndef, m_APFloatAllowUndef(C)));
1123+
1124+
// We can always match simple constants and simple splats.
1125+
C = nullptr;
1126+
EXPECT_TRUE(match(ScalarZero, m_APFloat(C)));
1127+
EXPECT_TRUE(C->isZero());
1128+
C = nullptr;
1129+
EXPECT_TRUE(match(ScalarZero, m_APFloatForbidUndef(C)));
1130+
EXPECT_TRUE(C->isZero());
1131+
C = nullptr;
1132+
EXPECT_TRUE(match(ScalarZero, m_APFloatAllowUndef(C)));
1133+
EXPECT_TRUE(C->isZero());
1134+
C = nullptr;
1135+
EXPECT_TRUE(match(VectorZero, m_APFloat(C)));
1136+
EXPECT_TRUE(C->isZero());
1137+
C = nullptr;
1138+
EXPECT_TRUE(match(VectorZero, m_APFloatForbidUndef(C)));
1139+
EXPECT_TRUE(C->isZero());
1140+
C = nullptr;
1141+
EXPECT_TRUE(match(VectorZero, m_APFloatAllowUndef(C)));
1142+
EXPECT_TRUE(C->isZero());
1143+
1144+
// Whether splats with undef can be matched depends on the matcher.
1145+
EXPECT_FALSE(match(VectorZeroUndef, m_APFloat(C)));
1146+
EXPECT_FALSE(match(VectorZeroUndef, m_APFloatForbidUndef(C)));
1147+
C = nullptr;
1148+
EXPECT_TRUE(match(VectorZeroUndef, m_APFloatAllowUndef(C)));
1149+
EXPECT_TRUE(C->isZero());
10761150
}
10771151

10781152
TEST_F(PatternMatchTest, FloatingPointFNeg) {

0 commit comments

Comments
 (0)