| author | |
| committer | |
| log | 31d1ec4c2fd0d1e07e0020b19b7bca8196d7879c |
| tree | dac56ed37e0a825de481088993ccc5bce25bdf7a |
| parent | 5d5db833f277518bab152b743d6a4cfaa1e3fd8d |
This for example allows for multiple LLVM instances to run in parallel.
Also rename some functions in llvm_bindings.zig.
Fixes #76882 files changed, 74 insertions(+), 66 deletions(-)
src/llvm_backend.zig+37-18| ... | ... | @@ -140,6 +140,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 { |
| 140 | 140 | pub const LLVMIRModule = struct { |
| 141 | 141 | module: *Module, |
| 142 | 142 | llvm_module: *const llvm.Module, |
| 143 | context: *const llvm.Context, | |
| 143 | 144 | target_machine: *const llvm.TargetMachine, |
| 144 | 145 | builder: *const llvm.Builder, |
| 145 | 146 | |
| ... | ... | @@ -181,19 +182,22 @@ pub const LLVMIRModule = struct { |
| 181 | 182 | const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename}); |
| 182 | 183 | errdefer gpa.free(object_path); |
| 183 | 184 | |
| 185 | const context = llvm.Context.create(); | |
| 186 | errdefer context.dispose(); | |
| 187 | ||
| 184 | 188 | initializeLLVMTargets(); |
| 185 | 189 | |
| 186 | 190 | const root_nameZ = try gpa.dupeZ(u8, options.root_name); |
| 187 | 191 | defer gpa.free(root_nameZ); |
| 188 | const llvm_module = llvm.Module.createWithName(root_nameZ.ptr); | |
| 189 | errdefer llvm_module.disposeModule(); | |
| 192 | const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context); | |
| 193 | errdefer llvm_module.dispose(); | |
| 190 | 194 | |
| 191 | 195 | const llvm_target_triple = try targetTriple(gpa, options.target); |
| 192 | 196 | defer gpa.free(llvm_target_triple); |
| 193 | 197 | |
| 194 | 198 | var error_message: [*:0]const u8 = undefined; |
| 195 | 199 | var target: *const llvm.Target = undefined; |
| 196 | if (llvm.Target.getTargetFromTriple(llvm_target_triple.ptr, &target, &error_message)) { | |
| 200 | if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message)) { | |
| 197 | 201 | defer llvm.disposeMessage(error_message); |
| 198 | 202 | |
| 199 | 203 | const stderr = std.io.getStdErr().outStream(); |
| ... | ... | @@ -213,7 +217,7 @@ pub const LLVMIRModule = struct { |
| 213 | 217 | } |
| 214 | 218 | |
| 215 | 219 | const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive; |
| 216 | const target_machine = llvm.TargetMachine.createTargetMachine( | |
| 220 | const target_machine = llvm.TargetMachine.create( | |
| 217 | 221 | target, |
| 218 | 222 | llvm_target_triple.ptr, |
| 219 | 223 | "", |
| ... | ... | @@ -222,14 +226,15 @@ pub const LLVMIRModule = struct { |
| 222 | 226 | .Static, |
| 223 | 227 | .Default, |
| 224 | 228 | ); |
| 225 | errdefer target_machine.disposeTargetMachine(); | |
| 229 | errdefer target_machine.dispose(); | |
| 226 | 230 | |
| 227 | const builder = llvm.Builder.createBuilder(); | |
| 228 | errdefer builder.disposeBuilder(); | |
| 231 | const builder = context.createBuilder(); | |
| 232 | errdefer builder.dispose(); | |
| 229 | 233 | |
| 230 | 234 | self.* = .{ |
| 231 | 235 | .module = options.module.?, |
| 232 | 236 | .llvm_module = llvm_module, |
| 237 | .context = context, | |
| 233 | 238 | .target_machine = target_machine, |
| 234 | 239 | .builder = builder, |
| 235 | 240 | .object_path = object_path, |
| ... | ... | @@ -239,9 +244,10 @@ pub const LLVMIRModule = struct { |
| 239 | 244 | } |
| 240 | 245 | |
| 241 | 246 | pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void { |
| 242 | self.builder.disposeBuilder(); | |
| 243 | self.target_machine.disposeTargetMachine(); | |
| 244 | self.llvm_module.disposeModule(); | |
| 247 | self.builder.dispose(); | |
| 248 | self.target_machine.dispose(); | |
| 249 | self.llvm_module.dispose(); | |
| 250 | self.context.dispose(); | |
| 245 | 251 | |
| 246 | 252 | self.func_inst_table.deinit(self.gpa); |
| 247 | 253 | self.gpa.free(self.object_path); |
| ... | ... | @@ -271,7 +277,7 @@ pub const LLVMIRModule = struct { |
| 271 | 277 | // verifyModule always allocs the error_message even if there is no error |
| 272 | 278 | defer llvm.disposeMessage(error_message); |
| 273 | 279 | |
| 274 | if (self.llvm_module.verifyModule(.ReturnStatus, &error_message)) { | |
| 280 | if (self.llvm_module.verify(.ReturnStatus, &error_message)) { | |
| 275 | 281 | const stderr = std.io.getStdErr().outStream(); |
| 276 | 282 | try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message}); |
| 277 | 283 | return error.BrokenLLVMModule; |
| ... | ... | @@ -340,7 +346,7 @@ pub const LLVMIRModule = struct { |
| 340 | 346 | bb.deleteBasicBlock(); |
| 341 | 347 | } |
| 342 | 348 | |
| 343 | self.entry_block = llvm_func.appendBasicBlock("Entry"); | |
| 349 | self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry"); | |
| 344 | 350 | self.builder.positionBuilderAtEnd(self.entry_block); |
| 345 | 351 | self.latest_alloca_inst = null; |
| 346 | 352 | |
| ... | ... | @@ -606,7 +612,7 @@ pub const LLVMIRModule = struct { |
| 606 | 612 | return self.fail(src, "TODO handle other sentinel values", .{}); |
| 607 | 613 | } else false; |
| 608 | 614 | |
| 609 | return llvm.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), !zero_sentinel); | |
| 615 | return self.context.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), !zero_sentinel); | |
| 610 | 616 | } else { |
| 611 | 617 | return self.fail(src, "TODO handle more array values", .{}); |
| 612 | 618 | } |
| ... | ... | @@ -617,13 +623,13 @@ pub const LLVMIRModule = struct { |
| 617 | 623 | |
| 618 | 624 | fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Type { |
| 619 | 625 | switch (t.zigTypeTag()) { |
| 620 | .Void => return llvm.voidType(), | |
| 621 | .NoReturn => return llvm.voidType(), | |
| 626 | .Void => return self.context.voidType(), | |
| 627 | .NoReturn => return self.context.voidType(), | |
| 622 | 628 | .Int => { |
| 623 | 629 | const info = t.intInfo(self.module.getTarget()); |
| 624 | return llvm.intType(info.bits); | |
| 630 | return self.context.intType(info.bits); | |
| 625 | 631 | }, |
| 626 | .Bool => return llvm.intType(1), | |
| 632 | .Bool => return self.context.intType(1), | |
| 627 | 633 | .Pointer => { |
| 628 | 634 | if (t.isSlice()) { |
| 629 | 635 | return self.fail(src, "TODO: LLVM backend: implement slices", .{}); |
| ... | ... | @@ -688,12 +694,25 @@ pub const LLVMIRModule = struct { |
| 688 | 694 | const llvm_fn = self.llvm_module.addFunction(func.name, fn_type); |
| 689 | 695 | |
| 690 | 696 | if (return_type.tag() == .noreturn) { |
| 691 | llvm_fn.addFnAttr("noreturn"); | |
| 697 | self.addFnAttr(llvm_fn, "noreturn"); | |
| 692 | 698 | } |
| 693 | 699 | |
| 694 | 700 | return llvm_fn; |
| 695 | 701 | } |
| 696 | 702 | |
| 703 | // Helper functions | |
| 704 | fn addAttr(self: LLVMIRModule, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void { | |
| 705 | const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len); | |
| 706 | assert(kind_id != 0); | |
| 707 | const llvm_attr = self.context.createEnumAttribute(kind_id, 0); | |
| 708 | val.addAttributeAtIndex(index, llvm_attr); | |
| 709 | } | |
| 710 | ||
| 711 | fn addFnAttr(self: *LLVMIRModule, val: *const llvm.Value, attr_name: []const u8) void { | |
| 712 | // TODO: improve this API, `addAttr(-1, attr_name)` | |
| 713 | self.addAttr(val, std.math.maxInt(llvm.AttributeIndex), attr_name); | |
| 714 | } | |
| 715 | ||
| 697 | 716 | pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 698 | 717 | @setCold(true); |
| 699 | 718 | assert(self.err_msg == null); |
src/llvm_bindings.zig+37-48| ... | ... | @@ -5,35 +5,44 @@ const std = @import("std"); |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | 6 | |
| 7 | 7 | const LLVMBool = bool; |
| 8 | pub const LLVMAttributeIndex = c_uint; | |
| 8 | pub const AttributeIndex = c_uint; | |
| 9 | ||
| 10 | /// Make sure to use the *InContext functions instead of the global ones. | |
| 11 | pub const Context = opaque { | |
| 12 | pub const create = LLVMContextCreate; | |
| 13 | extern fn LLVMContextCreate() *const Context; | |
| 14 | ||
| 15 | pub const dispose = LLVMContextDispose; | |
| 16 | extern fn LLVMContextDispose(C: *const Context) void; | |
| 17 | ||
| 18 | pub const createEnumAttribute = LLVMCreateEnumAttribute; | |
| 19 | extern fn LLVMCreateEnumAttribute(*const Context, KindID: c_uint, Val: u64) *const Attribute; | |
| 20 | ||
| 21 | pub const intType = LLVMIntTypeInContext; | |
| 22 | extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type; | |
| 23 | ||
| 24 | pub const voidType = LLVMVoidTypeInContext; | |
| 25 | extern fn LLVMVoidTypeInContext(C: *const Context) *const Type; | |
| 26 | ||
| 27 | pub const constString = LLVMConstStringInContext; | |
| 28 | extern fn LLVMConstStringInContext(C: *const Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value; | |
| 29 | ||
| 30 | pub const appendBasicBlock = LLVMAppendBasicBlockInContext; | |
| 31 | extern fn LLVMAppendBasicBlockInContext(C: *const Context, Fn: *const Value, Name: [*:0]const u8) *const BasicBlock; | |
| 32 | ||
| 33 | pub const createBuilder = LLVMCreateBuilderInContext; | |
| 34 | extern fn LLVMCreateBuilderInContext(C: *const Context) *const Builder; | |
| 35 | }; | |
| 9 | 36 | |
| 10 | 37 | pub const Value = opaque { |
| 11 | 38 | pub const addAttributeAtIndex = LLVMAddAttributeAtIndex; |
| 12 | extern fn LLVMAddAttributeAtIndex(*const Value, Idx: LLVMAttributeIndex, A: *const Attribute) void; | |
| 13 | ||
| 14 | pub const appendBasicBlock = LLVMAppendBasicBlock; | |
| 15 | extern fn LLVMAppendBasicBlock(Fn: *const Value, Name: [*:0]const u8) *const BasicBlock; | |
| 39 | extern fn LLVMAddAttributeAtIndex(*const Value, Idx: AttributeIndex, A: *const Attribute) void; | |
| 16 | 40 | |
| 17 | 41 | pub const getFirstBasicBlock = LLVMGetFirstBasicBlock; |
| 18 | 42 | extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock; |
| 19 | 43 | |
| 20 | 44 | pub const getNextInstruction = LLVMGetNextInstruction; |
| 21 | 45 | extern fn LLVMGetNextInstruction(Inst: *const Value) ?*const Value; |
| 22 | ||
| 23 | // Helper functions | |
| 24 | // TODO: Do we want to put these functions here? It allows for convienient function calls | |
| 25 | // on Value: llvm_fn.addFnAttr("noreturn") | |
| 26 | fn addAttr(val: *const Value, index: LLVMAttributeIndex, name: []const u8) void { | |
| 27 | const kind_id = getEnumAttributeKindForName(name.ptr, name.len); | |
| 28 | assert(kind_id != 0); | |
| 29 | const llvm_attr = Context.getGlobal().createEnumAttribute(kind_id, 0); | |
| 30 | val.addAttributeAtIndex(index, llvm_attr); | |
| 31 | } | |
| 32 | ||
| 33 | pub fn addFnAttr(val: *const Value, attr_name: []const u8) void { | |
| 34 | // TODO: improve this API, `addAttr(-1, attr_name)` | |
| 35 | val.addAttr(std.math.maxInt(LLVMAttributeIndex), attr_name); | |
| 36 | } | |
| 37 | 46 | }; |
| 38 | 47 | |
| 39 | 48 | pub const Type = opaque { |
| ... | ... | @@ -63,13 +72,13 @@ pub const Type = opaque { |
| 63 | 72 | }; |
| 64 | 73 | |
| 65 | 74 | pub const Module = opaque { |
| 66 | pub const createWithName = LLVMModuleCreateWithName; | |
| 67 | extern fn LLVMModuleCreateWithName(ModuleID: [*:0]const u8) *const Module; | |
| 75 | pub const createWithName = LLVMModuleCreateWithNameInContext; | |
| 76 | extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *const Context) *const Module; | |
| 68 | 77 | |
| 69 | pub const disposeModule = LLVMDisposeModule; | |
| 78 | pub const dispose = LLVMDisposeModule; | |
| 70 | 79 | extern fn LLVMDisposeModule(*const Module) void; |
| 71 | 80 | |
| 72 | pub const verifyModule = LLVMVerifyModule; | |
| 81 | pub const verify = LLVMVerifyModule; | |
| 73 | 82 | extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool; |
| 74 | 83 | |
| 75 | 84 | pub const addFunction = LLVMAddFunction; |
| ... | ... | @@ -106,15 +115,9 @@ pub const VerifierFailureAction = extern enum { |
| 106 | 115 | pub const constNeg = LLVMConstNeg; |
| 107 | 116 | extern fn LLVMConstNeg(ConstantVal: *const Value) *const Value; |
| 108 | 117 | |
| 109 | pub const constString = LLVMConstString; | |
| 110 | extern fn LLVMConstString(Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value; | |
| 111 | ||
| 112 | 118 | pub const setInitializer = LLVMSetInitializer; |
| 113 | 119 | extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void; |
| 114 | 120 | |
| 115 | pub const voidType = LLVMVoidType; | |
| 116 | extern fn LLVMVoidType() *const Type; | |
| 117 | ||
| 118 | 121 | pub const getParam = LLVMGetParam; |
| 119 | 122 | extern fn LLVMGetParam(Fn: *const Value, Index: c_uint) *const Value; |
| 120 | 123 | |
| ... | ... | @@ -123,22 +126,8 @@ extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint |
| 123 | 126 | |
| 124 | 127 | pub const Attribute = opaque {}; |
| 125 | 128 | |
| 126 | pub const Context = opaque { | |
| 127 | pub const createEnumAttribute = LLVMCreateEnumAttribute; | |
| 128 | extern fn LLVMCreateEnumAttribute(*const Context, KindID: c_uint, Val: u64) *const Attribute; | |
| 129 | ||
| 130 | pub const getGlobal = LLVMGetGlobalContext; | |
| 131 | extern fn LLVMGetGlobalContext() *const Context; | |
| 132 | }; | |
| 133 | ||
| 134 | pub const intType = LLVMIntType; | |
| 135 | extern fn LLVMIntType(NumBits: c_uint) *const Type; | |
| 136 | ||
| 137 | 129 | pub const Builder = opaque { |
| 138 | pub const createBuilder = LLVMCreateBuilder; | |
| 139 | extern fn LLVMCreateBuilder() *const Builder; | |
| 140 | ||
| 141 | pub const disposeBuilder = LLVMDisposeBuilder; | |
| 130 | pub const dispose = LLVMDisposeBuilder; | |
| 142 | 131 | extern fn LLVMDisposeBuilder(Builder: *const Builder) void; |
| 143 | 132 | |
| 144 | 133 | pub const positionBuilder = LLVMPositionBuilder; |
| ... | ... | @@ -208,7 +197,7 @@ pub const BasicBlock = opaque { |
| 208 | 197 | }; |
| 209 | 198 | |
| 210 | 199 | pub const TargetMachine = opaque { |
| 211 | pub const createTargetMachine = LLVMCreateTargetMachine; | |
| 200 | pub const create = LLVMCreateTargetMachine; | |
| 212 | 201 | extern fn LLVMCreateTargetMachine( |
| 213 | 202 | T: *const Target, |
| 214 | 203 | Triple: [*:0]const u8, |
| ... | ... | @@ -219,7 +208,7 @@ pub const TargetMachine = opaque { |
| 219 | 208 | CodeModel: CodeMode, |
| 220 | 209 | ) *const TargetMachine; |
| 221 | 210 | |
| 222 | pub const disposeTargetMachine = LLVMDisposeTargetMachine; | |
| 211 | pub const dispose = LLVMDisposeTargetMachine; | |
| 223 | 212 | extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void; |
| 224 | 213 | |
| 225 | 214 | pub const emitToFile = LLVMTargetMachineEmitToFile; |
| ... | ... | @@ -259,7 +248,7 @@ pub const CodeGenFileType = extern enum { |
| 259 | 248 | }; |
| 260 | 249 | |
| 261 | 250 | pub const Target = opaque { |
| 262 | pub const getTargetFromTriple = LLVMGetTargetFromTriple; | |
| 251 | pub const getFromTriple = LLVMGetTargetFromTriple; | |
| 263 | 252 | extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool; |
| 264 | 253 | }; |
| 265 | 254 |