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 {...@@ -140,6 +140,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
140pub const LLVMIRModule = struct {140pub const LLVMIRModule = struct {
141 module: *Module,141 module: *Module,
142 llvm_module: *const llvm.Module,142 llvm_module: *const llvm.Module,
143 context: *const llvm.Context,
143 target_machine: *const llvm.TargetMachine,144 target_machine: *const llvm.TargetMachine,
144 builder: *const llvm.Builder,145 builder: *const llvm.Builder,
145146
...@@ -181,19 +182,22 @@ pub const LLVMIRModule = struct {...@@ -181,19 +182,22 @@ pub const LLVMIRModule = struct {
181 const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename});182 const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename});
182 errdefer gpa.free(object_path);183 errdefer gpa.free(object_path);
183184
185 const context = llvm.Context.create();
186 errdefer context.dispose();
187
184 initializeLLVMTargets();188 initializeLLVMTargets();
185189
186 const root_nameZ = try gpa.dupeZ(u8, options.root_name);190 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
187 defer gpa.free(root_nameZ);191 defer gpa.free(root_nameZ);
188 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr);192 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
189 errdefer llvm_module.disposeModule();193 errdefer llvm_module.dispose();
190194
191 const llvm_target_triple = try targetTriple(gpa, options.target);195 const llvm_target_triple = try targetTriple(gpa, options.target);
192 defer gpa.free(llvm_target_triple);196 defer gpa.free(llvm_target_triple);
193197
194 var error_message: [*:0]const u8 = undefined;198 var error_message: [*:0]const u8 = undefined;
195 var target: *const llvm.Target = undefined;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 defer llvm.disposeMessage(error_message);201 defer llvm.disposeMessage(error_message);
198202
199 const stderr = std.io.getStdErr().outStream();203 const stderr = std.io.getStdErr().outStream();
...@@ -213,7 +217,7 @@ pub const LLVMIRModule = struct {...@@ -213,7 +217,7 @@ pub const LLVMIRModule = struct {
213 }217 }
214218
215 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive;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 target,221 target,
218 llvm_target_triple.ptr,222 llvm_target_triple.ptr,
219 "",223 "",
...@@ -222,14 +226,15 @@ pub const LLVMIRModule = struct {...@@ -222,14 +226,15 @@ pub const LLVMIRModule = struct {
222 .Static,226 .Static,
223 .Default,227 .Default,
224 );228 );
225 errdefer target_machine.disposeTargetMachine();229 errdefer target_machine.dispose();
226230
227 const builder = llvm.Builder.createBuilder();231 const builder = context.createBuilder();
228 errdefer builder.disposeBuilder();232 errdefer builder.dispose();
229233
230 self.* = .{234 self.* = .{
231 .module = options.module.?,235 .module = options.module.?,
232 .llvm_module = llvm_module,236 .llvm_module = llvm_module,
237 .context = context,
233 .target_machine = target_machine,238 .target_machine = target_machine,
234 .builder = builder,239 .builder = builder,
235 .object_path = object_path,240 .object_path = object_path,
...@@ -239,9 +244,10 @@ pub const LLVMIRModule = struct {...@@ -239,9 +244,10 @@ pub const LLVMIRModule = struct {
239 }244 }
240245
241 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {246 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {
242 self.builder.disposeBuilder();247 self.builder.dispose();
243 self.target_machine.disposeTargetMachine();248 self.target_machine.dispose();
244 self.llvm_module.disposeModule();249 self.llvm_module.dispose();
250 self.context.dispose();
245251
246 self.func_inst_table.deinit(self.gpa);252 self.func_inst_table.deinit(self.gpa);
247 self.gpa.free(self.object_path);253 self.gpa.free(self.object_path);
...@@ -271,7 +277,7 @@ pub const LLVMIRModule = struct {...@@ -271,7 +277,7 @@ pub const LLVMIRModule = struct {
271 // verifyModule always allocs the error_message even if there is no error277 // verifyModule always allocs the error_message even if there is no error
272 defer llvm.disposeMessage(error_message);278 defer llvm.disposeMessage(error_message);
273279
274 if (self.llvm_module.verifyModule(.ReturnStatus, &error_message)) {280 if (self.llvm_module.verify(.ReturnStatus, &error_message)) {
275 const stderr = std.io.getStdErr().outStream();281 const stderr = std.io.getStdErr().outStream();
276 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});282 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});
277 return error.BrokenLLVMModule;283 return error.BrokenLLVMModule;
...@@ -340,7 +346,7 @@ pub const LLVMIRModule = struct {...@@ -340,7 +346,7 @@ pub const LLVMIRModule = struct {
340 bb.deleteBasicBlock();346 bb.deleteBasicBlock();
341 }347 }
342348
343 self.entry_block = llvm_func.appendBasicBlock("Entry");349 self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry");
344 self.builder.positionBuilderAtEnd(self.entry_block);350 self.builder.positionBuilderAtEnd(self.entry_block);
345 self.latest_alloca_inst = null;351 self.latest_alloca_inst = null;
346352
...@@ -606,7 +612,7 @@ pub const LLVMIRModule = struct {...@@ -606,7 +612,7 @@ pub const LLVMIRModule = struct {
606 return self.fail(src, "TODO handle other sentinel values", .{});612 return self.fail(src, "TODO handle other sentinel values", .{});
607 } else false;613 } 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);
610 } else {616 } else {
611 return self.fail(src, "TODO handle more array values", .{});617 return self.fail(src, "TODO handle more array values", .{});
612 }618 }
...@@ -617,13 +623,13 @@ pub const LLVMIRModule = struct {...@@ -617,13 +623,13 @@ pub const LLVMIRModule = struct {
617623
618 fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Type {624 fn getLLVMType(self: *LLVMIRModule, t: Type, src: usize) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
619 switch (t.zigTypeTag()) {625 switch (t.zigTypeTag()) {
620 .Void => return llvm.voidType(),626 .Void => return self.context.voidType(),
621 .NoReturn => return llvm.voidType(),627 .NoReturn => return self.context.voidType(),
622 .Int => {628 .Int => {
623 const info = t.intInfo(self.module.getTarget());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 .Pointer => {633 .Pointer => {
628 if (t.isSlice()) {634 if (t.isSlice()) {
629 return self.fail(src, "TODO: LLVM backend: implement slices", .{});635 return self.fail(src, "TODO: LLVM backend: implement slices", .{});
...@@ -688,12 +694,25 @@ pub const LLVMIRModule = struct {...@@ -688,12 +694,25 @@ pub const LLVMIRModule = struct {
688 const llvm_fn = self.llvm_module.addFunction(func.name, fn_type);694 const llvm_fn = self.llvm_module.addFunction(func.name, fn_type);
689695
690 if (return_type.tag() == .noreturn) {696 if (return_type.tag() == .noreturn) {
691 llvm_fn.addFnAttr("noreturn");697 self.addFnAttr(llvm_fn, "noreturn");
692 }698 }
693699
694 return llvm_fn;700 return llvm_fn;
695 }701 }
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
697 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {716 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
698 @setCold(true);717 @setCold(true);
699 assert(self.err_msg == null);718 assert(self.err_msg == null);
src/llvm_bindings.zig+37-48
...@@ -5,35 +5,44 @@ const std = @import("std");...@@ -5,35 +5,44 @@ const std = @import("std");
5const assert = std.debug.assert;5const assert = std.debug.assert;
66
7const LLVMBool = bool;7const 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
10pub const Value = opaque {37pub const Value = opaque {
11 pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;38 pub const addAttributeAtIndex = LLVMAddAttributeAtIndex;
12 extern fn LLVMAddAttributeAtIndex(*const Value, Idx: LLVMAttributeIndex, A: *const Attribute) void;39 extern fn LLVMAddAttributeAtIndex(*const Value, Idx: AttributeIndex, A: *const Attribute) void;
13
14 pub const appendBasicBlock = LLVMAppendBasicBlock;
15 extern fn LLVMAppendBasicBlock(Fn: *const Value, Name: [*:0]const u8) *const BasicBlock;
1640
17 pub const getFirstBasicBlock = LLVMGetFirstBasicBlock;41 pub const getFirstBasicBlock = LLVMGetFirstBasicBlock;
18 extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock;42 extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock;
1943
20 pub const getNextInstruction = LLVMGetNextInstruction;44 pub const getNextInstruction = LLVMGetNextInstruction;
21 extern fn LLVMGetNextInstruction(Inst: *const Value) ?*const Value;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};
3847
39pub const Type = opaque {48pub const Type = opaque {
...@@ -63,13 +72,13 @@ pub const Type = opaque {...@@ -63,13 +72,13 @@ pub const Type = opaque {
63};72};
6473
65pub const Module = opaque {74pub const Module = opaque {
66 pub const createWithName = LLVMModuleCreateWithName;75 pub const createWithName = LLVMModuleCreateWithNameInContext;
67 extern fn LLVMModuleCreateWithName(ModuleID: [*:0]const u8) *const Module;76 extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *const Context) *const Module;
6877
69 pub const disposeModule = LLVMDisposeModule;78 pub const dispose = LLVMDisposeModule;
70 extern fn LLVMDisposeModule(*const Module) void;79 extern fn LLVMDisposeModule(*const Module) void;
7180
72 pub const verifyModule = LLVMVerifyModule;81 pub const verify = LLVMVerifyModule;
73 extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool;82 extern fn LLVMVerifyModule(*const Module, Action: VerifierFailureAction, OutMessage: *[*:0]const u8) LLVMBool;
7483
75 pub const addFunction = LLVMAddFunction;84 pub const addFunction = LLVMAddFunction;
...@@ -106,15 +115,9 @@ pub const VerifierFailureAction = extern enum {...@@ -106,15 +115,9 @@ pub const VerifierFailureAction = extern enum {
106pub const constNeg = LLVMConstNeg;115pub const constNeg = LLVMConstNeg;
107extern fn LLVMConstNeg(ConstantVal: *const Value) *const Value;116extern 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
112pub const setInitializer = LLVMSetInitializer;118pub const setInitializer = LLVMSetInitializer;
113extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void;119extern fn LLVMSetInitializer(GlobalVar: *const Value, ConstantVal: *const Value) void;
114120
115pub const voidType = LLVMVoidType;
116extern fn LLVMVoidType() *const Type;
117
118pub const getParam = LLVMGetParam;121pub const getParam = LLVMGetParam;
119extern fn LLVMGetParam(Fn: *const Value, Index: c_uint) *const Value;122extern 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...@@ -123,22 +126,8 @@ extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint
123126
124pub const Attribute = opaque {};127pub 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
137pub const Builder = opaque {129pub const Builder = opaque {
138 pub const createBuilder = LLVMCreateBuilder;130 pub const dispose = LLVMDisposeBuilder;
139 extern fn LLVMCreateBuilder() *const Builder;
140
141 pub const disposeBuilder = LLVMDisposeBuilder;
142 extern fn LLVMDisposeBuilder(Builder: *const Builder) void;131 extern fn LLVMDisposeBuilder(Builder: *const Builder) void;
143132
144 pub const positionBuilder = LLVMPositionBuilder;133 pub const positionBuilder = LLVMPositionBuilder;
...@@ -208,7 +197,7 @@ pub const BasicBlock = opaque {...@@ -208,7 +197,7 @@ pub const BasicBlock = opaque {
208};197};
209198
210pub const TargetMachine = opaque {199pub const TargetMachine = opaque {
211 pub const createTargetMachine = LLVMCreateTargetMachine;200 pub const create = LLVMCreateTargetMachine;
212 extern fn LLVMCreateTargetMachine(201 extern fn LLVMCreateTargetMachine(
213 T: *const Target,202 T: *const Target,
214 Triple: [*:0]const u8,203 Triple: [*:0]const u8,
...@@ -219,7 +208,7 @@ pub const TargetMachine = opaque {...@@ -219,7 +208,7 @@ pub const TargetMachine = opaque {
219 CodeModel: CodeMode,208 CodeModel: CodeMode,
220 ) *const TargetMachine;209 ) *const TargetMachine;
221210
222 pub const disposeTargetMachine = LLVMDisposeTargetMachine;211 pub const dispose = LLVMDisposeTargetMachine;
223 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;212 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;
224213
225 pub const emitToFile = LLVMTargetMachineEmitToFile;214 pub const emitToFile = LLVMTargetMachineEmitToFile;
...@@ -259,7 +248,7 @@ pub const CodeGenFileType = extern enum {...@@ -259,7 +248,7 @@ pub const CodeGenFileType = extern enum {
259};248};
260249
261pub const Target = opaque {250pub const Target = opaque {
262 pub const getTargetFromTriple = LLVMGetTargetFromTriple;251 pub const getFromTriple = LLVMGetTargetFromTriple;
263 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool;252 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) LLVMBool;
264};253};
265254