diff --git a/include/swift/SIL/SILBuilder.h b/include/swift/SIL/SILBuilder.h index 3dab391d9d3..b56fb744bf1 100644 --- a/include/swift/SIL/SILBuilder.h +++ b/include/swift/SIL/SILBuilder.h @@ -409,6 +409,10 @@ public: return insert(new (F.getModule()) ReleaseValueInst(loc, operand)); } + AutoreleaseValueInst *createAutoreleaseValue(SILLocation loc, SILValue operand) { + return insert(new (F.getModule()) AutoreleaseValueInst(loc, operand)); + } + StructInst *createStruct(SILLocation Loc, SILType Ty, ArrayRef Elements) { return insert(StructInst::create(Loc, Ty, Elements, F)); diff --git a/include/swift/SIL/SILCloner.h b/include/swift/SIL/SILCloner.h index 7268368dbdf..ea523ce0186 100644 --- a/include/swift/SIL/SILCloner.h +++ b/include/swift/SIL/SILCloner.h @@ -587,6 +587,14 @@ SILCloner::visitReleaseValueInst(ReleaseValueInst *Inst) { getOpValue(Inst->getOperand()))); } +template +void +SILCloner::visitAutoreleaseValueInst(AutoreleaseValueInst *Inst) { + doPostProcess(Inst, + getBuilder().createAutoreleaseValue(getOpLocation(Inst->getLoc()), + getOpValue(Inst->getOperand()))); +} + template void SILCloner::visitStructInst(StructInst *Inst) { diff --git a/include/swift/SIL/SILInstruction.h b/include/swift/SIL/SILInstruction.h index 32e1625cfbb..03d3f25201d 100644 --- a/include/swift/SIL/SILInstruction.h +++ b/include/swift/SIL/SILInstruction.h @@ -1337,6 +1337,16 @@ public: : UnaryInstructionBase(loc, operand) {} }; +/// Transfers ownership of a loadable value to the current autorelease pool. +class AutoreleaseValueInst + : public UnaryInstructionBase { +public: + AutoreleaseValueInst(SILLocation loc, SILValue operand) + : UnaryInstructionBase(loc, operand) {} +}; + /// TupleInst - Represents a constructed loadable tuple. class TupleInst : public SILInstruction { TailAllocatedOperandList<0> Operands; diff --git a/include/swift/SIL/SILNodes.def b/include/swift/SIL/SILNodes.def index 2a4bee907d4..deacca784a0 100644 --- a/include/swift/SIL/SILNodes.def +++ b/include/swift/SIL/SILNodes.def @@ -140,6 +140,7 @@ ABSTRACT_VALUE(SILInstruction, ValueBase) // Aggregate Types INST(RetainValueInst, SILInstruction, MayHaveSideEffects) INST(ReleaseValueInst, SILInstruction, MayHaveSideEffects) + INST(AutoreleaseValueInst, SILInstruction, MayHaveSideEffects) INST(TupleInst, SILInstruction, None) INST(TupleExtractInst, SILInstruction, None) INST(TupleElementAddrInst, SILInstruction, None) diff --git a/include/swift/Serialization/ModuleFormat.h b/include/swift/Serialization/ModuleFormat.h index 28d6b1c9108..18e9510d7c3 100644 --- a/include/swift/Serialization/ModuleFormat.h +++ b/include/swift/Serialization/ModuleFormat.h @@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0; /// Serialized module format minor version number. /// /// When the format changes IN ANY WAY, this number should be incremented. -const uint16_t VERSION_MINOR = 74; +const uint16_t VERSION_MINOR = 77; using DeclID = Fixnum<31>; using DeclIDField = BCFixed<31>; diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 185b806e1f6..603d8ef5971 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -588,6 +588,7 @@ public: void visitStoreWeakInst(StoreWeakInst *i); void visitRetainValueInst(RetainValueInst *i); void visitReleaseValueInst(ReleaseValueInst *i); + void visitAutoreleaseValueInst(AutoreleaseValueInst *i); void visitStructInst(StructInst *i); void visitTupleInst(TupleInst *i); void visitEnumInst(EnumInst *i); @@ -2117,6 +2118,22 @@ void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) { out.claimAll(); } +// TODO: Implement this more generally for arbitrary values. Currently the +// SIL verifier restricts it to single-refcounted-pointer types. +void IRGenSILFunction::visitAutoreleaseValueInst(swift::AutoreleaseValueInst *i) +{ + Explosion in = getLoweredExplosion(i->getOperand()); + auto val = in.claimNext(); + + if (val->getType()->isPointerTy()) + val = Builder.CreateBitCast(val, IGM.ObjCPtrTy); + else + val = Builder.CreateIntToPtr(val, IGM.ObjCPtrTy); + + auto call = Builder.CreateCall(IGM.getObjCAutoreleaseFn(), val); + call->setDoesNotThrow(); +} + void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) { Explosion in = getLoweredExplosion(i->getOperand()); cast(getTypeInfo(i->getOperand().getType())) diff --git a/lib/IRGen/RuntimeFunctions.def b/lib/IRGen/RuntimeFunctions.def index a690c87e488..496e43857af 100644 --- a/lib/IRGen/RuntimeFunctions.def +++ b/lib/IRGen/RuntimeFunctions.def @@ -519,6 +519,8 @@ FUNCTION(ObjCRetain, objc_retain, C_CC, RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind)) FUNCTION(ObjCRelease, objc_release, C_CC, RETURNS(VoidTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind)) +FUNCTION(ObjCAutorelease, objc_autorelease, C_CC, + RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind)) FUNCTION(ObjCRetainAutoreleasedReturnValue, objc_retainAutoreleasedReturnValue, C_CC, RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind)) diff --git a/lib/Parse/ParseSIL.cpp b/lib/Parse/ParseSIL.cpp index bc7e2ba3dc2..95efa4fc2fc 100644 --- a/lib/Parse/ParseSIL.cpp +++ b/lib/Parse/ParseSIL.cpp @@ -994,6 +994,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc, .Case("apply", ValueKind::ApplyInst) .Case("assign", ValueKind::AssignInst) .Case("autorelease_return", ValueKind::AutoreleaseReturnInst) + .Case("autorelease_value", ValueKind::AutoreleaseValueInst) .Case("br", ValueKind::BranchInst) .Case("builtin_function_ref", ValueKind::BuiltinFunctionRefInst) .Case("checked_cast_br", ValueKind::CheckedCastBranchInst) @@ -1475,6 +1476,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) { UNARY_INSTRUCTION(UnownedRetain) UNARY_INSTRUCTION(UnownedRelease) UNARY_INSTRUCTION(DestroyAddr) + UNARY_INSTRUCTION(AutoreleaseValue) UNARY_INSTRUCTION(ReleaseValue) UNARY_INSTRUCTION(RetainValue) UNARY_INSTRUCTION(Load) diff --git a/lib/SIL/SILPrinter.cpp b/lib/SIL/SILPrinter.cpp index 8cf5aa1b5ff..88cbd16b634 100644 --- a/lib/SIL/SILPrinter.cpp +++ b/lib/SIL/SILPrinter.cpp @@ -801,6 +801,10 @@ public: OS << "release_value " << getIDAndType(I->getOperand()); } + void visitAutoreleaseValueInst(AutoreleaseValueInst *I) { + OS << "autorelease_value " << getIDAndType(I->getOperand()); + } + void visitStructInst(StructInst *SI) { OS << "struct " << SI->getType() << " ("; interleave(SI->getElements(), diff --git a/lib/SIL/Verifier.cpp b/lib/SIL/Verifier.cpp index c3d3e25ccb2..87f5b010bda 100644 --- a/lib/SIL/Verifier.cpp +++ b/lib/SIL/Verifier.cpp @@ -579,6 +579,14 @@ public: "Source value should be an object value"); } + void checkAutoreleaseValueInst(ReleaseValueInst *I) { + require(I->getOperand().getType().isObject(), + "Source value should be an object value"); + // TODO: This instruction could in principle be generalized. + require(I->getOperand().getType().hasRetainablePointerRepresentation(), + "Source value must be a reference type or optional thereof"); + } + void checkCopyBlockInst(CopyBlockInst *I) { require(I->getOperand().getType().isBlockPointerCompatible(), "operand of copy_block should be a block"); diff --git a/lib/SILAnalysis/ValueTracking.cpp b/lib/SILAnalysis/ValueTracking.cpp index 928798b3433..ca5e400e485 100644 --- a/lib/SILAnalysis/ValueTracking.cpp +++ b/lib/SILAnalysis/ValueTracking.cpp @@ -64,6 +64,7 @@ static bool isTransitiveEscapeInst(SILInstruction *Inst) { case ValueKind::DebugValueInst: case ValueKind::DestroyAddrInst: case ValueKind::ReleaseValueInst: + case ValueKind::AutoreleaseValueInst: case ValueKind::FloatLiteralInst: case ValueKind::FunctionRefInst: case ValueKind::GlobalAddrInst: diff --git a/lib/SILPasses/Utils/SILInliner.cpp b/lib/SILPasses/Utils/SILInliner.cpp index e13289c110b..ef8d9eb5f83 100644 --- a/lib/SILPasses/Utils/SILInliner.cpp +++ b/lib/SILPasses/Utils/SILInliner.cpp @@ -353,6 +353,7 @@ static InlineCost instructionInlineCost(SILInstruction &I, case ValueKind::DeinitExistentialInst: case ValueKind::DestroyAddrInst: case ValueKind::ReleaseValueInst: + case ValueKind::AutoreleaseValueInst: case ValueKind::DynamicMethodBranchInst: case ValueKind::DynamicMethodInst: case ValueKind::EnumInst: diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index d691bb05fd5..f5cee65ac2c 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -1001,6 +1001,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB, UNARY_INSTRUCTION(CondFail) UNARY_INSTRUCTION(RetainValue) UNARY_INSTRUCTION(ReleaseValue) + UNARY_INSTRUCTION(AutoreleaseValue) UNARY_INSTRUCTION(DeinitExistential) UNARY_INSTRUCTION(DestroyAddr) UNARY_INSTRUCTION(IsNonnull) diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index cd06821f9fb..fba144af4a1 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -625,6 +625,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) { case ValueKind::CondFailInst: case ValueKind::RetainValueInst: case ValueKind::ReleaseValueInst: + case ValueKind::AutoreleaseValueInst: case ValueKind::DeallocStackInst: case ValueKind::DeallocRefInst: case ValueKind::DeinitExistentialInst: diff --git a/test/IRGen/class.sil b/test/IRGen/class.sil index 627ee4d0344..7f9784438a1 100644 --- a/test/IRGen/class.sil +++ b/test/IRGen/class.sil @@ -1,6 +1,7 @@ // RUN: %swift -emit-ir -target x86_64-apple-darwin10 %s | FileCheck %s import Builtin +import Swift // CHECK: [[OBJCCLASS:%objc_class]] = type // CHECK: [[OPAQUE:%swift.opaque]] = type opaque @@ -126,3 +127,22 @@ bb0(%0 : $@thick C.Type): return %1 : $C } +// CHECK-LABEL: define %C5class1C* @autorelease(%C5class1C*) { +// CHECK: %1 = bitcast %C5class1C* %0 to %objc_object* +// CHECK: call %objc_object* @objc_autorelease(%objc_object* %1) +// CHECK: ret %C5class1C* %0 +sil @autorelease : $@thin (@owned C) -> @autoreleased C { +entry(%c : $C): + autorelease_value %c : $C + return %c : $C +} + +// CHECK-LABEL: define i64 @autorelease_optional(i64) { +// CHECK: %1 = inttoptr i64 %0 to %objc_object* +// CHECK: call %objc_object* @objc_autorelease(%objc_object* %1) +// CHECK: ret i64 %0 +sil @autorelease_optional : $@thin (@owned C?) -> @autoreleased C? { +entry(%c : $C?): + autorelease_value %c : $C? + return %c : $C? +} diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index 32e414e04cb..390af61169a 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -935,9 +935,11 @@ sil @test_copy_release_value : $(Val) -> (Val) { bb0(%0 : $Val): retain_value %0 : $Val release_value %0 : $Val + autorelease_value %0 : $Val return %0 : $Val // CHECK: retain_value [[T0:%.*]] : $Val // CHECK-NEXT: release_value [[T0]] : $Val +// CHECK-NEXT: autorelease_value [[T0]] : $Val // CHECK-NEXT: return [[T0]] : $Val } diff --git a/test/Serialization/Inputs/def_basic.sil b/test/Serialization/Inputs/def_basic.sil index 26d80d846bd..ddc7c16d2f4 100644 --- a/test/Serialization/Inputs/def_basic.sil +++ b/test/Serialization/Inputs/def_basic.sil @@ -864,9 +864,11 @@ sil @test_copy_release_value : $@thin (Val) -> (Val) { bb0(%0 : $Val): retain_value %0 : $Val release_value %0 : $Val + autorelease_value %0 : $Val return %0 : $Val // CHECK: retain_value [[T0:%.*]] : $Val // CHECK-NEXT: release_value [[T0]] : $Val + // CHECK-NEXT: autorelease_value [[T0]] : $Val // CHECK-NEXT: return [[T0]] : $Val }