SIL: Add unchecked_{trivial,ref}_bit_cast instructions.

These instructions do a bitcast operation without stack traffic (at the SIL level). unchecked_trivial_bit_cast represents a conversion from a potentially nontrivial type to a trivial type, such as from a class reference to Int. unchecked_ref_bit_cast represents a conversion between types for which retain_value and release_value has equivalent effects when applied on the input or output values.

Swift SVN r19053
This commit is contained in:
Joe Groff
2014-06-20 22:02:38 +00:00
parent 7a15e4b479
commit d9d451cea5
15 changed files with 196 additions and 2 deletions

View File

@@ -352,6 +352,18 @@ public:
return insert(new (F.getModule()) UncheckedAddrCastInst(Loc, Op, Ty));
}
UncheckedTrivialBitCastInst *createUncheckedTrivialBitCast(SILLocation Loc,
SILValue Op,
SILType Ty) {
return insert(new (F.getModule()) UncheckedTrivialBitCastInst(Loc, Op, Ty));
}
UncheckedRefBitCastInst *createUncheckedRefBitCast(SILLocation Loc,
SILValue Op,
SILType Ty) {
return insert(new (F.getModule()) UncheckedRefBitCastInst(Loc, Op, Ty));
}
RefToRawPointerInst *createRefToRawPointer(SILLocation Loc, SILValue Op,
SILType Ty) {
return insert(new (F.getModule()) RefToRawPointerInst(Loc, Op, Ty));

View File

@@ -556,6 +556,26 @@ visitUncheckedAddrCastInst(UncheckedAddrCastInst *Inst) {
getOpType(Inst->getType())));
}
template<typename ImplClass>
void
SILCloner<ImplClass>::
visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *Inst) {
doPostProcess(Inst,
getBuilder().createUncheckedTrivialBitCast(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpType(Inst->getType())));
}
template<typename ImplClass>
void
SILCloner<ImplClass>::
visitUncheckedRefBitCastInst(UncheckedRefBitCastInst *Inst) {
doPostProcess(Inst,
getBuilder().createUncheckedRefBitCast(getOpLocation(Inst->getLoc()),
getOpValue(Inst->getOperand()),
getOpType(Inst->getType())));
}
template<typename ImplClass>
void
SILCloner<ImplClass>::visitRefToRawPointerInst(RefToRawPointerInst *Inst) {

View File

@@ -1233,6 +1233,29 @@ public:
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// Convert a value's binary representation to a trivial type of the same size.
class UncheckedTrivialBitCastInst
: public UnaryInstructionBase<ValueKind::UncheckedTrivialBitCastInst,
ConversionInst>
{
public:
UncheckedTrivialBitCastInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// Convert a value to a layout-compatible type with equivalent
/// "reference semantics identity", that is, a type for which retain_value and
/// release_value have equivalent effects to retaining or releasing the original
/// value.
class UncheckedRefBitCastInst
: public UnaryInstructionBase<ValueKind::UncheckedRefBitCastInst,
ConversionInst>
{
public:
UncheckedRefBitCastInst(SILLocation Loc, SILValue Operand, SILType Ty)
: UnaryInstructionBase(Loc, Operand, Ty) {}
};
/// RefToRawPointer - Convert a reference type to a Builtin.RawPointer.
class RefToRawPointerInst
: public UnaryInstructionBase<ValueKind::RefToRawPointerInst, ConversionInst>

View File

@@ -179,6 +179,8 @@ ABSTRACT_VALUE(SILInstruction, ValueBase)
INST(PointerToAddressInst, ConversionInst, None)
INST(UncheckedRefCastInst, ConversionInst, None)
INST(UncheckedAddrCastInst, ConversionInst, None)
INST(UncheckedTrivialBitCastInst, ConversionInst, None)
INST(UncheckedRefBitCastInst, ConversionInst, None)
INST(RefToRawPointerInst, ConversionInst, None)
INST(RawPointerToRefInst, ConversionInst, None)
INST(RefToUnownedInst, ConversionInst, None)

View File

@@ -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 = 103;
const uint16_t VERSION_MINOR = 105;
using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;

View File

@@ -657,6 +657,8 @@ public:
void visitPointerToAddressInst(PointerToAddressInst *i);
void visitUncheckedRefCastInst(UncheckedRefCastInst *i);
void visitUncheckedAddrCastInst(UncheckedAddrCastInst *i);
void visitUncheckedRefBitCastInst(UncheckedRefBitCastInst *i);
void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *i);
void visitRefToRawPointerInst(RefToRawPointerInst *i);
void visitRawPointerToRefInst(RawPointerToRefInst *i);
void visitRefToUnownedInst(RefToUnownedInst *i);
@@ -2632,6 +2634,64 @@ void IRGenSILFunction::visitUncheckedAddrCastInst(
setLoweredAddress(SILValue(i, 0), result);
}
static void emitValueBitCast(IRGenFunction &IGF,
SourceLoc loc,
Explosion &in,
const LoadableTypeInfo &inTI,
Explosion &out,
const LoadableTypeInfo &outTI) {
// Unfortunately, we can't check this invariant until we get to IRGen, since
// the AST and SIL don't know anything about type layout.
if (inTI.getFixedSize() != outTI.getFixedSize()) {
IGF.unimplemented(loc, "bitcast between types of different size");
in.claimAll();
for (auto schema : outTI.getSchema(out.getKind()))
out.add(llvm::UndefValue::get(schema.getScalarType()));
return;
}
// TODO: We could do bitcasts entirely in the value domain in some cases, but
// for simplicity, let's just always go through the stack for now.
// Create the allocation.
auto inStorage = IGF.createAlloca(inTI.getStorageType(),
std::max(inTI.getFixedAlignment(),
outTI.getFixedAlignment()),
"bitcast");
// Store the 'in' value.
inTI.initialize(IGF, in, inStorage);
// Load the 'out' value as the destination type.
auto outStorage = IGF.Builder.CreateBitCast(inStorage,
outTI.getStorageType());
outTI.loadAsTake(IGF, outStorage, out);
return;
}
void IRGenSILFunction::visitUncheckedTrivialBitCastInst(
swift::UncheckedTrivialBitCastInst *i) {
Explosion in = getLoweredExplosion(i->getOperand());
Explosion out(in.getKind());
emitValueBitCast(*this, i->getLoc().getSourceLoc(),
in, cast<LoadableTypeInfo>(getTypeInfo(i->getOperand().getType())),
out, cast<LoadableTypeInfo>(getTypeInfo(i->getType())));
setLoweredExplosion(SILValue(i, 0), out);
}
void IRGenSILFunction::visitUncheckedRefBitCastInst(
swift::UncheckedRefBitCastInst *i) {
Explosion in = getLoweredExplosion(i->getOperand());
Explosion out(in.getKind());
emitValueBitCast(*this, i->getLoc().getSourceLoc(),
in, cast<LoadableTypeInfo>(getTypeInfo(i->getOperand().getType())),
out, cast<LoadableTypeInfo>(getTypeInfo(i->getType())));
setLoweredExplosion(SILValue(i, 0), out);
}
void IRGenSILFunction::visitRefToRawPointerInst(
swift::RefToRawPointerInst *i) {
emitPointerCastInst(*this, i->getOperand(), SILValue(i, 0),

View File

@@ -1175,6 +1175,8 @@ bool SILParser::parseSILOpcode(ValueKind &Opcode, SourceLoc &OpcodeLoc,
.Case("switch_enum", ValueKind::SwitchEnumInst)
.Case("unchecked_enum_data", ValueKind::UncheckedEnumDataInst)
.Case("unchecked_addr_cast", ValueKind::UncheckedAddrCastInst)
.Case("unchecked_trivial_bit_cast", ValueKind::UncheckedTrivialBitCastInst)
.Case("unchecked_ref_bit_cast", ValueKind::UncheckedRefBitCastInst)
.Case("unchecked_ref_cast", ValueKind::UncheckedRefCastInst)
.Case("unchecked_take_enum_data_addr", ValueKind::UncheckedTakeEnumDataAddrInst)
.Case("thick_to_objc_metatype", ValueKind::ThickToObjCMetatypeInst)
@@ -1644,6 +1646,8 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
// Conversion instructions.
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::UncheckedRefBitCastInst:
case ValueKind::UpcastInst:
case ValueKind::AddressToPointerInst:
case ValueKind::PointerToAddressInst:
@@ -1682,6 +1686,12 @@ bool SILParser::parseSILInstruction(SILBasicBlock *BB) {
case ValueKind::UncheckedAddrCastInst:
ResultVal = B.createUncheckedAddrCast(InstLoc, Val, Ty);
break;
case ValueKind::UncheckedTrivialBitCastInst:
ResultVal = B.createUncheckedTrivialBitCast(InstLoc, Val, Ty);
break;
case ValueKind::UncheckedRefBitCastInst:
ResultVal = B.createUncheckedRefBitCast(InstLoc, Val, Ty);
break;
case ValueKind::UpcastInst:
ResultVal = B.createUpcast(InstLoc, Val, Ty);
break;

View File

@@ -803,6 +803,12 @@ public:
void visitUncheckedAddrCastInst(UncheckedAddrCastInst *CI) {
printUncheckedConversionInst(CI, CI->getOperand(), "unchecked_addr_cast");
}
void visitUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *CI) {
printUncheckedConversionInst(CI, CI->getOperand(), "unchecked_trivial_bit_cast");
}
void visitUncheckedRefBitCastInst(UncheckedRefBitCastInst *CI) {
printUncheckedConversionInst(CI, CI->getOperand(), "unchecked_ref_bit_cast");
}
void visitRefToRawPointerInst(RefToRawPointerInst *CI) {
printUncheckedConversionInst(CI, CI->getOperand(), "ref_to_raw_pointer");
}

View File

@@ -1708,6 +1708,30 @@ public:
"unchecked_addr_cast result must be an address");
}
void checkUncheckedTrivialBitCastInst(UncheckedTrivialBitCastInst *BI) {
require(BI->getOperand().getType().isObject(),
"unchecked_trivial_bit_cast must operate on a value");
require(BI->getType().isObject(),
"unchecked_trivial_bit_cast must produce a value");
require(BI->getType().isTrivial(F.getModule()),
"unchecked_trivial_bit_cast must produce a value of trivial type");
}
void checkUncheckedRefBitCastInst(UncheckedRefBitCastInst *BI) {
require(BI->getOperand().getType().isObject(),
"unchecked_ref_bit_cast must operate on a value");
require(BI->getType().isObject(),
"unchecked_ref_bit_cast must produce a value");
// TODO: A deeper comparison of the source and destination types to ensure
// they're reference-counting-identical.
auto &M = F.getModule();
require(BI->getOperand().getType().isTrivial(M)
== BI->getType().isTrivial(M),
"unchecked_ref_bit_cast cannot change the reference count semantics"
" of the value");
}
void checkRefToRawPointerInst(RefToRawPointerInst *AI) {
require(AI->getOperand().getType()
.getSwiftType()->mayHaveSuperclass() ||

View File

@@ -117,6 +117,8 @@ static bool isTransitiveEscapeInst(SILInstruction *Inst) {
case ValueKind::ObjCToThickMetatypeInst:
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::UncheckedRefBitCastInst:
case ValueKind::OpenExistentialInst:
case ValueKind::OpenExistentialRefInst:
case ValueKind::PartialApplyInst:

View File

@@ -280,6 +280,8 @@ static InlineCost instructionInlineCost(SILInstruction &I,
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedRefBitCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::RawPointerToRefInst:
case ValueKind::RefToRawPointerInst:

View File

@@ -744,6 +744,8 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
// Conversion instructions.
ONEOPERAND_ONETYPE_INST(UncheckedRefCast)
ONEOPERAND_ONETYPE_INST(UncheckedAddrCast)
ONEOPERAND_ONETYPE_INST(UncheckedTrivialBitCast)
ONEOPERAND_ONETYPE_INST(UncheckedRefBitCast)
ONEOPERAND_ONETYPE_INST(Upcast)
ONEOPERAND_ONETYPE_INST(AddressToPointer)
ONEOPERAND_ONETYPE_INST(PointerToAddress)

View File

@@ -883,6 +883,8 @@ void SILSerializer::writeSILInstruction(const SILInstruction &SI) {
// Conversion instructions.
case ValueKind::UncheckedRefCastInst:
case ValueKind::UncheckedAddrCastInst:
case ValueKind::UncheckedTrivialBitCastInst:
case ValueKind::UncheckedRefBitCastInst:
case ValueKind::UpcastInst:
case ValueKind::AddressToPointerInst:
case ValueKind::PointerToAddressInst:

View File

@@ -1097,6 +1097,20 @@ entry(%a : $@objc_metatype SomeClass.Type, %b : $@objc_metatype SomeClassProtoco
return %z : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil @bitcasts : $@thin (@owned Class1) -> @owned (Class2, Int) {
// CHECK-NEXT: bb0(%0 : $Class1):
// CHECK-NEXT: %1 = unchecked_ref_bit_cast %0 : $Class1 to $Class2
// CHECK-NEXT: %2 = unchecked_trivial_bit_cast %0 : $Class1 to $Int
// CHECK-NEXT: %3 = tuple (%1 : $Class2, %2 : $Int)
// CHECK-NEXT: return %3 : $(Class2, Int)
sil @bitcasts : $@thin (@owned Class1) -> @owned (Class2, Int) {
entry(%0 : $Class1):
%1 = unchecked_ref_bit_cast %0 : $Class1 to $Class2
%2 = unchecked_trivial_bit_cast %0 : $Class1 to $Int
%3 = tuple (%1 : $Class2, %2 : $Int)
return %3 : $(Class2, Int)
}
// CHECK-LABEL: sil_vtable Foo {
// CHECK: #Foo.subscript!getter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sig
// CHECK: #Foo.subscript!setter.1: _TC3tmp3Foo9subscriptFT1xSi1ySi_Sis

View File

@@ -917,6 +917,20 @@ entry(%a : $@objc_metatype SomeClass.Type, %b : $@objc_metatype SomeClassProtoco
return %z : $(AnyObject, AnyObject)
}
// CHECK-LABEL: sil public_external @bitcasts : $@thin (@owned Class1) -> @owned (Class2, Int) {
// CHECK-NEXT: bb0(%0 : $Class1):
// CHECK-NEXT: %1 = unchecked_ref_bit_cast %0 : $Class1 to $Class2
// CHECK-NEXT: %2 = unchecked_trivial_bit_cast %0 : $Class1 to $Int
// CHECK-NEXT: %3 = tuple (%1 : $Class2, %2 : $Int)
// CHECK-NEXT: return %3 : $(Class2, Int)
sil @bitcasts : $@thin (@owned Class1) -> @owned (Class2, Int) {
entry(%0 : $Class1):
%1 = unchecked_ref_bit_cast %0 : $Class1 to $Class2
%2 = unchecked_trivial_bit_cast %0 : $Class1 to $Int
%3 = tuple (%1 : $Class2, %2 : $Int)
return %3 : $(Class2, Int)
}
@objc protocol ObjCProto {}
// CHECK-LABEL: sil public_external @protocol_conversion
@@ -1172,6 +1186,7 @@ bb0:
%124 = function_ref @block_storage_type : $@thin Int -> @cc(cdecl) @objc_block () -> ()
%125 = function_ref @metatype_to_object : $@thin (@objc_metatype SomeClass.Type, @objc_metatype SomeClassProtocol.Type) -> @owned (AnyObject, AnyObject)
%127 = function_ref @bitcasts : $@thin (@owned Class1) -> @owned (Class2, Int)
%126 = function_ref @protocol_conversion : $@thin () -> @owned Protocol
%120 = function_ref @test_forward_ref : $@thin (UInt8, UInt8) -> UInt8
%121 = function_ref @partial_apply : $@thin (@thin (@out Int, Int) -> (), Int) -> Int