Raw File
Signature.h
//===--- Signature.h - An IR function signature -----------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
//  This file defines the Signature type, which encapsulates all the
//  information necessary to call a function value correctly.
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_IRGEN_SIGNATURE_H
#define SWIFT_IRGEN_SIGNATURE_H

#include "llvm/IR/Attributes.h"
#include "llvm/IR/CallingConv.h"
#include "swift/AST/Types.h"
#include "swift/Basic/ExternalUnion.h"

namespace llvm {
  class FunctionType;
}

namespace clang {
  namespace CodeGen {
    class CGFunctionInfo;    
  }
}

namespace swift {
  class Identifier;
  enum class SILFunctionTypeRepresentation : uint8_t;
  class SILType;

namespace irgen {

class FunctionPointerKind;
class IRGenModule;

/// An encapsulation of different foreign calling-convention lowering
/// information we might have.  Should be interpreted according to the
/// abstract CC of the formal function type.
class ForeignFunctionInfo {
public:
  const clang::CodeGen::CGFunctionInfo *ClangInfo = nullptr;
};

/// An encapsulation of the extra lowering information we might want to
/// store about a coroutine.
///
/// The ABI for yields breaks the yielded values down into a scalar type
/// sequence, much like argument lowering does: indirect yields (either
/// due to abstraction or size) become pointers and direct yields undergo
/// the general expansion algorithm.  We then find the longest prefix of
/// the resulting sequence for which the concatenation
///   (continuation function pointer) + prefix + (optional remainder pointer)
/// is a legal return type according to the swiftcall ABI.  The remainder
/// pointer must be included whenever the prefix is strict; it points to
/// a structure containing the remainder of the type sequence, with each
/// element naturally aligned.
///
/// For example, suppose the yields are
///   @in Any, @inout Double, @in Int64, Float, Int8, Int16, Int32
/// This is expanded to the legal type sequence:
///   Any*, double*, i64*, float, i8, i16, i32
/// To the beginning is always appended a continuation function pointer:
///   void (...)*, Any*, double*, i64*, float, i8, i16, i32
/// Suppose that the current target can support at most 4 scalar results.
/// Then the final sequence will be:
///   void (...)*, Any*, double*, { i64*, float, i8, i16, i32 }*
///
/// This final sequence becomes the result type of the coroutine's ramp
/// function and (if a yield_many coroutine) its continuation functions.
class CoroutineInfo {
public:
  /// The number of yield components that are returned directly in the
  /// coroutine return value.
  unsigned NumDirectYieldComponents = 0;
};

namespace {
  class SignatureExpansion;
}

class AsyncInfo {
public:
  uint32_t AsyncContextIdx = 0;
  uint32_t AsyncResumeFunctionSwiftSelfIdx = 0;
};

/// A signature represents something which can actually be called.
class Signature {
  using ExtraData =
      SimpleExternalUnion<void, ForeignFunctionInfo, CoroutineInfo, AsyncInfo>;

  llvm::FunctionType *Type;
  llvm::AttributeList Attributes;
  llvm::CallingConv::ID CallingConv;
  ExtraData::Kind ExtraDataKind; // packed with above
  ExtraData ExtraDataStorage;
  static_assert(ExtraData::union_is_trivially_copyable,
                "not trivially copyable");

  friend class irgen::SignatureExpansion;

public:
  Signature() : Type(nullptr) {}
  Signature(llvm::FunctionType *fnType, llvm::AttributeList attrs,
            llvm::CallingConv::ID callingConv)
    : Type(fnType), Attributes(attrs), CallingConv(callingConv),
      ExtraDataKind(ExtraData::kindForMember<void>()) {}

  bool isValid() const {
    return Type != nullptr;
  }

  /// Compute the signature of the given type.
  ///
  /// This is a private detail of the implementation of
  /// IRGenModule::getSignature(CanSILFunctionType), which is what
  /// clients should generally be using.
  static Signature getUncached(IRGenModule &IGM, CanSILFunctionType formalType,
                               FunctionPointerKind kind);

  /// Compute the signature of a coroutine's continuation function.
  static Signature forCoroutineContinuation(IRGenModule &IGM,
                                            CanSILFunctionType coroType);

  static Signature forAsyncReturn(IRGenModule &IGM,
                                  CanSILFunctionType asyncType);
  static Signature forAsyncAwait(IRGenModule &IGM, CanSILFunctionType asyncType,
                                 FunctionPointerKind kind);
  static Signature forAsyncEntry(IRGenModule &IGM, CanSILFunctionType asyncType,
                                 FunctionPointerKind kind);

  llvm::FunctionType *getType() const {
    assert(isValid());
    return Type;
  }

  llvm::CallingConv::ID getCallingConv() const {
    assert(isValid());
    return CallingConv;
  }

  llvm::AttributeList getAttributes() const {
    assert(isValid());
    return Attributes;
  }

  ForeignFunctionInfo getForeignInfo() const {
    assert(isValid());
    if (auto info =
          ExtraDataStorage.dyn_cast<ForeignFunctionInfo>(ExtraDataKind))
      return *info;
    return ForeignFunctionInfo();
  }

  CoroutineInfo getCoroutineInfo() const {
    assert(isValid());
    if (auto info = ExtraDataStorage.dyn_cast<CoroutineInfo>(ExtraDataKind))
      return *info;
    return CoroutineInfo();
  }

  AsyncInfo getAsyncInfo() const {
    assert(isValid());
    if (auto info = ExtraDataStorage.dyn_cast<AsyncInfo>(ExtraDataKind))
      return *info;
    return AsyncInfo();
  }

  uint32_t getAsyncContextIndex() const {
    return getAsyncInfo().AsyncContextIdx;
  }
  uint32_t getAsyncResumeFunctionSwiftSelfIndex() const {
    return getAsyncInfo().AsyncResumeFunctionSwiftSelfIdx;
  }

  // The mutators below should generally only be used when building up
  // a callee.

  void setType(llvm::FunctionType *type) {
    Type = type;
  }

  llvm::AttributeList &getMutableAttributes() & {
    assert(isValid());
    return Attributes;
  }
};

} // end namespace irgen
} // end namespace swift

#endif
back to top