Skip to content

Commit bc4310b

Browse files
committed
Optimizer: simplify unchecked_addr_cast for vectors
Reimplement the simplification in swift and add a new transformation: ``` %1 = unchecked_addr_cast %0 : $*Builtin.FixedArray<N, Element> to $*Element ``` -> ``` %1 = vector_base_addr %0 : $*Builtin.FixedArray<N, Element> ```
1 parent e3f25d7 commit bc4310b

File tree

8 files changed

+157
-34
lines changed

8 files changed

+157
-34
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ swift_compiler_sources(Optimizer
3939
SimplifySwitchEnum.swift
4040
SimplifyTuple.swift
4141
SimplifyTupleExtract.swift
42+
SimplifyUncheckedAddrCast.swift
4243
SimplifyUncheckedEnumData.swift
4344
SimplifyValueToBridgeObject.swift
4445
SimplifyWitnessMethod.swift)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===--- SimplifyUncheckedAddrCast.swift ----------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 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 SIL
14+
15+
extension UncheckedAddrCastInst : OnoneSimplifiable, SILCombineSimplifiable {
16+
17+
func simplify(_ context: SimplifyContext) {
18+
// ```
19+
// %1 = unchecked_addr_cast %0 : $*T to $*T
20+
// ```
21+
// ->
22+
// replace %1 with %0
23+
//
24+
if optimizeSameTypeCast(context) {
25+
return
26+
}
27+
28+
// ```
29+
// %1 = unchecked_addr_cast %0 : $*U to $*V
30+
// %2 = unchecked_addr_cast %1 : $*V to $*T
31+
// ```
32+
// ->
33+
// ```
34+
// %2 = unchecked_addr_cast %0: $*U to $*T
35+
// ```
36+
if optimizeDoubleCast(context) {
37+
return
38+
}
39+
40+
// ```
41+
// %1 = unchecked_addr_cast %0 : $*Builtin.FixedArray<N, Element> to $*Element
42+
// ```
43+
// ->
44+
// ```
45+
// %1 = vector_base_addr %0 : $*Builtin.FixedArray<N, Element>
46+
// ```
47+
_ = optimizeVectorBaseCast(context)
48+
}
49+
}
50+
51+
private extension UncheckedAddrCastInst {
52+
func optimizeSameTypeCast(_ context: SimplifyContext) -> Bool {
53+
if fromAddress.type == type {
54+
self.replace(with: fromAddress, context)
55+
return true
56+
}
57+
return false
58+
}
59+
60+
func optimizeDoubleCast(_ context: SimplifyContext) -> Bool {
61+
if let firstCast = fromAddress as? UncheckedAddrCastInst {
62+
let builder = Builder(before: self, context)
63+
let newCast = builder.createUncheckedAddrCast(from: firstCast.fromAddress, to: type)
64+
self.replace(with: newCast, context)
65+
return true
66+
}
67+
return false
68+
}
69+
70+
func optimizeVectorBaseCast(_ context: SimplifyContext) -> Bool {
71+
if fromAddress.type.isBuiltinFixedArray,
72+
fromAddress.type.builtinFixedArrayElementType(in: parentFunction, maximallyAbstracted: true).addressType == type
73+
{
74+
let builder = Builder(before: self, context)
75+
let vectorBase = builder.createVectorBaseAddr(vector: fromAddress)
76+
self.replace(with: vectorBase, context)
77+
return true
78+
}
79+
return false
80+
}
81+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ private func registerSwiftPasses() {
125125
registerForSILCombine(PointerToAddressInst.self, { run(PointerToAddressInst.self, $0) })
126126
registerForSILCombine(UncheckedEnumDataInst.self, { run(UncheckedEnumDataInst.self, $0) })
127127
registerForSILCombine(WitnessMethodInst.self, { run(WitnessMethodInst.self, $0) })
128+
registerForSILCombine(UncheckedAddrCastInst.self, { run(UncheckedAddrCastInst.self, $0) })
128129
registerForSILCombine(UnconditionalCheckedCastInst.self, { run(UnconditionalCheckedCastInst.self, $0) })
129130
registerForSILCombine(AllocStackInst.self, { run(AllocStackInst.self, $0) })
130131
registerForSILCombine(ApplyInst.self, { run(ApplyInst.self, $0) })

lib/SILOptimizer/Analysis/SimplifyInstruction.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ namespace {
5252
SILValue
5353
visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI);
5454
SILValue visitUncheckedRefCastInst(UncheckedRefCastInst *OPRI);
55-
SILValue visitUncheckedAddrCastInst(UncheckedAddrCastInst *UACI);
5655
SILValue visitStructInst(StructInst *SI);
5756
SILValue visitTupleInst(TupleInst *SI);
5857
SILValue visitBuiltinInst(BuiltinInst *AI);
@@ -357,21 +356,6 @@ visitUncheckedRefCastInst(UncheckedRefCastInst *OPRI) {
357356
return simplifyDeadCast(OPRI);
358357
}
359358

360-
SILValue
361-
InstSimplifier::
362-
visitUncheckedAddrCastInst(UncheckedAddrCastInst *UACI) {
363-
// (unchecked-addr-cast Y->X (unchecked-addr-cast x X->Y)) -> x
364-
if (auto *OtherUACI = dyn_cast<UncheckedAddrCastInst>(&*UACI->getOperand()))
365-
if (OtherUACI->getOperand()->getType() == UACI->getType())
366-
return OtherUACI->getOperand();
367-
368-
// (unchecked-addr-cast X->X x) -> x
369-
if (UACI->getOperand()->getType() == UACI->getType())
370-
return UACI->getOperand();
371-
372-
return SILValue();
373-
}
374-
375359
SILValue InstSimplifier::visitUpcastInst(UpcastInst *UI) {
376360
// (upcast Y->X (unchecked-ref-cast x X->Y)) -> x
377361
if (auto *URCI = dyn_cast<UncheckedRefCastInst>(UI->getOperand()))

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ class SILCombiner :
260260
bool optimizeStackAllocatedEnum(AllocStackInst *AS);
261261
SILInstruction *visitSwitchEnumAddrInst(SwitchEnumAddrInst *SEAI);
262262
SILInstruction *visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI);
263-
SILInstruction *visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI);
264263
SILInstruction *visitUncheckedRefCastInst(UncheckedRefCastInst *URCI);
265264
SILInstruction *visitEndCOWMutationInst(EndCOWMutationInst *URCI);
266265
SILInstruction *visitUncheckedRefCastAddrInst(UncheckedRefCastAddrInst *URCI);

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -219,23 +219,6 @@ SILInstruction *SILCombiner::visitUpcastInst(UpcastInst *uci) {
219219
return nullptr;
220220
}
221221

222-
SILInstruction *
223-
SILCombiner::visitUncheckedAddrCastInst(UncheckedAddrCastInst *UADCI) {
224-
// These are always safe to perform due to interior pointer ownership
225-
// requirements being transitive along addresses.
226-
227-
Builder.setCurrentDebugScope(UADCI->getDebugScope());
228-
229-
// (unchecked_addr_cast (unchecked_addr_cast x X->Y) Y->Z)
230-
// ->
231-
// (unchecked_addr_cast x X->Z)
232-
if (auto *OtherUADCI = dyn_cast<UncheckedAddrCastInst>(UADCI->getOperand()))
233-
return Builder.createUncheckedAddrCast(UADCI->getLoc(),
234-
OtherUADCI->getOperand(),
235-
UADCI->getType());
236-
return nullptr;
237-
}
238-
239222
SILInstruction *
240223
SILCombiner::visitUncheckedRefCastInst(UncheckedRefCastInst *urci) {
241224
// %0 = unchecked_ref_cast %x : $X->Y

lib/SILOptimizer/SILCombiner/Simplifications.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ INSTRUCTION_SIMPLIFICATION(DestructureStructInst)
4747
INSTRUCTION_SIMPLIFICATION(DestructureTupleInst)
4848
INSTRUCTION_SIMPLIFICATION(PointerToAddressInst)
4949
INSTRUCTION_SIMPLIFICATION(TypeValueInst)
50+
INSTRUCTION_SIMPLIFICATION(UncheckedAddrCastInst)
5051
INSTRUCTION_SIMPLIFICATION(UncheckedEnumDataInst)
5152
INSTRUCTION_SIMPLIFICATION(WitnessMethodInst)
5253
INSTRUCTION_SIMPLIFICATION_WITH_LEGACY(AllocStackInst)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %target-sil-opt %s -onone-simplification -simplify-instruction=unchecked_addr_cast | %FileCheck %s
2+
// RUN: %target-sil-opt %s -simplification -simplify-instruction=unchecked_addr_cast | %FileCheck %s
3+
4+
import Swift
5+
import Builtin
6+
7+
// CHECK-LABEL: sil [ossa] @same_type :
8+
// CHECK-NOT: unchecked_addr_cast
9+
// CHECK: %1 = load [trivial] %0
10+
// CHECK: } // end sil function 'same_type'
11+
sil [ossa] @same_type : $@convention(thin) (@inout Int) -> Int {
12+
bb0(%0 : $*Int):
13+
%1 = unchecked_addr_cast %0 to $*Int
14+
%2 = load [trivial] %1
15+
return %2
16+
}
17+
18+
// CHECK-LABEL: sil [ossa] @not_same_type :
19+
// CHECK: %1 = unchecked_addr_cast %0 to $*Float
20+
// CHECK: %2 = load [trivial] %1
21+
// CHECK: } // end sil function 'not_same_type'
22+
sil [ossa] @not_same_type : $@convention(thin) (@inout Int) -> Float {
23+
bb0(%0 : $*Int):
24+
%1 = unchecked_addr_cast %0 to $*Float
25+
%2 = load [trivial] %1
26+
return %2
27+
}
28+
29+
// CHECK-LABEL: sil [ossa] @double_cast :
30+
// CHECK: %1 = unchecked_addr_cast %0 to $*Bool
31+
// CHECK: %2 = load [trivial] %1
32+
// CHECK: } // end sil function 'double_cast'
33+
sil [ossa] @double_cast : $@convention(thin) (@inout Int) -> Bool {
34+
bb0(%0 : $*Int):
35+
%1 = unchecked_addr_cast %0 to $*Float
36+
%2 = unchecked_addr_cast %1 to $*Bool
37+
%3 = load [trivial] %2
38+
return %3
39+
}
40+
41+
// CHECK-LABEL: sil [ossa] @vector_base :
42+
// CHECK: %1 = vector_base_addr %0
43+
// CHECK: %2 = load [trivial] %1
44+
// CHECK: } // end sil function 'vector_base'
45+
sil [ossa] @vector_base : $@convention(thin) (@inout Builtin.FixedArray<10, Int>) -> Int {
46+
bb0(%0 : $*Builtin.FixedArray<10, Int>):
47+
%1 = unchecked_addr_cast %0 to $*Int
48+
%2 = load [trivial] %1
49+
return %2
50+
}
51+
52+
// CHECK-LABEL: sil [ossa] @vector_base_wrong_type :
53+
// CHECK: %1 = unchecked_addr_cast %0 to $*Bool
54+
// CHECK: %2 = load [trivial] %1
55+
// CHECK: } // end sil function 'vector_base_wrong_type'
56+
sil [ossa] @vector_base_wrong_type : $@convention(thin) (@inout Builtin.FixedArray<10, Int>) -> Bool {
57+
bb0(%0 : $*Builtin.FixedArray<10, Int>):
58+
%1 = unchecked_addr_cast %0 to $*Bool
59+
%2 = load [trivial] %1
60+
return %2
61+
}
62+
63+
// CHECK-LABEL: sil [ossa] @vector_base_function_type :
64+
// CHECK: %1 = vector_base_addr %0
65+
// CHECK: %2 = load [copy] %1
66+
// CHECK: } // end sil function 'vector_base_function_type'
67+
sil [ossa] @vector_base_function_type : $@convention(thin) (@inout Builtin.FixedArray<10, ()->()>) -> @owned @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()> {
68+
bb0(%0 : $*Builtin.FixedArray<10, ()->()>):
69+
%1 = unchecked_addr_cast %0 to $*@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <()>
70+
%2 = load [copy] %1
71+
return %2
72+
}
73+

0 commit comments

Comments
 (0)