Skip to content

Commit 1ecd938

Browse files
Merge pull request #71673 from nate-chandler/bitwise-copyable/opt-store-bytes
[BitwiseCopyable] Optimize storeBytes overload.
2 parents e9c7f3c + 60d7ff8 commit 1ecd938

File tree

5 files changed

+65
-26
lines changed

5 files changed

+65
-26
lines changed

include/swift/AST/Builtins.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ BUILTIN_SIL_OPERATION(Assign, "assign", Special)
261261
/// Init has type (T, Builtin.RawPointer) -> ()
262262
BUILTIN_SIL_OPERATION(Init, "initialize", Special)
263263

264+
/// StoreRaw has type (T, Builtin.RawPointer) -> ()
265+
/// Stores a T to raw memory.
266+
/// Its address does not adhere to strict aliasing.
267+
/// See also LoadRaw.
268+
BUILTIN_SIL_OPERATION(StoreRaw, "storeRaw", Special)
269+
264270
/// CastToNativeObject has type (T) -> Builtin.NativeObject.
265271
///
266272
/// This builtin asserts if the underlying type /could/ be objc.

lib/AST/Builtins.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2776,6 +2776,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
27762776

27772777
case BuiltinValueKind::Assign:
27782778
case BuiltinValueKind::Init:
2779+
case BuiltinValueKind::StoreRaw:
27792780
if (!Types.empty()) return nullptr;
27802781
return getStoreOperation(Context, Id);
27812782

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -206,35 +206,48 @@ static ManagedValue emitBuiltinDestroy(SILGenFunction &SGF,
206206
return ManagedValue::forObjectRValueWithoutOwnership(SGF.emitEmptyTuple(loc));
207207
}
208208

209-
static ManagedValue emitBuiltinAssign(SILGenFunction &SGF,
210-
SILLocation loc,
211-
SubstitutionMap substitutions,
212-
ArrayRef<ManagedValue> args,
213-
SGFContext C) {
214-
assert(args.size() >= 2 && "assign should have two arguments");
209+
static ManagedValue emitBuiltinStore(SILGenFunction &SGF, SILLocation loc,
210+
SubstitutionMap substitutions,
211+
ArrayRef<ManagedValue> args, SGFContext C,
212+
bool isStrict, bool isInvariant,
213+
llvm::MaybeAlign alignment) {
214+
assert(args.size() >= 2 && "should have two arguments");
215215
assert(substitutions.getReplacementTypes().size() == 1 &&
216-
"assign should have a single substitution");
216+
"should have a single substitution");
217217

218218
// The substitution determines the type of the thing we're destroying.
219-
CanType assignFormalType =
220-
substitutions.getReplacementTypes()[0]->getCanonicalType();
221-
SILType assignType = SGF.getLoweredType(assignFormalType);
222-
219+
CanType formalTy = substitutions.getReplacementTypes()[0]->getCanonicalType();
220+
SILType loweredTy = SGF.getLoweredType(formalTy);
221+
223222
// Convert the destination pointer argument to a SIL address.
224-
SILValue addr = SGF.B.createPointerToAddress(loc,
225-
args.back().getUnmanagedValue(),
226-
assignType.getAddressType(),
227-
/*isStrict*/ true,
228-
/*isInvariant*/ false);
229-
230-
// Build the value to be assigned, reconstructing tuples if needed.
231-
auto src = RValue(SGF, args.slice(0, args.size() - 1), assignFormalType);
232-
223+
SILValue addr = SGF.B.createPointerToAddress(
224+
loc, args.back().getUnmanagedValue(), loweredTy.getAddressType(),
225+
isStrict, isInvariant, alignment);
226+
227+
// Build the value to be stored, reconstructing tuples if needed.
228+
auto src = RValue(SGF, args.slice(0, args.size() - 1), formalTy);
229+
233230
std::move(src).ensurePlusOne(SGF, loc).assignInto(SGF, loc, addr);
234231

235232
return ManagedValue::forObjectRValueWithoutOwnership(SGF.emitEmptyTuple(loc));
236233
}
237234

