//===--- SILInstructions.cpp - Instructions for SIL code ------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the high-level SILInstruction classes used for SIL code. // //===----------------------------------------------------------------------===// #include "swift/SIL/SILInstruction.h" #include "swift/Basic/type_traits.h" #include "swift/Basic/Unicode.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILCloner.h" #include "swift/SIL/SILVisitor.h" #include "swift/AST/AST.h" #include "swift/Basic/AssertImplements.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/SIL/SILModule.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" using namespace swift; using namespace Lowering; //===----------------------------------------------------------------------===// // SILInstruction Subclasses //===----------------------------------------------------------------------===// template static void *allocateDebugVarCarryingInst(SILModule &M, SILDebugVariable Var) { return M.allocateInst(sizeof(INST) + Var.Name.size(), alignof(INST)); } TailAllocatedDebugVariable::TailAllocatedDebugVariable(SILDebugVariable Var, char *buf) : ArgNo(Var.ArgNo), NameLength(Var.Name.size()), Constant(Var.Constant) { assert((Var.ArgNo < (2<<16)) && "too many arguments"); assert((NameLength < (2<<15)) && "variable name too long"); memcpy(buf, Var.Name.data(), NameLength); } StringRef TailAllocatedDebugVariable::getName(const char *buf) const { return NameLength ? StringRef(buf, NameLength) : StringRef(); } AllocStackInst::AllocStackInst(SILDebugLocation Loc, SILType elementType, SILFunction &F, SILDebugVariable Var) : AllocationInst(ValueKind::AllocStackInst, Loc, elementType.getAddressType()), VarInfo(Var, getTrailingObjects()) {} AllocStackInst *AllocStackInst::create(SILDebugLocation Loc, SILType elementType, SILFunction &F, SILDebugVariable Var) { void *buf = allocateDebugVarCarryingInst(F.getModule(), Var); return ::new (buf) AllocStackInst(Loc, elementType, F, Var); } /// getDecl - Return the underlying variable declaration associated with this /// allocation, or null if this is a temporary allocation. VarDecl *AllocStackInst::getDecl() const { return getLoc().getAsASTNode(); } AllocRefInst::AllocRefInst(SILDebugLocation Loc, SILType elementType, SILFunction &F, bool objc, bool canBeOnStack) : AllocationInst(ValueKind::AllocRefInst, Loc, elementType), StackPromotable(canBeOnStack), ObjC(objc) {} AllocBoxInst::AllocBoxInst(SILDebugLocation Loc, SILType ElementType, SILFunction &F, SILDebugVariable Var) : AllocationInst(ValueKind::AllocBoxInst, Loc, SILType::getPrimitiveObjectType( SILBoxType::get(ElementType.getSwiftRValueType()))), VarInfo(Var, getTrailingObjects()) {} AllocBoxInst *AllocBoxInst::create(SILDebugLocation Loc, SILType ElementType, SILFunction &F, SILDebugVariable Var) { void *buf = allocateDebugVarCarryingInst(F.getModule(), Var); return ::new (buf) AllocBoxInst(Loc, ElementType, F, Var); } /// getDecl - Return the underlying variable declaration associated with this /// allocation, or null if this is a temporary allocation. VarDecl *AllocBoxInst::getDecl() const { return getLoc().getAsASTNode(); } DebugValueInst::DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand, SILDebugVariable Var) : UnaryInstructionBase(DebugLoc, Operand), VarInfo(Var, getTrailingObjects()) {} DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc, SILValue Operand, SILModule &M, SILDebugVariable Var) { void *buf = allocateDebugVarCarryingInst(M, Var); return ::new (buf) DebugValueInst(DebugLoc, Operand, Var); } DebugValueAddrInst::DebugValueAddrInst(SILDebugLocation DebugLoc, SILValue Operand, SILDebugVariable Var) : UnaryInstructionBase(DebugLoc, Operand), VarInfo(Var, getTrailingObjects()) {} DebugValueAddrInst *DebugValueAddrInst::create(SILDebugLocation DebugLoc, SILValue Operand, SILModule &M, SILDebugVariable Var) { void *buf = allocateDebugVarCarryingInst(M, Var); return ::new (buf) DebugValueAddrInst(DebugLoc, Operand, Var); } VarDecl *DebugValueInst::getDecl() const { return getLoc().getAsASTNode(); } VarDecl *DebugValueAddrInst::getDecl() const { return getLoc().getAsASTNode(); } AllocExistentialBoxInst::AllocExistentialBoxInst( SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType, ArrayRef Conformances, SILFunction *Parent) : AllocationInst(ValueKind::AllocExistentialBoxInst, Loc, ExistentialType.getObjectType()), ConcreteType(ConcreteType), Conformances(Conformances) {} static void declareWitnessTable(SILModule &Mod, ProtocolConformanceRef conformanceRef) { if (conformanceRef.isAbstract()) return; auto C = conformanceRef.getConcrete(); if (!Mod.lookUpWitnessTable(C, false)) Mod.createWitnessTableDeclaration(C, TypeConverter::getLinkageForProtocolConformance( C->getRootNormalConformance(), NotForDefinition)); } AllocExistentialBoxInst *AllocExistentialBoxInst::create( SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(AllocExistentialBoxInst), alignof(AllocExistentialBoxInst)); for (ProtocolConformanceRef C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) AllocExistentialBoxInst(Loc, ExistentialType, ConcreteType, Conformances, F); } BuiltinInst *BuiltinInst::create(SILDebugLocation Loc, Identifier Name, SILType ReturnType, ArrayRef Substitutions, ArrayRef Args, SILFunction &F) { void *Buffer = F.getModule().allocateInst( sizeof(BuiltinInst) + decltype(Operands)::getExtraSize(Args.size()) + sizeof(Substitution) * Substitutions.size(), alignof(BuiltinInst)); return ::new (Buffer) BuiltinInst(Loc, Name, ReturnType, Substitutions, Args); } BuiltinInst::BuiltinInst(SILDebugLocation Loc, Identifier Name, SILType ReturnType, ArrayRef Subs, ArrayRef Args) : SILInstruction(ValueKind::BuiltinInst, Loc, ReturnType), Name(Name), NumSubstitutions(Subs.size()), Operands(this, Args) { static_assert(IsTriviallyCopyable::value, "assuming Substitution is trivially copyable"); memcpy(getSubstitutionsStorage(), Subs.begin(), sizeof(Substitution) * Subs.size()); } ApplyInst::ApplyInst(SILDebugLocation Loc, SILValue Callee, SILType SubstCalleeTy, SILType Result, ArrayRef Subs, ArrayRef Args, bool isNonThrowing) : ApplyInstBase(ValueKind::ApplyInst, Loc, Callee, SubstCalleeTy, Subs, Args, Result) { setNonThrowing(isNonThrowing); } ApplyInst *ApplyInst::create(SILDebugLocation Loc, SILValue Callee, SILType SubstCalleeTy, SILType Result, ArrayRef Subs, ArrayRef Args, bool isNonThrowing, SILFunction &F) { void *Buffer = allocate(F, Subs, Args); return ::new(Buffer) ApplyInst(Loc, Callee, SubstCalleeTy, Result, Subs, Args, isNonThrowing); } bool swift::doesApplyCalleeHaveSemantics(SILValue callee, StringRef semantics) { if (auto *FRI = dyn_cast(callee)) if (auto *F = FRI->getReferencedFunction()) return F->hasSemanticsAttr(semantics); return false; } void *swift::allocateApplyInst(SILFunction &F, size_t size, size_t alignment) { return F.getModule().allocateInst(size, alignment); } PartialApplyInst::PartialApplyInst(SILDebugLocation Loc, SILValue Callee, SILType SubstCalleeTy, ArrayRef Subs, ArrayRef Args, SILType ClosureType) // FIXME: the callee should have a lowered SIL function type, and // PartialApplyInst // should derive the type of its result by partially applying the callee's // type. : ApplyInstBase(ValueKind::PartialApplyInst, Loc, Callee, SubstCalleeTy, Subs, Args, ClosureType) {} PartialApplyInst * PartialApplyInst::create(SILDebugLocation Loc, SILValue Callee, SILType SubstCalleeTy, ArrayRef Subs, ArrayRef Args, SILType ClosureType, SILFunction &F) { void *Buffer = allocate(F, Subs, Args); return ::new(Buffer) PartialApplyInst(Loc, Callee, SubstCalleeTy, Subs, Args, ClosureType); } TryApplyInstBase::TryApplyInstBase(ValueKind valueKind, SILDebugLocation Loc, SILBasicBlock *normalBB, SILBasicBlock *errorBB) : TermInst(valueKind, Loc), DestBBs{{this, normalBB}, {this, errorBB}} {} TryApplyInst::TryApplyInst(SILDebugLocation Loc, SILValue callee, SILType substCalleeTy, ArrayRef subs, ArrayRef args, SILBasicBlock *normalBB, SILBasicBlock *errorBB) : ApplyInstBase(ValueKind::TryApplyInst, Loc, callee, substCalleeTy, subs, args, normalBB, errorBB) {} TryApplyInst *TryApplyInst::create(SILDebugLocation Loc, SILValue callee, SILType substCalleeTy, ArrayRef subs, ArrayRef args, SILBasicBlock *normalBB, SILBasicBlock *errorBB, SILFunction &F) { void *buffer = allocate(F, subs, args); return ::new (buffer) TryApplyInst(Loc, callee, substCalleeTy, subs, args, normalBB, errorBB); } FunctionRefInst::FunctionRefInst(SILDebugLocation Loc, SILFunction *F) : LiteralInst(ValueKind::FunctionRefInst, Loc, F->getLoweredType()), Function(F) { F->incrementRefCount(); } FunctionRefInst::~FunctionRefInst() { if (Function) Function->decrementRefCount(); } void FunctionRefInst::dropReferencedFunction() { if (Function) Function->decrementRefCount(); Function = nullptr; } AllocGlobalInst::AllocGlobalInst(SILDebugLocation Loc, SILGlobalVariable *Global) : SILInstruction(ValueKind::AllocGlobalInst, Loc), Global(Global) {} AllocGlobalInst::AllocGlobalInst(SILDebugLocation Loc) : SILInstruction(ValueKind::AllocGlobalInst, Loc) {} GlobalAddrInst::GlobalAddrInst(SILDebugLocation Loc, SILGlobalVariable *Global) : LiteralInst(ValueKind::GlobalAddrInst, Loc, Global->getLoweredType().getAddressType()), Global(Global) {} GlobalAddrInst::GlobalAddrInst(SILDebugLocation Loc, SILType Ty) : LiteralInst(ValueKind::GlobalAddrInst, Loc, Ty), Global(nullptr) {} const IntrinsicInfo &BuiltinInst::getIntrinsicInfo() const { return getModule().getIntrinsicInfo(getName()); } const BuiltinInfo &BuiltinInst::getBuiltinInfo() const { return getModule().getBuiltinInfo(getName()); } static unsigned getWordsForBitWidth(unsigned bits) { return (bits + llvm::integerPartWidth - 1)/llvm::integerPartWidth; } template static void *allocateLiteralInstWithTextSize(SILFunction &F, unsigned length) { return F.getModule().allocateInst(sizeof(INST) + length, alignof(INST)); } template static void *allocateLiteralInstWithBitSize(SILFunction &F, unsigned bits) { unsigned words = getWordsForBitWidth(bits); return F.getModule().allocateInst( sizeof(INST) + sizeof(llvm::integerPart)*words, alignof(INST)); } IntegerLiteralInst::IntegerLiteralInst(SILDebugLocation Loc, SILType Ty, const llvm::APInt &Value) : LiteralInst(ValueKind::IntegerLiteralInst, Loc, Ty), numBits(Value.getBitWidth()) { std::uninitialized_copy_n(Value.getRawData(), Value.getNumWords(), getTrailingObjects()); } IntegerLiteralInst *IntegerLiteralInst::create(SILDebugLocation Loc, SILType Ty, const APInt &Value, SILFunction &B) { auto intTy = Ty.castTo(); assert(intTy->getGreatestWidth() == Value.getBitWidth() && "IntegerLiteralInst APInt value's bit width doesn't match type"); (void)intTy; void *buf = allocateLiteralInstWithBitSize(B, Value.getBitWidth()); return ::new (buf) IntegerLiteralInst(Loc, Ty, Value); } IntegerLiteralInst *IntegerLiteralInst::create(SILDebugLocation Loc, SILType Ty, intmax_t Value, SILFunction &B) { auto intTy = Ty.castTo(); return create(Loc, Ty, APInt(intTy->getGreatestWidth(), Value), B); } IntegerLiteralInst *IntegerLiteralInst::create(IntegerLiteralExpr *E, SILDebugLocation Loc, SILFunction &F) { return create( Loc, SILType::getBuiltinIntegerType( E->getType()->castTo()->getGreatestWidth(), F.getASTContext()), E->getValue(), F); } /// getValue - Return the APInt for the underlying integer literal. APInt IntegerLiteralInst::getValue() const { return APInt(numBits, {getTrailingObjects(), getWordsForBitWidth(numBits)}); } FloatLiteralInst::FloatLiteralInst(SILDebugLocation Loc, SILType Ty, const APInt &Bits) : LiteralInst(ValueKind::FloatLiteralInst, Loc, Ty), numBits(Bits.getBitWidth()) { std::uninitialized_copy_n(Bits.getRawData(), Bits.getNumWords(), getTrailingObjects()); } FloatLiteralInst *FloatLiteralInst::create(SILDebugLocation Loc, SILType Ty, const APFloat &Value, SILFunction &B) { auto floatTy = Ty.castTo(); assert(&floatTy->getAPFloatSemantics() == &Value.getSemantics() && "FloatLiteralInst value's APFloat semantics do not match type"); (void)floatTy; APInt Bits = Value.bitcastToAPInt(); void *buf = allocateLiteralInstWithBitSize(B, Bits.getBitWidth()); return ::new (buf) FloatLiteralInst(Loc, Ty, Bits); } FloatLiteralInst *FloatLiteralInst::create(FloatLiteralExpr *E, SILDebugLocation Loc, SILFunction &F) { return create(Loc, // Builtin floating-point types are always valid SIL types. SILType::getBuiltinFloatType( E->getType()->castTo()->getFPKind(), F.getASTContext()), E->getValue(), F); } APInt FloatLiteralInst::getBits() const { return APInt(numBits, {getTrailingObjects(), getWordsForBitWidth(numBits)}); } APFloat FloatLiteralInst::getValue() const { return APFloat(getType().castTo()->getAPFloatSemantics(), getBits()); } StringLiteralInst::StringLiteralInst(SILDebugLocation Loc, StringRef Text, Encoding encoding, SILType Ty) : LiteralInst(ValueKind::StringLiteralInst, Loc, Ty), Length(Text.size()), TheEncoding(encoding) { memcpy(getTrailingObjects(), Text.data(), Text.size()); } StringLiteralInst *StringLiteralInst::create(SILDebugLocation Loc, StringRef text, Encoding encoding, SILFunction &F) { void *buf = allocateLiteralInstWithTextSize(F, text.size()); auto Ty = SILType::getRawPointerType(F.getModule().getASTContext()); return ::new (buf) StringLiteralInst(Loc, text, encoding, Ty); } uint64_t StringLiteralInst::getCodeUnitCount() { if (TheEncoding == Encoding::UTF16) return unicode::getUTF16Length(getValue()); return Length; } StoreInst::StoreInst(SILDebugLocation Loc, SILValue Src, SILValue Dest) : SILInstruction(ValueKind::StoreInst, Loc), Operands(this, Src, Dest) {} AssignInst::AssignInst(SILDebugLocation Loc, SILValue Src, SILValue Dest) : SILInstruction(ValueKind::AssignInst, Loc), Operands(this, Src, Dest) {} MarkFunctionEscapeInst * MarkFunctionEscapeInst::create(SILDebugLocation Loc, ArrayRef Elements, SILFunction &F) { void *Buffer = F.getModule().allocateInst(sizeof(MarkFunctionEscapeInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(MarkFunctionEscapeInst)); return ::new(Buffer) MarkFunctionEscapeInst(Loc, Elements); } MarkFunctionEscapeInst::MarkFunctionEscapeInst(SILDebugLocation Loc, ArrayRef Elems) : SILInstruction(ValueKind::MarkFunctionEscapeInst, Loc), Operands(this, Elems) {} static SILType getPinResultType(SILType operandType) { return SILType::getPrimitiveObjectType( OptionalType::get(operandType.getSwiftRValueType())->getCanonicalType()); } StrongPinInst::StrongPinInst(SILDebugLocation Loc, SILValue operand) : UnaryInstructionBase(Loc, operand, getPinResultType(operand->getType())) {} CopyAddrInst::CopyAddrInst(SILDebugLocation Loc, SILValue SrcLValue, SILValue DestLValue, IsTake_t isTakeOfSrc, IsInitialization_t isInitializationOfDest) : SILInstruction(ValueKind::CopyAddrInst, Loc), IsTakeOfSrc(isTakeOfSrc), IsInitializationOfDest(isInitializationOfDest), Operands(this, SrcLValue, DestLValue) {} UncheckedRefCastAddrInst::UncheckedRefCastAddrInst(SILDebugLocation Loc, SILValue src, CanType srcType, SILValue dest, CanType targetType) : SILInstruction(ValueKind::UncheckedRefCastAddrInst, Loc), Operands(this, src, dest), SourceType(srcType), TargetType(targetType) {} UnconditionalCheckedCastAddrInst::UnconditionalCheckedCastAddrInst( SILDebugLocation Loc, CastConsumptionKind consumption, SILValue src, CanType srcType, SILValue dest, CanType targetType) : SILInstruction(ValueKind::UnconditionalCheckedCastAddrInst, Loc), Operands(this, src, dest), ConsumptionKind(consumption), SourceType(srcType), TargetType(targetType) {} StructInst *StructInst::create(SILDebugLocation Loc, SILType Ty, ArrayRef Elements, SILFunction &F) { void *Buffer = F.getModule().allocateInst(sizeof(StructInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(StructInst)); return ::new(Buffer) StructInst(Loc, Ty, Elements); } StructInst::StructInst(SILDebugLocation Loc, SILType Ty, ArrayRef Elems) : SILInstruction(ValueKind::StructInst, Loc, Ty), Operands(this, Elems) { assert(!Ty.getStructOrBoundGenericStruct()->hasUnreferenceableStorage()); } TupleInst *TupleInst::create(SILDebugLocation Loc, SILType Ty, ArrayRef Elements, SILFunction &F) { void *Buffer = F.getModule().allocateInst(sizeof(TupleInst) + decltype(Operands)::getExtraSize(Elements.size()), alignof(TupleInst)); return ::new(Buffer) TupleInst(Loc, Ty, Elements); } TupleInst::TupleInst(SILDebugLocation Loc, SILType Ty, ArrayRef Elems) : SILInstruction(ValueKind::TupleInst, Loc, Ty), Operands(this, Elems) {} MetatypeInst::MetatypeInst(SILDebugLocation Loc, SILType Metatype) : SILInstruction(ValueKind::MetatypeInst, Loc, Metatype) {} bool TupleExtractInst::isTrivialEltOfOneRCIDTuple() const { SILModule &Mod = getModule(); // If we are not trivial, bail. if (!getType().isTrivial(Mod)) return false; // If the elt we are extracting is trivial, we cannot have any non trivial // fields. if (getOperand()->getType().isTrivial(Mod)) return false; // Ok, now we know that our tuple has non-trivial fields. Make sure that our // parent tuple has only one non-trivial field. bool FoundNonTrivialField = false; SILType OpTy = getOperand()->getType(); unsigned FieldNo = getFieldNo(); // For each element index of the tuple... for (unsigned i = 0, e = getNumTupleElts(); i != e; ++i) { // If the element index is the one we are extracting, skip it... if (i == FieldNo) continue; // Otherwise check if we have a non-trivial type. If we don't have one, // continue. if (OpTy.getTupleElementType(i).isTrivial(Mod)) continue; // Ok, this type is non-trivial. If we have not seen a non-trivial field // yet, set the FoundNonTrivialField flag. if (!FoundNonTrivialField) { FoundNonTrivialField = true; continue; } // If we have seen a field and thus the FoundNonTrivialField flag is set, // return false. return false; } // We found only one trivial field. assert(FoundNonTrivialField && "Tuple is non-trivial, but does not have a " "non-trivial element?!"); return true; } bool TupleExtractInst::isEltOnlyNonTrivialElt() const { SILModule &Mod = getModule(); // If the elt we are extracting is trivial, we cannot be a non-trivial // field... return false. if (getType().isTrivial(Mod)) return false; // Ok, we know that the elt we are extracting is non-trivial. Make sure that // we have no other non-trivial elts. SILType OpTy = getOperand()->getType(); unsigned FieldNo = getFieldNo(); // For each element index of the tuple... for (unsigned i = 0, e = getNumTupleElts(); i != e; ++i) { // If the element index is the one we are extracting, skip it... if (i == FieldNo) continue; // Otherwise check if we have a non-trivial type. If we don't have one, // continue. if (OpTy.getTupleElementType(i).isTrivial(Mod)) continue; // If we do have a non-trivial type, return false. We have multiple // non-trivial types violating our condition. return false; } // We checked every other elt of the tuple and did not find any // non-trivial elt except for ourselves. Return true. return true; } bool StructExtractInst::isTrivialFieldOfOneRCIDStruct() const { SILModule &Mod = getModule(); // If we are not trivial, bail. if (!getType().isTrivial(Mod)) return false; SILType StructTy = getOperand()->getType(); // If the elt we are extracting is trivial, we cannot have any non trivial // fields. if (StructTy.isTrivial(Mod)) return false; // Ok, now we know that our tuple has non-trivial fields. Make sure that our // parent tuple has only one non-trivial field. bool FoundNonTrivialField = false; // For each element index of the tuple... for (VarDecl *D : getStructDecl()->getStoredProperties()) { // If the field is the one we are extracting, skip it... if (Field == D) continue; // Otherwise check if we have a non-trivial type. If we don't have one, // continue. if (StructTy.getFieldType(D, Mod).isTrivial(Mod)) continue; // Ok, this type is non-trivial. If we have not seen a non-trivial field // yet, set the FoundNonTrivialField flag. if (!FoundNonTrivialField) { FoundNonTrivialField = true; continue; } // If we have seen a field and thus the FoundNonTrivialField flag is set, // return false. return false; } // We found only one trivial field. assert(FoundNonTrivialField && "Struct is non-trivial, but does not have a " "non-trivial field?!"); return true; } /// Return true if we are extracting the only non-trivial field of out parent /// struct. This implies that a ref count operation on the aggregate is /// equivalent to a ref count operation on this field. bool StructExtractInst::isFieldOnlyNonTrivialField() const { SILModule &Mod = getModule(); // If the field we are extracting is trivial, we cannot be a non-trivial // field... return false. if (getType().isTrivial(Mod)) return false; SILType StructTy = getOperand()->getType(); // Ok, we are visiting a non-trivial field. Then for every stored field... for (VarDecl *D : getStructDecl()->getStoredProperties()) { // If we are visiting our own field continue. if (Field == D) continue; // Ok, we have a field that is not equal to the field we are // extracting. If that field is trivial, we do not care about // it... continue. if (StructTy.getFieldType(D, Mod).isTrivial(Mod)) continue; // We have found a non trivial member that is not the member we are // extracting, fail. return false; } // We checked every other field of the struct and did not find any // non-trivial fields except for ourselves. Return true. return true; } //===----------------------------------------------------------------------===// // Instructions representing terminators //===----------------------------------------------------------------------===// TermInst::SuccessorListTy TermInst::getSuccessors() { #define TERMINATOR(TYPE, PARENT, EFFECT, RELEASING) \ if (auto I = dyn_cast(this)) \ return I->getSuccessors(); #include "swift/SIL/SILNodes.def" llvm_unreachable("not a terminator?!"); } BranchInst::BranchInst(SILDebugLocation Loc, SILBasicBlock *DestBB, ArrayRef Args) : TermInst(ValueKind::BranchInst, Loc), DestBB(this, DestBB), Operands(this, Args) {} BranchInst *BranchInst::create(SILDebugLocation Loc, SILBasicBlock *DestBB, SILFunction &F) { return create(Loc, DestBB, {}, F); } BranchInst *BranchInst::create(SILDebugLocation Loc, SILBasicBlock *DestBB, ArrayRef Args, SILFunction &F) { void *Buffer = F.getModule().allocateInst(sizeof(BranchInst) + decltype(Operands)::getExtraSize(Args.size()), alignof(BranchInst)); return ::new (Buffer) BranchInst(Loc, DestBB, Args); } CondBranchInst::CondBranchInst(SILDebugLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, SILBasicBlock *FalseBB, ArrayRef Args, unsigned NumTrue, unsigned NumFalse) : TermInst(ValueKind::CondBranchInst, Loc), DestBBs{{this, TrueBB}, {this, FalseBB}}, NumTrueArgs(NumTrue), NumFalseArgs(NumFalse), Operands(this, Args, Condition) { assert(Args.size() == (NumTrueArgs + NumFalseArgs) && "Invalid number of args"); assert(TrueBB != FalseBB && "Identical destinations"); } CondBranchInst *CondBranchInst::create(SILDebugLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, SILBasicBlock *FalseBB, SILFunction &F) { return create(Loc, Condition, TrueBB, {}, FalseBB, {}, F); } CondBranchInst * CondBranchInst::create(SILDebugLocation Loc, SILValue Condition, SILBasicBlock *TrueBB, ArrayRef TrueArgs, SILBasicBlock *FalseBB, ArrayRef FalseArgs, SILFunction &F) { SmallVector Args; Args.append(TrueArgs.begin(), TrueArgs.end()); Args.append(FalseArgs.begin(), FalseArgs.end()); void *Buffer = F.getModule().allocateInst(sizeof(CondBranchInst) + decltype(Operands)::getExtraSize(Args.size()), alignof(CondBranchInst)); return ::new (Buffer) CondBranchInst(Loc, Condition, TrueBB, FalseBB, Args, TrueArgs.size(), FalseArgs.size()); } OperandValueArrayRef CondBranchInst::getTrueArgs() const { return Operands.asValueArray().slice(1, NumTrueArgs); } OperandValueArrayRef CondBranchInst::getFalseArgs() const { return Operands.asValueArray().slice(1 + NumTrueArgs, NumFalseArgs); } SILValue CondBranchInst::getArgForDestBB(const SILBasicBlock *DestBB, const SILArgument *Arg) const { return getArgForDestBB(DestBB, Arg->getIndex()); } SILValue CondBranchInst::getArgForDestBB(const SILBasicBlock *DestBB, unsigned ArgIndex) const { // If TrueBB and FalseBB equal, we cannot find an arg for this DestBB so // return an empty SILValue. if (getTrueBB() == getFalseBB()) { assert(DestBB == getTrueBB() && "DestBB is not a target of this cond_br"); return SILValue(); } if (DestBB == getTrueBB()) return Operands[1 + ArgIndex].get(); assert(DestBB == getFalseBB() && "By process of elimination BB must be false BB"); return Operands[1 + NumTrueArgs + ArgIndex].get(); } ArrayRef CondBranchInst::getTrueOperands() const { if (NumTrueArgs == 0) return ArrayRef(); return ArrayRef(&Operands[1], NumTrueArgs); } MutableArrayRef CondBranchInst::getTrueOperands() { if (NumTrueArgs == 0) return MutableArrayRef(); return MutableArrayRef(&Operands[1], NumTrueArgs); } ArrayRef CondBranchInst::getFalseOperands() const { if (NumFalseArgs == 0) return ArrayRef(); return ArrayRef(&Operands[1+NumTrueArgs], NumFalseArgs); } MutableArrayRef CondBranchInst::getFalseOperands() { if (NumFalseArgs == 0) return MutableArrayRef(); return MutableArrayRef(&Operands[1+NumTrueArgs], NumFalseArgs); } void CondBranchInst::swapSuccessors() { // Swap our destinations. SILBasicBlock *First = DestBBs[0].getBB(); DestBBs[0] = DestBBs[1].getBB(); DestBBs[1] = First; // If we don't have any arguments return. if (!NumTrueArgs && !NumFalseArgs) return; // Otherwise swap our true and false arguments. MutableArrayRef Ops = getAllOperands(); llvm::SmallVector TrueOps; for (SILValue V : getTrueArgs()) TrueOps.push_back(V); auto FalseArgs = getFalseArgs(); for (unsigned i = 0, e = NumFalseArgs; i < e; ++i) { Ops[1+i].set(FalseArgs[i]); } for (unsigned i = 0, e = NumTrueArgs; i < e; ++i) { Ops[1+i+NumFalseArgs].set(TrueOps[i]); } // Finally swap the number of arguments that we have. std::swap(NumTrueArgs, NumFalseArgs); } SwitchValueInst::SwitchValueInst(SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef Cases, ArrayRef BBs) : TermInst(ValueKind::SwitchValueInst, Loc), NumCases(Cases.size()), HasDefault(bool(DefaultBB)), Operands(this, Cases, Operand) { // Initialize the successor array. auto *succs = getSuccessorBuf(); unsigned OperandBitWidth = 0; if (auto OperandTy = Operand->getType().getAs()) { OperandBitWidth = OperandTy->getGreatestWidth(); } for (unsigned i = 0, size = Cases.size(); i < size; ++i) { // If we have undef, just add the case and continue. if (isa(Cases[i])) { ::new (succs + i) SILSuccessor(this, BBs[i]); continue; } if (OperandBitWidth) { auto *IL = dyn_cast(Cases[i]); assert(IL && "switch_value case value should be of an integer type"); assert(IL->getValue().getBitWidth() == OperandBitWidth && "switch_value case value is not same bit width as operand"); (void)IL; } else { auto *FR = dyn_cast(Cases[i]); if (!FR) { if (auto *CF = dyn_cast(Cases[i])) { FR = dyn_cast(CF->getOperand()); } } assert(FR && "switch_value case value should be a function reference"); } ::new (succs + i) SILSuccessor(this, BBs[i]); } if (HasDefault) ::new (succs + NumCases) SILSuccessor(this, DefaultBB); } SwitchValueInst::~SwitchValueInst() { // Destroy the successor records to keep the CFG up to date. auto *succs = getSuccessorBuf(); for (unsigned i = 0, end = NumCases + HasDefault; i < end; ++i) { succs[i].~SILSuccessor(); } } SwitchValueInst *SwitchValueInst::create( SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F) { // Allocate enough room for the instruction with tail-allocated data for all // the case values and the SILSuccessor arrays. There are `CaseBBs.size()` // SILValues and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. SmallVector Cases; SmallVector BBs; unsigned numCases = CaseBBs.size(); unsigned numSuccessors = numCases + (DefaultBB ? 1 : 0); for(auto pair: CaseBBs) { Cases.push_back(pair.first); BBs.push_back(pair.second); } size_t bufSize = sizeof(SwitchValueInst) + decltype(Operands)::getExtraSize(Cases.size()) + sizeof(SILSuccessor) * numSuccessors; void *buf = F.getModule().allocateInst(bufSize, alignof(SwitchValueInst)); return ::new (buf) SwitchValueInst(Loc, Operand, DefaultBB, Cases, BBs); } SelectValueInst::SelectValueInst(SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultResult, ArrayRef CaseValuesAndResults) : SelectInstBase(ValueKind::SelectValueInst, Loc, Type, CaseValuesAndResults.size() / 2, bool(DefaultResult), CaseValuesAndResults, Operand) { unsigned OperandBitWidth = 0; if (auto OperandTy = Operand->getType().getAs()) { OperandBitWidth = OperandTy->getGreatestWidth(); } } SelectValueInst::~SelectValueInst() { } SelectValueInst * SelectValueInst::create(SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultResult, ArrayRef> CaseValues, SILFunction &F) { // Allocate enough room for the instruction with tail-allocated data for all // the case values and the SILSuccessor arrays. There are `CaseBBs.size()` // SILValues and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. SmallVector CaseValuesAndResults; for (auto pair : CaseValues) { CaseValuesAndResults.push_back(pair.first); CaseValuesAndResults.push_back(pair.second); } if ((bool)DefaultResult) CaseValuesAndResults.push_back(DefaultResult); size_t bufSize = sizeof(SelectValueInst) + decltype(Operands)::getExtraSize( CaseValuesAndResults.size()); void *buf = F.getModule().allocateInst(bufSize, alignof(SelectValueInst)); return ::new (buf) SelectValueInst(Loc, Operand, Type, DefaultResult, CaseValuesAndResults); } static SmallVector getCaseOperands(ArrayRef> CaseValues, SILValue DefaultValue) { SmallVector result; for (auto &pair : CaseValues) result.push_back(pair.second); if (DefaultValue) result.push_back(DefaultValue); return result; } SelectEnumInstBase::SelectEnumInstBase( ValueKind Kind, SILDebugLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue, ArrayRef> CaseValues) : SelectInstBase(Kind, Loc, Ty, CaseValues.size(), bool(DefaultValue), getCaseOperands(CaseValues, DefaultValue), Operand) { // Initialize the case and successor arrays. auto *cases = getCaseBuf(); for (unsigned i = 0, size = CaseValues.size(); i < size; ++i) { cases[i] = CaseValues[i].first; } } template SELECT_ENUM_INST *SelectEnumInstBase::createSelectEnum( SILDebugLocation Loc, SILValue Operand, SILType Ty, SILValue DefaultValue, ArrayRef> CaseValues, SILFunction &F) { // Allocate enough room for the instruction with tail-allocated // EnumElementDecl and operand arrays. There are `CaseBBs.size()` decls // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` values. unsigned numCases = CaseValues.size(); void *buf = F.getModule().allocateInst( sizeof(SELECT_ENUM_INST) + sizeof(EnumElementDecl*) * numCases + TailAllocatedOperandList<1>::getExtraSize(numCases + (bool)DefaultValue), alignof(SELECT_ENUM_INST)); return ::new (buf) SELECT_ENUM_INST(Loc,Operand,Ty,DefaultValue,CaseValues); } SelectEnumInst *SelectEnumInst::create( SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue, ArrayRef> CaseValues, SILFunction &F) { return createSelectEnum(Loc, Operand, Type, DefaultValue, CaseValues, F); } SelectEnumAddrInst *SelectEnumAddrInst::create( SILDebugLocation Loc, SILValue Operand, SILType Type, SILValue DefaultValue, ArrayRef> CaseValues, SILFunction &F) { return createSelectEnum(Loc, Operand, Type, DefaultValue, CaseValues, F); } SwitchEnumInstBase::SwitchEnumInstBase( ValueKind Kind, SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs) : TermInst(Kind, Loc), Operands(this, Operand), NumCases(CaseBBs.size()), HasDefault(bool(DefaultBB)) { // Initialize the case and successor arrays. auto *cases = getCaseBuf(); auto *succs = getSuccessorBuf(); for (unsigned i = 0, size = CaseBBs.size(); i < size; ++i) { cases[i] = CaseBBs[i].first; ::new (succs + i) SILSuccessor(this, CaseBBs[i].second); } if (HasDefault) ::new (succs + NumCases) SILSuccessor(this, DefaultBB); } namespace { template EnumElementDecl * getUniqueCaseForDefaultValue(Inst *inst, SILValue enumValue) { assert(inst->hasDefault() && "doesn't have a default"); SILType enumType = enumValue->getType(); EnumDecl *decl = enumType.getEnumOrBoundGenericEnum(); assert(decl && "switch_enum operand is not an enum"); // FIXME: Get expansion from SILFunction if (!decl->hasFixedLayout(inst->getModule().getSwiftModule(), ResilienceExpansion::Maximal)) return nullptr; llvm::SmallPtrSet unswitchedElts; for (auto elt : decl->getAllElements()) unswitchedElts.insert(elt); for (unsigned i = 0, e = inst->getNumCases(); i != e; ++i) { auto Entry = inst->getCase(i); unswitchedElts.erase(Entry.first); } if (unswitchedElts.size() == 1) return *unswitchedElts.begin(); return nullptr; } } NullablePtr SelectEnumInstBase::getUniqueCaseForDefault() { return getUniqueCaseForDefaultValue(this, getEnumOperand()); } NullablePtr SelectEnumInstBase::getSingleTrueElement() const { auto SEIType = getType().getAs(); if (!SEIType) return nullptr; if (SEIType->getWidth() != BuiltinIntegerWidth::fixed(1)) return nullptr; // Try to find a single literal "true" case. Optional TrueElement; for (unsigned i = 0, e = getNumCases(); i < e; ++i) { auto casePair = getCase(i); if (auto intLit = dyn_cast(casePair.second)) { if (intLit->getValue() == APInt(1, 1)) { if (!TrueElement) TrueElement = casePair.first; else // Use Optional(nullptr) to represent more than one. TrueElement = Optional(nullptr); } } } if (!TrueElement || !*TrueElement) return nullptr; return *TrueElement; } SwitchEnumInstBase::~SwitchEnumInstBase() { // Destroy the successor records to keep the CFG up to date. auto *succs = getSuccessorBuf(); for (unsigned i = 0, end = NumCases + HasDefault; i < end; ++i) { succs[i].~SILSuccessor(); } } template SWITCH_ENUM_INST *SwitchEnumInstBase::createSwitchEnum( SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F) { // Allocate enough room for the instruction with tail-allocated // EnumElementDecl and SILSuccessor arrays. There are `CaseBBs.size()` decls // and `CaseBBs.size() + (DefaultBB ? 1 : 0)` successors. unsigned numCases = CaseBBs.size(); unsigned numSuccessors = numCases + (DefaultBB ? 1 : 0); void *buf = F.getModule().allocateInst(sizeof(SWITCH_ENUM_INST) + sizeof(EnumElementDecl*) * numCases + sizeof(SILSuccessor) * numSuccessors, alignof(SWITCH_ENUM_INST)); return ::new (buf) SWITCH_ENUM_INST(Loc, Operand, DefaultBB, CaseBBs); } NullablePtr SwitchEnumInstBase::getUniqueCaseForDefault() { return getUniqueCaseForDefaultValue(this, getOperand()); } NullablePtr SwitchEnumInstBase::getUniqueCaseForDestination(SILBasicBlock *BB) { SILValue value = getOperand(); SILType enumType = value->getType(); EnumDecl *decl = enumType.getEnumOrBoundGenericEnum(); assert(decl && "switch_enum operand is not an enum"); (void)decl; EnumElementDecl *D = nullptr; for (unsigned i = 0, e = getNumCases(); i != e; ++i) { auto Entry = getCase(i); if (Entry.second == BB) { if (D != nullptr) return nullptr; D = Entry.first; } } if (!D && hasDefault() && getDefaultBB() == BB) { return getUniqueCaseForDefault(); } return D; } SwitchEnumInst *SwitchEnumInst::create( SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F) { return createSwitchEnum(Loc, Operand, DefaultBB, CaseBBs, F); } SwitchEnumAddrInst *SwitchEnumAddrInst::create( SILDebugLocation Loc, SILValue Operand, SILBasicBlock *DefaultBB, ArrayRef> CaseBBs, SILFunction &F) { return createSwitchEnum (Loc, Operand, DefaultBB, CaseBBs, F); } DynamicMethodBranchInst::DynamicMethodBranchInst(SILDebugLocation Loc, SILValue Operand, SILDeclRef Member, SILBasicBlock *HasMethodBB, SILBasicBlock *NoMethodBB) : TermInst(ValueKind::DynamicMethodBranchInst, Loc), Member(Member), DestBBs{{this, HasMethodBB}, {this, NoMethodBB}}, Operands(this, Operand) { } DynamicMethodBranchInst * DynamicMethodBranchInst::create(SILDebugLocation Loc, SILValue Operand, SILDeclRef Member, SILBasicBlock *HasMethodBB, SILBasicBlock *NoMethodBB, SILFunction &F) { void *Buffer = F.getModule().allocateInst(sizeof(DynamicMethodBranchInst), alignof(DynamicMethodBranchInst)); return ::new (Buffer) DynamicMethodBranchInst(Loc, Operand, Member, HasMethodBB, NoMethodBB); } SILLinkage TypeConverter::getLinkageForProtocolConformance(const NormalProtocolConformance *C, ForDefinition_t definition) { // Behavior conformances are always private. if (C->isBehaviorConformance()) return (definition ? SILLinkage::Private : SILLinkage::PrivateExternal); // If the conformance is imported from Clang, give it shared linkage. auto typeDecl = C->getType()->getNominalOrBoundGenericNominal(); auto typeUnit = typeDecl->getModuleScopeContext(); if (isa(typeUnit) && C->getDeclContext()->getParentModule() == typeUnit->getParentModule()) return SILLinkage::Shared; // FIXME: This should be using std::min(protocol's access, type's access). switch (C->getProtocol()->getEffectiveAccess()) { case Accessibility::Private: return (definition ? SILLinkage::Private : SILLinkage::PrivateExternal); case Accessibility::Internal: return (definition ? SILLinkage::Hidden : SILLinkage::HiddenExternal); default: return (definition ? SILLinkage::Public : SILLinkage::PublicExternal); } } /// Create a witness method, creating a witness table declaration if we don't /// have a witness table for it. Later on if someone wants the real definition, /// lookUpWitnessTable will deserialize it for us if we can. /// /// This is following the same model of how we deal with SILFunctions in /// function_ref. There we always just create a declaration and then later /// deserialize the actual function definition if we need to. WitnessMethodInst * WitnessMethodInst::create(SILDebugLocation Loc, CanType LookupType, ProtocolConformanceRef Conformance, SILDeclRef Member, SILType Ty, SILFunction *F, SILValue OpenedExistential, bool Volatile) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(WitnessMethodInst), alignof(WitnessMethodInst)); declareWitnessTable(Mod, Conformance); return ::new (Buffer) WitnessMethodInst(Loc, LookupType, Conformance, Member, Ty, OpenedExistential, Volatile); } InitExistentialAddrInst *InitExistentialAddrInst::create( SILDebugLocation Loc, SILValue Existential, CanType ConcreteType, SILType ConcreteLoweredType, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(InitExistentialAddrInst), alignof(InitExistentialAddrInst)); for (ProtocolConformanceRef C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) InitExistentialAddrInst(Loc, Existential, ConcreteType, ConcreteLoweredType, Conformances); } InitExistentialRefInst * InitExistentialRefInst::create(SILDebugLocation Loc, SILType ExistentialType, CanType ConcreteType, SILValue Instance, ArrayRef Conformances, SILFunction *F) { SILModule &Mod = F->getModule(); void *Buffer = Mod.allocateInst(sizeof(InitExistentialRefInst), alignof(InitExistentialRefInst)); for (ProtocolConformanceRef C : Conformances) declareWitnessTable(Mod, C); return ::new (Buffer) InitExistentialRefInst(Loc, ExistentialType, ConcreteType, Instance, Conformances); } InitExistentialMetatypeInst::InitExistentialMetatypeInst( SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype, ArrayRef conformances) : UnaryInstructionBase(Loc, metatype, existentialMetatypeType), NumConformances(conformances.size()) { std::uninitialized_copy(conformances.begin(), conformances.end(), getTrailingObjects()); } InitExistentialMetatypeInst *InitExistentialMetatypeInst::create( SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype, ArrayRef conformances, SILFunction *F) { SILModule &M = F->getModule(); unsigned size = totalSizeToAlloc(conformances.size()); void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst)); for (ProtocolConformanceRef conformance : conformances) declareWitnessTable(M, conformance); return ::new (buffer) InitExistentialMetatypeInst( Loc, existentialMetatypeType, metatype, conformances); } ArrayRef InitExistentialMetatypeInst::getConformances() const { return {getTrailingObjects(), NumConformances}; } MarkUninitializedBehaviorInst * MarkUninitializedBehaviorInst::create(SILModule &M, SILDebugLocation DebugLoc, SILValue InitStorage, ArrayRef InitStorageSubs, SILValue Storage, SILValue Setter, ArrayRef SetterSubs, SILValue Self, SILType Ty) { auto totalSubs = InitStorageSubs.size() + SetterSubs.size(); auto mem = M.allocateInst(sizeof(MarkUninitializedBehaviorInst) + additionalSizeToAlloc(totalSubs), alignof(MarkUninitializedBehaviorInst)); return ::new (mem) MarkUninitializedBehaviorInst(DebugLoc, InitStorage, InitStorageSubs, Storage, Setter, SetterSubs, Self, Ty); } MarkUninitializedBehaviorInst::MarkUninitializedBehaviorInst( SILDebugLocation DebugLoc, SILValue InitStorage, ArrayRef InitStorageSubs, SILValue Storage, SILValue Setter, ArrayRef SetterSubs, SILValue Self, SILType Ty) : SILInstruction(ValueKind::MarkUninitializedBehaviorInst, DebugLoc, Ty), Operands(this, InitStorage, Storage, Setter, Self), NumInitStorageSubstitutions(InitStorageSubs.size()), NumSetterSubstitutions(SetterSubs.size()) { auto *trailing = getTrailingObjects(); for (unsigned i = 0; i < InitStorageSubs.size(); ++i) { ::new ((void*)trailing++) Substitution(InitStorageSubs[i]); } for (unsigned i = 0; i < SetterSubs.size(); ++i) { ::new ((void*)trailing++) Substitution(SetterSubs[i]); } }