Skip to content

Commit 750d397

Browse files
committed
Substantially rework how IRGen handles function pointers.
The goals here are four-fold: - provide cleaner internal abstractions - avoid IR bloat from extra bitcasts - avoid recomputing function-type lowering information - allow more information to be propagated from the function access site (e.g. class_method) to the call site Use this framework immediately for class and protocol methods.
1 parent 3f308b7 commit 750d397

24 files changed

+749
-563
lines changed

lib/IRGen/CallEmission.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ class CallEmission {
3535
IRGenFunction &IGF;
3636

3737
private:
38-
/// The function attributes for the call.
39-
llvm::AttributeSet Attrs;
40-
4138
/// The builtin/special arguments to pass to the call.
4239
SmallVector<llvm::Value*, 8> Args;
4340

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

6357
public:
64-
CallEmission(IRGenFunction &IGF, const Callee &callee)
65-
: IGF(IGF), CurCallee(callee) {
58+
CallEmission(IRGenFunction &IGF, Callee &&callee)
59+
: IGF(IGF), CurCallee(std::move(callee)) {
6660
setFromCallee();
6761
}
6862
CallEmission(const CallEmission &other) = delete;
6963
CallEmission(CallEmission &&other);
7064
CallEmission &operator=(const CallEmission &other) = delete;
7165
~CallEmission();
7266

73-
Callee &getMutableCallee() { return CurCallee; }
7467
const Callee &getCallee() const { return CurCallee; }
7568

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

8578
void emitToMemory(Address addr, const LoadableTypeInfo &substResultTI);
8679
void emitToExplosion(Explosion &out);
87-
88-
void invalidate();
8980
};
9081

9182

lib/IRGen/Callee.h

Lines changed: 131 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,82 +36,162 @@ namespace irgen {
3636
class Callee;
3737
class IRGenFunction;
3838

39-
class Callee {
39+
class CalleeInfo {
40+
public:
4041
/// The unsubstituted function type being called.
4142
CanSILFunctionType OrigFnType;
4243

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

46-
/// The clang information for the function being called, if applicable.
47-
ForeignFunctionInfo ForeignInfo;
48-
49-
/// The pointer to the actual function.
50-
llvm::Value *FnPtr;
51-
52-
/// The data pointer required by the function. There's an
53-
/// invariant that this never stores an llvm::ConstantPointerNull.
54-
llvm::Value *DataPtr;
55-
5647
/// The archetype substitutions under which the function is being
5748
/// called.
5849
std::vector<Substitution> Substitutions;
5950

51+
CalleeInfo(CanSILFunctionType origFnType,
52+
CanSILFunctionType substFnType,
53+
SubstitutionList substitutions)
54+
: OrigFnType(origFnType), SubstFnType(substFnType),
55+
Substitutions(substitutions.begin(), substitutions.end()) {
56+
}
57+
};
58+
59+
/// A function pointer value.
60+
class FunctionPointer {
61+
/// The actual function pointer.
62+
llvm::Value *Value;
63+
64+
Signature Sig;
65+
66+
public:
67+
/// Construct a FunctionPointer for an arbitrary pointer value.
68+
/// We may add more arguments to this; try to use the other
69+
/// constructors/factories if possible.
70+
explicit FunctionPointer(llvm::Value *value, const Signature &signature)
71+
: Value(value), Sig(signature) {
72+
// The function pointer should have function type.
73+
assert(value->getType()->getPointerElementType()->isFunctionTy());
74+
// TODO: maybe assert similarity to signature.getType()?
75+
}
76+
77+
static FunctionPointer forDirect(IRGenModule &IGM,
78+
llvm::Constant *value,
79+
CanSILFunctionType fnType);
80+
81+
static FunctionPointer forDirect(llvm::Constant *value,
82+
const Signature &signature) {
83+
return FunctionPointer(value, signature);
84+
}
85+
86+
static FunctionPointer forExplosionValue(IRGenFunction &IGF,
87+
llvm::Value *fnPtr,
88+
CanSILFunctionType fnType);
89+
90+
/// Return the actual function pointer.
91+
llvm::Value *getPointer() const { return Value; }
92+
93+
/// Given that this value is known to have been constructed from
94+
/// a direct function, return the function pointer.
95+
llvm::Constant *getDirectPointer() const {
96+
return cast<llvm::Constant>(Value);
97+
}
98+
99+
llvm::FunctionType *getFunctionType() const {
100+
return cast<llvm::FunctionType>(
101+
Value->getType()->getPointerElementType());
102+
}
103+
104+
const Signature &getSignature() const {
105+
return Sig;
106+
}
107+
108+
llvm::CallingConv::ID getCallingConv() const {
109+
return Sig.getCallingConv();
110+
}
111+
112+
llvm::AttributeSet getAttributes() const {
113+
return Sig.getAttributes();
114+
}
115+
llvm::AttributeSet &getMutableAttributes() & {
116+
return Sig.getMutableAttributes();
117+
}
118+
119+
ForeignFunctionInfo getForeignInfo() const {
120+
return Sig.getForeignInfo();
121+
}
122+
123+
llvm::Value *getExplosionValue(IRGenFunction &IGF,
124+
CanSILFunctionType fnType) const;
125+
};
126+
127+
class Callee {
128+
CalleeInfo Info;
129+
130+
/// The actual function pointer to invoke.
131+
FunctionPointer Fn;
132+
133+
/// The first data pointer required by the function invocation.
134+
llvm::Value *FirstData;
135+
136+
/// The second data pointer required by the function invocation.
137+
llvm::Value *SecondData;
138+
60139
public:
61-
Callee() = default;
62-
63-
/// Prepare a callee for a known function with a known data pointer.
64-
static Callee forKnownFunction(CanSILFunctionType origFnType,
65-
CanSILFunctionType substFnType,
66-
SubstitutionList subs,
67-
llvm::Value *fn, llvm::Value *data,
68-
ForeignFunctionInfo foreignInfo) {
69-
// Invariant on the function pointer.
70-
assert(fn->getType()->getPointerElementType()->isFunctionTy());
71-
assert((foreignInfo.ClangInfo != nullptr) ==
72-
(origFnType->getLanguage() == SILFunctionLanguage::C));
73-
74-
Callee result;
75-
result.OrigFnType = origFnType;
76-
result.SubstFnType = substFnType;
77-
result.FnPtr = fn;
78-
result.DataPtr = data;
79-
result.Substitutions = subs;
80-
result.ForeignInfo = foreignInfo;
81-
return result;
82-
}
83-
140+
Callee(const Callee &other) = delete;
141+
Callee &operator=(const Callee &other) = delete;
142+
143+
Callee(Callee &&other) = default;
144+
Callee &operator=(Callee &&other) = default;
145+
146+
Callee(CalleeInfo &&info, const FunctionPointer &fn,
147+
llvm::Value *firstData = nullptr,
148+
llvm::Value *secondData = nullptr);
149+
84150
SILFunctionTypeRepresentation getRepresentation() const {
85-
return OrigFnType->getRepresentation();
151+
return Info.OrigFnType->getRepresentation();
86152
}
87153

88-
CanSILFunctionType getOrigFunctionType() const { return OrigFnType; }
89-
CanSILFunctionType getSubstFunctionType() const { return SubstFnType; }
154+
CanSILFunctionType getOrigFunctionType() const {
155+
return Info.OrigFnType;
156+
}
157+
CanSILFunctionType getSubstFunctionType() const {
158+
return Info.SubstFnType;
159+
}
90160

91-
bool hasSubstitutions() const { return !Substitutions.empty(); }
92-
SubstitutionList getSubstitutions() const { return Substitutions; }
161+
bool hasSubstitutions() const { return !Info.Substitutions.empty(); }
162+
SubstitutionList getSubstitutions() const { return Info.Substitutions; }
93163

94-
llvm::Value *getFunction() const { return FnPtr; }
164+
const FunctionPointer &getFunctionPointer() const { return Fn; }
95165

96166
llvm::FunctionType *getLLVMFunctionType() {
97-
return cast<llvm::FunctionType>(FnPtr->getType()->getPointerElementType());
167+
return Fn.getFunctionType();
168+
}
169+
170+
llvm::AttributeSet getAttributes() const {
171+
return Fn.getAttributes();
172+
}
173+
llvm::AttributeSet &getMutableAttributes() & {
174+
return Fn.getMutableAttributes();
98175
}
99176

100-
const ForeignFunctionInfo &getForeignInfo() const {
101-
return ForeignInfo;
177+
ForeignFunctionInfo getForeignInfo() const {
178+
return Fn.getForeignInfo();
102179
}
103180

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

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

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

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

117197
} // end namespace irgen

0 commit comments

Comments
 (0)