235+
static ManagedValue emitBuiltinAssign(SILGenFunction &SGF, SILLocation loc,
236+
SubstitutionMap substitutions,
237+
ArrayRef<ManagedValue> args,
238+
SGFContext C) {
239+
return emitBuiltinStore(SGF, loc, substitutions, args, C, /*isStrict=*/true,
240+
/*isInvariant=*/false, llvm::MaybeAlign());
241+
}
242+
243+
static ManagedValue emitBuiltinStoreRaw(SILGenFunction &SGF, SILLocation loc,
244+
SubstitutionMap substitutions,
245+
ArrayRef<ManagedValue> args,
246+
SGFContext C) {
247+
return emitBuiltinStore(SGF, loc, substitutions, args, C, /*isStrict=*/false,
248+
/*isInvariant=*/false, llvm::MaybeAlign(1));
249+
}
250+
238251
/// Emit Builtin.initialize by evaluating the operand directly into
239252
/// the address.
240253
static ManagedValue emitBuiltinInit(SILGenFunction &SGF,

stdlib/public/core/UnsafeRawPointer.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,12 +1316,7 @@ public struct UnsafeMutableRawPointer: _Pointer {
13161316
public func storeBytes<T : _BitwiseCopyable>(
13171317
of value: T, toByteOffset offset: Int = 0, as type: T.Type
13181318
) {
1319-
withUnsafePointer(to: value) { source in
1320-
_memcpy(
1321-
dest: (self + offset),
1322-
src: source,
1323-
size: UInt(MemoryLayout<T>.size))
1324-
}
1319+
Builtin.storeRaw(value, (self + offset)._rawValue)
13251320
}
13261321
#endif
13271322
@inlinable

test/SILOptimizer/builtins.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swift-frontend -enable-builtin-module -O -emit-sil %s | %FileCheck %s
2+
3+
import Builtin
4+
5+
// CHECK-LABEL: sil @storeBytes_BitwiseCopyable : {{.*}} {
6+
// CHECK: bb0(
7+
// CHECK-SAME: [[SELF:%[^,]+]] : $UnsafeMutableRawPointer,
8+
// CHECK-SAME: [[VALUE:%[^,]+]] : $*T,
9+
// CHECK-SAME: [[OFFSET:%[^,]+]] : $Int,
10+
// CHECK-SAME: {{%[^,]+}} : $@thick T.Type):
11+
// CHECK: [[SELF_RAW_VALUE:%[^,]+]] = struct_extract [[SELF]] : {{.*}} #UnsafeMutableRawPointer._rawValue
12+
// CHECK: [[OFFSET_VALUE:%[^,]+]] = struct_extract [[OFFSET]] : {{.*}} #Int._value
13+
// CHECK: [[OFFSET_WORD:%[^,]+]] = builtin "truncOrBitCast_Int64_Word"([[OFFSET_VALUE]] : $Builtin.Int64)
14+
// CHECK: [[DESTINATION_POINTER:%[^,]+]] = index_raw_pointer [[SELF_RAW_VALUE]] : $Builtin.RawPointer, [[OFFSET_WORD]]
15+
// CHECK: [[DESTINATION:%[^,]+]] = pointer_to_address [[DESTINATION_POINTER]] : $Builtin.RawPointer to [align=1]
16+
// CHECK: copy_addr [[VALUE]] to [[DESTINATION]]
17+
// CHECK-LABEL: } // end sil function 'storeBytes_BitwiseCopyable'
18+
@_silgen_name("storeBytes_BitwiseCopyable")
19+
public func storeBytes<T : _BitwiseCopyable>(
20+
_ self: UnsafeMutableRawPointer,
21+
of value: T, toByteOffset offset: Int = 0, as type: T.Type
22+
) {
23+
Builtin.storeRaw(value, (self + offset)._rawValue)
24+
}

0 commit comments

Comments
 (0)