Skip to content

Commit 865fee8

Browse files
author
Joe Shajrawi
authored
Merge pull request #5714 from shajrawi/ins_combine
[SILOptimizer] Add support for new patterns in SILCombiner
2 parents 455be3a + 675820d commit 865fee8

File tree

4 files changed

+147
-12
lines changed

4 files changed

+147
-12
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -367,18 +367,21 @@ class SILBuilder {
367367
auto &C = getASTContext();
368368

369369
llvm::SmallString<16> NameStr = Name;
370-
if (auto BuiltinIntTy =
371-
dyn_cast<BuiltinIntegerType>(OpdTy.getSwiftRValueType())) {
372-
if (BuiltinIntTy == BuiltinIntegerType::getWordType(getASTContext())) {
373-
NameStr += "_Word";
374-
} else {
375-
unsigned NumBits = BuiltinIntTy->getWidth().getFixedWidth();
376-
NameStr += "_Int" + llvm::utostr(NumBits);
377-
}
378-
} else {
379-
assert(OpdTy.getSwiftRValueType() == C.TheRawPointerType);
380-
NameStr += "_RawPointer";
381-
}
370+
appendOperandTypeName(OpdTy, NameStr);
371+
auto Ident = C.getIdentifier(NameStr);
372+
return insert(BuiltinInst::create(getSILDebugLocation(Loc), Ident, ResultTy,
373+
{}, Args, F));
374+
}
375+
376+
// Create a binary function with the signature: OpdTy1, OpdTy2 -> ResultTy.
377+
BuiltinInst *createBuiltinBinaryFunctionWithTwoOpTypes(
378+
SILLocation Loc, StringRef Name, SILType OpdTy1, SILType OpdTy2,
379+
SILType ResultTy, ArrayRef<SILValue> Args) {
380+
auto &C = getASTContext();
381+
382+
llvm::SmallString<16> NameStr = Name;
383+
appendOperandTypeName(OpdTy1, NameStr);
384+
appendOperandTypeName(OpdTy2, NameStr);
382385
auto Ident = C.getIdentifier(NameStr);
383386
return insert(BuiltinInst::create(getSILDebugLocation(Loc), Ident,
384387
ResultTy, {}, Args, F));
@@ -1635,6 +1638,22 @@ class SILBuilder {
16351638

16361639
BB->insert(InsertPt, TheInst);
16371640
}
1641+
1642+
void appendOperandTypeName(SILType OpdTy, llvm::SmallString<16> &Name) {
1643+
auto &C = getASTContext();
1644+
if (auto BuiltinIntTy =
1645+
dyn_cast<BuiltinIntegerType>(OpdTy.getSwiftRValueType())) {
1646+
if (BuiltinIntTy == BuiltinIntegerType::getWordType(getASTContext())) {
1647+
Name += "_Word";
1648+
} else {
1649+
unsigned NumBits = BuiltinIntTy->getWidth().getFixedWidth();
1650+
Name += "_Int" + llvm::utostr(NumBits);
1651+
}
1652+
} else {
1653+
assert(OpdTy.getSwiftRValueType() == C.TheRawPointerType);
1654+
Name += "_RawPointer";
1655+
}
1656+
}
16381657
};
16391658

16401659
/// An wrapper on top of SILBuilder's constructor that automatically sets the

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ class SILCombiner :
231231
/// Instruction visitor helpers.
232232
SILInstruction *optimizeBuiltinCanBeObjCClass(BuiltinInst *AI);
233233

234+
// Optimize the "trunc_N1_M2" builtin. if N1 is a result of "zext_M1_*" and
235+
// the following holds true: N1 > M1 and M2>= M1
236+
SILInstruction *optimizeBuiltinTruncOrBitCast(BuiltinInst *I);
237+
238+
// Optimize the "zext_M2_M3" builtin. if M2 is a result of "zext_M1_M2"
239+
SILInstruction *optimizeBuiltinZextOrBitCast(BuiltinInst *I);
240+
234241
// Optimize the "cmp_eq_XXX" builtin. If \p NegateResult is true then negate
235242
// the result bit.
236243
SILInstruction *optimizeBuiltinCompareEq(BuiltinInst *AI, bool NegateResult);

lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,69 @@ SILInstruction *SILCombiner::optimizeBuiltinCanBeObjCClass(BuiltinInst *BI) {
8989
}
9090
}
9191

92+
static unsigned getTypeWidth(SILType Ty) {
93+
if (auto BuiltinIntTy =
94+
dyn_cast<BuiltinIntegerType>(Ty.getSwiftRValueType())) {
95+
if (BuiltinIntTy->isFixedWidth()) {
96+
return BuiltinIntTy->getFixedWidth();
97+
}
98+
}
99+
return 0;
100+
}
101+
102+
SILInstruction *SILCombiner::optimizeBuiltinTruncOrBitCast(BuiltinInst *I) {
103+
assert(I->getBuiltinInfo().ID == BuiltinValueKind::TruncOrBitCast &&
104+
"BuiltinInst is not Trunc");
105+
SILValue Op = I->getArguments()[0];
106+
SILValue Source;
107+
if (match(Op, m_ZExtOrBitCast(m_SILValue(Source)))) {
108+
SILType ResultType = I->getType();
109+
SILType SourceType = Source->getType();
110+
SILType SourceTargetType = Op->getType();
111+
unsigned ResultTypeWidth = getTypeWidth(ResultType);
112+
unsigned SourceTypeWidth = getTypeWidth(SourceType);
113+
unsigned SourceTargetTypeWidth = getTypeWidth(SourceTargetType);
114+
if (ResultTypeWidth == 0 || SourceTypeWidth == 0 ||
115+
SourceTargetTypeWidth == 0) {
116+
// Not all types involved have fixed width
117+
return nullptr;
118+
}
119+
if (SourceTargetTypeWidth <= SourceTypeWidth) {
120+
return nullptr;
121+
}
122+
if (ResultTypeWidth < SourceTypeWidth) {
123+
return nullptr;
124+
}
125+
// Reach here if and only if:
126+
// SourceTargetTypeWidth > SourceTypeWidth and ResultTypeWidth >=
127+
// SourceTypeWidth
128+
auto *NI = Builder.createBuiltinBinaryFunctionWithTwoOpTypes(
129+
I->getLoc(), "zextOrBitCast", Source->getType(), ResultType, ResultType,
130+
Source);
131+
replaceInstUsesWith(*I, NI);
132+
return eraseInstFromFunction(*I);
133+
}
134+
return nullptr;
135+
}
136+
137+
SILInstruction *SILCombiner::optimizeBuiltinZextOrBitCast(BuiltinInst *I) {
138+
assert(I->getBuiltinInfo().ID == BuiltinValueKind::ZExtOrBitCast &&
139+
"BuiltinInst is not ZExt");
140+
SILValue Op = I->getArguments()[0];
141+
SILValue Source;
142+
if (match(Op, m_ZExtOrBitCast(m_SILValue(Source)))) {
143+
SILType ResultType = I->getType();
144+
// We can't extend to a size *smaller* than the source.
145+
// As such, this transformation will always maintain correctness
146+
auto *NI = Builder.createBuiltinBinaryFunctionWithTwoOpTypes(
147+
I->getLoc(), "zextOrBitCast", Source->getType(), ResultType, ResultType,
148+
Source);
149+
replaceInstUsesWith(*I, NI);
150+
return eraseInstFromFunction(*I);
151+
}
152+
return nullptr;
153+
}
154+
92155
/// Optimize builtins which receive the same value in their first and second
93156
/// operand.
94157
static SILInstruction *optimizeBuiltinWithSameOperands(SILBuilder &Builder,
@@ -360,6 +423,13 @@ SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) {
360423
I->getBuiltinInfo().ID == BuiltinValueKind::CopyArray)
361424
return optimizeBuiltinArrayOperation(I, Builder);
362425

