Skip to content

Commit c47fe03

Browse files
committed
Optimize Builtin.assumeAlignment -> pointer_to_address
Case #1. Literal zero = natural alignment %1 = integer_literal $Builtin.Int64, 0 %2 = builtin "uncheckedAssertAlignment" (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int Erases the `pointer_to_address` `[align=]` attribute: Case #2. Literal nonzero = forced alignment. %1 = integer_literal $Builtin.Int64, 16 %2 = builtin "uncheckedAssertAlignment" (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int Promotes the `pointer_to_address` `[align=]` attribute to a higher value. Case #3. Folded dynamic alignment %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word %2 = builtin "uncheckedAssertAlignment" (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T Erases the `pointer_to_address` `[align=]` attribute.
1 parent 385a85c commit c47fe03

File tree

4 files changed

+190
-1
lines changed

4 files changed

+190
-1
lines changed

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,8 @@ class SILCombiner :
406406
SingleValueInstruction *user, SingleValueInstruction *value,
407407
function_ref<SILValue()> newValueGenerator);
408408

409+
SILInstruction *optimizeAlignment(PointerToAddressInst *ptrAdrInst);
410+
409411
InstModCallbacks &getInstModCallbacks() { return deleter.getCallbacks(); }
410412

411413
private:

lib/SILOptimizer/SILCombiner/SILCombinerCastVisitors.cpp

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,84 @@ SILInstruction *SILCombiner::visitUpcastInst(UpcastInst *uci) {
218218
return nullptr;
219219
}
220220

221+
// Optimize Builtin.assumeAlignment -> pointer_to_address
222+
//
223+
// Case #1. Literal zero = natural alignment
224+
// %1 = integer_literal $Builtin.Int64, 0
225+
// %2 = builtin "assumeAlignment"
226+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
227+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
228+
//
229+
// Erases the `pointer_to_address` `[align=]` attribute:
230+
//
231+
// Case #2. Literal nonzero = forced alignment.
232+
//
233+
// %1 = integer_literal $Builtin.Int64, 16
234+
// %2 = builtin "assumeAlignment"
235+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
236+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
237+
//
238+
// Promotes the `pointer_to_address` `[align=]` attribute to a higher value.
239+
//
240+
// Case #3. Folded dynamic alignment
241+
//
242+
// %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word
243+
// %2 = builtin "assumeAlignment"
244+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
245+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T
246+
//
247+
// Erases the `pointer_to_address` `[align=]` attribute.
248+
SILInstruction *
249+
SILCombiner::optimizeAlignment(PointerToAddressInst *ptrAdrInst) {
250+
if (!ptrAdrInst->alignment())
251+
return nullptr;
252+
253+
llvm::Align oldAlign = ptrAdrInst->alignment().valueOrOne();
254+
255+
// TODO: stripCasts(ptrAdrInst->getOperand()) can be used to find the Builtin,
256+
// but then the Builtin could not be trivially removed. Ideally,
257+
// Builtin.assume will be the immediate operand so it can be removed in the
258+
// common case.
259+
BuiltinInst *assumeAlign = dyn_cast<BuiltinInst>(ptrAdrInst->getOperand());
260+
if (!assumeAlign
261+
|| assumeAlign->getBuiltinKind() != BuiltinValueKind::AssumeAlignment) {
262+
return nullptr;
263+
}
264+
SILValue ptrSrc = assumeAlign->getArguments()[0];
265+
SILValue alignOper = assumeAlign->getArguments()[1];
266+
267+
if (auto *integerInst = dyn_cast<IntegerLiteralInst>(alignOper)) {
268+
llvm::MaybeAlign newAlign(integerInst->getValue().getLimitedValue());
269+
if (newAlign && newAlign.valueOrOne() <= oldAlign)
270+
return nullptr;
271+
272+
// Case #1: the pointer is assumed naturally aligned, or Case #2: the
273+
// pointer is assumed to have non-zero alignment greater than it current
274+
// alignment. In either case, rewrite the address alignment with the assumed
275+
// alignment, and bypass the Builtin.assumeAlign.
276+
return Builder.createPointerToAddress(
277+
ptrAdrInst->getLoc(), ptrSrc, ptrAdrInst->getType(),
278+
ptrAdrInst->isStrict(), ptrAdrInst->isInvariant(), newAlign);
279+
}
280+
MetatypeInst *metatype;
281+
if (match(alignOper,
282+
m_ApplyInst(BuiltinValueKind::Alignof, m_MetatypeInst(metatype)))) {
283+
SILType instanceType = ptrAdrInst->getFunction()->getLoweredType(
284+
metatype->getType().castTo<MetatypeType>().getInstanceType());
285+
286+
if (instanceType.getAddressType() != ptrAdrInst->getType())
287+
return nullptr;
288+
289+
// Case #3: the alignOf type matches the address type. Convert to a
290+
// naturally aligned pointer by erasing alignment and bypassing the
291+
// Builtin.assumeAlign.
292+
return Builder.createPointerToAddress(
293+
ptrAdrInst->getLoc(), ptrSrc, ptrAdrInst->getType(),
294+
ptrAdrInst->isStrict(), ptrAdrInst->isInvariant());
295+
}
296+
return nullptr;
297+
}
298+
221299
SILInstruction *
222300
SILCombiner::
223301
visitPointerToAddressInst(PointerToAddressInst *PTAI) {
@@ -374,7 +452,7 @@ visitPointerToAddressInst(PointerToAddressInst *PTAI) {
374452
}
375453
}
376454

