authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-03-08 00:09:03+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-20 15:10:44-07:00
loga710368054096889385562addaed2d16f0705332
tree66cc9673d9bd3ddd914aafeee964d50e55cf4d50
parent56677f2f2da41af5999b84b7f740d7bc463d1032

stage2: restructure LLVM backend

The LLVM backend is now structured into 3 different structs, namely Object, DeclGen and FuncGen. Object represents an object that is generated by the LLVM backend. DeclGen is responsible for generating a decl and FuncGen is responsible for generating llvm instructions from tzir in a function.

3 files changed, 408 insertions(+), 377 deletions(-)

src/codegen/llvm.zig+387-356
......@@ -16,7 +16,6 @@ const Value = @import("../value.zig").Value;
1616const Type = @import("../type.zig").Type;
1717
1818const LazySrcLoc = Module.LazySrcLoc;
19const SrcLoc = Module.SrcLoc;
2019
2120pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
2221 const llvm_arch = switch (target.cpu.arch) {
......@@ -146,83 +145,42 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
146145 return std.fmt.allocPrintZ(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi });
147146}
148147
149pub const LLVMIRModule = struct {
150 module: *Module,
148pub const Object = struct {
151149 llvm_module: *const llvm.Module,
152150 context: *const llvm.Context,
153151 target_machine: *const llvm.TargetMachine,
154 builder: *const llvm.Builder,
155
156 object_path: []const u8,
157
158 gpa: *Allocator,
159 err_msg: ?*Module.ErrorMsg = null,
160
161 // TODO: The fields below should really move into a different struct,
162 // because they are only valid when generating a function
163
164 /// TODO: this should not be undefined since it should be in another per-decl struct
165 /// Curent decl we are analysing. Stored to get source locations from relative info
166 decl: *Module.Decl = undefined,
167
168 /// This stores the LLVM values used in a function, such that they can be
169 /// referred to in other instructions. This table is cleared before every function is generated.
170 /// TODO: Change this to a stack of Branch. Currently we store all the values from all the blocks
171 /// in here, however if a block ends, the instructions can be thrown away.
172 func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.Value) = .{},
173
174 /// These fields are used to refer to the LLVM value of the function paramaters in an Arg instruction.
175 args: []*const llvm.Value = &[_]*const llvm.Value{},
176 arg_index: usize = 0,
177
178 entry_block: *const llvm.BasicBlock = undefined,
179 /// This fields stores the last alloca instruction, such that we can append more alloca instructions
180 /// to the top of the function.
181 latest_alloca_inst: ?*const llvm.Value = null,
182
183 llvm_func: *const llvm.Value = undefined,
184
185 /// This data structure is used to implement breaking to blocks.
186 blocks: std.AutoHashMapUnmanaged(*Inst.Block, struct {
187 parent_bb: *const llvm.BasicBlock,
188 break_bbs: *BreakBasicBlocks,
189 break_vals: *BreakValues,
190 }) = .{},
191
192 src_loc: Module.SrcLoc,
193
194 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
195 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
152 object_pathZ: [:0]const u8,
196153
197 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {
198 const self = try allocator.create(LLVMIRModule);
154 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Object {
155 const self = try allocator.create(Object);
199156 errdefer allocator.destroy(self);
200157
201 const gpa = options.module.?.gpa;
202
203 const obj_basename = try std.zig.binNameAlloc(gpa, .{
158 const obj_basename = try std.zig.binNameAlloc(allocator, .{
204159 .root_name = options.root_name,
205160 .target = options.target,
206161 .output_mode = .Obj,
207162 });
208 defer gpa.free(obj_basename);
163 defer allocator.free(obj_basename);
209164
210165 const o_directory = options.module.?.zig_cache_artifact_directory;
211 const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename});
212 errdefer gpa.free(object_path);
166 const object_path = try o_directory.join(allocator, &[_][]const u8{obj_basename});
167 defer allocator.free(object_path);
168
169 const object_pathZ = try allocator.dupeZ(u8, object_path);
170 errdefer allocator.free(object_pathZ);
213171
214172 const context = llvm.Context.create();
215173 errdefer context.dispose();
216174
217175 initializeLLVMTargets();
218176
219 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
220 defer gpa.free(root_nameZ);
177 const root_nameZ = try allocator.dupeZ(u8, options.root_name);
178 defer allocator.free(root_nameZ);
221179 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
222180 errdefer llvm_module.dispose();
223181
224 const llvm_target_triple = try targetTriple(gpa, options.target);
225 defer gpa.free(llvm_target_triple);
182 const llvm_target_triple = try targetTriple(allocator, options.target);
183 defer allocator.free(llvm_target_triple);
226184
227185 var error_message: [*:0]const u8 = undefined;
228186 var target: *const llvm.Target = undefined;
......@@ -257,34 +215,21 @@ pub const LLVMIRModule = struct {
257215 );
258216 errdefer target_machine.dispose();
259217
260 const builder = context.createBuilder();
261 errdefer builder.dispose();
262
263218 self.* = .{
264 .module = options.module.?,
265219 .llvm_module = llvm_module,
266220 .context = context,
267221 .target_machine = target_machine,
268 .builder = builder,
269 .object_path = object_path,
270 .gpa = gpa,
271 // TODO move this field into a struct that is only instantiated per gen() call
272 .src_loc = undefined,
222 .object_pathZ = object_pathZ,
273223 };
274224 return self;
275225 }
276226
277 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {
278 self.builder.dispose();
227 pub fn deinit(self: *Object, allocator: *Allocator) void {
279228 self.target_machine.dispose();
280229 self.llvm_module.dispose();
281230 self.context.dispose();
282231
283 self.func_inst_table.deinit(self.gpa);
284 self.gpa.free(self.object_path);
285
286 self.blocks.deinit(self.gpa);
287
232 allocator.free(self.object_pathZ);
288233 allocator.destroy(self);
289234 }
290235
......@@ -296,7 +241,7 @@ pub const LLVMIRModule = struct {
296241 llvm.initializeAllAsmParsers();
297242 }
298243
299 pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void {
244 pub fn flushModule(self: *Object, comp: *Compilation) !void {
300245 if (comp.verbose_llvm_ir) {
301246 const dump = self.llvm_module.printToString();
302247 defer llvm.disposeMessage(dump);
......@@ -317,13 +262,10 @@ pub const LLVMIRModule = struct {
317262 }
318263 }
319264
320 const object_pathZ = try self.gpa.dupeZ(u8, self.object_path);
321 defer self.gpa.free(object_pathZ);
322
323265 var error_message: [*:0]const u8 = undefined;
324266 if (self.target_machine.emitToFile(
325267 self.llvm_module,
326 object_pathZ.ptr,
268 self.object_pathZ.ptr,
327269 .ObjectFile,
328270 &error_message,
329271 ).toBool()) {
......@@ -335,23 +277,55 @@ pub const LLVMIRModule = struct {
335277 }
336278 }
337279
338 pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {
339 self.gen(module, decl) catch |err| switch (err) {
280 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
281 var dg: DeclGen = .{
282 .object = self,
283 .module = module,
284 .decl = decl,
285 .err_msg = null,
286 .gpa = module.gpa,
287 };
288 dg.genDecl() catch |err| switch (err) {
340289 error.CodegenFail => {
341290 decl.analysis = .codegen_failure;
342 try module.failed_decls.put(module.gpa, decl, self.err_msg.?);
343 self.err_msg = null;
291 try module.failed_decls.put(module.gpa, decl, dg.err_msg.?);
292 dg.err_msg = null;
344293 return;
345294 },
346295 else => |e| return e,
347296 };
348297 }
298};
299
300pub const DeclGen = struct {
301 object: *Object,
302 module: *Module,
303 decl: *Module.Decl,
304 err_msg: ?*Module.ErrorMsg,
305
306 gpa: *Allocator,
307
308 fn fail(self: *DeclGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
309 @setCold(true);
310 assert(self.err_msg == null);
311 const src_loc = src.toSrcLocWithDecl(self.decl);
312 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, format, args);
313 return error.CodegenFail;
314 }
315
316 fn llvmModule(self: *DeclGen) *const llvm.Module {
317 return self.object.llvm_module;
318 }
319
320 fn context(self: *DeclGen) *const llvm.Context {
321 return self.object.context;
322 }
349323
350 fn gen(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {
324 fn genDecl(self: *DeclGen) !void {
325 const decl = self.decl;
351326 const typed_value = decl.typed_value.most_recent.typed_value;
352 self.src_loc = decl.srcLoc();
353 self.decl = decl;
354 const src = self.src_loc.lazy;
327
328 const src = decl.srcLoc().lazy;
355329
356330 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val });
357331
......@@ -363,16 +337,10 @@ pub const LLVMIRModule = struct {
363337 // This gets the LLVM values from the function and stores them in `self.args`.
364338 const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen();
365339 var args = try self.gpa.alloc(*const llvm.Value, fn_param_len);
366 defer self.gpa.free(args);
367340
368341 for (args) |*arg, i| {
369342 arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
370343 }
371 self.args = args;
372 self.arg_index = 0;
373
374 // Make sure no other LLVM values from other functions can be referenced
375 self.func_inst_table.clearRetainingCapacity();
376344
377345 // We remove all the basic blocks of a function to support incremental
378346 // compilation!
......@@ -381,12 +349,25 @@ pub const LLVMIRModule = struct {
381349 bb.deleteBasicBlock();
382350 }
383351
384 self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry");
385 self.builder.positionBuilderAtEnd(self.entry_block);
386 self.latest_alloca_inst = null;
387 self.llvm_func = llvm_func;
352 const builder = self.context().createBuilder();
353
354 const entry_block = self.context().appendBasicBlock(llvm_func, "Entry");
355 builder.positionBuilderAtEnd(entry_block);
356
357 var fg: FuncGen = .{
358 .dg = self,
359 .builder = builder,
360 .args = args,
361 .arg_index = 0,
362 .func_inst_table = .{},
363 .entry_block = entry_block,
364 .latest_alloca_inst = null,
365 .llvm_func = llvm_func,
366 .blocks = .{},
367 };
368 defer fg.deinit();
388369
389 try self.genBody(func.body);
370 try fg.genBody(func.body);
390371 } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| {
391372 _ = try self.resolveLLVMFunction(extern_fn.data, src);
392373 } else {
......@@ -394,7 +375,267 @@ pub const LLVMIRModule = struct {
394375 }
395376 }
396377
397 fn genBody(self: *LLVMIRModule, body: ir.Body) error{ OutOfMemory, CodegenFail }!void {
378 /// If the llvm function does not exist, create it
379 fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl, src: LazySrcLoc) !*const llvm.Value {
380 // TODO: do we want to store this in our own datastructure?
381 if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn;
382
383 const zig_fn_type = func.typed_value.most_recent.typed_value.ty;
384 const return_type = zig_fn_type.fnReturnType();
385
386 const fn_param_len = zig_fn_type.fnParamLen();
387
388 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
389 defer self.gpa.free(fn_param_types);
390 zig_fn_type.fnParamTypes(fn_param_types);
391
392 const llvm_param = try self.gpa.alloc(*const llvm.Type, fn_param_len);
393 defer self.gpa.free(llvm_param);
394
395 for (fn_param_types) |fn_param, i| {
396 llvm_param[i] = try self.getLLVMType(fn_param, src);
397 }
398
399 const fn_type = llvm.Type.functionType(
400 try self.getLLVMType(return_type, src),
401 if (fn_param_len == 0) null else llvm_param.ptr,
402 @intCast(c_uint, fn_param_len),
403 .False,
404 );
405 const llvm_fn = self.llvmModule().addFunction(func.name, fn_type);
406
407 if (return_type.tag() == .noreturn) {
408 self.addFnAttr(llvm_fn, "noreturn");
409 }
410
411 return llvm_fn;
412 }
413
414 fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
415 // TODO: do we want to store this in our own datastructure?
416 if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val;
417
418 const typed_value = decl.typed_value.most_recent.typed_value;
419
420 // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`.
421 const llvm_type = try self.getLLVMType(typed_value.ty, src);
422 const val = try self.genTypedValue(src, typed_value, null);
423 const global = self.llvmModule().addGlobal(llvm_type, decl.name);
424 llvm.setInitializer(global, val);
425
426 // TODO ask the Decl if it is const
427 // https://github.com/ziglang/zig/issues/7582
428
429 return global;
430 }
431
432 fn getLLVMType(self: *DeclGen, t: Type, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
433 switch (t.zigTypeTag()) {
434 .Void => return self.context().voidType(),
435 .NoReturn => return self.context().voidType(),
436 .Int => {
437 const info = t.intInfo(self.module.getTarget());
438 return self.context().intType(info.bits);
439 },
440 .Bool => return self.context().intType(1),
441 .Pointer => {
442 if (t.isSlice()) {
443 return self.fail(src, "TODO: LLVM backend: implement slices", .{});
444 } else {
445 const elem_type = try self.getLLVMType(t.elemType(), src);
446 return elem_type.pointerType(0);
447 }
448 },
449 .Array => {
450 const elem_type = try self.getLLVMType(t.elemType(), src);
451 return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));
452 },
453 .Optional => {
454 if (!t.isPtrLikeOptional()) {
455 var buf: Type.Payload.ElemType = undefined;
456 const child_type = t.optionalChild(&buf);
457
458 var optional_types: [2]*const llvm.Type = .{
459 try self.getLLVMType(child_type, src),
460 self.context().intType(1),
461 };
462 return self.context().structType(&optional_types, 2, .False);
463 } else {
464 return self.fail(src, "TODO implement optional pointers as actual pointers", .{});
465 }
466 },
467 else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),
468 }
469 }
470
471 // TODO: figure out a way to remove the FuncGen argument
472 fn genTypedValue(self: *DeclGen, src: LazySrcLoc, tv: TypedValue, fg: ?*FuncGen) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
473 const llvm_type = try self.getLLVMType(tv.ty, src);
474
475 if (tv.val.isUndef())
476 return llvm_type.getUndef();
477
478 switch (tv.ty.zigTypeTag()) {
479 .Bool => return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),
480 .Int => {
481 var bigint_space: Value.BigIntSpace = undefined;
482 const bigint = tv.val.toBigInt(&bigint_space);
483
484 if (bigint.eqZero()) return llvm_type.constNull();
485
486 if (bigint.limbs.len != 1) {
487 return self.fail(src, "TODO implement bigger bigint", .{});
488 }
489 const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
490 if (!bigint.positive) {
491 return llvm.constNeg(llvm_int);
492 }
493 return llvm_int;
494 },
495 .Pointer => switch (tv.val.tag()) {
496 .decl_ref => {
497 const decl = tv.val.castTag(.decl_ref).?.data;
498 const val = try self.resolveGlobalDecl(decl, src);
499
500 const usize_type = try self.getLLVMType(Type.initTag(.usize), src);
501
502 // TODO: second index should be the index into the memory!
503 var indices: [2]*const llvm.Value = .{
504 usize_type.constNull(),
505 usize_type.constNull(),
506 };
507
508 // TODO: consider using buildInBoundsGEP2 for opaque pointers
509 return fg.?.builder.buildInBoundsGEP(val, &indices, 2, "");
510 },
511 .ref_val => {
512 const elem_value = tv.val.castTag(.ref_val).?.data;
513 const elem_type = tv.ty.castPointer().?.data;
514 const alloca = fg.?.buildAlloca(try self.getLLVMType(elem_type, src));
515 _ = fg.?.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }, fg), alloca);
516 return alloca;
517 },
518 else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),
519 },
520 .Array => {
521 if (tv.val.castTag(.bytes)) |payload| {
522 const zero_sentinel = if (tv.ty.sentinel()) |sentinel| blk: {
523 if (sentinel.tag() == .zero) break :blk true;
524 return self.fail(src, "TODO handle other sentinel values", .{});
525 } else false;
526
527 return self.context().constString(payload.data.ptr, @intCast(c_uint, payload.data.len), llvm.Bool.fromBool(!zero_sentinel));
528 } else {
529 return self.fail(src, "TODO handle more array values", .{});
530 }
531 },
532 .Optional => {
533 if (!tv.ty.isPtrLikeOptional()) {
534 var buf: Type.Payload.ElemType = undefined;
535 const child_type = tv.ty.optionalChild(&buf);
536 const llvm_child_type = try self.getLLVMType(child_type, src);
537
538 if (tv.val.tag() == .null_value) {
539 var optional_values: [2]*const llvm.Value = .{
540 llvm_child_type.constNull(),
541 self.context().intType(1).constNull(),
542 };
543 return self.context().constStruct(&optional_values, 2, .False);
544 } else {
545 var optional_values: [2]*const llvm.Value = .{
546 try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }, fg),
547 self.context().intType(1).constAllOnes(),
548 };
549 return self.context().constStruct(&optional_values, 2, .False);
550 }
551 } else {
552 return self.fail(src, "TODO implement const of optional pointer", .{});
553 }
554 },
555 else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),
556 }
557 }
558
559 // Helper functions
560 fn addAttr(self: *DeclGen, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
561 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
562 assert(kind_id != 0);
563 const llvm_attr = self.context().createEnumAttribute(kind_id, 0);
564 val.addAttributeAtIndex(index, llvm_attr);
565 }
566
567 fn addFnAttr(self: *DeclGen, val: *const llvm.Value, attr_name: []const u8) void {
568 // TODO: improve this API, `addAttr(-1, attr_name)`
569 self.addAttr(val, std.math.maxInt(llvm.AttributeIndex), attr_name);
570 }
571};
572
573pub const FuncGen = struct {
574 dg: *DeclGen,
575
576 builder: *const llvm.Builder,
577
578 /// This stores the LLVM values used in a function, such that they can be
579 /// referred to in other instructions. This table is cleared before every function is generated.
580 /// TODO: Change this to a stack of Branch. Currently we store all the values from all the blocks
581 /// in here, however if a block ends, the instructions can be thrown away.
582 func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.Value),
583
584 /// These fields are used to refer to the LLVM value of the function paramaters in an Arg instruction.
585 args: []*const llvm.Value,
586 arg_index: usize,
587
588 entry_block: *const llvm.BasicBlock,
589 /// This fields stores the last alloca instruction, such that we can append more alloca instructions
590 /// to the top of the function.
591 latest_alloca_inst: ?*const llvm.Value,
592
593 llvm_func: *const llvm.Value,
594
595 /// This data structure is used to implement breaking to blocks.
596 blocks: std.AutoHashMapUnmanaged(*Inst.Block, struct {
597 parent_bb: *const llvm.BasicBlock,
598 break_bbs: *BreakBasicBlocks,
599 break_vals: *BreakValues,
600 }),
601
602 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
603 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
604
605 fn deinit(self: *FuncGen) void {
606 self.builder.dispose();
607 self.func_inst_table.deinit(self.gpa());
608 self.gpa().free(self.args);
609 self.blocks.deinit(self.gpa());
610 }
611
612 fn fail(self: *FuncGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
613 @setCold(true);
614 return self.dg.fail(src, format, args);
615 }
616
617 fn llvmModule(self: *FuncGen) *const llvm.Module {
618 return self.dg.object.llvm_module;
619 }
620
621 fn context(self: *FuncGen) *const llvm.Context {
622 return self.dg.object.context;
623 }
624
625 fn gpa(self: *FuncGen) *Allocator {
626 return self.dg.gpa;
627 }
628
629 fn resolveInst(self: *FuncGen, inst: *ir.Inst) !*const llvm.Value {
630 if (inst.value()) |val| {
631 return self.dg.genTypedValue(inst.src, .{ .ty = inst.ty, .val = val }, self);
632 }
633 if (self.func_inst_table.get(inst)) |value| return value;
634
635 return self.fail(inst.src, "TODO implement global llvm values (or the value is not in the func_inst_table table)", .{});
636 }
637
638 fn genBody(self: *FuncGen, body: ir.Body) error{ OutOfMemory, CodegenFail }!void {
398639 for (body.instructions) |inst| {
399640 const opt_value = switch (inst.tag) {
400641 .add => try self.genAdd(inst.castTag(.add).?),
......@@ -434,11 +675,11 @@ pub const LLVMIRModule = struct {
434675 },
435676 else => |tag| return self.fail(inst.src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}),
436677 };
437 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa, inst, val);
678 if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa(), inst, val);
438679 }
439680 }
440681
441 fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !?*const llvm.Value {
682 fn genCall(self: *FuncGen, inst: *Inst.Call) !?*const llvm.Value {
442683 if (inst.func.value()) |func_value| {
443684 const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|
444685 extern_fn.data
......@@ -448,12 +689,12 @@ pub const LLVMIRModule = struct {
448689 unreachable;
449690
450691 const zig_fn_type = fn_decl.typed_value.most_recent.typed_value.ty;
451 const llvm_fn = try self.resolveLLVMFunction(fn_decl, inst.base.src);
692 const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl, inst.base.src);
452693
453694 const num_args = inst.args.len;
454695
455 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, num_args);
456 defer self.gpa.free(llvm_param_vals);
696 const llvm_param_vals = try self.gpa().alloc(*const llvm.Value, num_args);
697 defer self.gpa().free(llvm_param_vals);
457698
458699 for (inst.args) |arg, i| {
459700 llvm_param_vals[i] = try self.resolveInst(arg);
......@@ -482,17 +723,17 @@ pub const LLVMIRModule = struct {
482723 }
483724 }
484725
485 fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value {
726 fn genRetVoid(self: *FuncGen, inst: *Inst.NoOp) ?*const llvm.Value {
486727 _ = self.builder.buildRetVoid();
487728 return null;
488729 }
489730
490 fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
731 fn genRet(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
491732 _ = self.builder.buildRet(try self.resolveInst(inst.operand));
492733 return null;
493734 }
494735
495 fn genCmp(self: *LLVMIRModule, inst: *Inst.BinOp, op: math.CompareOperator) !?*const llvm.Value {
736 fn genCmp(self: *FuncGen, inst: *Inst.BinOp, op: math.CompareOperator) !?*const llvm.Value {
496737 const lhs = try self.resolveInst(inst.lhs);
497738 const rhs = try self.resolveInst(inst.rhs);
498739
......@@ -513,21 +754,21 @@ pub const LLVMIRModule = struct {
513754 return self.builder.buildICmp(operation, lhs, rhs, "");
514755 }
515756
516 fn genBlock(self: *LLVMIRModule, inst: *Inst.Block) !?*const llvm.Value {
517 const parent_bb = self.context.createBasicBlock("Block");
757 fn genBlock(self: *FuncGen, inst: *Inst.Block) !?*const llvm.Value {
758 const parent_bb = self.context().createBasicBlock("Block");
518759
519760 // 5 breaks to a block seems like a reasonable default.
520 var break_bbs = try BreakBasicBlocks.initCapacity(self.gpa, 5);
521 var break_vals = try BreakValues.initCapacity(self.gpa, 5);
522 try self.blocks.putNoClobber(self.gpa, inst, .{
761 var break_bbs = try BreakBasicBlocks.initCapacity(self.gpa(), 5);
762 var break_vals = try BreakValues.initCapacity(self.gpa(), 5);
763 try self.blocks.putNoClobber(self.gpa(), inst, .{
523764 .parent_bb = parent_bb,
524765 .break_bbs = &break_bbs,
525766 .break_vals = &break_vals,
526767 });
527768 defer {
528769 self.blocks.removeAssertDiscard(inst);
529 break_bbs.deinit(self.gpa);
530 break_vals.deinit(self.gpa);
770 break_bbs.deinit(self.gpa());
771 break_vals.deinit(self.gpa());
531772 }
532773
533774 try self.genBody(inst.body);
......@@ -538,7 +779,7 @@ pub const LLVMIRModule = struct {
538779 // If the block does not return a value, we dont have to create a phi node.
539780 if (!inst.base.ty.hasCodeGenBits()) return null;
540781
541 const phi_node = self.builder.buildPhi(try self.getLLVMType(inst.base.ty, inst.base.src), "");
782 const phi_node = self.builder.buildPhi(try self.dg.getLLVMType(inst.base.ty, inst.base.src), "");
542783 phi_node.addIncoming(
543784 break_vals.items.ptr,
544785 break_bbs.items.ptr,
......@@ -547,7 +788,7 @@ pub const LLVMIRModule = struct {
547788 return phi_node;
548789 }
549790
550 fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {
791 fn genBr(self: *FuncGen, inst: *Inst.Br) !?*const llvm.Value {
551792 var block = self.blocks.get(inst.block).?;
552793
553794 // If the break doesn't break a value, then we don't have to add
......@@ -560,25 +801,25 @@ pub const LLVMIRModule = struct {
560801
561802 // For the phi node, we need the basic blocks and the values of the
562803 // break instructions.
563 try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());
564 try block.break_vals.append(self.gpa, val);
804 try block.break_bbs.append(self.gpa(), self.builder.getInsertBlock());
805 try block.break_vals.append(self.gpa(), val);
565806
566807 _ = self.builder.buildBr(block.parent_bb);
567808 }
568809 return null;
569810 }
570811
571 fn genBrVoid(self: *LLVMIRModule, inst: *Inst.BrVoid) !?*const llvm.Value {
812 fn genBrVoid(self: *FuncGen, inst: *Inst.BrVoid) !?*const llvm.Value {
572813 var block = self.blocks.get(inst.block).?;
573814 _ = self.builder.buildBr(block.parent_bb);
574815 return null;
575816 }
576817
577 fn genCondBr(self: *LLVMIRModule, inst: *Inst.CondBr) !?*const llvm.Value {
818 fn genCondBr(self: *FuncGen, inst: *Inst.CondBr) !?*const llvm.Value {
578819 const condition_value = try self.resolveInst(inst.condition);
579820
580 const then_block = self.context.appendBasicBlock(self.llvm_func, "Then");
581 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");
821 const then_block = self.context().appendBasicBlock(self.llvm_func, "Then");
822 const else_block = self.context().appendBasicBlock(self.llvm_func, "Else");
582823 {
583824 const prev_block = self.builder.getInsertBlock();
584825 defer self.builder.positionBuilderAtEnd(prev_block);
......@@ -593,8 +834,8 @@ pub const LLVMIRModule = struct {
593834 return null;
594835 }
595836
596 fn genLoop(self: *LLVMIRModule, inst: *Inst.Loop) !?*const llvm.Value {
597 const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");
837 fn genLoop(self: *FuncGen, inst: *Inst.Loop) !?*const llvm.Value {
838 const loop_block = self.context().appendBasicBlock(self.llvm_func, "Loop");
598839 _ = self.builder.buildBr(loop_block);
599840
600841 self.builder.positionBuilderAtEnd(loop_block);
......@@ -604,20 +845,20 @@ pub const LLVMIRModule = struct {
604845 return null;
605846 }
606847
607 fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
848 fn genNot(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
608849 return self.builder.buildNot(try self.resolveInst(inst.operand), "");
609850 }
610851
611 fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value {
852 fn genUnreach(self: *FuncGen, inst: *Inst.NoOp) ?*const llvm.Value {
612853 _ = self.builder.buildUnreachable();
613854 return null;
614855 }
615856
616 fn genIsNonNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
857 fn genIsNonNull(self: *FuncGen, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
617858 const operand = try self.resolveInst(inst.operand);
618859
619860 if (operand_is_ptr) {
620 const index_type = self.context.intType(32);
861 const index_type = self.context().intType(32);
621862
622863 var indices: [2]*const llvm.Value = .{
623864 index_type.constNull(),
......@@ -630,15 +871,15 @@ pub const LLVMIRModule = struct {
630871 }
631872 }
632873
633 fn genIsNull(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
874 fn genIsNull(self: *FuncGen, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
634875 return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, "");
635876 }
636877
637 fn genOptionalPayload(self: *LLVMIRModule, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
878 fn genOptionalPayload(self: *FuncGen, inst: *Inst.UnOp, operand_is_ptr: bool) !?*const llvm.Value {
638879 const operand = try self.resolveInst(inst.operand);
639880
640881 if (operand_is_ptr) {
641 const index_type = self.context.intType(32);
882 const index_type = self.context().intType(32);
642883
643884 var indices: [2]*const llvm.Value = .{
644885 index_type.constNull(),
......@@ -651,7 +892,7 @@ pub const LLVMIRModule = struct {
651892 }
652893 }
653894
654 fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
895 fn genAdd(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
655896 const lhs = try self.resolveInst(inst.lhs);
656897 const rhs = try self.resolveInst(inst.rhs);
657898
......@@ -664,7 +905,7 @@ pub const LLVMIRModule = struct {
664905 self.builder.buildNUWAdd(lhs, rhs, "");
665906 }
666907
667 fn genSub(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
908 fn genSub(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
668909 const lhs = try self.resolveInst(inst.lhs);
669910 const rhs = try self.resolveInst(inst.rhs);
670911
......@@ -677,44 +918,44 @@ pub const LLVMIRModule = struct {
677918 self.builder.buildNUWSub(lhs, rhs, "");
678919 }
679920
680 fn genIntCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
921 fn genIntCast(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
681922 const val = try self.resolveInst(inst.operand);
682923
683924 const signed = inst.base.ty.isSignedInt();
684925 // TODO: Should we use intcast here or just a simple bitcast?
685926 // LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes
686 return self.builder.buildIntCast2(val, try self.getLLVMType(inst.base.ty, inst.base.src), llvm.Bool.fromBool(signed), "");
927 return self.builder.buildIntCast2(val, try self.dg.getLLVMType(inst.base.ty, inst.base.src), llvm.Bool.fromBool(signed), "");
687928 }
688929
689 fn genBitCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
930 fn genBitCast(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
690931 const val = try self.resolveInst(inst.operand);
691 const dest_type = try self.getLLVMType(inst.base.ty, inst.base.src);
932 const dest_type = try self.dg.getLLVMType(inst.base.ty, inst.base.src);
692933
693934 return self.builder.buildBitCast(val, dest_type, "");
694935 }
695936
696 fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.Value {
937 fn genArg(self: *FuncGen, inst: *Inst.Arg) !?*const llvm.Value {
697938 const arg_val = self.args[self.arg_index];
698939 self.arg_index += 1;
699940
700 const ptr_val = self.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src));
941 const ptr_val = self.buildAlloca(try self.dg.getLLVMType(inst.base.ty, inst.base.src));
701942 _ = self.builder.buildStore(arg_val, ptr_val);
702943 return self.builder.buildLoad(ptr_val, "");
703944 }
704945
705 fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value {
946 fn genAlloc(self: *FuncGen, inst: *Inst.NoOp) !?*const llvm.Value {
706947 // buildAlloca expects the pointee type, not the pointer type, so assert that
707948 // a Payload.PointerSimple is passed to the alloc instruction.
708949 const pointee_type = inst.base.ty.castPointer().?.data;
709950
710951 // TODO: figure out a way to get the name of the var decl.
711952 // TODO: set alignment and volatile
712 return self.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src));
953 return self.buildAlloca(try self.dg.getLLVMType(pointee_type, inst.base.src));
713954 }
714955
715956 /// Use this instead of builder.buildAlloca, because this function makes sure to
716957 /// put the alloca instruction at the top of the function!
717 fn buildAlloca(self: *LLVMIRModule, t: *const llvm.Type) *const llvm.Value {
958 fn buildAlloca(self: *FuncGen, t: *const llvm.Type) *const llvm.Value {
718959 const prev_block = self.builder.getInsertBlock();
719960 defer self.builder.positionBuilderAtEnd(prev_block);
720961
......@@ -736,240 +977,30 @@ pub const LLVMIRModule = struct {
736977 return val;
737978 }
738979
739 fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {
980 fn genStore(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
740981 const val = try self.resolveInst(inst.rhs);
741982 const ptr = try self.resolveInst(inst.lhs);
742983 _ = self.builder.buildStore(val, ptr);
743984 return null;
744985 }
745986
746 fn genLoad(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {
987 fn genLoad(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
747988 const ptr_val = try self.resolveInst(inst.operand);
748989 return self.builder.buildLoad(ptr_val, "");
749990 }
750991
751 fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value {
992 fn genBreakpoint(self: *FuncGen, inst: *Inst.NoOp) !?*const llvm.Value {
752993 const llvn_fn = self.getIntrinsic("llvm.debugtrap");
753994 _ = self.builder.buildCall(llvn_fn, null, 0, "");
754995 return null;
755996 }
756997
757 fn getIntrinsic(self: *LLVMIRModule, name: []const u8) *const llvm.Value {
998 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
758999 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
7591000 assert(id != 0);
7601001 // TODO: add support for overload intrinsics by passing the prefix of the intrinsic
7611002 // to `lookupIntrinsicID` and then passing the correct types to
7621003 // `getIntrinsicDeclaration`
763 return self.llvm_module.getIntrinsicDeclaration(id, null, 0);
764 }
765
766 fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.Value {
767 if (inst.value()) |val| {
768 return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = val });
769 }
770 if (self.func_inst_table.get(inst)) |value| return value;
771
772 return self.fail(inst.src, "TODO implement global llvm values (or the value is not in the func_inst_table table)", .{});
773 }
774
775 fn genTypedValue(self: *LLVMIRModule, src: LazySrcLoc, tv: TypedValue) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
776 const llvm_type = try self.getLLVMType(tv.ty, src);
777
778 if (tv.val.isUndef())
779 return llvm_type.getUndef();
780
781 switch (tv.ty.zigTypeTag()) {
782 .Bool => return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),
783 .Int => {
784 var bigint_space: Value.BigIntSpace = undefined;
785 const bigint = tv.val.toBigInt(&bigint_space);
786
787 if (bigint.eqZero()) return llvm_type.constNull();
788
789 if (bigint.limbs.len != 1) {
790 return self.fail(src, "TODO implement bigger bigint", .{});
791 }
792 const llvm_int = llvm_type.constInt(bigint.limbs[0], .False);
793 if (!bigint.positive) {
794 return llvm.constNeg(llvm_int);
795 }
796 return llvm_int;
797 },
798 .Pointer => switch (tv.val.tag()) {
799 .decl_ref => {
800 const decl = tv.val.castTag(.decl_ref).?.data;
801 const val = try self.resolveGlobalDecl(decl, src);
802
803 const usize_type = try self.getLLVMType(Type.initTag(.usize), src);
804
805 // TODO: second index should be the index into the memory!
806 var indices: [2]*const llvm.Value = .{
807 usize_type.constNull(),
808 usize_type.constNull(),
809 };
810
811 // TODO: consider using buildInBoundsGEP2 for opaque pointers
812 return self.builder.buildInBoundsGEP(val, &indices, 2, "");
813 },
814 .ref_val => {
815 const elem_value = tv.val.castTag(.ref_val).?.data;
816 const elem_type = tv.ty.castPointer().?.data;
817 const alloca = self.buildAlloca(try self.getLLVMType(elem_type, src));
818 _ = self.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }), alloca);
819 return alloca;
820 },
821 else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}),
822 },
823 .Array => {
824 if (tv.val.castTag(.bytes)) |payload| {
825 const zero_sentinel = if (tv.ty.sentinel()) |sentinel| blk: {
826 if (sentinel.tag() == .zero) break :blk true;
827 return self.fail(src, "TODO handle other sentinel values", .{});
828 } else false;
829
830 return self.context.constString(payload.data.ptr, @intCast(c_uint, payload.data.len), llvm.Bool.fromBool(!zero_sentinel));
831 } else {
832 return self.fail(src, "TODO handle more array values", .{});
833 }
834 },
835 .Optional => {
836 if (!tv.ty.isPtrLikeOptional()) {
837 var buf: Type.Payload.ElemType = undefined;
838 const child_type = tv.ty.optionalChild(&buf);
839 const llvm_child_type = try self.getLLVMType(child_type, src);
840
841 if (tv.val.tag() == .null_value) {
842 var optional_values: [2]*const llvm.Value = .{
843 llvm_child_type.constNull(),
844 self.context.intType(1).constNull(),
845 };
846 return self.context.constStruct(&optional_values, 2, .False);
847 } else {
848 var optional_values: [2]*const llvm.Value = .{
849 try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }),
850 self.context.intType(1).constAllOnes(),
851 };
852 return self.context.constStruct(&optional_values, 2, .False);
853 }
854 } else {
855 return self.fail(src, "TODO implement const of optional pointer", .{});
856 }
857 },
858 else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}),
859 }
860 }
861
862 fn getLLVMType(self: *LLVMIRModule, t: Type, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Type {
863 switch (t.zigTypeTag()) {
864 .Void => return self.context.voidType(),
865 .NoReturn => return self.context.voidType(),
866 .Int => {
867 const info = t.intInfo(self.module.getTarget());
868 return self.context.intType(info.bits);
869 },
870 .Bool => return self.context.intType(1),
871 .Pointer => {
872 if (t.isSlice()) {
873 return self.fail(src, "TODO: LLVM backend: implement slices", .{});
874 } else {
875 const elem_type = try self.getLLVMType(t.elemType(), src);
876 return elem_type.pointerType(0);
877 }
878 },
879 .Array => {
880 const elem_type = try self.getLLVMType(t.elemType(), src);
881 return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget())));
882 },
883 .Optional => {
884 if (!t.isPtrLikeOptional()) {
885 var buf: Type.Payload.ElemType = undefined;
886 const child_type = t.optionalChild(&buf);
887
888 var optional_types: [2]*const llvm.Type = .{
889 try self.getLLVMType(child_type, src),
890 self.context.intType(1),
891 };
892 return self.context.structType(&optional_types, 2, .False);
893 } else {
894 return self.fail(src, "TODO implement optional pointers as actual pointers", .{});
895 }
896 },
897 else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}),
898 }
899 }
900
901 fn resolveGlobalDecl(self: *LLVMIRModule, decl: *Module.Decl, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
902 // TODO: do we want to store this in our own datastructure?
903 if (self.llvm_module.getNamedGlobal(decl.name)) |val| return val;
904
905 const typed_value = decl.typed_value.most_recent.typed_value;
906
907 // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`.
908 const llvm_type = try self.getLLVMType(typed_value.ty, src);
909 const val = try self.genTypedValue(src, typed_value);
910 const global = self.llvm_module.addGlobal(llvm_type, decl.name);
911 llvm.setInitializer(global, val);
912
913 // TODO ask the Decl if it is const
914 // https://github.com/ziglang/zig/issues/7582
915
916 return global;
917 }
918
919 /// If the llvm function does not exist, create it
920 fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Decl, src: LazySrcLoc) !*const llvm.Value {
921 // TODO: do we want to store this in our own datastructure?
922 if (self.llvm_module.getNamedFunction(func.name)) |llvm_fn| return llvm_fn;
923
924 const zig_fn_type = func.typed_value.most_recent.typed_value.ty;
925 const return_type = zig_fn_type.fnReturnType();
926
927 const fn_param_len = zig_fn_type.fnParamLen();
928
929 const fn_param_types = try self.gpa.alloc(Type, fn_param_len);
930 defer self.gpa.free(fn_param_types);
931 zig_fn_type.fnParamTypes(fn_param_types);
932
933 const llvm_param = try self.gpa.alloc(*const llvm.Type, fn_param_len);
934 defer self.gpa.free(llvm_param);
935
936 for (fn_param_types) |fn_param, i| {
937 llvm_param[i] = try self.getLLVMType(fn_param, src);
938 }
939
940 const fn_type = llvm.Type.functionType(
941 try self.getLLVMType(return_type, src),
942 if (fn_param_len == 0) null else llvm_param.ptr,
943 @intCast(c_uint, fn_param_len),
944 .False,
945 );
946 const llvm_fn = self.llvm_module.addFunction(func.name, fn_type);
947
948 if (return_type.tag() == .noreturn) {
949 self.addFnAttr(llvm_fn, "noreturn");
950 }
951
952 return llvm_fn;
953 }
954
955 // Helper functions
956 fn addAttr(self: LLVMIRModule, val: *const llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
957 const kind_id = llvm.getEnumAttributeKindForName(name.ptr, name.len);
958 assert(kind_id != 0);
959 const llvm_attr = self.context.createEnumAttribute(kind_id, 0);
960 val.addAttributeAtIndex(index, llvm_attr);
961 }
962
963 fn addFnAttr(self: *LLVMIRModule, val: *const llvm.Value, attr_name: []const u8) void {
964 // TODO: improve this API, `addAttr(-1, attr_name)`
965 self.addAttr(val, std.math.maxInt(llvm.AttributeIndex), attr_name);
966 }
967
968 pub fn fail(self: *LLVMIRModule, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
969 @setCold(true);
970 assert(self.err_msg == null);
971 const src_loc = src.toSrcLocWithDecl(self.decl);
972 self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, format, args);
973 return error.CodegenFail;
1004 return self.llvmModule().getIntrinsicDeclaration(id, null, 0);
9741005 }
9751006};
src/link/Coff.zig+9-9
......@@ -34,7 +34,7 @@ pub const base_tag: link.File.Tag = .coff;
3434const msdos_stub = @embedFile("msdos-stub.bin");
3535
3636/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
37llvm_ir_module: ?*llvm_backend.LLVMIRModule = null,
37llvm_object: ?*llvm_backend.Object = null,
3838
3939base: link.File,
4040ptr_width: PtrWidth,
......@@ -129,7 +129,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
129129 const self = try createEmpty(allocator, options);
130130 errdefer self.base.destroy();
131131
132 self.llvm_ir_module = try llvm_backend.LLVMIRModule.create(allocator, sub_path, options);
132 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
133133 return self;
134134 }
135135
......@@ -413,7 +413,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Coff {
413413}
414414
415415pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void {
416 if (self.llvm_ir_module) |_| return;
416 if (self.llvm_object) |_| return;
417417
418418 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
419419
......@@ -660,7 +660,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
660660 defer tracy.end();
661661
662662 if (build_options.have_llvm)
663 if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl);
663 if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
664664
665665 const typed_value = decl.typed_value.most_recent.typed_value;
666666 if (typed_value.val.tag() == .extern_fn) {
......@@ -720,7 +720,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
720720}
721721
722722pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
723 if (self.llvm_ir_module) |_| return;
723 if (self.llvm_object) |_| return;
724724
725725 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
726726 self.freeTextBlock(&decl.link.coff);
......@@ -728,7 +728,7 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
728728}
729729
730730pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void {
731 if (self.llvm_ir_module) |_| return;
731 if (self.llvm_object) |_| return;
732732
733733 for (exports) |exp| {
734734 if (exp.options.section) |section_name| {
......@@ -771,7 +771,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
771771 defer tracy.end();
772772
773773 if (build_options.have_llvm)
774 if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.flushModule(comp);
774 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);
775775
776776 if (self.text_section_size_dirty) {
777777 // Write the new raw size in the .text header
......@@ -1308,7 +1308,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
13081308}
13091309
13101310pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {
1311 assert(self.llvm_ir_module == null);
1311 assert(self.llvm_object == null);
13121312 return self.text_section_virtual_address + decl.link.coff.text_offset;
13131313}
13141314
......@@ -1318,7 +1318,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
13181318
13191319pub fn deinit(self: *Coff) void {
13201320 if (build_options.have_llvm)
1321 if (self.llvm_ir_module) |ir_module| ir_module.deinit(self.base.allocator);
1321 if (self.llvm_object) |ir_module| ir_module.deinit(self.base.allocator);
13221322
13231323 self.text_block_free_list.deinit(self.base.allocator);
13241324 self.offset_table.deinit(self.base.allocator);
src/link/Elf.zig+12-12
......@@ -35,7 +35,7 @@ base: File,
3535ptr_width: PtrWidth,
3636
3737/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
38llvm_ir_module: ?*llvm_backend.LLVMIRModule = null,
38llvm_object: ?*llvm_backend.Object = null,
3939
4040/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
4141/// Same order as in the file.
......@@ -232,7 +232,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
232232 const self = try createEmpty(allocator, options);
233233 errdefer self.base.destroy();
234234
235 self.llvm_ir_module = try llvm_backend.LLVMIRModule.create(allocator, sub_path, options);
235 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
236236 return self;
237237 }
238238
......@@ -299,7 +299,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
299299
300300pub fn deinit(self: *Elf) void {
301301 if (build_options.have_llvm)
302 if (self.llvm_ir_module) |ir_module|
302 if (self.llvm_object) |ir_module|
303303 ir_module.deinit(self.base.allocator);
304304
305305 self.sections.deinit(self.base.allocator);
......@@ -318,7 +318,7 @@ pub fn deinit(self: *Elf) void {
318318}
319319
320320pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
321 assert(self.llvm_ir_module == null);
321 assert(self.llvm_object == null);
322322 assert(decl.link.elf.local_sym_index != 0);
323323 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;
324324}
......@@ -438,7 +438,7 @@ fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
438438}
439439
440440pub fn populateMissingMetadata(self: *Elf) !void {
441 assert(self.llvm_ir_module == null);
441 assert(self.llvm_object == null);
442442
443443 const small_ptr = switch (self.ptr_width) {
444444 .p32 => true,
......@@ -745,7 +745,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
745745 defer tracy.end();
746746
747747 if (build_options.have_llvm)
748 if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.flushModule(comp);
748 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);
749749
750750 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
751751 // Zig source code.
......@@ -2111,7 +2111,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21112111}
21122112
21132113pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
2114 if (self.llvm_ir_module) |_| return;
2114 if (self.llvm_object) |_| return;
21152115
21162116 if (decl.link.elf.local_sym_index != 0) return;
21172117
......@@ -2149,7 +2149,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
21492149}
21502150
21512151pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2152 if (self.llvm_ir_module) |_| return;
2152 if (self.llvm_object) |_| return;
21532153
21542154 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
21552155 self.freeTextBlock(&decl.link.elf);
......@@ -2189,7 +2189,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
21892189 defer tracy.end();
21902190
21912191 if (build_options.have_llvm)
2192 if (self.llvm_ir_module) |llvm_ir_module| return try llvm_ir_module.updateDecl(module, decl);
2192 if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
21932193
21942194 const typed_value = decl.typed_value.most_recent.typed_value;
21952195 if (typed_value.val.tag() == .extern_fn) {
......@@ -2673,7 +2673,7 @@ pub fn updateDeclExports(
26732673 decl: *Module.Decl,
26742674 exports: []const *Module.Export,
26752675) !void {
2676 if (self.llvm_ir_module) |_| return;
2676 if (self.llvm_object) |_| return;
26772677
26782678 const tracy = trace(@src());
26792679 defer tracy.end();
......@@ -2748,7 +2748,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27482748 const tracy = trace(@src());
27492749 defer tracy.end();
27502750
2751 if (self.llvm_ir_module) |_| return;
2751 if (self.llvm_object) |_| return;
27522752
27532753 const tree = decl.container.file_scope.tree;
27542754 const node_tags = tree.nodes.items(.tag);
......@@ -2773,7 +2773,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27732773}
27742774
27752775pub fn deleteExport(self: *Elf, exp: Export) void {
2776 if (self.llvm_ir_module) |_| return;
2776 if (self.llvm_object) |_| return;
27772777
27782778 const sym_index = exp.sym_index orelse return;
27792779 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};