Skip to content

Commit c975023

Browse files
committed
Optimizer: add constant folding of classify_bridge_object
Constant fold `classify_bridge_object` to `(false, false)` if the operand is known to be a swift class.
1 parent 1856e7f commit c975023

File tree

7 files changed

+88
-19
lines changed

7 files changed

+88
-19
lines changed

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/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,
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+

0 commit comments

Comments
 (0)