diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index d172628b8a5d7..2573c3f448690 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -1137,6 +1137,17 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, ptr = IGF.Builder.CreateBitCast(ptr, valueTy.second.getStorageType()->getPointerTo()); Address array = valueTy.second.getAddressForPointer(ptr); + + // If the count is statically known to be a constant 1, then just call the + // type's destroy instead of the array variant. + if (auto ci = dyn_cast(count)) { + if (ci->isOne()) { + bool isOutlined = false; + valueTy.second.destroy(IGF, array, valueTy.first, isOutlined); + return; + } + } + valueTy.second.destroyArray(IGF, array, count, valueTy.first); return; } diff --git a/stdlib/public/core/UnsafePointer.swift b/stdlib/public/core/UnsafePointer.swift index d5522e07e6b65..6990626b50f4c 100644 --- a/stdlib/public/core/UnsafePointer.swift +++ b/stdlib/public/core/UnsafePointer.swift @@ -1166,8 +1166,8 @@ extension UnsafeMutablePointer where Pointee: ~Copyable { @discardableResult public func deinitialize(count: Int) -> UnsafeMutableRawPointer { _debugPrecondition(count >= 0, "UnsafeMutablePointer.deinitialize with negative count") - // TODO: IRGen optimization when `count` value is statically known to be 1, - // then call `Builtin.destroy(Pointee.self, _rawValue)` instead. + // Note: When count is statically known to be 1 the compiler will optimize + // away a call to swift_arrayDestroy into the type's specific destroy. Builtin.destroyArray(Pointee.self, _rawValue, count._builtinWordValue) return UnsafeMutableRawPointer(self) } diff --git a/test/IRGen/builtins.swift b/test/IRGen/builtins.swift index 84a5b796b4a5a..d758ef180298a 100644 --- a/test/IRGen/builtins.swift +++ b/test/IRGen/builtins.swift @@ -456,6 +456,26 @@ func destroyGenArray(_ array: Builtin.RawPointer, count: Builtin.Word, _: T) Builtin.destroyArray(T.self, array, count) } +// CHECK-LABEL: define hidden {{.*}}void @"$s8builtins21destroyArraySinglePODyyBpF"(ptr %0) +// CHECK-NOT: call void @swift_arrayDestroy +func destroyArraySinglePOD(_ array: Builtin.RawPointer) { + Builtin.destroyArray(Int.self, array, 1._builtinWordValue) +} + +// CHECK-LABEL: define hidden {{.*}}void @"$s8builtins24destroyArraySingleNonPODyyBpF"(ptr %0) +// CHECK-NOT: call void @swift_arrayDestroy +// CHECK: [[TO_DESTROY:%.*]] = load ptr, ptr {{%.*}} +// CHECK: call void @swift_release(ptr [[TO_DESTROY]]) +func destroyArraySingleNonPOD(_ array: Builtin.RawPointer) { + Builtin.destroyArray(C.self, array, 1._builtinWordValue) +} + +// CHECK-LABEL: define hidden {{.*}}void @"$s8builtins21destroyArraySingleGenyyBp_xmtlF"(ptr %0, ptr %1, ptr %T) +// CHECK-NOT: call void @swift_arrayDestroy +// CHECK: call void {{%.*}}(ptr {{.*}} {{%.*}}, ptr %T) +func destroyArraySingleGen(_ array: Builtin.RawPointer, _: T.Type) { + Builtin.destroyArray(T.self, array, 1._builtinWordValue) +} // CHECK-LABEL: define hidden {{.*}}void @"$s8builtins12copyPODArray{{[_0-9a-zA-Z]*}}F"(ptr %0, ptr %1, i64 %2) // check: mul nuw i64 4, %2