377-
return nullptr;
455+
return optimizeAlignment(PTAI);
378456
}
379457

380458
SILInstruction *

test/SILGen/unsafe_pointer_gen.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
// RUN: %target-swift-emit-sil -O -parse-as-library %s | %FileCheck %s
22

33
// Test the absence of a 'strict' flag.
4+
// Test the absence of an 'align' flag.
5+
//
46
// CHECK-LABEL: $s18unsafe_pointer_gen13test_raw_load2rpSiSV_tF
57
// CHECK: pointer_to_address {{%.*}} : $Builtin.RawPointer to $*Int
68
public func test_raw_load(rp: UnsafeRawPointer) -> Int {
79
return rp.load(as: Int.self)
810
}
11+
12+
// Test the absence of a 'strict' flag.
13+
// Test the absence of an 'align' flag.
14+
//
15+
// CHECK-LABEL: $s18unsafe_pointer_gen20test_mutableraw_load2rpSiSv_tF
16+
// CHECK: pointer_to_address {{%.*}} : $Builtin.RawPointer to $*Int
17+
public func test_mutableraw_load(rp: UnsafeMutableRawPointer) -> Int {
18+
return rp.load(as: Int.self)
19+
}

test/SILOptimizer/sil_combine_casts.sil

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,101 @@ bb0(%0 : @owned $Optional<Klass>):
200200
return %2 : $Builtin.RawPointer
201201
}
202202

