Skip to content

Substantially rework how IRGen handles function pointers. #11082

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
merged 1 commit into from
Jul 20, 2017
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
13 changes: 2 additions & 11 deletions lib/IRGen/CallEmission.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ class CallEmission {
IRGenFunction &IGF;

private:
/// The function attributes for the call.
llvm::AttributeSet Attrs;

/// The builtin/special arguments to pass to the call.
SmallVector<llvm::Value*, 8> Args;

Expand All @@ -56,21 +53,17 @@ class CallEmission {
void emitToUnmappedMemory(Address addr);
void emitToUnmappedExplosion(Explosion &out);
llvm::CallSite emitCallSite();
llvm::CallSite emitInvoke(llvm::CallingConv::ID cc, llvm::Value *fn,
ArrayRef<llvm::Value*> args,
const llvm::AttributeSet &attrs);

public:
CallEmission(IRGenFunction &IGF, const Callee &callee)
: IGF(IGF), CurCallee(callee) {
CallEmission(IRGenFunction &IGF, Callee &&callee)
: IGF(IGF), CurCallee(std::move(callee)) {
setFromCallee();
}
CallEmission(const CallEmission &other) = delete;
CallEmission(CallEmission &&other);
CallEmission &operator=(const CallEmission &other) = delete;
~CallEmission();

Callee &getMutableCallee() { return CurCallee; }
const Callee &getCallee() const { return CurCallee; }

SubstitutionList getSubstitutions() const {
Expand All @@ -84,8 +77,6 @@ class CallEmission {

void emitToMemory(Address addr, const LoadableTypeInfo &substResultTI);
void emitToExplosion(Explosion &out);

void invalidate();
};


Expand Down
182 changes: 131 additions & 51 deletions lib/IRGen/Callee.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,82 +36,162 @@ namespace irgen {
class Callee;
class IRGenFunction;

class Callee {
class CalleeInfo {
public:
/// The unsubstituted function type being called.
CanSILFunctionType OrigFnType;

/// The substituted result type of the function being called.
CanSILFunctionType SubstFnType;

/// The clang information for the function being called, if applicable.
ForeignFunctionInfo ForeignInfo;

/// 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;

CalleeInfo(CanSILFunctionType origFnType,
CanSILFunctionType substFnType,
SubstitutionList substitutions)
: OrigFnType(origFnType), SubstFnType(substFnType),
Substitutions(substitutions.begin(), substitutions.end()) {
}
};

/// A function pointer value.
class FunctionPointer {
/// The actual function pointer.
llvm::Value *Value;

Signature Sig;

public:
/// Construct a FunctionPointer for an arbitrary pointer value.
/// We may add more arguments to this; try to use the other
/// constructors/factories if possible.
explicit FunctionPointer(llvm::Value *value, const Signature &signature)
: Value(value), Sig(signature) {
// The function pointer should have function type.
assert(value->getType()->getPointerElementType()->isFunctionTy());
// TODO: maybe assert similarity to signature.getType()?
}

static FunctionPointer forDirect(IRGenModule &IGM,
llvm::Constant *value,
CanSILFunctionType fnType);

static FunctionPointer forDirect(llvm::Constant *value,
const Signature &signature) {
return FunctionPointer(value, signature);
}

static FunctionPointer forExplosionValue(IRGenFunction &IGF,
llvm::Value *fnPtr,
CanSILFunctionType fnType);

/// Return the actual function pointer.
llvm::Value *getPointer() const { return Value; }

/// Given that this value is known to have been constructed from
/// a direct function, return the function pointer.
llvm::Constant *getDirectPointer() const {
return cast<llvm::Constant>(Value);
}

llvm::FunctionType *getFunctionType() const {
return cast<llvm::FunctionType>(
Value->getType()->getPointerElementType());
}

const Signature &getSignature() const {
return Sig;
}

llvm::CallingConv::ID getCallingConv() const {
return Sig.getCallingConv();
}

llvm::AttributeSet getAttributes() const {
return Sig.getAttributes();
}
llvm::AttributeSet &getMutableAttributes() & {
return Sig.getMutableAttributes();
}

ForeignFunctionInfo getForeignInfo() const {
return Sig.getForeignInfo();
}

llvm::Value *getExplosionValue(IRGenFunction &IGF,
CanSILFunctionType fnType) const;
};

class Callee {
CalleeInfo Info;

/// The actual function pointer to invoke.
FunctionPointer Fn;

/// The first data pointer required by the function invocation.
llvm::Value *FirstData;

/// The second data pointer required by the function invocation.
llvm::Value *SecondData;

public:
Callee() = default;

/// Prepare a callee for a known function with a known data pointer.
static Callee forKnownFunction(CanSILFunctionType origFnType,
CanSILFunctionType substFnType,
SubstitutionList subs,
llvm::Value *fn, llvm::Value *data,
ForeignFunctionInfo foreignInfo) {
// Invariant on the function pointer.
assert(fn->getType()->getPointerElementType()->isFunctionTy());
assert((foreignInfo.ClangInfo != nullptr) ==
(origFnType->getLanguage() == SILFunctionLanguage::C));

Callee result;
result.OrigFnType = origFnType;
result.SubstFnType = substFnType;
result.FnPtr = fn;
result.DataPtr = data;
result.Substitutions = subs;
result.ForeignInfo = foreignInfo;
return result;
}

Callee(const Callee &other) = delete;
Callee &operator=(const Callee &other) = delete;

Callee(Callee &&other) = default;
Callee &operator=(Callee &&other) = default;

Callee(CalleeInfo &&info, const FunctionPointer &fn,
llvm::Value *firstData = nullptr,
llvm::Value *secondData = nullptr);

SILFunctionTypeRepresentation getRepresentation() const {
return OrigFnType->getRepresentation();
return Info.OrigFnType->getRepresentation();
}

CanSILFunctionType getOrigFunctionType() const { return OrigFnType; }
CanSILFunctionType getSubstFunctionType() const { return SubstFnType; }
CanSILFunctionType getOrigFunctionType() const {
return Info.OrigFnType;
}
CanSILFunctionType getSubstFunctionType() const {
return Info.SubstFnType;
}

bool hasSubstitutions() const { return !Substitutions.empty(); }
SubstitutionList getSubstitutions() const { return Substitutions; }
bool hasSubstitutions() const { return !Info.Substitutions.empty(); }
SubstitutionList getSubstitutions() const { return Info.Substitutions; }

llvm::Value *getFunction() const { return FnPtr; }
const FunctionPointer &getFunctionPointer() const { return Fn; }

llvm::FunctionType *getLLVMFunctionType() {
return cast<llvm::FunctionType>(FnPtr->getType()->getPointerElementType());
return Fn.getFunctionType();
}

llvm::AttributeSet getAttributes() const {
return Fn.getAttributes();
}
llvm::AttributeSet &getMutableAttributes() & {
return Fn.getMutableAttributes();
}

const ForeignFunctionInfo &getForeignInfo() const {
return ForeignInfo;
ForeignFunctionInfo getForeignInfo() const {
return Fn.getForeignInfo();
}

/// Return the function pointer as an i8*.
llvm::Value *getOpaqueFunctionPointer(IRGenFunction &IGF) const;
/// If this callee has a value for the Swift context slot, return
/// it; otherwise return non-null.
llvm::Value *getSwiftContext() const;

/// Return the function pointer as an appropriate pointer-to-function.
llvm::Value *getFunctionPointer() const { return FnPtr; }
/// Given that this callee is a block, return the block pointer.
llvm::Value *getBlockObject() const;

/// Is it possible that this function requires a non-null data pointer?
bool hasDataPointer() const { return DataPtr != nullptr; }
/// Given that this callee is an ObjC method, return the receiver
/// argument. This might not be 'self' anymore.
llvm::Value *getObjCMethodReceiver() const;

/// Return the data pointer as a %swift.refcounted*.
llvm::Value *getDataPointer(IRGenFunction &IGF) const;
/// Given that this callee is an ObjC method, return the receiver
/// argument. This might not be 'self' anymore.
llvm::Value *getObjCMethodSelector() const;
};

} // end namespace irgen
Expand Down
Loading