Skip to content

Commit d3fab7f

Browse files
authored
Merge pull request swiftlang#12019 from swiftix/layout-constraints-improvements
Layout constraints improvements
2 parents 2bf49b0 + ac73a65 commit d3fab7f

File tree

10 files changed

+149
-11
lines changed

10 files changed

+149
-11
lines changed

include/swift/AST/LayoutConstraint.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,27 @@ class LayoutConstraintInfo : public llvm::FoldingSetNode {
150150
return SizeInBits;
151151
}
152152

153-
unsigned getAlignment() const {
154-
assert(isKnownSizeTrivial());
153+
unsigned getAlignmentInBits() const {
155154
return Alignment;
156155
}
157156

157+
unsigned getAlignmentInBytes() const {
158+
assert(isKnownSizeTrivial());
159+
if (Alignment)
160+
return Alignment;
161+
162+
// There is no explicitly defined alignment. Try to come up with a
163+
// reasonable one.
164+
165+
// If the size is a power of 2, use it also for the default alignment.
166+
auto SizeInBytes = getTrivialSizeInBytes();
167+
if (llvm::isPowerOf2_32(SizeInBytes))
168+
return SizeInBytes * 8;
169+
170+
// Otherwise assume the alignment of 8 bytes.
171+
return 8*8;
172+
}
173+
158174
operator bool() const {
159175
return isKnownLayout();
160176
}

lib/AST/ASTMangler.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,18 +2042,18 @@ void ASTMangler::appendOpParamForLayoutConstraint(LayoutConstraint layout) {
20422042
appendOperatorParam("T");
20432043
break;
20442044
case LayoutConstraintKind::TrivialOfExactSize:
2045-
if (!layout->getAlignment())
2045+
if (!layout->getAlignmentInBits())
20462046
appendOperatorParam("e", Index(layout->getTrivialSizeInBits()));
20472047
else
20482048
appendOperatorParam("E", Index(layout->getTrivialSizeInBits()),
2049-
Index(layout->getAlignment()));
2049+
Index(layout->getAlignmentInBits()));
20502050
break;
20512051
case LayoutConstraintKind::TrivialOfAtMostSize:
2052-
if (!layout->getAlignment())
2052+
if (!layout->getAlignmentInBits())
20532053
appendOperatorParam("m", Index(layout->getTrivialSizeInBits()));
20542054
else
20552055
appendOperatorParam("M", Index(layout->getTrivialSizeInBits()),
2056-
Index(layout->getAlignment()));
2056+
Index(layout->getAlignmentInBits()));
20572057
break;
20582058
}
20592059
}

lib/AST/ASTPrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3921,7 +3921,7 @@ void LayoutConstraintInfo::print(ASTPrinter &Printer,
39213921
Printer << "(";
39223922
Printer << SizeInBits;
39233923
if (Alignment)
3924-
Printer << ", " << Alignment <<")";
3924+
Printer << ", " << Alignment;
39253925
Printer << ")";
39263926
break;
39273927
}