203+
// -----------------------------------------------------------------------------
204+
// SILCombiner::optimizeAlignment
205+
//
206+
// Optimize Builtin.assumeAlignment -> pointer_to_address
207+
// -----------------------------------------------------------------------------
208+
209+
// Case #1. Literal zero = natural alignment
210+
// %1 = integer_literal $Builtin.Int64, 0
211+
// %2 = builtin "assumeAlignment"
212+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
213+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
214+
//
215+
// Erases the `pointer_to_address` `[align=]` attribute:
216+
//
217+
// CHECK-LABEL: sil @$s8builtins20testNaturalAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
218+
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
219+
// CHECK-NOT: integer_literal
220+
// CHECK-NOT: builtin "assumeAlignment"
221+
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to $*T
222+
// CHECK: copy_addr [[PTR]] to [initialization] %0 : $*T
223+
// CHECK-LABEL: } // end sil function '$s8builtins20testNaturalAlignmentyxBp_xmtlF'
224+
sil @$s8builtins20testNaturalAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
225+
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
226+
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
227+
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
228+
%5 = integer_literal $Builtin.Word, 0
229+
%6 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %5 : $Builtin.Word) : $Builtin.RawPointer
230+
debug_value %6 : $Builtin.RawPointer, let, name "alignedPointer"
231+
%8 = pointer_to_address %6 : $Builtin.RawPointer to [align=1] $*T
232+
copy_addr %8 to [initialization] %0 : $*T
233+
%10 = tuple ()
234+
return %10 : $()
235+
}
236+
237+
//
238+
// Case #2. Literal nonzero = forced alignment.
239+
//
240+
// %1 = integer_literal $Builtin.Int64, 16
241+
// %2 = builtin "assumeAlignment"
242+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
243+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*Int
244+
//
245+
// Promotes the `pointer_to_address` `[align=]` attribute to a higher value.
246+
//
247+
// CHECK-LABEL: sil @$s8builtins18testFixedAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
248+
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
249+
// CHECK-NOT: integer_literal
250+
// CHECK-NOT: builtin "assumeAlignment"
251+
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to [align=8] $*T
252+
// CHECK: copy_addr [[PTR]] to [initialization] %0 : $*T
253+
// CHECK-LABEL: } // end sil function '$s8builtins18testFixedAlignmentyxBp_xmtlF'
254+
sil @$s8builtins18testFixedAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
255+
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
256+
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
257+
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
258+
%5 = integer_literal $Builtin.Word, 8
259+
%6 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %5 : $Builtin.Word) : $Builtin.RawPointer
260+
debug_value %6 : $Builtin.RawPointer, let, name "alignedPointer"
261+
%8 = pointer_to_address %6 : $Builtin.RawPointer to [align=1] $*T
262+
copy_addr %8 to [initialization] %0 : $*T
263+
%10 = tuple ()
264+
return %10 : $()
265+
}
266+
267+
// Case #3. Folded dynamic alignment
268+
//
269+
// %1 = builtin "alignof"<T>(%0 : $@thin T.Type) : $Builtin.Word
270+
// %2 = builtin "assumeAlignment"
271+
// (%0 : $Builtin.RawPointer, %1 : $Builtin.Int64) : $Builtin.RawPointer
272+
// %3 = pointer_to_address %2 : $Builtin.RawPointer to [align=1] $*T
273+
//
274+
// Erases the `pointer_to_address` `[align=]` attribute.
275+
//
276+
// CHECK-LABEL: sil @$s8builtins20testDynamicAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
277+
// CHECK: bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
278+
// CHECK-NOT: metatype
279+
// CHECK-NOT: builtin "alignOf"
280+
// CHECK-NOT: builtin "assumeAlignment"
281+
// CHECK: [[PTR:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to $*T
282+
// CHECK: copy_addr [[PTR]] to [initialization] %0 : $*T
283+
// CHECK-LABEL: } // end sil function '$s8builtins20testDynamicAlignmentyxBp_xmtlF'
284+
sil @$s8builtins20testDynamicAlignmentyxBp_xmtlF : $@convention(thin) <T> (Builtin.RawPointer, @thick T.Type) -> @out T {
285+
bb0(%0 : $*T, %1 : $Builtin.RawPointer, %2 : $@thick T.Type):
286+
debug_value %1 : $Builtin.RawPointer, let, name "rawPointer", argno 1
287+
debug_value %2 : $@thick T.Type, let, name "_1", argno 2
288+
%5 = metatype $@thick T.Type
289+
%6 = builtin "alignof"<T>(%5 : $@thick T.Type) : $Builtin.Word
290+
%7 = builtin "sextOrBitCast_Word_Int64"(%6 : $Builtin.Word) : $Builtin.Int64
291+
%8 = struct $Int (%7 : $Builtin.Int64)
292+
debug_value %8 : $Int, let, name "align"
293+
%10 = builtin "truncOrBitCast_Int64_Word"(%7 : $Builtin.Int64) : $Builtin.Word
294+
%11 = builtin "assumeAlignment"(%1 : $Builtin.RawPointer, %10 : $Builtin.Word) : $Builtin.RawPointer
295+
debug_value %11 : $Builtin.RawPointer, let, name "alignedPointer"
296+
%13 = pointer_to_address %11 : $Builtin.RawPointer to [align=1] $*T
297+
copy_addr %13 to [initialization] %0 : $*T
298+
%15 = tuple ()
299+
return %15 : $()
300+
}

0 commit comments

Comments
 (0)