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));
|
||||
}
|
||||
|
||||
AutoreleaseValueInst *createAutoreleaseValue(SILLocation loc, SILValue operand) {
|
||||
return insert(new (F.getModule()) AutoreleaseValueInst(loc, operand));
|
||||
}
|
||||
|
||||
StructInst *createStruct(SILLocation Loc, SILType Ty,
|
||||
ArrayRef<SILValue> Elements) {
|
||||
return insert(StructInst::create(Loc, Ty, Elements, F));
|
||||
|
||||
@@ -587,6 +587,14 @@ SILCloner<ImplClass>::visitReleaseValueInst(ReleaseValueInst *Inst) {
|
||||
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>
|
||||
void
|
||||
SILCloner<ImplClass>::visitStructInst(StructInst *Inst) {
|
||||
|
||||
@@ -1337,6 +1337,16 @@ public:
|
||||
: 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.
|
||||
class TupleInst : public SILInstruction {
|
||||
TailAllocatedOperandList<0> Operands;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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<LoadableTypeInfo>(getTypeInfo(i->getOperand().getType()))
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user