Skip to content

Commit f65d41e

Browse files
authored
Merge pull request #76908 from eeckstein/array-improvements
Improve code generation for arrays of classes.
2 parents 9c44b79 + e50a93a commit f65d41e

File tree

12 files changed

+106
-24
lines changed

12 files changed

+106
-24
lines changed

SwiftCompilerSources/Sources/AST/Declarations.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class Decl: CustomStringConvertible, Hashable {
3030
public class ValueDecl: Decl {
3131
final public var nameLoc: SourceLoc? { SourceLoc(bridged: bridged.Value_getNameLoc()) }
3232
final public var userFacingName: StringRef { StringRef(bridged: bridged.Value_getUserFacingName()) }
33+
final public var isObjC: Bool { bridged.Value_isObjC() }
3334
}
3435

3536
public class TypeDecl: ValueDecl {

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ swift_compiler_sources(Optimizer
1414
SimplifyBranch.swift
1515
SimplifyBuiltin.swift
1616
SimplifyCheckedCast.swift
17+
SimplifyClassifyBridgeObject.swift
1718
SimplifyCondBranch.swift
1819
SimplifyCondFail.swift
1920
SimplifyConvertEscapeToNoEscape.swift
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===--- SimplifyClassifyBridgeObject.swift -------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import AST
14+
import SIL
15+
16+
extension ClassifyBridgeObjectInst : OnoneSimplifyable, SILCombineSimplifyable {
17+
func simplify(_ context: SimplifyContext) {
18+
// Constant fold `classify_bridge_object` to `(false, false)` if the operand is known
19+
// to be a swift class.
20+
var walker = CheckForSwiftClasses();
21+
if walker.walkUp(value: operand.value, path: UnusedWalkingPath()) == .abortWalk {
22+
return
23+
}
24+
25+
let builder = Builder(before: self, context)
26+
let falseLiteral = builder.createIntegerLiteral(0, type: context.getBuiltinIntegerType(bitWidth: 1))
27+
let tp = builder.createTuple(type: self.type, elements: [falseLiteral, falseLiteral])
28+
uses.replaceAll(with: tp, context)
29+
context.erase(instruction: self)
30+
}
31+
}
32+
33+
private struct CheckForSwiftClasses: ValueUseDefWalker {
34+
mutating func walkUp(value: Value, path: UnusedWalkingPath) -> WalkResult {
35+
if let nominal = value.type.nominal,
36+
let classDecl = nominal as? ClassDecl,
37+
!classDecl.isObjC
38+
{
39+
// Stop this use-def walk if the value is known to be a swift class.
40+
return .continueWalk
41+
}
42+
return walkUpDefault(value: value, path: path)
43+
}
44+
45+
mutating func rootDef(value: Value, path: UnusedWalkingPath) -> WalkResult {
46+
return .abortWalk
47+
}
48+
49+
var walkUpCache = WalkerCache<UnusedWalkingPath>()
50+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ private func registerSwiftPasses() {
111111
registerForSILCombine(DestructureStructInst.self, { run(DestructureStructInst.self, $0) })
112112
registerForSILCombine(DestructureTupleInst.self, { run(DestructureTupleInst.self, $0) })
113113
registerForSILCombine(TypeValueInst.self, { run(TypeValueInst.self, $0) })
114+
registerForSILCombine(ClassifyBridgeObjectInst.self, { run(ClassifyBridgeObjectInst.self, $0) })
114115

115116
// Test passes
116117
registerPass(aliasInfoDumper, { aliasInfoDumper.run($0) })

include/swift/AST/ASTBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ struct BridgedDeclObj {
317317
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef Type_getName() const;
318318
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef Value_getUserFacingName() const;
319319
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSourceLoc Value_getNameLoc() const;
320+
BRIDGED_INLINE bool Value_isObjC() const;
320321
BRIDGED_INLINE bool GenericType_isGenericAtAnyLevel() const;
321322
BRIDGED_INLINE bool NominalType_isGlobalActor() const;
322323
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj NominalType_getValueTypeDestructor() const;

include/swift/AST/ASTBridgingImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ BridgedSourceLoc BridgedDeclObj::Value_getNameLoc() const {
5252
return BridgedSourceLoc(getAs<swift::ValueDecl>()->getNameLoc().getOpaquePointerValue());
5353
}
5454

55+
bool BridgedDeclObj::Value_isObjC() const {
56+
return getAs<swift::ValueDecl>()->isObjC();
57+
}
58+
5559
bool BridgedDeclObj::GenericType_isGenericAtAnyLevel() const {
5660
return getAs<swift::GenericTypeDecl>()->isGenericContext();
5761
}

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ PASS(PruneVTables, "prune-vtables",
517517
PASS_RANGE(AllPasses, AliasInfoDumper, PruneVTables)
518518

519519
SWIFT_SILCOMBINE_PASS(BeginCOWMutationInst)
520+
SWIFT_SILCOMBINE_PASS(ClassifyBridgeObjectInst)
520521
SWIFT_SILCOMBINE_PASS(GlobalValueInst)
521522
SWIFT_SILCOMBINE_PASS(StrongRetainInst)
522523
SWIFT_SILCOMBINE_PASS(StrongReleaseInst)

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ class SILCombiner :
292292
SILInstruction *visitAllocRefDynamicInst(AllocRefDynamicInst *ARDI);
293293

294294
SILInstruction *visitMarkDependenceInst(MarkDependenceInst *MDI);
295-
SILInstruction *visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *CBOI);
296295
SILInstruction *visitConvertFunctionInst(ConvertFunctionInst *CFI);
297296
SILInstruction *
298297
visitConvertEscapeToNoEscapeInst(ConvertEscapeToNoEscapeInst *Cvt);

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,24 +2006,6 @@ SILInstruction *SILCombiner::visitMarkDependenceInst(MarkDependenceInst *mdi) {
20062006
return nullptr;
20072007
}
20082008

2009-
SILInstruction *
2010-
SILCombiner::visitClassifyBridgeObjectInst(ClassifyBridgeObjectInst *cboi) {
2011-
auto *urc = dyn_cast<UncheckedRefCastInst>(cboi->getOperand());
2012-
if (!urc)
2013-
return nullptr;
2014-
2015-
auto type = urc->getOperand()->getType().getASTType();
2016-
if (ClassDecl *cd = type->getClassOrBoundGenericClass()) {
2017-
if (!cd->isObjC()) {
2018-
auto int1Ty = SILType::getBuiltinIntegerType(1, Builder.getASTContext());
2019-
SILValue zero = Builder.createIntegerLiteral(cboi->getLoc(), int1Ty, 0);
2020-
return Builder.createTuple(cboi->getLoc(), {zero, zero});
2021-
}
2022-
}
2023-
2024-
return nullptr;
2025-
}
2026-
20272009
/// Returns true if reference counting and debug_value users of a global_value
20282010
/// can be deleted.
20292011
static bool checkGlobalValueUsers(SILValue val,

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2982,6 +2982,13 @@ static bool usePrespecialized(
29822982
if (refF->getSpecializeAttrs().empty())
29832983
return false;
29842984

2985+
// `Array._endMutation` was added for pre-specialization by mistake. But we
2986+
// cannot remove the specialize-attributes anymore because the pre-specialized
2987+
// functions are now part of the stdlib's ABI.
2988+
// Therefore make an exception for `Array._endMutation` here.
2989+
if (refF->getName() == "$sSa12_endMutationyyF")
2990+
return false;
2991+
29852992
SmallVector<std::tuple<unsigned, ReabstractionInfo, AvailabilityRange>, 4>
29862993
layoutMatches;
29872994

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -onone-simplification -simplify-instruction=classify_bridge_object | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
struct MyArray {
9+
let o: Builtin.BridgeObject
10+
}
11+
12+
// CHECK-LABEL: sil @test_swift_class :
13+
// CHECK: %1 = integer_literal $Builtin.Int1, 0
14+
// CHECK: %2 = tuple (%1 : $Builtin.Int1, %1 : $Builtin.Int1)
15+
// CHECK: return %2
16+
// CHECK: } // end sil function 'test_swift_class'
17+
sil @test_swift_class : $@convention(thin) (@guaranteed _ContiguousArrayStorage<Int>) -> (Builtin.Int1, Builtin.Int1) {
18+
bb0(%0 : $_ContiguousArrayStorage<Int>):
19+
%1 = unchecked_ref_cast %0 : $_ContiguousArrayStorage<Int> to $Builtin.BridgeObject
20+
%2 = classify_bridge_object %1 : $Builtin.BridgeObject
21+
return %2 : $(Builtin.Int1, Builtin.Int1)
22+
}
23+
24+
// CHECK-LABEL: sil @test_unknown_class :
25+
// CHECK: %1 = struct_extract %0
26+
// CHECK: %2 = classify_bridge_object %1
27+
// CHECK: return %2
28+
// CHECK: } // end sil function 'test_unknown_class'
29+
sil @test_unknown_class : $@convention(thin) (@guaranteed MyArray) -> (Builtin.Int1, Builtin.Int1) {
30+
bb0(%0 : $MyArray):
31+
%1 = struct_extract %0 : $MyArray, #MyArray.o
32+
%2 = classify_bridge_object %1 : $Builtin.BridgeObject
33+
return %2 : $(Builtin.Int1, Builtin.Int1)
34+
}
35+

test/SILOptimizer/static_arrays.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,12 @@ func takeUnsafePointer(ptr : UnsafePointer<SwiftClass>, len: Int) {
267267
// This should be a single basic block, and the array should end up being stack
268268
// allocated.
269269
//
270-
// CHECK-LABEL: sil [noinline] @{{.*passArrayOfClasses.*}} : $@convention(thin) (@guaranteed SwiftClass, @guaranteed SwiftClass, @guaranteed SwiftClass) -> () {
270+
// CHECK-LABEL: sil [noinline] @$s4test18passArrayOfClasses1a1b1cyAA10SwiftClassC_A2GtF : $@convention(thin) (@guaranteed SwiftClass, @guaranteed SwiftClass, @guaranteed SwiftClass) -> () {
271271
// CHECK: bb0(%0 : $SwiftClass, %1 : $SwiftClass, %2 : $SwiftClass):
272-
// CHECK-NOT: bb1(
273-
// CHECK: alloc_ref{{(_dynamic)?}} {{.*}}[tail_elems $SwiftClass *
274-
// CHECK-NOT: bb1(
275-
// CHECK: } // end sil function '{{.*passArrayOfClasses.*}}'
272+
// CHECK-NOT: bb1
273+
// CHECK: alloc_ref{{.*}}[stack] [tail_elems $SwiftClass *
274+
// CHECK-NOT: bb1
275+
// CHECK: } // end sil function '$s4test18passArrayOfClasses1a1b1cyAA10SwiftClassC_A2GtF'
276276
@inline(never)
277277
public func passArrayOfClasses(a: SwiftClass, b: SwiftClass, c: SwiftClass) {
278278
let arr = [a, b, c]

0 commit comments

Comments
 (0)