diff --git a/include/swift/SIL/SILFunctionConventions.h b/include/swift/SIL/SILFunctionConventions.h index b80dfe77a061..bae6d44124c5 100644 --- a/include/swift/SIL/SILFunctionConventions.h +++ b/include/swift/SIL/SILFunctionConventions.h @@ -515,6 +515,9 @@ class SILFunctionConventions { - getNumIndirectSILErrorResults()]; } + /// WARNING: Do not use this from SILGen! + /// Use methods such as `isSILIndirect` or query the ParameterInfo instead. + /// /// Return the SIL argument convention of apply/entry argument at /// the given argument index. SILArgumentConvention getSILArgumentConvention(unsigned index) const; diff --git a/lib/SIL/IR/SILArgument.cpp b/lib/SIL/IR/SILArgument.cpp index 3cbfc18e350b..ed4af8004f03 100644 --- a/lib/SIL/IR/SILArgument.cpp +++ b/lib/SIL/IR/SILArgument.cpp @@ -87,6 +87,8 @@ SILParameterInfo SILFunctionArgument::getKnownParameterInfo() const { return getFunction()->getConventions().getParamInfoForSILArg(getIndex()); } +/// WARNING: Do not use this from SILGen! +/// Use methods such as `isSILIndirect` or query the ParameterInfo instead. SILArgumentConvention SILFunctionConventions::getSILArgumentConvention(unsigned index) const { assert(index < getNumSILArguments()); diff --git a/lib/SIL/Verifier/SILVerifier.cpp b/lib/SIL/Verifier/SILVerifier.cpp index 10bfceda8607..93bc0bc25d51 100644 --- a/lib/SIL/Verifier/SILVerifier.cpp +++ b/lib/SIL/Verifier/SILVerifier.cpp @@ -3189,9 +3189,9 @@ class SILVerifier : public SILVerifierBase { CanSILFunctionType initTy = initFn->getType().castTo(); SILFunctionConventions initConv(initTy, AI->getModule()); - require(initConv.getNumIndirectSILResults() == + require(initConv.getResults().size() == AI->getNumInitializedProperties(), - "init function has invalid number of indirect results"); + "init function has invalid number of results"); checkAssigOrInitInstAccessorArgs(Src->getType(), initConv); } diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 7268ea79891a..e0b9e13ef815 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -1822,35 +1822,46 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor( RegularLocation Loc(value); Loc.markAutoGenerated(); - auto loweredFuncDeclTy = F.getLoweredFunctionType(); - bool isLocalContext = vd->getDeclContext()->isLocalContext(); - - auto createArgument = [&](VarDecl *property, SILType type, - bool markUninitialized = false) { - auto *arg = ParamDecl::createImplicit( - getASTContext(), property->getBaseIdentifier(), - property->getBaseIdentifier(), property->getInterfaceType(), - declContext, ParamSpecifier::InOut); - - RegularLocation loc(property); - loc.markAutoGenerated(); - - SILValue argValue = F.begin()->createFunctionArgument(type, arg); - if (markUninitialized) { - argValue = B.createMarkUninitializedOut(loc, argValue); - } + auto backingStorage = vd->getPropertyWrapperBackingProperty(); + Type returnTy = vd->getPropertyWrapperBackingPropertyType(); + + /// This thunk uses its own return convention, unlike a usual function, + /// by always returning its result indirect, even if the type is trivial. + /// + /// Because of that, much of the work that would normally be handled in SILGen + /// using standard function conventions is done manually here, when + /// -enable-sil-opaque-values is disabled. Part of the reason for this is + /// that calls to this accessor are lowered after DefiniteInitialization. + if (useLoweredAddresses()) { + returnTy = TupleType::getEmpty(F.getASTContext()); + + auto loweredFuncDeclTy = F.getLoweredFunctionType(); + auto createArgument = [&](VarDecl *property, SILType type, + bool markUninitialized = false) { + auto *arg = ParamDecl::createImplicit( + getASTContext(), property->getBaseIdentifier(), + property->getBaseIdentifier(), property->getInterfaceType(), + declContext, ParamSpecifier::InOut); + + RegularLocation loc(property); + loc.markAutoGenerated(); + + SILValue argValue = F.begin()->createFunctionArgument(type, arg); + if (markUninitialized) { + argValue = B.createMarkUninitializedOut(loc, argValue); + } - VarLocs[arg] = VarLoc(argValue, SILAccessEnforcement::Static); - InitAccessorArgumentMappings[property] = arg; - }; + VarLocs[arg] = VarLoc(argValue, SILAccessEnforcement::Static); + InitAccessorArgumentMappings[property] = arg; + }; - // Emit @out backing storage argument - auto backingStorage = vd->getPropertyWrapperBackingProperty(); - auto backingStorageTy = getSILTypeInContext( - loweredFuncDeclTy->getResults()[0], loweredFuncDeclTy); - createArgument(backingStorage, backingStorageTy, /*markUninitialized=*/true); + // Emit @out backing storage argument + auto backingStorageTy = getSILTypeInContext( + loweredFuncDeclTy->getResults()[0], loweredFuncDeclTy); + createArgument(backingStorage, backingStorageTy, /*markUninitialized=*/true); + } - // Emit `newValue` argument + // Create the `newValue` argument ParameterList *params = nullptr; auto newValueParam = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), ctx.getIdentifier("$input_value"), @@ -1864,9 +1875,10 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor( // Nominal contexts have an extra trailing metatype argument, // local contexts do not + const bool isLocalContext = vd->getDeclContext()->isLocalContext(); auto numIgnoredParams = isLocalContext ? 0 : 1; emitBasicProlog(declContext, params, - /*selfParam=*/nullptr, TupleType::getEmpty(F.getASTContext()), + /*selfParam=*/nullptr, returnTy, /*errorType=*/std::nullopt, /*throwsLoc=*/SourceLoc(), /*ignored parameters*/ numIgnoredParams); @@ -1875,9 +1887,14 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor( if (!isLocalContext) emitConstructorMetatypeArg(*this, vd); - prepareEpilog(declContext, TupleType::getEmpty(F.getASTContext()), + prepareEpilog(declContext, returnTy, std::nullopt, CleanupLocation(Loc)); + if (EmitProfilerIncrement) + emitProfilerIncrement(value); + + FullExpr scope(Cleanups, CleanupLocation(value)); + // Create an opaque value binding that maps 'newValue' to the wrapper's // wrappedValue AST placeholder. This makes the argument available when // init(wrappedValue:) is emitted @@ -1889,16 +1906,19 @@ void SILGenFunction::emitPropertyWrappedFieldInitAccessor( maybeEmitValueOfLocalVarDecl(newValueParam, AccessKind::Read)); assert(value == initInfo.getInitFromWrappedValue()); - // Prepare InitializationPtr for the @out return buffer - FullExpr scope(Cleanups, CleanupLocation(value)); - auto backingStorageArg = InitAccessorArgumentMappings[backingStorage]; - auto backingStorageAddr = VarLocs[backingStorageArg].value; - InitializationPtr init(new KnownAddressInitialization(backingStorageAddr)); + if (useLoweredAddresses()) { + // Prepare InitializationPtr for the @out return buffer + auto backingStorageArg = InitAccessorArgumentMappings[backingStorage]; + auto backingStorageAddr = VarLocs[backingStorageArg].value; + InitializationPtr init(new KnownAddressInitialization(backingStorageAddr)); - // Intialize the @out buffer with the given expression - emitExprInto(value, init.get()); + // Intialize the @out buffer with the given expression + emitExprInto(value, init.get()); + } else { + emitReturnExpr(Loc, value); + } // Emit epilog/cleanups emitEpilog(Loc); mergeCleanupBlocks(); -} \ No newline at end of file +} diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index db567b68fc62..493f50c02cea 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -1883,9 +1883,10 @@ SILGenFunction::emitApplyOfSetterToBase(SILLocation loc, SILDeclRef setter, assert(base); SILValue capturedBase; - unsigned argIdx = setterConv.getNumSILArguments() - 1; + unsigned argIdx = setterConv.getSILArgIndexOfSelf(); + auto paramInfo = setterConv.getParamInfoForSILArg(argIdx); - if (setterConv.getSILArgumentConvention(argIdx).isInoutConvention()) { + if (paramInfo.isIndirectMutating()) { capturedBase = base.getValue(); } else if (base.getType().isAddress() && base.getType().getObjectType() == @@ -1975,9 +1976,9 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue, SILFunctionConventions initConv(initTy, SGM.M); auto newValueArgIdx = initConv.getSILArgIndexOfFirstParam(); + auto newValueParamInfo = initConv.getParamInfoForSILArg(newValueArgIdx); // If we need the argument in memory, materialize an address. - if (initConv.getSILArgumentConvention(newValueArgIdx) - .isIndirectConvention() && + if (initConv.isSILIndirect(newValueParamInfo) && !newValue.getType().isAddress()) { newValue = newValue.materialize(*this, loc); } diff --git a/lib/SILGen/SILGenLValue.cpp b/lib/SILGen/SILGenLValue.cpp index 9a24b81873af..e3d577517f51 100644 --- a/lib/SILGen/SILGenLValue.cpp +++ b/lib/SILGen/SILGenLValue.cpp @@ -1528,8 +1528,10 @@ namespace { return cast(Accessor.getFuncDecl()); } - ManagedValue emitValue(SILGenFunction &SGF, SILLocation loc, VarDecl *field, - ArgumentSource &&value, AccessorKind accessorKind) { + ManagedValue emitValueForAssignOrInit(SILGenFunction &SGF, SILLocation loc, + VarDecl *field, + ArgumentSource &&value, + AccessorKind accessorKind) { auto accessorInfo = SGF.getConstantInfo( SGF.getTypeExpansionContext(), SILDeclRef(field->getOpaqueAccessor(accessorKind))); @@ -1553,7 +1555,8 @@ namespace { assert(value.isRValue()); ManagedValue Mval = std::move(value).asKnownRValue(SGF).getAsSingleValue(SGF, loc); - auto param = accessorTy->getParameters()[0]; + auto paramIdx = accessorConv.getSILArgIndexOfFirstParam(); + auto param = accessorConv.getParamInfoForSILArg(paramIdx); SILType loweredSubstArgType = Mval.getType(); if (param.isIndirectInOut()) { loweredSubstArgType = @@ -1572,11 +1575,8 @@ namespace { fieldTy->getCanonicalType()); } - auto newValueArgIdx = accessorConv.getNumIndirectSILResults(); // If we need the argument in memory, materialize an address. - if (accessorConv.getSILArgumentConvention(newValueArgIdx) - .isIndirectConvention() && - !Mval.getType().isAddress()) { + if (accessorConv.isSILIndirect(param) && !Mval.getType().isAddress()) { Mval = Mval.materialize(SGF, loc); } @@ -1610,7 +1610,7 @@ namespace { override { VarDecl *field = cast(Storage); auto Mval = - emitValue(SGF, loc, field, std::move(value), AccessorKind::Init); + emitValueForAssignOrInit(SGF, loc, field, std::move(value), AccessorKind::Init); SGF.emitAssignOrInit(loc, base, field, Mval, Substitutions); } @@ -1875,7 +1875,7 @@ namespace { // Create the assign_or_init SIL instruction auto Mval = - emitValue(SGF, loc, field, std::move(value), AccessorKind::Set); + emitValueForAssignOrInit(SGF, loc, field, std::move(value), AccessorKind::Set); auto selfOrLocal = selfMetatype ? base.getValue() : proj.forward(SGF); SGF.B.createAssignOrInit(loc, field, selfOrLocal, Mval.forward(SGF), initFn.getValue(), setterFn, diff --git a/lib/SILGen/SILGenProlog.cpp b/lib/SILGen/SILGenProlog.cpp index ff89141e0151..cc1f80205421 100644 --- a/lib/SILGen/SILGenProlog.cpp +++ b/lib/SILGen/SILGenProlog.cpp @@ -1331,11 +1331,9 @@ static void emitCaptureArguments(SILGenFunction &SGF, case CaptureKind::Immutable: { auto argIndex = SGF.F.begin()->getNumArguments(); // Non-escaping stored decls are captured as the address of the value. - auto argConv = SGF.F.getConventions().getSILArgumentConvention(argIndex); - bool isInOut = (argConv == SILArgumentConvention::Indirect_Inout || - argConv == SILArgumentConvention::Indirect_InoutAliasable); - auto param = SGF.F.getConventions().getParamInfoForSILArg(argIndex); - if (SGF.F.getConventions().isSILIndirect(param)) { + auto fnConv = SGF.F.getConventions(); + auto paramInfo = fnConv.getParamInfoForSILArg(argIndex); + if (fnConv.isSILIndirect(paramInfo)) { ty = ty.getAddressType(); } auto *fArg = SGF.F.begin()->createFunctionArgument(ty, VD); @@ -1343,7 +1341,8 @@ static void emitCaptureArguments(SILGenFunction &SGF, arg = SILValue(fArg); if (isNoImplicitCopy && !arg->getType().isMoveOnly()) { - switch (argConv) { + // FIXME: this incompatible with -enable-sil-opaque-values + switch (fnConv.getSILArgumentConvention(argIndex)) { case SILArgumentConvention::Indirect_Inout: case SILArgumentConvention::Indirect_InoutAliasable: case SILArgumentConvention::Indirect_In: @@ -1377,6 +1376,7 @@ static void emitCaptureArguments(SILGenFunction &SGF, // in SIL since it is illegal to capture an inout value in an escaping // closure. The later code knows how to handle that we have the // mark_unresolved_non_copyable_value here. + bool isInOut = paramInfo.isIndirectMutating(); if (isInOut && arg->getType().isMoveOnly()) { arg = SGF.B.createMarkUnresolvedNonCopyableValueInst( Loc, arg, diff --git a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp index 79e4a949e014..28890bfc75eb 100644 --- a/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp +++ b/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp @@ -206,8 +206,8 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b, auto inLocalContext = inst->getProperty()->getDeclContext()->isLocalContext(); - auto selfOrLocalValue = inst->getSelfOrLocalOperand(); - bool isRefSelf = + const auto selfOrLocalValue = inst->getSelfOrLocalOperand(); + const bool isRefSelf = selfOrLocalValue->getType().getASTType()->mayHaveSuperclass(); auto emitFieldReference = [&](SILValue selfRef, VarDecl *field, @@ -225,40 +225,58 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b, return fieldRef; }; - SmallVector arguments; + /// Returns the reference of self ready for modification, and a flag + /// indicating whether a begin_access was emitted that must be ended. + auto emitBeginModifyOfSelf = [&]() -> std::pair { + if (isRefSelf) + return {b.emitBeginBorrowOperation(loc, selfOrLocalValue), false}; + + // Don't insert an access scope if there is already one. This avoids + // inserting a dynamic access check when the parent is static (and + // therefore can be statically enforced). + if (auto *bai = dyn_cast(selfOrLocalValue)) { + bai->setAccessKind(SILAccessKind::Modify); + return {selfOrLocalValue, false}; + } + + return {b.createBeginAccess(loc, selfOrLocalValue, + SILAccessKind::Modify, + SILAccessEnforcement::Dynamic, + /*noNestedConflict=*/false, + /*fromBuiltin=*/false), + /*needsEndAccess=*/true}; + }; + + auto initializeAddress = [&b](SILLocation loc, SILValue src, SILValue dest) { + ASSERT(dest->getType().isAddress()); + auto qualifier = src->getType().isTrivial(b.getFunction()) + ? StoreOwnershipQualifier::Trivial + : StoreOwnershipQualifier::Init; + b.createStore(loc, src, dest, qualifier); + }; - // First, emit all of the properties listed in `initializes`. They - // are passed as indirect results. + // Set-up the arguments for the apply. + SmallVector arguments; SILValue selfRef = nullptr; bool needInsertEndAccess = false; - if (inLocalContext) { - // add the local projection which is for the _x backing local storage - arguments.push_back(selfOrLocalValue); - } else { - if (isRefSelf) { - selfRef = b.emitBeginBorrowOperation(loc, selfOrLocalValue); - } else if (isa(selfOrLocalValue)) { - // Don't insert an access scope if there is already one. This avoids - // inserting a dynamic access check when the parent is static (and therefore - // can be statically enforced). - selfRef = selfOrLocalValue; - } - else { - selfRef = - b.createBeginAccess(loc, selfOrLocalValue, SILAccessKind::Modify, - SILAccessEnforcement::Dynamic, - /*noNestedConflict=*/false, - /*fromBuiltin=*/false); - needInsertEndAccess = true; - } - unsigned index = 0; - inst->forEachInitializedProperty([&](VarDecl *property) { - arguments.push_back(emitFieldReference( - selfRef, property, - /*emitDestroy=*/inst->isPropertyAlreadyInitialized(index))); - index++; - }); + if (convention.useLoweredAddresses()) { + // First, emit all of the properties listed in `initializes`. They + // are passed as indirect results. + if (inLocalContext) { + // add the local projection which is for the _x backing local storage + arguments.push_back(selfOrLocalValue); + } else { + std::tie(selfRef, needInsertEndAccess) = emitBeginModifyOfSelf(); + + unsigned index = 0; + inst->forEachInitializedProperty([&](VarDecl *property) { + arguments.push_back(emitFieldReference( + selfRef, property, + /*emitDestroy=*/inst->isPropertyAlreadyInitialized(index))); + index++; + }); + } } // Now emit `initialValue` which is the only argument specified @@ -270,7 +288,40 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b, for (auto *property : inst->getAccessedProperties()) arguments.push_back(emitFieldReference(selfRef, property)); - b.createApply(loc, initFn, SubstitutionMap(), arguments); + + // Actually emit the apply. + auto apply = b.createApply(loc, initFn, SubstitutionMap(), arguments); + ASSERT(apply->getNumResults() == 1 && "multi-result not handled yet"); + + + // Handle direct results in the case of -enable-sil-opaque-values + if (!convention.useLoweredAddresses()) { + // Write the result(s) to the field(s) to be initialized. + if (inLocalContext) { + initializeAddress(loc, apply->getResult(0), selfOrLocalValue); + } else { + std::tie(selfRef, needInsertEndAccess) = emitBeginModifyOfSelf(); + + SILValue result = apply->getResult(0); + + ASSERT(!result->getType().isTuple() && "insert destructure_tuple?"); + + SmallVector results; + results.push_back(result); + + ASSERT(results.size() == inst->getNumInitializedProperties()); + + unsigned index = 0; + inst->forEachInitializedProperty([&](VarDecl *property) { + auto fieldRef = emitFieldReference( + selfRef, property, + /*emitDestroy=*/inst->isPropertyAlreadyInitialized(index)); + + initializeAddress(loc, results[index], fieldRef); + index++; + }); + } + } if (selfRef) { if (isRefSelf) { diff --git a/test/Interpreter/property_wrappers.swift b/test/Interpreter/property_wrappers.swift index 5517f178c154..74bf537f7aa7 100644 --- a/test/Interpreter/property_wrappers.swift +++ b/test/Interpreter/property_wrappers.swift @@ -1,4 +1,5 @@ // RUN: %target-run-simple-swift | %FileCheck %s +// RUN: %target-run-simple-swift(-Xfrontend -enable-sil-opaque-values) | %FileCheck %s // REQUIRES: executable_test protocol Observed: AnyObject { diff --git a/test/SILGen/assign_or_init_without_opaque_sil.swift b/test/SILGen/assign_or_init_without_opaque_sil.swift deleted file mode 100644 index 5fd3b6b7b26f..000000000000 --- a/test/SILGen/assign_or_init_without_opaque_sil.swift +++ /dev/null @@ -1,35 +0,0 @@ -// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -disable-availability-checking -Xllvm -sil-full-demangle -primary-file %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-runtime - -// Extracted from opaque_values_closures.swift. -// This version uses the assign_or_init SILGen instruction instead of the previous assign_by_wrapper. -// Because init accessors do not currently support `-enable-sil-opaque-values`, -// this test runs without that flag to validate closure behavior in the local context. - -@propertyWrapper struct BoxWrapper { var wrappedValue: T } - -// CHECK-LABEL: sil {{.*}}[ossa] @$s33assign_or_init_without_opaque_sil35captureBoxNonopaqueOwnedNonescapingyyxyXElF : {{.*}} { -// CHECK: bb0([[GET:%[^,]+]] : -// CHECK: [[BOX:%[^,]+]] = alloc_box $<τ_0_0> { var BoxWrapper<τ_0_0> } , var -// CHECK: [[VAR:%[^,]+]] = mark_uninitialized [var] [[BOX]] -// CHECK: [[VAR_LIFETIME:%[^,]+]] = begin_borrow [lexical] [var_decl] [[VAR]] -// CHECK: [[VAR_ADDR:%[^,]+]] = project_box [[VAR_LIFETIME]] -// TODO: DETERMINE: Considering that captureCanEscape is false, should this mark_function_escape be emitted? -// CHECK: mark_function_escape [[VAR_ADDR]] -// CHECK: [[LOCAL:%[^,]+]] = function_ref @$s33assign_or_init_without_opaque_sil35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF -// CHECK: apply [[LOCAL]]([[VAR_LIFETIME]], [[GET]]) -// CHECK: end_borrow [[VAR_LIFETIME]] -// CHECK: destroy_value [[VAR]] -// CHECK-LABEL: } // end sil function '$s33assign_or_init_without_opaque_sil35captureBoxNonopaqueOwnedNonescapingyyxyXElF' - -// CHECK-LABEL: sil {{.*}}[ossa] @$s33assign_or_init_without_opaque_sil35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF : {{.*}} -// CHECK: bb0(%0 : @closureCapture @guaranteed $<τ_0_0> { var BoxWrapper<τ_0_0> } , -// CHECK-SAME: %1 : -// CHECK-LABEL: } // end sil function '$s33assign_or_init_without_opaque_sil35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF' -func captureBoxNonopaqueOwnedNonescaping(_ get: () -> U) { - @BoxWrapper var u: U - - func local() { - u = get() - } - local() -} diff --git a/test/SILGen/opaque_values_closures.swift b/test/SILGen/opaque_values_closures.swift index b470357628d2..563f51aeb3bd 100644 --- a/test/SILGen/opaque_values_closures.swift +++ b/test/SILGen/opaque_values_closures.swift @@ -43,6 +43,7 @@ struct G {} struct MOG : ~Copyable {} func getMOG(_ t: T.Type) -> MOG { return MOG() } func borrow(_ t: T) {} +@propertyWrapper struct BoxWrapper { var wrappedValue: T } // CaptureKind::Immutable, canGuarantee=true, isPack=true // CHECK-LABEL: sil {{.*}}[ossa] @$s22opaque_values_closures30captureImmutablePackGuaranteed1tyxxQp_tRvzlF6$deferL_yyRvzlF : {{.*}} { @@ -356,4 +357,31 @@ func captureBoxNonopaqueOwnedEscaping() { } } func captureBoxNonopaqueOwnedEscaping_callee(_ t: T, _ c: @escaping (T) -> ()) {} -func captureBoxNonopaqueOwnedEscaping_vend() -> C { return C() } \ No newline at end of file +func captureBoxNonopaqueOwnedEscaping_vend() -> C { return C() } + +// CaptureKind::Box, non-opaque, canGuarantee=false, captureCanEscape=false +// CHECK-LABEL: sil {{.*}}[ossa] @$s22opaque_values_closures35captureBoxNonopaqueOwnedNonescapingyyxyXElF : {{.*}} { +// CHECK: bb0([[GET:%[^,]+]] : +// CHECK: [[BOX:%[^,]+]] = alloc_box $<τ_0_0> { var BoxWrapper<τ_0_0> } , var +// CHECK: [[VAR:%[^,]+]] = mark_uninitialized [var] [[BOX]] +// CHECK: [[VAR_LIFETIME:%[^,]+]] = begin_borrow [lexical] [var_decl] [[VAR]] +// CHECK: [[VAR_ADDR:%[^,]+]] = project_box [[VAR_LIFETIME]] +// TODO: DETERMINE: Considering that captureCanEscape is false, should this mark_function_escape be emitted? +// CHECK: mark_function_escape [[VAR_ADDR]] +// CHECK: [[LOCAL:%[^,]+]] = function_ref @$s22opaque_values_closures35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF +// CHECK: apply [[LOCAL]]([[VAR_LIFETIME]], [[GET]]) +// CHECK: end_borrow [[VAR_LIFETIME]] +// CHECK: destroy_value [[VAR]] +// CHECK-LABEL: } // end sil function '$s22opaque_values_closures35captureBoxNonopaqueOwnedNonescapingyyxyXElF' +// CHECK-LABEL: sil {{.*}}[ossa] @$s22opaque_values_closures35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF : {{.*}} +// CHECK: bb0(%0 : @closureCapture @guaranteed $<τ_0_0> { var BoxWrapper<τ_0_0> } , +// CHECK-SAME: %1 : +// CHECK-LABEL: } // end sil function '$s22opaque_values_closures35captureBoxNonopaqueOwnedNonescapingyyxyXElF5localL_yylF' +func captureBoxNonopaqueOwnedNonescaping(_ get: () -> U) { + @BoxWrapper var u: U + + func local() { + u = get() + } + local() +} diff --git a/test/SILGen/property_wrappers.swift b/test/SILGen/property_wrappers.swift index 33c33052cbbd..b82d5f77f526 100644 --- a/test/SILGen/property_wrappers.swift +++ b/test/SILGen/property_wrappers.swift @@ -1,6 +1,10 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -o %t -enable-library-evolution %S/Inputs/property_wrapper_defs.swift -// RUN: %target-swift-emit-silgen -Xllvm -sil-print-types -primary-file %s -I %t | %FileCheck %s +// RUN: %target-swift-emit-silgen -sil-verify-all -Xllvm -sil-print-types -primary-file %s -I %t | %FileCheck %s --check-prefixes CHECK,ADR + +// RUN: %target-swift-frontend -emit-module -o %t -enable-library-evolution %S/Inputs/property_wrapper_defs.swift -enable-sil-opaque-values +// RUN: %target-swift-emit-silgen -sil-verify-all -Xllvm -sil-print-types -primary-file %s -I %t -enable-sil-opaque-values | %FileCheck %s --check-prefixes CHECK,OV + import property_wrapper_defs @propertyWrapper @@ -58,18 +62,22 @@ func forceHasMemberwiseInit() { // variable initialization expression of HasMemberwiseInit._x // CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers17HasMemberwiseInitV2_x33_{{.*}}AA7WrapperVySbGvpfi : $@convention(thin) () -> Wrapper { +// CHECK: bb0: // CHECK: integer_literal $Builtin.Int1, 0 // CHECK-NOT: return // CHECK: function_ref @$sSb22_builtinBooleanLiteralSbBi1__tcfC : $@convention(method) (Builtin.Int1, @thin Bool.Type) -> Bool // CHECK-NOT: return -// CHECK: function_ref @$s17property_wrappers7WrapperV5valueACyxGx_tcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin Wrapper<τ_0_0>.Type) -> @out Wrapper<τ_0_0> // user: %9 +// CHECK: function_ref @$s17property_wrappers7WrapperV5valueACyxGx_tcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin Wrapper<τ_0_0>.Type) -> @out Wrapper<τ_0_0> // CHECK: return {{%.*}} : $Wrapper // variable initialization expression of HasMemberwiseInit.$y // CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers17HasMemberwiseInitV2_y33_{{.*}}23WrapperWithInitialValueVyxGvpfi : $@convention(thin) () -> @out -// CHECK: bb0(%0 : $*T): +// ADR: bb0(%0 : $*T): +// OV: bb0: // CHECK-NOT: return // CHECK: witness_method $T, #DefaultInit.init!allocator : (Self.Type) -> () -> Self : $@convention(witness_method: DefaultInit) <τ_0_0 where τ_0_0 : DefaultInit> (@thick τ_0_0.Type) -> @out τ_0_0 +// ADR: return {{%.*}} : $() +// OV: return {{%.*}} : $T // variable initialization expression of HasMemberwiseInit._z // CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers17HasMemberwiseInitV2_z33_{{.*}}23WrapperWithInitialValueVySiGvpfi : $@convention(thin) () -> WrapperWithInitialValue { @@ -78,6 +86,7 @@ func forceHasMemberwiseInit() { // CHECK: integer_literal $Builtin.IntLiteral, 17 // CHECK-NOT: return // CHECK: function_ref @$s17property_wrappers23WrapperWithInitialValueV07wrappedF0ACyxGx_tcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin WrapperWithInitialValue<τ_0_0>.Type) -> @out WrapperWithInitialValue<τ_0_0> +// CHECK: return {{%.*}} : $WrapperWithInitialValue // variable initialization expression of HasMemberwiseInit._p // CHECK-LABEL: sil hidden [transparent] [ossa] @$s17property_wrappers17HasMemberwiseInitV2_p33_{{.*}}23WrapperWithInitialValueVySbGvpfi : $@convention(thin) () -> Bool { diff --git a/test/SILOptimizer/di_property_wrappers.swift b/test/SILOptimizer/di_property_wrappers.swift index 73043c4294ac..c10de5f2832b 100644 --- a/test/SILOptimizer/di_property_wrappers.swift +++ b/test/SILOptimizer/di_property_wrappers.swift @@ -3,6 +3,10 @@ // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s +// RUN: %target-build-swift %s -Xfrontend -enable-sil-opaque-values -o %t/a.out +// RUN: %target-codesign %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + // REQUIRES: executable_test @propertyWrapper diff --git a/test/SILOptimizer/di_property_wrappers_errors.swift b/test/SILOptimizer/di_property_wrappers_errors.swift index 7692f6069c52..9c8f8ca4155b 100644 --- a/test/SILOptimizer/di_property_wrappers_errors.swift +++ b/test/SILOptimizer/di_property_wrappers_errors.swift @@ -1,4 +1,5 @@ // RUN: %target-swift-frontend -emit-sil -verify %s +// RUN: %target-swift-frontend -enable-sil-opaque-values -emit-sil -verify %s @propertyWrapper final class ClassWrapper { diff --git a/test/SILOptimizer/di_property_wrappers_leak.swift b/test/SILOptimizer/di_property_wrappers_leak.swift index 4bfc99e08d55..644b513d7757 100644 --- a/test/SILOptimizer/di_property_wrappers_leak.swift +++ b/test/SILOptimizer/di_property_wrappers_leak.swift @@ -3,6 +3,10 @@ // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out +// RUN: %target-build-swift %s -Xfrontend -enable-sil-opaque-values -o %t/a.out +// RUN: %target-codesign %t/a.out +// RUN: %target-run %t/a.out + // REQUIRES: executable_test import StdlibUnittest diff --git a/test/SILOptimizer/opaque_values_O.swift b/test/SILOptimizer/opaque_values_O.swift index 710cfafe2ed9..ac14aa14ad1a 100644 --- a/test/SILOptimizer/opaque_values_O.swift +++ b/test/SILOptimizer/opaque_values_O.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-frontend -enable-sil-opaque-values -parse-as-library -emit-sil -O %s | %FileCheck %s +// RUN: %target-swift-frontend -sil-verify-all -enable-sil-opaque-values -parse-as-library -emit-sil -O %s | %FileCheck %s // Verify the arguments. When AccessPathVerification runs, it will be checked // that the ParamDecl that AddressLowering synthesizes has a specifier @@ -9,3 +9,17 @@ public func min(_ x: T, _ y: T) -> T { return y < x ? y : x } + + +// This example use to produce invalid SIL after RawSILInstLowering of assign_or_init +@propertyWrapper +struct WrapperWithInitialValue { + var wrappedValue: T +} +public protocol TestProtocol {} +public class TestClass { + @WrapperWithInitialValue var value: T + init(value: T, protocol: U) { + self.value = value + } +} diff --git a/test/SILOptimizer/property_wrappers_and_tuples.swift b/test/SILOptimizer/property_wrappers_and_tuples.swift index 783a36473384..2d3b04095b7e 100644 --- a/test/SILOptimizer/property_wrappers_and_tuples.swift +++ b/test/SILOptimizer/property_wrappers_and_tuples.swift @@ -1,8 +1,13 @@ -// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t) + // RUN: %target-build-swift %s -module-name=a -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s +// RUN: %target-build-swift %s -Xfrontend -enable-sil-opaque-values -module-name=a -o %t/a.out +// RUN: %target-codesign %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s + // REQUIRES: executable_test @propertyWrapper struct D {