mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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() ||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user