lib/AST/LayoutConstraint.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,12 +250,13 @@ mergeKnownSizeTrivialConstraints(LayoutConstraint LHS, LayoutConstraint RHS) {
250250
// Check alignments
251251

252252
// Quick exit if at_most_size_layout does not care about the alignment.
253-
if (!RHS->getAlignment())
253+
if (!RHS->getAlignmentInBits())
254254
return LHS;
255255

256256
// Check if fixed_size_layout.alignment is a multiple of
257257
// at_most_size_layout.alignment.
258-
if (LHS->getAlignment() && LHS->getAlignment() % RHS->getAlignment() == 0)
258+
if (LHS->getAlignmentInBits() &&
259+
LHS->getAlignmentInBits() % RHS->getAlignmentInBits() == 0)
259260
return LHS;
260261

261262
return LayoutConstraint::getUnknownLayout();

lib/AST/Type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,6 +4033,17 @@ TypeTraitResult TypeBase::canBeClass() {
40334033

40344034
CanType self = getCanonicalType();
40354035

4036+
// Archetypes with a trivial layout constraint can never
4037+
// represent a class.
4038+
if (auto Archetype = dyn_cast<ArchetypeType>(self)) {
4039+
if (auto Layout = Archetype->getLayoutConstraint()) {
4040+
if (Layout->isTrivial())
4041+
return TypeTraitResult::IsNot;
4042+
if (Layout->isClass())
4043+
return TypeTraitResult::Is;
4044+
}
4045+
}
4046+
40364047
// Dependent types might be bound to classes.
40374048
if (isa<SubstitutableType>(self))
40384049
return TypeTraitResult::CanBe;

lib/IRGen/GenArchetype.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,9 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
318318
// representation.
319319
if (layout && layout->isFixedSizeTrivial()) {
320320
Size size(layout->getTrivialSizeInBytes());
321-
Alignment align(layout->getTrivialSizeInBytes());
321+
auto layoutAlignment = layout->getAlignmentInBytes();
322+
assert(layoutAlignment && "layout constraint alignment should not be 0");
323+
Alignment align(layoutAlignment);
322324
auto spareBits =
323325
SpareBitVector::getConstant(size.getValueInBits(), false);
324326
// Get an integer type of the required size.

lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,37 @@ static bool shouldSkipApplyDuringEarlyInlining(FullApplySite AI) {
621621
return false;
622622
}
623623

624+
/// Checks if a generic callee and caller have compatible layout constraints.
625+
static bool isCallerAndCalleeLayoutConstraintsCompatible(FullApplySite AI) {
626+
SILFunction *Callee = AI.getReferencedFunction();
627+
auto CalleeSig = Callee->getLoweredFunctionType()->getGenericSignature();
628+
auto SubstParams = CalleeSig->getSubstitutableParams();
629+
auto AISubs = AI.getSubstitutions();
630+
for (auto idx : indices(SubstParams)) {
631+
auto Param = SubstParams[idx];
632+
// Map the parameter into context
633+
auto ContextTy = Callee->mapTypeIntoContext(Param->getCanonicalType());
634+
auto Archetype = ContextTy->getAs<ArchetypeType>();
635+
if (!Archetype)
636+
continue;
637+
auto Layout = Archetype->getLayoutConstraint();
638+
if (!Layout)
639+
continue;
640+
// The generic parameter has a layout constraint.
641+
// Check that the substitution has the same constraint.
642+
auto AIReplacement = AISubs[idx].getReplacement();
643+
auto AIArchetype = AIReplacement->getAs<ArchetypeType>();
644+
if (!AIArchetype)
645+
return false;
646+
auto AILayout = AIArchetype->getLayoutConstraint();
647+
if (!AILayout)
648+
return false;
649+
if (AILayout != Layout)
650+
return false;
651+
}
652+
return true;
653+
}
654+
624655
// Returns the callee of an apply_inst if it is basically inlineable.
625656
SILFunction *swift::getEligibleFunction(FullApplySite AI,
626657
InlineSelection WhatToInline) {
@@ -725,6 +756,16 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI,
725756
return nullptr;
726757
}
727758

759+
// We cannot inline function with layout constraints on its generic types
760+
// if the corresponding substitution type does not have the same constraints.
761+
// The reason for this restriction is that we'd need to be able to express
762+
// in SIL something like casting a value of generic type T into a value of
763+
// generic type T: _LayoutConstraint, which is impossible currently.
764+
if (EnableSILInliningOfGenerics && AI.hasSubstitutions()) {
765+
if (!isCallerAndCalleeLayoutConstraintsCompatible(AI))
766+
return nullptr;
767+
}
768+
728769
// IRGen cannot handle partial_applies containing opened_existentials
729770
// in its substitutions list.
730771
if (calleeHasPartialApplyWithOpenedExistentials(AI)) {

lib/Serialization/Serialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1174,7 +1174,7 @@ void Serializer::writeGenericRequirements(ArrayRef<Requirement> requirements,
11741174
unsigned alignment = 0;
11751175
if (layout->isKnownSizeTrivial()) {
11761176
size = layout->getTrivialSizeInBits();
1177-
alignment = layout->getAlignment();
1177+
alignment = layout->getAlignmentInBits();
11781178
}
11791179
LayoutRequirementKind rawKind = LayoutRequirementKind::UnknownLayout;
11801180
switch (layout->getKind()) {

test/SILOptimizer/eager_specialize.sil

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -eager-specializer %s | %FileCheck %s
22
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -eager-specializer -sil-deadfuncelim %s | %FileCheck --check-prefix=CHECK-DEADFUNCELIM %s
33
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -eager-specializer %s -o %t.sil && %target-swift-frontend -assume-parsing-unqualified-ownership-sil -module-name=eager_specialize -emit-ir %t.sil | %FileCheck --check-prefix=CHECK-IRGEN %s
4+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -eager-specializer -sil-inline-generics=true -inline %s | %FileCheck --check-prefix=CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE %s
45

56
sil_stage canonical
67

@@ -828,6 +829,27 @@ bb2(%10 : $Error): // Preds: bb0
828829
throw %10 : $Error
829830
} // end sil function '_T034eager_specialize_throwing_function19ClassUsingThrowingPC1gs5Int64VxKAA0G1PRzlFZ'
830831

832+
// Check that a specialization was produced and it is not inlined.
833+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE-LABEL: sil{{.*}}@{{.*}}testSimpleGeneric{{.*}}where τ_0_0 : _Trivial(64, 64)
834+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE-LABEL: sil{{.*}}@testSimpleGeneric :
835+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[METATYPE:%.*]] = metatype $@thick T.Type
836+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[SIZEOF:%.*]] = builtin "sizeof"<T>([[METATYPE]] : $@thick T.Type)
837+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: [[SIZE:%.*]] = integer_literal $Builtin.Word, 8
838+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: builtin "cmp_eq_Word"([[SIZEOF]] : $Builtin.Word, [[SIZE]] : $Builtin.Word)
839+
// Invoke the specialization, but do not inline it!
840+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: function_ref @{{.*}}testSimpleGeneric{{.*}}
841+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: apply
842+
// CHECK-EAGER-SPECIALIZE-AND-GENERICS-INLINE: // end sil function 'testSimpleGeneric'
843+
844+
sil [_specialize exported: false, kind: full, where T: _Trivial(64, 64)] @testSimpleGeneric : $@convention(thin) <T>(@in T) -> Builtin.Int64 {
845+
bb0(%0 : $*T):
846+
%1 = metatype $@thick T.Type
847+
%2 = builtin "sizeof"<T>(%1 : $@thick T.Type) : $Builtin.Word
848+
%8 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
849+
destroy_addr %0 : $*T
850+
return %8 : $Builtin.Int64
851+
}
852+
831853
sil_vtable ClassUsingThrowingP {
832854
#ClassUsingThrowingP.init!allocator.1: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : _T034eager_specialize_throwing_function19ClassUsingThrowingPCACycfC // ClassUsingThrowingP.__allocating_init()
833855
#ClassUsingThrowingP.init!initializer.1: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : _T034eager_specialize_throwing_function19ClassUsingThrowingPCACycfc // ClassUsingThrowingP.init()

test/SILOptimizer/sil_combine.sil

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,51 @@ bb0(%0 : $Int):
859859
return %4 : $Int8 // id: %5
860860
}
861861

862+
// An archetype with a trivial layout constraint can never be a class.
863+
// CHECK-LABEL: sil @is_trivial_layout_constraint_class
864+
sil @is_trivial_layout_constraint_class : $@convention(thin) <T where T: _Trivial> (@in T) -> Int8 {
865+
bb0(%0 : $*T):
866+
%1 = metatype $@thick T.Type
867+
// CHECK-NOT: builtin "canBeClass"
868+
// CHECK-NOT: apply
869+
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
870+
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 0
871+
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
872+
%4 = struct $Int8 (%3 : $Builtin.Int8)
873+
// CHECK: return [[RESULT]] : $Int8
874+
return %4 : $Int8
875+
}
876+
877+
// An archetype with a _Class layout constraint is always a class.
878+
// CHECK-LABEL: sil @is_class_layout_constraint_class
879+
sil @is_class_layout_constraint_class : $@convention(thin) <T where T: _Class> (@in T) -> Int8 {
880+
bb0(%0 : $*T):
881+
%1 = metatype $@thick T.Type
882+
// CHECK-NOT: builtin "canBeClass"
883+
// CHECK-NOT: apply
884+
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
885+
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 1
886+
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
887+
%4 = struct $Int8 (%3 : $Builtin.Int8)
888+
// CHECK: return [[RESULT]] : $Int8
889+
return %4 : $Int8
890+
}
891+
892+
// An archetype with a _NativeClass layout constraint is always a class.
893+
// CHECK-LABEL: sil @is_native_class_layout_constraint_class
894+
sil @is_native_class_layout_constraint_class : $@convention(thin) <T where T: _NativeClass> (@in T) -> Int8 {
895+
bb0(%0 : $*T):
896+
%1 = metatype $@thick T.Type
897+
// CHECK-NOT: builtin "canBeClass"
898+
// CHECK-NOT: apply
899+
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
900+
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 1
901+
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
902+
%4 = struct $Int8 (%3 : $Builtin.Int8)
903+
// CHECK: return [[RESULT]] : $Int8
904+
return %4 : $Int8
905+
}
906+
862907
@objc class MyClass {
863908
}
864909

0 commit comments

Comments
 (0)