authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-01-06 00:34:11+01:00
committergravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-01-06 10:52:20+01:00
log31d1ec4c2fd0d1e07e0020b19b7bca8196d7879c
treedac56ed37e0a825de481088993ccc5bce25bdf7a
parent5d5db833f277518bab152b743d6a4cfaa1e3fd8d

stage2: make use of `llvm.Context` in LLVM backend

This for example allows for multiple LLVM instances to run in parallel. Also rename some functions in llvm_bindings.zig. Fixes #7688

2 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 {
140140pub const LLVMIRModule = struct {
141141 module: *Module,
142142 llvm_module: *const llvm.Module,
143 context: *const llvm.Context,
143144 target_machine: *const llvm.TargetMachine,
144145 builder: *const llvm.Builder,
145146
......@@ -181,19 +182,22 @@ pub const LLVMIRModule = struct {
181182 const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename});
182183 errdefer gpa.free(object_path);
183184
185 const context = llvm.Context.create();
186 errdefer context.dispose();
187
184188 initializeLLVMTargets();
185189
186190 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
187191 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();
190194
191195 const llvm_target_triple = try targetTriple(gpa, options.target);
192196 defer gpa.free(llvm_target_triple);
193197
194198 var error_message: [*:0]const u8 = undefined;
195199 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)) {
197201 defer llvm.disposeMessage(error_message);
198202
199203 const stderr = std.io.getStdErr().outStream();
......@@ -213,7 +217,7 @@ pub const LLVMIRModule = struct {
213217 }
214218
215219 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(
217221 target,
218222 llvm_target_triple.ptr,
219223 "",
......@@ -222,14 +226,15 @@ pub const LLVMIRModule = struct {
222226 .Static,
223227 .Default,
224228 );
225 errdefer target_machine.disposeTargetMachine();
229 errdefer target_machine.dispose();
226230
227 const builder = llvm.Builder.createBuilder();
228 errdefer builder.disposeBuilder();
231 const builder = context.createBuilder();
232 errdefer builder.dispose();
229233
230234 self.* = .{
231235 .module = options.module.?,
232236 .llvm_module = llvm_module,
237 .context = context,
233238 .target_machine = target_machine,
234239 .builder = builder,
235240 .object_path = object_path,
......@@ -239,9 +244,10 @@ pub const LLVMIRModule = struct {
239244 }
240245
241246 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();
245251
246252 self.func_inst_table.deinit(self.gpa);
247253 self.gpa.free(self.object_path);
......@@ -271,7 +277,7 @@ pub const LLVMIRModule = struct {
271277 // verifyModule always allocs the error_message even if there is no error
272278 defer llvm.disposeMessage(error_message);
273279
274 if (self.llvm_module.verifyModule(.ReturnStatus, &error_message)) {
280 if (self.llvm_module.verify(.ReturnStatus, &error_message)) {
275281 const stderr = std.io.getStdErr().outStream();
276282 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});
277283 return error.BrokenLLVMModule;
......@@ -340,7 +346,7 @@ pub const LLVMIRModule = struct {
340346 bb.deleteBasicBlock();
341347 }
342348
343 self.entry_block = llvm_func.appendBasicBlock("Entry");
349 self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry");
344350 self.builder.positionBuilderAtEnd(self.entry_block);
345351 self.latest_alloca_inst = null;
346352
......@@ -606,7 +612,7 @@ pub const LLVMIRModule = struct {
606612 return self.fail(src, "TODO handle other sentinel values", .{});
607613 } else false;
608614
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);
610616 } else {
611617 return self.fail(src, "TODO handle more array values", .{});
612618 }
......@@ -617,13 +623,13 @@ pub const LLVMIRModule = struct {
617623
618624 fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
619625 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(),
622628 .Int => {
623629 const info = t.intInfo(self.module.getTarget());
624 return llvm.intType(info.bits);
630 return self.context.intType(info.bits);
625631 },
626 .Bool => return llvm.intType(1),
632 .Bool => return self.context.intType(1),
627633 .Pointer => {
628634 if (t.isSlice()) {
629635 return self.fail(src, "TODO: LLVM backend: implement slices", .{});
......@@ -688,12 +694,25 @@ pub const LLVMIRModule = struct {
688694 const llvm_fn = self.llvm_module.addFunction(func.name, fn_type);
689695
690696 if (return_type.tag() == .noreturn) {
691 llvm_fn.addFnAttr("noreturn");
697 self.addFnAttr(llvm_fn, "noreturn");
692698 }
693699
694700 return llvm_fn;
695701 }
696702
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
697716 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
698717 @setCold(true);
699718 assert(self.err_msg == null);
src/llvm_bindings.zig+37-48
......@@ -5,35 +5,44 @@ const std = @import("std");
55const assert = std.debug.assert;
66
77const LLVMBool = bool;
8pub const LLVMAttributeIndex = c_uint;
8pub const AttributeIndex = c_uint;
9
10/// Make sure to use the *InContext functions instead of the global ones.
11pub 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};
936
1037pub const Value = opaque {
1138 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;
1640
1741 pub const getFirstBasicBlock = LLVMGetFirstBasicBlock;
1842 extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock;
1943
2044 pub const getNextInstruction = LLVMGetNextInstruction;
2145 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 }
3746};
3847
3948pub const Type = opaque {
......@@ -63,13 +72,13 @@ pub const Type = opaque {
6372};
6473
6574pub 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;
6877
69 pub const disposeModule = LLVMDisposeModule;
78 pub const dispose = LLVMDisposeModule;
7079 extern fn LLVMDisposeModule(*const Module) void;
7180
72 pub const verifyModule = LLVMVerifyModule;
81 pub const verify = LLVMVerifyModule;
7382 extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool;
7483
7584 pub const addFunction = LLVMAddFunction;
......@@ -106,15 +115,9 @@ pub const VerifierFailureAction = extern enum {
106115pub const constNeg = LLVMConstNeg;
107116extern fn LLVMConstNeg(ConstantVal: *const Value) *const Value;
108117
109pub const constString = LLVMConstString;
110extern fn LLVMConstString(Str: [*]const u8, Length: c_uint, DontNullTerminate: LLVMBool) *const Value;
111
112118pub const setInitializer = LLVMSetInitializer;
113119extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void;
114120
115pub const voidType = LLVMVoidType;
116extern fn LLVMVoidType() *const Type;
117
118121pub const getParam = LLVMGetParam;
119122extern fn LLVMGetParam(Fn: *const Value, Index: c_uint) *const Value;
120123
......@@ -123,22 +126,8 @@ extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint
123126
124127pub const Attribute = opaque {};
125128
126pub 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
134pub const intType = LLVMIntType;
135extern fn LLVMIntType(NumBits: c_uint) *const Type;
136
137129pub 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;
142131 extern fn LLVMDisposeBuilder(Builder: *const Builder) void;
143132
144133 pub const positionBuilder = LLVMPositionBuilder;
......@@ -208,7 +197,7 @@ pub const BasicBlock = opaque {
208197};
209198
210199pub const TargetMachine = opaque {
211 pub const createTargetMachine = LLVMCreateTargetMachine;
200 pub const create = LLVMCreateTargetMachine;
212201 extern fn LLVMCreateTargetMachine(
213202 T: *const Target,
214203 Triple: [*:0]const u8,
......@@ -219,7 +208,7 @@ pub const TargetMachine = opaque {
219208 CodeModel: CodeMode,
220209 ) *const TargetMachine;
221210
222 pub const disposeTargetMachine = LLVMDisposeTargetMachine;
211 pub const dispose = LLVMDisposeTargetMachine;
223212 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;
224213
225214 pub const emitToFile = LLVMTargetMachineEmitToFile;
......@@ -259,7 +248,7 @@ pub const CodeGenFileType = extern enum {
259248};
260249
261250pub const Target = opaque {
262 pub const getTargetFromTriple = LLVMGetTargetFromTriple;
251 pub const getFromTriple = LLVMGetTargetFromTriple;
263252 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool;
264253};
265254