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