Skip to content

Propagate Clang function types through SIL #33085

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 106 additions & 8 deletions include/swift/AST/ExtInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class FunctionType;
class SILExtInfo;
class SILExtInfoBuilder;
class SILFunctionType;
enum class SILFunctionTypeRepresentation : uint8_t;
} // namespace swift

namespace swift {
Expand All @@ -54,6 +55,7 @@ class ClangTypeInfo {
friend ASTExtInfoBuilder;
friend SILExtInfoBuilder;

// [NOTE: ClangTypeInfo-contents]
// We preserve a full clang::Type *, not a clang::FunctionType * as:
// 1. We need to keep sugar in case we need to present an error to the user
// (for AnyFunctionType).
Expand Down Expand Up @@ -81,6 +83,26 @@ class ClangTypeInfo {
void dump(llvm::raw_ostream &os, const clang::ASTContext &ctx) const;
};

// MARK: - UnexpectedClangTypeError
/// Potential errors when trying to store a Clang type in an ExtInfo.
struct UnexpectedClangTypeError {
enum class Kind {
NullForCOrBlock,
NonnullForNonCOrBlock,
NotBlockPointer,
NotFunctionPointerOrReference,
NonCanonical,
};
const Kind errorKind;
const clang::Type *type;

static Optional<UnexpectedClangTypeError> checkClangType(
SILFunctionTypeRepresentation fnRep, const clang::Type *type,
bool expectNonnullForCOrBlock, bool expectCanonical);

void dump();
};

// MARK: - FunctionTypeRepresentation
/// The representation form of a function.
enum class FunctionTypeRepresentation : uint8_t {
Expand Down Expand Up @@ -146,6 +168,41 @@ enum class SILFunctionTypeRepresentation : uint8_t {
Closure,
};

constexpr SILFunctionTypeRepresentation
convertRepresentation(FunctionTypeRepresentation rep) {
switch (rep) {
case FunctionTypeRepresentation::Swift:
return SILFunctionTypeRepresentation::Thick;
case FunctionTypeRepresentation::Block:
return SILFunctionTypeRepresentation::Block;
case FunctionTypeRepresentation::Thin:
return SILFunctionTypeRepresentation::Thin;
case FunctionTypeRepresentation::CFunctionPointer:
return SILFunctionTypeRepresentation::CFunctionPointer;
}
llvm_unreachable("Unhandled FunctionTypeRepresentation!");
};

inline Optional<FunctionTypeRepresentation>
convertRepresentation(SILFunctionTypeRepresentation rep) {
switch (rep) {
case SILFunctionTypeRepresentation::Thick:
return {FunctionTypeRepresentation::Swift};
case SILFunctionTypeRepresentation::Block:
return {FunctionTypeRepresentation::Block};
case SILFunctionTypeRepresentation::Thin:
return {FunctionTypeRepresentation::Thin};
case SILFunctionTypeRepresentation::CFunctionPointer:
return {FunctionTypeRepresentation::CFunctionPointer};
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::WitnessMethod:
case SILFunctionTypeRepresentation::Closure:
return None;
}
llvm_unreachable("Unhandled SILFunctionTypeRepresentation!");
};

/// Can this calling convention result in a function being called indirectly
/// through the runtime.
constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
Expand All @@ -165,6 +222,25 @@ constexpr bool canBeCalledIndirectly(SILFunctionTypeRepresentation rep) {
llvm_unreachable("Unhandled SILFunctionTypeRepresentation in switch.");
}

template <typename Repr> constexpr bool shouldStoreClangType(Repr repr) {
static_assert(std::is_same<Repr, FunctionTypeRepresentation>::value ||
std::is_same<Repr, SILFunctionTypeRepresentation>::value,
"Expected a Representation type as the argument type.");
switch (static_cast<SILFunctionTypeRepresentation>(repr)) {
case SILFunctionTypeRepresentation::CFunctionPointer:
case SILFunctionTypeRepresentation::Block:
return true;
case SILFunctionTypeRepresentation::ObjCMethod:
case SILFunctionTypeRepresentation::Thick:
case SILFunctionTypeRepresentation::Thin:
case SILFunctionTypeRepresentation::Method:
case SILFunctionTypeRepresentation::WitnessMethod:
case SILFunctionTypeRepresentation::Closure:
return false;
}
llvm_unreachable("Unhandled SILFunctionTypeRepresentation.");
}

// MARK: - ASTExtInfoBuilder
/// A builder type for creating an \c ASTExtInfo.
///
Expand Down Expand Up @@ -292,7 +368,8 @@ class ASTExtInfoBuilder {
LLVM_NODISCARD
ASTExtInfoBuilder withRepresentation(Representation rep) const {
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
clangTypeInfo);
shouldStoreClangType(rep) ? clangTypeInfo
: ClangTypeInfo());
}
LLVM_NODISCARD
ASTExtInfoBuilder withNoEscape(bool noEscape = true) const {
Expand Down Expand Up @@ -333,7 +410,8 @@ class ASTExtInfoBuilder {
ASTExtInfoBuilder
withSILRepresentation(SILFunctionTypeRepresentation rep) const {
return ASTExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
clangTypeInfo);
shouldStoreClangType(rep) ? clangTypeInfo
: ClangTypeInfo());
}

bool isEqualTo(ASTExtInfoBuilder other, bool useClangTypes) const {
Expand All @@ -360,12 +438,16 @@ class ASTExtInfo {

ASTExtInfoBuilder builder;

// Only for use by ASTExtInfoBuilder::build. Don't use it elsewhere!
ASTExtInfo(ASTExtInfoBuilder builder) : builder(builder) {}

ASTExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo)
: builder(bits, clangTypeInfo){};
: builder(bits, clangTypeInfo) {
builder.checkInvariants();
};

public:
ASTExtInfo() : builder(){};
ASTExtInfo() : builder() { builder.checkInvariants(); };

/// Create a builder with the same state as \c this.
ASTExtInfoBuilder intoBuilder() const { return builder; }
Expand Down Expand Up @@ -504,7 +586,7 @@ class SILExtInfoBuilder {
using Representation = SILFunctionTypeRepresentation;

SILExtInfoBuilder(unsigned bits, ClangTypeInfo clangTypeInfo)
: bits(bits), clangTypeInfo(clangTypeInfo) {}
: bits(bits), clangTypeInfo(clangTypeInfo.getCanonical()) {}

static constexpr unsigned makeBits(Representation rep, bool isPseudogeneric,
bool isNoEscape, bool isAsync,
Expand Down Expand Up @@ -606,7 +688,8 @@ class SILExtInfoBuilder {
// the following with methods instead of mutating these objects.
SILExtInfoBuilder withRepresentation(Representation rep) const {
return SILExtInfoBuilder((bits & ~RepresentationMask) | (unsigned)rep,
clangTypeInfo);
shouldStoreClangType(rep) ? clangTypeInfo
: ClangTypeInfo());
}
SILExtInfoBuilder withIsPseudogeneric(bool isPseudogeneric = true) const {
return SILExtInfoBuilder(isPseudogeneric ? (bits | PseudogenericMask)
Expand All @@ -629,6 +712,10 @@ class SILExtInfoBuilder {
((unsigned)differentiability << DifferentiabilityMaskOffset),
clangTypeInfo);
}
LLVM_NODISCARD
SILExtInfoBuilder withClangFunctionType(const clang::Type *type) const {
return SILExtInfoBuilder(bits, ClangTypeInfo(type).getCanonical());
}

bool isEqualTo(SILExtInfoBuilder other, bool useClangTypes) const {
return bits == other.bits &&
Expand All @@ -654,12 +741,21 @@ class SILExtInfo {

SILExtInfoBuilder builder;

// Only for use by SILExtInfoBuilder::build. Don't use it elsewhere!
SILExtInfo(SILExtInfoBuilder builder) : builder(builder) {}

SILExtInfo(unsigned bits, ClangTypeInfo clangTypeInfo)
: builder(bits, clangTypeInfo){};
: builder(bits, clangTypeInfo) {
builder.checkInvariants();
};

public:
SILExtInfo() : builder(){};
SILExtInfo() : builder() { builder.checkInvariants(); };

SILExtInfo(ASTExtInfo info, bool isPseudogeneric)
: builder(info.intoBuilder(), isPseudogeneric) {
builder.checkInvariants();
}

static SILExtInfo getThin() {
return SILExtInfoBuilder(SILExtInfoBuilder::Representation::Thin, false,
Expand Down Expand Up @@ -722,6 +818,8 @@ class SILExtInfo {
constexpr std::pair<unsigned, const void *> getFuncAttrKey() const {
return builder.getFuncAttrKey();
}

Optional<UnexpectedClangTypeError> checkClangType() const;
};

/// Helper function to obtain the useClangTypes parameter for checking equality
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ struct PrintOptions {
static PrintOptions printDocInterface();

/// Retrieve the set of options suitable for printing SIL functions.
static PrintOptions printSIL() {
static PrintOptions printSIL(bool printFullConvention = false) {
PrintOptions result;
result.PrintLongAttrsOnSeparateLines = true;
result.PrintStorageRepresentationAttrs = true;
Expand All @@ -605,6 +605,9 @@ struct PrintOptions {
result.PrintIfConfig = false;
result.OpaqueReturnTypePrinting =
OpaqueReturnTypePrintingMode::StableReference;
if (printFullConvention)
result.PrintFunctionRepresentationAttrs =
PrintOptions::FunctionRepresentationMode::Full;
return result;
}

Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/SILOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class SILOptions {
/// variables by name when we print it out. This eases diffing of SIL files.
bool EmitSortedSIL = false;

/// See \ref FrontendOptions.PrintFullConvention
bool PrintFullConvention = false;

/// Whether to stop the optimization pipeline after serializing SIL.
bool StopOptimizationAfterSerialization = false;

Expand Down
6 changes: 5 additions & 1 deletion include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -3888,7 +3888,7 @@ class SILFunctionType final
public llvm::FoldingSetNode,
private llvm::TrailingObjects<SILFunctionType, SILParameterInfo,
SILResultInfo, SILYieldInfo,
SubstitutionMap, CanType> {
SubstitutionMap, CanType, ClangTypeInfo> {
friend TrailingObjects;

size_t numTrailingObjects(OverloadToken<SILParameterInfo>) const {
Expand All @@ -3912,6 +3912,10 @@ class SILFunctionType final
size_t(hasInvocationSubstitutions());
}

size_t numTrailingObjects(OverloadToken<ClangTypeInfo>) const {
return Bits.SILFunctionType.HasClangTypeInfo ? 1 : 0;
}

public:
using ExtInfo = SILExtInfo;
using ExtInfoBuilder = SILExtInfoBuilder;
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ class FrontendOptions {
/// output path is configured.
Optional<IntermoduleDepTrackingMode> IntermoduleDependencyTracking;

/// Should we emit the cType when printing @convention(c) or no?
bool PrintFullConvention = false;

/// Should we serialize the hashes of dependencies (vs. the modification
/// times) when compiling a module interface?
bool SerializeModuleInterfaceDependencyHashes = false;
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Frontend/ModuleInterfaceSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct ModuleInterfaceOptions {
/// interface, or should we fully-qualify them?
bool PreserveTypesAsWritten = false;

/// Should we emit the cType when printing @convention(c) or no?
/// See \ref FrontendOptions.PrintFullConvention.
/// [TODO: Clang-type-plumbing] This check should go away.
bool PrintFullConvention = false;

Expand Down
6 changes: 4 additions & 2 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -659,10 +659,12 @@ def experimental_spi_imports :
Flag<["-"], "experimental-spi-imports">,
HelpText<"Enable experimental support for SPI imports">;

// [FIXME: Clang-type-plumbing] Make this a SIL-only option once we start
// unconditionally emitting non-canonical Clang types in swiftinterfaces.
def experimental_print_full_convention :
Flag<["-"], "experimental-print-full-convention">,
HelpText<"When emitting a module interface, emit additional @convention "
"arguments, regardless of whether they were written in the source">;
HelpText<"When emitting a module interface or SIL, emit additional @convention"
" arguments, regardless of whether they were written in the source">;

def experimental_one_way_closure_params :
Flag<["-"], "experimental-one-way-closure-params">,
Expand Down
3 changes: 1 addition & 2 deletions include/swift/SIL/SILModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -671,8 +671,7 @@ class SILModule {
/// \param Opts The SIL options, used to determine printing verbosity and
/// and sorting.
/// \param PrintASTDecls If set to true print AST decls.
void print(raw_ostream& OS,
ModuleDecl *M = nullptr,
void print(raw_ostream &OS, ModuleDecl *M = nullptr,
const SILOptions &Opts = SILOptions(),
bool PrintASTDecls = true) const {
SILPrintContext PrintCtx(OS, Opts);
Expand Down
12 changes: 9 additions & 3 deletions include/swift/SIL/SILPrintContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,23 @@ class SILPrintContext {
/// Print debug locations and scopes.
bool DebugInfo;

/// See \ref FrontendOptions.PrintFullConvention.
bool PrintFullConvention;

public:
/// Constructor with default values for options.
///
/// DebugInfo will be set according to the -sil-print-debuginfo option.
SILPrintContext(llvm::raw_ostream &OS, bool Verbose = false,
bool SortedSIL = false);
bool SortedSIL = false, bool PrintFullConvention = false);

/// Constructor based on SILOptions.
///
/// DebugInfo will be set according to the -sil-print-debuginfo option.
SILPrintContext(llvm::raw_ostream &OS, const SILOptions &Opts);

SILPrintContext(llvm::raw_ostream &OS, bool Verbose,
bool SortedSIL, bool DebugInfo);
SILPrintContext(llvm::raw_ostream &OS, bool Verbose, bool SortedSIL,
bool DebugInfo, bool PrintFullConvention);

virtual ~SILPrintContext();

Expand All @@ -100,6 +103,9 @@ class SILPrintContext {
/// Returns true if debug locations and scopes should be printed.
bool printDebugInfo() const { return DebugInfo; }

/// Returns true if the entire @convention(c, cType: ..) should be printed.
bool printFullConvention() const { return PrintFullConvention; }

SILPrintContext::ID getID(const SILBasicBlock *Block);

SILPrintContext::ID getID(const SILNode *node);
Expand Down
3 changes: 2 additions & 1 deletion include/swift/SIL/SILType.h
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,8 @@ class SILType {

std::string getAsString() const;
void dump() const;
void print(raw_ostream &OS) const;
void print(raw_ostream &OS,
const PrintOptions &PO = PrintOptions::printSIL()) const;
};

// Statically prevent SILTypes from being directly cast to a type
Expand Down
Loading