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:
Joe Groff
2014-04-21 23:11:38 +00:00
parent c56458d173
commit dcad7fb248
17 changed files with 85 additions and 1 deletions

View File

@@ -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));

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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)

View File

@@ -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>;

View File

@@ -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()))

View File

@@ -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))

View File

@@ -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)

View File

@@ -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(),

View File

@@ -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");

View File

@@ -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:

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -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?
}

View File

@@ -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
} }

View File

@@ -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
} }