Skip to content

Commit 8a16a10

Browse files
committed
Add Builtin.packCount
1 parent 1ebbc22 commit 8a16a10

File tree

11 files changed

+164
-10
lines changed

11 files changed

+164
-10
lines changed

include/swift/AST/Builtins.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,11 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildDefaultActorExecutorRef,
10121012
BUILTIN_MISC_OPERATION_WITH_SILGEN(BuildMainActorExecutorRef,
10131013
"buildMainActorExecutorRef", "n", Special)
10141014

1015+
/// packCount: <each T>(_: repeat each T) -> Int
1016+
///
1017+
/// Returns the number of items in a pack.
1018+
BUILTIN_MISC_OPERATION(PackCount, "packCount", "n", Special)
1019+
10151020
#undef BUILTIN_MISC_OPERATION_WITH_SILGEN
10161021

10171022
#undef BUILTIN_MISC_OPERATION

lib/AST/Builtins.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,25 @@ static const char * const GenericParamNames[] = {
235235
};
236236

237237
static GenericTypeParamDecl*
238-
createGenericParam(ASTContext &ctx, const char *name, unsigned index) {
238+
createGenericParam(ASTContext &ctx, const char *name, unsigned index,
239+
bool isParameterPack = false) {
239240
ModuleDecl *M = ctx.TheBuiltinModule;
240241
Identifier ident = ctx.getIdentifier(name);
241242
return GenericTypeParamDecl::createImplicit(
242-
&M->getMainFile(FileUnitKind::Builtin), ident, /*depth*/ 0, index);
243+
&M->getMainFile(FileUnitKind::Builtin), ident, /*depth*/ 0, index,
244+
isParameterPack);
243245
}
244246

245247
/// Create a generic parameter list with multiple generic parameters.
246248
static GenericParamList *getGenericParams(ASTContext &ctx,
247-
unsigned numParameters) {
249+
unsigned numParameters,
250+
bool areParametersPacks = false) {
248251
assert(numParameters <= std::size(GenericParamNames));
249252

250253
SmallVector<GenericTypeParamDecl *, 2> genericParams;
251254
for (unsigned i = 0; i != numParameters; ++i)
252-
genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i));
255+
genericParams.push_back(createGenericParam(ctx, GenericParamNames[i], i,
256+
areParametersPacks));
253257

