Skip to content

Commit 56c7547

Browse files
committed
Treat types obviously word-sized in SIL as simple nonescaping partial_apply contexts
1 parent a416f3d commit 56c7547

File tree

4 files changed

+110
-8
lines changed

4 files changed

+110
-8
lines changed

include/swift/SIL/SILType.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ class SILType {
427427

428428
/// True if the given type has at least the size and alignment of a native
429429
/// pointer.
430-
bool isPointerSizeAndAligned();
430+
bool isPointerSizeAndAligned(SILModule &M,
431+
ResilienceExpansion expansion) const;
431432

432433
/// True if `operTy` can be cast by single-reference value into `resultTy`.
433434
static bool canRefCast(SILType operTy, SILType resultTy, SILModule &M);
@@ -613,6 +614,12 @@ class SILType {
613614
llvm::hash_code getHashCode() const {
614615
return llvm::hash_combine(*this);
615616
}
617+
618+
/// If a type is visibly a singleton aggregate (a tuple with one element, a
619+
/// struct with one field, or an enum with a single payload case), return the
620+
/// type of its field, which it is guaranteed to have identical layout to.
621+
SILType getSingletonAggregateFieldType(SILModule &M,
622+
ResilienceExpansion expansion) const;
616623

617624
//
618625
// Accessors for types used in SIL instructions:

lib/IRGen/GenType.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ class LoweringModeScope {
305305
/// If a type is visibly a singleton aggregate (a tuple with one element, a
306306
/// struct with one field, or an enum with a single payload case), return the
307307
/// type of its field, which it is guaranteed to have identical layout to.
308+
///
309+
/// This can use more concrete type layout information than
310+
/// SILType::getSingletonAggregateFieldType, because we have full access to the
311+
/// LLVM-level layout of types in IRGen.
308312
SILType getSingletonAggregateFieldType(IRGenModule &IGM,
309313
SILType t,
310314
ResilienceExpansion expansion);

lib/SIL/IR/SILType.cpp

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ std::string SILType::getAsString() const {
174174
return OS.str();
175175
}
176176

177-
bool SILType::isPointerSizeAndAligned() {
177+
bool SILType::isPointerSizeAndAligned(SILModule &M,
178+
ResilienceExpansion expansion) const {
178179
auto &C = getASTContext();
179180
if (isHeapObjectReferenceType()
180181
|| getASTType()->isEqual(C.TheRawPointerType)) {
@@ -183,6 +184,10 @@ bool SILType::isPointerSizeAndAligned() {
183184
if (auto intTy = dyn_cast<BuiltinIntegerType>(getASTType()))
184185
return intTy->getWidth().isPointerWidth();
185186

187+
if (auto underlyingField = getSingletonAggregateFieldType(M, expansion)) {
188+
return underlyingField.isPointerSizeAndAligned(M, expansion);
189+
}
190+
186191
return false;
187192
}
188193

@@ -766,3 +771,79 @@ SILType SILType::getSILBoxFieldType(const SILFunction *f, unsigned field) {
766771
return ::getSILBoxFieldType(f->getTypeExpansionContext(), boxTy,
767772
f->getModule().Types, field);
768773
}
774+
775+
SILType
776+
SILType::getSingletonAggregateFieldType(SILModule &M,
777+
ResilienceExpansion expansion) const {
778+
if (auto tuple = getAs<TupleType>()) {
779+
if (tuple->getNumElements() == 1) {
780+
return getTupleElementType(0);
781+
}
782+
}
783+
784+
if (auto structDecl = getStructOrBoundGenericStruct()) {
785+
// If the struct has to be accessed resiliently from this resilience domain,
786+
// we can't assume anything about its layout.
787+
if (structDecl->isResilient(M.getSwiftModule(), expansion)) {
788+
return SILType();
789+
}
790+
791+
// C ABI wackiness may cause a single-field struct to have different layout
792+
// from its field.
793+
if (structDecl->hasUnreferenceableStorage()
794+
|| structDecl->hasClangNode()) {
795+
return SILType();
796+
}
797+
798+
// A single-field struct with custom alignment has different layout from its
799+
// field.
800+
if (structDecl->getAttrs().hasAttribute<AlignmentAttr>()) {
801+
return SILType();
802+
}
803+
804+
// If there's only one stored property, we have the layout of its field.
805+
auto allFields = structDecl->getStoredProperties();
806+
807+
if (allFields.size() == 1) {
808+
auto fieldTy = getFieldType(
809+
allFields[0], M,
810+
TypeExpansionContext(expansion, M.getSwiftModule(),
811+
M.isWholeModule()));
812+
if (!M.isTypeABIAccessible(fieldTy,
813+
TypeExpansionContext::maximalResilienceExpansionOnly())){
814+
return SILType();
815+
}
816+
return fieldTy;
817+
}
818+
819+
return SILType();
820+
}
821+
822+
if (auto enumDecl = getEnumOrBoundGenericEnum()) {
823+
// If the enum has to be accessed resiliently from this resilience domain,
824+
// we can't assume anything about its layout.
825+
if (enumDecl->isResilient(M.getSwiftModule(), expansion)) {
826+
return SILType();
827+
}
828+
829+
auto allCases = enumDecl->getAllElements();
830+
831+
auto theCase = allCases.begin();
832+
if (!allCases.empty() && std::next(theCase) == allCases.end()
833+
&& (*theCase)->hasAssociatedValues()) {
834+
auto enumEltTy = getEnumElementType(
835+
*theCase, M,
836+
TypeExpansionContext(expansion, M.getSwiftModule(),
837+
M.isWholeModule()));
838+
if (!M.isTypeABIAccessible(enumEltTy,
839+
TypeExpansionContext::maximalResilienceExpansionOnly())){
840+
return SILType();
841+
}
842+
return enumEltTy;
843+
}
844+
845+
return SILType();
846+
}
847+
848+
return SILType();
849+
}

lib/SILOptimizer/Transforms/PartialApplySimplification.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,9 @@ class PartialApplySimplificationPass : public SILModuleTransform {
136136
/// sized strictly less than one word
137137
/// - the argument ownership convention matches the callee convention of the
138138
/// resulting function
139-
static bool isSimplePartialApply(CanSILFunctionType calleeTy,
139+
static bool isSimplePartialApply(SILModule &M,
140+
CanSILFunctionType calleeTy,
141+
TypeExpansionContext context,
140142
unsigned numPartiallyAppliedArgs,
141143
bool isOnStack) {
142144
if (calleeTy->isPolymorphic()) {
@@ -165,9 +167,13 @@ static bool isSimplePartialApply(CanSILFunctionType calleeTy,
165167
return true;
166168

167169
case ParameterConvention::Direct_Guaranteed:
168-
case ParameterConvention::Direct_Unowned:
169-
// TODO: Handle word-sized direct arguments.
170-
return false;
170+
case ParameterConvention::Direct_Unowned: {
171+
auto argTy = contextParam.getArgumentType(M, calleeTy, context);
172+
return SILType::getPrimitiveObjectType(argTy)
173+
.isPointerSizeAndAligned(M, context.getResilienceExpansion());
174+
// TODO: If we're running as an IRGen pass, use IRGen's version of
175+
// `isPointerSizeAndAligned` as a more accurate check.
176+
}
171177

172178
// +1 arguments need a thunk to stage a copy for the callee to consume.
173179
case ParameterConvention::Direct_Owned:
@@ -191,7 +197,9 @@ static bool isSimplePartialApply(CanSILFunctionType calleeTy,
191197
}
192198

193199
static bool isSimplePartialApply(PartialApplyInst *i) {
194-
return isSimplePartialApply(i->getCallee()->getType().castTo<SILFunctionType>(),
200+
return isSimplePartialApply(i->getModule(),
201+
i->getCallee()->getType().castTo<SILFunctionType>(),
202+
i->getFunction()->getTypeExpansionContext(),
195203
i->getNumArguments(),
196204
i->isOnStack());
197205
}
@@ -312,7 +320,9 @@ void PartialApplySimplificationPass::processKnownCallee(SILFunction *callee,
312320
// Would the partial application become simple with a mere convention change?
313321
auto calleeTyAsMethod = callee->getLoweredFunctionType()
314322
->getWithRepresentation(SILFunctionTypeRepresentation::Method);
315-
if (isSimplePartialApply(calleeTyAsMethod,
323+
if (isSimplePartialApply(callee->getModule(),
324+
calleeTyAsMethod,
325+
examplePA->getFunction()->getTypeExpansionContext(),
316326
examplePA->getNumArguments(),
317327
examplePA->isOnStack())) {
318328
return rewriteKnownCalleeConventionOnly(callee, pa, examplePA,

0 commit comments

Comments
 (0)