authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2020-12-24 16:47:09+01:00
committergravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2020-12-28 21:20:49+01:00
log4a32d4f288737a0d67484c1f05817ec468ec41f1
treed41c1643aeedf082bae5eb7d8801029c99cddf52
parent09cf043efd5966e328e4454bc30bc756f439938b

stage2: refactor (simplify) code structure of `llvm_backend.zig`


1 files changed, 55 insertions(+), 59 deletions(-)

src/llvm_backend.zig+55-59
...@@ -136,8 +136,11 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -136,8 +136,11 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
136}136}
137137
138pub const LLVMIRModule = struct {138pub const LLVMIRModule = struct {
139 module: *Module,
139 llvm_module: *const llvm.ModuleRef,140 llvm_module: *const llvm.ModuleRef,
140 target_machine: *const llvm.TargetMachineRef,141 target_machine: *const llvm.TargetMachineRef,
142 builder: *const llvm.BuilderRef,
143
141 output_path: []const u8,144 output_path: []const u8,
142145
143 gpa: *Allocator,146 gpa: *Allocator,
...@@ -192,9 +195,14 @@ pub const LLVMIRModule = struct {...@@ -192,9 +195,14 @@ pub const LLVMIRModule = struct {
192 );195 );
193 errdefer target_machine.disposeTargetMachine();196 errdefer target_machine.disposeTargetMachine();
194197
198 const builder = llvm.BuilderRef.createBuilder();
199 errdefer builder.disposeBuilder();
200
195 self.* = .{201 self.* = .{
202 .module = options.module.?,
196 .llvm_module = llvm_module,203 .llvm_module = llvm_module,
197 .target_machine = target_machine,204 .target_machine = target_machine,
205 .builder = builder,
198 .output_path = sub_path,206 .output_path = sub_path,
199 .gpa = gpa,207 .gpa = gpa,
200 };208 };
...@@ -202,8 +210,9 @@ pub const LLVMIRModule = struct {...@@ -202,8 +210,9 @@ pub const LLVMIRModule = struct {
202 }210 }
203211
204 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {212 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {
205 self.llvm_module.disposeModule();213 self.builder.disposeBuilder();
206 self.target_machine.disposeTargetMachine();214 self.target_machine.disposeTargetMachine();
215 self.llvm_module.disposeModule();
207 allocator.destroy(self);216 allocator.destroy(self);
208 }217 }
209218
...@@ -216,6 +225,14 @@ pub const LLVMIRModule = struct {...@@ -216,6 +225,14 @@ pub const LLVMIRModule = struct {
216 }225 }
217226
218 pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void {227 pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void {
228 if (comp.verbose_llvm_ir) {
229 const dump = self.llvm_module.printToString();
230 defer llvm.disposeMessage(dump);
231
232 const stderr = std.io.getStdErr().outStream();
233 try stderr.writeAll(std.mem.spanZ(dump));
234 }
235
219 {236 {
220 var error_message: [*:0]const u8 = undefined;237 var error_message: [*:0]const u8 = undefined;
221 // verifyModule always allocs the error_message even if there is no error238 // verifyModule always allocs the error_message even if there is no error
...@@ -228,14 +245,6 @@ pub const LLVMIRModule = struct {...@@ -228,14 +245,6 @@ pub const LLVMIRModule = struct {
228 }245 }
229 }246 }
230247
231 if (comp.verbose_llvm_ir) {
232 const dump = self.llvm_module.printToString();
233 defer llvm.disposeMessage(dump);
234
235 const stderr = std.io.getStdErr().outStream();
236 try stderr.writeAll(std.mem.spanZ(dump));
237 }
238
239 const output_pathZ = try self.gpa.dupeZ(u8, self.output_path);248 const output_pathZ = try self.gpa.dupeZ(u8, self.output_path);
240 defer self.gpa.free(output_pathZ);249 defer self.gpa.free(output_pathZ);
241250
...@@ -258,7 +267,7 @@ pub const LLVMIRModule = struct {...@@ -258,7 +267,7 @@ pub const LLVMIRModule = struct {
258267
259 pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {268 pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {
260 const typed_value = decl.typed_value.most_recent.typed_value;269 const typed_value = decl.typed_value.most_recent.typed_value;
261 self.generate(module, typed_value, decl.src()) catch |err| switch (err) {270 self.gen(module, typed_value, decl.src()) catch |err| switch (err) {
262 error.CodegenFail => {271 error.CodegenFail => {
263 decl.analysis = .codegen_failure;272 decl.analysis = .codegen_failure;
264 try module.failed_decls.put(module.gpa, decl, self.err_msg.?);273 try module.failed_decls.put(module.gpa, decl, self.err_msg.?);
...@@ -268,19 +277,12 @@ pub const LLVMIRModule = struct {...@@ -268,19 +277,12 @@ pub const LLVMIRModule = struct {
268 };277 };
269 }278 }
270279
271 fn generate(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void {280 fn gen(self: *LLVMIRModule, module: *Module, typed_value: TypedValue, src: usize) !void {
272 switch (typed_value.ty.zigTypeTag()) {281 switch (typed_value.ty.zigTypeTag()) {
273 .Fn => {282 .Fn => {
274 const func = typed_value.val.cast(Value.Payload.Function).?.func;283 const func = typed_value.val.cast(Value.Payload.Function).?.func;
275284
276 var codegen = CodeGen{285 const llvm_func = try self.resolveLLVMFunction(func);
277 .module = module,
278 .llvm_module = self.llvm_module,
279 .builder = llvm.BuilderRef.createBuilder(),
280 };
281 defer codegen.builder.disposeBuilder();
282
283 const llvm_func = try codegen.resolveLLVMFunction(func);
284286
285 // We remove all the basic blocks of a function to support incremental287 // We remove all the basic blocks of a function to support incremental
286 // compilation!288 // compilation!
...@@ -290,15 +292,15 @@ pub const LLVMIRModule = struct {...@@ -290,15 +292,15 @@ pub const LLVMIRModule = struct {
290 }292 }
291293
292 const entry_block = llvm_func.appendBasicBlock("Entry");294 const entry_block = llvm_func.appendBasicBlock("Entry");
293 codegen.builder.positionBuilderAtEnd(entry_block);295 self.builder.positionBuilderAtEnd(entry_block);
294296
295 const instructions = func.analysis.success.instructions;297 const instructions = func.analysis.success.instructions;
296 for (instructions) |inst| {298 for (instructions) |inst| {
297 switch (inst.tag) {299 switch (inst.tag) {
298 .breakpoint => try codegen.generateBreakpoint(inst.castTag(.breakpoint).?),300 .breakpoint => try self.genBreakpoint(inst.castTag(.breakpoint).?),
299 .call => try codegen.generateCall(inst.castTag(.call).?),301 .call => try self.genCall(inst.castTag(.call).?),
300 .unreach => codegen.generateUnreach(inst.castTag(.unreach).?),302 .unreach => self.genUnreach(inst.castTag(.unreach).?),
301 .retvoid => codegen.generateRetVoid(inst.castTag(.retvoid).?),303 .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),
302 .dbg_stmt => {304 .dbg_stmt => {
303 // TODO: implement debug info305 // TODO: implement debug info
304 },306 },
...@@ -310,83 +312,70 @@ pub const LLVMIRModule = struct {...@@ -310,83 +312,70 @@ pub const LLVMIRModule = struct {
310 }312 }
311 }313 }
312314
313 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {315 fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !void {
314 @setCold(true);
315 std.debug.assert(self.err_msg == null);
316 self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);
317 return error.CodegenFail;
318 }
319};
320
321const CodeGen = struct {
322 module: *Module,
323 llvm_module: *const llvm.ModuleRef,
324 builder: *const llvm.BuilderRef,
325
326 fn generateCall(codegen: *CodeGen, inst: *Inst.Call) !void {
327 if (inst.func.cast(Inst.Constant)) |func_inst| {316 if (inst.func.cast(Inst.Constant)) |func_inst| {
328 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {317 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
329 const func = func_val.func;318 const func = func_val.func;
330 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;319 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
331 const llvm_fn = try codegen.resolveLLVMFunction(func);320 const llvm_fn = try self.resolveLLVMFunction(func);
332321
333 // TODO: handle more arguments, inst.args322 // TODO: handle more arguments, inst.args
334323
335 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs324 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
336 // Do we need that?325 // Do we need that?
337 const call = codegen.builder.buildCall(llvm_fn, null, 0, "");326 const call = self.builder.buildCall(llvm_fn, null, 0, "");
338327
339 if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {328 if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {
340 _ = codegen.builder.buildUnreachable();329 _ = self.builder.buildUnreachable();
341 }330 }
342 }331 }
343 }332 }
344 }333 }
345334
346 fn generateRetVoid(codegen: *CodeGen, inst: *Inst.NoOp) void {335 fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) void {
347 _ = codegen.builder.buildRetVoid();336 _ = self.builder.buildRetVoid();
348 }337 }
349338
350 fn generateUnreach(codegen: *CodeGen, inst: *Inst.NoOp) void {339 fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) void {
351 _ = codegen.builder.buildUnreachable();340 _ = self.builder.buildUnreachable();
352 }341 }
353342
354 fn generateBreakpoint(codegen: *CodeGen, inst: *Inst.NoOp) !void {343 fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void {
355 // TODO: Store this function somewhere such that we dont have to add it again344 // TODO: Store this function somewhere such that we dont have to add it again
356 const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);345 const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);
357 const func = codegen.llvm_module.addFunction("llvm.debugtrap", fn_type);346 const func = self.llvm_module.addFunction("llvm.debugtrap", fn_type);
358 // TODO: add assertion: LLVMGetIntrinsicID347 // TODO: add assertion: LLVMGetIntrinsicID
359 _ = codegen.builder.buildCall(func, null, 0, "");348 _ = self.builder.buildCall(func, null, 0, "");
360 }349 }
361350
362 /// If the llvm function does not exist, create it351 /// If the llvm function does not exist, create it
363 fn resolveLLVMFunction(codegen: *CodeGen, func: *Module.Fn) !*const llvm.ValueRef {352 fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef {
364 // TODO: do we want to store this in our own datastructure?353 // TODO: do we want to store this in our own datastructure?
365 if (codegen.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn;354 if (self.llvm_module.getNamedFunction(func.owner_decl.name)) |llvm_fn| return llvm_fn;
366355
367 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;356 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
368 const return_type = zig_fn_type.fnReturnType();357 const return_type = zig_fn_type.fnReturnType();
369358
370 const fn_param_len = zig_fn_type.fnParamLen();359 const fn_param_len = zig_fn_type.fnParamLen();
371360
372 const fn_param_types = try codegen.module.gpa.alloc(Type, fn_param_len);361 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
373 defer codegen.module.gpa.free(fn_param_types);362 defer self.gpa.free(fn_param_types);
374 zig_fn_type.fnParamTypes(fn_param_types);363 zig_fn_type.fnParamTypes(fn_param_types);
375364
376 const llvm_param = try codegen.module.gpa.alloc(*const llvm.TypeRef, fn_param_len);365 const llvm_param = try self.gpa.alloc(*const llvm.TypeRef, fn_param_len);
377 defer codegen.module.gpa.free(llvm_param);366 defer self.gpa.free(llvm_param);
378367
379 for (fn_param_types) |fn_param, i| {368 for (fn_param_types) |fn_param, i| {
380 llvm_param[i] = codegen.getLLVMType(fn_param);369 llvm_param[i] = self.getLLVMType(fn_param);
381 }370 }
382371
383 const fn_type = llvm.TypeRef.functionType(372 const fn_type = llvm.TypeRef.functionType(
384 codegen.getLLVMType(return_type),373 self.getLLVMType(return_type),
385 if (fn_param_len == 0) null else llvm_param.ptr,374 if (fn_param_len == 0) null else llvm_param.ptr,
386 @intCast(c_uint, fn_param_len),375 @intCast(c_uint, fn_param_len),
387 false,376 false,
388 );377 );
389 const llvm_fn = codegen.llvm_module.addFunction(func.owner_decl.name, fn_type);378 const llvm_fn = self.llvm_module.addFunction(func.owner_decl.name, fn_type);
390379
391 if (return_type.zigTypeTag() == .NoReturn) {380 if (return_type.zigTypeTag() == .NoReturn) {
392 llvm_fn.addFnAttr("noreturn");381 llvm_fn.addFnAttr("noreturn");
...@@ -395,16 +384,23 @@ const CodeGen = struct {...@@ -395,16 +384,23 @@ const CodeGen = struct {
395 return llvm_fn;384 return llvm_fn;
396 }385 }
397386
398 fn getLLVMType(codegen: *CodeGen, t: Type) *const llvm.TypeRef {387 fn getLLVMType(self: *LLVMIRModule, t: Type) *const llvm.TypeRef {
399 switch (t.zigTypeTag()) {388 switch (t.zigTypeTag()) {
400 .Void => return llvm.voidType(),389 .Void => return llvm.voidType(),
401 .NoReturn => return llvm.voidType(),390 .NoReturn => return llvm.voidType(),
402 .Int => {391 .Int => {
403 const info = t.intInfo(codegen.module.getTarget());392 const info = t.intInfo(self.module.getTarget());
404 return llvm.intType(info.bits);393 return llvm.intType(info.bits);
405 },394 },
406 .Bool => return llvm.intType(1),395 .Bool => return llvm.intType(1),
407 else => unreachable,396 else => unreachable,
408 }397 }
409 }398 }
399
400 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
401 @setCold(true);
402 std.debug.assert(self.err_msg == null);
403 self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);
404 return error.CodegenFail;
405 }
410};406};