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 Modules represent the top-level structure in an LLVM program. An LLVM module is
7 effectively a translation unit or a collection of translation units merged
8 together.
9 */
10 module llvm_hiwrap.module_;
11 
12 import llvm : LLVMVerifyModule, LLVMModuleCreateWithName, LLVMModuleRef,
13     LLVMDisposeModule, LLVMBool, LLVMVerifierFailureAction,
14     LLVMGetModuleIdentifier;
15 
16 import llvm_hiwrap.util : toD;
17 import llvm_hiwrap.types; // : LxVerifierFailureAction, LxMessage;
18 import llvm_hiwrap.value.function_;
19 
20 import std.conv : to;
21 import std..string : toStringz;
22 import std.typecons : NullableRef;
23 
24 struct Module {
25     import llvm_hiwrap.value.metadata : NamedMetadataValue;
26 
27     LLVMModuleRef lx;
28     alias lx this;
29 
30     @disable this();
31     // if a refcount is used instead this could be removed.
32     @disable this(this);
33 
34     this(LLVMModuleRef m) {
35         this.lx = m;
36     }
37 
38     /** Create a new, empty module in the global context.
39      */
40     this(string module_id) {
41         const(char)* s = module_id.toStringz;
42         lx = LLVMModuleCreateWithName(s);
43     }
44 
45     ~this() {
46         LLVMDisposeModule(lx);
47     }
48 
49     /** Verifies that a module is valid.
50      *
51      * Optionally returns a human-readable description of any invalid
52      * constructs. OutMessage must be disposed with LLVMDisposeMessage.
53      */
54     VerifyResult verify() {
55         LxMessage msg;
56         auto action = LxVerifierFailureAction.ReturnStatusAction.to!LLVMVerifierFailureAction;
57         LLVMBool res = LLVMVerifyModule(lx, action, &msg.rawPtr);
58 
59         return VerifyResult(res == 0, msg.toD);
60     }
61 
62     /** Obtain the identifier of the module.
63      */
64     const(char)[] identifier() {
65         import llvm : LLVMGetModuleIdentifier;
66 
67         size_t len;
68         auto str = LLVMGetModuleIdentifier(lx, &len);
69         return str[0 .. len];
70     }
71 
72     void identifier(string module_id) {
73         import llvm : LLVMSetModuleIdentifier;
74 
75         LLVMSetModuleIdentifier(lx, module_id.ptr, module_id.length);
76     }
77 
78     FunctionRange functions() {
79         return FunctionRange(NullableRef!Module(&this));
80     }
81 
82     /// Returns: Obtain a Function value from a Module by its name.
83     FunctionValue func(string name) {
84         import std..string : toStringz;
85         import llvm : LLVMGetNamedFunction;
86         import llvm_hiwrap;
87 
88         auto s = name.toStringz;
89         auto v = LLVMGetNamedFunction(lx, cast(const(char)*) s);
90         return v.LxValue.LxUserValue.LxFunctionValue.FunctionValue;
91     }
92 
93     /** Writes a module to a new memory buffer and returns it. */
94     auto toBuffer() @trusted {
95         import llvm : LLVMMemoryBufferRef, LLVMWriteBitcodeToMemoryBuffer;
96         import llvm_hiwrap.buffer : MemoryBuffer;
97 
98         LLVMMemoryBufferRef buf = LLVMWriteBitcodeToMemoryBuffer(lx);
99         return MemoryBuffer(buf);
100     }
101 
102     /** Obtain the named metadata operands for a module.
103      *
104      * @see llvm::Module::getNamedMetadata()
105      * @see llvm::MDNode::getOperand()
106      */
107     NamedMetadataValue namedMetadata(string name) {
108         import std.array : array;
109         import std.algorithm : map;
110         import llvm;
111 
112         LLVMValueRef[] ops;
113         auto name_ = name.toStringz;
114         ops.length = LLVMGetNamedMetadataNumOperands(lx, name_);
115 
116         if (ops.length != 0) {
117             LLVMGetNamedMetadataOperands(lx, name_, ops.ptr);
118         }
119 
120         NamedMetadataValue nmd;
121         nmd.operands = ops.map!(a => a.LxValue.LxNamedMetadataNodeValue).array();
122 
123         return nmd;
124     }
125 
126     /** Add an operand to named metadata.
127      *
128      * @see llvm::Module::getNamedMetadata()
129      * @see llvm::MDNode::addOperand()
130      */
131     //void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Name,
132     //                                 LLVMValueRef Val);
133 
134     import std.format : FormatSpec;
135 
136     void toString(Writer, Char)(scope Writer w, FormatSpec!Char fmt) {
137         import std.format : formatValue;
138         import std.range.primitives : put;
139         import llvm : LLVMPrintModuleToString;
140 
141         () @trusted{
142             auto msg = LxMessage(LLVMPrintModuleToString(lx));
143             put(w, msg.toChar);
144         }();
145     }
146 
147     string toString() @safe {
148         import std.exception : assumeUnique;
149         import std.format : FormatSpec;
150 
151         char[] buf;
152         buf.reserve(100);
153         auto fmt = FormatSpec!char("%s");
154         toString((const(char)[] s) { buf ~= s; }, fmt);
155         auto trustedUnique(T)(T t) @trusted {
156             return assumeUnique(t);
157         }
158 
159         return trustedUnique(buf);
160     }
161 }
162 
163 @("the ModuleID shall be changed")
164 unittest {
165     import llvm_hiwrap.context;
166 
167     auto ctx = Context.make;
168 
169     auto m = ctx.makeModule("foo");
170     assert(m.identifier == "foo");
171 
172     m.identifier = "bar";
173     assert(m.identifier == "bar");
174 }
175 
176 struct FunctionRange {
177     import llvm;
178     import llvm_hiwrap;
179 
180     private FunctionValue cur;
181     private const LLVMValueRef end;
182 
183     this(NullableRef!Module parent) {
184         cur = LLVMGetFirstFunction(parent.lx).LxValue.LxUserValue.LxFunctionValue.FunctionValue;
185         end = LLVMGetLastFunction(parent.lx);
186     }
187 
188     FunctionValue front() {
189         assert(!empty, "Can't get front of an empty range");
190         return cur;
191     }
192 
193     void popFront() {
194         assert(!empty, "Can't pop front of an empty range");
195         cur = LLVMGetNextFunction(cur).LxValue.LxUserValue.LxFunctionValue.FunctionValue;
196     }
197 
198     bool empty() {
199         return cur == end;
200     }
201 }
202 
203 mixin template ModuleAccept(VisitorT, UserT) {
204     import llvm_hiwrap.module_;
205 
206     void implAccept(ref Module n) {
207         import llvm_hiwrap.ast.tree;
208 
209         foreach (func; n.functions) {
210             maybeCallVisit(this, user, func);
211         }
212     }
213 }
214 
215 /** A depth-first visitor.
216  *
217  * See: llvm_hiwrap.ast.tree
218  *
219  * Accepted node types are:
220  *  - Module
221  *
222  * and those specified in:
223  * See: llvm_hiwrap.value.function_
224  * See: llvm_hiwrap.value.basic_block
225  */
226 struct ModuleVisitor(UserT) {
227     import llvm_hiwrap.value.basic_block : BasicBlockAccept;
228     import llvm_hiwrap.value.function_ : FunctionAccept;
229 
230     UserT user;
231 
232     void visit(ref Module n) {
233         import llvm_hiwrap.ast.tree;
234 
235         static void fallback(T)(ref this self, ref UserT user, ref T node) {
236             accept(n, self);
237         }
238 
239         maybeCallVisit(this, user, n);
240     }
241 
242     mixin ModuleAccept!(ModuleVisitor, UserT);
243     mixin FunctionAccept!(ModuleVisitor, UserT);
244     mixin BasicBlockAccept!(ModuleVisitor, UserT);
245 }
246 
247 @("shall instantiate a ModuleVisitor")
248 unittest {
249     import llvm_hiwrap.ast.tree;
250     import llvm_hiwrap.context;
251 
252     auto ctx = Context.make;
253 
254     auto m = ctx.makeModule("foo");
255 
256     struct Null {
257     }
258 
259     ModuleVisitor!Null v;
260 }
261 
262 private:
263 
264 struct VerifyResult {
265     const bool isValid;
266     const string errorMsg;
267 }