mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Remove the substitution map from zeroInitializer builtin in SIL.
This is a value operation that can work just fine on lowered types, so there's no need to carry along a formal type. Make the value/address duality clearer, and enforce it in the verifier.
This commit is contained in:
@@ -719,9 +719,6 @@ BUILTIN_MISC_OPERATION(IsNegative, "isNegative", "n", Special)
|
||||
/// (_ value: Builtin.IntLiteral, _ index: Builtin.Word) -> Builtin.Word
|
||||
BUILTIN_MISC_OPERATION(WordAtIndex, "wordAtIndex", "n", Special)
|
||||
|
||||
/// zeroInitializer has type <T> () -> T
|
||||
BUILTIN_MISC_OPERATION(ZeroInitializer, "zeroInitializer", "n", Special)
|
||||
|
||||
/// once has type (Builtin.RawPointer, (Builtin.RawPointer) -> ())
|
||||
BUILTIN_MISC_OPERATION(Once, "once", "", Special)
|
||||
/// onceWithContext has type (Builtin.RawPointer, (Builtin.RawPointer) -> (), Builtin.RawPointer)
|
||||
@@ -842,6 +839,10 @@ BUILTIN_MISC_OPERATION_WITH_SILGEN(Strideof, "strideof", "n", Special)
|
||||
/// Alignof has type T.Type -> Int
|
||||
BUILTIN_MISC_OPERATION_WITH_SILGEN(Alignof, "alignof", "n", Special)
|
||||
|
||||
/// zeroInitializer has type <T> () -> T, but the SIL builtin has its
|
||||
/// own rules.
|
||||
BUILTIN_MISC_OPERATION_WITH_SILGEN(ZeroInitializer, "zeroInitializer", "n", Special)
|
||||
|
||||
// getCurrentExecutor: () async -> Builtin.Executor?
|
||||
//
|
||||
// Retrieve the SerialExecutorRef on which the current asynchronous
|
||||
|
||||
@@ -2422,6 +2422,16 @@ public:
|
||||
valueType, paramType));
|
||||
}
|
||||
|
||||
/// Create a zero-initialized value of the given (loadable) type.
|
||||
///
|
||||
/// This is currently only expected to be used in narrow situations
|
||||
/// involving bridging and only makes a best effort attempt.
|
||||
SILValue createZeroInitValue(SILLocation loc, SILType loweredTy);
|
||||
|
||||
/// Zero-initialize an object in memory of the given type (which may
|
||||
/// or may not be loadable).
|
||||
BuiltinInst *createZeroInitAddr(SILLocation loc, SILValue addr);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Unchecked cast helpers
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
@@ -1327,18 +1327,18 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
|
||||
}
|
||||
|
||||
if (Builtin.ID == BuiltinValueKind::ZeroInitializer) {
|
||||
// Build a zero initializer of the result type.
|
||||
auto valueTy = getLoweredTypeAndTypeInfo(IGF.IGM,
|
||||
substitutions.getReplacementTypes()[0]);
|
||||
|
||||
if (args.size() > 0) {
|
||||
auto valueType = argTypes[0];
|
||||
auto &valueTI = IGF.IGM.getTypeInfo(valueType);
|
||||
|
||||
// `memset` the memory addressed by the argument.
|
||||
auto address = args.claimNext();
|
||||
IGF.Builder.CreateMemSet(valueTy.second.getAddressForPointer(address),
|
||||
IGF.Builder.CreateMemSet(valueTI.getAddressForPointer(address),
|
||||
llvm::ConstantInt::get(IGF.IGM.Int8Ty, 0),
|
||||
valueTy.second.getSize(IGF, argTypes[0]));
|
||||
valueTI.getSize(IGF, valueType));
|
||||
} else {
|
||||
auto schema = valueTy.second.getSchema();
|
||||
auto &resultTI = cast<LoadableTypeInfo>(IGF.IGM.getTypeInfo(resultType));
|
||||
auto schema = resultTI.getSchema();
|
||||
for (auto &elt : schema) {
|
||||
out.add(llvm::Constant::getNullValue(elt.getScalarType()));
|
||||
}
|
||||
|
||||
@@ -4165,9 +4165,9 @@ protected:
|
||||
BuiltinValueKind::ZeroInitializer) {
|
||||
auto build = assignment.getBuilder(++bi->getIterator());
|
||||
auto newAddr = assignment.createAllocStack(bi->getType());
|
||||
build.createZeroInitAddr(bi->getLoc(), newAddr);
|
||||
assignment.mapValueToAddress(origValue, newAddr);
|
||||
build.createStore(bi->getLoc(), origValue, newAddr,
|
||||
StoreOwnershipQualifier::Unqualified);
|
||||
assignment.markForDeletion(bi);
|
||||
} else {
|
||||
singleValueInstructionFallback(bi);
|
||||
}
|
||||
|
||||
@@ -805,6 +805,26 @@ CheckedCastBranchInst *SILBuilder::createCheckedCastBranch(
|
||||
target2Count, forwardingOwnershipKind));
|
||||
}
|
||||
|
||||
BuiltinInst *SILBuilder::createZeroInitAddr(SILLocation loc, SILValue addr) {
|
||||
assert(addr->getType().isAddress());
|
||||
auto &C = getASTContext();
|
||||
auto zeroInit = getBuiltinValueDecl(C, C.getIdentifier("zeroInitializer"));
|
||||
return createBuiltin(loc, zeroInit->getBaseIdentifier(),
|
||||
SILType::getEmptyTupleType(C),
|
||||
SubstitutionMap(),
|
||||
addr);
|
||||
}
|
||||
|
||||
SILValue SILBuilder::createZeroInitValue(SILLocation loc, SILType loweredTy) {
|
||||
assert(loweredTy.isObject());
|
||||
auto &C = getASTContext();
|
||||
auto zeroInit = getBuiltinValueDecl(C, C.getIdentifier("zeroInitializer"));
|
||||
return createBuiltin(loc, zeroInit->getBaseIdentifier(),
|
||||
loweredTy,
|
||||
SubstitutionMap(),
|
||||
{});
|
||||
}
|
||||
|
||||
void SILBuilderWithScope::insertAfter(SILInstruction *inst,
|
||||
function_ref<void(SILBuilder &)> func) {
|
||||
if (isa<TermInst>(inst)) {
|
||||
|
||||
@@ -1009,6 +1009,11 @@ public:
|
||||
#define requireAddressType(type, value, valueDescription) \
|
||||
_requireAddressType<type>(value, valueDescription, #type)
|
||||
|
||||
void requireVoidObjectType(SILType type, const Twine &valueDescription) {
|
||||
_require(type.isObject() && type.isVoid(),
|
||||
valueDescription + " must be a scalar of type ()");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename CanTypeWrapperTraits<T>::type
|
||||
_forbidObjectType(SILType type, const Twine &valueDescription,
|
||||
@@ -2375,6 +2380,23 @@ public:
|
||||
auto builtinKind = BI->getBuiltinKind();
|
||||
auto arguments = BI->getArguments();
|
||||
|
||||
if (builtinKind == BuiltinValueKind::ZeroInitializer) {
|
||||
require(!BI->getSubstitutions(),
|
||||
"zeroInitializer has no generic arguments as a SIL builtin");
|
||||
if (arguments.size() == 0) {
|
||||
require(!fnConv.useLoweredAddresses()
|
||||
|| BI->getType().isLoadable(*BI->getFunction()),
|
||||
"scalar zeroInitializer must have a loadable result type");
|
||||
} else {
|
||||
require(arguments.size() == 1,
|
||||
"zeroInitializer cannot have multiple arguments");
|
||||
require(arguments[0]->getType().isAddress(),
|
||||
"zeroInitializer argument must have address type");
|
||||
requireVoidObjectType(BI->getType(),
|
||||
"result of zeroInitializer");
|
||||
}
|
||||
}
|
||||
|
||||
// Check that 'getCurrentAsyncTask' only occurs within an async function.
|
||||
if (builtinKind == BuiltinValueKind::GetCurrentAsyncTask) {
|
||||
require(F.isAsync(),
|
||||
|
||||
@@ -2097,6 +2097,26 @@ static ManagedValue emitBuiltinAddressOfRawLayout(SILGenFunction &SGF,
|
||||
return ManagedValue::forObjectRValueWithoutOwnership(bi);
|
||||
}
|
||||
|
||||
static ManagedValue emitBuiltinZeroInitializer(SILGenFunction &SGF,
|
||||
SILLocation loc,
|
||||
SubstitutionMap subs,
|
||||
ArrayRef<ManagedValue> args,
|
||||
SGFContext C) {
|
||||
auto valueType = subs.getReplacementTypes()[0]->getCanonicalType();
|
||||
auto &valueTL = SGF.getTypeLowering(valueType);
|
||||
auto loweredValueTy = valueTL.getLoweredType().getObjectType();
|
||||
|
||||
if (valueTL.isLoadable() ||
|
||||
!SGF.F.getConventions().useLoweredAddresses()) {
|
||||
auto value = SGF.B.createZeroInitValue(loc, loweredValueTy);
|
||||
return SGF.emitManagedRValueWithCleanup(value, valueTL);
|
||||
}
|
||||
|
||||
SILValue valueAddr = SGF.getBufferForExprResult(loc, loweredValueTy, C);
|
||||
SGF.B.createZeroInitAddr(loc, valueAddr);
|
||||
return SGF.manageBufferForExprResult(valueAddr, valueTL, C);
|
||||
}
|
||||
|
||||
static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
|
||||
SILLocation loc,
|
||||
SubstitutionMap subs,
|
||||
@@ -2129,15 +2149,7 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
|
||||
// Aside from providing a modicum of predictability if the memory isn't
|
||||
// actually initialized, this also serves to communicate to DI that the memory
|
||||
// is considered initialized from this point.
|
||||
auto zeroInit = getBuiltinValueDecl(Ctx,
|
||||
Ctx.getIdentifier("zeroInitializer"));
|
||||
SGF.B.createBuiltin(loc, zeroInit->getBaseIdentifier(),
|
||||
SILType::getEmptyTupleType(Ctx),
|
||||
SubstitutionMap::get(zeroInit->getInnermostDeclContext()
|
||||
->getGenericSignatureOfContext(),
|
||||
{resultASTTy},
|
||||
LookUpConformanceInModule()),
|
||||
buffer);
|
||||
SGF.B.createZeroInitAddr(loc, buffer);
|
||||
|
||||
SILValue bufferPtr = SGF.B.createAddressToPointer(loc, buffer,
|
||||
SILType::getPrimitiveObjectType(SGF.getASTContext().TheRawPointerType),
|
||||
|
||||
@@ -739,15 +739,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
|
||||
if (nominal->getAttrs().hasAttribute<RawLayoutAttr>()) {
|
||||
// Raw memory is not directly decomposable, but we still want to mark
|
||||
// it as initialized. Use a zero initializer.
|
||||
auto &C = ctor->getASTContext();
|
||||
auto zeroInit = getBuiltinValueDecl(C, C.getIdentifier("zeroInitializer"));
|
||||
B.createBuiltin(ctor, zeroInit->getBaseIdentifier(),
|
||||
SILType::getEmptyTupleType(C),
|
||||
SubstitutionMap::get(zeroInit->getInnermostDeclContext()
|
||||
->getGenericSignatureOfContext(),
|
||||
{selfDecl->getTypeInContext()},
|
||||
LookUpConformanceInModule()),
|
||||
selfLV.getLValueAddress());
|
||||
B.createZeroInitAddr(ctor, selfLV.getLValueAddress());
|
||||
} else if (isa<StructDecl>(nominal)
|
||||
&& lowering.getLoweredType().isMoveOnly()
|
||||
&& nominal->getStoredProperties().empty()) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Make sure that the SIL ownership verifier passes.
|
||||
// UnsafeUnretainedBlockClass.init()
|
||||
// CHECK-LABEL: sil hidden @$s16objc_init_blocks26UnsafeUnretainedBlockClassCACycfc : $@convention(method) (@owned UnsafeUnretainedBlockClass) -> @owned UnsafeUnretainedBlockClass {
|
||||
// CHECK: [[ZI:%.*]] = builtin "zeroInitializer"<objc_bool_block>() : $objc_bool_block
|
||||
// CHECK: [[ZI:%.*]] = builtin "zeroInitializer"() : $objc_bool_block
|
||||
// CHECK: store [[ZI]] to %{{.*}} : $*objc_bool_block
|
||||
// CHECK-LABEL: } // end sil function '$s16objc_init_blocks26UnsafeUnretainedBlockClassCACycfc'
|
||||
open class UnsafeUnretainedBlockClass {
|
||||
|
||||
@@ -1289,18 +1289,18 @@ bb0(%0 : $*C, %1 : $*C, %2 : @owned $C):
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
@@ -1312,18 +1312,18 @@ bb0:
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicload
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer_atomicload : $@convention(thin) () -> Builtin.Int64 {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
@@ -1336,18 +1336,18 @@ bb0:
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicstore
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer_atomicstore : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
@@ -1362,18 +1362,18 @@ bb0:
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicrmw
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer_atomicrmw : $@convention(thin) () -> (Builtin.Int64, Builtin.Int64) {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
@@ -1389,18 +1389,18 @@ bb0:
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer_cmpxchg
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer_cmpxchg : $@convention(thin) () -> (Builtin.Int64, Builtin.Int1) {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
@@ -1414,18 +1414,18 @@ bb0:
|
||||
|
||||
// CHECK-LABEL: @test_builtin_zeroInitializer_fence
|
||||
// CHECK: PAIR #0.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %0 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=0
|
||||
// CHECK: PAIR #1.
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
|
||||
// CHECK-NEXT: %2 = builtin "zeroInitializer"(%1 : $*C)
|
||||
// CHECK-NEXT: %1 = alloc_stack
|
||||
// CHECK-NEXT: r=0,w=1
|
||||
sil @test_builtin_zeroInitializer_fence : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $C
|
||||
%1 = alloc_stack $C
|
||||
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
|
||||
%2 = builtin "zeroInitializer"(%1 : $*C) : $()
|
||||
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
|
||||
copy_addr [take] %1 to [init] %0 : $*C
|
||||
dealloc_stack %1 : $*C
|
||||
|
||||
@@ -20,7 +20,7 @@ struct Lock: ~Copyable {
|
||||
// CHECK-NEXT: sil{{.*}} @[[INIT:\$.*4LockV.*fC]] :
|
||||
init() {
|
||||
// CHECK-NOT: destroy_addr
|
||||
// CHECK: builtin "zeroInitializer"<Lock>
|
||||
// CHECK: builtin "zeroInitializer"({{%.*}} : $*Lock)
|
||||
// CHECK-NOT: destroy_addr
|
||||
// CHECK: [[F:%.*]] = function_ref @init_lock
|
||||
// CHECK: apply [[F]](
|
||||
|
||||
@@ -20,7 +20,7 @@ public struct Cell<T: ~Copyable>: ~Copyable {
|
||||
|
||||
// CHECK-LABEL: sil {{.*}} @$s4CellAAVAARi_zrlEyAByxGxcfC : $@convention(method) <T where T : ~Copyable> (@in T, @thin Cell<T>.Type) -> @out Cell<T> {
|
||||
// CHECK: bb0({{%.*}} : $*Cell<T>, [[VALUE:%.*]] : $*T, {{%.*}} : $@thin Cell<T>.Type):
|
||||
// CHECK: {{%.*}} = builtin "zeroInitializer"<Cell<T>>([[SELF:%.*]] : $*Cell<T>) : $()
|
||||
// CHECK: {{%.*}} = builtin "zeroInitializer"([[SELF:%.*]] : $*Cell<T>) : $()
|
||||
// CHECK-NEXT: [[RAW_LAYOUT_ADDR:%.*]] = builtin "addressOfRawLayout"<Cell<T>>([[SELF]] : $*Cell<T>) : $Builtin.RawPointer
|
||||
// CHECK-NEXT: [[POINTER:%.*]] = struct $UnsafeMutablePointer<T> ([[RAW_LAYOUT_ADDR]] : $Builtin.RawPointer)
|
||||
// Calling 'UnsafeMutablePointer<T>.initialize(to:)'
|
||||
|
||||
@@ -254,13 +254,13 @@ bb0(%0 : $*T, %1 : $*T):
|
||||
|
||||
// CHECK-LABEL: sil @optimize_builtin_zeroInitialize : {{.*}} {
|
||||
// CHECK: bb0([[RET_ADDR:%[^,]+]] :
|
||||
// CHECK: builtin "zeroInitializer"<T>([[RET_ADDR]] : $*T) : $()
|
||||
// CHECK: builtin "zeroInitializer"([[RET_ADDR]] : $*T) : $()
|
||||
// CHECK: apply undef<T>([[RET_ADDR]])
|
||||
// CHECK-LABEL: } // end sil function 'optimize_builtin_zeroInitialize'
|
||||
sil @optimize_builtin_zeroInitialize : $@convention(thin) <T> () -> @out T {
|
||||
bb0(%ret_addr : $*T):
|
||||
%temporary = alloc_stack [lexical] $T
|
||||
builtin "zeroInitializer"<T>(%temporary : $*T) : $()
|
||||
builtin "zeroInitializer"(%temporary : $*T) : $()
|
||||
apply undef<T>(%temporary) : $@convention(thin) <T> () -> @out T
|
||||
copy_addr [take] %temporary to [init] %ret_addr : $*T
|
||||
dealloc_stack %temporary : $*T
|
||||
|
||||
Reference in New Issue
Block a user