mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This instruction can be used to disable ownership verification on it's result and will be allowed only in raw SIL. Sometimes SILGen can produce invalid ownership SSA, that cannot be resolved until mandatory passes run. We have a few ways to piecewise disable verification. With unchecked_ownership instruction we can provide a uniform way to disable ownership verification for a value.
8999 lines
318 KiB
C++
8999 lines
318 KiB
C++
//===--- ParseSIL.cpp - SIL File Parsing logic ----------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SILParser.h"
|
|
#include "SILParserFunctionBuilder.h"
|
|
#include "SILParserState.h"
|
|
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/ConformanceLookup.h"
|
|
#include "swift/AST/DiagnosticsParse.h"
|
|
#include "swift/AST/ExistentialLayout.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/AST/NameLookup.h"
|
|
#include "swift/AST/NameLookupRequests.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/SILGenRequests.h"
|
|
#include "swift/AST/SourceFile.h"
|
|
#include "swift/AST/TypeCheckRequests.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Defer.h"
|
|
#include "swift/Demangling/Demangle.h"
|
|
#include "swift/Parse/Lexer.h"
|
|
#include "swift/Parse/ParseSILSupport.h"
|
|
#include "swift/SIL/AbstractionPattern.h"
|
|
#include "swift/SIL/InstructionUtils.h"
|
|
#include "swift/SIL/OwnershipUtils.h"
|
|
#include "swift/SIL/ParseTestSpecification.h"
|
|
#include "swift/SIL/SILArgument.h"
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/SILDebugScope.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "swift/SIL/SILMoveOnlyDeinit.h"
|
|
#include "swift/SIL/SILUndef.h"
|
|
#include "swift/SIL/TypeLowering.h"
|
|
#include "swift/Sema/SILTypeResolutionContext.h"
|
|
#include "swift/Subsystems.h"
|
|
#include "llvm/ADT/StringSwitch.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
|
|
#include <variant>
|
|
|
|
using namespace swift;
|
|
|
|
static llvm::cl::opt<bool>
|
|
ParseSerializedSIL("parse-serialized-sil",
|
|
llvm::cl::desc("Parse the output of a serialized module"));
|
|
|
|
static llvm::cl::opt<bool>
|
|
DisableInputVerify("sil-disable-input-verify",
|
|
llvm::cl::desc("Disable verification of input SIL"),
|
|
llvm::cl::init(false));
|
|
|
|
// Option for testing -silgen-cleanup -enable-complete-ossa
|
|
static llvm::cl::opt<bool>
|
|
ParseIncompleteOSSA("parse-incomplete-ossa",
|
|
llvm::cl::desc("Parse OSSA with incomplete lifetimes"));
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILParserState implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
SILParserState::~SILParserState() {
|
|
if (!ForwardRefFns.empty()) {
|
|
for (auto Entry : ForwardRefFns) {
|
|
if (Entry.second.Loc.isValid()) {
|
|
M.getASTContext().Diags.diagnose(Entry.second.Loc,
|
|
diag::sil_use_of_undefined_value,
|
|
Entry.first.str());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Turn any debug-info-only function declarations into zombies.
|
|
markZombies();
|
|
}
|
|
|
|
void SILParserState::markZombies() {
|
|
for (auto *Fn : PotentialZombieFns) {
|
|
if (Fn->isExternalDeclaration() && !Fn->isZombie()) {
|
|
Fn->setInlined();
|
|
M.eraseFunction(Fn);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<SILModule>
|
|
ParseSILModuleRequest::evaluate(Evaluator &evaluator,
|
|
ASTLoweringDescriptor desc) const {
|
|
auto *SF = desc.getSourceFileToParse();
|
|
assert(SF);
|
|
|
|
auto bufferID = SF->getBufferID();
|
|
auto silMod = SILModule::createEmptyModule(desc.context, desc.conv,
|
|
desc.opts);
|
|
SILParserState parserState(*silMod.get());
|
|
Parser parser(bufferID, *SF, &parserState);
|
|
PrettyStackTraceParser StackTrace(parser);
|
|
|
|
if (ParseSerializedSIL) {
|
|
silMod.get()->setParsedAsSerializedSIL();
|
|
}
|
|
|
|
auto hadError = parser.parseTopLevelSIL();
|
|
if (hadError) {
|
|
// The rest of the SIL pipeline expects well-formed SIL, so if we encounter
|
|
// a parsing error, just return an empty SIL module.
|
|
//
|
|
// Because the SIL parser's notion of failing with an error is distinct from
|
|
// the ASTContext's notion of having emitted a diagnostic, it's possible for
|
|
// the parser to fail silently without emitting a diagnostic. This assertion
|
|
// ensures that +asserts builds will fail fast. If you crash here, please go
|
|
// back and add a diagnostic after identifying where the SIL parser failed.
|
|
assert(SF->getASTContext().hadError() &&
|
|
"Failed to parse SIL but did not emit any errors!");
|
|
return SILModule::createEmptyModule(desc.context, desc.conv, desc.opts);
|
|
}
|
|
|
|
// Mark functions as zombies before calling SILVerifier as functions referred
|
|
//to by debug scopes only can fail verifier checks
|
|
parserState.markZombies();
|
|
|
|
// If SIL parsing succeeded, verify the generated SIL.
|
|
if (!parser.Diags.hadAnyError() && !DisableInputVerify) {
|
|
silMod->verify(/*SingleFunction=*/true, !ParseIncompleteOSSA);
|
|
}
|
|
|
|
return silMod;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SILParser
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
bool SILParser::parseSILIdentifier(Identifier &Result, SourceLoc &Loc,
|
|
DiagRef D) {
|
|
switch (P.Tok.getKind()) {
|
|
case tok::identifier:
|
|
case tok::dollarident:
|
|
Result = P.Context.getIdentifier(P.Tok.getText());
|
|
break;
|
|
case tok::string_literal: {
|
|
// Drop the double quotes.
|
|
StringRef rawString = P.Tok.getText().drop_front().drop_back();
|
|
Result = P.Context.getIdentifier(rawString);
|
|
break;
|
|
}
|
|
case tok::oper_binary_unspaced: // fixme?
|
|
case tok::oper_binary_spaced:
|
|
case tok::kw_init:
|
|
// A binary operator or `init` can be part of a SILDeclRef.
|
|
Result = P.Context.getIdentifier(P.Tok.getText());
|
|
break;
|
|
default:
|
|
// If it's some other keyword, grab an identifier for it.
|
|
if (P.Tok.isKeyword()) {
|
|
Result = P.Context.getIdentifier(P.Tok.getText());
|
|
break;
|
|
}
|
|
P.diagnose(P.Tok, D);
|
|
return true;
|
|
}
|
|
|
|
Loc = P.Tok.getLoc();
|
|
P.consumeToken();
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseVerbatim(StringRef name) {
|
|
Identifier tok;
|
|
SourceLoc loc;
|
|
|
|
if (parseSILIdentifier(tok, loc, diag::expected_tok_in_sil_instr, name)) {
|
|
return true;
|
|
}
|
|
if (tok.str() != name) {
|
|
P.diagnose(loc, diag::expected_tok_in_sil_instr, name);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
SILParser::~SILParser() {
|
|
for (auto &Entry : ForwardRefLocalValues) {
|
|
if (ValueBase *dummyVal = LocalValues[Entry.first()]) {
|
|
dummyVal->replaceAllUsesWith(
|
|
SILUndef::get(dummyVal->getFunction(), dummyVal->getType()));
|
|
::delete cast<PlaceholderValue>(dummyVal);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// diagnoseProblems - After a function is fully parse, emit any diagnostics
|
|
/// for errors and return true if there were any.
|
|
bool SILParser::diagnoseProblems() {
|
|
// Check for any uses of basic blocks that were not defined.
|
|
if (!UndefinedBlocks.empty()) {
|
|
// FIXME: These are going to come out in nondeterministic order.
|
|
for (auto Entry : UndefinedBlocks)
|
|
P.diagnose(Entry.second.Loc, diag::sil_undefined_basicblock_use,
|
|
Entry.second.Item);
|
|
|
|
HadError = true;
|
|
}
|
|
|
|
if (!ForwardRefLocalValues.empty()) {
|
|
// FIXME: These are going to come out in nondeterministic order.
|
|
for (auto &Entry : ForwardRefLocalValues)
|
|
P.diagnose(Entry.second, diag::sil_use_of_undefined_value,
|
|
Entry.first());
|
|
HadError = true;
|
|
}
|
|
|
|
return HadError;
|
|
}
|
|
|
|
/// getGlobalNameForDefinition - Given a definition of a global name, look
|
|
/// it up and return an appropriate SIL function.
|
|
SILFunction *SILParser::getGlobalNameForDefinition(Identifier name,
|
|
CanSILFunctionType ty,
|
|
SourceLoc sourceLoc) {
|
|
SILParserFunctionBuilder builder(SILMod);
|
|
auto silLoc = RegularLocation(sourceLoc);
|
|
|
|
// Check to see if a function of this name has been forward referenced. If so
|
|
// complete the forward reference.
|
|
auto iter = TUState.ForwardRefFns.find(name);
|
|
if (iter != TUState.ForwardRefFns.end()) {
|
|
SILFunction *fn = iter->second.Item;
|
|
|
|
// Verify that the types match up.
|
|
if (fn->getLoweredFunctionType() != ty) {
|
|
P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(),
|
|
fn->getLoweredFunctionType(), ty);
|
|
P.diagnose(iter->second.Loc, diag::sil_prior_reference);
|
|
fn = builder.createFunctionForForwardReference("" /*name*/, ty, silLoc);
|
|
}
|
|
|
|
assert(fn->isExternalDeclaration() && "Forward defns cannot have bodies!");
|
|
TUState.ForwardRefFns.erase(iter);
|
|
|
|
// Move the function to this position in the module.
|
|
//
|
|
// FIXME: Should we move this functionality into SILParserFunctionBuilder?
|
|
SILMod.getFunctionList().remove(fn);
|
|
SILMod.getFunctionList().push_back(fn);
|
|
|
|
return fn;
|
|
}
|
|
|
|
// If we don't have a forward reference, make sure the function hasn't been
|
|
// defined already.
|
|
if (SILMod.lookUpFunction(name.str()) != nullptr) {
|
|
P.diagnose(sourceLoc, diag::sil_value_redefinition, name.str());
|
|
return builder.createFunctionForForwardReference("" /*name*/, ty, silLoc);
|
|
}
|
|
|
|
// Otherwise, this definition is the first use of this name.
|
|
return builder.createFunctionForForwardReference(name.str(), ty, silLoc);
|
|
}
|
|
|
|
/// getGlobalNameForReference - Given a reference to a global name, look it
|
|
/// up and return an appropriate SIL function.
|
|
SILFunction *SILParser::getGlobalNameForReference(Identifier name,
|
|
CanSILFunctionType funcTy,
|
|
SourceLoc sourceLoc,
|
|
bool ignoreFwdRef) {
|
|
SILParserFunctionBuilder builder(SILMod);
|
|
auto silLoc = RegularLocation(sourceLoc);
|
|
|
|
// Check to see if we have a function by this name already.
|
|
if (SILFunction *fn = SILMod.lookUpFunction(name.str())) {
|
|
// If so, check for matching types.
|
|
if (fn->getLoweredFunctionType() == funcTy) {
|
|
return fn;
|
|
}
|
|
|
|
P.diagnose(sourceLoc, diag::sil_value_use_type_mismatch, name.str(),
|
|
fn->getLoweredFunctionType(), funcTy);
|
|
|
|
return builder.createFunctionForForwardReference("" /*name*/, funcTy,
|
|
silLoc);
|
|
}
|
|
|
|
// If we didn't find a function, create a new one - it must be a forward
|
|
// reference.
|
|
auto *fn =
|
|
builder.createFunctionForForwardReference(name.str(), funcTy, silLoc);
|
|
TUState.ForwardRefFns[name] = {fn, ignoreFwdRef ? SourceLoc() : sourceLoc};
|
|
return fn;
|
|
}
|
|
|
|
|
|
/// getBBForDefinition - Return the SILBasicBlock for a definition of the
|
|
/// specified block.
|
|
SILBasicBlock *SILParser::getBBForDefinition(Identifier Name, SourceLoc Loc) {
|
|
// If there was no name specified for this block, just create a new one.
|
|
if (Name.empty())
|
|
return F->createBasicBlock();
|
|
|
|
SILBasicBlock *&BB = BlocksByName[Name];
|
|
// If the block has never been named yet, just create it.
|
|
if (BB == nullptr)
|
|
return BB = F->createBasicBlock();
|
|
|
|
// If it already exists, it was either a forward reference or a redefinition.
|
|
// If it is a forward reference, it should be in our undefined set.
|
|
if (!UndefinedBlocks.erase(BB)) {
|
|
// If we have a redefinition, return a new BB to avoid inserting
|
|
// instructions after the terminator.
|
|
P.diagnose(Loc, diag::sil_basicblock_redefinition, Name);
|
|
HadError = true;
|
|
return F->createBasicBlock();
|
|
}
|
|
|
|
// FIXME: Splice the block to the end of the function so they come out in the
|
|
// right order.
|
|
return BB;
|
|
}
|
|
|
|
/// getBBForReference - return the SILBasicBlock of the specified name. The
|
|
/// source location is used to diagnose a failure if the block ends up never
|
|
/// being defined.
|
|
SILBasicBlock *SILParser::getBBForReference(Identifier Name, SourceLoc Loc) {
|
|
// If the block has already been created, use it.
|
|
SILBasicBlock *&BB = BlocksByName[Name];
|
|
if (BB != nullptr)
|
|
return BB;
|
|
|
|
// Otherwise, create it and remember that this is a forward reference so
|
|
// that we can diagnose use without definition problems.
|
|
BB = F->createBasicBlock();
|
|
UndefinedBlocks[BB] = {Name, Loc};
|
|
return BB;
|
|
}
|
|
|
|
/// sil-global-name:
|
|
/// '@' identifier
|
|
bool SILParser::parseGlobalName(Identifier &Name) {
|
|
return P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
|
|
parseSILIdentifier(Name, diag::expected_sil_value_name);
|
|
}
|
|
|
|
/// getLocalValue - Get a reference to a local value with the specified name
|
|
/// and type.
|
|
SILValue SILParser::getLocalValue(UnresolvedValueName Name, SILType Type,
|
|
SILLocation Loc, SILBuilder &B) {
|
|
if (Name.isUndef())
|
|
return SILUndef::get(B.getFunction(), Type);
|
|
|
|
// Check to see if this is already defined.
|
|
ValueBase *&Entry = LocalValues[Name.Name];
|
|
|
|
if (Entry) {
|
|
// If this value is already defined, check it to make sure types match.
|
|
SILType EntryTy = Entry->getType();
|
|
|
|
if (EntryTy != Type) {
|
|
HadError = true;
|
|
P.diagnose(Name.NameLoc, diag::sil_value_use_type_mismatch, Name.Name,
|
|
EntryTy.getRawASTType(), Type.getRawASTType());
|
|
// Make sure to return something of the requested type.
|
|
return SILUndef::get(B.getFunction(), Type);
|
|
}
|
|
|
|
return SILValue(Entry);
|
|
}
|
|
|
|
// Otherwise, this is a forward reference. Create a dummy node to represent
|
|
// it until we see a real definition.
|
|
ForwardRefLocalValues[Name.Name] = Name.NameLoc;
|
|
|
|
Entry = ::new PlaceholderValue(&B.getFunction(), Type);
|
|
return Entry;
|
|
}
|
|
|
|
/// setLocalValue - When an instruction or block argument is defined, this
|
|
/// method is used to register it and update our symbol table.
|
|
void SILParser::setLocalValue(ValueBase *Value, StringRef Name,
|
|
SourceLoc NameLoc) {
|
|
ValueBase *&Entry = LocalValues[Name];
|
|
|
|
// If this value was already defined, it is either a redefinition, or a
|
|
// specification for a forward referenced value.
|
|
if (Entry) {
|
|
if (!ForwardRefLocalValues.erase(Name)) {
|
|
P.diagnose(NameLoc, diag::sil_value_redefinition, Name);
|
|
HadError = true;
|
|
return;
|
|
}
|
|
|
|
// If the forward reference was of the wrong type, diagnose this now.
|
|
if (Entry->getType() != Value->getType()) {
|
|
P.diagnose(NameLoc, diag::sil_value_def_type_mismatch, Name,
|
|
Entry->getType().getRawASTType(),
|
|
Value->getType().getRawASTType());
|
|
HadError = true;
|
|
} else {
|
|
if (TestSpecsWithRefs.find(Name) != TestSpecsWithRefs.end()) {
|
|
for (auto *tsi : TestSpecsWithRefs[Name]) {
|
|
tsi->setValueForName(Name, Value);
|
|
}
|
|
}
|
|
|
|
// Forward references only live here if they have a single result.
|
|
Entry->replaceAllUsesWith(Value);
|
|
::delete cast<PlaceholderValue>(Entry);
|
|
}
|
|
Entry = Value;
|
|
return;
|
|
}
|
|
|
|
if (TestSpecsWithRefs.find(Name) != TestSpecsWithRefs.end()) {
|
|
for (auto *tsi : TestSpecsWithRefs[Name]) {
|
|
tsi->setValueForName(Name, Value);
|
|
}
|
|
}
|
|
|
|
// Otherwise, just store it in our map.
|
|
Entry = Value;
|
|
}
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SIL Parsing Logic
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// parseSILLinkage - Parse a linkage specifier if present.
|
|
/// sil-linkage:
|
|
/// /*empty*/ // default depends on whether this is a definition
|
|
/// 'public'
|
|
/// 'hidden'
|
|
/// 'shared'
|
|
/// 'private'
|
|
/// 'public_external'
|
|
/// 'hidden_external'
|
|
/// 'private_external'
|
|
static bool parseSILLinkage(std::optional<SILLinkage> &Result, Parser &P) {
|
|
// Begin by initializing result to our base value of None.
|
|
Result = std::nullopt;
|
|
|
|
// Unfortunate collision with access control keywords.
|
|
if (P.Tok.is(tok::kw_public)) {
|
|
Result = SILLinkage::Public;
|
|
P.consumeToken();
|
|
return false;
|
|
}
|
|
|
|
// Unfortunate collision with access control keywords.
|
|
if (P.Tok.is(tok::kw_private)) {
|
|
Result = SILLinkage::Private;
|
|
P.consumeToken();
|
|
return false;
|
|
}
|
|
|
|
// If we do not have an identifier, bail. All SILLinkages that we are parsing
|
|
// are identifiers.
|
|
if (P.Tok.isNot(tok::identifier))
|
|
return false;
|
|
|
|
// Then use a string switch to try and parse the identifier.
|
|
Result = llvm::StringSwitch<std::optional<SILLinkage>>(P.Tok.getText())
|
|
.Case("non_abi", SILLinkage::PublicNonABI)
|
|
.Case("package_non_abi", SILLinkage::PackageNonABI)
|
|
.Case("package", SILLinkage::Package)
|
|
.Case("hidden", SILLinkage::Hidden)
|
|
.Case("shared", SILLinkage::Shared)
|
|
.Case("public_external", SILLinkage::PublicExternal)
|
|
.Case("package_external", SILLinkage::PackageExternal)
|
|
.Case("hidden_external", SILLinkage::HiddenExternal)
|
|
.Default(std::nullopt);
|
|
|
|
// If we succeed, consume the token.
|
|
if (Result) {
|
|
P.consumeToken(tok::identifier);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Given whether it's known to be a definition, resolve an optional
|
|
/// SIL linkage to a real one.
|
|
static SILLinkage resolveSILLinkage(std::optional<SILLinkage> linkage,
|
|
bool isDefinition) {
|
|
if (linkage.has_value()) {
|
|
return linkage.value();
|
|
} else if (isDefinition) {
|
|
return SILLinkage::DefaultForDefinition;
|
|
} else {
|
|
return SILLinkage::DefaultForDeclaration;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
using SILOptionalAttrValue = std::optional<std::variant<uint64_t, StringRef>>;
|
|
|
|
} // namespace
|
|
|
|
/// Returns false if no optional exists. Returns true on both success and
|
|
/// failure. On success, the Result string is nonempty. If the optional is
|
|
/// assigned to an integer value using an equal, \p value contains the parsed
|
|
/// value. Otherwise, value is set to the maximum uint64_t.
|
|
///
|
|
/// Example: [alignment=$NUM]
|
|
static bool parseSILOptional(StringRef &parsedName, SourceLoc &parsedNameLoc,
|
|
SILOptionalAttrValue &parsedValue,
|
|
SourceLoc &parsedValueLoc, SILParser &parser) {
|
|
if (!parser.P.consumeIf(tok::l_square))
|
|
return false;
|
|
|
|
Identifier parsedNameId;
|
|
if (parser.parseSILIdentifier(parsedNameId, parsedNameLoc,
|
|
diag::expected_in_attribute_list))
|
|
return true;
|
|
parsedName = parsedNameId.str();
|
|
|
|
uint64_t parsedIntValue = ~uint64_t(0);
|
|
Identifier parsedStringId;
|
|
if (parser.P.consumeIf(tok::equal)) {
|
|
auto currentTok = parser.P.Tok;
|
|
parsedValueLoc = currentTok.getLoc();
|
|
|
|
if (currentTok.is(tok::integer_literal)) {
|
|
if (parser.parseInteger(parsedIntValue,
|
|
diag::expected_in_attribute_list)) {
|
|
return true;
|
|
}
|
|
parsedValue = parsedIntValue;
|
|
} else {
|
|
if (parser.parseSILIdentifier(parsedStringId, parsedValueLoc,
|
|
diag::expected_in_attribute_list)) {
|
|
return true;
|
|
}
|
|
parsedValue = parsedStringId.str();
|
|
}
|
|
}
|
|
|
|
if (parser.P.parseToken(tok::r_square, diag::expected_in_attribute_list))
|
|
return true;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool parseSILOptional(StringRef &attrName, SourceLoc &attrLoc,
|
|
SILParser &SP) {
|
|
SILOptionalAttrValue parsedValue;
|
|
SourceLoc parsedValueLoc;
|
|
return parseSILOptional(attrName, attrLoc, parsedValue, parsedValueLoc, SP);
|
|
}
|
|
|
|
static bool parseSILOptional(StringRef &attrName, SILParser &SP) {
|
|
SourceLoc attrLoc;
|
|
return parseSILOptional(attrName, attrLoc, SP);
|
|
}
|
|
|
|
/// Parse an option attribute ('[' Expected ']')?
|
|
static bool parseSILOptional(bool &Result, SILParser &SP, StringRef Expected) {
|
|
StringRef Optional;
|
|
SourceLoc Loc;
|
|
if (parseSILOptional(Optional, Loc, SP)) {
|
|
if (Optional != Expected) {
|
|
SP.P.diagnose(Loc, diag::sil_invalid_attribute_for_expected, Optional,
|
|
Expected);
|
|
return true;
|
|
}
|
|
Result = true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// If the qualifier string is unrecognized, then diagnose and fail.
|
|
//
|
|
// If the qualifier is absent, then succeed and set the result to None.
|
|
// The caller can decide how to proceed with an absent qualifier.
|
|
//
|
|
// Usage:
|
|
// auto parseQualifierName = [](StringRef Str) {
|
|
// return llvm::StringSwitch<std::optional<SomeQualifier>>(Str)
|
|
// .Case("one", SomeQualifier::One)
|
|
// .Case("two", SomeQualifier::Two)
|
|
// .Default(None);
|
|
// };
|
|
// if (parseSILQualifier<SomeQualifier>(Qualifier, parseQualifierName))
|
|
// return true;
|
|
template <typename T>
|
|
bool SILParser::parseSILQualifier(
|
|
std::optional<T> &result,
|
|
llvm::function_ref<std::optional<T>(StringRef)> parseName) {
|
|
auto loc = P.Tok.getLoc();
|
|
StringRef Str;
|
|
// If we do not parse '[' ... ']',
|
|
if (!parseSILOptional(Str, *this)) {
|
|
result = std::nullopt;
|
|
return false;
|
|
}
|
|
result = parseName(Str);
|
|
if (!result) {
|
|
P.diagnose(loc, diag::unrecognized_sil_qualifier);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Remap RequirementReps to Requirements.
|
|
void SILParser::convertRequirements(ArrayRef<RequirementRepr> From,
|
|
SmallVectorImpl<Requirement> &To,
|
|
SmallVectorImpl<Type> &typeErasedParams) {
|
|
if (From.empty()) {
|
|
To.clear();
|
|
return;
|
|
}
|
|
|
|
// Use parser lexical scopes to resolve references
|
|
// to the generic parameters.
|
|
auto ResolveToInterfaceType = [&](TypeRepr *TyR) -> Type {
|
|
return performTypeResolution(TyR, /*IsSILType=*/false, ContextGenericSig,
|
|
ContextGenericParams);
|
|
};
|
|
|
|
for (auto &Req : From) {
|
|
if (Req.getKind() == RequirementReprKind::SameType) {
|
|
auto FirstType = ResolveToInterfaceType(Req.getFirstTypeRepr());
|
|
auto SecondType = ResolveToInterfaceType(Req.getSecondTypeRepr());
|
|
Requirement ConvertedRequirement(RequirementKind::SameType, FirstType,
|
|
SecondType);
|
|
To.push_back(ConvertedRequirement);
|
|
continue;
|
|
}
|
|
|
|
if (Req.getKind() == RequirementReprKind::TypeConstraint) {
|
|
auto Subject = ResolveToInterfaceType(Req.getSubjectRepr());
|
|
auto Constraint = ResolveToInterfaceType(Req.getConstraintRepr());
|
|
Requirement ConvertedRequirement(RequirementKind::Conformance, Subject,
|
|
Constraint);
|
|
To.push_back(ConvertedRequirement);
|
|
continue;
|
|
}
|
|
|
|
if (Req.getKind() == RequirementReprKind::LayoutConstraint) {
|
|
auto Subject = ResolveToInterfaceType(Req.getSubjectRepr());
|
|
Requirement ConvertedRequirement(RequirementKind::Layout, Subject,
|
|
Req.getLayoutConstraint());
|
|
To.push_back(ConvertedRequirement);
|
|
|
|
if (auto *attributedTy =
|
|
dyn_cast<AttributedTypeRepr>(Req.getSubjectRepr())) {
|
|
if (attributedTy->has(TypeAttrKind::NoMetadata)) {
|
|
typeErasedParams.push_back(Subject);
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
llvm_unreachable("Unsupported requirement kind");
|
|
}
|
|
}
|
|
|
|
static bool parseDeclSILOptional(
|
|
bool *isTransparent, SerializedKind_t *serializedKind, bool *isCanonical,
|
|
bool *hasOwnershipSSA, IsThunk_t *isThunk,
|
|
IsDynamicallyReplaceable_t *isDynamic, IsDistributed_t *isDistributed,
|
|
IsRuntimeAccessible_t *isRuntimeAccessible,
|
|
ForceEnableLexicalLifetimes_t *forceEnableLexicalLifetimes,
|
|
UseStackForPackMetadata_t *useStackForPackMetadata,
|
|
bool *hasUnsafeNonEscapableResult, IsExactSelfClass_t *isExactSelfClass,
|
|
SILFunction **dynamicallyReplacedFunction,
|
|
SILFunction **usedAdHocRequirementWitness, Identifier *objCReplacementFor,
|
|
SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy,
|
|
OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints,
|
|
bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *asmName,
|
|
StringRef *section,
|
|
bool *isLet, bool *isWeakImported, bool *needStackProtection,
|
|
bool *isSpecialized, AvailabilityRange *availability,
|
|
bool *isWithoutActuallyEscapingThunk,
|
|
SmallVectorImpl<std::string> *Semantics,
|
|
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs, ValueDecl **ClangDecl,
|
|
EffectsKind *MRK, ActorIsolation *actorIsolation, SILParser &SP,
|
|
SILModule &M) {
|
|
while (SP.P.consumeIf(tok::l_square)) {
|
|
if (isLet && SP.P.Tok.is(tok::kw_let)) {
|
|
*isLet = true;
|
|
SP.P.consumeToken(tok::kw_let);
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
}
|
|
else if (SP.P.Tok.isNot(tok::identifier)) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
} else if (isTransparent && SP.P.Tok.getText() == "transparent")
|
|
*isTransparent = true;
|
|
else if (serializedKind && SP.P.Tok.getText() == "serialized")
|
|
*serializedKind = IsSerialized;
|
|
else if (serializedKind && SP.P.Tok.getText() == "serialized_for_package")
|
|
*serializedKind = IsSerializedForPackage;
|
|
else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable")
|
|
*isDynamic = IsDynamic;
|
|
else if (isDistributed && SP.P.Tok.getText() == "distributed")
|
|
*isDistributed = IsDistributed;
|
|
else if (isRuntimeAccessible && SP.P.Tok.getText() == "runtime_accessible")
|
|
*isRuntimeAccessible = IsRuntimeAccessible;
|
|
else if (forceEnableLexicalLifetimes &&
|
|
SP.P.Tok.getText() == "lexical_lifetimes")
|
|
*forceEnableLexicalLifetimes = DoForceEnableLexicalLifetimes;
|
|
else if (useStackForPackMetadata &&
|
|
SP.P.Tok.getText() == "no_onstack_pack_metadata")
|
|
*useStackForPackMetadata = DoNotUseStackForPackMetadata;
|
|
else if (hasUnsafeNonEscapableResult &&
|
|
SP.P.Tok.getText() == "unsafe_nonescapable_result")
|
|
*hasUnsafeNonEscapableResult = hasUnsafeNonEscapableResult;
|
|
else if (isExactSelfClass && SP.P.Tok.getText() == "exact_self_class")
|
|
*isExactSelfClass = IsExactSelfClass;
|
|
else if (isCanonical && SP.P.Tok.getText() == "canonical")
|
|
*isCanonical = true;
|
|
else if (hasOwnershipSSA && SP.P.Tok.getText() == "ossa")
|
|
*hasOwnershipSSA = true;
|
|
else if (needStackProtection && SP.P.Tok.getText() == "stack_protection")
|
|
*needStackProtection = true;
|
|
else if (isSpecialized && SP.P.Tok.getText() == "specialized")
|
|
*isSpecialized = true;
|
|
else if (isThunk && SP.P.Tok.getText() == "thunk")
|
|
*isThunk = IsThunk;
|
|
else if (isThunk && SP.P.Tok.getText() == "signature_optimized_thunk")
|
|
*isThunk = IsSignatureOptimizedThunk;
|
|
else if (isThunk && SP.P.Tok.getText() == "reabstraction_thunk")
|
|
*isThunk = IsReabstractionThunk;
|
|
else if (isThunk && SP.P.Tok.getText() == "back_deployed_thunk")
|
|
*isThunk = IsBackDeployedThunk;
|
|
else if (isWithoutActuallyEscapingThunk
|
|
&& SP.P.Tok.getText() == "without_actually_escaping")
|
|
*isWithoutActuallyEscapingThunk = true;
|
|
else if (specialPurpose && SP.P.Tok.getText() == "global_init")
|
|
*specialPurpose = SILFunction::Purpose::GlobalInit;
|
|
else if (specialPurpose && SP.P.Tok.getText() == "lazy_getter")
|
|
*specialPurpose = SILFunction::Purpose::LazyPropertyGetter;
|
|
else if (specialPurpose && SP.P.Tok.getText() == "global_init_once_fn")
|
|
*specialPurpose = SILFunction::Purpose::GlobalInitOnceFunction;
|
|
else if (isWeakImported && SP.P.Tok.getText() == "weak_imported") {
|
|
if (M.getASTContext().LangOpts.Target.isOSBinFormatCOFF())
|
|
SP.P.diagnose(SP.P.Tok, diag::attr_name_unsupported_on_target,
|
|
SP.P.Tok.getText(),
|
|
M.getASTContext().LangOpts.Target.str());
|
|
else
|
|
*isWeakImported = true;
|
|
} else if (availability && SP.P.Tok.getText() == "available") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
|
|
SourceRange range;
|
|
llvm::VersionTuple version;
|
|
if (SP.P.parseVersionTuple(version, range,
|
|
diag::sil_availability_expected_version))
|
|
return true;
|
|
|
|
*availability = AvailabilityRange(version);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (inlineStrategy && SP.P.Tok.getText() == "noinline")
|
|
*inlineStrategy = NoInline;
|
|
else if (optimizationMode && SP.P.Tok.getText() == "Onone")
|
|
*optimizationMode = OptimizationMode::NoOptimization;
|
|
else if (optimizationMode && SP.P.Tok.getText() == "Ospeed")
|
|
*optimizationMode = OptimizationMode::ForSpeed;
|
|
else if (optimizationMode && SP.P.Tok.getText() == "Osize")
|
|
*optimizationMode = OptimizationMode::ForSize;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "no_locks")
|
|
*perfConstraints = PerformanceConstraints::NoLocks;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "no_allocation")
|
|
*perfConstraints = PerformanceConstraints::NoAllocation;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "no_runtime")
|
|
*perfConstraints = PerformanceConstraints::NoRuntime;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "no_existentials")
|
|
*perfConstraints = PerformanceConstraints::NoExistentials;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "no_objc_bridging")
|
|
*perfConstraints = PerformanceConstraints::NoObjCBridging;
|
|
else if (perfConstraints && SP.P.Tok.getText() == "manual_ownership")
|
|
*perfConstraints = PerformanceConstraints::ManualOwnership;
|
|
else if (isPerformanceConstraint && SP.P.Tok.getText() == "perf_constraint")
|
|
*isPerformanceConstraint = true;
|
|
else if (markedAsUsed && SP.P.Tok.getText() == "used")
|
|
*markedAsUsed = true;
|
|
else if (actorIsolation && SP.P.Tok.getText() == "isolation") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
|
|
// TODO: By using a raw string here, we can perhaps put in a simple string
|
|
// representation of an actor that can be parsed back. For now this is
|
|
// just a quick hack so we can write tests.
|
|
auto optIsolation = ActorIsolation::forSILString(
|
|
SP.P.Context.getIdentifier(rawString).str());
|
|
if (!optIsolation) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
*actorIsolation = *optIsolation;
|
|
SP.P.consumeToken(tok::string_literal);
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (asmName && SP.P.Tok.getText() == "asmname") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
|
|
// Drop the double quotes.
|
|
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
|
|
*asmName = SP.P.Context.getIdentifier(rawString).str();
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (section && SP.P.Tok.getText() == "section") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
|
|
// Drop the double quotes.
|
|
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
|
|
*section = SP.P.Context.getIdentifier(rawString).str();
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (inlineStrategy && SP.P.Tok.getText() == "heuristic_always_inline")
|
|
*inlineStrategy = HeuristicAlwaysInline;
|
|
else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
|
|
*inlineStrategy = AlwaysInline;
|
|
else if (MRK && SP.P.Tok.getText() == "readnone")
|
|
*MRK = EffectsKind::ReadNone;
|
|
else if (MRK && SP.P.Tok.getText() == "readonly")
|
|
*MRK = EffectsKind::ReadOnly;
|
|
else if (MRK && SP.P.Tok.getText() == "readwrite")
|
|
*MRK = EffectsKind::ReadWrite;
|
|
else if (MRK && SP.P.Tok.getText() == "releasenone")
|
|
*MRK = EffectsKind::ReleaseNone;
|
|
else if (dynamicallyReplacedFunction && SP.P.Tok.getText() == "dynamic_replacement_for") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back();
|
|
SILFunction *Func = M.lookUpFunction(replacedFunc.str());
|
|
if (!Func) {
|
|
Identifier Id = SP.P.Context.getIdentifier(replacedFunc);
|
|
SP.P.diagnose(SP.P.Tok, diag::sil_dynamically_replaced_func_not_found,
|
|
Id);
|
|
return true;
|
|
}
|
|
*dynamicallyReplacedFunction = Func;
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (usedAdHocRequirementWitness && SP.P.Tok.getText() == "ref_adhoc_requirement_witness") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
StringRef witnessFunc = SP.P.Tok.getText().drop_front().drop_back();
|
|
SILFunction *Func = M.lookUpFunction(witnessFunc.str());
|
|
if (!Func) {
|
|
Identifier Id = SP.P.Context.getIdentifier(witnessFunc);
|
|
SP.P.diagnose(SP.P.Tok, diag::sil_adhoc_requirement_witness_func_not_found,
|
|
Id);
|
|
return true;
|
|
}
|
|
*usedAdHocRequirementWitness = Func;
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (objCReplacementFor &&
|
|
SP.P.Tok.getText() == "objc_replacement_for") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
StringRef replacedFunc = SP.P.Tok.getText().drop_front().drop_back();
|
|
*objCReplacementFor = SP.P.Context.getIdentifier(replacedFunc);
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (Semantics && SP.P.Tok.getText() == "_semantics") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.P.Tok.getKind() != tok::string_literal) {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
|
|
// Drop the double quotes.
|
|
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
|
|
Semantics->push_back(rawString.str());
|
|
SP.P.consumeToken(tok::string_literal);
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else if (SpecAttrs && SP.P.Tok.getText() == "_specialize") {
|
|
SourceLoc AtLoc = SP.P.Tok.getLoc();
|
|
SourceLoc Loc(AtLoc);
|
|
|
|
// Parse a _specialized attribute, building a parsed substitution list
|
|
// and pushing a new ParsedSpecAttr on the SpecAttrs list. Conformances
|
|
// cannot be generated until the function declaration is fully parsed so
|
|
// that the function's generic signature can be consulted.
|
|
ParsedSpecAttr SpecAttr;
|
|
SpecAttr.requirements = {};
|
|
SpecAttr.exported = false;
|
|
SpecAttr.kind = SILSpecializeAttr::SpecializationKind::Full;
|
|
AbstractSpecializeAttr *Attr;
|
|
StringRef targetFunctionName;
|
|
ModuleDecl *module = nullptr;
|
|
bool isPublic = false; // In SIL we don't care to disambiguate @specialize
|
|
// and @_specialize. We use the "more permissive"
|
|
// non-public version when parsing SIL.
|
|
AvailabilityRange availability = AvailabilityRange::alwaysAvailable();
|
|
if (!SP.P.parseSpecializeAttribute(
|
|
tok::r_square, AtLoc, Loc, isPublic, Attr, &availability,
|
|
[&targetFunctionName](Parser &P) -> bool {
|
|
if (P.Tok.getKind() != tok::string_literal) {
|
|
P.diagnose(P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
targetFunctionName = P.Tok.getText().drop_front().drop_back();
|
|
|
|
P.consumeToken(tok::string_literal);
|
|
return true;
|
|
},
|
|
[&module](Parser &P) -> bool {
|
|
if (P.Tok.getKind() != tok::identifier) {
|
|
P.diagnose(P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
auto ident = P.Context.getIdentifier(P.Tok.getText());
|
|
module = P.Context.getModuleByIdentifier(ident);
|
|
assert(module);
|
|
P.consumeToken();
|
|
return true;
|
|
}))
|
|
return true;
|
|
SILFunction *targetFunction = nullptr;
|
|
if (!targetFunctionName.empty()) {
|
|
targetFunction = M.lookUpFunction(targetFunctionName.str());
|
|
if (!targetFunction) {
|
|
Identifier Id = SP.P.Context.getIdentifier(targetFunctionName);
|
|
SP.P.diagnose(SP.P.Tok, diag::sil_specialize_target_func_not_found,
|
|
Id);
|
|
return true;
|
|
}
|
|
}
|
|
// Convert SpecializeAttr into ParsedSpecAttr.
|
|
SpecAttr.requirements = Attr->getTrailingWhereClause()->getRequirements();
|
|
SpecAttr.kind = Attr->getSpecializationKind() ==
|
|
swift::SpecializeAttr::SpecializationKind::Full
|
|
? SILSpecializeAttr::SpecializationKind::Full
|
|
: SILSpecializeAttr::SpecializationKind::Partial;
|
|
SpecAttr.exported = Attr->isExported();
|
|
SpecAttr.target = targetFunction;
|
|
SpecAttr.availability = availability;
|
|
SpecAttrs->emplace_back(SpecAttr);
|
|
if (!Attr->getSPIGroups().empty()) {
|
|
SpecAttr.spiGroupID = Attr->getSPIGroups()[0];
|
|
}
|
|
continue;
|
|
}
|
|
else if (ClangDecl && SP.P.Tok.getText() == "clang") {
|
|
SP.P.consumeToken(tok::identifier);
|
|
if (SP.parseSILDottedPathWithoutPound(*ClangDecl))
|
|
return true;
|
|
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
continue;
|
|
} else {
|
|
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
SP.P.consumeToken(tok::identifier);
|
|
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Type SILParser::performTypeResolution(TypeRepr *TyR, bool IsSILType,
|
|
GenericSignature GenericSig,
|
|
GenericParamList *GenericParams) {
|
|
if (!GenericSig)
|
|
GenericSig = ContextGenericSig;
|
|
|
|
SILTypeResolutionContext SILContext(IsSILType, GenericParams,
|
|
&OpenedPackElements);
|
|
|
|
return swift::performTypeResolution(TyR, P.Context, GenericSig,
|
|
&SILContext, &P.SF);
|
|
}
|
|
|
|
/// Find the top-level ValueDecl or Module given a name.
|
|
static llvm::PointerUnion<ValueDecl *, ModuleDecl *>
|
|
lookupTopDecl(Parser &P, DeclBaseName Name, bool typeLookup) {
|
|
// Use UnqualifiedLookup to look through all of the imports.
|
|
UnqualifiedLookupOptions options;
|
|
if (typeLookup)
|
|
options |= UnqualifiedLookupFlags::TypeLookup;
|
|
|
|
auto &ctx = P.SF.getASTContext();
|
|
auto descriptor = UnqualifiedLookupDescriptor(DeclNameRef(Name), &P.SF);
|
|
auto lookup = evaluateOrDefault(ctx.evaluator,
|
|
UnqualifiedLookupRequest{descriptor}, {});
|
|
lookup.filter([](LookupResultEntry entry, bool isOuter) -> bool {
|
|
return !isa<MacroDecl>(entry.getValueDecl());
|
|
});
|
|
|
|
assert(lookup.size() == 1);
|
|
|
|
return lookup.back().getValueDecl();
|
|
}
|
|
|
|
/// Find the ValueDecl given an interface type and a member name.
|
|
static ValueDecl *lookupMember(Parser &P, Type Ty, DeclBaseName Name,
|
|
SourceLoc Loc,
|
|
SmallVectorImpl<ValueDecl *> &Lookup,
|
|
bool ExpectMultipleResults) {
|
|
Type CheckTy = Ty;
|
|
if (auto MetaTy = CheckTy->getAs<AnyMetatypeType>())
|
|
CheckTy = MetaTy->getInstanceType();
|
|
|
|
if (auto nominal = CheckTy->getAnyNominal()) {
|
|
if (Name == DeclBaseName::createDestructor() &&
|
|
isa<ClassDecl>(nominal)) {
|
|
auto *classDecl = cast<ClassDecl>(nominal);
|
|
Lookup.push_back(classDecl->getDestructor());
|
|
} else {
|
|
auto found = nominal->lookupDirect(Name);
|
|
Lookup.append(found.begin(), found.end());
|
|
}
|
|
} else if (auto moduleTy = CheckTy->getAs<ModuleType>()) {
|
|
moduleTy->getModule()->lookupValue(Name, NLKind::QualifiedLookup, Lookup);
|
|
} else {
|
|
P.diagnose(Loc, diag::sil_member_lookup_bad_type, Name, Ty);
|
|
return nullptr;
|
|
}
|
|
|
|
if (Lookup.empty() || (!ExpectMultipleResults && Lookup.size() != 1)) {
|
|
P.diagnose(Loc, diag::sil_named_member_decl_not_found, Name, Ty);
|
|
return nullptr;
|
|
}
|
|
return Lookup[0];
|
|
}
|
|
|
|
bool SILParser::parseASTType(CanType &result,
|
|
GenericSignature genericSig,
|
|
GenericParamList *genericParams,
|
|
bool forceContextualType) {
|
|
ParserResult<TypeRepr> parsedType = P.parseType();
|
|
if (parsedType.isNull()) return true;
|
|
|
|
// If we weren't given a specific generic context to resolve the type
|
|
// within, use the contextual generic parameters and always produce
|
|
// a contextual type. Otherwise, produce a contextual type only if
|
|
// we were asked for one.
|
|
bool wantContextualType = forceContextualType;
|
|
if (!genericSig) {
|
|
genericSig = ContextGenericSig;
|
|
wantContextualType = true;
|
|
}
|
|
if (genericParams == nullptr)
|
|
genericParams = ContextGenericParams;
|
|
|
|
bindSILGenericParams(parsedType.get());
|
|
|
|
auto resolvedType = performTypeResolution(
|
|
parsedType.get(), /*isSILType=*/false, genericSig, genericParams);
|
|
if (wantContextualType && genericSig) {
|
|
resolvedType = genericSig.getGenericEnvironment()
|
|
->mapTypeIntoContext(resolvedType);
|
|
}
|
|
|
|
if (resolvedType->hasError())
|
|
return true;
|
|
|
|
result = resolvedType->getCanonicalType();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseASTTypeOrValue(CanType &result,
|
|
GenericSignature genericSig,
|
|
GenericParamList *genericParams,
|
|
bool forceContextualType) {
|
|
auto parsedType = P.parseTypeOrValue();
|
|
if (parsedType.isNull()) return true;
|
|
|
|
// If we weren't given a specific generic context to resolve the type
|
|
// within, use the contextual generic parameters and always produce
|
|
// a contextual type. Otherwise, produce a contextual type only if
|
|
// we were asked for one.
|
|
bool wantContextualType = forceContextualType;
|
|
if (!genericSig) {
|
|
genericSig = ContextGenericSig;
|
|
wantContextualType = true;
|
|
}
|
|
if (genericParams == nullptr)
|
|
genericParams = ContextGenericParams;
|
|
|
|
bindSILGenericParams(parsedType.get());
|
|
|
|
auto resolvedType = performTypeResolution(
|
|
parsedType.get(), /*isSILType=*/false, genericSig, genericParams);
|
|
if (wantContextualType && genericSig) {
|
|
resolvedType = genericSig.getGenericEnvironment()
|
|
->mapTypeIntoContext(resolvedType);
|
|
}
|
|
|
|
if (resolvedType->hasError())
|
|
return true;
|
|
|
|
result = resolvedType->getCanonicalType();
|
|
|
|
return false;
|
|
}
|
|
|
|
void SILParser::bindSILGenericParams(TypeRepr *TyR) {
|
|
// Resolve the generic environments for parsed generic function and box types.
|
|
class HandleSILGenericParamsWalker : public ASTWalker {
|
|
SourceFile *SF;
|
|
|
|
public:
|
|
HandleSILGenericParamsWalker(SourceFile *SF) : SF(SF) {}
|
|
|
|
/// Walk everything in a macro
|
|
MacroWalking getMacroWalkingBehavior() const override {
|
|
return MacroWalking::ArgumentsAndExpansion;
|
|
}
|
|
|
|
PreWalkAction walkToTypeReprPre(TypeRepr *T) override {
|
|
if (auto fnType = dyn_cast<FunctionTypeRepr>(T)) {
|
|
if (auto *genericParams = fnType->getGenericParams()) {
|
|
auto sig = handleSILGenericParams(genericParams, SF);
|
|
fnType->setGenericSignature(sig);
|
|
}
|
|
|
|
if (auto *genericParams = fnType->getPatternGenericParams()) {
|
|
auto sig = handleSILGenericParams(genericParams, SF,
|
|
/*allowInverses=*/false);
|
|
fnType->setPatternGenericSignature(sig);
|
|
}
|
|
}
|
|
|
|
if (auto boxType = dyn_cast<SILBoxTypeRepr>(T)) {
|
|
if (auto *genericParams = boxType->getGenericParams()) {
|
|
auto sig = handleSILGenericParams(genericParams, SF);
|
|
boxType->setGenericSignature(sig);
|
|
}
|
|
}
|
|
|
|
return Action::Continue();
|
|
}
|
|
};
|
|
|
|
TyR->walk(HandleSILGenericParamsWalker(&P.SF));
|
|
}
|
|
|
|
/// sil-type:
|
|
/// '$' '*'? attribute-list (generic-params)? type
|
|
///
|
|
bool SILParser::parseSILType(SILType &Result,
|
|
GenericSignature &ParsedGenericSig,
|
|
GenericParamList *&ParsedGenericParams,
|
|
bool IsFuncDecl,
|
|
GenericSignature OuterGenericSig,
|
|
GenericParamList *OuterGenericParams) {
|
|
ParsedGenericSig = GenericSignature();
|
|
ParsedGenericParams = nullptr;
|
|
|
|
if (!OuterGenericSig)
|
|
OuterGenericSig = ContextGenericSig;
|
|
if (OuterGenericParams == nullptr)
|
|
OuterGenericParams = ContextGenericParams;
|
|
|
|
if (P.parseToken(tok::sil_dollar, diag::expected_sil_type))
|
|
return true;
|
|
|
|
// If we have a '*', then this is an address type.
|
|
SILValueCategory category = SILValueCategory::Object;
|
|
if (P.Tok.isAnyOperator() && P.Tok.getText().starts_with("*")) {
|
|
category = SILValueCategory::Address;
|
|
P.consumeStartingCharacterOfCurrentToken();
|
|
}
|
|
|
|
// Parse attributes.
|
|
Parser::ParsedTypeAttributeList parsedAttrs(
|
|
Parser::ParseTypeReason::Unspecified);
|
|
parsedAttrs.parse(P);
|
|
|
|
// Global functions are implicitly @convention(thin) if not specified otherwise.
|
|
if (IsFuncDecl && !llvm::any_of(parsedAttrs.Attributes,
|
|
[](TypeOrCustomAttr attr) {
|
|
if (auto typeAttr = attr.dyn_cast<TypeAttribute*>())
|
|
return isa<ConventionTypeAttr>(typeAttr);
|
|
return false;
|
|
})) {
|
|
// Use a random location.
|
|
auto loc = P.PreviousLoc;
|
|
parsedAttrs.Attributes.push_back(
|
|
new (P.Context) ConventionTypeAttr(loc, loc, {loc, loc},
|
|
{"thin", loc}, DeclNameRef(), {}));
|
|
}
|
|
|
|
ParserResult<TypeRepr> TyR = P.parseType(diag::expected_sil_type);
|
|
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
bindSILGenericParams(TyR.get());
|
|
|
|
// Apply attributes to the type.
|
|
auto *attrRepr = parsedAttrs.applyAttributesToType(P, TyR.get());
|
|
auto Ty = performTypeResolution(attrRepr, /*IsSILType=*/true, OuterGenericSig,
|
|
OuterGenericParams);
|
|
if (OuterGenericSig) {
|
|
Ty = OuterGenericSig.getGenericEnvironment()->mapTypeIntoContext(Ty);
|
|
}
|
|
|
|
if (Ty->hasError())
|
|
return true;
|
|
|
|
// Save the top-level function generic environment if there was one.
|
|
if (auto fnType = dyn_cast<FunctionTypeRepr>(TyR.get())) {
|
|
if (auto genericSig = fnType->getGenericSignature())
|
|
ParsedGenericSig = genericSig;
|
|
if (auto *genericParams = fnType->getGenericParams())
|
|
ParsedGenericParams = genericParams;
|
|
}
|
|
|
|
Result = SILType::getPrimitiveType(Ty->getCanonicalType(),
|
|
category);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseSILDottedPath(ValueDecl *&Decl,
|
|
SmallVectorImpl<ValueDecl *> &values) {
|
|
if (P.parseToken(tok::pound, diag::expected_sil_constant))
|
|
return true;
|
|
return parseSILDottedPathWithoutPound(Decl, values);
|
|
}
|
|
|
|
bool SILParser::parseSILDottedPathWithoutPound(ValueDecl *&Decl,
|
|
SmallVectorImpl<ValueDecl *> &values) {
|
|
// Handle sil-dotted-path.
|
|
Identifier Id;
|
|
SmallVector<DeclBaseName, 4> FullName;
|
|
SmallVector<SourceLoc, 4> Locs;
|
|
do {
|
|
Locs.push_back(P.Tok.getLoc());
|
|
switch (P.Tok.getKind()) {
|
|
case tok::kw_subscript:
|
|
P.consumeToken();
|
|
FullName.push_back(DeclBaseName::createSubscript());
|
|
break;
|
|
case tok::kw_init:
|
|
P.consumeToken();
|
|
FullName.push_back(DeclBaseName::createConstructor());
|
|
break;
|
|
case tok::kw_deinit:
|
|
P.consumeToken();
|
|
FullName.push_back(DeclBaseName::createDestructor());
|
|
break;
|
|
default:
|
|
if (parseSILIdentifier(Id, diag::expected_sil_constant))
|
|
return true;
|
|
FullName.push_back(Id);
|
|
break;
|
|
}
|
|
} while (P.consumeIf(tok::period));
|
|
|
|
// Look up ValueDecl from a dotted path. If there are multiple components,
|
|
// the first one must be a type declaration.
|
|
ValueDecl *VD;
|
|
llvm::PointerUnion<ValueDecl*, ModuleDecl *> Res = lookupTopDecl(
|
|
P, FullName[0], /*typeLookup=*/FullName.size() > 1);
|
|
// It is possible that the last member lookup can return multiple lookup
|
|
// results. One example is the overloaded member functions.
|
|
if (isa<ModuleDecl *>(Res)) {
|
|
assert(FullName.size() > 1 &&
|
|
"A single module is not a full path to SILDeclRef");
|
|
auto Mod = cast<ModuleDecl *>(Res);
|
|
values.clear();
|
|
VD = lookupMember(P, ModuleType::get(Mod), FullName[1], Locs[1], values,
|
|
FullName.size() == 2/*ExpectMultipleResults*/);
|
|
for (unsigned I = 2, E = FullName.size(); I < E; ++I) {
|
|
values.clear();
|
|
VD = lookupMember(P, VD->getInterfaceType(), FullName[I], Locs[I], values,
|
|
I == FullName.size() - 1/*ExpectMultipleResults*/);
|
|
}
|
|
} else {
|
|
VD = cast<ValueDecl *>(Res);
|
|
for (unsigned I = 1, E = FullName.size(); I < E; ++I) {
|
|
values.clear();
|
|
VD = lookupMember(P, VD->getInterfaceType(), FullName[I], Locs[I], values,
|
|
I == FullName.size() - 1/*ExpectMultipleResults*/);
|
|
}
|
|
}
|
|
Decl = VD;
|
|
return false;
|
|
}
|
|
|
|
static std::optional<AccessorKind> getAccessorKind(StringRef ident) {
|
|
return llvm::StringSwitch<std::optional<AccessorKind>>(ident)
|
|
.Case("getter", AccessorKind::Get)
|
|
.Case("setter", AccessorKind::Set)
|
|
.Case("addressor", AccessorKind::Address)
|
|
.Case("mutableAddressor", AccessorKind::MutableAddress)
|
|
.Case("read", AccessorKind::Read)
|
|
.Case("read2", AccessorKind::Read2)
|
|
.Case("modify", AccessorKind::Modify)
|
|
.Case("modify2", AccessorKind::Modify2)
|
|
.Default(std::nullopt);
|
|
}
|
|
|
|
/// sil-decl-ref ::= '#' sil-identifier ('.' sil-identifier)* sil-decl-subref?
|
|
/// sil-decl-subref ::= '!' sil-decl-subref-part ('.' sil-decl-lang)?
|
|
/// ('.' sil-decl-autodiff)?
|
|
/// sil-decl-subref ::= '!' sil-decl-lang
|
|
/// sil-decl-subref ::= '!' sil-decl-autodiff
|
|
/// sil-decl-subref-part ::= 'getter'
|
|
/// sil-decl-subref-part ::= 'setter'
|
|
/// sil-decl-subref-part ::= 'allocator'
|
|
/// sil-decl-subref-part ::= 'initializer'
|
|
/// sil-decl-subref-part ::= 'enumelt'
|
|
/// sil-decl-subref-part ::= 'destroyer'
|
|
/// sil-decl-subref-part ::= 'globalaccessor'
|
|
/// sil-decl-lang ::= 'foreign'
|
|
/// sil-decl-autodiff ::= sil-decl-autodiff-kind '.' sil-decl-autodiff-indices
|
|
/// sil-decl-autodiff-kind ::= 'jvp'
|
|
/// sil-decl-autodiff-kind ::= 'vjp'
|
|
/// sil-decl-autodiff-indices ::= [SU]+
|
|
bool SILParser::parseSILDeclRef(SILDeclRef &Result,
|
|
SmallVectorImpl<ValueDecl *> &values) {
|
|
ValueDecl *VD;
|
|
if (parseSILDottedPath(VD, values))
|
|
return true;
|
|
|
|
// Initialize SILDeclRef components.
|
|
SILDeclRef::Kind Kind = SILDeclRef::Kind::Func;
|
|
bool IsObjC = false;
|
|
AutoDiffDerivativeFunctionIdentifier *DerivativeId = nullptr;
|
|
|
|
if (!P.consumeIf(tok::sil_exclamation)) {
|
|
// Construct SILDeclRef.
|
|
Result = SILDeclRef(VD, Kind, IsObjC,
|
|
/*distributed=*/false, /*knownToBeLocal=*/false,
|
|
/*runtimeAccessible=*/false,
|
|
SILDeclRef::BackDeploymentKind::None, DerivativeId);
|
|
return false;
|
|
}
|
|
|
|
// Handle SILDeclRef components. ParseState tracks the last parsed component.
|
|
//
|
|
// When ParseState is 0, accept kind (`func|getter|setter|...`) and set
|
|
// ParseState to 1.
|
|
//
|
|
// Always accept `foreign` and derivative function identifier.
|
|
unsigned ParseState = 0;
|
|
Identifier Id;
|
|
do {
|
|
if (P.Tok.is(tok::identifier)) {
|
|
auto IdLoc = P.Tok.getLoc();
|
|
if (parseSILIdentifier(Id, diag::expected_sil_constant))
|
|
return true;
|
|
std::optional<AccessorKind> accessorKind;
|
|
if (!ParseState && Id.str() == "func") {
|
|
Kind = SILDeclRef::Kind::Func;
|
|
ParseState = 1;
|
|
} else if (!ParseState &&
|
|
(accessorKind = getAccessorKind(Id.str())).has_value()) {
|
|
// Drill down to the corresponding accessor for each declaration,
|
|
// compacting away decls that lack it.
|
|
size_t destI = 0;
|
|
for (size_t srcI = 0, e = values.size(); srcI != e; ++srcI) {
|
|
if (auto storage = dyn_cast<AbstractStorageDecl>(values[srcI]))
|
|
if (auto accessor = storage->getOpaqueAccessor(*accessorKind))
|
|
values[destI++] = accessor;
|
|
}
|
|
values.resize(destI);
|
|
|
|
// Complain if none of the decls had a corresponding accessor.
|
|
if (destI == 0) {
|
|
P.diagnose(IdLoc, diag::referenced_value_no_accessor, 0);
|
|
return true;
|
|
}
|
|
|
|
Kind = SILDeclRef::Kind::Func;
|
|
VD = values[0];
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "allocator") {
|
|
Kind = SILDeclRef::Kind::Allocator;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "initializer") {
|
|
Kind = SILDeclRef::Kind::Initializer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "enumelt") {
|
|
Kind = SILDeclRef::Kind::EnumElement;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "destroyer") {
|
|
Kind = SILDeclRef::Kind::Destroyer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "deallocator") {
|
|
Kind = SILDeclRef::Kind::Deallocator;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "isolateddeallocator") {
|
|
Kind = SILDeclRef::Kind::IsolatedDeallocator;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "globalaccessor") {
|
|
Kind = SILDeclRef::Kind::GlobalAccessor;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "ivardestroyer") {
|
|
Kind = SILDeclRef::Kind::IVarDestroyer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "ivarinitializer") {
|
|
Kind = SILDeclRef::Kind::IVarInitializer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "defaultarg") {
|
|
Kind = SILDeclRef::Kind::IVarInitializer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "propertyinit") {
|
|
Kind = SILDeclRef::Kind::StoredPropertyInitializer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "backinginit") {
|
|
Kind = SILDeclRef::Kind::PropertyWrapperBackingInitializer;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "wrappedfieldinitaccessor") {
|
|
Kind = SILDeclRef::Kind::PropertyWrappedFieldInitAccessor;
|
|
ParseState = 1;
|
|
} else if (!ParseState && Id.str() == "projectedvalueinit") {
|
|
Kind = SILDeclRef::Kind::PropertyWrapperInitFromProjectedValue;
|
|
ParseState = 1;
|
|
} else if (Id.str() == "foreign") {
|
|
IsObjC = true;
|
|
break;
|
|
} else if (Id.str() == "jvp" || Id.str() == "vjp") {
|
|
IndexSubset *parameterIndices = nullptr;
|
|
GenericSignature derivativeGenSig;
|
|
// Parse derivative function kind.
|
|
AutoDiffDerivativeFunctionKind derivativeKind(Id.str());
|
|
if (!P.consumeIf(tok::period)) {
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ".");
|
|
return true;
|
|
}
|
|
// Parse parameter indices.
|
|
parameterIndices =
|
|
IndexSubset::getFromString(SILMod.getASTContext(), P.Tok.getText());
|
|
if (!parameterIndices) {
|
|
P.diagnose(P.Tok, diag::invalid_index_subset);
|
|
return true;
|
|
}
|
|
P.consumeToken();
|
|
// Parse derivative generic signature (optional).
|
|
if (P.Tok.is(tok::oper_binary_unspaced) && P.Tok.getText() == ".<") {
|
|
P.consumeStartingCharacterOfCurrentToken(tok::period);
|
|
// Create a new scope to avoid type redefinition errors.
|
|
auto *genericParams = P.maybeParseGenericParams().getPtrOrNull();
|
|
assert(genericParams);
|
|
derivativeGenSig = handleSILGenericParams(genericParams, &P.SF);
|
|
}
|
|
DerivativeId = AutoDiffDerivativeFunctionIdentifier::get(
|
|
derivativeKind, parameterIndices, derivativeGenSig,
|
|
SILMod.getASTContext());
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
} else
|
|
break;
|
|
|
|
} while (P.consumeIf(tok::period));
|
|
|
|
// Construct SILDeclRef.
|
|
Result = SILDeclRef(VD, Kind, IsObjC,
|
|
/*distributed=*/false, /*knownToBeLocal=*/false,
|
|
/*runtimeAccessible=*/false,
|
|
SILDeclRef::BackDeploymentKind::None, DerivativeId);
|
|
return false;
|
|
}
|
|
|
|
/// parseValueName - Parse a value name without a type available yet.
|
|
///
|
|
/// sil-value-name:
|
|
/// sil-local-name
|
|
/// 'undef'
|
|
///
|
|
bool SILParser::parseValueName(UnresolvedValueName &Result) {
|
|
Result.Name = P.Tok.getText();
|
|
|
|
if (P.Tok.is(tok::kw_undef)) {
|
|
Result.NameLoc = P.consumeToken(tok::kw_undef);
|
|
return false;
|
|
}
|
|
|
|
// Parse the local-name.
|
|
if (P.parseToken(tok::sil_local_name, Result.NameLoc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// parseValueRef - Parse a value, given a contextual type.
|
|
///
|
|
/// sil-value-ref:
|
|
/// sil-local-name
|
|
///
|
|
bool SILParser::parseValueRef(SILValue &Result, SILType Ty,
|
|
SILLocation Loc, SILBuilder &B) {
|
|
UnresolvedValueName Name;
|
|
if (parseValueName(Name)) return true;
|
|
Result = getLocalValue(Name, Ty, Loc, B);
|
|
return false;
|
|
}
|
|
|
|
/// parseTypedValueRef - Parse a type/value reference pair.
|
|
///
|
|
/// sil-typed-valueref:
|
|
/// sil-value-ref ':' sil-type
|
|
///
|
|
bool SILParser::parseTypedValueRef(SILValue &Result, SourceLoc &Loc,
|
|
SILBuilder &B) {
|
|
Loc = P.Tok.getLoc();
|
|
|
|
UnresolvedValueName Name;
|
|
if (parseValueName(Name))
|
|
return true;
|
|
|
|
if (P.consumeIf(tok::colon)) {
|
|
SILType Ty;
|
|
parseSILType(Ty);
|
|
Result = getLocalValue(Name, Ty, RegularLocation(Loc), B);
|
|
return false;
|
|
} else {
|
|
ValueBase *&Entry = LocalValues[Name.Name];
|
|
if (!Entry) {
|
|
P.diagnose(Name.NameLoc, diag::sil_forward_ref_value_needs_type, Name.Name);
|
|
return true;
|
|
}
|
|
Result = SILValue(Entry);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// Look up whether the given string corresponds to a SIL opcode.
|
|
static std::optional<SILInstructionKind> getOpcodeByName(StringRef OpcodeName) {
|
|
return llvm::StringSwitch<std::optional<SILInstructionKind>>(OpcodeName)
|
|
#define FULL_INST(Id, TextualName, Parent, MemBehavior, MayRelease) \
|
|
.Case(#TextualName, SILInstructionKind::Id)
|
|
#include "swift/SIL/SILNodes.def"
|
|
.Default(std::nullopt);
|
|
}
|
|
|
|
/// getInstructionKind - This method maps the string form of a SIL instruction
|
|
/// opcode to an enum.
|
|
bool SILParser::parseSILOpcode(SILInstructionKind &Opcode, SourceLoc &OpcodeLoc,
|
|
StringRef &OpcodeName) {
|
|
OpcodeLoc = P.Tok.getLoc();
|
|
OpcodeName = P.Tok.getText();
|
|
// Parse this textually to avoid Swift keywords (like 'return') from
|
|
// interfering with opcode recognition.
|
|
auto MaybeOpcode = getOpcodeByName(OpcodeName);
|
|
if (!MaybeOpcode) {
|
|
P.diagnose(OpcodeLoc, diag::expected_sil_instr_opcode);
|
|
return true;
|
|
}
|
|
|
|
Opcode = MaybeOpcode.value();
|
|
P.consumeToken();
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseSILDebugInfoExpression(SILDebugInfoExpression &DIExpr) {
|
|
if (P.Tok.getText() != "expr")
|
|
return true;
|
|
|
|
// All operators that we currently support
|
|
static const SILDIExprOperator AllOps[] = {
|
|
SILDIExprOperator::Dereference,
|
|
SILDIExprOperator::Fragment,
|
|
SILDIExprOperator::Plus,
|
|
SILDIExprOperator::Minus,
|
|
SILDIExprOperator::ConstUInt,
|
|
SILDIExprOperator::ConstSInt,
|
|
SILDIExprOperator::TupleFragment
|
|
};
|
|
|
|
do {
|
|
P.consumeToken();
|
|
bool FoundOp = false;
|
|
auto OpLoc = P.Tok.getLoc();
|
|
for (const auto &Op : AllOps) {
|
|
const auto *ExprInfo = SILDIExprInfo::get(Op);
|
|
auto OpText = ExprInfo->OpText;
|
|
if (OpText != P.Tok.getText())
|
|
continue;
|
|
auto NewOperator = SILDIExprElement::createOperator(Op);
|
|
DIExpr.push_back(NewOperator);
|
|
P.consumeToken();
|
|
|
|
// Ready to parse the operands
|
|
for (const auto &OpKind : ExprInfo->OperandKinds) {
|
|
if (P.parseToken(tok::colon, diag::expected_sil_colon,
|
|
"debug info expression operand"))
|
|
return true;
|
|
|
|
switch (OpKind) {
|
|
case SILDIExprElement::DeclKind: {
|
|
SILDeclRef Result;
|
|
if (parseSILDeclRef(Result) || !Result.hasDecl()) {
|
|
P.diagnose(P.Tok.getLoc(), diag::sil_dbg_expr_expect_operand_kind,
|
|
OpText, "declaration");
|
|
return true;
|
|
}
|
|
auto NewOperand = SILDIExprElement::createDecl(Result.getDecl());
|
|
DIExpr.push_back(NewOperand);
|
|
break;
|
|
}
|
|
case SILDIExprElement::ConstIntKind: {
|
|
bool IsNegative = false;
|
|
if (P.Tok.is(tok::oper_prefix) && P.Tok.getRawText() == "-") {
|
|
P.consumeToken();
|
|
IsNegative = true;
|
|
}
|
|
uint64_t Val;
|
|
if (parseInteger(Val, diag::sil_invalid_constant))
|
|
return true;
|
|
if (IsNegative)
|
|
Val = -Val;
|
|
auto NewOperand =
|
|
SILDIExprElement::createConstInt(static_cast<uint64_t>(Val));
|
|
DIExpr.push_back(NewOperand);
|
|
break;
|
|
}
|
|
case SILDIExprElement::TypeKind: {
|
|
SILType Result;
|
|
if (parseSILType(Result)) {
|
|
P.diagnose(P.Tok.getLoc(), diag::sil_dbg_expr_expect_operand_kind,
|
|
OpText, "type");
|
|
return true;
|
|
}
|
|
auto NewOperand = SILDIExprElement::createType(
|
|
Result.getASTType().getPointer());
|
|
DIExpr.push_back(NewOperand);
|
|
break;
|
|
}
|
|
default:
|
|
P.diagnose(P.Tok.getLoc(), diag::sil_dbg_unknown_expr_part,
|
|
"operand kind");
|
|
return true;
|
|
}
|
|
}
|
|
FoundOp = true;
|
|
break;
|
|
}
|
|
|
|
if (!FoundOp) {
|
|
P.diagnose(OpLoc, diag::sil_dbg_unknown_expr_part, "operator");
|
|
return true;
|
|
}
|
|
} while (P.Tok.is(tok::colon));
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool peekSILDebugLocation(Parser &P) {
|
|
auto T = P.peekToken().getText();
|
|
return P.Tok.is(tok::comma) && (T == "loc" || T == "scope");
|
|
}
|
|
|
|
bool SILParser::parseSILDebugVar(SILDebugVariable &Var) {
|
|
auto parseVariableName = [&, this](bool Consume) -> bool {
|
|
if (Consume)
|
|
P.consumeToken();
|
|
if (P.Tok.getKind() != tok::string_literal) {
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string");
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
StringRef Val = P.Tok.getText().drop_front().drop_back();
|
|
Var.Name = Val;
|
|
return false;
|
|
};
|
|
|
|
while (P.Tok.is(tok::comma) && !peekSILDebugLocation(P)) {
|
|
P.consumeToken();
|
|
StringRef Key = P.Tok.getText();
|
|
bool NoConsume = false;
|
|
if (P.consumeIf(tok::l_paren)) {
|
|
if (parseVerbatim("name"))
|
|
return true;
|
|
if (parseVariableName(/*Consume=*/false))
|
|
return true;
|
|
P.consumeToken();
|
|
|
|
// Optional operands
|
|
if (peekSILDebugLocation(P)) {
|
|
P.consumeToken(tok::comma);
|
|
|
|
bool requireScope = false;
|
|
if (P.Tok.getText() == "loc") {
|
|
SILLocation VarLoc = RegularLocation::getAutoGeneratedLocation();
|
|
if (parseSILLocation(VarLoc))
|
|
return true;
|
|
Var.Loc = VarLoc;
|
|
requireScope = P.consumeIf(tok::comma);
|
|
}
|
|
|
|
if (P.Tok.getText() == "scope" || requireScope) {
|
|
parseVerbatim("scope");
|
|
SILDebugScope *DS = nullptr;
|
|
if (parseScopeRef(DS))
|
|
return true;
|
|
if (DS)
|
|
Var.Scope = DS;
|
|
}
|
|
}
|
|
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
|
|
return true;
|
|
|
|
NoConsume = true;
|
|
} else if (Key == "name") {
|
|
if (parseVariableName(/*Consume=*/true))
|
|
return true;
|
|
} else if (Key == "argno") {
|
|
P.consumeToken();
|
|
if (P.Tok.getKind() != tok::integer_literal) {
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "integer");
|
|
return true;
|
|
}
|
|
uint16_t ArgNo;
|
|
if (parseIntegerLiteral(P.Tok.getText(), 0, ArgNo))
|
|
return true;
|
|
Var.ArgNo = ArgNo;
|
|
} else if (Key == "expr") {
|
|
if (parseSILDebugInfoExpression(Var.DIExpr))
|
|
return true;
|
|
NoConsume = true;
|
|
} else if (Key == "type") {
|
|
// Auxiliary type information
|
|
P.consumeToken();
|
|
SILType Ty;
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
Var.Type = Ty;
|
|
NoConsume = true;
|
|
} else if (Key == "let") {
|
|
Var.Constant = true;
|
|
} else if (Key == "var") {
|
|
Var.Constant = false;
|
|
} else if (Key == "loc") {
|
|
Var.Constant = false;
|
|
} else {
|
|
P.diagnose(P.Tok, diag::sil_dbg_unknown_key, Key);
|
|
return true;
|
|
}
|
|
|
|
if (!NoConsume)
|
|
P.consumeToken();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseSILBBArgsAtBranch(SmallVector<SILValue, 6> &Args,
|
|
SILBuilder &B) {
|
|
if (P.Tok.is(tok::l_paren)) {
|
|
SourceLoc LParenLoc = P.consumeToken(tok::l_paren);
|
|
SourceLoc RParenLoc;
|
|
|
|
bool HasError = false;
|
|
if (P.parseList(tok::r_paren, LParenLoc, RParenLoc,
|
|
/*AllowSepAfterLast=*/false,
|
|
diag::sil_basicblock_arg_rparen,
|
|
[&]() -> ParserStatus {
|
|
SILValue Arg;
|
|
SourceLoc ArgLoc;
|
|
if (parseTypedValueRef(Arg, ArgLoc, B)) {
|
|
HasError = true;
|
|
return makeParserError();
|
|
}
|
|
Args.push_back(Arg);
|
|
return makeParserSuccess();
|
|
}).isErrorOrHasCompletion() || HasError)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Parse the substitution list for an apply instruction or
|
|
/// specialized protocol conformance.
|
|
bool SILParser::parseSubstitutions(SmallVectorImpl<ParsedSubstitution> &parsed,
|
|
GenericSignature GenericSig,
|
|
GenericParamList *GenericParams) {
|
|
// Check for an opening '<' bracket.
|
|
if (!P.startsWithLess(P.Tok))
|
|
return false;
|
|
|
|
if (!GenericSig)
|
|
GenericSig = ContextGenericSig;
|
|
if (GenericParams == nullptr)
|
|
GenericParams = ContextGenericParams;
|
|
|
|
P.consumeStartingLess();
|
|
|
|
// Parse a list of Substitutions.
|
|
do {
|
|
SourceLoc Loc = P.Tok.getLoc();
|
|
|
|
// Parse substitution as AST type.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
auto Ty = performTypeResolution(TyR.get(), /*IsSILType=*/false, GenericSig,
|
|
GenericParams);
|
|
if (GenericSig) {
|
|
Ty = GenericSig.getGenericEnvironment()->mapTypeIntoContext(Ty);
|
|
}
|
|
|
|
if (Ty->hasError())
|
|
return true;
|
|
parsed.push_back({Loc, Ty});
|
|
} while (P.consumeIf(tok::comma));
|
|
|
|
// Consume the closing '>'.
|
|
if (!P.startsWithGreater(P.Tok)) {
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ">");
|
|
return true;
|
|
}
|
|
P.consumeStartingGreater();
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Collect conformances by looking up the conformance from replacement
|
|
/// type and protocol decl.
|
|
static bool getConformancesForSubstitution(Parser &P,
|
|
ArrayRef<ProtocolDecl*> protocols,
|
|
Type subReplacement,
|
|
SourceLoc loc,
|
|
SmallVectorImpl<ProtocolConformanceRef> &conformances) {
|
|
subReplacement = subReplacement->getReferenceStorageReferent();
|
|
|
|
for (auto protoDecl : protocols) {
|
|
auto conformance = lookupConformance(subReplacement, protoDecl);
|
|
if (conformance.isInvalid()) {
|
|
P.diagnose(loc, diag::sil_substitution_mismatch, subReplacement,
|
|
protoDecl->getDeclaredInterfaceType());
|
|
return true;
|
|
}
|
|
conformances.push_back(conformance);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Reconstruct an AST substitution map from parsed substitutions.
|
|
SubstitutionMap getApplySubstitutionsFromParsed(
|
|
SILParser &SP,
|
|
GenericSignature genericSig,
|
|
ArrayRef<ParsedSubstitution> parses) {
|
|
if (parses.empty()) {
|
|
assert(!genericSig);
|
|
return SubstitutionMap();
|
|
}
|
|
|
|
assert(genericSig);
|
|
|
|
auto loc = parses[0].loc;
|
|
|
|
// Ensure that we have the right number of type arguments.
|
|
if (parses.size() != genericSig.getGenericParams().size()) {
|
|
bool hasTooFew = parses.size() < genericSig.getGenericParams().size();
|
|
SP.P.diagnose(loc,
|
|
hasTooFew ? diag::sil_missing_substitutions
|
|
: diag::sil_too_many_substitutions);
|
|
return SubstitutionMap();
|
|
}
|
|
|
|
bool failed = false;
|
|
auto subMap = SubstitutionMap::get(
|
|
genericSig,
|
|
[&](SubstitutableType *type) -> Type {
|
|
auto genericParam = dyn_cast<GenericTypeParamType>(type);
|
|
if (!genericParam)
|
|
return nullptr;
|
|
|
|
auto index = genericSig->getGenericParamOrdinal(genericParam);
|
|
assert(index < genericSig.getGenericParams().size());
|
|
assert(index < parses.size());
|
|
|
|
// Provide the replacement type.
|
|
return parses[index].replacement;
|
|
},
|
|
[&](InFlightSubstitution &IFS, Type dependentType,
|
|
ProtocolDecl *proto) -> ProtocolConformanceRef {
|
|
auto replacementType = dependentType.subst(IFS)
|
|
->getReferenceStorageReferent();
|
|
if (auto conformance = lookupConformance(replacementType, proto))
|
|
return conformance;
|
|
|
|
SP.P.diagnose(loc, diag::sil_substitution_mismatch, replacementType,
|
|
proto->getDeclaredInterfaceType());
|
|
failed = true;
|
|
|
|
return ProtocolConformanceRef::forInvalid();
|
|
});
|
|
|
|
return failed ? SubstitutionMap() : subMap;
|
|
}
|
|
|
|
static ArrayRef<ProtocolConformanceRef>
|
|
collectExistentialConformances(Parser &P, CanType conformingType, SourceLoc loc,
|
|
CanType protocolType) {
|
|
auto layout = protocolType.getExistentialLayout();
|
|
|
|
if (layout.requiresClass()) {
|
|
if (!conformingType->mayHaveSuperclass() &&
|
|
!conformingType->isObjCExistentialType()) {
|
|
P.diagnose(loc, diag::sil_not_class, conformingType);
|
|
}
|
|
}
|
|
|
|
// FIXME: Check superclass also.
|
|
|
|
auto protocols = layout.getProtocols();
|
|
if (protocols.empty())
|
|
return {};
|
|
|
|
SmallVector<ProtocolConformanceRef, 2> conformances;
|
|
getConformancesForSubstitution(P, protocols, conformingType,
|
|
loc, conformances);
|
|
|
|
return P.Context.AllocateCopy(conformances);
|
|
}
|
|
|
|
/// sil-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+
|
|
bool SILParser::parseSILLocation(SILLocation &Loc) {
|
|
if (parseVerbatim("loc"))
|
|
return true;
|
|
|
|
bool isAutoGenerated = false;
|
|
if (P.Tok.isAnyOperator() && P.Tok.getText().starts_with("*")) {
|
|
isAutoGenerated = true;
|
|
P.consumeStartingCharacterOfCurrentToken();
|
|
}
|
|
|
|
if (P.Tok.getKind() != tok::string_literal) {
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, "string");
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
StringRef File = P.Tok.getText().drop_front().drop_back();
|
|
P.consumeToken(tok::string_literal);
|
|
if (P.parseToken(tok::colon, diag::expected_colon_in_sil_location))
|
|
return true;
|
|
unsigned Line = 0;
|
|
if (parseInteger(Line, diag::sil_invalid_line_in_sil_location))
|
|
return true;
|
|
if (P.parseToken(tok::colon, diag::expected_colon_in_sil_location))
|
|
return true;
|
|
unsigned Column = 0;
|
|
if (parseInteger(Column, diag::sil_invalid_column_in_sil_location))
|
|
return true;
|
|
|
|
auto fnl = SILLocation::FilenameAndLocation::alloc(Line, Column,
|
|
P.Context.getIdentifier(File).str().data(), SILMod);
|
|
|
|
Loc = RegularLocation(fnl);
|
|
|
|
if (isAutoGenerated)
|
|
Loc.markAutoGenerated();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseScopeRef(SILDebugScope *&DS) {
|
|
unsigned Slot;
|
|
SourceLoc SlotLoc = P.Tok.getLoc();
|
|
if (parseInteger(Slot, diag::sil_invalid_scope_slot))
|
|
return true;
|
|
|
|
DS = TUState.ScopeSlots[Slot];
|
|
if (!DS) {
|
|
P.diagnose(SlotLoc, diag::sil_scope_undeclared, Slot);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseForwardingOwnershipKind(
|
|
ValueOwnershipKind &forwardingKind) {
|
|
if (P.Tok.is(tok::comma)) {
|
|
P.consumeToken();
|
|
parsedComma = true;
|
|
}
|
|
if (!parsedComma)
|
|
return false;
|
|
|
|
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "forwarding") {
|
|
parsedComma = false;
|
|
P.consumeToken();
|
|
return P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|
|
|| parseSILOwnership(forwardingKind);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// (',' sil-loc)? (',' sil-scope-ref)?
|
|
bool SILParser::parseSILDebugLocation(SILLocation &L, SILBuilder &B) {
|
|
// Parse the debug information, if any.
|
|
if (P.Tok.is(tok::comma)) {
|
|
P.consumeToken();
|
|
parsedComma = true;
|
|
}
|
|
if (!parsedComma)
|
|
return false;
|
|
|
|
bool requireScope = false;
|
|
if (P.Tok.getText() == "loc") {
|
|
parsedComma = false;
|
|
if (parseSILLocation(L))
|
|
return true;
|
|
|
|
if (P.Tok.is(tok::comma)) {
|
|
P.consumeToken();
|
|
requireScope = true;
|
|
}
|
|
}
|
|
if (P.Tok.getText() == "scope" || requireScope) {
|
|
parsedComma = false;
|
|
parseVerbatim("scope");
|
|
SILDebugScope *DS = nullptr;
|
|
if (parseScopeRef(DS))
|
|
return true;
|
|
if (DS)
|
|
B.setCurrentDebugScope(DS);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool parseAssignOrInitMode(AssignOrInitInst::Mode &Result,
|
|
SILParser &P) {
|
|
StringRef Str;
|
|
if (!parseSILOptional(Str, P)) {
|
|
Result = AssignOrInitInst::Unknown;
|
|
return false;
|
|
}
|
|
|
|
auto Tmp = llvm::StringSwitch<AssignOrInitInst::Mode>(Str)
|
|
.Case("init", AssignOrInitInst::Init)
|
|
.Case("set", AssignOrInitInst::Set)
|
|
.Default(AssignOrInitInst::Unknown);
|
|
|
|
// Return true (following the conventions in this file) if we fail.
|
|
if (Tmp == AssignOrInitInst::Unknown)
|
|
return true;
|
|
|
|
Result = Tmp;
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
parseAssignOrInitAssignments(llvm::SmallVectorImpl<unsigned> &assignments,
|
|
SILParser &SP) {
|
|
// Could be more than one [assign=<index>] attributes.
|
|
for (;;) {
|
|
SourceLoc loc;
|
|
|
|
// Consume '['
|
|
if (!SP.P.consumeIf(tok::l_square))
|
|
return false;
|
|
|
|
// Consume the identifier which should be "assign"
|
|
{
|
|
Identifier Id;
|
|
if (SP.parseSILIdentifier(Id, loc, diag::expected_in_attribute_list))
|
|
return true;
|
|
|
|
if (!Id.is("assign")) {
|
|
SP.P.diagnose(loc, diag::sil_invalid_attribute_for_expected, Id.str(),
|
|
"assign");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
uint64_t index;
|
|
|
|
// Consume '='
|
|
if (!SP.P.consumeIf(tok::equal)) {
|
|
SP.P.diagnose(loc, diag::expected_equal_in_sil_instr);
|
|
return true;
|
|
}
|
|
|
|
// Consume the property index.
|
|
if (SP.parseInteger(index, diag::expected_in_attribute_list))
|
|
return true;
|
|
|
|
// Consume ']'
|
|
if (SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list))
|
|
return true;
|
|
|
|
assignments.push_back(index);
|
|
}
|
|
}
|
|
|
|
// Parse a list of integer indices, prefaced with the given string label.
|
|
// Returns true on error.
|
|
static bool parseIndexList(Parser &P, StringRef label,
|
|
SmallVectorImpl<unsigned> &indices,
|
|
DiagRef parseIndexDiag) {
|
|
SourceLoc loc;
|
|
// Parse `[<label> <integer_literal>...]`.
|
|
if (P.parseToken(tok::l_square, diag::sil_autodiff_expected_lsquare,
|
|
"index list") ||
|
|
P.parseSpecificIdentifier(
|
|
label, diag::sil_autodiff_expected_index_list_label, label))
|
|
return true;
|
|
while (P.Tok.is(tok::integer_literal)) {
|
|
unsigned index;
|
|
if (P.parseUnsignedInteger(index, loc, parseIndexDiag))
|
|
return true;
|
|
indices.push_back(index);
|
|
}
|
|
if (P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
|
|
"index list"))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
/// Parse a differentiability kind, an autodiff config, and a function name for
|
|
/// a differentiability witness. Returns true on error.
|
|
///
|
|
/// sil-differentiability-witness-config-and-function ::=
|
|
/// '[' differentiability-kind ']'
|
|
/// '[' 'parameters' index-subset ']'
|
|
/// '[' 'results' index-subset ']'
|
|
/// ('<' 'where' derivative-generic-signature-requirements '>')?
|
|
/// sil-function-ref
|
|
///
|
|
/// e.g. [reverse] [parameters 0 1] [results 0] <T where T: Differentiable>
|
|
/// @foo : <T> $(T) -> T
|
|
static bool parseSILDifferentiabilityWitnessConfigAndFunction(
|
|
Parser &P, SILParser &SP, SILLocation L,
|
|
DifferentiabilityKind &resultDiffKind, AutoDiffConfig &resultConfig,
|
|
SILFunction *&resultOrigFn) {
|
|
// Parse differentiability kind.
|
|
if (P.parseToken(tok::l_square, diag::sil_autodiff_expected_lsquare,
|
|
"differentiability kind"))
|
|
return true;
|
|
resultDiffKind = llvm::StringSwitch<DifferentiabilityKind>(P.Tok.getText())
|
|
.Case("forward", DifferentiabilityKind::Forward)
|
|
.Case("reverse", DifferentiabilityKind::Reverse)
|
|
.Case("normal", DifferentiabilityKind::Normal)
|
|
.Case("linear", DifferentiabilityKind::Linear)
|
|
.Default(DifferentiabilityKind::NonDifferentiable);
|
|
if (resultDiffKind == DifferentiabilityKind::NonDifferentiable) {
|
|
P.diagnose(P.Tok, diag::sil_diff_witness_unknown_kind, P.Tok.getText());
|
|
return true;
|
|
}
|
|
P.consumeToken(tok::identifier);
|
|
if (P.parseToken(tok::r_square, diag::sil_autodiff_expected_rsquare,
|
|
"differentiability kind"))
|
|
return true;
|
|
// Parse parameter and result indices.
|
|
SmallVector<unsigned, 8> rawParameterIndices;
|
|
SmallVector<unsigned, 8> rawResultIndices;
|
|
if (parseIndexList(P, "parameters", rawParameterIndices,
|
|
diag::sil_autodiff_expected_parameter_index))
|
|
return true;
|
|
if (parseIndexList(P, "results", rawResultIndices,
|
|
diag::sil_autodiff_expected_result_index))
|
|
return true;
|
|
// Parse witness generic parameter clause.
|
|
GenericSignature witnessGenSig = GenericSignature();
|
|
SourceLoc witnessGenSigStartLoc = P.getEndOfPreviousLoc();
|
|
{
|
|
auto *genericParams = P.maybeParseGenericParams().getPtrOrNull();
|
|
if (genericParams) {
|
|
witnessGenSig = handleSILGenericParams(genericParams, &P.SF);
|
|
}
|
|
}
|
|
// Parse original function name and type.
|
|
if (SP.parseSILFunctionRef(L, resultOrigFn))
|
|
return true;
|
|
// Resolve parsed witness generic signature.
|
|
if (witnessGenSig) {
|
|
auto origGenSig =
|
|
resultOrigFn->getLoweredFunctionType()->getSubstGenericSignature();
|
|
// Check whether original function generic signature and parsed witness
|
|
// generic have the same generic parameters.
|
|
auto areGenericParametersConsistent = [&]() {
|
|
llvm::SmallDenseSet<GenericParamKey, 4> genericParamKeys;
|
|
for (auto origGP : origGenSig.getGenericParams())
|
|
genericParamKeys.insert(GenericParamKey(origGP.getPointer()));
|
|
for (auto *witnessGP : witnessGenSig.getGenericParams())
|
|
if (!genericParamKeys.erase(GenericParamKey(witnessGP)))
|
|
return false;
|
|
return genericParamKeys.empty();
|
|
};
|
|
if (!areGenericParametersConsistent()) {
|
|
P.diagnose(witnessGenSigStartLoc,
|
|
diag::sil_diff_witness_invalid_generic_signature,
|
|
witnessGenSig->getAsString(), origGenSig->getAsString());
|
|
return true;
|
|
}
|
|
// Combine parsed witness requirements with original function generic
|
|
// signature requirements to form full witness generic signature.
|
|
SmallVector<Requirement, 4> witnessRequirements(
|
|
witnessGenSig.getRequirements().begin(),
|
|
witnessGenSig.getRequirements().end());
|
|
witnessGenSig = buildGenericSignature(
|
|
P.Context, origGenSig,
|
|
/*addedGenericParams=*/{},
|
|
std::move(witnessRequirements),
|
|
/*allowInverses=*/false);
|
|
}
|
|
auto origFnType = resultOrigFn->getLoweredFunctionType();
|
|
auto *parameterIndices = IndexSubset::get(
|
|
P.Context, origFnType->getNumParameters(), rawParameterIndices);
|
|
auto *resultIndices = IndexSubset::get(P.Context,
|
|
origFnType->getNumResults() +
|
|
origFnType->getNumIndirectMutatingParameters(),
|
|
rawResultIndices);
|
|
resultConfig = AutoDiffConfig(parameterIndices, resultIndices, witnessGenSig);
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseSILDeclRef(SILDeclRef &Member, bool FnTypeRequired) {
|
|
SourceLoc TyLoc;
|
|
SmallVector<ValueDecl *, 4> values;
|
|
if (parseSILDeclRef(Member, values))
|
|
return true;
|
|
|
|
// : ( or : < means that what follows is function type.
|
|
if (!P.Tok.is(tok::colon))
|
|
return false;
|
|
|
|
if (FnTypeRequired &&
|
|
!P.peekToken().is(tok::l_paren) &&
|
|
!P.startsWithLess(P.peekToken()))
|
|
return false;
|
|
|
|
// Type of the SILDeclRef is optional to be compatible with the old format.
|
|
if (!P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")) {
|
|
// Parse the type for SILDeclRef.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
bindSILGenericParams(TyR.get());
|
|
|
|
// The type can be polymorphic.
|
|
GenericSignature genericSig;
|
|
GenericParamList *genericParams = nullptr;
|
|
if (auto *fnType = dyn_cast<FunctionTypeRepr>(TyR.get())) {
|
|
genericSig = fnType->getGenericSignature();
|
|
genericParams = fnType->getGenericParams();
|
|
}
|
|
|
|
const auto Ty = performTypeResolution(TyR.get(), /*IsSILType=*/false,
|
|
genericSig, genericParams);
|
|
if (Ty->hasError())
|
|
return true;
|
|
|
|
// Pick the ValueDecl that has the right type.
|
|
ValueDecl *TheDecl = nullptr;
|
|
auto declTy = Ty->getCanonicalType();
|
|
for (unsigned I = 0, E = values.size(); I < E; ++I) {
|
|
auto *decl = values[I];
|
|
|
|
auto lookupTy =
|
|
decl->getInterfaceType()
|
|
->removeArgumentLabels(decl->getNumCurryLevels());
|
|
if (declTy == lookupTy->getCanonicalType()) {
|
|
TheDecl = decl;
|
|
// Update SILDeclRef to point to the right Decl.
|
|
Member.loc = decl;
|
|
break;
|
|
}
|
|
if (values.size() == 1 && !TheDecl) {
|
|
P.diagnose(TyLoc, diag::sil_member_decl_type_mismatch, declTy,
|
|
lookupTy);
|
|
return true;
|
|
}
|
|
}
|
|
if (!TheDecl) {
|
|
P.diagnose(TyLoc, diag::sil_member_decl_not_found);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
SILParser::parseKeyPathPatternComponent(KeyPathPatternComponent &component,
|
|
SmallVectorImpl<SILType> &operandTypes,
|
|
SourceLoc componentLoc,
|
|
Identifier componentKind,
|
|
SILLocation InstLoc,
|
|
GenericSignature patternSig,
|
|
GenericParamList *patternParams) {
|
|
auto parseComponentIndices =
|
|
[&](SmallVectorImpl<KeyPathPatternComponent::Index> &indexes) -> bool {
|
|
while (true) {
|
|
unsigned index;
|
|
CanType formalTy;
|
|
SILType loweredTy;
|
|
if (P.parseToken(tok::oper_prefix,
|
|
diag::expected_tok_in_sil_instr, "%")
|
|
|| P.parseToken(tok::sil_dollar,
|
|
diag::expected_tok_in_sil_instr, "$"))
|
|
return true;
|
|
|
|
if (!P.Tok.is(tok::integer_literal)
|
|
|| parseIntegerLiteral(P.Tok.getText(), 0, index))
|
|
return true;
|
|
|
|
P.consumeToken(tok::integer_literal);
|
|
|
|
SourceLoc formalTyLoc;
|
|
SourceLoc loweredTyLoc;
|
|
GenericSignature ignoredParsedSig;
|
|
GenericParamList *ignoredParsedParams = nullptr;
|
|
if (P.parseToken(tok::colon,
|
|
diag::expected_tok_in_sil_instr, ":")
|
|
|| P.parseToken(tok::sil_dollar,
|
|
diag::expected_tok_in_sil_instr, "$")
|
|
|| parseASTType(formalTy, formalTyLoc,
|
|
patternSig, patternParams)
|
|
|| P.parseToken(tok::colon,
|
|
diag::expected_tok_in_sil_instr, ":")
|
|
|| parseSILType(loweredTy, loweredTyLoc,
|
|
ignoredParsedSig, ignoredParsedParams,
|
|
patternSig, patternParams))
|
|
return true;
|
|
|
|
if (patternSig)
|
|
loweredTy = SILType::getPrimitiveType(loweredTy.getRawASTType()
|
|
->mapTypeOutOfContext()
|
|
->getCanonicalType(),
|
|
loweredTy.getCategory());
|
|
|
|
// Formal type must be hashable.
|
|
auto proto = P.Context.getProtocol(KnownProtocolKind::Hashable);
|
|
Type contextFormalTy = formalTy;
|
|
if (patternSig) {
|
|
contextFormalTy = patternSig.getGenericEnvironment()
|
|
->mapTypeIntoContext(formalTy);
|
|
}
|
|
auto lookup = lookupConformance(contextFormalTy, proto);
|
|
if (lookup.isInvalid()) {
|
|
P.diagnose(formalTyLoc,
|
|
diag::sil_keypath_index_not_hashable,
|
|
formalTy);
|
|
return true;
|
|
}
|
|
auto conformance = ProtocolConformanceRef(lookup);
|
|
|
|
indexes.push_back({index, formalTy, loweredTy, conformance});
|
|
|
|
if (operandTypes.size() <= index)
|
|
operandTypes.resize(index+1);
|
|
if (operandTypes[index] && operandTypes[index] != loweredTy) {
|
|
P.diagnose(loweredTyLoc,
|
|
diag::sil_keypath_index_operand_type_conflict, index,
|
|
operandTypes[index].getRawASTType(),
|
|
loweredTy.getRawASTType());
|
|
return true;
|
|
}
|
|
operandTypes[index] = loweredTy;
|
|
|
|
if (P.consumeIf(tok::comma))
|
|
continue;
|
|
if (P.consumeIf(tok::r_square))
|
|
break;
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
if (componentKind.str() == "stored_property") {
|
|
ValueDecl *prop;
|
|
CanType ty;
|
|
if (parseSILDottedPath(prop)
|
|
|| P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|
|
|| P.parseToken(tok::sil_dollar,
|
|
diag::expected_tok_in_sil_instr, "$")
|
|
|| parseASTType(ty, patternSig, patternParams))
|
|
return true;
|
|
component =
|
|
KeyPathPatternComponent::forStoredProperty(cast<VarDecl>(prop), ty);
|
|
return false;
|
|
} else if (componentKind.str() == "gettable_property"
|
|
|| componentKind.str() == "settable_property") {
|
|
bool isSettable = componentKind.str()[0] == 's';
|
|
|
|
CanType componentTy;
|
|
if (P.parseToken(tok::sil_dollar,diag::expected_tok_in_sil_instr,"$")
|
|
|| parseASTType(componentTy, patternSig, patternParams)
|
|
|| P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
|
|
return true;
|
|
|
|
SILFunction *idFn = nullptr;
|
|
SILDeclRef idDecl;
|
|
VarDecl *idProperty = nullptr;
|
|
SILFunction *getter = nullptr;
|
|
SILFunction *setter = nullptr;
|
|
SILFunction *equals = nullptr;
|
|
SILFunction *hash = nullptr;
|
|
AbstractStorageDecl *externalDecl = nullptr;
|
|
SubstitutionMap externalSubs;
|
|
SmallVector<KeyPathPatternComponent::Index, 4> indexes;
|
|
while (true) {
|
|
Identifier subKind;
|
|
SourceLoc subKindLoc;
|
|
if (parseSILIdentifier(subKind, subKindLoc,
|
|
diag::sil_keypath_expected_component_kind))
|
|
return true;
|
|
|
|
if (subKind.str() == "id") {
|
|
// The identifier can be either a function ref, a SILDeclRef
|
|
// to a class or protocol method, or a decl ref to a property:
|
|
// @static_fn_ref : $...
|
|
// #Type.method!whatever : (T) -> ...
|
|
// ##Type.property
|
|
if (P.Tok.is(tok::at_sign)) {
|
|
if (parseSILFunctionRef(InstLoc, idFn))
|
|
return true;
|
|
} else if (P.Tok.is(tok::pound)) {
|
|
if (P.peekToken().is(tok::pound)) {
|
|
ValueDecl *propertyValueDecl;
|
|
P.consumeToken(tok::pound);
|
|
if (parseSILDottedPath(propertyValueDecl))
|
|
return true;
|
|
idProperty = cast<VarDecl>(propertyValueDecl);
|
|
} else if (parseSILDeclRef(idDecl, /*fnType*/ true))
|
|
return true;
|
|
} else {
|
|
P.diagnose(subKindLoc, diag::expected_tok_in_sil_instr, "# or @");
|
|
return true;
|
|
}
|
|
} else if (subKind.str() == "getter" || subKind.str() == "setter") {
|
|
bool isSetter = subKind.str()[0] == 's';
|
|
if (parseSILFunctionRef(InstLoc, isSetter ? setter : getter))
|
|
return true;
|
|
} else if (subKind.str() == "indices") {
|
|
if (P.parseToken(tok::l_square,
|
|
diag::expected_tok_in_sil_instr, "[")
|
|
|| parseComponentIndices(indexes))
|
|
return true;
|
|
} else if (subKind.str() == "indices_equals") {
|
|
if (parseSILFunctionRef(InstLoc, equals))
|
|
return true;
|
|
} else if (subKind.str() == "indices_hash") {
|
|
if (parseSILFunctionRef(InstLoc, hash))
|
|
return true;
|
|
} else if (subKind.str() == "external") {
|
|
ValueDecl *parsedExternalDecl;
|
|
SmallVector<ParsedSubstitution, 4> parsedSubs;
|
|
|
|
if (parseSILDottedPath(parsedExternalDecl)
|
|
|| parseSubstitutions(parsedSubs, patternSig, patternParams))
|
|
return true;
|
|
|
|
externalDecl = cast<AbstractStorageDecl>(parsedExternalDecl);
|
|
|
|
if (!parsedSubs.empty()) {
|
|
auto genericSig = externalDecl->getInnermostDeclContext()
|
|
->getGenericSignatureOfContext();
|
|
if (!genericSig) {
|
|
P.diagnose(P.Tok,
|
|
diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
externalSubs = getApplySubstitutionsFromParsed(*this, genericSig,
|
|
parsedSubs);
|
|
if (!externalSubs) return true;
|
|
|
|
// Map the substitutions out of the pattern context so that they
|
|
// use interface types.
|
|
externalSubs =
|
|
externalSubs.mapReplacementTypesOutOfContext().getCanonical();
|
|
}
|
|
|
|
} else {
|
|
P.diagnose(subKindLoc, diag::sil_keypath_unknown_component_kind,
|
|
subKind);
|
|
return true;
|
|
}
|
|
|
|
if (!P.consumeIf(tok::comma))
|
|
break;
|
|
}
|
|
|
|
if ((idFn == nullptr && idDecl.isNull() && idProperty == nullptr)
|
|
|| getter == nullptr
|
|
|| (isSettable && setter == nullptr)) {
|
|
P.diagnose(componentLoc,
|
|
diag::sil_keypath_computed_property_missing_part,
|
|
isSettable);
|
|
return true;
|
|
}
|
|
|
|
if ((idFn != nullptr) + (!idDecl.isNull()) + (idProperty != nullptr)
|
|
!= 1) {
|
|
P.diagnose(componentLoc,
|
|
diag::sil_keypath_computed_property_missing_part,
|
|
isSettable);
|
|
return true;
|
|
}
|
|
|
|
KeyPathPatternComponent::ComputedPropertyId id;
|
|
if (idFn)
|
|
id = idFn;
|
|
else if (!idDecl.isNull())
|
|
id = idDecl;
|
|
else if (idProperty)
|
|
id = idProperty;
|
|
else
|
|
llvm_unreachable("no id?!");
|
|
|
|
auto indexesCopy = P.Context.AllocateCopy(indexes);
|
|
|
|
if (!indexes.empty() && (!equals || !hash)) {
|
|
P.diagnose(componentLoc,
|
|
diag::sil_keypath_computed_property_missing_part,
|
|
isSettable);
|
|
}
|
|
|
|
if (isSettable) {
|
|
component = KeyPathPatternComponent::forComputedSettableProperty(
|
|
id, getter, setter,
|
|
indexesCopy, equals, hash,
|
|
externalDecl, externalSubs, componentTy);
|
|
} else {
|
|
component = KeyPathPatternComponent::forComputedGettableProperty(
|
|
id, getter,
|
|
indexesCopy, equals, hash,
|
|
externalDecl, externalSubs, componentTy);
|
|
}
|
|
return false;
|
|
} else if (componentKind.str() == "optional_wrap"
|
|
|| componentKind.str() == "optional_chain"
|
|
|| componentKind.str() == "optional_force") {
|
|
CanType ty;
|
|
if (P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|
|
|| P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$")
|
|
|| parseASTType(ty, patternSig, patternParams))
|
|
return true;
|
|
KeyPathPatternComponent::Kind kind;
|
|
|
|
if (componentKind.str() == "optional_wrap") {
|
|
kind = KeyPathPatternComponent::Kind::OptionalWrap;
|
|
} else if (componentKind.str() == "optional_chain") {
|
|
kind = KeyPathPatternComponent::Kind::OptionalChain;
|
|
} else if (componentKind.str() == "optional_force") {
|
|
kind = KeyPathPatternComponent::Kind::OptionalForce;
|
|
} else {
|
|
llvm_unreachable("unpossible");
|
|
}
|
|
|
|
component = KeyPathPatternComponent::forOptional(kind, ty);
|
|
return false;
|
|
} else if (componentKind.str() == "tuple_element") {
|
|
unsigned tupleIndex;
|
|
CanType ty;
|
|
|
|
if (P.parseToken(tok::pound, diag::expected_sil_constant)
|
|
|| parseInteger(tupleIndex, diag::expected_sil_tuple_index)
|
|
|| P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":")
|
|
|| P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$")
|
|
|| parseASTType(ty, patternSig, patternParams))
|
|
return true;
|
|
|
|
component = KeyPathPatternComponent::forTupleElement(tupleIndex, ty);
|
|
return false;
|
|
} else {
|
|
P.diagnose(componentLoc, diag::sil_keypath_unknown_component_kind,
|
|
componentKind);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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, /*implicit*/ false);
|
|
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<std::optional<OpenedExistentialAccess>>(
|
|
accessKindToken.str())
|
|
.Case("mutable_access", OpenedExistentialAccess::Mutable)
|
|
.Case("immutable_access", OpenedExistentialAccess::Immutable)
|
|
.Default(std::nullopt);
|
|
|
|
if (kind) {
|
|
AccessKind = kind.value();
|
|
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: {
|
|
auto hasDynamicLifetime = DoesNotHaveDynamicLifetime;
|
|
bool hasReflection = false;
|
|
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
|
|
DoesNotUseMoveableValueDebugInfo;
|
|
auto hasPointerEscape = DoesNotHavePointerEscape;
|
|
StringRef attrName;
|
|
SourceLoc attrLoc;
|
|
while (parseSILOptional(attrName, attrLoc, *this)) {
|
|
if (attrName == "dynamic_lifetime") {
|
|
hasDynamicLifetime = HasDynamicLifetime;
|
|
} else if (attrName == "reflection") {
|
|
hasReflection = true;
|
|
} else if (attrName == "moveable_value_debuginfo") {
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
} else if (attrName == "pointer_escape") {
|
|
hasPointerEscape = HasPointerEscape;
|
|
} else {
|
|
P.diagnose(attrLoc, diag::sil_invalid_attribute_for_expected, attrName,
|
|
"dynamic_lifetime, reflection, pointer_escape or "
|
|
"usesMoveableValueDebugInfo");
|
|
}
|
|
}
|
|
|
|
SILType Ty;
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
SILDebugVariable VarInfo;
|
|
if (parseSILDebugVar(VarInfo))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
if (Ty.isMoveOnly())
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
|
|
ResultVal = B.createAllocBox(InstLoc, Ty.castTo<SILBoxType>(), VarInfo,
|
|
hasDynamicLifetime, hasReflection,
|
|
usesMoveableValueDebugInfo,
|
|
/*skipVarDeclAssert*/ false, hasPointerEscape);
|
|
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: {
|
|
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);
|
|
ResultVal = B.createAbortApply(InstLoc, op);
|
|
break;
|
|
}
|
|
case SILInstructionKind::EndApplyInst: {
|
|
UnresolvedValueName argName;
|
|
SILType ResultTy;
|
|
|
|
if (parseValueName(argName) || parseVerbatim("as") ||
|
|
parseSILType(ResultTy) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
SILType expectedTy = SILType::getSILTokenType(P.Context);
|
|
SILValue op = getLocalValue(argName, expectedTy, InstLoc, B);
|
|
|
|
ResultVal = B.createEndApply(InstLoc, op, ResultTy);
|
|
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 if (P.Tok.getText() == "oslog") {
|
|
encoding = StringLiteralInst::Encoding::UTF8_OSLOG;
|
|
} 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::IncrementProfilerCounterInst: {
|
|
// First argument is the counter index.
|
|
unsigned CounterIdx;
|
|
if (parseInteger(CounterIdx, diag::expected_sil_profiler_counter_idx))
|
|
return true;
|
|
|
|
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
|
|
return true;
|
|
|
|
// Parse the PGO function name.
|
|
if (P.Tok.getKind() != tok::string_literal) {
|
|
P.diagnose(P.Tok, diag::expected_sil_profiler_counter_pgo_func_name);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
auto FuncName = P.Tok.getText().drop_front().drop_back();
|
|
P.consumeToken(tok::string_literal);
|
|
|
|
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
|
|
return true;
|
|
|
|
// Parse the number of counters.
|
|
if (parseVerbatim("num_counters"))
|
|
return true;
|
|
|
|
unsigned NumCounters;
|
|
if (parseInteger(NumCounters, diag::expected_sil_profiler_counter_total))
|
|
return true;
|
|
|
|
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ","))
|
|
return true;
|
|
|
|
// Parse the PGO function hash.
|
|
if (parseVerbatim("hash"))
|
|
return true;
|
|
|
|
uint64_t Hash;
|
|
if (parseInteger(Hash, diag::expected_sil_profiler_counter_hash))
|
|
return true;
|
|
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createIncrementProfilerCounter(InstLoc, CounterIdx, FuncName,
|
|
NumCounters, Hash);
|
|
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]);
|
|
GenericSignature genericSig = builtinFunc->getGenericSignature();
|
|
|
|
SmallVector<ParsedSubstitution, 4> parsedSubs;
|
|
SubstitutionMap subMap;
|
|
if (parseSubstitutions(parsedSubs))
|
|
return true;
|
|
|
|
if (!parsedSubs.empty()) {
|
|
if (!genericSig) {
|
|
P.diagnose(P.Tok, diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
subMap = getApplySubstitutionsFromParsed(*this, genericSig, 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::MergeIsolationRegionInst: {
|
|
SmallVector<SILValue, 4> Args;
|
|
do {
|
|
SILValue Val;
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
Args.push_back(Val);
|
|
} while (P.consumeIf(tok::comma));
|
|
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createMergeIsolationRegion(InstLoc, 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;
|
|
}
|
|
case SILInstructionKind::TypeValueInst: {
|
|
CanType paramType;
|
|
if (parseSILType(Ty) ||
|
|
parseVerbatim("for") ||
|
|
parseASTTypeOrValue(paramType))
|
|
return true;
|
|
|
|
ResultVal = B.createTypeValue(InstLoc, Ty, paramType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::PackLengthInst: {
|
|
CanPackType packType;
|
|
if (P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
|
|
parseASTPackType(packType))
|
|
return true;
|
|
ResultVal = B.createPackLength(InstLoc, packType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::DynamicPackIndexInst: {
|
|
CanPackType packType;
|
|
if (parseValueRef(Val, SILType::getBuiltinWordType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of") ||
|
|
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
|
|
parseASTPackType(packType))
|
|
return true;
|
|
ResultVal =
|
|
B.createDynamicPackIndex(InstLoc, Val, packType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::PackPackIndexInst: {
|
|
unsigned componentIndex = 0;
|
|
CanPackType packType;
|
|
if (parseInteger(componentIndex, diag::expected_sil_constant) ||
|
|
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
|
|
parseValueRef(Val, SILType::getPackIndexType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of") ||
|
|
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
|
|
parseASTPackType(packType))
|
|
return true;
|
|
ResultVal =
|
|
B.createPackPackIndex(InstLoc, componentIndex, Val, packType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::ScalarPackIndexInst: {
|
|
unsigned componentIndex = 0;
|
|
CanPackType packType;
|
|
if (parseInteger(componentIndex, diag::expected_sil_constant) ||
|
|
parseVerbatim("of") ||
|
|
P.parseToken(tok::sil_dollar, diag::expected_tok_in_sil_instr, "$") ||
|
|
parseASTPackType(packType))
|
|
return true;
|
|
ResultVal =
|
|
B.createScalarPackIndex(InstLoc, componentIndex, packType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::OpenPackElementInst: {
|
|
if (parseValueRef(Val, SILType::getPackIndexType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of"))
|
|
return true;
|
|
|
|
// Parse the generic parameters for the environment being opened.
|
|
// This does not include the opened generic parameters.
|
|
GenericParamList *openedGenerics; {
|
|
if (!P.startsWithLess(P.Tok)) {
|
|
P.diagnose(P.Tok, diag::expected_generic_signature);
|
|
return true;
|
|
}
|
|
openedGenerics = P.maybeParseGenericParams().getPtrOrNull();
|
|
if (!openedGenerics)
|
|
return true;
|
|
}
|
|
|
|
// Resolve a generic signature from those parameters.
|
|
auto openedGenericsSig = handleSILGenericParams(openedGenerics, &P.SF);
|
|
if (!openedGenericsSig) return true;
|
|
|
|
// Parse the substitutions for the environment being opened.
|
|
SubstitutionMap openedSubMap; {
|
|
if (parseVerbatim("at"))
|
|
return true;
|
|
|
|
// The substitutions are not contextual within the signature
|
|
// we just parsed.
|
|
SmallVector<ParsedSubstitution> parsedOpenedSubs;
|
|
if (parseSubstitutions(parsedOpenedSubs))
|
|
return true;
|
|
|
|
// We do need those substitutions to resolve a SubstitutionMap,
|
|
// though.
|
|
openedSubMap =
|
|
getApplySubstitutionsFromParsed(*this, openedGenericsSig,
|
|
parsedOpenedSubs);
|
|
if (!openedSubMap)
|
|
return true;
|
|
}
|
|
|
|
// Parse the shape class that should be opened. This is a contextual
|
|
// type within the signature we just parsed.
|
|
CanType shapeClass;
|
|
SourceLoc shapeClassLoc;
|
|
if (!P.consumeIf(tok::comma) ||
|
|
parseVerbatim("shape") ||
|
|
P.parseToken(tok::sil_dollar,
|
|
diag::expected_tok_in_sil_instr, "$") ||
|
|
parseASTType(shapeClass, shapeClassLoc, openedGenericsSig,
|
|
openedGenerics, /*wantContextualType*/ true))
|
|
return true;
|
|
|
|
// Map it out of context. It should be a type pack parameter.
|
|
shapeClass = shapeClass->mapTypeOutOfContext()->getCanonicalType();
|
|
auto shapeParam = dyn_cast<GenericTypeParamType>(shapeClass);
|
|
if (!shapeParam || !shapeParam->isParameterPack()) {
|
|
P.diagnose(shapeClassLoc, diag::opened_shape_class_not_pack_param);
|
|
return true;
|
|
}
|
|
|
|
// Parse the UUID for the opening.
|
|
UUID uuid;
|
|
if (!P.consumeIf(tok::comma) ||
|
|
parseVerbatim("uuid") ||
|
|
P.parseUUIDString(uuid, diag::sil_expected_uuid))
|
|
return true;
|
|
|
|
// Build the opened-element signature, which adds the parameters for
|
|
// the opened elements to the signature we parsed above.
|
|
auto openedElementSig =
|
|
P.Context.getOpenedElementSignature(
|
|
openedGenericsSig.getCanonicalSignature(), shapeParam);
|
|
|
|
auto openedEnv = GenericEnvironment::forOpenedElement(openedElementSig,
|
|
uuid, shapeParam, openedSubMap);
|
|
|
|
auto openInst = B.createOpenPackElement(InstLoc, Val, openedEnv);
|
|
ResultVal = openInst;
|
|
|
|
auto &entry = OpenedPackElements[uuid];
|
|
if (entry.DefinitionPoint.isValid()) {
|
|
P.diagnose(OpcodeLoc, diag::multiple_open_pack_element);
|
|
P.diagnose(entry.DefinitionPoint, diag::sil_previous_instruction);
|
|
} else {
|
|
entry.DefinitionPoint = OpcodeLoc;
|
|
entry.Params = openedGenerics;
|
|
entry.Environment = openedEnv;
|
|
}
|
|
break;
|
|
}
|
|
case SILInstructionKind::PackElementGetInst: {
|
|
SILValue index, pack;
|
|
SILType elementType;
|
|
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of") ||
|
|
parseTypedValueRef(pack, B) ||
|
|
parseVerbatim("as") ||
|
|
parseSILType(elementType))
|
|
return true;
|
|
ResultVal = B.createPackElementGet(InstLoc, index, pack, elementType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::PackElementSetInst: {
|
|
SILValue value, index, pack;
|
|
if (parseTypedValueRef(value, B) ||
|
|
parseVerbatim("into") ||
|
|
parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of") ||
|
|
parseTypedValueRef(pack, B))
|
|
return true;
|
|
ResultVal = B.createPackElementSet(InstLoc, value, index, pack);
|
|
break;
|
|
}
|
|
case SILInstructionKind::TuplePackElementAddrInst: {
|
|
SILValue index, tuple;
|
|
SILType elementType;
|
|
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc, B) ||
|
|
parseVerbatim("of") ||
|
|
parseTypedValueRef(tuple, B) ||
|
|
parseVerbatim("as") ||
|
|
parseSILType(elementType))
|
|
return true;
|
|
ResultVal = B.createTuplePackElementAddr(InstLoc, index, tuple, elementType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::TuplePackExtractInst: {
|
|
SILValue index, tuple;
|
|
SILType elementType;
|
|
if (parseValueRef(index, SILType::getPackIndexType(P.Context), InstLoc,
|
|
B) ||
|
|
parseVerbatim("of") || parseTypedValueRef(tuple, B) ||
|
|
parseVerbatim("as") || parseSILType(elementType))
|
|
return true;
|
|
ResultVal = B.createTuplePackExtract(InstLoc, index, tuple, elementType);
|
|
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(ExtendLifetime)
|
|
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)
|
|
UNARY_INSTRUCTION(FunctionExtractIsolation)
|
|
UNARY_INSTRUCTION(EndInitLetRef)
|
|
REFCOUNTING_INSTRUCTION(UnmanagedReleaseValue)
|
|
REFCOUNTING_INSTRUCTION(UnmanagedRetainValue)
|
|
REFCOUNTING_INSTRUCTION(UnmanagedAutoreleaseValue)
|
|
REFCOUNTING_INSTRUCTION(StrongRetain)
|
|
REFCOUNTING_INSTRUCTION(StrongRelease)
|
|
REFCOUNTING_INSTRUCTION(AutoreleaseValue)
|
|
REFCOUNTING_INSTRUCTION(ReleaseValue)
|
|
REFCOUNTING_INSTRUCTION(RetainValue)
|
|
REFCOUNTING_INSTRUCTION(ReleaseValueAddr)
|
|
REFCOUNTING_INSTRUCTION(RetainValueAddr)
|
|
UNARY_INSTRUCTION(UnownedCopyValue)
|
|
UNARY_INSTRUCTION(WeakCopyValue)
|
|
#define UNCHECKED_REF_STORAGE(Name, ...) \
|
|
UNARY_INSTRUCTION(StrongCopy##Name##Value)
|
|
#define NEVER_LOADABLE_CHECKED_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: {
|
|
PoisonRefs_t poisonRefs = DontPoisonRefs;
|
|
IsDeadEnd_t isDeadEnd = IsntDeadEnd;
|
|
StringRef attributeName;
|
|
SourceLoc attributeLoc;
|
|
while (parseSILOptional(attributeName, attributeLoc, *this)) {
|
|
if (attributeName == "poison")
|
|
poisonRefs = PoisonRefs;
|
|
else if (attributeName == "dead_end")
|
|
isDeadEnd = IsDeadEnd;
|
|
else {
|
|
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
|
|
attributeName, "destroy_value");
|
|
return true;
|
|
}
|
|
}
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDestroyValue(InstLoc, Val, poisonRefs, isDeadEnd);
|
|
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::EndCOWMutationAddrInst: {
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createEndCOWMutationAddr(InstLoc, Val);
|
|
break;
|
|
}
|
|
case SILInstructionKind::DestroyNotEscapedClosureInst: {
|
|
bool IsObjcVerificationType = false;
|
|
if (parseSILOptional(IsObjcVerificationType, *this, "objc"))
|
|
return true;
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDestroyNotEscapedClosure(
|
|
InstLoc, Val,
|
|
IsObjcVerificationType ? DestroyNotEscapedClosureInst::ObjCEscaping
|
|
: DestroyNotEscapedClosureInst::WithoutActuallyEscaping);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::DebugValueInst: {
|
|
PoisonRefs_t poisonRefs = DontPoisonRefs;
|
|
bool hasTrace = false;
|
|
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
|
|
DoesNotUseMoveableValueDebugInfo;
|
|
SILDebugVariable VarInfo;
|
|
|
|
// Allow for poison and moved to be in either order.
|
|
StringRef attributeName;
|
|
SourceLoc attributeLoc;
|
|
while (parseSILOptional(attributeName, attributeLoc, *this)) {
|
|
if (attributeName == "poison")
|
|
poisonRefs = PoisonRefs;
|
|
else if (attributeName == "trace")
|
|
hasTrace = true;
|
|
else if (attributeName == "moveable_value_debuginfo")
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
else {
|
|
P.diagnose(attributeLoc, diag::sil_invalid_attribute_for_instruction,
|
|
attributeName, "debug_value");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (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");
|
|
|
|
if (Val->getType().isMoveOnly())
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
|
|
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo, poisonRefs,
|
|
usesMoveableValueDebugInfo, hasTrace);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::DebugStepInst:
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDebugStep(InstLoc);
|
|
break;
|
|
|
|
case SILInstructionKind::SpecifyTestInst: {
|
|
// Parse the specification string.
|
|
if (P.Tok.getKind() != tok::string_literal) {
|
|
P.diagnose(P.Tok, diag::expected_sil_specify_test_body);
|
|
return true;
|
|
}
|
|
// Drop the double quotes.
|
|
unsigned numQuotes = P.Tok.isMultilineString() ? 4 : 1;
|
|
auto ArgumentsSpecification =
|
|
P.Tok.getText().drop_front(numQuotes).drop_back(numQuotes).trim();
|
|
P.consumeToken(tok::string_literal);
|
|
auto *tsi = B.createSpecifyTestInst(InstLoc, ArgumentsSpecification);
|
|
SmallVector<StringRef, 4> components;
|
|
test::getTestSpecificationComponents(ArgumentsSpecification, components);
|
|
for (auto component : components) {
|
|
auto offset = 0;
|
|
size_t nameStart = StringRef::npos;
|
|
while ((nameStart = component.find_if([](char c) { return c == '%'; },
|
|
offset)) != StringRef::npos) {
|
|
auto nameEnd = component.find_if_not(
|
|
[](char c) { return clang::isAsciiIdentifierContinue(c); },
|
|
nameStart + 1);
|
|
if (nameEnd == StringRef::npos)
|
|
nameEnd = component.size();
|
|
auto name = component.substr(nameStart, nameEnd);
|
|
component = component.drop_front(nameEnd);
|
|
if (nameStart + 1 == nameEnd) {
|
|
continue;
|
|
}
|
|
auto *&entry = LocalValues[name];
|
|
if (entry) {
|
|
tsi->setValueForName(name, entry);
|
|
} else {
|
|
TestSpecsWithRefs[name].push_back(tsi);
|
|
}
|
|
}
|
|
}
|
|
ResultVal = tsi;
|
|
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::ImplicitActorToOpaqueIsolationCastInst: {
|
|
SourceLoc ValueLoc;
|
|
SILValue Value;
|
|
|
|
if (parseTypedValueRef(Value, ValueLoc, B) ||
|
|
parseSILDebugLocation(InstLoc, B)) {
|
|
return true;
|
|
}
|
|
|
|
if (B.getFunction().hasOwnership()) {
|
|
if (Value->getOwnershipKind() != OwnershipKind::Guaranteed) {
|
|
P.diagnose(ValueLoc, diag::sil_operand_has_wrong_ownership_kind,
|
|
Value->getOwnershipKind().asString(),
|
|
OwnershipKind(OwnershipKind::Guaranteed).asString());
|
|
return true;
|
|
}
|
|
}
|
|
|
|
ResultVal = B.createImplicitActorToOpaqueIsolationCast(InstLoc, Value);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::MoveValueInst: {
|
|
bool allowsDiagnostics = false;
|
|
auto isLexical = IsNotLexical;
|
|
auto hasPointerEscape = DoesNotHavePointerEscape;
|
|
auto fromVarDecl = IsNotFromVarDecl;
|
|
|
|
StringRef AttrName;
|
|
SourceLoc AttrLoc;
|
|
while (parseSILOptional(AttrName, AttrLoc, *this)) {
|
|
if (AttrName == "allows_diagnostics")
|
|
allowsDiagnostics = true;
|
|
else if (AttrName == "lexical")
|
|
isLexical = IsLexical;
|
|
else if (AttrName == "pointer_escape")
|
|
hasPointerEscape = HasPointerEscape;
|
|
else if (AttrName == "var_decl")
|
|
fromVarDecl = IsFromVarDecl;
|
|
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, hasPointerEscape,
|
|
fromVarDecl);
|
|
MVI->setAllowsDiagnostics(allowsDiagnostics);
|
|
ResultVal = MVI;
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::DropDeinitInst: {
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDropDeinit(InstLoc, Val);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::MarkUnresolvedNonCopyableValueInst: {
|
|
StringRef AttrName;
|
|
if (!parseSILOptional(AttrName, *this)) {
|
|
auto diag = diag::sil_markmustcheck_requires_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag);
|
|
return true;
|
|
}
|
|
|
|
auto Strict = MarkUnresolvedNonCopyableValueInst::IsNotStrict;
|
|
if (AttrName == "strict") {
|
|
Strict = MarkUnresolvedNonCopyableValueInst::IsStrict;
|
|
if (!parseSILOptional(AttrName, *this)) {
|
|
auto diag = diag::sil_markmustcheck_requires_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
using CheckKind = MarkUnresolvedNonCopyableValueInst::CheckKind;
|
|
CheckKind CKind =
|
|
llvm::StringSwitch<CheckKind>(AttrName)
|
|
.Case("consumable_and_assignable",
|
|
CheckKind::ConsumableAndAssignable)
|
|
.Case("no_consume_or_assign", CheckKind::NoConsumeOrAssign)
|
|
.Case("assignable_but_not_consumable",
|
|
CheckKind::AssignableButNotConsumable)
|
|
.Case("initable_but_not_consumable",
|
|
CheckKind::InitableButNotConsumable)
|
|
.Default(CheckKind::Invalid);
|
|
|
|
if (CKind == CheckKind::Invalid) {
|
|
auto diag = diag::sil_markmustcheck_invalid_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag, AttrName);
|
|
return true;
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
auto *MVI = B.createMarkUnresolvedNonCopyableValueInst(InstLoc, Val, CKind,
|
|
Strict);
|
|
ResultVal = MVI;
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::MarkUnresolvedReferenceBindingInst: {
|
|
StringRef AttrName;
|
|
if (!parseSILOptional(AttrName, *this)) {
|
|
auto diag = diag::sil_markuncheckedreferencebinding_requires_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag);
|
|
return true;
|
|
}
|
|
|
|
using Kind = MarkUnresolvedReferenceBindingInst::Kind;
|
|
Kind CKind = llvm::StringSwitch<Kind>(AttrName)
|
|
.Case("inout", Kind::InOut)
|
|
.Default(Kind::Invalid);
|
|
|
|
if (CKind == Kind::Invalid) {
|
|
auto diag = diag::sil_markuncheckedreferencebinding_invalid_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag, AttrName);
|
|
return true;
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
auto *MVI = B.createMarkUnresolvedReferenceBindingInst(InstLoc, Val, CKind);
|
|
ResultVal = MVI;
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst: {
|
|
StringRef AttrName;
|
|
if (!parseSILOptional(AttrName, *this)) {
|
|
auto diag = diag::sil_moveonlytocopyable_requires_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag);
|
|
return true;
|
|
}
|
|
|
|
OwnershipKind OwnershipKind =
|
|
llvm::StringSwitch<ValueOwnershipKind>(AttrName)
|
|
.Case("owned", OwnershipKind::Owned)
|
|
.Case("guaranteed", OwnershipKind::Guaranteed)
|
|
.Default(OwnershipKind::None);
|
|
|
|
if (OwnershipKind == OwnershipKind::None) {
|
|
auto diag = diag::sil_moveonlytocopyable_invalid_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag, AttrName);
|
|
return true;
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
if (!Val->getType().isObject()) {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_operand_not_object, "operand", OpcodeName);
|
|
return true;
|
|
}
|
|
|
|
if (Val->getType().isMoveOnlyWrapped()) {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_operand_has_incorrect_moveonlywrapped,
|
|
"operand", OpcodeName, 1);
|
|
return true;
|
|
}
|
|
|
|
if (OwnershipKind == OwnershipKind::Owned)
|
|
ResultVal = B.createOwnedCopyableToMoveOnlyWrapperValue(InstLoc, Val);
|
|
else
|
|
ResultVal =
|
|
B.createGuaranteedCopyableToMoveOnlyWrapperValue(InstLoc, Val);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst: {
|
|
StringRef AttrName;
|
|
if (!parseSILOptional(AttrName, *this)) {
|
|
auto diag = diag::sil_moveonlytocopyable_requires_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag);
|
|
return true;
|
|
}
|
|
|
|
OwnershipKind OwnershipKind =
|
|
llvm::StringSwitch<ValueOwnershipKind>(AttrName)
|
|
.Case("owned", OwnershipKind::Owned)
|
|
.Case("guaranteed", OwnershipKind::Guaranteed)
|
|
.Default(OwnershipKind::None);
|
|
|
|
if (OwnershipKind == OwnershipKind::None) {
|
|
auto diag = diag::sil_moveonlytocopyable_invalid_attribute;
|
|
P.diagnose(InstLoc.getSourceLoc(), diag, AttrName);
|
|
return true;
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
if (!Val->getType().isObject()) {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_operand_not_object, "operand", OpcodeName);
|
|
return true;
|
|
}
|
|
|
|
if (!Val->getType().isMoveOnlyWrapped()) {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_operand_has_incorrect_moveonlywrapped,
|
|
"operand", OpcodeName, 0);
|
|
return true;
|
|
}
|
|
|
|
if (OwnershipKind == OwnershipKind::Owned)
|
|
ResultVal = B.createOwnedMoveOnlyWrapperToCopyableValue(InstLoc, Val);
|
|
else
|
|
ResultVal =
|
|
B.createGuaranteedMoveOnlyWrapperToCopyableValue(InstLoc, Val);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::UncheckedOwnershipInst: {
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createUncheckedOwnership(InstLoc, Val);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::LoadInst: {
|
|
std::optional<LoadOwnershipQualifier> Qualifier;
|
|
SourceLoc AddrLoc;
|
|
auto parseLoadOwnership = [](StringRef Str) {
|
|
return llvm::StringSwitch<std::optional<LoadOwnershipQualifier>>(Str)
|
|
.Case("take", LoadOwnershipQualifier::Take)
|
|
.Case("copy", LoadOwnershipQualifier::Copy)
|
|
.Case("trivial", LoadOwnershipQualifier::Trivial)
|
|
.Default(std::nullopt);
|
|
};
|
|
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.value());
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::LoadBorrowInst: {
|
|
SourceLoc AddrLoc;
|
|
|
|
bool IsUnchecked = false;
|
|
StringRef AttrName;
|
|
SourceLoc AttrLoc;
|
|
if (parseSILOptional(AttrName, AttrLoc, *this)) {
|
|
if (AttrName == "unchecked") {
|
|
IsUnchecked = true;
|
|
} else {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_invalid_attribute_for_instruction, AttrName,
|
|
"load_borrow");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, AddrLoc, B) ||
|
|
parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
auto LB = B.createLoadBorrow(InstLoc, Val);
|
|
LB->setUnchecked(IsUnchecked);
|
|
ResultVal = LB;
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::BeginBorrowInst: {
|
|
SourceLoc AddrLoc;
|
|
|
|
auto isLexical = IsNotLexical;
|
|
auto hasPointerEscape = DoesNotHavePointerEscape;
|
|
auto fromVarDecl = IsNotFromVarDecl;
|
|
auto fixed = BeginBorrowInst::IsNotFixed;
|
|
|
|
StringRef AttrName;
|
|
SourceLoc AttrLoc;
|
|
while (parseSILOptional(AttrName, AttrLoc, *this)) {
|
|
if (AttrName == "lexical")
|
|
isLexical = IsLexical;
|
|
else if (AttrName == "pointer_escape")
|
|
hasPointerEscape = HasPointerEscape;
|
|
else if (AttrName == "var_decl")
|
|
fromVarDecl = IsFromVarDecl;
|
|
else if (AttrName == "fixed")
|
|
fixed = BeginBorrowInst::IsFixed;
|
|
else {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_invalid_attribute_for_instruction, AttrName,
|
|
"begin_borrow");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (parseTypedValueRef(Val, AddrLoc, B) ||
|
|
parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createBeginBorrow(InstLoc, Val, isLexical, hasPointerEscape,
|
|
fromVarDecl, fixed);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::BorrowedFromInst: {
|
|
SILValue guaranteedValue;
|
|
if (parseTypedValueRef(guaranteedValue, B))
|
|
return true;
|
|
|
|
if (parseVerbatim("from") ||
|
|
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
|
|
return true;
|
|
|
|
if (P.Tok.isNot(tok::r_paren)) {
|
|
do {
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
OpList.push_back(Val);
|
|
} while (P.consumeIf(tok::comma));
|
|
}
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
|
|
return true;
|
|
|
|
ResultVal = B.createBorrowedFrom(InstLoc, guaranteedValue, OpList);
|
|
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:
|
|
case SILInstructionKind::MarkDependenceAddrInst: {
|
|
std::optional<MarkDependenceKind> dependenceKind;
|
|
SILValue Base;
|
|
auto parseDependenceKind = [](StringRef Str) {
|
|
return llvm::StringSwitch<std::optional<MarkDependenceKind>>(Str)
|
|
.Case("unresolved", MarkDependenceKind::Unresolved)
|
|
.Case("nonescaping", MarkDependenceKind::NonEscaping)
|
|
.Default(std::nullopt);
|
|
};
|
|
if (parseSILQualifier<MarkDependenceKind>(dependenceKind,
|
|
parseDependenceKind)
|
|
|| parseTypedValueRef(Val, B) || parseVerbatim("on")
|
|
|| parseTypedValueRef(Base, B)) {
|
|
return true;
|
|
}
|
|
if (!dependenceKind) {
|
|
dependenceKind = MarkDependenceKind::Escaping;
|
|
}
|
|
if (Opcode == SILInstructionKind::MarkDependenceInst) {
|
|
ValueOwnershipKind forwardingOwnership = Val->getOwnershipKind();
|
|
if (parseForwardingOwnershipKind(forwardingOwnership)
|
|
|| parseSILDebugLocation(InstLoc, B)) {
|
|
return true;
|
|
}
|
|
ResultVal = B.createMarkDependence(InstLoc, Val, Base,
|
|
forwardingOwnership,
|
|
dependenceKind.value());
|
|
} else {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createMarkDependenceAddr(InstLoc, Val, Base,
|
|
dependenceKind.value());
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::BeginDeallocRefInst: {
|
|
SILValue allocation;
|
|
if (parseTypedValueRef(Val, B) || parseVerbatim("of") ||
|
|
parseTypedValueRef(allocation, B) ||
|
|
parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createBeginDeallocRef(InstLoc, Val, allocation);
|
|
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;
|
|
GenericSignature patternSig;
|
|
CanType rootType;
|
|
StringRef objcString;
|
|
SmallVector<SILType, 4> operandTypes;
|
|
{
|
|
patternParams = P.maybeParseGenericParams().getPtrOrNull();
|
|
patternSig = 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, patternSig, 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,
|
|
patternSig, 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, ContextGenericSig, ContextGenericParams))
|
|
return true;
|
|
|
|
SubstitutionMap subMap;
|
|
if (!parsedSubs.empty()) {
|
|
if (!patternSig) {
|
|
P.diagnose(InstLoc.getSourceLoc(),
|
|
diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
|
|
subMap = getApplySubstitutionsFromParsed(*this, patternSig, 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 (patternSig) {
|
|
canSig = patternSig.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;
|
|
}
|
|
|
|
case SILInstructionKind::ThunkInst: {
|
|
// We have to parse a sil optional.
|
|
StringRef attrName;
|
|
if (!parseSILOptional(attrName, *this)) {
|
|
P.diagnose(OpcodeLoc, diag::sil_failed_to_parse_sil_optional);
|
|
return true;
|
|
}
|
|
|
|
auto kind = llvm::StringSwitch<ThunkInst::Kind>(attrName)
|
|
.Case("identity", ThunkInst::Kind::Identity)
|
|
.Default(ThunkInst::Kind::Invalid);
|
|
if (!kind) {
|
|
P.diagnose(OpcodeLoc, diag::sil_thunkinst_failed_to_parse_kind, attrName);
|
|
return true;
|
|
}
|
|
|
|
UnresolvedValueName fnName;
|
|
if (parseValueName(fnName)) {
|
|
return true;
|
|
}
|
|
|
|
SmallVector<ParsedSubstitution, 4> parsedSubs;
|
|
if (parseSubstitutions(parsedSubs))
|
|
return true;
|
|
|
|
// TODO: When we support full parameters, add them here.
|
|
SILType thunkTy;
|
|
SourceLoc TypeLoc;
|
|
GenericSignature genericSig;
|
|
GenericParamList *genericParams = nullptr;
|
|
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(") ||
|
|
P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") ||
|
|
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
|
|
parseSILType(thunkTy, TypeLoc, genericSig, genericParams))
|
|
return true;
|
|
|
|
auto FTI = thunkTy.getAs<SILFunctionType>();
|
|
if (!FTI) {
|
|
P.diagnose(TypeLoc, diag::expected_sil_type_kind, "be a function");
|
|
return true;
|
|
}
|
|
|
|
SubstitutionMap subs;
|
|
if (!parsedSubs.empty()) {
|
|
if (!genericSig) {
|
|
P.diagnose(TypeLoc, diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
subs = getApplySubstitutionsFromParsed(*this, genericSig, parsedSubs);
|
|
if (!subs)
|
|
return true;
|
|
}
|
|
|
|
if (parseSILDebugLocation(InstLoc, B)) {
|
|
return true;
|
|
}
|
|
|
|
SILValue fnVal = getLocalValue(fnName, thunkTy, InstLoc, B);
|
|
ResultVal = B.createThunk(InstLoc, fnVal, kind, subs);
|
|
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::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;
|
|
bool needsStackProtection = false;
|
|
if (Opcode == SILInstructionKind::ConvertEscapeToNoEscapeInst) {
|
|
StringRef attrName;
|
|
if (parseSILOptional(attrName, *this)) {
|
|
if (attrName == "not_guaranteed")
|
|
not_guaranteed = true;
|
|
else
|
|
return true;
|
|
}
|
|
} if (Opcode == SILInstructionKind::AddressToPointerInst) {
|
|
if (parseSILOptional(needsStackProtection, *this, "stack_protection"))
|
|
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 == "without_actually_escaping")
|
|
without_actually_escaping = true;
|
|
else
|
|
return true;
|
|
}
|
|
}
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
|
|
ValueOwnershipKind forwardingOwnership = Val->getOwnershipKind();
|
|
if (ForwardingInstruction::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, needsStackProtection);
|
|
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::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;
|
|
SILOptionalAttrValue parsedValue;
|
|
SourceLoc parsedValueLoc;
|
|
while (parseSILOptional(attr, ToLoc, parsedValue, parsedValueLoc, *this)) {
|
|
if (attr.empty())
|
|
return true;
|
|
|
|
if (attr == "strict")
|
|
isStrict = true;
|
|
|
|
if (attr == "invariant")
|
|
isInvariant = true;
|
|
|
|
if (attr == "align")
|
|
alignment = llvm::Align(std::get<uint64_t>(*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: {
|
|
CheckedCastInstOptions options = parseCheckedCastInstOptions(nullptr);
|
|
|
|
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<std::optional<CastConsumptionKind>>(
|
|
consumptionKindToken.str())
|
|
.Case("take_always", CastConsumptionKind::TakeAlways)
|
|
.Case("take_on_success", CastConsumptionKind::TakeOnSuccess)
|
|
.Case("copy_on_success", CastConsumptionKind::CopyOnSuccess)
|
|
.Default(std::nullopt);
|
|
|
|
if (!kind) {
|
|
P.diagnose(consumptionKindLoc, diag::expected_tok_in_sil_instr,
|
|
"cast consumption kind");
|
|
return true;
|
|
}
|
|
auto consumptionKind = kind.value();
|
|
|
|
if (parseSourceAndDestAddress() || parseConditionalBranchDestinations() ||
|
|
parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createCheckedCastAddrBranch(
|
|
InstLoc, options, 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: {
|
|
CheckedCastInstOptions options = parseCheckedCastInstOptions(nullptr);
|
|
|
|
if (parseSourceAndDestAddress() || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createUnconditionalCheckedCastAddr(
|
|
InstLoc, options, SourceAddr, SourceType,
|
|
DestAddr, TargetType);
|
|
break;
|
|
}
|
|
case SILInstructionKind::UnconditionalCheckedCastInst: {
|
|
CheckedCastInstOptions options = parseCheckedCastInstOptions(nullptr);
|
|
|
|
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, options, Val,
|
|
F->getLoweredType(opaque, TargetType), TargetType,
|
|
forwardingOwnership);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::CheckedCastBranchInst: {
|
|
bool isExact = false;
|
|
CheckedCastInstOptions options = parseCheckedCastInstOptions(&isExact);
|
|
|
|
if (parseASTType(SourceType) || parseVerbatim("in"))
|
|
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, options, Val, SourceType,
|
|
F->getLoweredType(opaque, TargetType), TargetType,
|
|
getBBForReference(SuccessBBName, SuccessBBLoc),
|
|
getBBForReference(FailureBBName, FailureBBLoc), forwardingOwnership);
|
|
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 if (KindId.str() == "out")
|
|
Kind = MarkUninitializedInst::Out;
|
|
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;
|
|
std::optional<StoreOwnershipQualifier> StoreQualifier;
|
|
std::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<std::optional<StoreOwnershipQualifier>>(Str)
|
|
.Case("init", StoreOwnershipQualifier::Init)
|
|
.Case("assign", StoreOwnershipQualifier::Assign)
|
|
.Case("trivial", StoreOwnershipQualifier::Trivial)
|
|
.Default(std::nullopt);
|
|
};
|
|
if (IsStore
|
|
&& parseSILQualifier<StoreOwnershipQualifier>(StoreQualifier,
|
|
parseStoreOwnership))
|
|
return true;
|
|
|
|
auto parseAssignOwnership = [](StringRef Str) {
|
|
return llvm::StringSwitch<std::optional<AssignOwnershipQualifier>>(Str)
|
|
.Case("reassign", AssignOwnershipQualifier::Reassign)
|
|
.Case("reinit", AssignOwnershipQualifier::Reinit)
|
|
.Case("init", AssignOwnershipQualifier::Init)
|
|
.Default(std::nullopt);
|
|
};
|
|
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.value());
|
|
} else {
|
|
assert(IsAssign);
|
|
if (!AssignQualifier)
|
|
AssignQualifier = AssignOwnershipQualifier::Unknown;
|
|
|
|
ResultVal =
|
|
B.createAssign(InstLoc, getLocalValue(From, ValType, InstLoc, B),
|
|
AddrVal, AssignQualifier.value());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::MoveOnlyWrapperToCopyableAddrInst: {
|
|
SILValue addrVal;
|
|
SourceLoc addrLoc;
|
|
if (parseTypedValueRef(addrVal, addrLoc, 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 (!addrVal->getType().isMoveOnlyWrapped()) {
|
|
P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped,
|
|
"operand", OpcodeName, 0);
|
|
return true;
|
|
}
|
|
|
|
ResultVal = B.createMoveOnlyWrapperToCopyableAddr(InstLoc, addrVal);
|
|
break;
|
|
}
|
|
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst: {
|
|
SILValue addrVal;
|
|
SourceLoc addrLoc;
|
|
if (parseTypedValueRef(addrVal, addrLoc, B))
|
|
return true;
|
|
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
if (!addrVal->getType().is<SILBoxType>()) {
|
|
P.diagnose(addrLoc, diag::sil_box_expected, OpcodeName);
|
|
return true;
|
|
}
|
|
|
|
if (!addrVal->getType().isBoxedMoveOnlyWrappedType(
|
|
addrVal->getFunction())) {
|
|
P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped,
|
|
"operand", OpcodeName, 0);
|
|
return true;
|
|
}
|
|
|
|
ResultVal = B.createMoveOnlyWrapperToCopyableBox(InstLoc, addrVal);
|
|
break;
|
|
}
|
|
case SILInstructionKind::CopyableToMoveOnlyWrapperAddrInst: {
|
|
SILValue addrVal;
|
|
SourceLoc addrLoc;
|
|
if (parseTypedValueRef(addrVal, addrLoc, 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 (addrVal->getType().isMoveOnlyWrapped()) {
|
|
P.diagnose(addrLoc, diag::sil_operand_has_incorrect_moveonlywrapped,
|
|
"operand", OpcodeName, 1);
|
|
return true;
|
|
}
|
|
|
|
ResultVal = B.createCopyableToMoveOnlyWrapperAddr(InstLoc, addrVal);
|
|
break;
|
|
}
|
|
|
|
case SILInstructionKind::AssignOrInitInst: {
|
|
ValueDecl *Prop;
|
|
SILValue Self, Src, InitFn, SetFn;
|
|
AssignOrInitInst::Mode Mode;
|
|
llvm::SmallVector<unsigned, 2> assignments;
|
|
|
|
if (parseAssignOrInitMode(Mode, *this) ||
|
|
parseAssignOrInitAssignments(assignments, *this) ||
|
|
parseSILDottedPath(Prop) ||
|
|
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
|
|
parseVerbatim("self") || parseTypedValueRef(Self, B) ||
|
|
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
|
|
parseVerbatim("value") || parseTypedValueRef(Src, 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;
|
|
|
|
auto *AI = B.createAssignOrInit(InstLoc, cast<VarDecl>(Prop), Self, Src,
|
|
InitFn, SetFn, Mode);
|
|
|
|
for (unsigned index : assignments)
|
|
AI->markAsInitialized(index);
|
|
|
|
ResultVal = AI;
|
|
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 == "signed") {
|
|
setEnforcement(SILAccessEnforcement::Signed);
|
|
} 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_attr_name, 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, "init")) ||
|
|
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::AllocPackInst: {
|
|
SILType Ty;
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
|
|
ResultVal = B.createAllocPack(InstLoc, Ty);
|
|
break;
|
|
}
|
|
case SILInstructionKind::AllocPackMetadataInst: {
|
|
SILType Ty;
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
|
|
ResultVal = B.createAllocPackMetadata(InstLoc, Ty);
|
|
break;
|
|
}
|
|
case SILInstructionKind::AllocStackInst: {
|
|
auto hasDynamicLifetime = DoesNotHaveDynamicLifetime;
|
|
auto isLexical = IsNotLexical;
|
|
auto isFromVarDecl = IsNotFromVarDecl;
|
|
UsesMoveableValueDebugInfo_t usesMoveableValueDebugInfo =
|
|
DoesNotUseMoveableValueDebugInfo;
|
|
|
|
StringRef attributeName;
|
|
SourceLoc attributeLoc;
|
|
while (parseSILOptional(attributeName, attributeLoc, *this)) {
|
|
if (attributeName == "dynamic_lifetime")
|
|
hasDynamicLifetime = HasDynamicLifetime;
|
|
else if (attributeName == "lexical")
|
|
isLexical = IsLexical;
|
|
else if (attributeName == "var_decl")
|
|
isFromVarDecl = IsFromVarDecl;
|
|
else if (attributeName == "moveable_value_debuginfo")
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
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;
|
|
|
|
if (Ty.isMoveOnly())
|
|
usesMoveableValueDebugInfo = UsesMoveableValueDebugInfo;
|
|
|
|
// 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, isFromVarDecl,
|
|
usesMoveableValueDebugInfo);
|
|
else
|
|
ResultVal =
|
|
B.createAllocStack(InstLoc, Ty, {}, hasDynamicLifetime, isLexical,
|
|
isFromVarDecl, usesMoveableValueDebugInfo);
|
|
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;
|
|
bool isBare = 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 == "bare" && Opcode == SILInstructionKind::AllocRefInst) {
|
|
isBare = 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) {
|
|
ResultVal = B.createAllocRefDynamic(InstLoc, Metadata, ObjectType, IsObjC,
|
|
OnStack,
|
|
ElementTypes, ElementCounts);
|
|
} else {
|
|
ResultVal = B.createAllocRef(InstLoc, ObjectType, IsObjC, OnStack, isBare,
|
|
ElementTypes, ElementCounts);
|
|
}
|
|
break;
|
|
}
|
|
case SILInstructionKind::IgnoredUseInst:
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createIgnoredUse(InstLoc, Val);
|
|
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::DeallocPackInst:
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDeallocPack(InstLoc, Val);
|
|
break;
|
|
case SILInstructionKind::DeallocPackMetadataInst:
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createDeallocPackMetadata(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: {
|
|
bool isDeadEnd = false;
|
|
if (parseSILOptional(isDeadEnd, *this, "dead_end") ||
|
|
parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal = B.createDeallocBox(InstLoc, Val, IsDeadEnd_t(isDeadEnd));
|
|
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().getRawASTType());
|
|
} 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() ? getSILValueOwnership(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().getRawASTType());
|
|
} 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::TupleAddrConstructorInst: {
|
|
// First parse [init] or [assign].
|
|
StringRef InitOrAssign;
|
|
SILValue DestValue;
|
|
SourceLoc WithLoc, DestToken;
|
|
Identifier WithToken;
|
|
|
|
if (!parseSILOptional(InitOrAssign, *this) ||
|
|
parseTypedValueRef(DestValue, DestToken, B) ||
|
|
parseSILIdentifier(WithToken, WithLoc,
|
|
diag::expected_tok_in_sil_instr, "with"))
|
|
return true;
|
|
|
|
auto IsInit =
|
|
llvm::StringSwitch<std::optional<IsInitialization_t>>(InitOrAssign)
|
|
.Case("init", IsInitialization_t::IsInitialization)
|
|
.Case("assign", IsInitialization_t::IsNotInitialization)
|
|
.Default({});
|
|
if (!IsInit) {
|
|
P.diagnose(WithLoc, diag::expected_tok_in_sil_instr,
|
|
"[init] | [assign]");
|
|
return true;
|
|
}
|
|
|
|
if (WithToken.str() != "with") {
|
|
P.diagnose(WithLoc, diag::expected_tok_in_sil_instr, "with");
|
|
return true;
|
|
}
|
|
|
|
// If there is no type, parse the simple form.
|
|
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "(")) {
|
|
P.diagnose(WithLoc, diag::expected_tok_in_sil_instr, "(");
|
|
return true;
|
|
}
|
|
|
|
// Then parse our tuple element list.
|
|
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().getRawASTType());
|
|
} while (P.consumeIf(tok::comma));
|
|
}
|
|
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")")) {
|
|
P.diagnose(WithLoc, diag::expected_tok_in_sil_instr, ")");
|
|
return true;
|
|
}
|
|
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
ResultVal =
|
|
B.createTupleAddrConstructor(InstLoc, DestValue, OpList, *IsInit);
|
|
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().castTo<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::ReturnBorrowInst: {
|
|
SILValue returnValue;
|
|
if (parseTypedValueRef(returnValue, B))
|
|
return true;
|
|
|
|
if (parseVerbatim("from_scopes") ||
|
|
P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
|
|
return true;
|
|
|
|
if (P.Tok.isNot(tok::r_paren)) {
|
|
do {
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
OpList.push_back(Val);
|
|
} while (P.consumeIf(tok::comma));
|
|
}
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
|
|
return true;
|
|
|
|
ResultVal = B.createReturnBorrow(InstLoc, returnValue, OpList);
|
|
break;
|
|
}
|
|
case SILInstructionKind::ThrowInst: {
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createThrow(InstLoc, Val);
|
|
break;
|
|
}
|
|
case SILInstructionKind::ThrowAddrInst: {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createThrowAddr(InstLoc);
|
|
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;
|
|
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 = 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, "init") ||
|
|
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::ExplicitCopyAddrInst: {
|
|
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, "init") ||
|
|
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.createExplicitCopyAddr(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;
|
|
|
|
if (Opcode == SILInstructionKind::StructInst) {
|
|
ValueOwnershipKind forwardingOwnership =
|
|
F && F->hasOwnership() ? getSILValueOwnership(OpList, Ty)
|
|
: ValueOwnershipKind(OwnershipKind::None);
|
|
if (parseForwardingOwnershipKind(forwardingOwnership)
|
|
|| parseSILDebugLocation(InstLoc, B)) {
|
|
return true;
|
|
}
|
|
ResultVal = B.createStruct(InstLoc, Ty, OpList, forwardingOwnership);
|
|
} else {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createObject(InstLoc, Ty, OpList, NumBaseElems );
|
|
}
|
|
break;
|
|
}
|
|
case SILInstructionKind::VectorInst: {
|
|
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
|
|
return true;
|
|
|
|
// Parse a list of SILValue.
|
|
do {
|
|
if (parseTypedValueRef(Val, B))
|
|
return true;
|
|
OpList.push_back(Val);
|
|
} while (P.consumeIf(tok::comma));
|
|
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
|
|
return true;
|
|
ResultVal = B.createVector(InstLoc, OpList);
|
|
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;
|
|
bool needsStackProtection = false;
|
|
if (parseSILOptional(needsStackProtection, *this, "stack_protection") ||
|
|
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, needsStackProtection);
|
|
break;
|
|
}
|
|
case SILInstructionKind::VectorBaseAddrInst: {
|
|
if (parseTypedValueRef(Val, B) || parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
ResultVal = B.createVectorBaseAddr(InstLoc, Val);
|
|
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;
|
|
bool isBare = false;
|
|
if (P.consumeIf(tok::l_square)) {
|
|
Identifier Id;
|
|
parseSILIdentifier(Id, diag::expected_in_attribute_list);
|
|
StringRef Optional = Id.str();
|
|
if (Optional == "bare" && Opcode == SILInstructionKind::GlobalValueInst) {
|
|
isBare = true;
|
|
} else {
|
|
return true;
|
|
}
|
|
P.parseToken(tok::r_square, diag::expected_in_attribute_list);
|
|
}
|
|
|
|
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))
|
|
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;
|
|
}
|
|
|
|
SILValue dependencyToken;
|
|
if (Opcode == SILInstructionKind::GlobalAddrInst && P.Tok.isContextualKeyword("depends_on")) {
|
|
P.consumeToken();
|
|
if (parseValueRef(dependencyToken, SILType::getSILTokenType(P.Context),
|
|
RegularLocation(P.Tok.getLoc()), B)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
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().getRawASTType(),
|
|
Ty.getRawASTType());
|
|
return true;
|
|
}
|
|
|
|
if (Opcode == SILInstructionKind::GlobalAddrInst) {
|
|
ResultVal = B.createGlobalAddr(InstLoc, global, dependencyToken);
|
|
} else {
|
|
ResultVal = B.createGlobalValue(InstLoc, global, isBare);
|
|
}
|
|
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;
|
|
std::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, std::nullopt, ProfileCounter());
|
|
} 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, std::nullopt,
|
|
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::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 =
|
|
ExistentialArchetypeType::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;
|
|
GenericSignature invokeGenericSig;
|
|
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, invokeGenericSig, 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 (!invokeGenericSig) {
|
|
P.diagnose(typeLoc, diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
|
|
subMap = getApplySubstitutionsFromParsed(*this, invokeGenericSig,
|
|
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;
|
|
}
|
|
std::optional<std::pair<SILValue, SILValue>> derivativeFunctions =
|
|
std::nullopt;
|
|
// 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.
|
|
std::optional<SILValue> transpose = std::nullopt;
|
|
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.
|
|
std::optional<SILType> extracteeType = std::nullopt;
|
|
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.
|
|
std::optional<SILType> functionType = std::nullopt;
|
|
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;
|
|
}
|
|
case SILInstructionKind::HasSymbolInst: {
|
|
// 'has_symbol' sil-decl-ref
|
|
SILDeclRef declRef;
|
|
if (parseSILDeclRef(declRef))
|
|
return true;
|
|
|
|
ResultVal = B.createHasSymbol(InstLoc, declRef.getDecl());
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// sil-instruction-result ::= sil-value-name '='
|
|
/// sil-instruction-result ::= '(' sil-value-name? ')'
|
|
/// sil-instruction-result ::= '(' sil-value-name (',' sil-value-name)* ')'
|
|
/// sil-instruction-source-info ::= (',' sil-scope-ref)? (',' sil-loc)?
|
|
/// sil-instruction-def ::=
|
|
/// (sil-instruction-result '=')? sil-instruction sil-instruction-source-info
|
|
bool SILParser::parseSILInstruction(SILBuilder &B) {
|
|
// We require SIL instructions to be at the start of a line to assist
|
|
// recovery.
|
|
if (!P.Tok.isAtStartOfLine()) {
|
|
P.diagnose(P.Tok, diag::expected_sil_instr_start_of_line);
|
|
return true;
|
|
}
|
|
|
|
if (!B.hasValidInsertionPoint()) {
|
|
P.diagnose(P.Tok, diag::expected_sil_block_name);
|
|
return true;
|
|
}
|
|
|
|
SmallVector<Located<StringRef>, 4> resultNames;
|
|
SourceLoc resultClauseBegin;
|
|
|
|
// If the instruction has a name '%foo =', parse it.
|
|
if (P.Tok.is(tok::sil_local_name)) {
|
|
resultClauseBegin = P.Tok.getLoc();
|
|
resultNames.push_back({P.Tok.getText(), P.Tok.getLoc()});
|
|
P.consumeToken(tok::sil_local_name);
|
|
|
|
// If the instruction has a '(%foo, %bar) = ', parse it.
|
|
} else if (P.consumeIf(tok::l_paren)) {
|
|
resultClauseBegin = P.PreviousLoc;
|
|
|
|
if (!P.consumeIf(tok::r_paren)) {
|
|
while (true) {
|
|
if (!P.Tok.is(tok::sil_local_name)) {
|
|
P.diagnose(P.Tok, diag::expected_sil_value_name);
|
|
return true;
|
|
}
|
|
|
|
resultNames.push_back({P.Tok.getText(), P.Tok.getLoc()});
|
|
P.consumeToken(tok::sil_local_name);
|
|
|
|
if (P.consumeIf(tok::comma))
|
|
continue;
|
|
if (P.consumeIf(tok::r_paren))
|
|
break;
|
|
|
|
P.diagnose(P.Tok, diag::expected_tok_in_sil_instr, ",");
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (resultClauseBegin.isValid()) {
|
|
if (P.parseToken(tok::equal, diag::expected_equal_in_sil_instr))
|
|
return true;
|
|
}
|
|
|
|
SILInstructionKind Opcode;
|
|
SourceLoc OpcodeLoc;
|
|
StringRef OpcodeName;
|
|
|
|
// Parse the opcode name.
|
|
if (parseSILOpcode(Opcode, OpcodeLoc, OpcodeName))
|
|
return true;
|
|
|
|
// Perform opcode specific parsing.
|
|
SILInstruction *ResultVal;
|
|
if (parseSpecificSILInstruction(B, Opcode, OpcodeLoc, OpcodeName, ResultVal))
|
|
return true;
|
|
|
|
// Match the results clause if we had one.
|
|
if (resultClauseBegin.isValid()) {
|
|
auto results = ResultVal->getResults();
|
|
if (results.size() != resultNames.size()) {
|
|
P.diagnose(resultClauseBegin, diag::wrong_result_count_in_sil_instr,
|
|
results.size());
|
|
} else {
|
|
for (size_t i : indices(results)) {
|
|
setLocalValue(results[i], resultNames[i].Item, resultNames[i].Loc);
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseCallInstruction(SILLocation InstLoc,
|
|
SILInstructionKind Opcode, SILBuilder &B,
|
|
SILInstruction *&ResultVal) {
|
|
UnresolvedValueName FnName;
|
|
SmallVector<UnresolvedValueName, 4> ArgNames;
|
|
|
|
auto PartialApplyConvention = ParameterConvention::Direct_Owned;
|
|
auto PartialApplyIsolation = SILFunctionTypeIsolation::forUnknown();
|
|
ApplyOptions ApplyOpts;
|
|
bool IsNoEscape = false;
|
|
|
|
StringRef AttrName;
|
|
SourceLoc AttrLoc;
|
|
SILOptionalAttrValue AttrValue;
|
|
SourceLoc AttrValueLoc;
|
|
std::optional<ApplyIsolationCrossing> isolationCrossing;
|
|
|
|
while (parseSILOptional(AttrName, AttrLoc, AttrValue, AttrValueLoc, *this)) {
|
|
if (AttrName == "nothrow") {
|
|
assert(!bool(AttrValue));
|
|
ApplyOpts |= ApplyFlags::DoesNotThrow;
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "noasync") {
|
|
assert(!bool(AttrValue));
|
|
ApplyOpts |= ApplyFlags::DoesNotAwait;
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "callee_guaranteed") {
|
|
assert(!bool(AttrValue));
|
|
PartialApplyConvention = ParameterConvention::Direct_Guaranteed;
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "isolated_any") {
|
|
assert(!bool(AttrValue));
|
|
PartialApplyIsolation = SILFunctionTypeIsolation::forErased();
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "on_stack") {
|
|
assert(!bool(AttrValue));
|
|
IsNoEscape = true;
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "callee_isolation") {
|
|
auto applyIsolation =
|
|
ActorIsolation::forSILString(std::get<StringRef>(*AttrValue));
|
|
if (!applyIsolation) {
|
|
P.diagnose(AttrValueLoc, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
if (!isolationCrossing)
|
|
isolationCrossing.emplace();
|
|
isolationCrossing->CalleeIsolation = *applyIsolation;
|
|
continue;
|
|
}
|
|
|
|
if (AttrName == "caller_isolation") {
|
|
auto applyIsolation =
|
|
ActorIsolation::forSILString(std::get<StringRef>(*AttrValue));
|
|
if (!applyIsolation) {
|
|
P.diagnose(AttrValueLoc, diag::expected_in_attribute_list);
|
|
return true;
|
|
}
|
|
if (!isolationCrossing)
|
|
isolationCrossing.emplace();
|
|
isolationCrossing->CallerIsolation = *applyIsolation;
|
|
continue;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
if (parseValueName(FnName))
|
|
return true;
|
|
SmallVector<ParsedSubstitution, 4> parsedSubs;
|
|
if (parseSubstitutions(parsedSubs))
|
|
return true;
|
|
|
|
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
|
|
return true;
|
|
|
|
if (P.Tok.isNot(tok::r_paren)) {
|
|
do {
|
|
UnresolvedValueName Arg;
|
|
if (parseValueName(Arg)) return true;
|
|
ArgNames.push_back(Arg);
|
|
} while (P.consumeIf(tok::comma));
|
|
}
|
|
|
|
SILType Ty;
|
|
SourceLoc TypeLoc;
|
|
GenericSignature GenericSig;
|
|
GenericParamList *GenericParams = nullptr;
|
|
if (P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")") ||
|
|
P.parseToken(tok::colon, diag::expected_tok_in_sil_instr, ":") ||
|
|
parseSILType(Ty, TypeLoc, GenericSig, GenericParams))
|
|
return true;
|
|
|
|
auto FTI = Ty.getAs<SILFunctionType>();
|
|
if (!FTI) {
|
|
P.diagnose(TypeLoc, diag::expected_sil_type_kind, "be a function");
|
|
return true;
|
|
}
|
|
|
|
SubstitutionMap subs;
|
|
if (!parsedSubs.empty()) {
|
|
if (!GenericSig) {
|
|
P.diagnose(TypeLoc, diag::sil_substitutions_on_non_polymorphic_type);
|
|
return true;
|
|
}
|
|
subs = getApplySubstitutionsFromParsed(*this, GenericSig, parsedSubs);
|
|
if (!subs)
|
|
return true;
|
|
}
|
|
|
|
SILValue FnVal = getLocalValue(FnName, Ty, InstLoc, B);
|
|
|
|
SILType FnTy = FnVal->getType();
|
|
CanSILFunctionType substFTI = FTI;
|
|
if (!subs.empty()) {
|
|
auto silFnTy = FnTy.castTo<SILFunctionType>();
|
|
substFTI =
|
|
silFnTy->substGenericArgs(SILMod, subs, B.getTypeExpansionContext());
|
|
FnTy = SILType::getPrimitiveObjectType(substFTI);
|
|
}
|
|
SILFunctionConventions substConv(substFTI, B.getModule());
|
|
|
|
// Validate the operand count.
|
|
if (substConv.getNumSILArguments() != ArgNames.size() &&
|
|
Opcode != SILInstructionKind::PartialApplyInst) {
|
|
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
|
|
"to have the same number of arg names as arg types");
|
|
return true;
|
|
}
|
|
|
|
// Validate the coroutine kind.
|
|
if (Opcode == SILInstructionKind::ApplyInst ||
|
|
Opcode == SILInstructionKind::TryApplyInst) {
|
|
if (FTI->getCoroutineKind() != SILCoroutineKind::None) {
|
|
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
|
|
"to not be a coroutine");
|
|
return true;
|
|
}
|
|
} else if (Opcode == SILInstructionKind::BeginApplyInst) {
|
|
if (FTI->getCoroutineKind() != SILCoroutineKind::YieldOnce &&
|
|
FTI->getCoroutineKind() != SILCoroutineKind::YieldOnce2) {
|
|
P.diagnose(TypeLoc, diag::expected_sil_type_kind,
|
|
"to be a yield_once coroutine");
|
|
return true;
|
|
}
|
|
} else {
|
|
assert(Opcode == SILInstructionKind::PartialApplyInst);
|
|
// partial_apply accepts all kinds of function
|
|
}
|
|
|
|
switch (Opcode) {
|
|
default: llvm_unreachable("Unexpected case");
|
|
case SILInstructionKind::ApplyInst : {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
unsigned ArgNo = 0;
|
|
SmallVector<SILValue, 4> Args;
|
|
for (auto &ArgName : ArgNames) {
|
|
SILType expectedTy =
|
|
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
|
|
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
|
|
}
|
|
|
|
ResultVal = B.createApply(InstLoc, FnVal, subs, Args, ApplyOpts, nullptr,
|
|
isolationCrossing);
|
|
break;
|
|
}
|
|
case SILInstructionKind::BeginApplyInst: {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
unsigned ArgNo = 0;
|
|
SmallVector<SILValue, 4> Args;
|
|
for (auto &ArgName : ArgNames) {
|
|
SILType expectedTy =
|
|
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
|
|
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
|
|
}
|
|
|
|
ResultVal = B.createBeginApply(InstLoc, FnVal, subs, Args, ApplyOpts,
|
|
nullptr, isolationCrossing);
|
|
break;
|
|
}
|
|
case SILInstructionKind::PartialApplyInst: {
|
|
if (parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
// Compute the result type of the partial_apply, based on which arguments
|
|
// are getting applied.
|
|
SmallVector<SILValue, 4> Args;
|
|
unsigned ArgNo = substConv.getNumSILArguments() - ArgNames.size();
|
|
for (auto &ArgName : ArgNames) {
|
|
SILType expectedTy =
|
|
substConv.getSILArgumentType(ArgNo++, B.getTypeExpansionContext());
|
|
Args.push_back(getLocalValue(ArgName, expectedTy, InstLoc, B));
|
|
}
|
|
|
|
if (isolationCrossing) {
|
|
if (isolationCrossing->getCalleeIsolation() !=
|
|
ActorIsolation::Unspecified) {
|
|
llvm::SmallString<64> name;
|
|
llvm::raw_svector_ostream os(name);
|
|
os << isolationCrossing->getCalleeIsolation();
|
|
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attr_name, name);
|
|
}
|
|
if (isolationCrossing->getCallerIsolation() !=
|
|
ActorIsolation::Unspecified) {
|
|
llvm::SmallString<64> name;
|
|
llvm::raw_svector_ostream os(name);
|
|
os << isolationCrossing->getCalleeIsolation();
|
|
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attr_name, name);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// FIXME: Why the arbitrary order difference in IRBuilder type argument?
|
|
ResultVal = B.createPartialApply(
|
|
InstLoc, FnVal, subs, Args, PartialApplyConvention,
|
|
PartialApplyIsolation,
|
|
IsNoEscape ? PartialApplyInst::OnStackKind::OnStack
|
|
: PartialApplyInst::OnStackKind::NotOnStack);
|
|
break;
|
|
}
|
|
case SILInstructionKind::TryApplyInst: {
|
|
Identifier normalBBName, errorBBName;
|
|
SourceLoc normalBBLoc, errorBBLoc;
|
|
if (P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
|
|
parseVerbatim("normal") ||
|
|
parseSILIdentifier(normalBBName, normalBBLoc,
|
|
diag::expected_sil_block_name) ||
|
|
P.parseToken(tok::comma, diag::expected_tok_in_sil_instr, ",") ||
|
|
parseVerbatim("error") ||
|
|
parseSILIdentifier(errorBBName, errorBBLoc,
|
|
diag::expected_sil_block_name) ||
|
|
parseSILDebugLocation(InstLoc, B))
|
|
return true;
|
|
|
|
unsigned argNo = 0;
|
|
SmallVector<SILValue, 4> args;
|
|
for (auto &argName : ArgNames) {
|
|
SILType expectedTy =
|
|
substConv.getSILArgumentType(argNo++, B.getTypeExpansionContext());
|
|
args.push_back(getLocalValue(argName, expectedTy, InstLoc, B));
|
|
}
|
|
|
|
SILBasicBlock *normalBB = getBBForReference(normalBBName, normalBBLoc);
|
|
SILBasicBlock *errorBB = getBBForReference(errorBBName, errorBBLoc);
|
|
ResultVal = B.createTryApply(InstLoc, FnVal, subs, args, normalBB, errorBB,
|
|
ApplyOpts, nullptr, isolationCrossing);
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool SILParser::parseSILFunctionRef(SILLocation InstLoc,
|
|
SILFunction *&ResultFn) {
|
|
Identifier Name;
|
|
SILType Ty;
|
|
SourceLoc Loc = P.Tok.getLoc();
|
|
if (parseGlobalName(Name) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) ||
|
|
parseSILType(Ty))
|
|
return true;
|
|
|
|
auto FnTy = Ty.getAs<SILFunctionType>();
|
|
if (!FnTy || !Ty.isObject()) {
|
|
P.diagnose(Loc, diag::expected_sil_function_type);
|
|
return true;
|
|
}
|
|
|
|
ResultFn = getGlobalNameForReference(Name, FnTy, Loc);
|
|
return false;
|
|
}
|
|
|
|
/// True if the current token sequence looks like the start of a SIL
|
|
/// instruction. This can be one of:
|
|
///
|
|
/// 1. %name
|
|
/// 2. ()
|
|
/// 3. (%name1
|
|
/// 4. identifier | keyword
|
|
/// where the identifier is not followed by a ':' or '(', or it is
|
|
/// followed by '(' and is an instruction name. The exceptions here
|
|
/// are for recognizing block names.
|
|
bool SILParser::isStartOfSILInstruction() {
|
|
if (P.Tok.is(tok::sil_local_name))
|
|
return true;
|
|
if (P.Tok.is(tok::l_paren) &&
|
|
(P.peekToken().is(tok::sil_local_name) || P.peekToken().is(tok::r_paren)))
|
|
return true;
|
|
if (P.Tok.is(tok::identifier) || P.Tok.isKeyword()) {
|
|
auto &peek = P.peekToken();
|
|
if (peek.is(tok::l_paren))
|
|
return getOpcodeByName(P.Tok.getText()).has_value();
|
|
return !peek.is(tok::colon);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// sil-basic-block:
|
|
/// sil-instruction+
|
|
/// identifier sil-bb-argument-list? ':' sil-instruction+
|
|
/// sil-bb-argument-list:
|
|
/// '(' sil-typed-valueref (',' sil-typed-valueref)+ ')'
|
|
bool SILParser::parseSILBasicBlock(SILBuilder &B) {
|
|
SILBasicBlock *BB;
|
|
|
|
// The basic block name is optional.
|
|
if (P.Tok.is(tok::sil_local_name)) {
|
|
BB = getBBForDefinition(Identifier(), SourceLoc());
|
|
} else {
|
|
Identifier BBName;
|
|
SourceLoc NameLoc;
|
|
if (parseSILIdentifier(BBName, NameLoc, diag::expected_sil_block_name))
|
|
return true;
|
|
|
|
BB = getBBForDefinition(BBName, NameLoc);
|
|
// For now, since we always assume that PhiArguments have
|
|
// OwnershipKind::None, do not parse or do anything special. Eventually
|
|
// we will parse the convention.
|
|
bool IsEntry = BB->isEntry();
|
|
|
|
// If there is a basic block argument list, process it.
|
|
if (P.consumeIf(tok::l_paren)) {
|
|
do {
|
|
SILType Ty;
|
|
ValueOwnershipKind OwnershipKind = OwnershipKind::None;
|
|
SourceLoc NameLoc;
|
|
StringRef Name = P.Tok.getText();
|
|
if (P.parseToken(tok::sil_local_name, NameLoc,
|
|
diag::expected_sil_value_name) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref))
|
|
return true;
|
|
|
|
bool foundNoImplicitCopy = false;
|
|
bool foundClosureCapture = false;
|
|
bool foundLexical = false;
|
|
bool foundEagerMove = false;
|
|
bool foundReborrow = false;
|
|
bool hasPointerEscape = false;
|
|
while (auto attributeName = parseOptionalAttribute(
|
|
{"noImplicitCopy", "_lexical", "_eagerMove",
|
|
"closureCapture", "reborrow", "pointer_escape"})) {
|
|
if (*attributeName == "noImplicitCopy")
|
|
foundNoImplicitCopy = true;
|
|
else if (*attributeName == "_lexical")
|
|
foundLexical = true;
|
|
else if (*attributeName == "_eagerMove")
|
|
foundEagerMove = true;
|
|
else if (*attributeName == "closureCapture")
|
|
foundClosureCapture = true;
|
|
else if (*attributeName == "reborrow")
|
|
foundReborrow = true;
|
|
else if (*attributeName == "pointer_escape")
|
|
hasPointerEscape = true;
|
|
else {
|
|
llvm_unreachable("Unexpected attribute!");
|
|
}
|
|
}
|
|
|
|
LifetimeAnnotation lifetime = LifetimeAnnotation::None;
|
|
if (foundEagerMove && foundLexical) {
|
|
P.diagnose(NameLoc, diag::sil_arg_both_lexical_and_eagerMove);
|
|
return true;
|
|
} else if (foundEagerMove) {
|
|
lifetime = LifetimeAnnotation::EagerMove;
|
|
} else if (foundLexical) {
|
|
lifetime = LifetimeAnnotation::Lexical;
|
|
}
|
|
|
|
// If SILOwnership is enabled and we are not assuming that we are
|
|
// parsing unqualified SIL, look for printed value ownership kinds.
|
|
if (F->hasOwnership()) {
|
|
if (P.Tok.is(tok::at_sign)) {
|
|
if (parseSILOwnership(OwnershipKind))
|
|
return true;
|
|
} else if (foundReborrow) {
|
|
OwnershipKind = OwnershipKind::Guaranteed;
|
|
}
|
|
}
|
|
|
|
if (parseSILType(Ty))
|
|
return true;
|
|
|
|
SILArgument *Arg;
|
|
if (IsEntry) {
|
|
auto *fArg = BB->createFunctionArgument(Ty);
|
|
fArg->setNoImplicitCopy(foundNoImplicitCopy);
|
|
fArg->setClosureCapture(foundClosureCapture);
|
|
fArg->setLifetimeAnnotation(lifetime);
|
|
fArg->setReborrow(foundReborrow);
|
|
fArg->setHasPointerEscape(hasPointerEscape);
|
|
Arg = fArg;
|
|
|
|
// Today, we construct the ownership kind straight from the function
|
|
// type. Make sure they are in sync, otherwise bail. We want this to
|
|
// be an exact check rather than a compatibility check since we do not
|
|
// want incompatibilities in between @any and other types of ownership
|
|
// to be ignored.
|
|
if (F->hasOwnership() && Arg->getOwnershipKind() != OwnershipKind) {
|
|
auto diagID =
|
|
diag::silfunc_and_silarg_have_incompatible_sil_value_ownership;
|
|
P.diagnose(NameLoc, diagID, Arg->getOwnershipKind().asString(),
|
|
OwnershipKind.asString());
|
|
return true;
|
|
}
|
|
} else {
|
|
Arg = BB->createPhiArgument(Ty, OwnershipKind, /*decl*/ nullptr,
|
|
foundReborrow, hasPointerEscape);
|
|
}
|
|
setLocalValue(Arg, Name, NameLoc);
|
|
} while (P.consumeIf(tok::comma));
|
|
|
|
if (P.parseToken(tok::r_paren, diag::sil_basicblock_arg_rparen))
|
|
return true;
|
|
}
|
|
|
|
if (P.parseToken(tok::colon, diag::expected_sil_block_colon))
|
|
return true;
|
|
}
|
|
|
|
// Make sure the block is at the end of the function so that forward
|
|
// references don't affect block layout.
|
|
F->moveBlockBefore(BB, F->end());
|
|
|
|
B.setInsertionPoint(BB);
|
|
do {
|
|
if (parseSILInstruction(B))
|
|
return true;
|
|
} while (isStartOfSILInstruction());
|
|
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil: [[only in SIL mode]]
|
|
/// 'sil' sil-linkage '@' identifier ':' sil-type decl-sil-body?
|
|
/// decl-sil-body:
|
|
/// '{' sil-basic-block+ '}'
|
|
bool SILParserState::parseDeclSIL(Parser &P) {
|
|
// Inform the lexer that we're lexing the body of the SIL declaration. Do
|
|
// this before we consume the 'sil' token so that all later tokens are
|
|
// properly handled.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
|
|
P.consumeToken(tok::kw_sil);
|
|
|
|
SILParser FunctionState(P);
|
|
|
|
std::optional<SILLinkage> FnLinkage;
|
|
Identifier FnName;
|
|
SILType FnType;
|
|
SourceLoc FnNameLoc;
|
|
|
|
bool isTransparent = false;
|
|
SerializedKind_t isSerialized = IsNotSerialized;
|
|
bool isCanonical = false;
|
|
IsDynamicallyReplaceable_t isDynamic = IsNotDynamic;
|
|
IsDistributed_t isDistributed = IsNotDistributed;
|
|
IsRuntimeAccessible_t isRuntimeAccessible = IsNotRuntimeAccessible;
|
|
ForceEnableLexicalLifetimes_t forceEnableLexicalLifetimes =
|
|
DoNotForceEnableLexicalLifetimes;
|
|
UseStackForPackMetadata_t useStackForPackMetadata = DoUseStackForPackMetadata;
|
|
bool hasUnsafeNonEscapableResult = false;
|
|
IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass;
|
|
bool hasOwnershipSSA = false;
|
|
IsThunk_t isThunk = IsNotThunk;
|
|
SILFunction::Purpose specialPurpose = SILFunction::Purpose::None;
|
|
bool isWeakImported = false;
|
|
bool needStackProtection = false;
|
|
AvailabilityRange availability = AvailabilityRange::alwaysAvailable();
|
|
bool isWithoutActuallyEscapingThunk = false;
|
|
Inline_t inlineStrategy = InlineDefault;
|
|
OptimizationMode optimizationMode = OptimizationMode::NotSet;
|
|
PerformanceConstraints perfConstr = PerformanceConstraints::None;
|
|
bool isPerformanceConstraint = false;
|
|
bool markedAsUsed = false;
|
|
StringRef asmName;
|
|
StringRef section;
|
|
SmallVector<std::string, 1> Semantics;
|
|
SmallVector<ParsedSpecAttr, 4> SpecAttrs;
|
|
ValueDecl *ClangDecl = nullptr;
|
|
EffectsKind MRK = EffectsKind::Unspecified;
|
|
SILFunction *DynamicallyReplacedFunction = nullptr;
|
|
SILFunction *AdHocWitnessFunction = nullptr;
|
|
Identifier objCReplacementFor;
|
|
ActorIsolation actorIsolation;
|
|
if (parseSILLinkage(FnLinkage, P) ||
|
|
parseDeclSILOptional(
|
|
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
|
|
&isThunk, &isDynamic, &isDistributed, &isRuntimeAccessible,
|
|
&forceEnableLexicalLifetimes, &useStackForPackMetadata,
|
|
&hasUnsafeNonEscapableResult, &isExactSelfClass,
|
|
&DynamicallyReplacedFunction, &AdHocWitnessFunction,
|
|
&objCReplacementFor, &specialPurpose, &inlineStrategy,
|
|
&optimizationMode, &perfConstr, &isPerformanceConstraint,
|
|
&markedAsUsed, &asmName, §ion, nullptr, &isWeakImported,
|
|
&needStackProtection, nullptr, &availability,
|
|
&isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl,
|
|
&MRK, &actorIsolation, FunctionState, M) ||
|
|
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
|
|
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
|
|
diag::expected_sil_function_name) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_type))
|
|
return true;
|
|
{
|
|
// Construct a Scope for the function body so TypeAliasDecl can be added to
|
|
// the scope.
|
|
GenericSignature GenericSig;
|
|
GenericParamList *GenericParams = nullptr;
|
|
if (FunctionState.parseSILType(FnType, GenericSig, GenericParams,
|
|
true /*IsFuncDecl*/))
|
|
return true;
|
|
auto SILFnType = FnType.getAs<SILFunctionType>();
|
|
if (!SILFnType || !FnType.isObject()) {
|
|
P.diagnose(FnNameLoc, diag::expected_sil_function_type);
|
|
return true;
|
|
}
|
|
|
|
FunctionState.F =
|
|
FunctionState.getGlobalNameForDefinition(FnName, SILFnType, FnNameLoc);
|
|
FunctionState.F->setBare(IsBare);
|
|
FunctionState.F->setTransparent(IsTransparent_t(isTransparent));
|
|
FunctionState.F->setSerializedKind(SerializedKind_t(isSerialized));
|
|
FunctionState.F->setWasDeserializedCanonical(isCanonical);
|
|
if (!hasOwnershipSSA)
|
|
FunctionState.F->setOwnershipEliminated();
|
|
FunctionState.F->setThunk(IsThunk_t(isThunk));
|
|
FunctionState.F->setIsDynamic(isDynamic);
|
|
FunctionState.F->setIsDistributed(isDistributed);
|
|
FunctionState.F->setIsRuntimeAccessible(isRuntimeAccessible);
|
|
FunctionState.F->setForceEnableLexicalLifetimes(
|
|
forceEnableLexicalLifetimes);
|
|
FunctionState.F->setUseStackForPackMetadata(useStackForPackMetadata);
|
|
FunctionState.F->setHasUnsafeNonEscapableResult(
|
|
hasUnsafeNonEscapableResult);
|
|
FunctionState.F->setIsExactSelfClass(isExactSelfClass);
|
|
FunctionState.F->setDynamicallyReplacedFunction(
|
|
DynamicallyReplacedFunction);
|
|
FunctionState.F->setReferencedAdHocRequirementWitnessFunction(
|
|
AdHocWitnessFunction);
|
|
if (!objCReplacementFor.empty())
|
|
FunctionState.F->setObjCReplacement(objCReplacementFor);
|
|
FunctionState.F->setSpecialPurpose(specialPurpose);
|
|
FunctionState.F->setIsAlwaysWeakImported(isWeakImported);
|
|
FunctionState.F->setAvailabilityForLinkage(availability);
|
|
FunctionState.F->setWithoutActuallyEscapingThunk(
|
|
isWithoutActuallyEscapingThunk);
|
|
FunctionState.F->setInlineStrategy(inlineStrategy);
|
|
FunctionState.F->setOptimizationMode(optimizationMode);
|
|
FunctionState.F->setPerfConstraints(perfConstr);
|
|
FunctionState.F->setIsPerformanceConstraint(isPerformanceConstraint);
|
|
FunctionState.F->setEffectsKind(MRK);
|
|
FunctionState.F->setMarkedAsUsed(markedAsUsed);
|
|
FunctionState.F->setAsmName(asmName);
|
|
FunctionState.F->setSection(section);
|
|
|
|
if (ClangDecl)
|
|
FunctionState.F->setClangNodeOwner(ClangDecl);
|
|
for (auto &Attr : Semantics) {
|
|
FunctionState.F->addSemanticsAttr(Attr);
|
|
}
|
|
if (actorIsolation)
|
|
FunctionState.F->setActorIsolation(actorIsolation);
|
|
// Now that we have a SILFunction parse the body, if present.
|
|
|
|
bool isDefinition = false;
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
|
|
if (P.consumeIf(tok::l_brace)) {
|
|
while (P.consumeIf(tok::l_square)) {
|
|
SourceLoc effectsStart = P.Tok.getLoc();
|
|
while (P.Tok.isNot(tok::r_square, tok::eof)) {
|
|
P.consumeToken();
|
|
}
|
|
SourceLoc effectsEnd = P.Tok.getLoc();
|
|
P.consumeToken();
|
|
StringRef effectsStr = P.SourceMgr.extractText(
|
|
CharSourceRange(P.SourceMgr, effectsStart, effectsEnd));
|
|
|
|
auto error = FunctionState.F->parseMultipleEffectsFromSIL(effectsStr);
|
|
if (error.first) {
|
|
SourceLoc loc = effectsStart;
|
|
if (loc.isValid())
|
|
loc = loc.getAdvancedLoc(error.second);
|
|
P.diagnose(loc, diag::error_in_effects_attribute, StringRef(error.first));
|
|
return true;
|
|
}
|
|
}
|
|
if (!P.consumeIf(tok::r_brace)) {
|
|
isDefinition = true;
|
|
|
|
FunctionState.ContextGenericSig = GenericSig;
|
|
FunctionState.ContextGenericParams = GenericParams;
|
|
FunctionState.F->setGenericEnvironment(GenericSig.getGenericEnvironment());
|
|
|
|
if (GenericSig && !SpecAttrs.empty()) {
|
|
for (auto &Attr : SpecAttrs) {
|
|
SmallVector<Requirement, 2> requirements;
|
|
SmallVector<Type, 2> typeErasedParams;
|
|
// Resolve types and convert requirements.
|
|
FunctionState.convertRequirements(Attr.requirements, requirements, typeErasedParams);
|
|
auto *fenv = FunctionState.F->getGenericEnvironment();
|
|
auto genericSig = buildGenericSignature(P.Context,
|
|
fenv->getGenericSignature(),
|
|
/*addedGenericParams=*/{ },
|
|
std::move(requirements),
|
|
/*allowInverses=*/false);
|
|
FunctionState.F->addSpecializeAttr(SILSpecializeAttr::create(
|
|
FunctionState.F->getModule(), genericSig, typeErasedParams, Attr.exported,
|
|
Attr.kind, Attr.target, Attr.spiGroupID, Attr.spiModule, Attr.availability));
|
|
}
|
|
}
|
|
|
|
// Parse the basic block list.
|
|
SILBuilder B(*FunctionState.F);
|
|
|
|
do {
|
|
if (FunctionState.parseSILBasicBlock(B))
|
|
return true;
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
// Check that there are no unresolved forward definitions of local
|
|
// archetypes.
|
|
if (M.hasUnresolvedLocalArchetypeDefinitions())
|
|
llvm_unreachable(
|
|
"All forward definitions of local archetypes should be resolved");
|
|
}
|
|
}
|
|
|
|
FunctionState.F->setLinkage(resolveSILLinkage(FnLinkage, isDefinition));
|
|
switch (FunctionState.F->getLinkage()) {
|
|
case SILLinkage::PublicExternal:
|
|
case SILLinkage::PackageExternal:
|
|
if (!FunctionState.F->isExternalDeclaration() && !FunctionState.F->isAnySerialized())
|
|
FunctionState.F->getModule().setParsedAsSerializedSIL();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FunctionState.diagnoseProblems())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-stage: [[only in SIL mode]]
|
|
/// 'sil_stage' ('raw' | 'canonical')
|
|
bool SILParserState::parseDeclSILStage(Parser &P) {
|
|
SourceLoc stageLoc = P.consumeToken(tok::kw_sil_stage);
|
|
if (!P.Tok.is(tok::identifier)) {
|
|
P.diagnose(P.Tok, diag::expected_sil_stage_name);
|
|
return true;
|
|
}
|
|
SILStage stage;
|
|
if (P.Tok.isContextualKeyword("raw")) {
|
|
stage = SILStage::Raw;
|
|
P.consumeToken();
|
|
} else if (P.Tok.isContextualKeyword("canonical")) {
|
|
stage = SILStage::Canonical;
|
|
P.consumeToken();
|
|
} else if (P.Tok.isContextualKeyword("lowered")) {
|
|
stage = SILStage::Lowered;
|
|
P.consumeToken();
|
|
} else {
|
|
P.diagnose(P.Tok, diag::expected_sil_stage_name);
|
|
P.consumeToken();
|
|
return true;
|
|
}
|
|
|
|
if (DidParseSILStage) {
|
|
P.diagnose(stageLoc, diag::multiple_sil_stage_decls);
|
|
return false;
|
|
}
|
|
|
|
M.setStage(stage);
|
|
if (M.getOptions().EnableSILOpaqueValues) {
|
|
M.setLoweredAddresses(stage != SILStage::Raw);
|
|
}
|
|
DidParseSILStage = true;
|
|
return false;
|
|
}
|
|
|
|
/// Lookup a global variable declaration from its demangled name.
|
|
///
|
|
/// A variable declaration exists for all sil_global variables defined in
|
|
/// Swift. A Swift global defined outside this module will be exposed
|
|
/// via an addressor rather than as a sil_global. Globals imported
|
|
/// from clang will produce a sil_global but will not have any corresponding
|
|
/// VarDecl.
|
|
///
|
|
/// FIXME: lookupGlobalDecl() can handle collisions between private or
|
|
/// fileprivate global variables in the same SIL Module, but the typechecker
|
|
/// will still incorrectly diagnose this as an "invalid redeclaration" and give
|
|
/// all but the first declaration an error type.
|
|
static std::optional<VarDecl *> lookupGlobalDecl(Identifier GlobalName,
|
|
SILLinkage GlobalLinkage,
|
|
SILType GlobalType,
|
|
Parser &P) {
|
|
// Create a set of DemangleOptions to produce the global variable's
|
|
// identifier, which is used as a search key in the declaration context.
|
|
Demangle::DemangleOptions demangleOpts;
|
|
demangleOpts.QualifyEntities = false;
|
|
demangleOpts.ShowPrivateDiscriminators = false;
|
|
demangleOpts.DisplayEntityTypes = false;
|
|
std::string GlobalDeclName = Demangle::demangleSymbolAsString(
|
|
GlobalName.str(), demangleOpts);
|
|
|
|
SmallVector<ValueDecl *, 4> CurModuleResults;
|
|
P.SF.getParentModule()->lookupValue(
|
|
P.Context.getIdentifier(GlobalDeclName), NLKind::UnqualifiedLookup,
|
|
CurModuleResults);
|
|
// Bail-out on clang-imported globals.
|
|
if (CurModuleResults.empty())
|
|
return nullptr;
|
|
|
|
// private and fileprivate globals of the same name may be merged into a
|
|
// single SIL module. Find the declaration with the correct type and
|
|
// linkage. (If multiple globals have the same type and linkage then it
|
|
// doesn't matter which declaration we use).
|
|
for (ValueDecl *ValDecl : CurModuleResults) {
|
|
auto *VD = cast<VarDecl>(ValDecl);
|
|
CanType DeclTy = VD->getTypeInContext()->getCanonicalType();
|
|
if (DeclTy == GlobalType.getASTType()
|
|
&& getDeclSILLinkage(VD) == GlobalLinkage) {
|
|
return VD;
|
|
}
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// decl-sil-global: [[only in SIL mode]]
|
|
/// 'sil_global' sil-linkage @name : sil-type [external]
|
|
bool SILParserState::parseSILGlobal(Parser &P) {
|
|
// Inform the lexer that we're lexing the body of the SIL declaration.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
|
|
P.consumeToken(tok::kw_sil_global);
|
|
std::optional<SILLinkage> GlobalLinkage;
|
|
Identifier GlobalName;
|
|
SILType GlobalType;
|
|
SourceLoc NameLoc;
|
|
SerializedKind_t isSerialized = IsNotSerialized;
|
|
bool isMarkedAsUsed = false;
|
|
StringRef asmName;
|
|
StringRef section;
|
|
bool isLet = false;
|
|
|
|
SILParser State(P);
|
|
if (parseSILLinkage(GlobalLinkage, P) ||
|
|
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, &isMarkedAsUsed, &asmName,
|
|
§ion, &isLet, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
State, M) ||
|
|
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
|
|
P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false,
|
|
diag::expected_sil_value_name) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_type))
|
|
return true;
|
|
|
|
if (State.parseSILType(GlobalType))
|
|
return true;
|
|
|
|
// Non-external global variables are definitions by default.
|
|
if (!GlobalLinkage.has_value())
|
|
GlobalLinkage = SILLinkage::DefaultForDefinition;
|
|
|
|
// Lookup the global variable declaration for this sil_global.
|
|
auto VD =
|
|
lookupGlobalDecl(GlobalName, GlobalLinkage.value(), GlobalType, P);
|
|
if (!VD) {
|
|
P.diagnose(NameLoc, diag::sil_global_variable_not_found, GlobalName);
|
|
return true;
|
|
}
|
|
auto *GV = SILGlobalVariable::create(
|
|
M, GlobalLinkage.value(), isSerialized, GlobalName.str(), GlobalType,
|
|
RegularLocation(NameLoc), VD.value());
|
|
|
|
GV->setLet(isLet);
|
|
GV->setMarkedAsUsed(isMarkedAsUsed);
|
|
GV->setAsmName(asmName);
|
|
GV->setSection(section);
|
|
|
|
// Parse static initializer if exists.
|
|
if (State.P.consumeIf(tok::equal) && State.P.consumeIf(tok::l_brace)) {
|
|
SILBuilder B(GV);
|
|
do {
|
|
if (State.parseSILInstruction(B))
|
|
return true;
|
|
} while (! State.P.consumeIf(tok::r_brace));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-property: [[only in SIL mode]]
|
|
/// 'sil_property' sil-decl-ref '(' sil-key-path-pattern-component ')'
|
|
|
|
bool SILParserState::parseSILProperty(Parser &P) {
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
|
|
auto loc = P.consumeToken(tok::kw_sil_property);
|
|
auto InstLoc = RegularLocation(loc);
|
|
SILParser SP(P);
|
|
|
|
SerializedKind_t Serialized = IsNotSerialized;
|
|
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, SP, M))
|
|
return true;
|
|
|
|
ValueDecl *VD;
|
|
|
|
if (SP.parseSILDottedPath(VD))
|
|
return true;
|
|
|
|
GenericParamList *patternParams;
|
|
patternParams = P.maybeParseGenericParams().getPtrOrNull();
|
|
auto patternSig = handleSILGenericParams(patternParams, &P.SF);
|
|
|
|
if (patternSig) {
|
|
if (patternSig.getCanonicalSignature() !=
|
|
VD->getInnermostDeclContext()
|
|
->getGenericSignatureOfContext()
|
|
.getCanonicalSignature()) {
|
|
P.diagnose(loc, diag::sil_property_generic_signature_mismatch);
|
|
return true;
|
|
}
|
|
} else {
|
|
if (VD->getInnermostDeclContext()->getGenericSignatureOfContext()) {
|
|
P.diagnose(loc, diag::sil_property_generic_signature_mismatch);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
Identifier ComponentKind;
|
|
std::optional<KeyPathPatternComponent> Component;
|
|
SourceLoc ComponentLoc;
|
|
SmallVector<SILType, 4> OperandTypes;
|
|
|
|
if (P.parseToken(tok::l_paren, diag::expected_tok_in_sil_instr, "("))
|
|
return true;
|
|
|
|
if (!P.consumeIf(tok::r_paren)) {
|
|
KeyPathPatternComponent parsedComponent;
|
|
if (P.parseIdentifier(ComponentKind, ComponentLoc,
|
|
/*diagnoseDollarPrefix=*/false,
|
|
diag::expected_tok_in_sil_instr, "component kind")
|
|
|| SP.parseKeyPathPatternComponent(parsedComponent, OperandTypes,
|
|
ComponentLoc, ComponentKind, InstLoc,
|
|
patternSig, patternParams)
|
|
|| P.parseToken(tok::r_paren, diag::expected_tok_in_sil_instr, ")"))
|
|
return true;
|
|
|
|
Component = std::move(parsedComponent);
|
|
}
|
|
|
|
SILProperty::create(M, Serialized,
|
|
cast<AbstractStorageDecl>(VD), Component);
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-vtable: [[only in SIL mode]]
|
|
/// 'sil_vtable' ClassName decl-sil-vtable-body
|
|
/// decl-sil-vtable-body:
|
|
/// '{' sil-vtable-entry* '}'
|
|
/// sil-vtable-entry:
|
|
/// SILDeclRef ':' SILFunctionName
|
|
bool SILParserState::parseSILVTable(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_vtable);
|
|
SILParser VTableState(P);
|
|
|
|
SerializedKind_t Serialized = IsNotSerialized;
|
|
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
VTableState, M))
|
|
return true;
|
|
|
|
|
|
ClassDecl *theClass = nullptr;
|
|
SILType specializedClassTy;
|
|
if (P.Tok.isNot(tok::sil_dollar)) {
|
|
// Parse the class name.
|
|
Identifier Name;
|
|
SourceLoc Loc;
|
|
if (VTableState.parseSILIdentifier(Name, Loc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
// Find the class decl.
|
|
llvm::PointerUnion<ValueDecl*, ModuleDecl *> Res =
|
|
lookupTopDecl(P, Name, /*typeLookup=*/true);
|
|
assert(isa<ValueDecl *>(Res) && "Class look-up should return a Decl");
|
|
ValueDecl *VD = cast<ValueDecl *>(Res);
|
|
if (!VD) {
|
|
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
|
|
return true;
|
|
}
|
|
|
|
theClass = dyn_cast<ClassDecl>(VD);
|
|
if (!theClass) {
|
|
P.diagnose(Loc, diag::sil_vtable_class_not_found, Name);
|
|
return true;
|
|
}
|
|
} else {
|
|
if (SILParser(P).parseSILType(specializedClassTy))
|
|
return true;
|
|
theClass = specializedClassTy.getClassOrBoundGenericClass();
|
|
if (!theClass) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
// We need to turn on InSILBody to parse SILDeclRef.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
// Parse the entry list.
|
|
std::vector<SILVTable::Entry> vtableEntries;
|
|
if (P.Tok.isNot(tok::r_brace)) {
|
|
do {
|
|
SILDeclRef Ref;
|
|
Identifier FuncName;
|
|
SourceLoc FuncLoc;
|
|
if (VTableState.parseSILDeclRef(Ref, true))
|
|
return true;
|
|
SILFunction *Func = nullptr;
|
|
if (P.Tok.is(tok::kw_nil)) {
|
|
P.consumeToken();
|
|
} else {
|
|
if (P.parseToken(tok::colon, diag::expected_sil_vtable_colon) ||
|
|
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
|
|
VTableState.parseSILIdentifier(FuncName, FuncLoc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
Func = M.lookUpFunction(FuncName.str());
|
|
if (!Func) {
|
|
P.diagnose(FuncLoc, diag::sil_vtable_func_not_found, FuncName);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
auto Kind = SILVTable::Entry::Kind::Normal;
|
|
bool NonOverridden = false;
|
|
while (P.Tok.is(tok::l_square)) {
|
|
P.consumeToken(tok::l_square);
|
|
if (P.Tok.isNot(tok::identifier)) {
|
|
P.diagnose(P.Tok.getLoc(), diag::sil_vtable_bad_entry_kind);
|
|
return true;
|
|
}
|
|
|
|
if (P.Tok.getText() == "override") {
|
|
P.consumeToken();
|
|
Kind = SILVTable::Entry::Kind::Override;
|
|
} else if (P.Tok.getText() == "inherited") {
|
|
P.consumeToken();
|
|
Kind = SILVTable::Entry::Kind::Inherited;
|
|
} else if (P.Tok.getText() == "nonoverridden") {
|
|
P.consumeToken();
|
|
NonOverridden = true;
|
|
} else {
|
|
P.diagnose(P.Tok.getLoc(), diag::sil_vtable_bad_entry_kind);
|
|
return true;
|
|
}
|
|
|
|
if (P.parseToken(tok::r_square, diag::sil_vtable_expect_rsquare))
|
|
return true;
|
|
}
|
|
|
|
vtableEntries.emplace_back(Ref, Func, Kind, NonOverridden);
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
SILVTable::create(M, theClass, specializedClassTy, Serialized, vtableEntries);
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-vtable: [[only in SIL mode]]
|
|
/// 'sil_vtable' ClassName decl-sil-vtable-body
|
|
/// decl-sil-vtable-body:
|
|
/// '{' sil-vtable-entry* '}'
|
|
/// sil-vtable-entry:
|
|
/// SILDeclRef ':' SILFunctionName
|
|
bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
|
|
parser.consumeToken(tok::kw_sil_moveonlydeinit);
|
|
SILParser moveOnlyDeinitTableState(parser);
|
|
|
|
SerializedKind_t Serialized = IsNotSerialized;
|
|
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
moveOnlyDeinitTableState, M))
|
|
return true;
|
|
|
|
// Parse the class name.
|
|
Identifier name;
|
|
SourceLoc loc;
|
|
if (moveOnlyDeinitTableState.parseSILIdentifier(
|
|
name, loc, diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
// Find the nominal decl.
|
|
llvm::PointerUnion<ValueDecl *, ModuleDecl *> res =
|
|
lookupTopDecl(parser, name, /*typeLookup=*/true);
|
|
assert(isa<ValueDecl *>(res) && "Class Nominal-up should return a Decl");
|
|
ValueDecl *varDecl = cast<ValueDecl *>(res);
|
|
if (!varDecl) {
|
|
parser.diagnose(loc, diag::sil_moveonlydeinit_nominal_not_found, name);
|
|
return true;
|
|
}
|
|
|
|
auto *theNominalDecl = dyn_cast<NominalTypeDecl>(varDecl);
|
|
if (!theNominalDecl) {
|
|
parser.diagnose(loc, diag::sil_moveonlydeinit_nominal_not_found, name);
|
|
return true;
|
|
}
|
|
|
|
SourceLoc lBraceLoc = parser.Tok.getLoc();
|
|
parser.consumeToken(tok::l_brace);
|
|
|
|
// We need to turn on InSILBody to parse SILDeclRef.
|
|
Lexer::SILBodyRAII tmp(*parser.L);
|
|
SILFunction *func = nullptr;
|
|
|
|
if (parser.Tok.isNot(tok::r_brace)) {
|
|
Identifier funcName;
|
|
SourceLoc funcLoc;
|
|
if (parser.Tok.is(tok::kw_nil)) {
|
|
parser.consumeToken();
|
|
} else {
|
|
if (parser.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
|
|
moveOnlyDeinitTableState.parseSILIdentifier(
|
|
funcName, funcLoc, diag::expected_sil_value_name))
|
|
return true;
|
|
func = M.lookUpFunction(funcName.str());
|
|
if (!func) {
|
|
parser.diagnose(funcLoc, diag::sil_moveonlydeinit_func_not_found,
|
|
funcName);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
parser.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
lBraceLoc);
|
|
|
|
SILMoveOnlyDeinit::create(M, theNominalDecl, Serialized, func);
|
|
return false;
|
|
}
|
|
|
|
static ClassDecl *parseClassDecl(Parser &P, SILParser &SP) {
|
|
Identifier DeclName;
|
|
SourceLoc DeclLoc;
|
|
if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name))
|
|
return nullptr;
|
|
|
|
// Find the protocol decl. The protocol can be imported.
|
|
llvm::PointerUnion<ValueDecl *, ModuleDecl *> Res =
|
|
lookupTopDecl(P, DeclName, /*typeLookup=*/true);
|
|
assert(isa<ValueDecl *>(Res) && "Protocol look-up should return a Decl");
|
|
ValueDecl *VD = cast<ValueDecl *>(Res);
|
|
if (!VD) {
|
|
P.diagnose(DeclLoc, diag::sil_default_override_class_not_found, DeclName);
|
|
return nullptr;
|
|
}
|
|
auto *decl = dyn_cast<ClassDecl>(VD);
|
|
if (!decl)
|
|
P.diagnose(DeclLoc, diag::sil_default_override_decl_not_class, DeclName);
|
|
return decl;
|
|
}
|
|
|
|
static ProtocolDecl *parseProtocolDecl(Parser &P, SILParser &SP) {
|
|
Identifier DeclName;
|
|
SourceLoc DeclLoc;
|
|
if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name))
|
|
return nullptr;
|
|
|
|
// Find the protocol decl. The protocol can be imported.
|
|
llvm::PointerUnion<ValueDecl*, ModuleDecl *> Res =
|
|
lookupTopDecl(P, DeclName, /*typeLookup=*/true);
|
|
assert(isa<ValueDecl *>(Res) && "Protocol look-up should return a Decl");
|
|
ValueDecl *VD = cast<ValueDecl *>(Res);
|
|
if (!VD) {
|
|
P.diagnose(DeclLoc, diag::sil_witness_protocol_not_found, DeclName);
|
|
return nullptr;
|
|
}
|
|
auto *proto = dyn_cast<ProtocolDecl>(VD);
|
|
if (!proto)
|
|
P.diagnose(DeclLoc, diag::sil_witness_protocol_not_found, DeclName);
|
|
return proto;
|
|
}
|
|
|
|
static AssociatedTypeDecl *parseAssociatedTypeDecl(Parser &P, SILParser &SP,
|
|
ProtocolDecl *proto) {
|
|
Identifier DeclName;
|
|
SourceLoc DeclLoc;
|
|
if (SP.parseSILIdentifier(DeclName, DeclLoc, diag::expected_sil_value_name))
|
|
return nullptr;
|
|
// We can return multiple decls, for now, we use the first lookup result.
|
|
// One example is two decls when searching for Generator of Sequence:
|
|
// one from Sequence, the other from _Sequence_Type.
|
|
SmallVector<ValueDecl *, 4> values;
|
|
auto VD = lookupMember(P, proto->getInterfaceType(), DeclName, DeclLoc,
|
|
values, true/*ExpectMultipleResults*/);
|
|
if (!VD) {
|
|
P.diagnose(DeclLoc, diag::sil_witness_assoc_not_found, DeclName);
|
|
return nullptr;
|
|
}
|
|
return dyn_cast<AssociatedTypeDecl>(VD);
|
|
}
|
|
|
|
static bool parseAssociatedTypePath(SILParser &SP,
|
|
SmallVectorImpl<Identifier> &path) {
|
|
do {
|
|
Identifier name;
|
|
SourceLoc loc;
|
|
if (SP.parseSILIdentifier(name, loc, diag::expected_sil_value_name))
|
|
return false;
|
|
path.push_back(name);
|
|
} while (SP.P.consumeIf(tok::period));
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool matchesAssociatedTypePath(CanType assocType,
|
|
ArrayRef<Identifier> path) {
|
|
if (auto memberType = dyn_cast<DependentMemberType>(assocType)) {
|
|
return (!path.empty() &&
|
|
memberType->getName() == path.back() &&
|
|
matchesAssociatedTypePath(memberType.getBase(), path.drop_back()));
|
|
} else {
|
|
assert(isa<GenericTypeParamType>(assocType));
|
|
return path.empty();
|
|
}
|
|
}
|
|
|
|
static CanType parseAssociatedTypePath(Parser &P, SILParser &SP,
|
|
ProtocolDecl *proto) {
|
|
SourceLoc loc = SP.P.Tok.getLoc();
|
|
SmallVector<Identifier, 4> path;
|
|
if (!parseAssociatedTypePath(SP, path))
|
|
return CanType();
|
|
|
|
// This is only used for parsing associated conformances, so we can
|
|
// go ahead and just search the requirement signature for something that
|
|
// matches the path.
|
|
for (auto &reqt : proto->getRequirementSignature().getRequirements()) {
|
|
if (reqt.getKind() != RequirementKind::Conformance)
|
|
continue;
|
|
CanType assocType = reqt.getFirstType()->getCanonicalType();
|
|
if (matchesAssociatedTypePath(assocType, path))
|
|
return assocType;
|
|
}
|
|
|
|
SmallString<128> name;
|
|
name += path[0].str();
|
|
for (auto elt : llvm::ArrayRef(path).slice(1)) {
|
|
name += '.';
|
|
name += elt.str();
|
|
}
|
|
P.diagnose(loc, diag::sil_witness_assoc_conf_not_found, name);
|
|
return CanType();
|
|
}
|
|
|
|
static ProtocolConformanceRef
|
|
parseRootProtocolConformance(Parser &P, SILParser &SP, Type ConformingTy,
|
|
ProtocolDecl *&proto) {
|
|
const StringRef ModuleKeyword = "module";
|
|
Identifier ModuleName;
|
|
SourceLoc Loc, KeywordLoc;
|
|
proto = parseProtocolDecl(P, SP);
|
|
if (!proto)
|
|
return ProtocolConformanceRef();
|
|
|
|
if (P.parseSpecificIdentifier(
|
|
ModuleKeyword, KeywordLoc,
|
|
{diag::expected_tok_in_sil_instr, {ModuleKeyword}}) ||
|
|
SP.parseSILIdentifier(ModuleName, Loc, diag::expected_sil_value_name))
|
|
return ProtocolConformanceRef();
|
|
|
|
// Calling lookupConformance on a specialized type will return a specialized
|
|
// conformance. We pass getDeclaredInterfaceType() to find the normal
|
|
// conformance.
|
|
Type lookupTy = ConformingTy;
|
|
if (auto bound = lookupTy->getAs<BoundGenericType>())
|
|
lookupTy = bound->getDecl()->getDeclaredInterfaceType();
|
|
auto lookup = lookupConformance(lookupTy, proto);
|
|
if (lookup.isInvalid()) {
|
|
P.diagnose(KeywordLoc, diag::sil_witness_protocol_conformance_not_found);
|
|
return ProtocolConformanceRef();
|
|
}
|
|
|
|
return lookup;
|
|
}
|
|
|
|
/// protocol-conformance ::= normal-protocol-conformance
|
|
/// protocol-conformance ::=
|
|
/// generic-parameter-list? type: 'inherit' '(' protocol-conformance ')'
|
|
/// protocol-conformance ::=
|
|
/// generic-parameter-list? type: 'specialize' '<' substitution* '>'
|
|
/// '(' protocol-conformance ')'
|
|
/// normal-protocol-conformance ::=
|
|
/// generic-parameter-list? type: protocolName module ModuleName
|
|
/// Note that generic-parameter-list is already parsed before calling this.
|
|
ProtocolConformanceRef SILParser::parseProtocolConformance(
|
|
ProtocolDecl *&proto,
|
|
GenericSignature &genericSig,
|
|
GenericParamList *&genericParams) {
|
|
// Make sure we don't leave it uninitialized in the caller
|
|
genericSig = GenericSignature();
|
|
|
|
genericParams = P.maybeParseGenericParams().getPtrOrNull();
|
|
if (genericParams) {
|
|
genericSig = handleSILGenericParams(genericParams, &P.SF);
|
|
}
|
|
|
|
return parseProtocolConformanceHelper(proto, genericSig, genericParams);
|
|
}
|
|
|
|
CheckedCastInstOptions SILParser::parseCheckedCastInstOptions(bool *isExact) {
|
|
CheckedCastInstOptions options;
|
|
StringRef attrName;
|
|
|
|
while (parseSILOptional(attrName, *this)) {
|
|
if (attrName == "prohibit_isolated_conformances") {
|
|
options = options.withIsolatedConformances(
|
|
CastingIsolatedConformances::Prohibit);
|
|
}
|
|
|
|
if (attrName == "exact" && isExact)
|
|
*isExact = true;
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
ProtocolConformanceRef SILParser::parseProtocolConformanceHelper(
|
|
ProtocolDecl *&proto,
|
|
GenericSignature witnessSig,
|
|
GenericParamList *witnessParams) {
|
|
// Parse AST type.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return ProtocolConformanceRef();
|
|
|
|
if (!witnessSig)
|
|
witnessSig = ContextGenericSig;
|
|
if (witnessParams == nullptr)
|
|
witnessParams = ContextGenericParams;
|
|
|
|
auto ConformingTy = performTypeResolution(TyR.get(), /*IsSILType=*/false,
|
|
witnessSig, witnessParams);
|
|
if (witnessSig) {
|
|
ConformingTy = witnessSig.getGenericEnvironment()
|
|
->mapTypeIntoContext(ConformingTy);
|
|
}
|
|
|
|
if (ConformingTy->hasError())
|
|
return ProtocolConformanceRef();
|
|
|
|
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return ProtocolConformanceRef();
|
|
|
|
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "specialize") {
|
|
P.consumeToken();
|
|
|
|
// Parse substitutions for specialized conformance.
|
|
SmallVector<ParsedSubstitution, 4> parsedSubs;
|
|
if (parseSubstitutions(parsedSubs, witnessSig, witnessParams))
|
|
return ProtocolConformanceRef();
|
|
|
|
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
|
|
return ProtocolConformanceRef();
|
|
ProtocolDecl *dummy;
|
|
GenericSignature specializedSig;
|
|
GenericParamList *specializedParams = nullptr;
|
|
auto genericConform =
|
|
parseProtocolConformance(dummy, specializedSig, specializedParams);
|
|
if (genericConform.isInvalid() || !genericConform.isConcrete())
|
|
return ProtocolConformanceRef();
|
|
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
|
|
return ProtocolConformanceRef();
|
|
|
|
SubstitutionMap subMap =
|
|
getApplySubstitutionsFromParsed(*this, specializedSig, parsedSubs);
|
|
if (!subMap)
|
|
return ProtocolConformanceRef();
|
|
|
|
auto *rootConform = cast<NormalProtocolConformance>(
|
|
genericConform.getConcrete());
|
|
auto result = P.Context.getSpecializedConformance(
|
|
ConformingTy, rootConform, subMap);
|
|
return ProtocolConformanceRef(result);
|
|
}
|
|
|
|
if (P.Tok.is(tok::identifier) && P.Tok.getText() == "inherit") {
|
|
P.consumeToken();
|
|
|
|
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
|
|
return ProtocolConformanceRef();
|
|
auto baseConform = parseProtocolConformance();
|
|
if (baseConform.isInvalid() || !baseConform.isConcrete())
|
|
return ProtocolConformanceRef();
|
|
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen))
|
|
return ProtocolConformanceRef();
|
|
|
|
auto result = P.Context.getInheritedConformance(ConformingTy,
|
|
baseConform.getConcrete());
|
|
return ProtocolConformanceRef(result);
|
|
}
|
|
|
|
auto retVal =
|
|
parseRootProtocolConformance(P, *this, ConformingTy, proto);
|
|
return retVal;
|
|
}
|
|
|
|
/// Parser a single SIL wtable entry and add it to either \p witnessEntries
|
|
/// or \c conditionalConformances.
|
|
static bool parseSILWitnessTableEntry(
|
|
Parser &P,
|
|
SILModule &M,
|
|
ProtocolDecl *proto,
|
|
GenericSignature witnessSig,
|
|
GenericParamList *witnessParams,
|
|
SILParser &witnessState,
|
|
std::vector<SILWitnessTable::Entry> &witnessEntries,
|
|
std::vector<ProtocolConformanceRef> &conditionalConformances) {
|
|
Identifier EntryKeyword;
|
|
SourceLoc KeywordLoc;
|
|
if (P.parseIdentifier(EntryKeyword, KeywordLoc,
|
|
/*diagnoseDollarPrefix=*/false,
|
|
diag::expected_tok_in_sil_instr,
|
|
"method, associated_type, associated_conformance"
|
|
", base_protocol, no_default"))
|
|
return true;
|
|
|
|
if (EntryKeyword.str() == "no_default") {
|
|
witnessEntries.push_back(SILDefaultWitnessTable::Entry());
|
|
return false;
|
|
}
|
|
|
|
if (EntryKeyword.str() == "base_protocol") {
|
|
ProtocolDecl *proto = parseProtocolDecl(P, witnessState);
|
|
if (!proto)
|
|
return true;
|
|
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
auto conform =
|
|
witnessState.parseProtocolConformance();
|
|
// Ignore invalid and abstract witness entries.
|
|
if (conform.isInvalid() || !conform.isConcrete())
|
|
return false;
|
|
|
|
witnessEntries.push_back(
|
|
SILWitnessTable::BaseProtocolWitness{proto, conform.getConcrete()});
|
|
return false;
|
|
}
|
|
|
|
if (EntryKeyword.str() == "associated_conformance" ||
|
|
EntryKeyword.str() == "conditional_conformance") {
|
|
if (P.parseToken(tok::l_paren, diag::expected_sil_witness_lparen))
|
|
return true;
|
|
CanType assocOrSubject;
|
|
if (EntryKeyword.str() == "associated_conformance") {
|
|
assocOrSubject = parseAssociatedTypePath(P, witnessState, proto);
|
|
} else {
|
|
// Parse AST type.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
SILTypeResolutionContext silContext(/*isSILType=*/false,
|
|
witnessParams,
|
|
/*openedPacks=*/nullptr);
|
|
auto Ty =
|
|
swift::performTypeResolution(TyR.get(), P.Context,
|
|
witnessSig, &silContext,
|
|
&P.SF);
|
|
if (witnessSig) {
|
|
Ty = witnessSig.getGenericEnvironment()->mapTypeIntoContext(Ty);
|
|
}
|
|
|
|
if (Ty->hasError())
|
|
return true;
|
|
|
|
assocOrSubject = Ty->getCanonicalType();
|
|
}
|
|
if (!assocOrSubject)
|
|
return true;
|
|
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
ProtocolDecl *proto = parseProtocolDecl(P, witnessState);
|
|
if (!proto)
|
|
return true;
|
|
if (P.parseToken(tok::r_paren, diag::expected_sil_witness_rparen) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
|
|
ProtocolConformanceRef conformance;
|
|
if (P.Tok.getText() != "dependent") {
|
|
auto concrete =
|
|
witnessState.parseProtocolConformance();
|
|
// Ignore invalid and abstract witness entries.
|
|
if (concrete.isInvalid() || !concrete.isConcrete())
|
|
return false;
|
|
conformance = concrete;
|
|
} else {
|
|
P.consumeToken();
|
|
|
|
// Parse AST type.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
SILTypeResolutionContext silContext(/*isSILType=*/false,
|
|
witnessParams,
|
|
/*openedPacks=*/nullptr);
|
|
auto Ty =
|
|
swift::performTypeResolution(TyR.get(), P.Context,
|
|
witnessSig, &silContext,
|
|
&P.SF);
|
|
if (witnessSig) {
|
|
Ty = witnessSig.getGenericEnvironment()->mapTypeIntoContext(Ty);
|
|
}
|
|
|
|
if (Ty->hasError())
|
|
return true;
|
|
|
|
conformance = ProtocolConformanceRef::forAbstract(
|
|
Ty->getCanonicalType(), proto);
|
|
}
|
|
|
|
if (EntryKeyword.str() == "associated_conformance")
|
|
witnessEntries.push_back(
|
|
SILWitnessTable::AssociatedConformanceWitness{assocOrSubject,
|
|
conformance});
|
|
else
|
|
conditionalConformances.push_back(conformance);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (EntryKeyword.str() == "associated_type") {
|
|
AssociatedTypeDecl *assoc = parseAssociatedTypeDecl(P, witnessState,
|
|
proto);
|
|
if (!assoc)
|
|
return true;
|
|
if (P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
|
|
// Parse AST type.
|
|
ParserResult<TypeRepr> TyR = P.parseType();
|
|
if (TyR.isNull())
|
|
return true;
|
|
|
|
SILTypeResolutionContext silContext(/*isSILType=*/false,
|
|
witnessParams,
|
|
/*openedPacks=*/nullptr);
|
|
auto Ty =
|
|
swift::performTypeResolution(TyR.get(), P.Context,
|
|
witnessSig, &silContext,
|
|
&P.SF);
|
|
if (witnessSig) {
|
|
Ty = witnessSig.getGenericEnvironment()->mapTypeIntoContext(Ty);
|
|
}
|
|
|
|
if (Ty->hasError())
|
|
return true;
|
|
|
|
witnessEntries.push_back(
|
|
SILWitnessTable::AssociatedTypeWitness{assoc, Ty->getCanonicalType()});
|
|
return false;
|
|
}
|
|
|
|
if (EntryKeyword.str() != "method") {
|
|
P.diagnose(KeywordLoc, diag::expected_tok_in_sil_instr, "method");
|
|
return true;
|
|
}
|
|
|
|
SILDeclRef Ref;
|
|
Identifier FuncName;
|
|
SourceLoc FuncLoc;
|
|
if (witnessState.parseSILDeclRef(Ref, true) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
|
|
SILFunction *Func = nullptr;
|
|
if (P.Tok.is(tok::kw_nil)) {
|
|
P.consumeToken();
|
|
} else {
|
|
if (P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
|
|
witnessState.parseSILIdentifier(FuncName, FuncLoc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
Func = M.lookUpFunction(FuncName.str());
|
|
if (!Func) {
|
|
P.diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName);
|
|
return true;
|
|
}
|
|
}
|
|
witnessEntries.push_back(SILWitnessTable::MethodWitness{
|
|
Ref, Func
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-witness ::= 'sil_witness_table' sil-linkage?
|
|
/// normal-protocol-conformance decl-sil-witness-body
|
|
/// normal-protocol-conformance ::=
|
|
/// generic-parameter-list? type: protocolName module ModuleName
|
|
/// decl-sil-witness-body:
|
|
/// '{' sil-witness-entry* '}'
|
|
/// sil-witness-entry:
|
|
/// method SILDeclRef ':' @SILFunctionName
|
|
/// associated_type AssociatedTypeDeclName: Type
|
|
/// associated_conformance (AssocName: ProtocolName):
|
|
/// protocol-conformance|dependent
|
|
/// base_protocol ProtocolName: protocol-conformance
|
|
bool SILParserState::parseSILWitnessTable(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_witness_table);
|
|
SILParser WitnessState(P);
|
|
|
|
// Parse the linkage.
|
|
std::optional<SILLinkage> Linkage;
|
|
parseSILLinkage(Linkage, P);
|
|
|
|
SerializedKind_t isSerialized = IsNotSerialized;
|
|
bool isSpecialized = false;
|
|
if (parseDeclSILOptional(
|
|
nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, &isSpecialized,
|
|
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
|
|
WitnessState, M))
|
|
return true;
|
|
|
|
// Parse the protocol conformance.
|
|
ProtocolDecl *proto;
|
|
GenericSignature witnessSig;
|
|
GenericParamList *witnessParams = nullptr;
|
|
auto conf = WitnessState.parseProtocolConformance(proto,
|
|
witnessSig,
|
|
witnessParams);
|
|
WitnessState.ContextGenericSig = witnessSig;
|
|
WitnessState.ContextGenericParams = witnessParams;
|
|
|
|
ProtocolConformance *theConformance = nullptr;
|
|
if (conf.isConcrete()) {
|
|
if (isSpecialized) {
|
|
theConformance = conf.getConcrete();
|
|
} else {
|
|
theConformance = conf.getConcrete()->getRootConformance();
|
|
}
|
|
}
|
|
|
|
SILWitnessTable *wt = nullptr;
|
|
if (theConformance) {
|
|
wt = M.lookUpWitnessTable(theConformance, isSpecialized);
|
|
assert((!wt || wt->isDeclaration()) &&
|
|
"Attempting to create duplicate witness table.");
|
|
}
|
|
|
|
// If we don't have an lbrace, then this witness table is a declaration.
|
|
if (P.Tok.getKind() != tok::l_brace) {
|
|
// Default to public external linkage.
|
|
if (!Linkage)
|
|
Linkage = SILLinkage::PublicExternal;
|
|
// We ignore empty witness table without normal protocol conformance.
|
|
if (!wt && theConformance)
|
|
wt = SILWitnessTable::create(M, *Linkage, theConformance, isSpecialized);
|
|
return false;
|
|
}
|
|
|
|
if (!theConformance) {
|
|
P.diagnose(P.Tok, diag::sil_witness_protocol_conformance_not_found);
|
|
return true;
|
|
}
|
|
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
// We need to turn on InSILBody to parse SILDeclRef.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
// Parse the entry list.
|
|
std::vector<SILWitnessTable::Entry> witnessEntries;
|
|
std::vector<ProtocolConformanceRef> conditionalConformances;
|
|
|
|
if (P.Tok.isNot(tok::r_brace)) {
|
|
do {
|
|
if (parseSILWitnessTableEntry(P, M, proto, witnessSig, witnessParams,
|
|
WitnessState, witnessEntries,
|
|
conditionalConformances))
|
|
return true;
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
// Default to public linkage.
|
|
if (!Linkage)
|
|
Linkage = SILLinkage::Public;
|
|
|
|
if (!wt)
|
|
wt = SILWitnessTable::create(M, *Linkage, theConformance, isSpecialized);
|
|
else
|
|
wt->setLinkage(*Linkage);
|
|
wt->convertToDefinition(witnessEntries, conditionalConformances,
|
|
isSerialized);
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-default-witness ::= 'sil_default_witness_table'
|
|
/// sil-linkage identifier
|
|
/// decl-sil-default-witness-body
|
|
/// decl-sil-default-witness-body:
|
|
/// '{' sil-default-witness-entry* '}'
|
|
/// sil-default-witness-entry:
|
|
/// sil-witness-entry
|
|
/// 'no_default'
|
|
bool SILParserState::parseSILDefaultWitnessTable(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_default_witness_table);
|
|
SILParser WitnessState(P);
|
|
|
|
// Parse the linkage.
|
|
std::optional<SILLinkage> Linkage;
|
|
parseSILLinkage(Linkage, P);
|
|
|
|
// Parse the protocol.
|
|
ProtocolDecl *protocol = parseProtocolDecl(P, WitnessState);
|
|
if (!protocol)
|
|
return true;
|
|
|
|
WitnessState.ContextGenericSig = protocol->getGenericSignature();
|
|
WitnessState.ContextGenericParams = protocol->getGenericParams();
|
|
|
|
// Parse the body.
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
// We need to turn on InSILBody to parse SILDeclRef.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
|
|
// Parse the entry list.
|
|
std::vector<SILWitnessTable::Entry> witnessEntries;
|
|
std::vector<ProtocolConformanceRef> conditionalConformances;
|
|
|
|
if (P.Tok.isNot(tok::r_brace)) {
|
|
do {
|
|
if (parseSILWitnessTableEntry(P, M, protocol,
|
|
protocol->getGenericSignature(),
|
|
protocol->getGenericParams(),
|
|
WitnessState, witnessEntries,
|
|
conditionalConformances))
|
|
return true;
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
// Default to public linkage.
|
|
if (!Linkage)
|
|
Linkage = SILLinkage::Public;
|
|
|
|
SILDefaultWitnessTable::create(M, *Linkage, protocol, witnessEntries);
|
|
return false;
|
|
}
|
|
|
|
/// Parser a single SIL default override table entry and add it to \p entries.
|
|
/// sil-default-override-entry:
|
|
/// SILDeclRef ':' SILDeclRef ':' @SILFunctionName
|
|
static bool parseSILDefaultOverrideTableEntry(
|
|
Parser &P, SILModule &M, ClassDecl *proto, GenericSignature witnessSig,
|
|
GenericParamList *witnessParams, SILParser &parser,
|
|
std::vector<SILDefaultOverrideTable::Entry> &entries) {
|
|
Identifier EntryKeyword;
|
|
SourceLoc KeywordLoc;
|
|
|
|
SILDeclRef replacement;
|
|
if (parser.parseSILDeclRef(replacement, true) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
|
|
SILDeclRef original;
|
|
if (parser.parseSILDeclRef(original, true) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_witness_colon))
|
|
return true;
|
|
|
|
SILFunction *impl = nullptr;
|
|
Identifier implName;
|
|
SourceLoc implLoc;
|
|
if (P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
|
|
parser.parseSILIdentifier(implName, implLoc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
impl = M.lookUpFunction(implName.str());
|
|
if (!impl) {
|
|
P.diagnose(implLoc, diag::sil_default_override_func_not_found, implName);
|
|
return true;
|
|
}
|
|
|
|
entries.push_back(
|
|
SILDefaultOverrideTable::Entry{replacement, original, impl});
|
|
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-default-override ::= 'sil_default_override_table'
|
|
/// sil-linkage identifier
|
|
/// decl-sil-default-override-body
|
|
/// decl-sil-default-override-body:
|
|
/// '{' sil-default-override-entry* '}'
|
|
/// sil-default-override-entry:
|
|
/// SILDeclRef ':' SILDeclRef ':' @SILFunctionName
|
|
bool SILParserState::parseSILDefaultOverrideTable(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_default_override_table);
|
|
SILParser OverrideState(P);
|
|
|
|
// Parse the linkage.
|
|
std::optional<SILLinkage> Linkage;
|
|
parseSILLinkage(Linkage, P);
|
|
|
|
// Parse the class.
|
|
ClassDecl *decl = parseClassDecl(P, OverrideState);
|
|
if (!decl)
|
|
return true;
|
|
|
|
OverrideState.ContextGenericSig = decl->getGenericSignature();
|
|
OverrideState.ContextGenericParams = decl->getGenericParams();
|
|
|
|
// Parse the body.
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
// We need to turn on InSILBody to parse SILDeclRef.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
|
|
// Parse the entry list.
|
|
std::vector<SILDefaultOverrideTable::Entry> entries;
|
|
|
|
if (P.Tok.isNot(tok::r_brace)) {
|
|
do {
|
|
if (parseSILDefaultOverrideTableEntry(
|
|
P, M, decl, decl->getGenericSignature(), decl->getGenericParams(),
|
|
OverrideState, entries))
|
|
return true;
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
// Default to public linkage.
|
|
if (!Linkage)
|
|
Linkage = SILLinkage::Public;
|
|
|
|
SILDefaultOverrideTable::define(M, *Linkage, decl, entries);
|
|
return false;
|
|
}
|
|
|
|
/// decl-sil-differentiability-witness ::=
|
|
/// 'sil_differentiability_witness'
|
|
/// ('[' 'serialized' ']')?
|
|
/// sil-linkage?
|
|
/// sil-differentiability-witness-config-and-function
|
|
/// decl-sil-differentiability-witness-body?
|
|
///
|
|
/// decl-sil-differentiability-witness-body ::=
|
|
/// '{'
|
|
/// ('jvp' sil-function-name ':' sil-type)?
|
|
/// ('vjp' sil-function-name ':' sil-type)?
|
|
/// '}'
|
|
///
|
|
/// index-subset ::=
|
|
/// [0-9]+ (' ' [0-9]+)*
|
|
bool SILParserState::parseSILDifferentiabilityWitness(Parser &P) {
|
|
auto loc = P.consumeToken(tok::kw_sil_differentiability_witness);
|
|
auto silLoc = RegularLocation(loc);
|
|
SILParser State(P);
|
|
|
|
// Parse the linkage.
|
|
std::optional<SILLinkage> linkage;
|
|
if (parseSILLinkage(linkage, P))
|
|
return true;
|
|
|
|
// Parse '[serialized]' flag (optional).
|
|
bool isSerialized = false;
|
|
SourceLoc serializedTokLoc;
|
|
if (P.Tok.is(tok::l_square) && P.isIdentifier(P.peekToken(), "serialized")) {
|
|
isSerialized = true;
|
|
serializedTokLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_square);
|
|
P.consumeToken(tok::identifier);
|
|
if (P.parseToken(tok::r_square, diag::sil_diff_witness_expected_token, "]"))
|
|
return true;
|
|
}
|
|
|
|
// We need to turn on InSILBody to parse the function references.
|
|
Lexer::SILBodyRAII tmp(*P.L);
|
|
|
|
DifferentiabilityKind kind;
|
|
AutoDiffConfig config;
|
|
SILFunction *originalFn;
|
|
if (parseSILDifferentiabilityWitnessConfigAndFunction(
|
|
P, State, silLoc, kind, config, originalFn))
|
|
return true;
|
|
|
|
// If this is just a declaration, create the declaration now and return.
|
|
if (!P.Tok.is(tok::l_brace)) {
|
|
if (isSerialized) {
|
|
P.diagnose(serializedTokLoc,
|
|
diag::sil_diff_witness_serialized_declaration);
|
|
return true;
|
|
}
|
|
|
|
SILDifferentiabilityWitness::createDeclaration(
|
|
M, linkage ? *linkage : SILLinkage::DefaultForDeclaration, originalFn,
|
|
kind, config.parameterIndices, config.resultIndices,
|
|
config.derivativeGenericSignature);
|
|
return false;
|
|
}
|
|
|
|
// This is a definition, so parse differentiability witness body.
|
|
SILFunction *jvp = nullptr;
|
|
SILFunction *vjp = nullptr;
|
|
if (P.Tok.is(tok::l_brace)) {
|
|
// Parse '{'.
|
|
SourceLoc lBraceLoc;
|
|
P.consumeIf(tok::l_brace, lBraceLoc);
|
|
// Parse JVP (optional).
|
|
if (P.isIdentifier(P.Tok, "jvp")) {
|
|
P.consumeToken(tok::identifier);
|
|
if (P.parseToken(tok::colon, diag::sil_diff_witness_expected_token, ":"))
|
|
return true;
|
|
if (State.parseSILFunctionRef(silLoc, jvp))
|
|
return true;
|
|
}
|
|
// Parse VJP (optional).
|
|
if (P.isIdentifier(P.Tok, "vjp")) {
|
|
P.consumeToken(tok::identifier);
|
|
if (P.parseToken(tok::colon, diag::sil_diff_witness_expected_token, ":"))
|
|
return true;
|
|
if (State.parseSILFunctionRef(silLoc, vjp))
|
|
return true;
|
|
}
|
|
// Parse '}'.
|
|
SourceLoc rBraceLoc;
|
|
if (P.parseMatchingToken(tok::r_brace, rBraceLoc, diag::expected_sil_rbrace,
|
|
lBraceLoc))
|
|
return true;
|
|
}
|
|
|
|
SILDifferentiabilityWitness::createDefinition(
|
|
M, linkage ? *linkage : SILLinkage::DefaultForDefinition, originalFn,
|
|
kind, config.parameterIndices, config.resultIndices,
|
|
config.derivativeGenericSignature, jvp, vjp, isSerialized);
|
|
return false;
|
|
}
|
|
|
|
std::optional<llvm::coverage::Counter> SILParser::parseSILCoverageExpr(
|
|
llvm::coverage::CounterExpressionBuilder &Builder) {
|
|
if (P.Tok.is(tok::integer_literal)) {
|
|
unsigned CounterId;
|
|
if (parseInteger(CounterId, diag::sil_coverage_invalid_counter))
|
|
return std::nullopt;
|
|
return llvm::coverage::Counter::getCounter(CounterId);
|
|
}
|
|
|
|
if (P.Tok.is(tok::identifier)) {
|
|
Identifier Zero;
|
|
SourceLoc Loc;
|
|
if (parseSILIdentifier(Zero, Loc, diag::sil_coverage_invalid_counter))
|
|
return std::nullopt;
|
|
if (Zero.str() != "zero") {
|
|
P.diagnose(Loc, diag::sil_coverage_invalid_counter);
|
|
return std::nullopt;
|
|
}
|
|
return llvm::coverage::Counter::getZero();
|
|
}
|
|
|
|
if (P.Tok.is(tok::l_paren)) {
|
|
P.consumeToken(tok::l_paren);
|
|
auto LHS = parseSILCoverageExpr(Builder);
|
|
if (!LHS)
|
|
return std::nullopt;
|
|
const Identifier Operator = P.Context.getIdentifier(P.Tok.getText());
|
|
const SourceLoc Loc = P.consumeToken();
|
|
if (Operator.str() != "+" && Operator.str() != "-") {
|
|
P.diagnose(Loc, diag::sil_coverage_invalid_operator);
|
|
return std::nullopt;
|
|
}
|
|
auto RHS = parseSILCoverageExpr(Builder);
|
|
if (!RHS)
|
|
return std::nullopt;
|
|
if (P.parseToken(tok::r_paren, diag::sil_coverage_expected_rparen))
|
|
return std::nullopt;
|
|
|
|
if (Operator.str() == "+")
|
|
return Builder.add(*LHS, *RHS);
|
|
return Builder.subtract(*LHS, *RHS);
|
|
}
|
|
|
|
P.diagnose(P.Tok, diag::sil_coverage_invalid_counter);
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// decl-sil-coverage-map ::= 'sil_coverage_map' CoveredName PGOFuncName CoverageHash
|
|
/// decl-sil-coverage-body
|
|
/// decl-sil-coverage-body:
|
|
/// '{' sil-coverage-entry* '}'
|
|
/// sil-coverage-entry:
|
|
/// sil-coverage-loc ':' sil-coverage-expr
|
|
/// sil-coverage-loc:
|
|
/// StartLine ':' StartCol '->' EndLine ':' EndCol
|
|
/// sil-coverage-expr:
|
|
/// ...
|
|
bool SILParserState::parseSILCoverageMap(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_coverage_map);
|
|
SILParser State(P);
|
|
|
|
// Parse the filename.
|
|
Identifier Filename;
|
|
SourceLoc FileLoc;
|
|
if (State.parseSILIdentifier(Filename, FileLoc,
|
|
diag::expected_sil_value_name))
|
|
return true;
|
|
|
|
// Parse the covered name.
|
|
if (!P.Tok.is(tok::string_literal)) {
|
|
P.diagnose(P.Tok, diag::sil_coverage_expected_quote);
|
|
return true;
|
|
}
|
|
StringRef FuncName = P.Tok.getText().drop_front().drop_back();
|
|
P.consumeToken();
|
|
|
|
// Parse the PGO func name.
|
|
if (!P.Tok.is(tok::string_literal)) {
|
|
P.diagnose(P.Tok, diag::sil_coverage_expected_quote);
|
|
return true;
|
|
}
|
|
StringRef PGOFuncName = P.Tok.getText().drop_front().drop_back();
|
|
P.consumeToken();
|
|
|
|
uint64_t Hash;
|
|
if (State.parseInteger(Hash, diag::sil_coverage_invalid_hash))
|
|
return true;
|
|
|
|
if (!P.Tok.is(tok::l_brace)) {
|
|
P.diagnose(P.Tok, diag::sil_coverage_expected_lbrace);
|
|
return true;
|
|
}
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
llvm::coverage::CounterExpressionBuilder Builder;
|
|
std::vector<SILCoverageMap::MappedRegion> Regions;
|
|
bool BodyHasError = false;
|
|
if (P.Tok.isNot(tok::r_brace)) {
|
|
do {
|
|
unsigned StartLine, StartCol, EndLine, EndCol;
|
|
if (State.parseInteger(StartLine, diag::sil_coverage_expected_loc) ||
|
|
P.parseToken(tok::colon, diag::sil_coverage_expected_loc) ||
|
|
State.parseInteger(StartCol, diag::sil_coverage_expected_loc) ||
|
|
P.parseToken(tok::arrow, diag::sil_coverage_expected_arrow) ||
|
|
State.parseInteger(EndLine, diag::sil_coverage_expected_loc) ||
|
|
P.parseToken(tok::colon, diag::sil_coverage_expected_loc) ||
|
|
State.parseInteger(EndCol, diag::sil_coverage_expected_loc)) {
|
|
BodyHasError = true;
|
|
break;
|
|
}
|
|
|
|
if (P.parseToken(tok::colon, diag::sil_coverage_expected_colon)) {
|
|
BodyHasError = true;
|
|
break;
|
|
}
|
|
|
|
using MappedRegion = SILCoverageMap::MappedRegion;
|
|
|
|
if (P.Tok.isContextualKeyword("skipped")) {
|
|
P.consumeToken();
|
|
Regions.push_back(
|
|
MappedRegion::skipped(StartLine, StartCol, EndLine, EndCol));
|
|
} else {
|
|
auto Counter = State.parseSILCoverageExpr(Builder);
|
|
if (!Counter) {
|
|
BodyHasError = true;
|
|
break;
|
|
}
|
|
Regions.push_back(
|
|
MappedRegion::code(StartLine, StartCol, EndLine, EndCol, *Counter));
|
|
}
|
|
|
|
} while (P.Tok.isNot(tok::r_brace) && P.Tok.isNot(tok::eof));
|
|
}
|
|
if (BodyHasError)
|
|
P.skipUntilDeclRBrace();
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
if (!BodyHasError)
|
|
SILCoverageMap::create(M, &P.SF, Filename.str(), FuncName.str(),
|
|
PGOFuncName.str(), Hash, Regions,
|
|
Builder.getExpressions());
|
|
return false;
|
|
}
|
|
|
|
/// sil-scope-ref ::= 'scope' [0-9]+
|
|
/// sil-scope ::= 'sil_scope' [0-9]+ '{'
|
|
/// debug-loc
|
|
/// 'parent' scope-parent
|
|
/// ('inlined_at' sil-scope-ref)?
|
|
/// '}'
|
|
/// scope-parent ::= sil-function-name ':' sil-type
|
|
/// scope-parent ::= sil-scope-ref
|
|
/// debug-loc ::= 'loc' string-literal ':' [0-9]+ ':' [0-9]+
|
|
bool SILParserState::parseSILScope(Parser &P) {
|
|
P.consumeToken(tok::kw_sil_scope);
|
|
SILParser ScopeState(P);
|
|
|
|
SourceLoc SlotLoc = P.Tok.getLoc();
|
|
unsigned Slot;
|
|
if (ScopeState.parseInteger(Slot, diag::sil_invalid_scope_slot))
|
|
return true;
|
|
|
|
SourceLoc LBraceLoc = P.Tok.getLoc();
|
|
P.consumeToken(tok::l_brace);
|
|
|
|
StringRef Key = P.Tok.getText();
|
|
SILLocation Loc = SILLocation::invalid();
|
|
if (Key == "loc")
|
|
if (ScopeState.parseSILLocation(Loc))
|
|
return true;
|
|
ScopeState.parseVerbatim("parent");
|
|
Identifier FnName;
|
|
SILDebugScope *Parent = nullptr;
|
|
SILFunction *ParentFn = nullptr;
|
|
if (P.Tok.is(tok::integer_literal)) {
|
|
/// scope-parent ::= sil-scope-ref
|
|
if (ScopeState.parseScopeRef(Parent))
|
|
return true;
|
|
} else {
|
|
/// scope-parent ::= sil-function-name
|
|
SILType Ty;
|
|
SourceLoc FnLoc = P.Tok.getLoc();
|
|
// We need to turn on InSILBody to parse the function reference.
|
|
Lexer::SILBodyRAII Tmp(*P.L);
|
|
GenericSignature IgnoredSig;
|
|
GenericParamList *IgnoredParams = nullptr;
|
|
if ((ScopeState.parseGlobalName(FnName)) ||
|
|
P.parseToken(tok::colon, diag::expected_sil_colon_value_ref) ||
|
|
ScopeState.parseSILType(Ty, IgnoredSig, IgnoredParams, true))
|
|
return true;
|
|
|
|
// The function doesn't exist yet. Create a zombie forward declaration.
|
|
auto FnTy = Ty.getAs<SILFunctionType>();
|
|
if (!FnTy || !Ty.isObject()) {
|
|
P.diagnose(FnLoc, diag::expected_sil_function_type);
|
|
return true;
|
|
}
|
|
ParentFn = ScopeState.getGlobalNameForReference(FnName, FnTy, FnLoc, true);
|
|
ScopeState.TUState.PotentialZombieFns.insert(ParentFn);
|
|
}
|
|
|
|
SILDebugScope *InlinedAt = nullptr;
|
|
if (P.Tok.getText() == "inlined_at") {
|
|
P.consumeToken();
|
|
if (ScopeState.parseScopeRef(InlinedAt))
|
|
return true;
|
|
}
|
|
|
|
SourceLoc RBraceLoc;
|
|
P.parseMatchingToken(tok::r_brace, RBraceLoc, diag::expected_sil_rbrace,
|
|
LBraceLoc);
|
|
|
|
auto &Scope = ScopeSlots[Slot];
|
|
if (Scope) {
|
|
P.diagnose(SlotLoc, diag::sil_scope_redefined, Slot);
|
|
return true;
|
|
}
|
|
|
|
Scope = new (M) SILDebugScope(Loc, ParentFn, Parent, InlinedAt);
|
|
return false;
|
|
}
|