/// Emit Builtin.initialize by evaluating the operand directly into /// the address. static ManagedValue emitBuiltinInit(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, PreparedArguments &&preparedArgs, SGFContext C) { auto argsOrError = decomposeArguments(SGF, loc, std::move(preparedArgs), 2); if (!argsOrError) return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); auto args = *argsOrError; CanType formalType = substitutions.getReplacementTypes()[0]->getCanonicalType(); auto &formalTL = SGF.getTypeLowering(formalType); SILValue addr = SGF.emitRValueAsSingleValue(args[1]).getUnmanagedValue(); addr = SGF.B.createPointerToAddress( loc, addr, formalTL.getLoweredType().getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); TemporaryInitialization init(addr, CleanupHandle::invalid()); SGF.emitExprInto(args[0], &init); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.destroy. static ManagedValue emitBuiltinDestroy(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 2 && "destroy should have two arguments"); assert(substitutions.size() == 1 && "destroy should have a single substitution"); // The substitution determines the type of the thing we're destroying. auto &ti = gen.getTypeLowering(substitutions[0].getReplacement()); // Destroy is a no-op for trivial types. if (ti.isTrivial()) return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); SILType destroyType = ti.getLoweredType(); // Convert the pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args[1].getUnmanagedValue(), destroyType.getAddressType(), /*isStrict*/ true); // Destroy the value indirectly. Canonicalization will promote to loads // and releases if appropriate. gen.B.createDestroyAddr(loc, addr); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinAssign(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions[0].getReplacement()->getCanonicalType(); SILType assignType = gen.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = gen.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType(), /*isStrict*/ true); // Build the value to be assigned, reconstructing tuples if needed. auto src = RValue::withPreExplodedElements(args.slice(0, args.size() - 1), assignFormalType); std::move(src).assignInto(gen, loc, addr); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.beginUnpairedModifyAccess. static ManagedValue emitBuiltinBeginUnpairedModifyAccess(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "Builtin.beginUnpairedModifyAccess should have one substitution"); assert(args.size() == 3 && "beginUnpairedModifyAccess should be given three arguments"); SILType elemTy = SGF.getLoweredType(substitutions.getReplacementTypes()[0]); SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), elemTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SILType valueBufferTy = SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType); SILValue buffer = SGF.B.createPointerToAddress(loc, args[1].getUnmanagedValue(), valueBufferTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SGF.B.createBeginUnpairedAccess(loc, addr, buffer, SILAccessKind::Modify, SILAccessEnforcement::Dynamic, /*noNestedConflict*/ false, /*fromBuiltin*/ true); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinAssign(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() >= 2 && "assign should have two arguments"); assert(substitutions.getReplacementTypes().size() == 1 && "assign should have a single substitution"); // The substitution determines the type of the thing we're destroying. CanType assignFormalType = substitutions.getReplacementTypes()[0]->getCanonicalType(); SILType assignType = SGF.getLoweredType(assignFormalType); // Convert the destination pointer argument to a SIL address. SILValue addr = SGF.B.createPointerToAddress(loc, args.back().getUnmanagedValue(), assignType.getAddressType(), /*isStrict*/ true, /*isInvariant*/ false); // Build the value to be assigned, reconstructing tuples if needed. auto src = RValue(SGF, args.slice(0, args.size() - 1), assignFormalType); std::move(src).ensurePlusOne(SGF, loc).assignInto(SGF, loc, addr); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinAutorelease(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { gen.B.createUnmanagedAutoreleaseValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinAutorelease(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { SGF.B.createUnmanagedAutoreleaseValue(loc, args[0].getValue(), SGF.B.getDefaultAtomicity()); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.condfail. static ManagedValue emitBuiltinCondFail(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1 && "condfail should be given one argument"); SGF.B.createCondFail(loc, args[0].getUnmanagedValue()); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.fixLifetime. static ManagedValue emitBuiltinFixLifetime(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { for (auto arg : args) { SGF.B.createFixLifetime(loc, arg.getValue()); } return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.condfail. static ManagedValue emitBuiltinCondFail(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1 && "condfail should be given one argument"); gen.B.createCondFail(loc, args[0].getUnmanagedValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinAutorelease(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { // The value was produced at +1, so to produce an unbalanced // autorelease we need to leave the cleanup intact. gen.B.createAutoreleaseValue(loc, args[0].getValue(), Atomicity::Atomic); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.fixLifetime. static ManagedValue emitBuiltinFixLifetime(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { for (auto arg : args) { gen.B.createFixLifetime(loc, arg.getValue()); } return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinRetain(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { // The value was produced at +1; we can produce an unbalanced // retain simply by disabling the cleanup. args[0].forward(gen); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinRelease(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { // The value was produced at +1, so to produce an unbalanced // release we need to leave the cleanup intact and then do a *second* // release. gen.B.createUnmanagedReleaseValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinRelease(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { // The value was produced at +1, so to produce an unbalanced // release we need to leave the cleanup intact and then do a *second* // release. SGF.B.createUnmanagedReleaseValue(loc, args[0].getValue(), SGF.B.getDefaultAtomicity()); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinRetain(SILGenFunction &gen, SILLocation loc, SubstitutionList substitutions, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { // The value was produced at +1; we can produce an unbalanced retain simply by // disabling the cleanup. But this would violate ownership semantics. Instead, // we must allow for the cleanup and emit a new unmanaged retain value. gen.B.createUnmanagedRetainValue(loc, args[0].getValue()); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinUnpin(SILGenFunction &SGF, SILLocation loc, SubstitutionList subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(args.size() == 1); if (requireIsOptionalNativeObject(SGF, loc, subs[0].getReplacement())) { // Unpinning takes responsibility for the +1 handle. SGF.B.createStrongUnpin(loc, args[0].forward(SGF), SGF.B.getDefaultAtomicity()); } return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinUnpin(SILGenFunction &gen, SILLocation loc, SubstitutionList subs, ArrayRef<ManagedValue> args, CanFunctionType formalApplyType, SGFContext C) { assert(args.size() == 1); if (requireIsOptionalNativeObject(gen, loc, subs[0].getReplacement())) { // Unpinning takes responsibility for the +1 handle. gen.B.createStrongUnpin(loc, args[0].forward(gen), Atomicity::Atomic); } return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
static ManagedValue emitBuiltinBindMemory(SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs, ArrayRef<ManagedValue> args, SGFContext C) { assert(subs.getReplacementTypes().size() == 1 && "bindMemory should have a single substitution"); assert(args.size() == 3 && "bindMemory should have three argument"); // The substitution determines the element type for bound memory. CanType boundFormalType = subs.getReplacementTypes()[0]->getCanonicalType(); SILType boundType = SGF.getLoweredType(boundFormalType); SGF.B.createBindMemory(loc, args[0].getValue(), args[1].getValue(), boundType); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static void emitAddressOnlyEnumConstructor(SILGenFunction &gen, SILType enumTy, EnumElementDecl *element) { RegularLocation Loc(element); CleanupLocation CleanupLoc(element); Loc.markAutoGenerated(); // Emit the indirect return slot. auto &AC = gen.getASTContext(); auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), enumTy.getSwiftType(), element->getDeclContext()); SILValue resultSlot = new (gen.F.getModule()) SILArgument(gen.F.begin(), enumTy, VD); Scope scope(gen.Cleanups, CleanupLoc); // Emit the exploded constructor argument. ManagedValue argValue; if (element->hasArgumentType()) { RValue arg = emitImplicitValueConstructorArg (gen, Loc, element->getArgumentType()->getCanonicalType(), element->getDeclContext()); argValue = std::move(arg).getAsSingleValue(gen, Loc); } emitConstructorMetatypeArg(gen, element); boxIndirectEnumPayload(gen, argValue, Loc, element); // Store the data, if any. if (argValue) { SILValue resultData = gen.B.createInitEnumDataAddr(element, resultSlot, element, argValue.getType().getAddressType()); argValue.forwardInto(gen, element, resultData); } // Apply the tag. gen.B.createInjectEnumAddr(Loc, resultSlot, element); scope.pop(); gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), gen.emitEmptyTuple(element)); }
/// Emit Builtin.initialize by evaluating the operand directly into /// the address. static ManagedValue emitBuiltinInit(SILGenFunction &gen, SILLocation loc, ArrayRef<Substitution> substitutions, Expr *tuple, CanFunctionType formalApplyType, SGFContext C) { auto args = decomposeArguments(gen, tuple, 2); CanType formalType = substitutions[0].getReplacement()->getCanonicalType(); auto &formalTL = gen.getTypeLowering(formalType); SILValue addr = gen.emitRValueAsSingleValue(args[1]).getUnmanagedValue(); addr = gen.B.createPointerToAddress(loc, addr, formalTL.getLoweredType().getAddressType()); TemporaryInitialization init(addr, CleanupHandle::invalid()); gen.emitExprInto(args[0], &init); return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.performInstantaneousReadAccess static ManagedValue emitBuiltinPerformInstantaneousReadAccess( SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.getReplacementTypes().size() == 1 && "Builtin.performInstantaneousReadAccess should have one substitution"); assert(args.size() == 2 && "Builtin.performInstantaneousReadAccess should be given " "two arguments"); SILType elemTy = SGF.getLoweredType(substitutions.getReplacementTypes()[0]); SILValue addr = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), elemTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SILType valueBufferTy = SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType); SILValue unusedBuffer = SGF.emitTemporaryAllocation(loc, valueBufferTy); // Begin an "unscoped" read access. No nested conflict is possible because // the compiler should generate the actual read for the KeyPath expression // immediately after the call to this builtin, which forms the address of // that real access. When noNestedConflict=true, no EndUnpairedAccess should // be emitted. // // Unpaired access is necessary because a BeginAccess/EndAccess pair with no // use will be trivially optimized away. SGF.B.createBeginUnpairedAccess(loc, addr, unusedBuffer, SILAccessKind::Read, SILAccessEnforcement::Dynamic, /*noNestedConflict*/ true, /*fromBuiltin*/ true); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
/// Specialized emitter for Builtin.endUnpairedAccessModifyAccess. static ManagedValue emitBuiltinEndUnpairedAccess(SILGenFunction &SGF, SILLocation loc, SubstitutionMap substitutions, ArrayRef<ManagedValue> args, SGFContext C) { assert(substitutions.empty() && "Builtin.endUnpairedAccess should have no substitutions"); assert(args.size() == 1 && "endUnpairedAccess should be given one argument"); SILType valueBufferTy = SGF.getLoweredType(SGF.getASTContext().TheUnsafeValueBufferType); SILValue buffer = SGF.B.createPointerToAddress(loc, args[0].getUnmanagedValue(), valueBufferTy.getAddressType(), /*strict*/ true, /*invariant*/ false); SGF.B.createEndUnpairedAccess(loc, buffer, SILAccessEnforcement::Dynamic, /*aborted*/ false, /*fromBuiltin*/ true); return ManagedValue::forUnmanaged(SGF.emitEmptyTuple(loc)); }
static void emitImplicitValueConstructor(SILGenFunction &gen, ConstructorDecl *ctor) { RegularLocation Loc(ctor); Loc.markAutoGenerated(); // FIXME: Handle 'self' along with the other arguments. auto *paramList = ctor->getParameterList(1); auto selfTyCan = ctor->getImplicitSelfDecl()->getType()->getInOutObjectType(); SILType selfTy = gen.getLoweredType(selfTyCan); // Emit the indirect return argument, if any. SILValue resultSlot; if (selfTy.isAddressOnly(gen.SGM.M)) { auto &AC = gen.getASTContext(); auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(), SourceLoc(), AC.getIdentifier("$return_value"), SourceLoc(), AC.getIdentifier("$return_value"), selfTyCan, ctor); resultSlot = new (gen.F.getModule()) SILArgument(gen.F.begin(), selfTy, VD); } // Emit the elementwise arguments. SmallVector<RValue, 4> elements; for (size_t i = 0, size = paramList->size(); i < size; ++i) { auto ¶m = paramList->get(i); elements.push_back( emitImplicitValueConstructorArg(gen, Loc, param->getType()->getCanonicalType(), ctor)); } emitConstructorMetatypeArg(gen, ctor); auto *decl = selfTy.getStructOrBoundGenericStruct(); assert(decl && "not a struct?!"); // If we have an indirect return slot, initialize it in-place. if (resultSlot) { auto elti = elements.begin(), eltEnd = elements.end(); for (VarDecl *field : decl->getStoredProperties()) { auto fieldTy = selfTy.getFieldType(field, gen.SGM.M); auto &fieldTL = gen.getTypeLowering(fieldTy); SILValue slot = gen.B.createStructElementAddr(Loc, resultSlot, field, fieldTL.getLoweredType().getAddressType()); InitializationPtr init(new KnownAddressInitialization(slot)); // An initialized 'let' property has a single value specified by the // initializer - it doesn't come from an argument. if (!field->isStatic() && field->isLet() && field->getParentInitializer()) { assert(field->getType()->isEqual(field->getParentInitializer() ->getType()) && "Checked by sema"); // Cleanup after this initialization. FullExpr scope(gen.Cleanups, field->getParentPatternBinding()); gen.emitExprInto(field->getParentInitializer(), init.get()); continue; } assert(elti != eltEnd && "number of args does not match number of fields"); (void)eltEnd; std::move(*elti).forwardInto(gen, Loc, init.get()); ++elti; } gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), gen.emitEmptyTuple(Loc)); return; } // Otherwise, build a struct value directly from the elements. SmallVector<SILValue, 4> eltValues; auto elti = elements.begin(), eltEnd = elements.end(); for (VarDecl *field : decl->getStoredProperties()) { auto fieldTy = selfTy.getFieldType(field, gen.SGM.M); SILValue v; // An initialized 'let' property has a single value specified by the // initializer - it doesn't come from an argument. if (!field->isStatic() && field->isLet() && field->getParentInitializer()) { // Cleanup after this initialization. FullExpr scope(gen.Cleanups, field->getParentPatternBinding()); v = gen.emitRValue(field->getParentInitializer()) .forwardAsSingleStorageValue(gen, fieldTy, Loc); } else { assert(elti != eltEnd && "number of args does not match number of fields"); (void)eltEnd; v = std::move(*elti).forwardAsSingleStorageValue(gen, fieldTy, Loc); ++elti; } eltValues.push_back(v); } SILValue selfValue = gen.B.createStruct(Loc, selfTy, eltValues); gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), selfValue); return; }