254258
auto paramList = GenericParamList::create(ctx, SourceLoc(), genericParams,
255259
SourceLoc());
@@ -678,9 +682,11 @@ namespace {
678682

679683
public:
680684
BuiltinFunctionBuilder(ASTContext &ctx, unsigned numGenericParams = 1,
681-
bool wantsAdditionalAnyObjectRequirement = false)
685+
bool wantsAdditionalAnyObjectRequirement = false,
686+
bool areParametersPacks = false)
682687
: Context(ctx) {
683-
TheGenericParamList = getGenericParams(ctx, numGenericParams);
688+
TheGenericParamList = getGenericParams(ctx, numGenericParams,
689+
areParametersPacks);
684690
if (wantsAdditionalAnyObjectRequirement) {
685691
Requirement req(RequirementKind::Conformance,
686692
TheGenericParamList->getParams()[0]->getInterfaceType(),
@@ -748,9 +754,16 @@ namespace {
748754
};
749755
struct ParameterGenerator {
750756
unsigned Index;
757+
bool isPackExpansion;
751758
Type build(BuiltinFunctionBuilder &builder) const {
752-
return builder.TheGenericParamList->getParams()[Index]
753-
->getDeclaredInterfaceType();
759+
auto ty = builder.TheGenericParamList->getParams()[Index]
760+
->getDeclaredInterfaceType();
761+
762+
if (isPackExpansion) {
763+
return PackExpansionType::get(ty, ty);
764+
}
765+
766+
return ty;
754767
}
755768
};
756769
struct LambdaGenerator {
@@ -776,8 +789,8 @@ makeConcrete(Type type) {
776789
}
777790

778791
static BuiltinFunctionBuilder::ParameterGenerator
779-
makeGenericParam(unsigned index = 0) {
780-
return { index };
792+
makeGenericParam(unsigned index = 0, bool isPackExpansion = false) {
793+
return { index, isPackExpansion };
781794
}
782795

783796
template <class... Gs>
@@ -1932,6 +1945,19 @@ static ValueDecl *getHopToActor(ASTContext &ctx, Identifier id) {
19321945
return builder.build(id);
19331946
}
19341947

1948+
static ValueDecl *getPackCount(ASTContext &ctx, Identifier id) {
1949+
BuiltinFunctionBuilder builder(ctx, /* genericParamCount */ 1,
1950+
/* anyObject */ false,
1951+
/* areParametersPack */ true);
1952+
1953+
auto packEx = makeGenericParam(/* index */ 0, /* isPackExpansion */ true);
1954+
auto paramTy = makeMetatype(makeTuple(packEx));
1955+
builder.addParameter(paramTy);
1956+
builder.setResult(makeConcrete(BuiltinIntegerType::getWordType(ctx)));
1957+
1958+
return builder.build(id);
1959+
}
1960+
19351961
/// An array of the overloaded builtin kinds.
19361962
static const OverloadedBuiltinKind OverloadedBuiltinKinds[] = {
19371963
OverloadedBuiltinKind::None,
@@ -2973,6 +2999,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
29732999

29743000
case BuiltinValueKind::AutoDiffAllocateSubcontext:
29753001
return getAutoDiffAllocateSubcontext(Context, Id);
3002+
3003+
case BuiltinValueKind::PackCount:
3004+
return getPackCount(Context, Id);
29763005
}
29773006

29783007
llvm_unreachable("bad builtin value!");

lib/IRGen/GenBuiltin.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,5 +1345,30 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
13451345
return;
13461346
}
13471347

1348+
if (Builtin.ID == BuiltinValueKind::PackCount) {
1349+
(void) args.claimAll();
1350+
1351+
auto metaTy = argTypes[0].getASTType()->castTo<MetatypeType>();
1352+
auto tupleTy = metaTy->getInstanceType()->castTo<TupleType>();
1353+
1354+
llvm::Value *count = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
1355+
1356+
// Accumulate the count of the pack.
1357+
for (auto eltTy : tupleTy->getElementTypes()) {
1358+
if (auto packExpTy = dyn_cast<PackExpansionType>(eltTy)) {
1359+
auto countTy = packExpTy->getCountType()->getCanonicalType();
1360+
auto packCount = IGF.emitPackShapeExpression(countTy);
1361+
count = IGF.Builder.CreateAdd(count, packCount);
1362+
continue;
1363+
}
1364+
1365+
count = IGF.Builder.CreateAdd(count,
1366+
llvm::ConstantInt::get(IGF.IGM.SizeTy, 1));
1367+
}
1368+
1369+
out.add(count);
1370+
return;
1371+
}
1372+
13481373
llvm_unreachable("IRGen unimplemented for this builtin!");
13491374
}

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,8 @@ BUILTIN_OPERAND_OWNERSHIP(BitwiseEscape, BuildMainActorExecutorRef)
966966

967967
BUILTIN_OPERAND_OWNERSHIP(TrivialUse, AutoDiffCreateLinearMapContext)
968968

969+
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PackCount)
970+
969971
#undef BUILTIN_OPERAND_OWNERSHIP
970972

971973
#define SHOULD_NEVER_VISIT_BUILTIN(ID) \

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroupWithFlags)
586586
CONSTANT_OWNERSHIP_BUILTIN(None, DestroyTaskGroup)
587587
CONSTANT_OWNERSHIP_BUILTIN(None, TaskRunInline)
588588
CONSTANT_OWNERSHIP_BUILTIN(None, Copy)
589+
CONSTANT_OWNERSHIP_BUILTIN(None, PackCount)
589590

590591
#undef CONSTANT_OWNERSHIP_BUILTIN
591592

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ class SILCombiner :
315315
// Optimize the "isConcrete" builtin.
316316
SILInstruction *optimizeBuiltinIsConcrete(BuiltinInst *I);
317317

318+
SILInstruction *optimizeBuiltinPackCount(BuiltinInst *BI);
319+
318320
SILInstruction *optimizeBuiltinCOWBufferForReading(BuiltinInst *BI);
319321
SILInstruction *optimizeBuiltinCOWBufferForReadingNonOSSA(BuiltinInst *BI);
320322
SILInstruction *optimizeBuiltinCOWBufferForReadingOSSA(BuiltinInst *BI);

lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,20 @@ SILInstruction *SILCombiner::optimizeStringObject(BuiltinInst *BI) {
656656
setBits & andBits);
657657
}
658658

