blob: 80ed4fc85e8ba88f88bfea5c1117c31dfdbedde3 [file] [log] [blame]
//===--- Callee.h - Information about a physical callee ---------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines the Callee type, which stores all necessary
// information about a physical callee.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_CALLEE_H
#define SWIFT_IRGEN_CALLEE_H
#include <type_traits>
#include "llvm/IR/DerivedTypes.h"
#include "swift/SIL/SILType.h"
#include "CallingConvention.h"
#include "Explosion.h"
#include "IRGen.h"
namespace llvm {
class PointerType;
}
namespace swift {
class Substitution;
namespace irgen {
class Callee;
class IRGenFunction;
/// Abstract information about how we can emit a call.
class AbstractCallee {
/// The best explosion level available for the call.
unsigned ExplosionLevel : 1;
/// The kind of extra data this call receives.
unsigned Data : 2;
/// The abstract calling convention.
unsigned Convention : 4;
/// The min uncurrying level available for the function.
unsigned MinUncurryLevel : 2;
/// The max uncurrying level available for the function.
unsigned MaxUncurryLevel : 9;
public:
AbstractCallee(SILFunctionTypeRepresentation convention,
ResilienceExpansion level,
unsigned minUncurry, unsigned maxUncurry, ExtraData data)
: ExplosionLevel(unsigned(level)), Data(unsigned(data)),
Convention(unsigned(convention)),
MinUncurryLevel(minUncurry), MaxUncurryLevel(maxUncurry) {}
static AbstractCallee forIndirect() {
return AbstractCallee(SILFunctionTypeRepresentation::Thin,
ResilienceExpansion::Minimal,
/*min uncurry*/ 0, /*max uncurry*/ 0,
ExtraData::Retainable);
}
SILFunctionTypeRepresentation getRepresentation() const {
return SILFunctionTypeRepresentation(Convention);
}
/// Returns the best explosion level at which we can emit this
/// call. We assume that we can call it at lower levels.
ResilienceExpansion getBestExplosionLevel() const {
return ResilienceExpansion(ExplosionLevel);
}
/// Whether the function requires a data pointer.
bool needsDataPointer() const { return getExtraData() != ExtraData::None; }
/// Whether the function requires a data pointer.
ExtraData getExtraData() const { return ExtraData(Data); }
/// The maximum uncurrying level at which the function can be called.
unsigned getMaxUncurryLevel() const { return MaxUncurryLevel; }
/// The minimum uncurrying level at which the function can be called.
unsigned getMinUncurryLevel() const { return MinUncurryLevel; }
};
class Callee {
/// The unsubstituted function type being called.
CanSILFunctionType OrigFnType;
/// The substituted result type of the function being called.
CanSILFunctionType SubstFnType;
/// The pointer to the actual function.
llvm::Value *FnPtr;
/// The data pointer required by the function. There's an
/// invariant that this never stores an llvm::ConstantPointerNull.
llvm::Value *DataPtr;
/// The archetype substitutions under which the function is being
/// called.
std::vector<Substitution> Substitutions;
public:
Callee() = default;
/// Prepare a callee for a known freestanding function that
/// requires no data pointer.
static Callee forFreestandingFunction(CanSILFunctionType origFnType,
CanSILFunctionType substFnType,
ArrayRef<Substitution> subs,
llvm::Constant *fn) {
return forKnownFunction(origFnType, substFnType, subs,
fn, nullptr);
}
/// Prepare a callee for a known instance method. Methods never
/// require a data pointer. The formal type here should
/// include the 'self' clause.
static Callee forMethod(CanSILFunctionType origFnType,
CanSILFunctionType substFnType,
ArrayRef<Substitution> subs,
llvm::Constant *fn) {
return forKnownFunction(origFnType, substFnType, subs,
fn, nullptr);
}
/// Prepare a callee for a known function with a known data pointer.
static Callee forKnownFunction(CanSILFunctionType origFnType,
CanSILFunctionType substFnType,
ArrayRef<Substitution> subs,
llvm::Value *fn, llvm::Value *data) {
// Invariant on the function pointer.
assert(cast<llvm::PointerType>(fn->getType())
->getElementType()->isFunctionTy());
Callee result;
result.OrigFnType = origFnType;
result.SubstFnType = substFnType;
result.FnPtr = fn;
result.DataPtr = data;
result.Substitutions = subs;
return result;
}
SILFunctionTypeRepresentation getRepresentation() const {
return OrigFnType->getRepresentation();
}
CanSILFunctionType getOrigFunctionType() const { return OrigFnType; }
CanSILFunctionType getSubstFunctionType() const { return SubstFnType; }
bool hasSubstitutions() const { return !Substitutions.empty(); }
ArrayRef<Substitution> getSubstitutions() const { return Substitutions; }
llvm::Value *getFunction() const { return FnPtr; }
llvm::FunctionType *getLLVMFunctionType() {
return cast<llvm::FunctionType>(FnPtr->getType()->getPointerElementType());
}
/// Return the function pointer as an i8*.
llvm::Value *getOpaqueFunctionPointer(IRGenFunction &IGF) const;
/// Return the function pointer as an appropriate pointer-to-function.
llvm::Value *getFunctionPointer() const { return FnPtr; }
/// Is it possible that this function requires a non-null data pointer?
bool hasDataPointer() const { return DataPtr != nullptr; }
/// Return the data pointer as a %swift.refcounted*.
llvm::Value *getDataPointer(IRGenFunction &IGF) const;
};
} // end namespace irgen
} // end namespace swift
#endif