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 }