From 6d86c17ff596b080abd7a7d536ee218b04ca11c2 Mon Sep 17 00:00:00 2001 From: zoecarver Date: Sun, 28 Jun 2020 10:52:00 -0700 Subject: [PATCH] [IRGen] [Builtin] Update zeroInitializer to support addresses. Adds support for addresses in `Builtin.zeroInitializer`. If an address is passed as the first (and only) argument, it will be zero'd out with a memset. This will "fix" the C++ default constructor for address types. --- lib/IRGen/GenBuiltin.cpp | 18 +++++- .../builtin-zero-initializer-address.sil | 58 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/IRGen/builtin-zero-initializer-address.sil diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index d97c0dd3f8e29..4a3e84e1e4f61 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -980,9 +980,21 @@ if (Builtin.ID == BuiltinValueKind::id) { \ } if (Builtin.ID == BuiltinValueKind::ZeroInitializer) { - // Build a zero initializer of the result type. - auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, - substitutions.getReplacementTypes()[0]); + auto genericArg = substitutions.getReplacementTypes()[0]; + auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM, genericArg); + // If the builtin returns void (and the generic argument isn't void), this + // is an address. + if (resultType.isVoid() && !genericArg->isVoid()) { + // The first (and only) argument will be a pointer. All we need to do is + // null it out. + IGF.Builder.CreateMemSet( + args.claimNext(), llvm::ConstantInt::get(IGF.IGM.Int8Ty, 0), + valueTy.second.getSize(IGF, valueTy.first), + llvm::MaybeAlign(valueTy.second.getBestKnownAlignment())); + return; + } + + // Otherwise, build a zero initializer of the result type. auto schema = valueTy.second.getSchema(); for (auto &elt : schema) { out.add(llvm::Constant::getNullValue(elt.getScalarType())); diff --git a/test/IRGen/builtin-zero-initializer-address.sil b/test/IRGen/builtin-zero-initializer-address.sil new file mode 100644 index 0000000000000..3e02d28720dd5 --- /dev/null +++ b/test/IRGen/builtin-zero-initializer-address.sil @@ -0,0 +1,58 @@ +// RUN: %swift -module-name main %s -emit-ir | %FileCheck %s + +import Builtin + +// CHECK-LABEL: define swiftcc void @test_trivial_type +// CHECK: [[I32PTR:%.*]] = alloca i32, align 4 +// CHECK: [[I8PTR:%.*]] = bitcast i32* [[I32PTR]] to i8* +// CHECK: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[I8PTR]]) +// CHECK: [[I8PTR2:%.*]] = bitcast i32* [[I32PTR]] to i8* +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 4 [[I8PTR2]], i8 0, i64 4, i1 false) +// CHECK: ret void +sil @test_trivial_type : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $Builtin.Int32 + %1 = builtin "zeroInitializer"(%0 : $*Builtin.Int32) : $() + dealloc_stack %0 : $*Builtin.Int32 + %t = tuple () + return %t : $() +} + +// CHECK-LABEL: define swiftcc void @test_object_type +// CHECK: [[PTR:%.*]] = alloca %AnyObject, align 8 +// CHECK: [[I8PTR:%.*]] = bitcast %AnyObject* [[PTR]] to i8* +// CHECK: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[I8PTR]]) +// CHECK: [[I8PTR2:%.*]] = bitcast %AnyObject* [[PTR]] to i8* +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 8 [[I8PTR2]], i8 0, i64 8, i1 false) +// CHECK: ret void +sil @test_object_type : $@convention(thin) () -> () { +bb0: + %0 = alloc_stack $Builtin.AnyObject + %1 = builtin "zeroInitializer"(%0 : $*Builtin.AnyObject) : $() + dealloc_stack %0 : $*Builtin.AnyObject + %t = tuple () + return %t : $() +} + +// CHECK_LABEL: define swiftcc void @test_generic (%swift.type* %0, %swift.type* %T) +// CHECK: [[TYPE_PTR:%.*]] = bitcast %swift.type* %T to i8*** +// CHECK: [[WITNESS_PTR:%.*]] = getelementptr inbounds i8**, i8*** [[TYPE_PTR:%.*]], i64 -1 +// CHECK: [[T_WITNESS:%.*]] = load i8**, i8*** [[WITNESS_PTR]] +// CHECK: [[WITNESS:%.*]] = bitcast i8** [[T_WITNESS]] to %swift.vwtable* +// CHECK: [[SIZE_PTR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[WITNESS]], i32 0, i32 8 +// CHECK: [[SIZE:%.*]] = load i64, i64* [[SIZE_PTR]] +// CHECK: [[SIZE_TMP:%.*]] = alloca i8, i64 %size +// CHECK: call void @llvm.lifetime.start.p0i8(i64 -1, i8* [[SIZE_TMP]]) +// CHECK: [[OBJECT_PTR:%.*]] = bitcast i8* [[SIZE_TMP]] to %swift.opaque* +// CHECK: [[OBJECT_RAW_PTR:%.*]] = bitcast %swift.opaque* [[OBJECT_PTR]] to i8* +// CHECK: call void @llvm.memset.p0i8.i64(i8* align 1 [[OBJECT_RAW_PTR]], i8 0, i64 [[SIZE]], i1 false) +// CHECK: ret void +sil @test_generic : $@convention(thin) (@thick T.Type) -> () { +bb0(%0 : $@thick T.Type): + %1 = alloc_stack $T + %2 = builtin "zeroInitializer"(%1 : $*T) : $() + destroy_addr %1 : $*T + dealloc_stack %1 : $*T + %t = tuple () + return %t : $() +}