in lib/SIL/Parser/ParseSIL.cpp [2677:5859]
bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
SILInstructionKind Opcode,
SourceLoc OpcodeLoc,
StringRef OpcodeName,
SILInstruction *&ResultVal) {
SmallVector<SILValue, 4> OpList;
SILValue Val;
SILType Ty;
SILLocation InstLoc = RegularLocation(OpcodeLoc);
this->parsedComma = false;
auto parseFormalTypeAndValue = [&](CanType &formalType,
SILValue &value) -> bool {
return (parseASTType(formalType) || parseVerbatim("in")
|| parseTypedValueRef(value, B));
};
OpenedExistentialAccess AccessKind;
auto parseOpenExistAddrKind = [&]() -> bool {
Identifier accessKindToken;
SourceLoc accessKindLoc;
if (parseSILIdentifier(accessKindToken, accessKindLoc,
diag::expected_tok_in_sil_instr,
"opened existential access kind")) {
return true;
}
auto kind =
llvm::StringSwitch<Optional<OpenedExistentialAccess>>(
accessKindToken.str())
.Case("mutable_access", OpenedExistentialAccess::Mutable)
.Case("immutable_access", OpenedExistentialAccess::Immutable)
.Default(None);
if (kind) {
AccessKind = kind.getValue();
return false;
}
P.diagnose(accessKindLoc, diag::expected_tok_in_sil_instr,
"opened existential access kind");
return true;
};
CanType SourceType, TargetType;
SILValue SourceAddr, DestAddr;
auto parseSourceAndDestAddress = [&] {
return parseFormalTypeAndValue(SourceType, SourceAddr) ||
parseVerbatim("to") || parseFormalTypeAndValue(TargetType, DestAddr);
};
Identifier SuccessBBName, FailureBBName;
SourceLoc SuccessBBLoc, FailureBBLoc;
auto parseConditionalBranchDestinations = [&] {
return P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| parseSILIdentifier(SuccessBBName, SuccessBBLoc,
diag::expected_sil_block_name)
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| parseSILIdentifier(FailureBBName, FailureBBLoc,
diag::expected_sil_block_name);
};
// Validate the opcode name, and do opcode-specific parsing logic based on the
// opcode we find.
switch (Opcode) {
case SILInstructionKind::AllocBoxInst: {
bool hasDynamicLifetime = false;
if (parseSILOptional(hasDynamicLifetime, *this, "dynamic_lifetime"))
return true;
SILType Ty;
if (parseSILType(Ty))
return true;
SILDebugVariable VarInfo;
if (parseSILDebugVar(VarInfo))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createAllocBox(InstLoc, Ty.castTo<SILBoxType>(), VarInfo,
hasDynamicLifetime);
break;
}
case SILInstructionKind::ApplyInst:
case SILInstructionKind::BeginApplyInst:
case SILInstructionKind::PartialApplyInst:
case SILInstructionKind::TryApplyInst:
if (parseCallInstruction(InstLoc, Opcode, B, ResultVal))
return true;
break;
case SILInstructionKind::AbortApplyInst:
case SILInstructionKind::EndApplyInst: {
UnresolvedValueName argName;
if (parseValueName(argName))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
SILType expectedTy = SILType::getSILTokenType(P.Context);
SILValue op = getLocalValue(argName, expectedTy, InstLoc, B);
if (Opcode == SILInstructionKind::AbortApplyInst) {
ResultVal = B.createAbortApply(InstLoc, op);
} else {
ResultVal = B.createEndApply(InstLoc, op);
}
break;
}
case SILInstructionKind::IntegerLiteralInst: {
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
bool Negative = false;
if (P.Tok.isAnyOperator() && P.Tok.getText() == "-") {
Negative = true;
P.consumeToken();
}
if (P.Tok.getKind() != tok::integer_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer");
return true;
}
auto intTy = Ty.getAs<AnyBuiltinIntegerType>();
if (!intTy) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type);
return true;
}
StringRef text = prepareIntegerLiteralForParsing(P.Tok.getText());
bool error;
APInt value = intTy->getWidth().parse(text, 0, Negative, &error);
if (error) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_well_formed, intTy);
return true;
}
P.consumeToken(tok::integer_literal);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIntegerLiteral(InstLoc, Ty, value);
break;
}
case SILInstructionKind::FloatLiteralInst: {
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
// The value is expressed as bits.
if (P.Tok.getKind() != tok::integer_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer");
return true;
}
auto floatTy = Ty.getAs<BuiltinFloatType>();
if (!floatTy) {
P.diagnose(P.Tok, diag::sil_float_literal_not_float_type);
return true;
}
StringRef text = prepareIntegerLiteralForParsing(P.Tok.getText());
APInt bits(floatTy->getBitWidth(), 0);
bool error = text.getAsInteger(0, bits);
assert(!error && "float_literal token did not parse as APInt?!");
(void)error;
if (bits.getBitWidth() != floatTy->getBitWidth())
bits = bits.zextOrTrunc(floatTy->getBitWidth());
APFloat value(floatTy->getAPFloatSemantics(), bits);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createFloatLiteral(InstLoc, Ty, value);
P.consumeToken(tok::integer_literal);
break;
}
case SILInstructionKind::StringLiteralInst: {
if (P.Tok.getKind() != tok::identifier) {
P.diagnose(P.Tok, diag::sil_string_no_encoding);
return true;
}
StringLiteralInst::Encoding encoding;
if (P.Tok.getText() == "utf8") {
encoding = StringLiteralInst::Encoding::UTF8;
} else if (P.Tok.getText() == "objc_selector") {
encoding = StringLiteralInst::Encoding::ObjCSelector;
} else if (P.Tok.getText() == "bytes") {
encoding = StringLiteralInst::Encoding::Bytes;
} else {
P.diagnose(P.Tok, diag::sil_string_invalid_encoding, P.Tok.getText());
return true;
}
P.consumeToken(tok::identifier);
if (P.Tok.getKind() != tok::string_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string");
return true;
}
// Parse the string.
SmallVector<Lexer::StringSegment, 1> segments;
P.L->getStringLiteralSegments(P.Tok, segments);
assert(segments.size() == 1);
P.consumeToken(tok::string_literal);
if (parseSILDebugLocation(InstLoc, B))
return true;
SmallVector<char, 128> stringBuffer;
if (encoding == StringLiteralInst::Encoding::Bytes) {
// Decode hex bytes.
CharSourceRange rawStringRange(segments.front().Loc,
segments.front().Length);
StringRef rawString = P.SourceMgr.extractText(rawStringRange);
if (rawString.size() & 1) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,
"even number of hex bytes");
return true;
}
while (!rawString.empty()) {
unsigned byte1 = llvm::hexDigitValue(rawString[0]);
unsigned byte2 = llvm::hexDigitValue(rawString[1]);
if (byte1 == -1U || byte2 == -1U) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,
"hex bytes should contain 0-9, a-f, A-F only");
return true;
}
stringBuffer.push_back((unsigned char)(byte1 << 4) | byte2);
rawString = rawString.drop_front(2);
}
ResultVal = B.createStringLiteral(InstLoc, stringBuffer, encoding);
break;
}
StringRef string =
P.L->getEncodedStringSegment(segments.front(), stringBuffer);
ResultVal = B.createStringLiteral(InstLoc, string, encoding);
break;
}
case SILInstructionKind::CondFailInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<char, 128> stringBuffer;
StringRef message;
if (P.consumeIf(tok::comma)) {
// Parse the string.
if (P.Tok.getKind() != tok::string_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string");
return true;
}
SmallVector<Lexer::StringSegment, 1> segments;
P.L->getStringLiteralSegments(P.Tok, segments);
assert(segments.size() == 1);
P.consumeToken(tok::string_literal);
message = P.L->getEncodedStringSegment(segments.front(), stringBuffer);
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCondFail(InstLoc, Val, message);
break;
}
case SILInstructionKind::ProjectBoxInst: {
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
if (!P.Tok.is(tok::integer_literal)) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer");
return true;
}
unsigned Index;
bool error = parseIntegerLiteral(P.Tok.getText(), 0, Index);
assert(!error && "project_box index did not parse as integer?!");
(void)error;
P.consumeToken(tok::integer_literal);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectBox(InstLoc, Val, Index);
break;
}
case SILInstructionKind::ProjectExistentialBoxInst: {
SILType Ty;
if (parseSILType(Ty) || parseVerbatim("in") || parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectExistentialBox(InstLoc, Ty, Val);
break;
}
case SILInstructionKind::FunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::DynamicFunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
// Set a forward reference's dynamic property for the first time.
if (!Fn->isDynamicallyReplaceable()) {
if (!Fn->empty()) {
P.diagnose(P.Tok, diag::expected_dynamic_func_attr);
return true;
}
Fn->setIsDynamic();
}
ResultVal = B.createDynamicFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::PreviousDynamicFunctionRefInst: {
SILFunction *Fn;
if (parseSILFunctionRef(InstLoc, Fn) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createPreviousDynamicFunctionRef(InstLoc, Fn);
break;
}
case SILInstructionKind::BuiltinInst: {
if (P.Tok.getKind() != tok::string_literal) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "builtin name");
return true;
}
StringRef Str = P.Tok.getText();
Identifier Id = P.Context.getIdentifier(Str.substr(1, Str.size() - 2));
P.consumeToken(tok::string_literal);
// Find the builtin in the Builtin module
SmallVector<ValueDecl *, 2> foundBuiltins;
P.Context.TheBuiltinModule->lookupMember(
foundBuiltins, P.Context.TheBuiltinModule, Id, Identifier());
if (foundBuiltins.empty()) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "builtin name");
return true;
}
assert(foundBuiltins.size() == 1 && "ambiguous builtin name?!");
auto *builtinFunc = cast<FuncDecl>(foundBuiltins[0]);
GenericEnvironment *genericEnv = builtinFunc->getGenericEnvironment();
SmallVector<ParsedSubstitution, 4> parsedSubs;
SubstitutionMap subMap;
if (parseSubstitutions(parsedSubs))
return true;
if (!parsedSubs.empty()) {
if (!genericEnv) {
P.diagnose(P.Tok, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, genericEnv, parsedSubs);
if (!subMap)
return true;
}
if (P.Tok.getKind() != tok::l_paren) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "(");
return true;
}
P.consumeToken(tok::l_paren);
SmallVector<SILValue, 4> Args;
while (true) {
if (P.consumeIf(tok::r_paren))
break;
SILValue Val;
if (parseTypedValueRef(Val, B))
return true;
Args.push_back(Val);
if (P.consumeIf(tok::comma))
continue;
if (P.consumeIf(tok::r_paren))
break;
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ")' or ',");
return true;
}
if (P.Tok.getKind() != tok::colon) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ":");
return true;
}
P.consumeToken(tok::colon);
SILType ResultTy;
if (parseSILType(ResultTy))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBuiltin(InstLoc, Id, ResultTy, subMap, Args);
break;
}
case SILInstructionKind::OpenExistentialAddrInst:
if (parseOpenExistAddrKind() || parseTypedValueRef(Val, B) ||
parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialAddr(InstLoc, Val, Ty, AccessKind);
break;
case SILInstructionKind::OpenExistentialBoxInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialBox(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialBoxValueInst: {
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createOpenExistentialBoxValue(InstLoc, Val, Ty, forwardingOwnership);
break;
}
case SILInstructionKind::OpenExistentialMetatypeInst:
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createOpenExistentialMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::OpenExistentialRefInst: {
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createOpenExistentialRef(InstLoc, Val, Ty, forwardingOwnership);
break;
}
case SILInstructionKind::OpenExistentialValueInst: {
if (parseTypedValueRef(Val, B) || parseVerbatim("to") || parseSILType(Ty))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createOpenExistentialValue(InstLoc, Val, Ty, forwardingOwnership);
break;
}
#define UNARY_INSTRUCTION(ID) \
case SILInstructionKind::ID##Inst: \
if (parseTypedValueRef(Val, B)) \
return true; \
if (parseSILDebugLocation(InstLoc, B)) \
return true; \
ResultVal = B.create##ID(InstLoc, Val); \
break;
#define REFCOUNTING_INSTRUCTION(ID) \
case SILInstructionKind::ID##Inst: { \
Atomicity atomicity = Atomicity::Atomic; \
StringRef Optional; \
if (parseSILOptional(Optional, *this)) { \
if (Optional == "nonatomic") { \
atomicity = Atomicity::NonAtomic; \
} else { \
return true; \
} \
} \
if (parseTypedValueRef(Val, B)) \
return true; \
if (parseSILDebugLocation(InstLoc, B)) \
return true; \
ResultVal = B.create##ID(InstLoc, Val, atomicity); \
} break;
UNARY_INSTRUCTION(ClassifyBridgeObject)
UNARY_INSTRUCTION(ValueToBridgeObject)
UNARY_INSTRUCTION(FixLifetime)
UNARY_INSTRUCTION(EndLifetime)
UNARY_INSTRUCTION(CopyBlock)
UNARY_INSTRUCTION(IsUnique)
UNARY_INSTRUCTION(DestroyAddr)
UNARY_INSTRUCTION(CopyValue)
UNARY_INSTRUCTION(ExplicitCopyValue)
UNARY_INSTRUCTION(EndBorrow)
UNARY_INSTRUCTION(DestructureStruct)
UNARY_INSTRUCTION(DestructureTuple)
UNARY_INSTRUCTION(ExtractExecutor)
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
REFCOUNTING_INSTRUCTION(StrongRetain)
REFCOUNTING_INSTRUCTION(StrongRelease)
REFCOUNTING_INSTRUCTION(AutoreleaseValue)
REFCOUNTING_INSTRUCTION(SetDeallocating)
REFCOUNTING_INSTRUCTION(ReleaseValue)
REFCOUNTING_INSTRUCTION(RetainValue)
REFCOUNTING_INSTRUCTION(ReleaseValueAddr)
REFCOUNTING_INSTRUCTION(RetainValueAddr)
#define UNCHECKED_REF_STORAGE(Name, ...) \
UNARY_INSTRUCTION(StrongCopy##Name##Value)
#define ALWAYS_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
REFCOUNTING_INSTRUCTION(StrongRetain##Name) \
REFCOUNTING_INSTRUCTION(Name##Retain) \
REFCOUNTING_INSTRUCTION(Name##Release) \
UNARY_INSTRUCTION(StrongCopy##Name##Value)
#include "swift/AST/ReferenceStorage.def"
#undef UNARY_INSTRUCTION
#undef REFCOUNTING_INSTRUCTION
case SILInstructionKind::HopToExecutorInst: {
bool mandatory = false;
if (parseSILOptional(mandatory, *this, "mandatory")
|| parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createHopToExecutor(InstLoc, Val, mandatory);
break;
}
case SILInstructionKind::DestroyValueInst: {
bool poisonRefs = false;
if (parseSILOptional(poisonRefs, *this, "poison")
|| parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDestroyValue(InstLoc, Val, poisonRefs);
break;
}
case SILInstructionKind::BeginCOWMutationInst: {
bool native = false;
if (parseSILOptional(native, *this, "native") ||
parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBeginCOWMutation(InstLoc, Val, native);
break;
}
case SILInstructionKind::EndCOWMutationInst: {
bool keepUnique = false;
if (parseSILOptional(keepUnique, *this, "keep_unique") ||
parseTypedValueRef(Val, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createEndCOWMutation(InstLoc, Val, keepUnique);
break;
}
case SILInstructionKind::IsEscapingClosureInst: {
bool IsObjcVerifcationType = false;
if (parseSILOptional(IsObjcVerifcationType, *this, "objc"))
return true;
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIsEscapingClosure(
InstLoc, Val,
IsObjcVerifcationType ? IsEscapingClosureInst::ObjCEscaping
: IsEscapingClosureInst::WithoutActuallyEscaping);
break;
}
case SILInstructionKind::DebugValueInst: {
bool poisonRefs = false;
SILDebugVariable VarInfo;
if (parseSILOptional(poisonRefs, *this, "poison")
|| parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (Val->getType().isAddress())
assert(!poisonRefs && "debug_value w/ address value does not support poison");
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo, poisonRefs);
break;
}
// unchecked_ownership_conversion <reg> : <type>, <ownership> to <ownership>
case SILInstructionKind::UncheckedOwnershipConversionInst: {
ValueOwnershipKind LHSKind = OwnershipKind::None;
ValueOwnershipKind RHSKind = OwnershipKind::None;
SourceLoc Loc;
if (parseTypedValueRef(Val, Loc, B) ||
P.parseToken(tok::comma, diag::expected_sil_colon,
"unchecked_ownership_conversion value ownership kind "
"conversion specification") ||
parseSILOwnership(LHSKind) || parseVerbatim("to") ||
parseSILOwnership(RHSKind) || parseSILDebugLocation(InstLoc, B)) {
return true;
}
if (Val.getOwnershipKind() != LHSKind) {
return true;
}
ResultVal = B.createUncheckedOwnershipConversion(InstLoc, Val, RHSKind);
break;
}
case SILInstructionKind::MoveValueInst: {
bool allowsDiagnostics = false;
bool isLexical = false;
StringRef AttrName;
SourceLoc AttrLoc;
while (parseSILOptional(AttrName, AttrLoc, *this)) {
if (AttrName == "allows_diagnostics")
allowsDiagnostics = true;
else if (AttrName == "lexical")
isLexical = true;
else {
P.diagnose(InstLoc.getSourceLoc(),
diag::sil_invalid_attribute_for_instruction, AttrName,
"move_value");
return true;
}
}
if (parseTypedValueRef(Val, B))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
auto *MVI = B.createMoveValue(InstLoc, Val, isLexical);
MVI->setAllowsDiagnostics(allowsDiagnostics);
ResultVal = MVI;
break;
}
case SILInstructionKind::LoadInst: {
Optional<LoadOwnershipQualifier> Qualifier;
SourceLoc AddrLoc;
auto parseLoadOwnership = [](StringRef Str) {
return llvm::StringSwitch<Optional<LoadOwnershipQualifier>>(Str)
.Case("take", LoadOwnershipQualifier::Take)
.Case("copy", LoadOwnershipQualifier::Copy)
.Case("trivial", LoadOwnershipQualifier::Trivial)
.Default(None);
};
if (parseSILQualifier<LoadOwnershipQualifier>(Qualifier, parseLoadOwnership)
|| parseTypedValueRef(Val, AddrLoc, B)
|| parseSILDebugLocation(InstLoc, B)) {
return true;
}
if (!Qualifier)
Qualifier = LoadOwnershipQualifier::Unqualified;
ResultVal = B.createLoad(InstLoc, Val, Qualifier.getValue());
break;
}
case SILInstructionKind::LoadBorrowInst: {
SourceLoc AddrLoc;
if (parseTypedValueRef(Val, AddrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createLoadBorrow(InstLoc, Val);
break;
}
case SILInstructionKind::BeginBorrowInst: {
SourceLoc AddrLoc;
bool isLexical = false;
if (parseSILOptional(isLexical, *this, "lexical"))
return true;
if (parseTypedValueRef(Val, AddrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBeginBorrow(InstLoc, Val, isLexical);
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::Load##Name##Inst: { \
bool isTake = false; \
SourceLoc addrLoc; \
if (parseSILOptional(isTake, *this, "take") || \
parseTypedValueRef(Val, addrLoc, B) || \
parseSILDebugLocation(InstLoc, B)) \
return true; \
if (!Val->getType().is<Name##StorageType>()) { \
P.diagnose(addrLoc, diag::sil_operand_not_ref_storage_address, "source", \
OpcodeName, ReferenceOwnership::Name); \
} \
ResultVal = B.createLoad##Name(InstLoc, Val, IsTake_t(isTake)); \
break; \
}
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::CopyBlockWithoutEscapingInst: {
SILValue Closure;
if (parseTypedValueRef(Val, B) || parseVerbatim("withoutEscaping") ||
parseTypedValueRef(Closure, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCopyBlockWithoutEscaping(InstLoc, Val, Closure);
break;
}
case SILInstructionKind::MarkDependenceInst: {
SILValue Base;
if (parseTypedValueRef(Val, B) || parseVerbatim("on") ||
parseTypedValueRef(Base, B))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMarkDependence(InstLoc, Val, Base, forwardingOwnership);
break;
}
case SILInstructionKind::KeyPathInst: {
SmallVector<KeyPathPatternComponent, 4> components;
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
GenericParamList *patternParams = nullptr;
GenericEnvironment *patternEnv = nullptr;
CanType rootType;
StringRef objcString;
SmallVector<SILType, 4> operandTypes;
{
patternParams = P.maybeParseGenericParams().getPtrOrNull();
patternEnv = handleSILGenericParams(patternParams, &P.SF);
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
while (true) {
Identifier componentKind;
SourceLoc componentLoc;
if (parseSILIdentifier(componentKind, componentLoc,
diag::sil_keypath_expected_component_kind))
return true;
if (componentKind.str() == "root") {
if (P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr,
"$") ||
parseASTType(rootType, patternEnv, patternParams))
return true;
} else if (componentKind.str() == "objc") {
auto tok = P.Tok;
if (P.parseToken(tok::string_literal, diag::expected_tok_in_sil_instr,
"string literal"))
return true;
auto objcStringValue = tok.getText().drop_front().drop_back();
objcString =
StringRef(P.Context.AllocateCopy<char>(objcStringValue.begin(),
objcStringValue.end()),
objcStringValue.size());
} else {
KeyPathPatternComponent component;
if (parseKeyPathPatternComponent(component, operandTypes,
componentLoc, componentKind, InstLoc,
patternEnv, patternParams))
return true;
components.push_back(component);
}
if (!P.consumeIf(tok::semi))
break;
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") ||
parseSILDebugLocation(InstLoc, B))
return true;
}
if (rootType.isNull())
P.diagnose(InstLoc.getSourceLoc(), diag::sil_keypath_no_root);
SmallVector<ParsedSubstitution, 4> parsedSubs;
if (parseSubstitutions(parsedSubs, ContextGenericEnv, ContextGenericParams))
return true;
SubstitutionMap subMap;
if (!parsedSubs.empty()) {
if (!patternEnv) {
P.diagnose(InstLoc.getSourceLoc(),
diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, patternEnv, parsedSubs);
if (!subMap)
return true;
}
SmallVector<SILValue, 4> operands;
if (P.consumeIf(tok::l_paren)) {
while (true) {
SILValue v;
if (operands.size() >= operandTypes.size() ||
!operandTypes[operands.size()]) {
P.diagnose(P.Tok, diag::sil_keypath_no_use_of_operand_in_pattern,
operands.size());
return true;
}
auto ty = operandTypes[operands.size()].subst(SILMod, subMap);
if (parseValueRef(v, ty, RegularLocation(P.Tok.getLoc()), B))
return true;
operands.push_back(v);
if (P.consumeIf(tok::comma))
continue;
if (P.consumeIf(tok::r_paren))
break;
return true;
}
}
if (parseSILDebugLocation(InstLoc, B))
return true;
CanGenericSignature canSig;
if (patternEnv && patternEnv->getGenericSignature()) {
canSig = patternEnv->getGenericSignature().getCanonicalSignature();
}
CanType leafType;
if (!components.empty())
leafType = components.back().getComponentType();
else
leafType = rootType;
auto pattern = KeyPathPattern::get(B.getModule(), canSig, rootType,
leafType, components, objcString);
ResultVal = B.createKeyPath(InstLoc, pattern, subMap, operands, Ty);
break;
}
// Conversion instructions.
case SILInstructionKind::UncheckedRefCastInst:
case SILInstructionKind::UncheckedAddrCastInst:
case SILInstructionKind::UncheckedTrivialBitCastInst:
case SILInstructionKind::UncheckedBitwiseCastInst:
case SILInstructionKind::UncheckedValueCastInst:
case SILInstructionKind::UpcastInst:
case SILInstructionKind::AddressToPointerInst:
case SILInstructionKind::BridgeObjectToRefInst:
case SILInstructionKind::BridgeObjectToWordInst:
case SILInstructionKind::RefToRawPointerInst:
case SILInstructionKind::RawPointerToRefInst:
#define LOADABLE_REF_STORAGE(Name, ...) \
case SILInstructionKind::RefTo##Name##Inst: \
case SILInstructionKind::Name##ToRefInst:
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::ThinFunctionToPointerInst:
case SILInstructionKind::PointerToThinFunctionInst:
case SILInstructionKind::ThinToThickFunctionInst:
case SILInstructionKind::ThickToObjCMetatypeInst:
case SILInstructionKind::ObjCToThickMetatypeInst:
case SILInstructionKind::ConvertFunctionInst:
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
case SILInstructionKind::ObjCMetatypeToObjectInst: {
SILType Ty;
Identifier ToToken;
SourceLoc ToLoc;
bool not_guaranteed = false;
bool without_actually_escaping = false;
if (Opcode == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
if (attrName.equals("not_guaranteed"))
not_guaranteed = true;
else
return true;
}
}
if (parseTypedValueRef(Val, B) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (Opcode == SILInstructionKind::ConvertFunctionInst) {
StringRef attrName;
if (parseSILOptional(attrName, *this)) {
if (attrName.equals("without_actually_escaping"))
without_actually_escaping = true;
else
return true;
}
}
if (parseSILType(Ty))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (OwnershipForwardingMixin::isa(Opcode)) {
if (parseForwardingOwnershipKind(forwardingOwnership))
return true;
}
if (parseSILDebugLocation(InstLoc, B)) {
return true;
}
switch (Opcode) {
default:
llvm_unreachable("Out of sync with parent switch");
case SILInstructionKind::UncheckedRefCastInst:
ResultVal =
B.createUncheckedRefCast(InstLoc, Val, Ty, forwardingOwnership);
break;
case SILInstructionKind::UncheckedAddrCastInst:
ResultVal = B.createUncheckedAddrCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedTrivialBitCastInst:
ResultVal = B.createUncheckedTrivialBitCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedBitwiseCastInst:
ResultVal = B.createUncheckedBitwiseCast(InstLoc, Val, Ty);
break;
case SILInstructionKind::UncheckedValueCastInst:
ResultVal =
B.createUncheckedValueCast(InstLoc, Val, Ty, forwardingOwnership);
break;
case SILInstructionKind::UpcastInst:
ResultVal = B.createUpcast(InstLoc, Val, Ty, forwardingOwnership);
break;
case SILInstructionKind::ConvertFunctionInst:
ResultVal = B.createConvertFunction(
InstLoc, Val, Ty, without_actually_escaping, forwardingOwnership);
break;
case SILInstructionKind::ConvertEscapeToNoEscapeInst:
ResultVal =
B.createConvertEscapeToNoEscape(InstLoc, Val, Ty, !not_guaranteed);
break;
case SILInstructionKind::AddressToPointerInst:
ResultVal = B.createAddressToPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::BridgeObjectToRefInst:
ResultVal =
B.createBridgeObjectToRef(InstLoc, Val, Ty, forwardingOwnership);
break;
case SILInstructionKind::BridgeObjectToWordInst:
ResultVal = B.createBridgeObjectToWord(InstLoc, Val);
break;
case SILInstructionKind::RefToRawPointerInst:
ResultVal = B.createRefToRawPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::RawPointerToRefInst:
ResultVal = B.createRawPointerToRef(InstLoc, Val, Ty);
break;
#define LOADABLE_REF_STORAGE(Name, ...) \
case SILInstructionKind::RefTo##Name##Inst: \
ResultVal = B.createRefTo##Name(InstLoc, Val, Ty); \
break; \
case SILInstructionKind::Name##ToRefInst: \
ResultVal = B.create##Name##ToRef(InstLoc, Val, Ty); \
break;
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::ThinFunctionToPointerInst:
ResultVal = B.createThinFunctionToPointer(InstLoc, Val, Ty);
break;
case SILInstructionKind::PointerToThinFunctionInst:
ResultVal = B.createPointerToThinFunction(InstLoc, Val, Ty);
break;
case SILInstructionKind::ThinToThickFunctionInst:
ResultVal =
B.createThinToThickFunction(InstLoc, Val, Ty, forwardingOwnership);
break;
case SILInstructionKind::ThickToObjCMetatypeInst:
ResultVal = B.createThickToObjCMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCToThickMetatypeInst:
ResultVal = B.createObjCToThickMetatype(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCMetatypeToObjectInst:
ResultVal = B.createObjCMetatypeToObject(InstLoc, Val, Ty);
break;
case SILInstructionKind::ObjCExistentialMetatypeToObjectInst:
ResultVal = B.createObjCExistentialMetatypeToObject(InstLoc, Val, Ty);
break;
}
break;
}
case SILInstructionKind::PointerToAddressInst: {
SILType Ty;
Identifier ToToken;
SourceLoc ToLoc;
StringRef attr;
if (parseTypedValueRef(Val, B) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
bool isStrict = false;
bool isInvariant = false;
llvm::MaybeAlign alignment;
uint64_t parsedValue = 0;
while (parseSILOptional(attr, parsedValue, ToLoc, *this)) {
if (attr.empty())
return true;
if (attr.equals("strict"))
isStrict = true;
if (attr.equals("invariant"))
isInvariant = true;
if (attr.equals("align"))
alignment = llvm::Align(parsedValue);
}
if (parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
ResultVal = B.createPointerToAddress(InstLoc, Val, Ty, isStrict,
isInvariant, alignment);
break;
}
case SILInstructionKind::RefToBridgeObjectInst: {
SILValue BitsVal;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(BitsVal, B))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createRefToBridgeObject(InstLoc, Val, BitsVal, forwardingOwnership);
break;
}
case SILInstructionKind::CheckedCastAddrBranchInst: {
Identifier consumptionKindToken;
SourceLoc consumptionKindLoc;
if (parseSILIdentifier(consumptionKindToken, consumptionKindLoc,
diag::expected_tok_in_sil_instr,
"cast consumption kind")) {
return true;
}
// NOTE: BorrowAlways is not a supported cast kind for address types, so we
// purposely do not parse it here.
auto kind = llvm::StringSwitch<Optional<CastConsumptionKind>>(
consumptionKindToken.str())
.Case("take_always", CastConsumptionKind::TakeAlways)
.Case("take_on_success", CastConsumptionKind::TakeOnSuccess)
.Case("copy_on_success", CastConsumptionKind::CopyOnSuccess)
.Default(None);
if (!kind) {
P.diagnose(consumptionKindLoc, diag::expected_tok_in_sil_instr,
"cast consumption kind");
return true;
}
auto consumptionKind = kind.getValue();
if (parseSourceAndDestAddress() || parseConditionalBranchDestinations() ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createCheckedCastAddrBranch(
InstLoc, consumptionKind, SourceAddr, SourceType, DestAddr, TargetType,
getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc));
break;
}
case SILInstructionKind::UncheckedRefCastAddrInst:
if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUncheckedRefCastAddr(InstLoc, SourceAddr, SourceType,
DestAddr, TargetType);
break;
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnconditionalCheckedCastAddr(
InstLoc, SourceAddr, SourceType, DestAddr, TargetType);
break;
case SILInstructionKind::UnconditionalCheckedCastValueInst: {
if (parseASTType(SourceType) || parseVerbatim("in") ||
parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType) || parseSILDebugLocation(InstLoc, B))
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createUnconditionalCheckedCastValue(
InstLoc, Val, SourceType, F->getLoweredType(opaque, TargetType),
TargetType);
break;
}
case SILInstructionKind::UnconditionalCheckedCastInst: {
if (parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createUnconditionalCheckedCast(
InstLoc, Val, F->getLoweredType(opaque, TargetType), TargetType,
forwardingOwnership);
break;
}
case SILInstructionKind::CheckedCastBranchInst: {
bool isExact = false;
if (Opcode == SILInstructionKind::CheckedCastBranchInst &&
parseSILOptional(isExact, *this, "exact"))
return true;
if (parseTypedValueRef(Val, B) || parseVerbatim("to") ||
parseASTType(TargetType) || parseConditionalBranchDestinations())
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B)) {
return true;
}
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createCheckedCastBranch(
InstLoc, isExact, Val, F->getLoweredType(opaque, TargetType),
TargetType, getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc), forwardingOwnership);
break;
}
case SILInstructionKind::CheckedCastValueBranchInst: {
if (parseASTType(SourceType) || parseVerbatim("in")
|| parseTypedValueRef(Val, B) || parseVerbatim("to")
|| parseASTType(TargetType) || parseConditionalBranchDestinations()
|| parseSILDebugLocation(InstLoc, B))
return true;
auto opaque = Lowering::AbstractionPattern::getOpaque();
ResultVal = B.createCheckedCastValueBranch(
InstLoc, Val, SourceType, F->getLoweredType(opaque, TargetType),
TargetType, getBBForReference(SuccessBBName, SuccessBBLoc),
getBBForReference(FailureBBName, FailureBBLoc));
break;
}
case SILInstructionKind::MarkUninitializedInst: {
if (P.parseToken(tok::l_square, diag::expected_tok_in_sil_instr, "["))
return true;
Identifier KindId;
SourceLoc KindLoc = P.Tok.getLoc();
if (P.consumeIf(tok::kw_var))
KindId = P.Context.getIdentifier("var");
else if (P.parseIdentifier(KindId, KindLoc, /*diagnoseDollarPrefix=*/false,
diag::expected_tok_in_sil_instr, "kind"))
return true;
if (P.parseToken(tok::r_square, diag::expected_tok_in_sil_instr, "]"))
return true;
MarkUninitializedInst::Kind Kind;
if (KindId.str() == "var")
Kind = MarkUninitializedInst::Var;
else if (KindId.str() == "rootself")
Kind = MarkUninitializedInst::RootSelf;
else if (KindId.str() == "crossmodulerootself")
Kind = MarkUninitializedInst::CrossModuleRootSelf;
else if (KindId.str() == "derivedself")
Kind = MarkUninitializedInst::DerivedSelf;
else if (KindId.str() == "derivedselfonly")
Kind = MarkUninitializedInst::DerivedSelfOnly;
else if (KindId.str() == "delegatingself")
Kind = MarkUninitializedInst::DelegatingSelf;
else if (KindId.str() == "delegatingselfallocated")
Kind = MarkUninitializedInst::DelegatingSelfAllocated;
else {
P.diagnose(KindLoc, diag::expected_tok_in_sil_instr,
"var, rootself, crossmodulerootself, derivedself, "
"derivedselfonly, delegatingself, or delegatingselfallocated");
return true;
}
if (parseTypedValueRef(Val, B))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createMarkUninitialized(InstLoc, Val, Kind, forwardingOwnership);
break;
}
case SILInstructionKind::MarkFunctionEscapeInst: {
SmallVector<SILValue, 4> OpList;
do {
if (parseTypedValueRef(Val, B))
return true;
OpList.push_back(Val);
} while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma));
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMarkFunctionEscape(InstLoc, OpList);
break;
}
case SILInstructionKind::AssignInst:
case SILInstructionKind::StoreInst: {
UnresolvedValueName From;
SourceLoc ToLoc, AddrLoc;
Identifier ToToken;
SILValue AddrVal;
Optional<StoreOwnershipQualifier> StoreQualifier;
Optional<AssignOwnershipQualifier> AssignQualifier;
bool IsStore = Opcode == SILInstructionKind::StoreInst;
bool IsAssign = Opcode == SILInstructionKind::AssignInst;
if (parseValueName(From) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to"))
return true;
auto parseStoreOwnership = [](StringRef Str) {
return llvm::StringSwitch<Optional<StoreOwnershipQualifier>>(Str)
.Case("init", StoreOwnershipQualifier::Init)
.Case("assign", StoreOwnershipQualifier::Assign)
.Case("trivial", StoreOwnershipQualifier::Trivial)
.Default(None);
};
if (IsStore
&& parseSILQualifier<StoreOwnershipQualifier>(StoreQualifier,
parseStoreOwnership))
return true;
auto parseAssignOwnership = [](StringRef Str) {
return llvm::StringSwitch<Optional<AssignOwnershipQualifier>>(Str)
.Case("reassign", AssignOwnershipQualifier::Reassign)
.Case("reinit", AssignOwnershipQualifier::Reinit)
.Case("init", AssignOwnershipQualifier::Init)
.Default(None);
};
if (IsAssign
&& parseSILQualifier<AssignOwnershipQualifier>(AssignQualifier,
parseAssignOwnership))
return true;
if (parseTypedValueRef(AddrVal, AddrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (!AddrVal->getType().isAddress()) {
P.diagnose(AddrLoc, diag::sil_operand_not_address, "destination",
OpcodeName);
return true;
}
SILType ValType = AddrVal->getType().getObjectType();
if (IsStore) {
if (!StoreQualifier)
StoreQualifier = StoreOwnershipQualifier::Unqualified;
ResultVal =
B.createStore(InstLoc, getLocalValue(From, ValType, InstLoc, B),
AddrVal, StoreQualifier.getValue());
} else {
assert(IsAssign);
if (!AssignQualifier)
AssignQualifier = AssignOwnershipQualifier::Unknown;
ResultVal =
B.createAssign(InstLoc, getLocalValue(From, ValType, InstLoc, B),
AddrVal, AssignQualifier.getValue());
}
break;
}
case SILInstructionKind::AssignByWrapperInst: {
SILValue Src, DestAddr, InitFn, SetFn;
SourceLoc DestLoc;
AssignByWrapperInst::Mode mode;
if (parseTypedValueRef(Src, B) || parseVerbatim("to") ||
parseAssignByWrapperMode(mode, *this) ||
parseTypedValueRef(DestAddr, DestLoc, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("init") || parseTypedValueRef(InitFn, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("set") || parseTypedValueRef(SetFn, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (!DestAddr->getType().isAddress()) {
P.diagnose(DestLoc, diag::sil_operand_not_address, "destination",
OpcodeName);
return true;
}
ResultVal = B.createAssignByWrapper(InstLoc, Src, DestAddr, InitFn, SetFn,
mode);
break;
}
case SILInstructionKind::BeginAccessInst:
case SILInstructionKind::BeginUnpairedAccessInst:
case SILInstructionKind::EndAccessInst:
case SILInstructionKind::EndUnpairedAccessInst: {
ParsedEnum<SILAccessKind> kind;
ParsedEnum<SILAccessEnforcement> enforcement;
ParsedEnum<bool> aborting;
ParsedEnum<bool> noNestedConflict;
ParsedEnum<bool> fromBuiltin;
bool isBeginAccess =
(Opcode == SILInstructionKind::BeginAccessInst ||
Opcode == SILInstructionKind::BeginUnpairedAccessInst);
bool wantsEnforcement =
(isBeginAccess || Opcode == SILInstructionKind::EndUnpairedAccessInst);
while (P.consumeIf(tok::l_square)) {
Identifier ident;
SourceLoc identLoc;
if (parseSILIdentifier(ident, identLoc,
diag::expected_in_attribute_list)) {
if (P.consumeIf(tok::r_square)) {
continue;
} else {
return true;
}
}
StringRef attr = ident.str();
auto setEnforcement = [&](SILAccessEnforcement value) {
maybeSetEnum(wantsEnforcement, enforcement, value, attr, identLoc);
};
auto setKind = [&](SILAccessKind value) {
maybeSetEnum(isBeginAccess, kind, value, attr, identLoc);
};
auto setAborting = [&](bool value) {
maybeSetEnum(!isBeginAccess, aborting, value, attr, identLoc);
};
auto setNoNestedConflict = [&](bool value) {
maybeSetEnum(isBeginAccess, noNestedConflict, value, attr, identLoc);
};
auto setFromBuiltin = [&](bool value) {
maybeSetEnum(Opcode != SILInstructionKind::EndAccessInst, fromBuiltin,
value, attr, identLoc);
};
if (attr == "unknown") {
setEnforcement(SILAccessEnforcement::Unknown);
} else if (attr == "static") {
setEnforcement(SILAccessEnforcement::Static);
} else if (attr == "dynamic") {
setEnforcement(SILAccessEnforcement::Dynamic);
} else if (attr == "unsafe") {
setEnforcement(SILAccessEnforcement::Unsafe);
} else if (attr == "init") {
setKind(SILAccessKind::Init);
} else if (attr == "read") {
setKind(SILAccessKind::Read);
} else if (attr == "modify") {
setKind(SILAccessKind::Modify);
} else if (attr == "deinit") {
setKind(SILAccessKind::Deinit);
} else if (attr == "abort") {
setAborting(true);
} else if (attr == "no_nested_conflict") {
setNoNestedConflict(true);
} else if (attr == "builtin") {
setFromBuiltin(true);
} else {
P.diagnose(identLoc, diag::unknown_attribute, attr);
}
if (!P.consumeIf(tok::r_square))
return true;
}
if (isBeginAccess && !kind.isSet()) {
P.diagnose(OpcodeLoc, diag::sil_expected_access_kind, OpcodeName);
kind.Value = SILAccessKind::Read;
}
if (wantsEnforcement && !enforcement.isSet()) {
P.diagnose(OpcodeLoc, diag::sil_expected_access_enforcement, OpcodeName);
enforcement.Value = SILAccessEnforcement::Unsafe;
}
if (!isBeginAccess && !aborting.isSet())
aborting.Value = false;
if (isBeginAccess && !noNestedConflict.isSet())
noNestedConflict.Value = false;
if (!fromBuiltin.isSet())
fromBuiltin.Value = false;
SILValue addrVal;
SourceLoc addrLoc;
if (parseTypedValueRef(addrVal, addrLoc, B))
return true;
SILValue bufferVal;
SourceLoc bufferLoc;
if (Opcode == SILInstructionKind::BeginUnpairedAccessInst &&
(P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(bufferVal, bufferLoc, B)))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
if (!addrVal->getType().isAddress()) {
P.diagnose(addrLoc, diag::sil_operand_not_address, "operand", OpcodeName);
return true;
}
if (Opcode == SILInstructionKind::BeginAccessInst) {
ResultVal = B.createBeginAccess(InstLoc, addrVal, *kind, *enforcement,
*noNestedConflict, *fromBuiltin);
} else if (Opcode == SILInstructionKind::EndAccessInst) {
ResultVal = B.createEndAccess(InstLoc, addrVal, *aborting);
} else if (Opcode == SILInstructionKind::BeginUnpairedAccessInst) {
ResultVal = B.createBeginUnpairedAccess(InstLoc, addrVal, bufferVal,
*kind, *enforcement,
*noNestedConflict, *fromBuiltin);
} else {
ResultVal = B.createEndUnpairedAccess(InstLoc, addrVal, *enforcement,
*aborting, *fromBuiltin);
}
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
case SILInstructionKind::Store##Name##Inst:
#include "swift/AST/ReferenceStorage.def"
case SILInstructionKind::StoreBorrowInst: {
UnresolvedValueName from;
bool isRefStorage = false;
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
isRefStorage |= Opcode == SILInstructionKind::Store##Name##Inst;
#include "swift/AST/ReferenceStorage.def"
SourceLoc toLoc, addrLoc;
Identifier toToken;
SILValue addrVal;
bool isInit = false;
if (parseValueName(from) ||
parseSILIdentifier(toToken, toLoc, diag::expected_tok_in_sil_instr,
"to") ||
(isRefStorage && parseSILOptional(isInit, *this, "initialization")) ||
parseTypedValueRef(addrVal, addrLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (toToken.str() != "to") {
P.diagnose(toLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (!addrVal->getType().isAddress()) {
P.diagnose(addrLoc, diag::sil_operand_not_address, "destination",
OpcodeName);
return true;
}
if (Opcode == SILInstructionKind::StoreBorrowInst) {
SILType valueTy = addrVal->getType().getObjectType();
ResultVal = B.createStoreBorrow(
InstLoc, getLocalValue(from, valueTy, InstLoc, B), addrVal);
break;
}
#define NEVER_OR_SOMETIMES_LOADABLE_CHECKED_REF_STORAGE(Name, ...) \
if (Opcode == SILInstructionKind::Store##Name##Inst) { \
auto refType = addrVal->getType().getAs<Name##StorageType>(); \
if (!refType) { \
P.diagnose(addrLoc, diag::sil_operand_not_ref_storage_address, \
"destination", OpcodeName, ReferenceOwnership::Name); \
return true; \
} \
auto valueTy = SILType::getPrimitiveObjectType(refType.getReferentType()); \
ResultVal = \
B.createStore##Name(InstLoc, getLocalValue(from, valueTy, InstLoc, B), \
addrVal, IsInitialization_t(isInit)); \
break; \
}
#include "swift/AST/ReferenceStorage.def"
break;
}
case SILInstructionKind::AllocStackInst: {
bool hasDynamicLifetime = false;
bool isLexical = false;
StringRef attributeName;
SourceLoc attributeLoc;
while (parseSILOptional(attributeName, attributeLoc, *this)) {
if (attributeName == "dynamic_lifetime")
hasDynamicLifetime = true;
else if (attributeName == "lexical")
isLexical = true;
else {
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
attributeName, "alloc_stack");
return true;
}
}
SILType Ty;
if (parseSILType(Ty))
return true;
SILDebugVariable VarInfo;
if (parseSILDebugVar(VarInfo) || parseSILDebugLocation(InstLoc, B))
return true;
// It doesn't make sense to attach a debug var info if the name is empty
if (VarInfo.Name.size())
ResultVal = B.createAllocStack(InstLoc, Ty, VarInfo, hasDynamicLifetime,
isLexical);
else
ResultVal =
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical);
break;
}
case SILInstructionKind::MetatypeInst: {
SILType Ty;
if (parseSILType(Ty))
return true;
assert(Opcode == SILInstructionKind::MetatypeInst);
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createMetatype(InstLoc, Ty);
break;
}
case SILInstructionKind::AllocRefInst:
case SILInstructionKind::AllocRefDynamicInst: {
bool IsObjC = false;
bool OnStack = false;
SmallVector<SILType, 2> ElementTypes;
SmallVector<SILValue, 2> ElementCounts;
while (P.consumeIf(tok::l_square)) {
Identifier Id;
parseSILIdentifier(Id, diag::expected_in_attribute_list);
StringRef Optional = Id.str();
if (Optional == "objc") {
IsObjC = true;
} else if (Optional == "stack") {
OnStack = true;
} else if (Optional == "tail_elems") {
SILType ElemTy;
if (parseSILType(ElemTy) || !P.Tok.isAnyOperator() ||
P.Tok.getText() != "*")
return true;
P.consumeToken();
SILValue ElemCount;
if (parseTypedValueRef(ElemCount, B))
return true;
ElementTypes.push_back(ElemTy);
ElementCounts.push_back(ElemCount);
} else {
return true;
}
P.parseToken(tok::r_square, diag::expected_in_attribute_list);
}
SILValue Metadata;
if (Opcode == SILInstructionKind::AllocRefDynamicInst) {
if (parseTypedValueRef(Metadata, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
}
SILType ObjectType;
if (parseSILType(ObjectType))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
if (IsObjC && !ElementTypes.empty()) {
P.diagnose(P.Tok, diag::sil_objc_with_tail_elements);
return true;
}
if (Opcode == SILInstructionKind::AllocRefDynamicInst) {
if (OnStack)
return true;
ResultVal = B.createAllocRefDynamic(InstLoc, Metadata, ObjectType, IsObjC,
ElementTypes, ElementCounts);
} else {
ResultVal = B.createAllocRef(InstLoc, ObjectType, IsObjC, OnStack,
ElementTypes, ElementCounts);
}
break;
}
case SILInstructionKind::DeallocStackInst:
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocStack(InstLoc, Val);
break;
case SILInstructionKind::DeallocStackRefInst:
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocStackRef(InstLoc, Val);
break;
case SILInstructionKind::DeallocRefInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocRef(InstLoc, Val);
break;
}
case SILInstructionKind::DeallocPartialRefInst: {
SILValue Metatype, Instance;
if (parseTypedValueRef(Instance, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(Metatype, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocPartialRef(InstLoc, Instance, Metatype);
break;
}
case SILInstructionKind::DeallocBoxInst:
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocBox(InstLoc, Val);
break;
case SILInstructionKind::ValueMetatypeInst:
case SILInstructionKind::ExistentialMetatypeInst: {
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
switch (Opcode) {
default:
llvm_unreachable("Out of sync with parent switch");
case SILInstructionKind::ValueMetatypeInst:
ResultVal = B.createValueMetatype(InstLoc, Ty, Val);
break;
case SILInstructionKind::ExistentialMetatypeInst:
ResultVal = B.createExistentialMetatype(InstLoc, Ty, Val);
break;
case SILInstructionKind::DeallocBoxInst:
ResultVal = B.createDeallocBox(InstLoc, Val);
break;
}
break;
}
case SILInstructionKind::DeallocExistentialBoxInst: {
CanType ConcreteTy;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(ConcreteTy) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeallocExistentialBox(InstLoc, ConcreteTy, Val);
break;
}
case SILInstructionKind::TupleInst: {
// Tuple instructions have two different syntaxes, one for simple tuple
// types, one for complicated ones.
if (P.Tok.isNot(tok::sil_dollar)) {
// If there is no type, parse the simple form.
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
// TODO: Check for a type here. This is how tuples with "interesting"
// types are described.
// This form is used with tuples that have elements with no names or
// default values.
SmallVector<TupleTypeElt, 4> TypeElts;
if (P.Tok.isNot(tok::r_paren)) {
do {
if (parseTypedValueRef(Val, B))
return true;
OpList.push_back(Val);
TypeElts.push_back(Val->getType().getASTType());
} while (P.consumeIf(tok::comma));
}
HadError |=
P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")");
auto Ty = TupleType::get(TypeElts, P.Context);
auto Ty2 = SILType::getPrimitiveObjectType(Ty->getCanonicalType());
ValueOwnershipKind forwardingOwnership =
F && F->hasOwnership() ? mergeSILValueOwnership(OpList)
: ValueOwnershipKind(OwnershipKind::None);
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createTuple(InstLoc, Ty2, OpList, forwardingOwnership);
break;
}
// Otherwise, parse the fully general form.
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
TupleType *TT = Ty.getAs<TupleType>();
if (TT == nullptr) {
P.diagnose(OpcodeLoc, diag::expected_tuple_type_in_tuple);
return true;
}
SmallVector<TupleTypeElt, 4> TypeElts;
if (P.Tok.isNot(tok::r_paren)) {
do {
if (TypeElts.size() > TT->getNumElements()) {
P.diagnose(P.Tok, diag::sil_tuple_inst_wrong_value_count,
TT->getNumElements());
return true;
}
Type EltTy = TT->getElement(TypeElts.size()).getType();
if (parseValueRef(
Val,
SILType::getPrimitiveObjectType(EltTy->getCanonicalType()),
RegularLocation(P.Tok.getLoc()), B))
return true;
OpList.push_back(Val);
TypeElts.push_back(Val->getType().getASTType());
} while (P.consumeIf(tok::comma));
}
HadError |= P.parseToken(tok::r_paren,
diag::expected_tok_in_sil_instr,")");
if (TypeElts.size() != TT->getNumElements()) {
P.diagnose(OpcodeLoc, diag::sil_tuple_inst_wrong_value_count,
TT->getNumElements());
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createTuple(InstLoc, Ty, OpList);
break;
}
case SILInstructionKind::EnumInst: {
SILType Ty;
SILDeclRef Elt;
SILValue Operand;
if (parseSILType(Ty) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDeclRef(Elt))
return true;
if (P.Tok.is(tok::comma) && !peekSILDebugLocation(P)) {
P.consumeToken(tok::comma);
if (parseTypedValueRef(Operand, B))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ValueOwnershipKind forwardingOwnership =
Operand ? Operand.getOwnershipKind()
: ValueOwnershipKind(OwnershipKind::None);
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal =
B.createEnum(InstLoc, Operand, cast<EnumElementDecl>(Elt.getDecl()),
Ty, forwardingOwnership);
break;
}
case SILInstructionKind::InitEnumDataAddrInst:
case SILInstructionKind::UncheckedEnumDataInst:
case SILInstructionKind::UncheckedTakeEnumDataAddrInst: {
SILValue Operand;
SILDeclRef EltRef;
if (parseTypedValueRef(Operand, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDeclRef(EltRef))
return true;
ValueOwnershipKind forwardingOwnership = Operand.getOwnershipKind();
if (Opcode == SILInstructionKind::UncheckedEnumDataInst)
parseForwardingOwnershipKind(forwardingOwnership);
if (parseSILDebugLocation(InstLoc, B))
return true;
EnumElementDecl *Elt = cast<EnumElementDecl>(EltRef.getDecl());
auto ResultTy = Operand->getType().getEnumElementType(
Elt, SILMod, B.getTypeExpansionContext());
switch (Opcode) {
case swift::SILInstructionKind::InitEnumDataAddrInst:
ResultVal = B.createInitEnumDataAddr(InstLoc, Operand, Elt, ResultTy);
break;
case swift::SILInstructionKind::UncheckedTakeEnumDataAddrInst:
ResultVal =
B.createUncheckedTakeEnumDataAddr(InstLoc, Operand, Elt, ResultTy);
break;
case swift::SILInstructionKind::UncheckedEnumDataInst: {
ResultVal = B.createUncheckedEnumData(InstLoc, Operand, Elt, ResultTy,
forwardingOwnership);
break;
}
default:
llvm_unreachable("switch out of sync");
}
break;
}
case SILInstructionKind::InjectEnumAddrInst: {
SILValue Operand;
SILDeclRef EltRef;
if (parseTypedValueRef(Operand, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDeclRef(EltRef) || parseSILDebugLocation(InstLoc, B))
return true;
EnumElementDecl *Elt = cast<EnumElementDecl>(EltRef.getDecl());
ResultVal = B.createInjectEnumAddr(InstLoc, Operand, Elt);
break;
}
case SILInstructionKind::TupleElementAddrInst:
case SILInstructionKind::TupleExtractInst: {
SourceLoc NameLoc;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
unsigned Field = 0;
TupleType *TT = Val->getType().getAs<TupleType>();
if (P.Tok.isNot(tok::integer_literal) ||
parseIntegerLiteral(P.Tok.getText(), 10, Field) ||
Field >= TT->getNumElements()) {
P.diagnose(P.Tok, diag::sil_tuple_inst_wrong_field);
return true;
}
P.consumeToken(tok::integer_literal);
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (Opcode == SILInstructionKind::TupleExtractInst) {
if (parseForwardingOwnershipKind(forwardingOwnership))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
auto ResultTy = TT->getElement(Field).getType()->getCanonicalType();
if (Opcode == SILInstructionKind::TupleElementAddrInst)
ResultVal = B.createTupleElementAddr(
InstLoc, Val, Field, SILType::getPrimitiveAddressType(ResultTy));
else {
ResultVal = B.createTupleExtract(
InstLoc, Val, Field, SILType::getPrimitiveObjectType(ResultTy),
forwardingOwnership);
}
break;
}
case SILInstructionKind::ReturnInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createReturn(InstLoc, Val);
break;
}
case SILInstructionKind::ThrowInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createThrow(InstLoc, Val);
break;
}
case SILInstructionKind::UnwindInst: {
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnwind(InstLoc);
break;
}
case SILInstructionKind::YieldInst: {
SmallVector<SILValue, 6> values;
// Parse a parenthesized (unless length-1), comma-separated list
// of yielded values.
if (P.consumeIf(tok::l_paren)) {
if (!P.Tok.is(tok::r_paren)) {
do {
if (parseTypedValueRef(Val, B))
return true;
values.push_back(Val);
} while (P.consumeIf(tok::comma));
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
return true;
} else {
if (parseTypedValueRef(Val, B))
return true;
values.push_back(Val);
}
Identifier resumeName, unwindName;
SourceLoc resumeLoc, unwindLoc;
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("resume") ||
parseSILIdentifier(resumeName, resumeLoc,
diag::expected_sil_block_name) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseVerbatim("unwind") ||
parseSILIdentifier(unwindName, unwindLoc,
diag::expected_sil_block_name) ||
parseSILDebugLocation(InstLoc, B))
return true;
auto resumeBB = getBBForReference(resumeName, resumeLoc);
auto unwindBB = getBBForReference(unwindName, unwindLoc);
ResultVal = B.createYield(InstLoc, values, resumeBB, unwindBB);
break;
}
case SILInstructionKind::BranchInst: {
Identifier BBName;
SourceLoc NameLoc;
if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name))
return true;
SmallVector<SILValue, 6> Args;
if (parseSILBBArgsAtBranch(Args, B))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
// Note, the basic block here could be a reference to an undefined
// basic block, which will be parsed later on.
ResultVal =
B.createBranch(InstLoc, getBBForReference(BBName, NameLoc), Args);
break;
}
case SILInstructionKind::CondBranchInst: {
UnresolvedValueName Cond;
Identifier BBName, BBName2;
SourceLoc NameLoc, NameLoc2;
SmallVector<SILValue, 6> Args, Args2;
if (parseValueName(Cond) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name) ||
parseSILBBArgsAtBranch(Args, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(BBName2, NameLoc2,
diag::expected_sil_block_name) ||
parseSILBBArgsAtBranch(Args2, B) || parseSILDebugLocation(InstLoc, B))
return true;
auto I1Ty = SILType::getBuiltinIntegerType(1, SILMod.getASTContext());
SILValue CondVal = getLocalValue(Cond, I1Ty, InstLoc, B);
ResultVal = B.createCondBranch(
InstLoc, CondVal, getBBForReference(BBName, NameLoc), Args,
getBBForReference(BBName2, NameLoc2), Args2);
break;
}
case SILInstructionKind::UnreachableInst:
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createUnreachable(InstLoc);
break;
case SILInstructionKind::ClassMethodInst:
case SILInstructionKind::SuperMethodInst:
case SILInstructionKind::ObjCMethodInst:
case SILInstructionKind::ObjCSuperMethodInst: {
SILDeclRef Member;
SILType MethodTy;
SourceLoc TyLoc;
SmallVector<ValueDecl *, 4> values;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
if (parseSILDeclRef(Member, true))
return true;
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(MethodTy, TyLoc) || parseSILDebugLocation(InstLoc, B))
return true;
switch (Opcode) {
default:
llvm_unreachable("Out of sync with parent switch");
case SILInstructionKind::ClassMethodInst:
ResultVal = B.createClassMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::SuperMethodInst:
ResultVal = B.createSuperMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::ObjCMethodInst:
ResultVal = B.createObjCMethod(InstLoc, Val, Member, MethodTy);
break;
case SILInstructionKind::ObjCSuperMethodInst:
ResultVal = B.createObjCSuperMethod(InstLoc, Val, Member, MethodTy);
break;
}
break;
}
case SILInstructionKind::WitnessMethodInst: {
CanType LookupTy;
SILDeclRef Member;
SILType MethodTy;
SourceLoc TyLoc;
if (P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(LookupTy) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
return true;
if (parseSILDeclRef(Member, true))
return true;
// Optional operand.
SILValue Operand;
if (P.Tok.is(tok::comma)) {
P.consumeToken(tok::comma);
if (parseTypedValueRef(Operand, B))
return true;
}
if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(MethodTy, TyLoc) || parseSILDebugLocation(InstLoc, B))
return true;
// If LookupTy is a non-archetype, look up its conformance.
ProtocolDecl *proto =
dyn_cast<ProtocolDecl>(Member.getDecl()->getDeclContext());
if (!proto) {
P.diagnose(TyLoc, diag::sil_witness_method_not_protocol);
return true;
}
auto conformance =
P.SF.getParentModule()->lookupConformance(LookupTy, proto);
if (conformance.isInvalid()) {
P.diagnose(TyLoc, diag::sil_witness_method_type_does_not_conform);
return true;
}
ResultVal = B.createWitnessMethod(InstLoc, LookupTy, conformance, Member,
MethodTy);
break;
}
case SILInstructionKind::CopyAddrInst: {
bool IsTake = false, IsInit = false;
UnresolvedValueName SrcLName;
SILValue DestLVal;
SourceLoc ToLoc, DestLoc;
Identifier ToToken;
if (parseSILOptional(IsTake, *this, "take") || parseValueName(SrcLName) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to") ||
parseSILOptional(IsInit, *this, "initialization") ||
parseTypedValueRef(DestLVal, DestLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (!DestLVal->getType().isAddress()) {
P.diagnose(DestLoc, diag::sil_invalid_instr_operands);
return true;
}
SILValue SrcLVal =
getLocalValue(SrcLName, DestLVal->getType(), InstLoc, B);
ResultVal = B.createCopyAddr(InstLoc, SrcLVal, DestLVal, IsTake_t(IsTake),
IsInitialization_t(IsInit));
break;
}
case SILInstructionKind::MarkUnresolvedMoveAddrInst: {
UnresolvedValueName SrcLName;
SILValue DestLVal;
SourceLoc ToLoc, DestLoc;
Identifier ToToken;
if (parseValueName(SrcLName) ||
parseSILIdentifier(ToToken, ToLoc, diag::expected_tok_in_sil_instr,
"to") ||
parseTypedValueRef(DestLVal, DestLoc, B) ||
parseSILDebugLocation(InstLoc, B))
return true;
if (ToToken.str() != "to") {
P.diagnose(ToLoc, diag::expected_tok_in_sil_instr, "to");
return true;
}
if (!DestLVal->getType().isAddress()) {
P.diagnose(DestLoc, diag::sil_invalid_instr_operands);
return true;
}
SILValue SrcLVal =
getLocalValue(SrcLName, DestLVal->getType(), InstLoc, B);
ResultVal = B.createMarkUnresolvedMoveAddr(InstLoc, SrcLVal, DestLVal);
break;
}
case SILInstructionKind::BindMemoryInst: {
SILValue IndexVal;
SILType EltTy;
if (parseTypedValueRef(Val, B)
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| parseTypedValueRef(IndexVal, B)
|| parseVerbatim("to")
|| parseSILType(EltTy)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBindMemory(InstLoc, Val, IndexVal, EltTy);
break;
}
case SILInstructionKind::RebindMemoryInst: {
SILValue InToken;
if (parseTypedValueRef(Val, B)
|| parseVerbatim("to")
|| parseTypedValueRef(InToken, B)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createRebindMemory(InstLoc, Val, InToken);
break;
}
case SILInstructionKind::ObjectInst:
case SILInstructionKind::StructInst: {
SILType Ty;
if (parseSILType(Ty) ||
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
return true;
// Parse a list of SILValue.
bool OpsAreTailElems = false;
unsigned NumBaseElems = 0;
if (P.Tok.isNot(tok::r_paren)) {
do {
if (Opcode == SILInstructionKind::ObjectInst) {
if (parseSILOptional(OpsAreTailElems, *this, "tail_elems"))
return true;
}
if (parseTypedValueRef(Val, B))
return true;
OpList.push_back(Val);
if (!OpsAreTailElems)
NumBaseElems = OpList.size();
} while (P.consumeIf(tok::comma));
}
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
return true;
ValueOwnershipKind forwardingOwnership =
F && F->hasOwnership() ? mergeSILValueOwnership(OpList)
: ValueOwnershipKind(OwnershipKind::None);
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B)) {
return true;
}
if (Opcode == SILInstructionKind::StructInst) {
ResultVal = B.createStruct(InstLoc, Ty, OpList, forwardingOwnership);
} else {
ResultVal = B.createObject(InstLoc, Ty, OpList, NumBaseElems,
forwardingOwnership);
}
break;
}
case SILInstructionKind::StructElementAddrInst:
case SILInstructionKind::StructExtractInst: {
ValueDecl *FieldV;
SourceLoc NameLoc = P.Tok.getLoc();
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDottedPath(FieldV))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (Opcode == SILInstructionKind::StructExtractInst) {
if (parseForwardingOwnershipKind(forwardingOwnership))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
if (!FieldV || !isa<VarDecl>(FieldV)) {
P.diagnose(NameLoc, diag::sil_struct_inst_wrong_field);
return true;
}
VarDecl *Field = cast<VarDecl>(FieldV);
// FIXME: substitution means this type should be explicit to improve
// performance.
auto ResultTy = Val->getType().getFieldType(Field, SILMod,
B.getTypeExpansionContext());
if (Opcode == SILInstructionKind::StructElementAddrInst)
ResultVal = B.createStructElementAddr(InstLoc, Val, Field,
ResultTy.getAddressType());
else {
ResultVal = B.createStructExtract(
InstLoc, Val, Field, ResultTy.getObjectType(), forwardingOwnership);
}
break;
}
case SILInstructionKind::RefElementAddrInst: {
ValueDecl *FieldV;
SourceLoc NameLoc;
bool IsImmutable = false;
if (parseSILOptional(IsImmutable, *this, "immutable") ||
parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDottedPath(FieldV) || parseSILDebugLocation(InstLoc, B))
return true;
if (!FieldV || !isa<VarDecl>(FieldV)) {
P.diagnose(NameLoc, diag::sil_ref_inst_wrong_field);
return true;
}
VarDecl *Field = cast<VarDecl>(FieldV);
auto ResultTy = Val->getType().getFieldType(Field, SILMod,
B.getTypeExpansionContext());
ResultVal = B.createRefElementAddr(InstLoc, Val, Field, ResultTy,
IsImmutable);
break;
}
case SILInstructionKind::RefTailAddrInst: {
SourceLoc NameLoc;
SILType ResultObjTy;
bool IsImmutable = false;
if (parseSILOptional(IsImmutable, *this, "immutable") ||
parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ResultObjTy) || parseSILDebugLocation(InstLoc, B))
return true;
SILType ResultTy = ResultObjTy.getAddressType();
ResultVal = B.createRefTailAddr(InstLoc, Val, ResultTy, IsImmutable);
break;
}
case SILInstructionKind::IndexAddrInst: {
SILValue IndexVal;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(IndexVal, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIndexAddr(InstLoc, Val, IndexVal);
break;
}
case SILInstructionKind::TailAddrInst: {
SILValue IndexVal;
SILType ResultObjTy;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(IndexVal, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ResultObjTy) || parseSILDebugLocation(InstLoc, B))
return true;
SILType ResultTy = ResultObjTy.getAddressType();
ResultVal = B.createTailAddr(InstLoc, Val, IndexVal, ResultTy);
break;
}
case SILInstructionKind::IndexRawPointerInst: {
SILValue IndexVal;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseTypedValueRef(IndexVal, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createIndexRawPointer(InstLoc, Val, IndexVal);
break;
}
case SILInstructionKind::ObjCProtocolInst: {
Identifier ProtocolName;
SILType Ty;
if (P.parseToken(tok::pound, diag::expected_sil_constant) ||
parseSILIdentifier(ProtocolName, diag::expected_sil_constant) ||
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;
// Find the decl for the protocol name.
ValueDecl *VD;
SmallVector<ValueDecl *, 4> CurModuleResults;
// Perform a module level lookup on the first component of the
// fully-qualified name.
P.SF.getParentModule()->lookupValue(
ProtocolName, NLKind::UnqualifiedLookup, CurModuleResults);
assert(CurModuleResults.size() == 1);
VD = CurModuleResults[0];
ResultVal = B.createObjCProtocol(InstLoc, cast<ProtocolDecl>(VD), Ty);
break;
}
case SILInstructionKind::AllocGlobalInst: {
Identifier GlobalName;
SourceLoc IdLoc;
if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
parseSILIdentifier(GlobalName, IdLoc,
diag::expected_sil_value_name) ||
parseSILDebugLocation(InstLoc, B))
return true;
// Go through list of global variables in the SILModule.
SILGlobalVariable *global = SILMod.lookUpGlobalVariable(GlobalName.str());
if (!global) {
P.diagnose(IdLoc, diag::sil_global_variable_not_found, GlobalName);
return true;
}
ResultVal = B.createAllocGlobal(InstLoc, global);
break;
}
case SILInstructionKind::GlobalAddrInst:
case SILInstructionKind::GlobalValueInst: {
Identifier GlobalName;
SourceLoc IdLoc;
SILType Ty;
if (P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
parseSILIdentifier(GlobalName, IdLoc,
diag::expected_sil_value_name) ||
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(Ty) || parseSILDebugLocation(InstLoc, B))
return true;
// Go through list of global variables in the SILModule.
SILGlobalVariable *global = SILMod.lookUpGlobalVariable(GlobalName.str());
if (!global) {
P.diagnose(IdLoc, diag::sil_global_variable_not_found, GlobalName);
return true;
}
SILType expectedType = (Opcode == SILInstructionKind::GlobalAddrInst
? global->getLoweredType().getAddressType()
: global->getLoweredType());
if (expectedType != Ty) {
P.diagnose(IdLoc, diag::sil_value_use_type_mismatch, GlobalName.str(),
global->getLoweredType().getASTType(), Ty.getASTType());
return true;
}
if (Opcode == SILInstructionKind::GlobalAddrInst) {
ResultVal = B.createGlobalAddr(InstLoc, global);
} else {
ResultVal = B.createGlobalValue(InstLoc, global);
}
break;
}
case SILInstructionKind::BaseAddrForOffsetInst: {
SILType Ty;
if (parseSILType(Ty))
return true;
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createBaseAddrForOffset(InstLoc, Ty);
break;
}
case SILInstructionKind::SelectEnumInst:
case SILInstructionKind::SelectEnumAddrInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<EnumElementDecl *, UnresolvedValueName>, 4>
CaseValueNames;
Optional<UnresolvedValueName> DefaultValueName;
while (P.consumeIf(tok::comma)) {
Identifier BBName;
SourceLoc BBLoc;
// Parse 'default' sil-value.
UnresolvedValueName tmp;
if (P.consumeIf(tok::kw_default)) {
if (parseValueName(tmp))
return true;
DefaultValueName = tmp;
break;
}
// Parse 'case' sil-decl-ref ':' sil-value.
if (P.consumeIf(tok::kw_case)) {
SILDeclRef ElemRef;
if (parseSILDeclRef(ElemRef))
return true;
assert(ElemRef.hasDecl() && isa<EnumElementDecl>(ElemRef.getDecl()));
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseValueName(tmp);
CaseValueNames.push_back(
std::make_pair(cast<EnumElementDecl>(ElemRef.getDecl()), tmp));
continue;
}
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default");
return true;
}
// Parse the type of the result operands.
SILType ResultType;
if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(ResultType))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (Opcode == SILInstructionKind::SelectEnumInst) {
if (parseForwardingOwnershipKind(forwardingOwnership))
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
// Resolve the results.
SmallVector<std::pair<EnumElementDecl *, SILValue>, 4> CaseValues;
SILValue DefaultValue;
if (DefaultValueName)
DefaultValue = getLocalValue(*DefaultValueName, ResultType, InstLoc, B);
for (auto &caseName : CaseValueNames)
CaseValues.push_back(std::make_pair(
caseName.first,
getLocalValue(caseName.second, ResultType, InstLoc, B)));
if (Opcode == SILInstructionKind::SelectEnumInst) {
ResultVal = B.createSelectEnum(InstLoc, Val, ResultType, DefaultValue,
CaseValues, None, ProfileCounter(),
forwardingOwnership);
} else
ResultVal = B.createSelectEnumAddr(InstLoc, Val, ResultType,
DefaultValue, CaseValues);
break;
}
case SILInstructionKind::SwitchEnumInst:
case SILInstructionKind::SwitchEnumAddrInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 4> CaseBBs;
SILBasicBlock *DefaultBB = nullptr;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma)) {
parsedComma = true;
Identifier BBName;
SourceLoc BBLoc;
// Parse 'case' sil-decl-ref ':' sil-identifier.
if (P.consumeIf(tok::kw_case)) {
parsedComma = false;
if (DefaultBB) {
P.diagnose(P.Tok, diag::case_after_default);
return true;
}
SILDeclRef ElemRef;
if (parseSILDeclRef(ElemRef))
return true;
assert(ElemRef.hasDecl() && isa<EnumElementDecl>(ElemRef.getDecl()));
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name);
CaseBBs.push_back({cast<EnumElementDecl>(ElemRef.getDecl()),
getBBForReference(BBName, BBLoc)});
continue;
}
// Parse 'default' sil-identifier.
if (P.consumeIf(tok::kw_default)) {
parsedComma = false;
parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name);
DefaultBB = getBBForReference(BBName, BBLoc);
continue;
}
break;
}
if (Opcode == SILInstructionKind::SwitchEnumInst
&& parseForwardingOwnershipKind(forwardingOwnership)) {
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
if (parsedComma || (CaseBBs.empty() && !DefaultBB)) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default");
return true;
}
if (Opcode == SILInstructionKind::SwitchEnumInst) {
ResultVal = B.createSwitchEnum(InstLoc, Val, DefaultBB, CaseBBs, None,
ProfileCounter(), forwardingOwnership);
} else
ResultVal = B.createSwitchEnumAddr(InstLoc, Val, DefaultBB, CaseBBs);
break;
}
case SILInstructionKind::SwitchValueInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<SILValue, SILBasicBlock *>, 4> CaseBBs;
SILBasicBlock *DefaultBB = nullptr;
while (!peekSILDebugLocation(P) && P.consumeIf(tok::comma)) {
Identifier BBName;
SourceLoc BBLoc;
SILValue CaseVal;
// Parse 'default' sil-identifier.
if (P.consumeIf(tok::kw_default)) {
parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name);
DefaultBB = getBBForReference(BBName, BBLoc);
break;
}
// Parse 'case' value-ref ':' sil-identifier.
if (P.consumeIf(tok::kw_case)) {
if (parseValueRef(CaseVal, Val->getType(),
RegularLocation(P.Tok.getLoc()), B)) {
// TODO: Issue a proper error message here
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr,
"reference to a value");
return true;
}
auto intTy = Val->getType().getAs<BuiltinIntegerType>();
auto functionTy = Val->getType().getAs<SILFunctionType>();
if (!intTy && !functionTy) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type);
return true;
}
if (intTy) {
// If it is a switch on an integer type, check that all case values
// are integer literals or undef.
if (!isa<SILUndef>(CaseVal)) {
auto *IL = dyn_cast<IntegerLiteralInst>(CaseVal);
if (!IL) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type);
return true;
}
APInt CaseValue = IL->getValue();
if (CaseValue.getBitWidth() != intTy->getGreatestWidth())
CaseVal = B.createIntegerLiteral(
IL->getLoc(), Val->getType(),
CaseValue.zextOrTrunc(intTy->getGreatestWidth()));
}
}
if (functionTy) {
// If it is a switch on a function type, check that all case values
// are function references or undef.
if (!isa<SILUndef>(CaseVal)) {
auto *FR = dyn_cast<FunctionRefInst>(CaseVal);
if (!FR) {
if (auto *CF = dyn_cast<ConvertFunctionInst>(CaseVal)) {
FR = dyn_cast<FunctionRefInst>(CF->getOperand());
}
}
if (!FR) {
P.diagnose(P.Tok, diag::sil_integer_literal_not_integer_type);
return true;
}
}
}
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseSILIdentifier(BBName, BBLoc, diag::expected_sil_block_name);
CaseBBs.push_back({CaseVal, getBBForReference(BBName, BBLoc)});
continue;
}
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default");
return true;
}
if (parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createSwitchValue(InstLoc, Val, DefaultBB, CaseBBs);
break;
}
case SILInstructionKind::SelectValueInst: {
if (parseTypedValueRef(Val, B))
return true;
SmallVector<std::pair<UnresolvedValueName, UnresolvedValueName>, 4>
CaseValueAndResultNames;
Optional<UnresolvedValueName> DefaultResultName;
while (P.consumeIf(tok::comma)) {
Identifier BBName;
SourceLoc BBLoc;
// Parse 'default' sil-value.
UnresolvedValueName tmp;
if (P.consumeIf(tok::kw_default)) {
if (parseValueName(tmp))
return true;
DefaultResultName = tmp;
break;
}
// Parse 'case' sil-decl-ref ':' sil-value.
if (P.consumeIf(tok::kw_case)) {
UnresolvedValueName casevalue;
parseValueName(casevalue);
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":");
parseValueName(tmp);
CaseValueAndResultNames.push_back(std::make_pair(casevalue, tmp));
continue;
}
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "case or default");
return true;
}
if (!DefaultResultName) {
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "default");
return true;
}
// Parse the type of the result operands.
SILType ResultType;
if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(ResultType) || parseSILDebugLocation(InstLoc, B))
return true;
// Resolve the results.
SmallVector<std::pair<SILValue, SILValue>, 4> CaseValues;
SILValue DefaultValue;
if (DefaultResultName)
DefaultValue =
getLocalValue(*DefaultResultName, ResultType, InstLoc, B);
SILType ValType = Val->getType();
for (auto &caseName : CaseValueAndResultNames)
CaseValues.push_back(std::make_pair(
getLocalValue(caseName.first, ValType, InstLoc, B),
getLocalValue(caseName.second, ResultType, InstLoc, B)));
ResultVal = B.createSelectValue(InstLoc, Val, ResultType, DefaultValue,
CaseValues);
break;
}
case SILInstructionKind::DeinitExistentialAddrInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeinitExistentialAddr(InstLoc, Val);
break;
}
case SILInstructionKind::DeinitExistentialValueInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDeinitExistentialValue(InstLoc, Val);
break;
}
case SILInstructionKind::InitExistentialAddrInst: {
CanType Ty;
SourceLoc TyLoc;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(Ty, TyLoc) || parseSILDebugLocation(InstLoc, B))
return true;
// Lower the type at the abstraction level of the existential.
auto archetype = OpenedArchetypeType::get(Val->getType().getASTType())
->getCanonicalType();
auto &F = B.getFunction();
SILType LoweredTy =
F.getLoweredType(Lowering::AbstractionPattern(archetype), Ty)
.getAddressType();
// Collect conformances for the type.
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, Ty, TyLoc,
Val->getType().getASTType());
ResultVal = B.createInitExistentialAddr(InstLoc, Val, Ty, LoweredTy,
conformances);
break;
}
case SILInstructionKind::InitExistentialValueInst: {
CanType FormalConcreteTy;
SILType ExistentialTy;
SourceLoc TyLoc;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(FormalConcreteTy, TyLoc) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ExistentialTy) || parseSILDebugLocation(InstLoc, B))
return true;
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, FormalConcreteTy, TyLoc,
ExistentialTy.getASTType());
ResultVal = B.createInitExistentialValue(
InstLoc, ExistentialTy, FormalConcreteTy, Val, conformances);
break;
}
case SILInstructionKind::AllocExistentialBoxInst: {
SILType ExistentialTy;
CanType ConcreteFormalTy;
SourceLoc TyLoc;
if (parseSILType(ExistentialTy) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(ConcreteFormalTy, TyLoc) ||
parseSILDebugLocation(InstLoc, B))
return true;
// Collect conformances for the type.
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, ConcreteFormalTy, TyLoc,
ExistentialTy.getASTType());
ResultVal = B.createAllocExistentialBox(InstLoc, ExistentialTy,
ConcreteFormalTy, conformances);
break;
}
case SILInstructionKind::InitExistentialRefInst: {
CanType FormalConcreteTy;
SILType ExistentialTy;
SourceLoc TyLoc;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
parseASTType(FormalConcreteTy, TyLoc) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ExistentialTy))
return true;
ValueOwnershipKind forwardingOwnership = Val.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, FormalConcreteTy, TyLoc,
ExistentialTy.getASTType());
// FIXME: Conformances in InitExistentialRefInst is currently not included
// in SIL.rst.
ResultVal =
B.createInitExistentialRef(InstLoc, ExistentialTy, FormalConcreteTy,
Val, conformances, forwardingOwnership);
break;
}
case SILInstructionKind::InitExistentialMetatypeInst: {
SourceLoc TyLoc;
SILType ExistentialTy;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILType(ExistentialTy, TyLoc) ||
parseSILDebugLocation(InstLoc, B))
return true;
auto baseExType = ExistentialTy.getASTType();
auto formalConcreteType = Val->getType().getASTType();
while (auto instExType = dyn_cast<ExistentialMetatypeType>(baseExType)) {
baseExType = instExType.getInstanceType();
formalConcreteType =
cast<MetatypeType>(formalConcreteType).getInstanceType();
}
ArrayRef<ProtocolConformanceRef> conformances =
collectExistentialConformances(P, formalConcreteType, TyLoc,
baseExType);
ResultVal = B.createInitExistentialMetatype(InstLoc, Val, ExistentialTy,
conformances);
break;
}
case SILInstructionKind::DynamicMethodBranchInst: {
SILDeclRef Member;
Identifier BBName, BBName2;
SourceLoc NameLoc, NameLoc2;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILDeclRef(Member) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(BBName2, NameLoc2,
diag::expected_sil_block_name) ||
parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDynamicMethodBranch(
InstLoc, Val, Member, getBBForReference(BBName, NameLoc),
getBBForReference(BBName2, NameLoc2));
break;
}
case SILInstructionKind::ProjectBlockStorageInst: {
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createProjectBlockStorage(InstLoc, Val);
break;
}
case SILInstructionKind::InitBlockStorageHeaderInst: {
Identifier invoke, type;
SourceLoc invokeLoc, typeLoc;
UnresolvedValueName invokeName;
SILType invokeTy;
GenericEnvironment *invokeGenericEnv = nullptr;
GenericParamList *invokeGenericParams = nullptr;
SILType blockType;
SmallVector<ParsedSubstitution, 4> parsedSubs;
if (parseTypedValueRef(Val, B) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(invoke, invokeLoc, diag::expected_tok_in_sil_instr,
"invoke") ||
parseValueName(invokeName) || parseSubstitutions(parsedSubs) ||
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
parseSILType(invokeTy, invokeGenericEnv, invokeGenericParams) ||
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
parseSILIdentifier(type, typeLoc, diag::expected_tok_in_sil_instr,
"type") ||
parseSILType(blockType) || parseSILDebugLocation(InstLoc, B))
return true;
if (invoke.str() != "invoke") {
P.diagnose(invokeLoc, diag::expected_tok_in_sil_instr, "invoke");
return true;
}
if (type.str() != "type") {
P.diagnose(invokeLoc, diag::expected_tok_in_sil_instr, "type");
return true;
}
auto invokeVal = getLocalValue(invokeName, invokeTy, InstLoc, B);
SubstitutionMap subMap;
if (!parsedSubs.empty()) {
if (!invokeGenericEnv) {
P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type);
return true;
}
subMap = getApplySubstitutionsFromParsed(*this, invokeGenericEnv,
parsedSubs);
if (!subMap)
return true;
}
ResultVal = B.createInitBlockStorageHeader(InstLoc, Val, invokeVal,
blockType, subMap);
break;
}
case SILInstructionKind::DifferentiableFunctionInst: {
// e.g. differentiable_function [parameters 0 1 2] [results 0] %0 : $T
//
// e.g. differentiable_function [parameters 0 1 2] [results 0] %0 : $T
// with_derivative {%1 : $T, %2 : $T}
// ^~ jvp ^~ vjp
// Parse `[parameters <integer_literal>...]`.
SmallVector<unsigned, 8> rawParameterIndices;
if (parseIndexList(P, "parameters", rawParameterIndices,
diag::sil_autodiff_expected_parameter_index))
return true;
SmallVector<unsigned, 2> rawResultIndices;
if (parseIndexList(P, "results", rawResultIndices,
diag::sil_autodiff_expected_result_index))
return true;
// Parse the original function value.
SILValue original;
SourceLoc originalOperandLoc;
if (parseTypedValueRef(original, originalOperandLoc, B))
return true;
auto fnType = original->getType().getAs<SILFunctionType>();
if (!fnType) {
P.diagnose(originalOperandLoc,
diag::sil_inst_autodiff_expected_function_type_operand);
return true;
}
Optional<std::pair<SILValue, SILValue>> derivativeFunctions = None;
// Parse an optional operand list
// `with_derivative { <operand> , <operand> }`.
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "with_derivative") {
P.consumeToken(tok::identifier);
// Parse derivative function values as an operand list.
// FIXME(rxwei): Change this to *not* require a type signature once
// we can infer derivative function types.
derivativeFunctions = std::make_pair(SILValue(), SILValue());
if (P.parseToken(
tok::l_brace,
diag::sil_inst_autodiff_operand_list_expected_lbrace) ||
parseTypedValueRef(derivativeFunctions->first, B) ||
P.parseToken(tok::comma,
diag::sil_inst_autodiff_operand_list_expected_comma) ||
parseTypedValueRef(derivativeFunctions->second, B) ||
P.parseToken(tok::r_brace,
diag::sil_inst_autodiff_operand_list_expected_rbrace))
return true;
}
ValueOwnershipKind forwardingOwnership(OwnershipKind::None);
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
auto *parameterIndices = IndexSubset::get(
P.Context, fnType->getNumParameters(), rawParameterIndices);
auto *resultIndices = IndexSubset::get(
P.Context,
fnType->getNumResults() + fnType->getNumIndirectMutatingParameters(),
rawResultIndices);
if (forwardingOwnership != OwnershipKind::None) {
ResultVal = B.createDifferentiableFunction(
InstLoc, parameterIndices, resultIndices, original,
derivativeFunctions, forwardingOwnership);
} else {
ResultVal = B.createDifferentiableFunction(InstLoc, parameterIndices,
resultIndices, original,
derivativeFunctions);
}
break;
}
case SILInstructionKind::LinearFunctionInst: {
// e.g. linear_function [parameters 0 1 2] %0 : $T
// e.g. linear_function [parameters 0 1 2] %0 : $T with_transpose %1 : $T
// Parse `[parameters <integer_literal>...]`.
SmallVector<unsigned, 8> rawParameterIndices;
if (parseIndexList(P, "parameters", rawParameterIndices,
diag::sil_autodiff_expected_parameter_index))
return true;
// Parse the original function value.
SILValue original;
SourceLoc originalOperandLoc;
if (parseTypedValueRef(original, originalOperandLoc, B))
return true;
auto fnType = original->getType().getAs<SILFunctionType>();
if (!fnType) {
P.diagnose(originalOperandLoc,
diag::sil_inst_autodiff_expected_function_type_operand);
return true;
}
// Parse an optional transpose function.
Optional<SILValue> transpose = None;
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "with_transpose") {
P.consumeToken(tok::identifier);
transpose = SILValue();
if (parseTypedValueRef(*transpose, B))
return true;
}
ValueOwnershipKind forwardingOwnership(OwnershipKind::None);
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
auto *parameterIndicesSubset = IndexSubset::get(
P.Context, fnType->getNumParameters(), rawParameterIndices);
if (forwardingOwnership != OwnershipKind::None) {
ResultVal =
B.createLinearFunction(InstLoc, parameterIndicesSubset, original,
forwardingOwnership, transpose);
} else {
ResultVal = B.createLinearFunction(InstLoc, parameterIndicesSubset,
original, transpose);
}
break;
}
case SILInstructionKind::DifferentiableFunctionExtractInst: {
// Parse the rest of the instruction: an extractee, a differentiable
// function operand, an optional explicit extractee type, and a debug
// location.
NormalDifferentiableFunctionTypeComponent extractee;
StringRef extracteeNames[3] = {"original", "jvp", "vjp"};
SILValue functionOperand;
SourceLoc lastLoc;
if (P.parseToken(
tok::l_square,
diag::sil_inst_autodiff_expected_differentiable_extractee_kind) ||
parseSILIdentifierSwitch(
extractee, extracteeNames,
diag::sil_inst_autodiff_expected_differentiable_extractee_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"extractee kind"))
return true;
if (parseTypedValueRef(functionOperand, B))
return true;
// Parse an optional explicit extractee type.
Optional<SILType> extracteeType = None;
if (P.consumeIf(tok::kw_as)) {
extracteeType = SILType();
if (parseSILType(*extracteeType))
return true;
}
ValueOwnershipKind forwardingOwnership =
functionOperand.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createDifferentiableFunctionExtract(
InstLoc, extractee, functionOperand, forwardingOwnership,
extracteeType);
break;
}
case SILInstructionKind::LinearFunctionExtractInst: {
// Parse the rest of the instruction: an extractee, a linear function
// operand, and a debug location.
LinearDifferentiableFunctionTypeComponent extractee;
StringRef extracteeNames[2] = {"original", "transpose"};
SILValue functionOperand;
SourceLoc lastLoc;
if (P.parseToken(tok::l_square,
diag::sil_inst_autodiff_expected_linear_extractee_kind) ||
parseSILIdentifierSwitch(extractee, extracteeNames,
diag::sil_inst_autodiff_expected_linear_extractee_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"extractee kind"))
return true;
if (parseTypedValueRef(functionOperand, B))
return true;
ValueOwnershipKind forwardingOwnership =
functionOperand.getOwnershipKind();
if (parseForwardingOwnershipKind(forwardingOwnership)
|| parseSILDebugLocation(InstLoc, B))
return true;
ResultVal = B.createLinearFunctionExtract(
InstLoc, extractee, functionOperand, forwardingOwnership);
break;
}
case SILInstructionKind::DifferentiabilityWitnessFunctionInst: {
// e.g. differentiability_witness_function
// [jvp] [parameters 0 1] [results 0] <T where T: Differentiable>
// @foo : <T> $(T) -> T
DifferentiabilityWitnessFunctionKind witnessKind;
StringRef witnessKindNames[3] = {"jvp", "vjp", "transpose"};
if (P.parseToken(
tok::l_square,
diag::
sil_inst_autodiff_expected_differentiability_witness_kind) ||
parseSILIdentifierSwitch(
witnessKind, witnessKindNames,
diag::
sil_inst_autodiff_expected_differentiability_witness_kind) ||
P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
"differentiability witness function kind"))
return true;
SourceLoc keyStartLoc = P.Tok.getLoc();
DifferentiabilityKind diffKind;
AutoDiffConfig config;
SILFunction *originalFn = nullptr;
if (parseSILDifferentiabilityWitnessConfigAndFunction(
P, *this, InstLoc, diffKind, config, originalFn))
return true;
auto *witness = SILMod.lookUpDifferentiabilityWitness(
{originalFn->getName(), diffKind, config});
if (!witness) {
P.diagnose(keyStartLoc, diag::sil_diff_witness_undefined);
return true;
}
// Parse an optional explicit function type.
Optional<SILType> functionType = None;
if (P.consumeIf(tok::kw_as)) {
functionType = SILType();
if (parseSILType(*functionType))
return true;
}
ResultVal = B.createDifferentiabilityWitnessFunction(
InstLoc, witnessKind, witness, functionType);
break;
}
case SILInstructionKind::AwaitAsyncContinuationInst: {
// 'await_async_continuation' operand, 'resume' bb, 'error' bb
Identifier ResumeBBName, ErrorBBName{};
SourceLoc ResumeNameLoc, ErrorNameLoc{};
if (parseTypedValueRef(Val, B)
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| P.parseSpecificIdentifier("resume", diag::expected_tok_in_sil_instr, "resume")
|| parseSILIdentifier(ResumeBBName, ResumeNameLoc, diag::expected_sil_block_name)) {
return true;
}
if (P.consumeIf(tok::comma)) {
if (P.parseSpecificIdentifier("error", diag::expected_tok_in_sil_instr, "error")
|| parseSILIdentifier(ErrorBBName, ErrorNameLoc, diag::expected_sil_block_name)
|| parseSILDebugLocation(InstLoc, B)) {
return true;
}
}
SILBasicBlock *resumeBB, *errorBB = nullptr;
resumeBB = getBBForReference(ResumeBBName, ResumeNameLoc);
if (!ErrorBBName.empty()) {
errorBB = getBBForReference(ErrorBBName, ErrorNameLoc);
}
ResultVal = B.createAwaitAsyncContinuation(InstLoc, Val, resumeBB, errorBB);
break;
}
case SILInstructionKind::GetAsyncContinuationInst:
case SILInstructionKind::GetAsyncContinuationAddrInst: {
// 'get_async_continuation' '[throws]'? type
// 'get_async_continuation_addr' '[throws]'? type ',' operand
bool throws = false;
if (P.consumeIf(tok::l_square)) {
if (P.parseToken(tok::kw_throws, diag::expected_tok_in_sil_instr, "throws")
|| P.parseToken(tok::r_square, diag::expected_tok_in_sil_instr, "]"))
return true;
throws = true;
}
CanType resumeTy;
if (parseASTType(resumeTy)) {
return true;
}
SILValue resumeBuffer;
if (Opcode == SILInstructionKind::GetAsyncContinuationAddrInst) {
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",")
|| parseTypedValueRef(resumeBuffer, B)) {
return true;
}
}
if (parseSILDebugLocation(InstLoc, B))
return true;
if (Opcode == SILInstructionKind::GetAsyncContinuationAddrInst) {
ResultVal = B.createGetAsyncContinuationAddr(InstLoc, resumeBuffer,
resumeTy, throws);
} else {
ResultVal = B.createGetAsyncContinuation(InstLoc, resumeTy, throws);
}
break;
}
}
return false;
}