426+
if (I->getBuiltinInfo().ID == BuiltinValueKind::TruncOrBitCast) {
427+
return optimizeBuiltinTruncOrBitCast(I);
428+
}
429+
if (I->getBuiltinInfo().ID == BuiltinValueKind::ZExtOrBitCast) {
430+
return optimizeBuiltinZextOrBitCast(I);
431+
}
432+
363433
if (I->getNumOperands() >= 2 && I->getOperand(0) == I->getOperand(1)) {
364434
// It's a builtin which has the same value in its first and second operand.
365435
auto *Replacement = optimizeBuiltinWithSameOperands(Builder, I, this);

test/SILOptimizer/sil_combine.sil

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,6 +1318,45 @@ bb0(%0 : $Builtin.RawPointer, %1: $Builtin.Int64):
13181318
return %11 : $Int32
13191319
}
13201320

1321+
// CHECK-LABEL: sil @trunc_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int32
1322+
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int64"
1323+
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int32"
1324+
// CHECK: builtin "zextOrBitCast_Int16_Int32"
1325+
// CHECK-NEXT: return
1326+
sil @trunc_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int32 {
1327+
bb0(%0 : $Builtin.Int16):
1328+
%zext = builtin "zextOrBitCast_Int16_Int64"(%0 : $Builtin.Int16) : $Builtin.Int64
1329+
%trunc = builtin "truncOrBitCast_Int64_Int32"(%zext : $Builtin.Int64) : $Builtin.Int32
1330+
return %trunc : $Builtin.Int32
1331+
}
1332+
1333+
// CHECK-LABEL: sil @zext_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int64
1334+
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int32"
1335+
// CHECK-NOT: builtin "zextOrBitCast_Int32_Int64"
1336+
// CHECK: builtin "zextOrBitCast_Int16_Int64"
1337+
// CHECK-NEXT: return
1338+
sil @zext_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int64 {
1339+
bb0(%0 : $Builtin.Int16):
1340+
%zext1 = builtin "zextOrBitCast_Int16_Int32"(%0 : $Builtin.Int16) : $Builtin.Int32
1341+
%zext2 = builtin "zextOrBitCast_Int32_Int64"(%zext1 : $Builtin.Int32) : $Builtin.Int64
1342+
return %zext2 : $Builtin.Int64
1343+
}
1344+
1345+
// CHECK-LABEL: sil @trunc_of_zext_then_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int16
1346+
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int64"
1347+
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int32"
1348+
// CHECK-NOT: builtin "zextOrBitCast_Int32_Int64"
1349+
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int16"
1350+
// CHECK: return
1351+
sil @trunc_of_zext_then_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int16 {
1352+
bb0(%0 : $Builtin.Int16):
1353+
%zext = builtin "zextOrBitCast_Int16_Int64"(%0 : $Builtin.Int16) : $Builtin.Int64
1354+
%trunc = builtin "truncOrBitCast_Int64_Int32"(%zext : $Builtin.Int64) : $Builtin.Int32
1355+
%zext2 = builtin "zextOrBitCast_Int32_Int64"(%trunc : $Builtin.Int32) : $Builtin.Int64
1356+
%trunc2 = builtin "truncOrBitCast_Int64_Int16"(%zext2 : $Builtin.Int64) : $Builtin.Int16
1357+
return %trunc2 : $Builtin.Int16
1358+
}
1359+
13211360
sil @eliminate_dead_thin_to_thick_function_fun : $@convention(thin) () -> ()
13221361

13231362
// CHECK-LABEL: sil @eliminate_dead_thin_to_thick_function : $@convention(thin) () -> () {

0 commit comments

Comments
 (0)