Skip to content

Commit b8f42d6

Browse files
authored
Merge pull request swiftlang#26466 from nvzqz/is_concrete_builtin
2 parents 1224e90 + 931ab46 commit b8f42d6

File tree

15 files changed

+263
-1
lines changed

15 files changed

+263
-1
lines changed

include/swift/AST/Builtins.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,14 @@ BUILTIN_MISC_OPERATION(Strideof, "strideof", "n", Special)
418418
/// IsPOD has type T.Type -> Bool
419419
BUILTIN_MISC_OPERATION(IsPOD, "ispod", "n", Special)
420420

421+
/// IsConcrete has type (T.Type) -> Bool
422+
///
423+
/// If the meta type T is concrete, we can always transform this to `true` at
424+
/// any time in SIL. If it's generic, then we lower it to `false` right before
425+
/// IRGen in IRGenPrepare. This allows for the optimizer to specialize this at
426+
/// -O and eliminate conditional code.
427+
BUILTIN_MISC_OPERATION(IsConcrete, "isConcrete", "n", Special)
428+
421429
/// IsBitwiseTakable has type T.Type -> Bool
422430
BUILTIN_MISC_OPERATION(IsBitwiseTakable, "isbitwisetakable", "n", Special)
423431

lib/AST/Builtins.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,13 @@ static ValueDecl *getIsPODOperation(ASTContext &Context, Identifier Id) {
737737
return builder.build(Id);
738738
}
739739

740+
static ValueDecl *getIsConcrete(ASTContext &Context, Identifier Id) {
741+
BuiltinGenericSignatureBuilder builder(Context);
742+
builder.addParameter(makeMetatype(makeGenericParam()));
743+
builder.setResult(makeConcrete(BuiltinIntegerType::get(1,Context)));
744+
return builder.build(Id);
745+
}
746+
740747
static ValueDecl *getIsBitwiseTakable(ASTContext &Context, Identifier Id) {
741748
BuiltinGenericSignatureBuilder builder(Context);
742749
builder.addParameter(makeMetatype(makeGenericParam()));
@@ -1857,6 +1864,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
18571864
case BuiltinValueKind::IsPOD:
18581865
return getIsPODOperation(Context, Id);
18591866

1867+
case BuiltinValueKind::IsConcrete:
1868+
return getIsConcrete(Context, Id);
1869+
18601870
case BuiltinValueKind::IsBitwiseTakable:
18611871
return getIsBitwiseTakable(Context, Id);
18621872

lib/IRGen/GenBuiltin.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
179179
return;
180180
}
181181

