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 }