mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SIL: Add an autorelease_value instruction.
Give us a way to formally represent autoreleases in SIL separate from autoreleased returns, allowing us to lifetime-extend inner pointer parameters the lazy way and hopefully clean up some asmname hacks in the stdlib implementation too. Swift SVN r16632
This commit is contained in:
@@ -409,6 +409,10 @@ public:
|
|||||||
return insert(new (F.getModule()) ReleaseValueInst(loc, operand));
|
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,
|
StructInst *createStruct(SILLocation Loc, SILType Ty,
|
||||||
ArrayRef<SILValue> Elements) {
|
ArrayRef<SILValue> Elements) {
|
||||||
return insert(StructInst::create(Loc, Ty, Elements, F));
|
return insert(StructInst::create(Loc, Ty, Elements, F));
|
||||||
|
|||||||
@@ -587,6 +587,14 @@ SILCloner<ImplClass>::visitReleaseValueInst(ReleaseValueInst *Inst) {
|
|||||||
getOpValue(Inst->getOperand())));
|
getOpValue(Inst->getOperand())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ImplClass>
|
||||||
|
void
|
||||||
|
SILCloner<ImplClass>::visitAutoreleaseValueInst(AutoreleaseValueInst *Inst) {
|
||||||
|
doPostProcess(Inst,
|
||||||
|
getBuilder().createAutoreleaseValue(getOpLocation(Inst->getLoc()),
|
||||||
|
getOpValue(Inst->getOperand())));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ImplClass>
|
template<typename ImplClass>
|
||||||
void
|
void
|
||||||
SILCloner<ImplClass>::visitStructInst(StructInst *Inst) {
|
SILCloner<ImplClass>::visitStructInst(StructInst *Inst) {
|
||||||
|
|||||||
@@ -1337,6 +1337,16 @@ public:
|
|||||||
: UnaryInstructionBase(loc, operand) {}
|
: UnaryInstructionBase(loc, operand) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Transfers ownership of a loadable value to the current autorelease pool.
|
||||||
|
class AutoreleaseValueInst
|
||||||
|
: public UnaryInstructionBase<ValueKind::AutoreleaseValueInst,
|
||||||
|
SILInstruction,
|
||||||
|
/*HasValue*/ false> {
|
||||||
|
public:
|
||||||
|
AutoreleaseValueInst(SILLocation loc, SILValue operand)
|
||||||
|
: UnaryInstructionBase(loc, operand) {}
|
||||||
|
};
|
||||||
|
|
||||||
/// TupleInst - Represents a constructed loadable tuple.
|
/// TupleInst - Represents a constructed loadable tuple.
|
||||||
class TupleInst : public SILInstruction {
|
class TupleInst : public SILInstruction {
|
||||||
TailAllocatedOperandList<0> Operands;
|
TailAllocatedOperandList<0> Operands;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
|
|||||||
// Aggregate Types
|
// Aggregate Types
|
||||||
INST(RetainValueInst, SILInstruction, MayHaveSideEffects)
|
INST(RetainValueInst, SILInstruction, MayHaveSideEffects)
|
||||||
INST(ReleaseValueInst, SILInstruction, MayHaveSideEffects)
|
INST(ReleaseValueInst, SILInstruction, MayHaveSideEffects)
|
||||||
|
INST(AutoreleaseValueInst, SILInstruction, MayHaveSideEffects)
|
||||||
INST(TupleInst, SILInstruction, None)
|
INST(TupleInst, SILInstruction, None)
|
||||||
INST(TupleExtractInst, SILInstruction, None)
|
INST(TupleExtractInst, SILInstruction, None)
|
||||||
INST(TupleElementAddrInst, SILInstruction, None)
|
INST(TupleElementAddrInst, SILInstruction, None)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const uint16_t VERSION_MAJOR = 0;
|
|||||||
/// Serialized module format minor version number.
|
/// Serialized module format minor version number.
|
||||||
///
|
///
|
||||||
/// When the format changes IN ANY WAY, this number should be incremented.
|
/// 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 DeclID = Fixnum<31>;
|
||||||
using DeclIDField = BCFixed<31>;
|
using DeclIDField = BCFixed<31>;
|
||||||
|
|||||||
@@ -588,6 +588,7 @@ public:
|
|||||||
void visitStoreWeakInst(StoreWeakInst *i);
|
void visitStoreWeakInst(StoreWeakInst *i);
|
||||||
void visitRetainValueInst(RetainValueInst *i);
|
void visitRetainValueInst(RetainValueInst *i);
|
||||||
void visitReleaseValueInst(ReleaseValueInst *i);
|
void visitReleaseValueInst(ReleaseValueInst *i);
|
||||||
|
void visitAutoreleaseValueInst(AutoreleaseValueInst *i);
|
||||||
void visitStructInst(StructInst *i);
|
void visitStructInst(StructInst *i);
|
||||||
void visitTupleInst(TupleInst *i);
|
void visitTupleInst(TupleInst *i);
|
||||||
void visitEnumInst(EnumInst *i);
|
void visitEnumInst(EnumInst *i);
|
||||||
@@ -2117,6 +2118,22 @@ void IRGenSILFunction::visitRetainValueInst(swift::RetainValueInst *i) {
|
|||||||
out.claimAll();
|
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) {
|
void IRGenSILFunction::visitReleaseValueInst(swift::ReleaseValueInst *i) {
|
||||||
Explosion in = getLoweredExplosion(i->getOperand());
|
Explosion in = getLoweredExplosion(i->getOperand());
|
||||||
cast<LoadableTypeInfo>(getTypeInfo(i->getOperand().getType()))
|
cast<LoadableTypeInfo>(getTypeInfo(i->getOperand().getType()))
|
||||||
|
|||||||
@@ -519,6 +519,8 @@ FUNCTION(ObjCRetain, objc_retain, C_CC,
|
|||||||
RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
||||||
FUNCTION(ObjCRelease, objc_release, C_CC,
|
FUNCTION(ObjCRelease, objc_release, C_CC,
|
||||||
RETURNS(VoidTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
RETURNS(VoidTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
||||||
|
FUNCTION(ObjCAutorelease, objc_autorelease, C_CC,
|
||||||
|
RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
||||||
FUNCTION(ObjCRetainAutoreleasedReturnValue,
|
FUNCTION(ObjCRetainAutoreleasedReturnValue,
|
||||||
objc_retainAutoreleasedReturnValue, C_CC,
|
objc_retainAutoreleasedReturnValue, C_CC,
|
||||||
RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
RETURNS(ObjCPtrTy), ARGS(ObjCPtrTy), ATTRS(NoUnwind))
|
||||||
|
|||||||
@@ -994,6 +994,7 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
|
|||||||
.Case("apply", ValueKind::ApplyInst)
|
.Case("apply", ValueKind::ApplyInst)
|
||||||
.Case("assign", ValueKind::AssignInst)
|
.Case("assign", ValueKind::AssignInst)
|
||||||
.Case("autorelease_return", ValueKind::AutoreleaseReturnInst)
|
.Case("autorelease_return", ValueKind::AutoreleaseReturnInst)
|
||||||
|
.Case("autorelease_value", ValueKind::AutoreleaseValueInst)
|
||||||
.Case("br", ValueKind::BranchInst)
|
.Case("br", ValueKind::BranchInst)
|
||||||
.Case("builtin_function_ref", ValueKind::BuiltinFunctionRefInst)
|
.Case("builtin_function_ref", ValueKind::BuiltinFunctionRefInst)
|
||||||
.Case("checked_cast_br", ValueKind::CheckedCastBranchInst)
|
.Case("checked_cast_br", ValueKind::CheckedCastBranchInst)
|
||||||
@@ -1475,6 +1476,7 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
|
|||||||
UNARY_INSTRUCTION(UnownedRetain)
|
UNARY_INSTRUCTION(UnownedRetain)
|
||||||
UNARY_INSTRUCTION(UnownedRelease)
|
UNARY_INSTRUCTION(UnownedRelease)
|
||||||
UNARY_INSTRUCTION(DestroyAddr)
|
UNARY_INSTRUCTION(DestroyAddr)
|
||||||
|
UNARY_INSTRUCTION(AutoreleaseValue)
|
||||||
UNARY_INSTRUCTION(ReleaseValue)
|
UNARY_INSTRUCTION(ReleaseValue)
|
||||||
UNARY_INSTRUCTION(RetainValue)
|
UNARY_INSTRUCTION(RetainValue)
|
||||||
UNARY_INSTRUCTION(Load)
|
UNARY_INSTRUCTION(Load)
|
||||||
|
|||||||
@@ -801,6 +801,10 @@ public:
|
|||||||
OS << "release_value " << getIDAndType(I->getOperand());
|
OS << "release_value " << getIDAndType(I->getOperand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void visitAutoreleaseValueInst(AutoreleaseValueInst *I) {
|
||||||
|
OS << "autorelease_value " << getIDAndType(I->getOperand());
|
||||||
|
}
|
||||||
|
|
||||||
void visitStructInst(StructInst *SI) {
|
void visitStructInst(StructInst *SI) {
|
||||||
OS << "struct " << SI->getType() << " (";
|
OS << "struct " << SI->getType() << " (";
|
||||||
interleave(SI->getElements(),
|
interleave(SI->getElements(),
|
||||||
|
|||||||
@@ -579,6 +579,14 @@ public:
|
|||||||
"Source value should be an object value");
|
"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) {
|
void checkCopyBlockInst(CopyBlockInst *I) {
|
||||||
require(I->getOperand().getType().isBlockPointerCompatible(),
|
require(I->getOperand().getType().isBlockPointerCompatible(),
|
||||||
"operand of copy_block should be a block");
|
"operand of copy_block should be a block");
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ static bool isTransitiveEscapeInst(SILInstruction *Inst) {
|
|||||||
case ValueKind::DebugValueInst:
|
case ValueKind::DebugValueInst:
|
||||||
case ValueKind::DestroyAddrInst:
|
case ValueKind::DestroyAddrInst:
|
||||||
case ValueKind::ReleaseValueInst:
|
case ValueKind::ReleaseValueInst:
|
||||||
|
case ValueKind::AutoreleaseValueInst:
|
||||||
case ValueKind::FloatLiteralInst:
|
case ValueKind::FloatLiteralInst:
|
||||||
case ValueKind::FunctionRefInst:
|
case ValueKind::FunctionRefInst:
|
||||||
case ValueKind::GlobalAddrInst:
|
case ValueKind::GlobalAddrInst:
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ static InlineCost instructionInlineCost(SILInstruction &I,
|
|||||||
case ValueKind::DeinitExistentialInst:
|
case ValueKind::DeinitExistentialInst:
|
||||||
case ValueKind::DestroyAddrInst:
|
case ValueKind::DestroyAddrInst:
|
||||||
case ValueKind::ReleaseValueInst:
|
case ValueKind::ReleaseValueInst:
|
||||||
|
case ValueKind::AutoreleaseValueInst:
|
||||||
case ValueKind::DynamicMethodBranchInst:
|
case ValueKind::DynamicMethodBranchInst:
|
||||||
case ValueKind::DynamicMethodInst:
|
case ValueKind::DynamicMethodInst:
|
||||||
case ValueKind::EnumInst:
|
case ValueKind::EnumInst:
|
||||||
|
|||||||
@@ -1001,6 +1001,7 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
|
|||||||
UNARY_INSTRUCTION(CondFail)
|
UNARY_INSTRUCTION(CondFail)
|
||||||
UNARY_INSTRUCTION(RetainValue)
|
UNARY_INSTRUCTION(RetainValue)
|
||||||
UNARY_INSTRUCTION(ReleaseValue)
|
UNARY_INSTRUCTION(ReleaseValue)
|
||||||
|
UNARY_INSTRUCTION(AutoreleaseValue)
|
||||||
UNARY_INSTRUCTION(DeinitExistential)
|
UNARY_INSTRUCTION(DeinitExistential)
|
||||||
UNARY_INSTRUCTION(DestroyAddr)
|
UNARY_INSTRUCTION(DestroyAddr)
|
||||||
UNARY_INSTRUCTION(IsNonnull)
|
UNARY_INSTRUCTION(IsNonnull)
|
||||||
|
|||||||
@@ -625,6 +625,7 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
|
|||||||
case ValueKind::CondFailInst:
|
case ValueKind::CondFailInst:
|
||||||
case ValueKind::RetainValueInst:
|
case ValueKind::RetainValueInst:
|
||||||
case ValueKind::ReleaseValueInst:
|
case ValueKind::ReleaseValueInst:
|
||||||
|
case ValueKind::AutoreleaseValueInst:
|
||||||
case ValueKind::DeallocStackInst:
|
case ValueKind::DeallocStackInst:
|
||||||
case ValueKind::DeallocRefInst:
|
case ValueKind::DeallocRefInst:
|
||||||
case ValueKind::DeinitExistentialInst:
|
case ValueKind::DeinitExistentialInst:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// RUN: %swift -emit-ir -target x86_64-apple-darwin10 %s | FileCheck %s
|
// RUN: %swift -emit-ir -target x86_64-apple-darwin10 %s | FileCheck %s
|
||||||
|
|
||||||
import Builtin
|
import Builtin
|
||||||
|
import Swift
|
||||||
|
|
||||||
// CHECK: [[OBJCCLASS:%objc_class]] = type
|
// CHECK: [[OBJCCLASS:%objc_class]] = type
|
||||||
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
|
// CHECK: [[OPAQUE:%swift.opaque]] = type opaque
|
||||||
@@ -126,3 +127,22 @@ bb0(%0 : $@thick C.Type):
|
|||||||
return %1 : $C
|
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?
|
||||||
|
}
|
||||||
|
|||||||
@@ -935,9 +935,11 @@ sil @test_copy_release_value : $(Val) -> (Val) {
|
|||||||
bb0(%0 : $Val):
|
bb0(%0 : $Val):
|
||||||
retain_value %0 : $Val
|
retain_value %0 : $Val
|
||||||
release_value %0 : $Val
|
release_value %0 : $Val
|
||||||
|
autorelease_value %0 : $Val
|
||||||
return %0 : $Val
|
return %0 : $Val
|
||||||
// CHECK: retain_value [[T0:%.*]] : $Val
|
// CHECK: retain_value [[T0:%.*]] : $Val
|
||||||
// CHECK-NEXT: release_value [[T0]] : $Val
|
// CHECK-NEXT: release_value [[T0]] : $Val
|
||||||
|
// CHECK-NEXT: autorelease_value [[T0]] : $Val
|
||||||
// CHECK-NEXT: return [[T0]] : $Val
|
// CHECK-NEXT: return [[T0]] : $Val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -864,9 +864,11 @@ sil @test_copy_release_value : $@thin (Val) -> (Val) {
|
|||||||
bb0(%0 : $Val):
|
bb0(%0 : $Val):
|
||||||
retain_value %0 : $Val
|
retain_value %0 : $Val
|
||||||
release_value %0 : $Val
|
release_value %0 : $Val
|
||||||
|
autorelease_value %0 : $Val
|
||||||
return %0 : $Val
|
return %0 : $Val
|
||||||
// CHECK: retain_value [[T0:%.*]] : $Val
|
// CHECK: retain_value [[T0:%.*]] : $Val
|
||||||
// CHECK-NEXT: release_value [[T0]] : $Val
|
// CHECK-NEXT: release_value [[T0]] : $Val
|
||||||
|
// CHECK-NEXT: autorelease_value [[T0]] : $Val
|
||||||
// CHECK-NEXT: return [[T0]] : $Val
|
// CHECK-NEXT: return [[T0]] : $Val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user