182+
if (Builtin.ID == BuiltinValueKind::IsConcrete) {
183+
(void)args.claimAll();
184+
auto isConcrete = !substitutions.getReplacementTypes()[0]->hasArchetype();
185+
out.add(llvm::ConstantInt::get(IGF.IGM.Int1Ty, isConcrete));
186+
return;
187+
}
188+
182189
if (Builtin.ID == BuiltinValueKind::IsBitwiseTakable) {
183190
(void)args.claimAll();
184191
auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM,

lib/SIL/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,7 @@ ANY_OWNERSHIP_BUILTIN(IntToFPWithOverflow)
983983
ANY_OWNERSHIP_BUILTIN(IntToPtr)
984984
ANY_OWNERSHIP_BUILTIN(IsOptionalType)
985985
ANY_OWNERSHIP_BUILTIN(IsPOD)
986+
ANY_OWNERSHIP_BUILTIN(IsConcrete)
986987
ANY_OWNERSHIP_BUILTIN(IsBitwiseTakable)
987988
ANY_OWNERSHIP_BUILTIN(IsSameMetatype)
988989
ANY_OWNERSHIP_BUILTIN(LShr)

lib/SIL/ValueOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ CONSTANT_OWNERSHIP_BUILTIN(Any, Sizeof)
448448
CONSTANT_OWNERSHIP_BUILTIN(Any, Strideof)
449449
CONSTANT_OWNERSHIP_BUILTIN(Any, StringObjectOr)
450450
CONSTANT_OWNERSHIP_BUILTIN(Any, IsPOD)
451+
CONSTANT_OWNERSHIP_BUILTIN(Any, IsConcrete)
451452
CONSTANT_OWNERSHIP_BUILTIN(Any, IsBitwiseTakable)
452453
CONSTANT_OWNERSHIP_BUILTIN(Any, IsSameMetatype)
453454
CONSTANT_OWNERSHIP_BUILTIN(Any, Alignof)

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,9 @@ class SILCombiner :
285285
/// Instruction visitor helpers.
286286
SILInstruction *optimizeBuiltinCanBeObjCClass(BuiltinInst *AI);
287287

288+
// Optimize the "isConcrete" builtin.
289+
SILInstruction *optimizeBuiltinIsConcrete(BuiltinInst *I);
290+
288291
// Optimize the "trunc_N1_M2" builtin. if N1 is a result of "zext_M1_*" and
289292
// the following holds true: N1 > M1 and M2>= M1
290293
SILInstruction *optimizeBuiltinTruncOrBitCast(BuiltinInst *I);

lib/SILOptimizer/SILCombiner/SILCombinerBuiltinVisitors.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ SILInstruction *SILCombiner::optimizeBuiltinCanBeObjCClass(BuiltinInst *BI) {
102102
llvm_unreachable("Unhandled TypeTraitResult in switch.");
103103
}
104104

105+
SILInstruction *SILCombiner::optimizeBuiltinIsConcrete(BuiltinInst *BI) {
106+
if (BI->getOperand(0)->getType().hasArchetype())
107+
return nullptr;
108+
109+
return Builder.createIntegerLiteral(BI->getLoc(), BI->getType(), 1);
110+
}
111+
105112
static unsigned getTypeWidth(SILType Ty) {
106113
if (auto BuiltinIntTy = Ty.getAs<BuiltinIntegerType>()) {
107114
if (BuiltinIntTy->isFixedWidth()) {
@@ -525,6 +532,8 @@ SILInstruction *SILCombiner::optimizeStringObject(BuiltinInst *BI) {
525532
SILInstruction *SILCombiner::visitBuiltinInst(BuiltinInst *I) {
526533
if (I->getBuiltinInfo().ID == BuiltinValueKind::CanBeObjCClass)
527534
return optimizeBuiltinCanBeObjCClass(I);
535+
if (I->getBuiltinInfo().ID == BuiltinValueKind::IsConcrete)
536+
return optimizeBuiltinIsConcrete(I);
528537
if (I->getBuiltinInfo().ID == BuiltinValueKind::TakeArrayFrontToBack ||
529538
I->getBuiltinInfo().ID == BuiltinValueKind::TakeArrayBackToFront ||
530539
I->getBuiltinInfo().ID == BuiltinValueKind::TakeArrayNoAlias ||

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ static bool isBarrier(SILInstruction *inst) {
109109
case BuiltinValueKind::Sizeof:
110110
case BuiltinValueKind::Strideof:
111111
case BuiltinValueKind::IsPOD:
112+
case BuiltinValueKind::IsConcrete:
112113
case BuiltinValueKind::IsBitwiseTakable:
113114
case BuiltinValueKind::IsSameMetatype:
114115
case BuiltinValueKind::Alignof:

lib/SILOptimizer/Utils/ConstantFolding.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,18 @@ static SILValue foldFPTrunc(BuiltinInst *BI, const BuiltinInfo &Builtin,
11661166
return B.createFloatLiteral(Loc, BI->getType(), truncVal);
11671167
}
11681168

1169+
static SILValue constantFoldIsConcrete(BuiltinInst *BI) {
1170+
if (BI->getOperand(0)->getType().hasArchetype()) {
1171+
return SILValue();
1172+
}
1173+
SILBuilderWithScope builder(BI);
1174+
auto *inst = builder.createIntegerLiteral(
1175+
BI->getLoc(), SILType::getBuiltinIntegerType(1, builder.getASTContext()),
1176+
true);
1177+
BI->replaceAllUsesWith(inst);
1178+
return inst;
1179+
}
1180+
11691181
static SILValue constantFoldBuiltin(BuiltinInst *BI,
11701182
Optional<bool> &ResultsInError) {
11711183
const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo();
@@ -1563,7 +1575,8 @@ void ConstantFolder::initializeWorklist(SILFunction &f) {
15631575
continue;
15641576
}
15651577

1566-
if (isApplyOfBuiltin(*inst, BuiltinValueKind::GlobalStringTablePointer)) {
1578+
if (isApplyOfBuiltin(*inst, BuiltinValueKind::GlobalStringTablePointer) ||
1579+
isApplyOfBuiltin(*inst, BuiltinValueKind::IsConcrete)) {
15671580
WorkList.insert(inst);
15681581
continue;
15691582
}
@@ -1781,6 +1794,17 @@ ConstantFolder::processWorkList() {
17811794
continue;
17821795
}
17831796

1797+
if (isApplyOfBuiltin(*I, BuiltinValueKind::IsConcrete)) {
1798+
if (constantFoldIsConcrete(cast<BuiltinInst>(I))) {
1799+
// Here, the bulitin instruction got folded, so clean it up.
1800+
recursivelyDeleteTriviallyDeadInstructions(
1801+
I, /*force*/ true,
1802+
[&](SILInstruction *DeadI) { WorkList.remove(DeadI); });
1803+
InvalidateInstructions = true;
1804+
}
1805+
continue;
1806+
}
1807+
17841808
// Go through all users of the constant and try to fold them.
17851809
FoldedUsers.clear();
17861810
for (auto Result : I->getResults()) {

stdlib/public/core/Builtin.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,19 @@ func _isPOD<T>(_ type: T.Type) -> Bool {
691691
return Bool(Builtin.ispod(type))
692692
}
693693

694+
/// Returns `true` if `type` is known to refer to a concrete type once all
695+
/// optimizations and constant folding has occurred at the call site. Otherwise,
696+
/// this returns `false` if the check has failed.
697+
///
698+
/// Note that there may be cases in which, despite `T` being concrete at some
699+
/// point in the caller chain, this function will return `false`.
700+
@_alwaysEmitIntoClient
701+
@_transparent
702+
public // @testable
703+
func _isConcrete<T>(_ type: T.Type) -> Bool {
704+
return Bool(Builtin.isConcrete(type))
705+
}
706+
694707
/// Returns `true` if type is a bitwise takable. A bitwise takable type can
695708
/// just be moved to a different address in memory.
696709
@_transparent

0 commit comments

Comments
 (0)