1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 */
6 module llvm_hiwrap.value.function_;
7 
8 import llvm_hiwrap.types;
9 
10 /**
11  * Functions in this group operate on LLVMValueRef instances that correspond to
12  * llvm::Function instances.
13  */
14 struct FunctionValue {
15     import llvm;
16     import llvm_hiwrap : Value;
17     import llvm_hiwrap.value.basic_block;
18 
19     LxFunctionValue value;
20     alias value this;
21 
22     Value asValue() {
23         return Value(value);
24     }
25 
26     /// Returns: range over the paramters
27     auto parameters() {
28         return ParametersRange(this);
29     }
30 
31     /// Obtain the number of basic blocks in a function.
32     auto countBasicBlocks() {
33         return LLVMCountBasicBlocks(this);
34     }
35 
36     /// Returns: range over all basic blocks in the function.
37     auto basicBlocks() {
38         return BasicBlockRange(this);
39     }
40 
41     /** Obtain the basic block that corresponds to the entry point of a
42      * function.
43      *
44      * @see llvm::Function::getEntryBlock()
45      */
46     EntryBasicBlock entryBlock() {
47         return LLVMGetEntryBasicBlock(value).LxBasicBlock.LxEntryBasicBlock.EntryBasicBlock;
48     }
49 
50     /** Check whether the given function has a personality function.
51      *
52      * @see llvm::Function::hasPersonalityFn()
53      */
54     bool hasPersonalityFn() {
55         return LLVMHasPersonalityFn(value) != 0;
56     }
57 
58     /** Obtain the personality function attached to the function.
59      *
60      * @see llvm::Function::getPersonalityFn()
61      */
62     FunctionValue personalityFn() {
63         assert(hasPersonalityFn);
64         auto v = LLVMGetPersonalityFn(value);
65         return v.LxValue.LxUserValue.LxFunctionValue.FunctionValue;
66     }
67 
68     /**
69      * Set the personality function attached to the function.
70      *
71      * @see llvm::Function::setPersonalityFn()
72      */
73     //void LLVMSetPersonalityFn(LLVMValueRef Fn, LLVMValueRef PersonalityFn);
74 
75     /** Obtain the ID number from a function instance.
76      *
77      * @see llvm::Function::getIntrinsicID()
78      */
79     FuncIntrinsicId intrinsicId() {
80         return LLVMGetIntrinsicID(value).FuncIntrinsicId;
81     }
82 
83     /**
84      * Obtain the calling function of a function.
85      *
86      * The returned value corresponds to the LLVMCallConv enumeration.
87      *
88      * @see llvm::Function::getCallingConv()
89      */
90     LxCallConv callConv() {
91         return LLVMGetFunctionCallConv(value).toCallConv;
92     }
93 
94     /** Remove a function from its containing module and deletes it.
95      *
96      * @see llvm::Function::eraseFromParent()
97      */
98     void remove() {
99         LLVMDeleteFunction(this);
100     }
101 
102     /**
103      * Set the calling convention of a function.
104      *
105      * @see llvm::Function::setCallingConv()
106      *
107      * @param Fn Function to operate on
108      * @param CC LLVMCallConv to set calling convention to
109      */
110     //void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC);
111 
112     /**
113      * Obtain the name of the garbage collector to use during code
114      * generation.
115      *
116      * @see llvm::Function::getGC()
117      */
118     //const char *LLVMGetGC(LLVMValueRef Fn);
119 
120     /**
121      * Define the garbage collector to use during code generation.
122      *
123      * @see llvm::Function::setGC()
124      */
125     //void LLVMSetGC(LLVMValueRef Fn, const char *Name);
126 
127     /**
128      * Add an attribute to a function.
129      *
130      * @see llvm::Function::addAttribute()
131      */
132     //void LLVMAddAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
133     //                             LLVMAttributeRef A);
134     //unsigned LLVMGetAttributeCountAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx);
135     //void LLVMGetAttributesAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
136     //                              LLVMAttributeRef *Attrs);
137     //LLVMAttributeRef LLVMGetEnumAttributeAtIndex(LLVMValueRef F,
138     //                                             LLVMAttributeIndex Idx,
139     //                                             unsigned KindID);
140     //LLVMAttributeRef LLVMGetStringAttributeAtIndex(LLVMValueRef F,
141     //                                               LLVMAttributeIndex Idx,
142     //                                               const char *K, unsigned KLen);
143     //void LLVMRemoveEnumAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
144     //                                    unsigned KindID);
145     //void LLVMRemoveStringAttributeAtIndex(LLVMValueRef F, LLVMAttributeIndex Idx,
146     //                                      const char *K, unsigned KLen);
147 
148     /**
149      * Add a target-dependent attribute to a function
150      * @see llvm::AttrBuilder::addAttribute()
151      */
152     //void LLVMAddTargetDependentFunctionAttr(LLVMValueRef Fn, const char *A,
153     //                                        const char *V);
154 
155     /**
156      * Append a basic block to the end of a function.
157      *
158      * @see llvm::BasicBlock::Create()
159      */
160     //LLVMBasicBlockRef LLVMAppendBasicBlockInContext(LLVMContextRef C,
161     //                                                LLVMValueRef Fn,
162     //                                                const char *Name);
163 
164     /**
165      * Append a basic block to the end of a function using the global
166      * context.
167      *
168      * @see llvm::BasicBlock::Create()
169      */
170     //LLVMBasicBlockRef LLVMAppendBasicBlock(LLVMValueRef Fn, const char *Name);
171 
172     /**
173      * Insert a basic block in a function before another basic block.
174      *
175      * The function to add to is determined by the function of the
176      * passed basic block.
177      *
178      * @see llvm::BasicBlock::Create()
179      */
180     //LLVMBasicBlockRef LLVMInsertBasicBlockInContext(LLVMContextRef C,
181     //                                                LLVMBasicBlockRef BB,
182     //                                                const char *Name);
183 
184     /**
185      * Insert a basic block in a function using the global context.
186      *
187      * @see llvm::BasicBlock::Create()
188      */
189     //LLVMBasicBlockRef LLVMInsertBasicBlock(LLVMBasicBlockRef InsertBeforeBB,
190     //                                       const char *Name);
191 }
192 
193 struct FuncIntrinsicId {
194     uint value;
195     alias value this;
196 
197     /// A normal function has the value 0.
198     bool isIntrinsic() {
199         return value != 0;
200     }
201 }
202 
203 // Range over all of the basic blocks in a function.
204 // TODO end is also a valid basic block. Instead check if LLVMGetNextBasicBlock returns null.
205 struct BasicBlockRange {
206     import llvm;
207     import llvm_hiwrap.value.basic_block;
208 
209     const size_t length;
210 
211     private LxBasicBlock cur;
212     private const LxBasicBlock end;
213 
214     this(FunctionValue v) {
215         length = LLVMCountBasicBlocks(v);
216         cur = LLVMGetFirstBasicBlock(v).LxBasicBlock;
217         end = LLVMGetLastBasicBlock(v).LxBasicBlock;
218     }
219 
220     BasicBlock front() {
221         assert(!empty, "Can't get front of an empty range");
222         return cur.BasicBlock;
223     }
224 
225     void popFront() {
226         assert(!empty, "Can't pop front of an empty range");
227         cur = LLVMGetNextBasicBlock(cur).LxBasicBlock;
228     }
229 
230     bool empty() {
231         return cur == end;
232     }
233 }
234 
235 struct ParametersRange {
236     import llvm;
237     import llvm_hiwrap.value.parameter;
238 
239     const size_t length;
240 
241     private FunctionValue value;
242 
243     this(FunctionValue v) {
244         value = v;
245         length = LLVMCountParams(v);
246     }
247 
248     ParameterValue opIndex(size_t index) nothrow {
249         assert(index < length);
250         return LLVMGetParam(value, cast(uint) index).LxValue.ParameterValue;
251     }
252 
253     import llvm_hiwrap.util;
254 
255     mixin IndexedRangeX!ParameterValue;
256 }
257 
258 mixin template FunctionAccept(VisitorT, UserT) {
259     import llvm_hiwrap.value.function_;
260 
261     void implAccept(ref FunctionValue n) {
262         import llvm_hiwrap.ast.tree : maybeCallVisit;
263 
264         // or it can crash when calling entryBlock
265         if (n.countBasicBlocks == 0)
266             return;
267 
268         auto entry = n.entryBlock;
269         // no fallback because IF the user hasn't implemented a visit for
270         // EntryBasicBlock it means the user is not interested in visiting that
271         // part of the tree.
272         maybeCallVisit(this, user, entry);
273     }
274 }
275 
276 /** A depth-first visitor.
277  *
278  * See: llvm_hiwrap.ast.tree
279  *
280  * Accepted node types are:
281  *  - FunctionValue
282  *
283  * and those specified in:
284  * See: llvm_hiwrap.value.basic_block
285  *
286  */
287 struct FunctionVisitor(UserT) {
288     import llvm_hiwrap.value.basic_block : BasicBlockAccept;
289 
290     UserT user;
291 
292     void visit(ref FunctionValue n) {
293         import llvm_hiwrap.ast.tree;
294 
295         static void fallback(T)(ref this self, ref UserT user, ref T node) {
296             accept(n, self);
297         }
298 
299         maybeCallVisit(this, user, n);
300     }
301 
302     mixin FunctionAccept!(FunctionVisitor, UserT);
303     mixin BasicBlockAccept!(FunctionVisitor, UserT);
304 }
305 
306 @("shall be an instance of FunctionVisitor")
307 unittest {
308     import llvm_hiwrap.ast.tree;
309 
310     struct Null {
311     }
312 
313     FunctionVisitor!Null v;
314 }