659+
SILInstruction *SILCombiner::optimizeBuiltinPackCount(BuiltinInst *BI) {
660+
// "packCount" requires a single generic type.
661+
auto argTy = BI->getSubstitutions().getReplacementTypes()[0];
662+
663+
auto packTy = argTy->castTo<PackType>();
664+
665+
if (packTy->containsPackExpansionType()) {
666+
return nullptr;
667+
}
668+
669+
return Builder.createIntegerLiteral(BI->getLoc(), BI->getType(),
670+
packTy->getNumElements());
671+
}
672+
659673
SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) {
660674
if (I->getBuiltinInfo().ID == BuiltinValueKind::CanBeObjCClass)
661675
return optimizeBuiltinCanBeObjCClass(I, Builder);
@@ -680,6 +694,10 @@ SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) {
680694
return optimizeBuiltinZextOrBitCast(I);
681695
}
682696

697+
if (I->getBuiltinInfo().ID == BuiltinValueKind::PackCount) {
698+
return optimizeBuiltinPackCount(I);
699+
}
700+
683701
if (I->getNumOperands() >= 2 && I->getOperand(0) == I->getOperand(1)) {
684702
// It's a builtin which has the same value in its first and second operand.
685703
auto *Replacement = optimizeBuiltinWithSameOperands(Builder, I, this);

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ static bool isBarrier(SILInstruction *inst) {
156156
case BuiltinValueKind::UnprotectedStackAlloc:
157157
case BuiltinValueKind::StackDealloc:
158158
case BuiltinValueKind::AssumeAlignment:
159+
case BuiltinValueKind::PackCount:
159160
return false;
160161

161162
// Handle some rare builtins that may be sensitive to object lifetime

test/IRGen/builtin_packCount.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %target-swift-frontend -module-name builtins -enable-builtin-module -Xllvm -sil-disable-pass=target-constant-folding -disable-access-control -primary-file %s -emit-ir -o - -disable-objc-attr-requires-foundation-module -disable-availability-checking -O | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime
2+
3+
// REQUIRES: CPU=x86_64 || CPU=arm64 || CPU=arm64e
4+
5+
import Builtin
6+
7+
// CHECK: define {{.*}} @"$s8builtins9packCountyBwxxQpRvzlF"(%swift.opaque** noalias nocapture readnone %0, i64 returned [[PACK_COUNT:%.*]], %swift.type** nocapture readnone %"each T")
8+
// CHECK-NEXT: entry:
9+
// CHECK-NEXT: ret i64 [[PACK_COUNT]]
10+
func packCount<each T>(_: repeat each T) -> Builtin.Word {
11+
Builtin.packCount((repeat each T).self)
12+
}
13+
14+
// CHECK: define {{.*}} @"$s8builtins12packCountUseBwyF"()
15+
// CHECK-NEXT: entry:
16+
// CHECK-NEXT: ret i64 4
17+
func packCountUse() -> Builtin.Word {
18+
packCount(123, 321, 456, 654)
19+
}
20+
21+
// CHECK: define {{.*}} @"$s8builtins18weirdPackCountUse0yBwxxQpRvzlF"(%swift.opaque** {{.*}} %0, i64 [[PACK_COUNT:%.*]], %swift.type** {{.*}} %"each T")
22+
// CHECK-NEXT: entry:
23+
// CHECK-NEXT: [[ADD:%.*]] = add i64 [[PACK_COUNT]], 2
24+
// CHECK-NEXT: ret i64 [[ADD]]
25+
func weirdPackCountUse0<each T>(_ x: repeat each T) -> Builtin.Word {
26+
Builtin.packCount((String, repeat each T, Int).self)
27+
}
28+
29+
// CHECK: define {{.*}} @"$s8builtins18weirdPackCountUse1yBwxxQpRvzlF"(%swift.opaque** {{.*}} %0, i64 %1, %swift.type** {{.*}} %"each T")
30+
// CHECK-NEXT: entry:
31+
// CHECK-NEXT: ret i64 3
32+
func weirdPackCountUse1<each T>(_ x: repeat each T) -> Builtin.Word {
33+
Builtin.packCount((String, (repeat each T), Int).self)
34+
}
35+
36+
struct Pack<each T> {
37+
// CHECK: define {{.*}} @"$s8builtins4PackV5countBwvgZ"(i64 returned [[PACK_COUNT:%.*]], %swift.type** nocapture readnone %"each T")
38+
// CHECK-NEXT: entry:
39+
// CHECK-NEXT: ret i64 [[PACK_COUNT]]
40+
static var count: Builtin.Word {
41+
Builtin.packCount((repeat each T).self)
42+
}
43+
}

test/SILGen/builtins.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,3 +876,12 @@ func assumeTrue(_ x: Builtin.Int1) {
876876
func assumeAlignment(_ p: Builtin.RawPointer, _ x: Builtin.Word) {
877877
Builtin.assumeAlignment(p, x)
878878
}
879+
880+
// CHECK-LABEL: sil hidden [ossa] @$s8builtins9packCountyBwxxQpRvzlF : $@convention(thin) <each T> (@pack_guaranteed Pack{repeat each T}) -> Builtin.Word {
881+
// CHECK: bb0(%0 : $*Pack{repeat each T}):
882+
// CHECK: [[META:%.*]] = metatype $@thin (repeat each T).Type
883+
// CHECK: [[BUILTIN:%.*]] = builtin "packCount"<Pack{repeat each T}>([[META]] : $@thin (repeat each T).Type) : $Builtin.Word
884+
// CHECK: return [[BUILTIN]] : $Builtin.Word
885+
func packCount<each T>(_ x: repeat each T) -> Builtin.Word {
886+
Builtin.packCount((repeat each T).self)
887+
}

test/SILOptimizer/sil_combine.sil

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4341,3 +4341,22 @@ bb0(%0 : $*Optional<String>, %1 : $*Kp1):
43414341
return %r : $()
43424342
}
43434343

4344+
// CHECK-LABEL: sil @packCount_expanded
4345+
// CHECK: [[META:%.*]] = metatype $@thin (String, repeat each T, Int).Type
4346+
// CHECK-NEXT: [[PACK_COUNT:%.*]] = builtin "packCount"<Pack{String, repeat each T, Int}>([[META]] : $@thin (String, repeat each T, Int).Type) : $Builtin.Word
4347+
// CHECK-NEXT: return [[PACK_COUNT]] : $Builtin.Word
4348+
sil @packCount_expanded : $@convention(thin) <each T> (@pack_guaranteed Pack{repeat each T}) -> Builtin.Word {
4349+
bb0(%0 : $*Pack{repeat each T}):
4350+
%meta = metatype $@thin (String, repeat each T, Int).Type
4351+
%pc = builtin "packCount"<Pack{String, repeat each T, Int}>(%meta : $@thin (String, repeat each T, Int).Type) : $Builtin.Word
4352+
return %pc : $Builtin.Word
4353+
}
4354+
4355+
// CHECK-LABEL: sil @packCount_concrete
4356+
// CHECK: [[PACK_COUNT:%.*]] = integer_literal $Builtin.Word, 4
4357+
// CHECK-NEXT: return [[PACK_COUNT]] : $Builtin.Word
4358+
sil @packCount_concrete : $@convention(thin) () -> Builtin.Word {
4359+
%meta = metatype $@thin (String, Int, Double, Float).Type
4360+
%pc = builtin "packCount"<Pack{String, Int, Double, Float}>(%meta : $@thin (String, Int, Double, Float).Type) : $Builtin.Word
4361+
return %pc : $Builtin.Word
4362+
}

0 commit comments

Comments
 (0)