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;...@@ -16,7 +16,6 @@ const Value = @import("../value.zig").Value;
16const Type = @import("../type.zig").Type;16const Type = @import("../type.zig").Type;
1717
18const LazySrcLoc = Module.LazySrcLoc;18const LazySrcLoc = Module.LazySrcLoc;
19const SrcLoc = Module.SrcLoc;
2019
21pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {20pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
22 const llvm_arch = switch (target.cpu.arch) {21 const llvm_arch = switch (target.cpu.arch) {
...@@ -146,83 +145,42 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -146,83 +145,42 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
146 return std.fmt.allocPrintZ(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi });145 return std.fmt.allocPrintZ(allocator, "{s}-unknown-{s}-{s}", .{ llvm_arch, llvm_os, llvm_abi });
147}146}
148147
149pub const LLVMIRModule = struct {148pub const Object = struct {
150 module: *Module,
151 llvm_module: *const llvm.Module,149 llvm_module: *const llvm.Module,
152 context: *const llvm.Context,150 context: *const llvm.Context,
153 target_machine: *const llvm.TargetMachine,151 target_machine: *const llvm.TargetMachine,
154 builder: *const llvm.Builder,152 object_pathZ: [:0]const u8,
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);
196153
197 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {154 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Object {
198 const self = try allocator.create(LLVMIRModule);155 const self = try allocator.create(Object);
199 errdefer allocator.destroy(self);156 errdefer allocator.destroy(self);
200157
201 const gpa = options.module.?.gpa;158 const obj_basename = try std.zig.binNameAlloc(allocator, .{
202
203 const obj_basename = try std.zig.binNameAlloc(gpa, .{
204 .root_name = options.root_name,159 .root_name = options.root_name,
205 .target = options.target,160 .target = options.target,
206 .output_mode = .Obj,161 .output_mode = .Obj,
207 });162 });
208 defer gpa.free(obj_basename);163 defer allocator.free(obj_basename);
209164
210 const o_directory = options.module.?.zig_cache_artifact_directory;165 const o_directory = options.module.?.zig_cache_artifact_directory;
211 const object_path = try o_directory.join(gpa, &[_][]const u8{obj_basename});166 const object_path = try o_directory.join(allocator, &[_][]const u8{obj_basename});
212 errdefer gpa.free(object_path);167 defer allocator.free(object_path);
168
169 const object_pathZ = try allocator.dupeZ(u8, object_path);
170 errdefer allocator.free(object_pathZ);
213171
214 const context = llvm.Context.create();172 const context = llvm.Context.create();
215 errdefer context.dispose();173 errdefer context.dispose();
216174
217 initializeLLVMTargets();175 initializeLLVMTargets();
218176
219 const root_nameZ = try gpa.dupeZ(u8, options.root_name);177 const root_nameZ = try allocator.dupeZ(u8, options.root_name);
220 defer gpa.free(root_nameZ);178 defer allocator.free(root_nameZ);
221 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);179 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
222 errdefer llvm_module.dispose();180 errdefer llvm_module.dispose();
223181
224 const llvm_target_triple = try targetTriple(gpa, options.target);182 const llvm_target_triple = try targetTriple(allocator, options.target);
225 defer gpa.free(llvm_target_triple);183 defer allocator.free(llvm_target_triple);
226184
227 var error_message: [*:0]const u8 = undefined;185 var error_message: [*:0]const u8 = undefined;
228 var target: *const llvm.Target = undefined;186 var target: *const llvm.Target = undefined;
...@@ -257,34 +215,21 @@ pub const LLVMIRModule = struct {...@@ -257,34 +215,21 @@ pub const LLVMIRModule = struct {
257 );215 );
258 errdefer target_machine.dispose();216 errdefer target_machine.dispose();
259217
260 const builder = context.createBuilder();
261 errdefer builder.dispose();
262
263 self.* = .{218 self.* = .{
264 .module = options.module.?,
265 .llvm_module = llvm_module,219 .llvm_module = llvm_module,
266 .context = context,220 .context = context,
267 .target_machine = target_machine,221 .target_machine = target_machine,
268 .builder = builder,222 .object_pathZ = object_pathZ,
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,
273 };223 };
274 return self;224 return self;
275 }225 }
276226
277 pub fn deinit(self: *LLVMIRModule, allocator: *Allocator) void {227 pub fn deinit(self: *Object, allocator: *Allocator) void {
278 self.builder.dispose();
279 self.target_machine.dispose();228 self.target_machine.dispose();
280 self.llvm_module.dispose();229 self.llvm_module.dispose();
281 self.context.dispose();230 self.context.dispose();
282231
283 self.func_inst_table.deinit(self.gpa);232 allocator.free(self.object_pathZ);
284 self.gpa.free(self.object_path);
285
286 self.blocks.deinit(self.gpa);
287
288 allocator.destroy(self);233 allocator.destroy(self);
289 }234 }
290235
...@@ -296,7 +241,7 @@ pub const LLVMIRModule = struct {...@@ -296,7 +241,7 @@ pub const LLVMIRModule = struct {
296 llvm.initializeAllAsmParsers();241 llvm.initializeAllAsmParsers();
297 }242 }
298243
299 pub fn flushModule(self: *LLVMIRModule, comp: *Compilation) !void {244 pub fn flushModule(self: *Object, comp: *Compilation) !void {
300 if (comp.verbose_llvm_ir) {245 if (comp.verbose_llvm_ir) {
301 const dump = self.llvm_module.printToString();246 const dump = self.llvm_module.printToString();
302 defer llvm.disposeMessage(dump);247 defer llvm.disposeMessage(dump);
...@@ -317,13 +262,10 @@ pub const LLVMIRModule = struct {...@@ -317,13 +262,10 @@ pub const LLVMIRModule = struct {
317 }262 }
318 }263 }
319264
320 const object_pathZ = try self.gpa.dupeZ(u8, self.object_path);
321 defer self.gpa.free(object_pathZ);
322
323 var error_message: [*:0]const u8 = undefined;265 var error_message: [*:0]const u8 = undefined;
324 if (self.target_machine.emitToFile(266 if (self.target_machine.emitToFile(
325 self.llvm_module,267 self.llvm_module,
326 object_pathZ.ptr,268 self.object_pathZ.ptr,
327 .ObjectFile,269 .ObjectFile,
328 &error_message,270 &error_message,
329 ).toBool()) {271 ).toBool()) {
...@@ -335,23 +277,55 @@ pub const LLVMIRModule = struct {...@@ -335,23 +277,55 @@ pub const LLVMIRModule = struct {
335 }277 }
336 }278 }
337279
338 pub fn updateDecl(self: *LLVMIRModule, module: *Module, decl: *Module.Decl) !void {280 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
339 self.gen(module, decl) catch |err| switch (err) {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) {
340 error.CodegenFail => {289 error.CodegenFail => {
341 decl.analysis = .codegen_failure;290 decl.analysis = .codegen_failure;
342 try module.failed_decls.put(module.gpa, decl, self.err_msg.?);291 try module.failed_decls.put(module.gpa, decl, dg.err_msg.?);
343 self.err_msg = null;292 dg.err_msg = null;
344 return;293 return;
345 },294 },
346 else => |e| return e,295 else => |e| return e,
347 };296 };
348 }297 }
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;
351 const typed_value = decl.typed_value.most_recent.typed_value;326 const typed_value = decl.typed_value.most_recent.typed_value;
352 self.src_loc = decl.srcLoc();327
353 self.decl = decl;328 const src = decl.srcLoc().lazy;
354 const src = self.src_loc.lazy;
355329
356 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val });330 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val });
357331
...@@ -363,16 +337,10 @@ pub const LLVMIRModule = struct {...@@ -363,16 +337,10 @@ pub const LLVMIRModule = struct {
363 // This gets the LLVM values from the function and stores them in `self.args`.337 // This gets the LLVM values from the function and stores them in `self.args`.
364 const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen();338 const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen();
365 var args = try self.gpa.alloc(*const llvm.Value, fn_param_len);339 var args = try self.gpa.alloc(*const llvm.Value, fn_param_len);
366 defer self.gpa.free(args);
367340
368 for (args) |*arg, i| {341 for (args) |*arg, i| {
369 arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));342 arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
370 }343 }
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
377 // We remove all the basic blocks of a function to support incremental345 // We remove all the basic blocks of a function to support incremental
378 // compilation!346 // compilation!
...@@ -381,12 +349,25 @@ pub const LLVMIRModule = struct {...@@ -381,12 +349,25 @@ pub const LLVMIRModule = struct {
381 bb.deleteBasicBlock();349 bb.deleteBasicBlock();
382 }350 }
383351
384 self.entry_block = self.context.appendBasicBlock(llvm_func, "Entry");352 const builder = self.context().createBuilder();
385 self.builder.positionBuilderAtEnd(self.entry_block);353
386 self.latest_alloca_inst = null;354 const entry_block = self.context().appendBasicBlock(llvm_func, "Entry");
387 self.llvm_func = llvm_func;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);
390 } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| {371 } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| {
391 _ = try self.resolveLLVMFunction(extern_fn.data, src);372 _ = try self.resolveLLVMFunction(extern_fn.data, src);
392 } else {373 } else {
...@@ -394,7 +375,267 @@ pub const LLVMIRModule = struct {...@@ -394,7 +375,267 @@ pub const LLVMIRModule = struct {
394 }375 }
395 }376 }
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 {
398 for (body.instructions) |inst| {639 for (body.instructions) |inst| {
399 const opt_value = switch (inst.tag) {640 const opt_value = switch (inst.tag) {
400 .add => try self.genAdd(inst.castTag(.add).?),641 .add => try self.genAdd(inst.castTag(.add).?),
...@@ -434,11 +675,11 @@ pub const LLVMIRModule = struct {...@@ -434,11 +675,11 @@ pub const LLVMIRModule = struct {
434 },675 },
435 else => |tag| return self.fail(inst.src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}),676 else => |tag| return self.fail(inst.src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}),
436 };677 };
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);
438 }679 }
439 }680 }
440681
441 fn genCall(self: *LLVMIRModule, inst: *Inst.Call) !?*const llvm.Value {682 fn genCall(self: *FuncGen, inst: *Inst.Call) !?*const llvm.Value {
442 if (inst.func.value()) |func_value| {683 if (inst.func.value()) |func_value| {
443 const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|684 const fn_decl = if (func_value.castTag(.extern_fn)) |extern_fn|
444 extern_fn.data685 extern_fn.data
...@@ -448,12 +689,12 @@ pub const LLVMIRModule = struct {...@@ -448,12 +689,12 @@ pub const LLVMIRModule = struct {
448 unreachable;689 unreachable;
449690
450 const zig_fn_type = fn_decl.typed_value.most_recent.typed_value.ty;691 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
453 const num_args = inst.args.len;694 const num_args = inst.args.len;
454695
455 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, num_args);696 const llvm_param_vals = try self.gpa().alloc(*const llvm.Value, num_args);
456 defer self.gpa.free(llvm_param_vals);697 defer self.gpa().free(llvm_param_vals);
457698
458 for (inst.args) |arg, i| {699 for (inst.args) |arg, i| {
459 llvm_param_vals[i] = try self.resolveInst(arg);700 llvm_param_vals[i] = try self.resolveInst(arg);
...@@ -482,17 +723,17 @@ pub const LLVMIRModule = struct {...@@ -482,17 +723,17 @@ pub const LLVMIRModule = struct {
482 }723 }
483 }724 }
484725
485 fn genRetVoid(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value {726 fn genRetVoid(self: *FuncGen, inst: *Inst.NoOp) ?*const llvm.Value {
486 _ = self.builder.buildRetVoid();727 _ = self.builder.buildRetVoid();
487 return null;728 return null;
488 }729 }
489730
490 fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {731 fn genRet(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
491 _ = self.builder.buildRet(try self.resolveInst(inst.operand));732 _ = self.builder.buildRet(try self.resolveInst(inst.operand));
492 return null;733 return null;
493 }734 }
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 {
496 const lhs = try self.resolveInst(inst.lhs);737 const lhs = try self.resolveInst(inst.lhs);
497 const rhs = try self.resolveInst(inst.rhs);738 const rhs = try self.resolveInst(inst.rhs);
498739
...@@ -513,21 +754,21 @@ pub const LLVMIRModule = struct {...@@ -513,21 +754,21 @@ pub const LLVMIRModule = struct {
513 return self.builder.buildICmp(operation, lhs, rhs, "");754 return self.builder.buildICmp(operation, lhs, rhs, "");
514 }755 }
515756
516 fn genBlock(self: *LLVMIRModule, inst: *Inst.Block) !?*const llvm.Value {757 fn genBlock(self: *FuncGen, inst: *Inst.Block) !?*const llvm.Value {
517 const parent_bb = self.context.createBasicBlock("Block");758 const parent_bb = self.context().createBasicBlock("Block");
518759
519 // 5 breaks to a block seems like a reasonable default.760 // 5 breaks to a block seems like a reasonable default.
520 var break_bbs = try BreakBasicBlocks.initCapacity(self.gpa, 5);761 var break_bbs = try BreakBasicBlocks.initCapacity(self.gpa(), 5);
521 var break_vals = try BreakValues.initCapacity(self.gpa, 5);762 var break_vals = try BreakValues.initCapacity(self.gpa(), 5);
522 try self.blocks.putNoClobber(self.gpa, inst, .{763 try self.blocks.putNoClobber(self.gpa(), inst, .{
523 .parent_bb = parent_bb,764 .parent_bb = parent_bb,
524 .break_bbs = &break_bbs,765 .break_bbs = &break_bbs,
525 .break_vals = &break_vals,766 .break_vals = &break_vals,
526 });767 });
527 defer {768 defer {
528 self.blocks.removeAssertDiscard(inst);769 self.blocks.removeAssertDiscard(inst);
529 break_bbs.deinit(self.gpa);770 break_bbs.deinit(self.gpa());
530 break_vals.deinit(self.gpa);771 break_vals.deinit(self.gpa());
531 }772 }
532773
533 try self.genBody(inst.body);774 try self.genBody(inst.body);
...@@ -538,7 +779,7 @@ pub const LLVMIRModule = struct {...@@ -538,7 +779,7 @@ pub const LLVMIRModule = struct {
538 // If the block does not return a value, we dont have to create a phi node.779 // If the block does not return a value, we dont have to create a phi node.
539 if (!inst.base.ty.hasCodeGenBits()) return null;780 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), "");
542 phi_node.addIncoming(783 phi_node.addIncoming(
543 break_vals.items.ptr,784 break_vals.items.ptr,
544 break_bbs.items.ptr,785 break_bbs.items.ptr,
...@@ -547,7 +788,7 @@ pub const LLVMIRModule = struct {...@@ -547,7 +788,7 @@ pub const LLVMIRModule = struct {
547 return phi_node;788 return phi_node;
548 }789 }
549790
550 fn genBr(self: *LLVMIRModule, inst: *Inst.Br) !?*const llvm.Value {791 fn genBr(self: *FuncGen, inst: *Inst.Br) !?*const llvm.Value {
551 var block = self.blocks.get(inst.block).?;792 var block = self.blocks.get(inst.block).?;
552793
553 // If the break doesn't break a value, then we don't have to add794 // If the break doesn't break a value, then we don't have to add
...@@ -560,25 +801,25 @@ pub const LLVMIRModule = struct {...@@ -560,25 +801,25 @@ pub const LLVMIRModule = struct {
560801
561 // For the phi node, we need the basic blocks and the values of the802 // For the phi node, we need the basic blocks and the values of the
562 // break instructions.803 // break instructions.
563 try block.break_bbs.append(self.gpa, self.builder.getInsertBlock());804 try block.break_bbs.append(self.gpa(), self.builder.getInsertBlock());
564 try block.break_vals.append(self.gpa, val);805 try block.break_vals.append(self.gpa(), val);
565806
566 _ = self.builder.buildBr(block.parent_bb);807 _ = self.builder.buildBr(block.parent_bb);
567 }808 }
568 return null;809 return null;
569 }810 }
570811
571 fn genBrVoid(self: *LLVMIRModule, inst: *Inst.BrVoid) !?*const llvm.Value {812 fn genBrVoid(self: *FuncGen, inst: *Inst.BrVoid) !?*const llvm.Value {
572 var block = self.blocks.get(inst.block).?;813 var block = self.blocks.get(inst.block).?;
573 _ = self.builder.buildBr(block.parent_bb);814 _ = self.builder.buildBr(block.parent_bb);
574 return null;815 return null;
575 }816 }
576817
577 fn genCondBr(self: *LLVMIRModule, inst: *Inst.CondBr) !?*const llvm.Value {818 fn genCondBr(self: *FuncGen, inst: *Inst.CondBr) !?*const llvm.Value {
578 const condition_value = try self.resolveInst(inst.condition);819 const condition_value = try self.resolveInst(inst.condition);
579820
580 const then_block = self.context.appendBasicBlock(self.llvm_func, "Then");821 const then_block = self.context().appendBasicBlock(self.llvm_func, "Then");
581 const else_block = self.context.appendBasicBlock(self.llvm_func, "Else");822 const else_block = self.context().appendBasicBlock(self.llvm_func, "Else");
582 {823 {
583 const prev_block = self.builder.getInsertBlock();824 const prev_block = self.builder.getInsertBlock();
584 defer self.builder.positionBuilderAtEnd(prev_block);825 defer self.builder.positionBuilderAtEnd(prev_block);
...@@ -593,8 +834,8 @@ pub const LLVMIRModule = struct {...@@ -593,8 +834,8 @@ pub const LLVMIRModule = struct {
593 return null;834 return null;
594 }835 }
595836
596 fn genLoop(self: *LLVMIRModule, inst: *Inst.Loop) !?*const llvm.Value {837 fn genLoop(self: *FuncGen, inst: *Inst.Loop) !?*const llvm.Value {
597 const loop_block = self.context.appendBasicBlock(self.llvm_func, "Loop");838 const loop_block = self.context().appendBasicBlock(self.llvm_func, "Loop");
598 _ = self.builder.buildBr(loop_block);839 _ = self.builder.buildBr(loop_block);
599840
600 self.builder.positionBuilderAtEnd(loop_block);841 self.builder.positionBuilderAtEnd(loop_block);
...@@ -604,20 +845,20 @@ pub const LLVMIRModule = struct {...@@ -604,20 +845,20 @@ pub const LLVMIRModule = struct {
604 return null;845 return null;
605 }846 }
606847
607 fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {848 fn genNot(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
608 return self.builder.buildNot(try self.resolveInst(inst.operand), "");849 return self.builder.buildNot(try self.resolveInst(inst.operand), "");
609 }850 }
610851
611 fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.Value {852 fn genUnreach(self: *FuncGen, inst: *Inst.NoOp) ?*const llvm.Value {
612 _ = self.builder.buildUnreachable();853 _ = self.builder.buildUnreachable();
613 return null;854 return null;
614 }855 }
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 {
617 const operand = try self.resolveInst(inst.operand);858 const operand = try self.resolveInst(inst.operand);
618859
619 if (operand_is_ptr) {860 if (operand_is_ptr) {
620 const index_type = self.context.intType(32);861 const index_type = self.context().intType(32);
621862
622 var indices: [2]*const llvm.Value = .{863 var indices: [2]*const llvm.Value = .{
623 index_type.constNull(),864 index_type.constNull(),
...@@ -630,15 +871,15 @@ pub const LLVMIRModule = struct {...@@ -630,15 +871,15 @@ pub const LLVMIRModule = struct {
630 }871 }
631 }872 }
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 {
634 return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, "");875 return self.builder.buildNot((try self.genIsNonNull(inst, operand_is_ptr)).?, "");
635 }876 }
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 {
638 const operand = try self.resolveInst(inst.operand);879 const operand = try self.resolveInst(inst.operand);
639880
640 if (operand_is_ptr) {881 if (operand_is_ptr) {
641 const index_type = self.context.intType(32);882 const index_type = self.context().intType(32);
642883
643 var indices: [2]*const llvm.Value = .{884 var indices: [2]*const llvm.Value = .{
644 index_type.constNull(),885 index_type.constNull(),
...@@ -651,7 +892,7 @@ pub const LLVMIRModule = struct {...@@ -651,7 +892,7 @@ pub const LLVMIRModule = struct {
651 }892 }
652 }893 }
653894
654 fn genAdd(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {895 fn genAdd(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
655 const lhs = try self.resolveInst(inst.lhs);896 const lhs = try self.resolveInst(inst.lhs);
656 const rhs = try self.resolveInst(inst.rhs);897 const rhs = try self.resolveInst(inst.rhs);
657898
...@@ -664,7 +905,7 @@ pub const LLVMIRModule = struct {...@@ -664,7 +905,7 @@ pub const LLVMIRModule = struct {
664 self.builder.buildNUWAdd(lhs, rhs, "");905 self.builder.buildNUWAdd(lhs, rhs, "");
665 }906 }
666907
667 fn genSub(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {908 fn genSub(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
668 const lhs = try self.resolveInst(inst.lhs);909 const lhs = try self.resolveInst(inst.lhs);
669 const rhs = try self.resolveInst(inst.rhs);910 const rhs = try self.resolveInst(inst.rhs);
670911
...@@ -677,44 +918,44 @@ pub const LLVMIRModule = struct {...@@ -677,44 +918,44 @@ pub const LLVMIRModule = struct {
677 self.builder.buildNUWSub(lhs, rhs, "");918 self.builder.buildNUWSub(lhs, rhs, "");
678 }919 }
679920
680 fn genIntCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {921 fn genIntCast(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
681 const val = try self.resolveInst(inst.operand);922 const val = try self.resolveInst(inst.operand);
682923
683 const signed = inst.base.ty.isSignedInt();924 const signed = inst.base.ty.isSignedInt();
684 // TODO: Should we use intcast here or just a simple bitcast?925 // TODO: Should we use intcast here or just a simple bitcast?
685 // LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes926 // 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), "");
687 }928 }
688929
689 fn genBitCast(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {930 fn genBitCast(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
690 const val = try self.resolveInst(inst.operand);931 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
693 return self.builder.buildBitCast(val, dest_type, "");934 return self.builder.buildBitCast(val, dest_type, "");
694 }935 }
695936
696 fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.Value {937 fn genArg(self: *FuncGen, inst: *Inst.Arg) !?*const llvm.Value {
697 const arg_val = self.args[self.arg_index];938 const arg_val = self.args[self.arg_index];
698 self.arg_index += 1;939 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));
701 _ = self.builder.buildStore(arg_val, ptr_val);942 _ = self.builder.buildStore(arg_val, ptr_val);
702 return self.builder.buildLoad(ptr_val, "");943 return self.builder.buildLoad(ptr_val, "");
703 }944 }
704945
705 fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value {946 fn genAlloc(self: *FuncGen, inst: *Inst.NoOp) !?*const llvm.Value {
706 // buildAlloca expects the pointee type, not the pointer type, so assert that947 // buildAlloca expects the pointee type, not the pointer type, so assert that
707 // a Payload.PointerSimple is passed to the alloc instruction.948 // a Payload.PointerSimple is passed to the alloc instruction.
708 const pointee_type = inst.base.ty.castPointer().?.data;949 const pointee_type = inst.base.ty.castPointer().?.data;
709950
710 // TODO: figure out a way to get the name of the var decl.951 // TODO: figure out a way to get the name of the var decl.
711 // TODO: set alignment and volatile952 // 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));
713 }954 }
714955
715 /// Use this instead of builder.buildAlloca, because this function makes sure to956 /// Use this instead of builder.buildAlloca, because this function makes sure to
716 /// put the alloca instruction at the top of the function!957 /// 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 {
718 const prev_block = self.builder.getInsertBlock();959 const prev_block = self.builder.getInsertBlock();
719 defer self.builder.positionBuilderAtEnd(prev_block);960 defer self.builder.positionBuilderAtEnd(prev_block);
720961
...@@ -736,240 +977,30 @@ pub const LLVMIRModule = struct {...@@ -736,240 +977,30 @@ pub const LLVMIRModule = struct {
736 return val;977 return val;
737 }978 }
738979
739 fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value {980 fn genStore(self: *FuncGen, inst: *Inst.BinOp) !?*const llvm.Value {
740 const val = try self.resolveInst(inst.rhs);981 const val = try self.resolveInst(inst.rhs);
741 const ptr = try self.resolveInst(inst.lhs);982 const ptr = try self.resolveInst(inst.lhs);
742 _ = self.builder.buildStore(val, ptr);983 _ = self.builder.buildStore(val, ptr);
743 return null;984 return null;
744 }985 }
745986
746 fn genLoad(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.Value {987 fn genLoad(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value {
747 const ptr_val = try self.resolveInst(inst.operand);988 const ptr_val = try self.resolveInst(inst.operand);
748 return self.builder.buildLoad(ptr_val, "");989 return self.builder.buildLoad(ptr_val, "");
749 }990 }
750991
751 fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.Value {992 fn genBreakpoint(self: *FuncGen, inst: *Inst.NoOp) !?*const llvm.Value {
752 const llvn_fn = self.getIntrinsic("llvm.debugtrap");993 const llvn_fn = self.getIntrinsic("llvm.debugtrap");
753 _ = self.builder.buildCall(llvn_fn, null, 0, "");994 _ = self.builder.buildCall(llvn_fn, null, 0, "");
754 return null;995 return null;
755 }996 }
756997
757 fn getIntrinsic(self: *LLVMIRModule, name: []const u8) *const llvm.Value {998 fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
758 const id = llvm.lookupIntrinsicID(name.ptr, name.len);999 const id = llvm.lookupIntrinsicID(name.ptr, name.len);
759 assert(id != 0);1000 assert(id != 0);
760 // TODO: add support for overload intrinsics by passing the prefix of the intrinsic1001 // TODO: add support for overload intrinsics by passing the prefix of the intrinsic
761 // to `lookupIntrinsicID` and then passing the correct types to1002 // to `lookupIntrinsicID` and then passing the correct types to
762 // `getIntrinsicDeclaration`1003 // `getIntrinsicDeclaration`
763 return self.llvm_module.getIntrinsicDeclaration(id, null, 0);1004 return self.llvmModule().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;
974 }1005 }
975};1006};
src/link/Coff.zig+9-9
...@@ -34,7 +34,7 @@ pub const base_tag: link.File.Tag = .coff;...@@ -34,7 +34,7 @@ pub const base_tag: link.File.Tag = .coff;
34const msdos_stub = @embedFile("msdos-stub.bin");34const msdos_stub = @embedFile("msdos-stub.bin");
3535
36/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.36/// 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
39base: link.File,39base: link.File,
40ptr_width: PtrWidth,40ptr_width: PtrWidth,
...@@ -129,7 +129,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -129,7 +129,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
129 const self = try createEmpty(allocator, options);129 const self = try createEmpty(allocator, options);
130 errdefer self.base.destroy();130 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);
133 return self;133 return self;
134 }134 }
135135
...@@ -413,7 +413,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Coff {...@@ -413,7 +413,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Coff {
413}413}
414414
415pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void {415pub fn allocateDeclIndexes(self: *Coff, decl: *Module.Decl) !void {
416 if (self.llvm_ir_module) |_| return;416 if (self.llvm_object) |_| return;
417417
418 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);418 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 {...@@ -660,7 +660,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
660 defer tracy.end();660 defer tracy.end();
661661
662 if (build_options.have_llvm)662 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
665 const typed_value = decl.typed_value.most_recent.typed_value;665 const typed_value = decl.typed_value.most_recent.typed_value;
666 if (typed_value.val.tag() == .extern_fn) {666 if (typed_value.val.tag() == .extern_fn) {
...@@ -720,7 +720,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {...@@ -720,7 +720,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
720}720}
721721
722pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {722pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
723 if (self.llvm_ir_module) |_| return;723 if (self.llvm_object) |_| return;
724724
725 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.725 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
726 self.freeTextBlock(&decl.link.coff);726 self.freeTextBlock(&decl.link.coff);
...@@ -728,7 +728,7 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {...@@ -728,7 +728,7 @@ pub fn freeDecl(self: *Coff, decl: *Module.Decl) void {
728}728}
729729
730pub fn updateDeclExports(self: *Coff, module: *Module, decl: *Module.Decl, exports: []const *Module.Export) !void {730pub 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
733 for (exports) |exp| {733 for (exports) |exp| {
734 if (exp.options.section) |section_name| {734 if (exp.options.section) |section_name| {
...@@ -771,7 +771,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {...@@ -771,7 +771,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
771 defer tracy.end();771 defer tracy.end();
772772
773 if (build_options.have_llvm)773 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
776 if (self.text_section_size_dirty) {776 if (self.text_section_size_dirty) {
777 // Write the new raw size in the .text header777 // Write the new raw size in the .text header
...@@ -1308,7 +1308,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {...@@ -1308,7 +1308,7 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
1308}1308}
13091309
1310pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {1310pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {
1311 assert(self.llvm_ir_module == null);1311 assert(self.llvm_object == null);
1312 return self.text_section_virtual_address + decl.link.coff.text_offset;1312 return self.text_section_virtual_address + decl.link.coff.text_offset;
1313}1313}
13141314
...@@ -1318,7 +1318,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v...@@ -1318,7 +1318,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
13181318
1319pub fn deinit(self: *Coff) void {1319pub fn deinit(self: *Coff) void {
1320 if (build_options.have_llvm)1320 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
1323 self.text_block_free_list.deinit(self.base.allocator);1323 self.text_block_free_list.deinit(self.base.allocator);
1324 self.offset_table.deinit(self.base.allocator);1324 self.offset_table.deinit(self.base.allocator);
src/link/Elf.zig+12-12
...@@ -35,7 +35,7 @@ base: File,...@@ -35,7 +35,7 @@ base: File,
35ptr_width: PtrWidth,35ptr_width: PtrWidth,
3636
37/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.37/// 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
40/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.40/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
41/// Same order as in the file.41/// Same order as in the file.
...@@ -232,7 +232,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -232,7 +232,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
232 const self = try createEmpty(allocator, options);232 const self = try createEmpty(allocator, options);
233 errdefer self.base.destroy();233 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);
236 return self;236 return self;
237 }237 }
238238
...@@ -299,7 +299,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {...@@ -299,7 +299,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
299299
300pub fn deinit(self: *Elf) void {300pub fn deinit(self: *Elf) void {
301 if (build_options.have_llvm)301 if (build_options.have_llvm)
302 if (self.llvm_ir_module) |ir_module|302 if (self.llvm_object) |ir_module|
303 ir_module.deinit(self.base.allocator);303 ir_module.deinit(self.base.allocator);
304304
305 self.sections.deinit(self.base.allocator);305 self.sections.deinit(self.base.allocator);
...@@ -318,7 +318,7 @@ pub fn deinit(self: *Elf) void {...@@ -318,7 +318,7 @@ pub fn deinit(self: *Elf) void {
318}318}
319319
320pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {320pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
321 assert(self.llvm_ir_module == null);321 assert(self.llvm_object == null);
322 assert(decl.link.elf.local_sym_index != 0);322 assert(decl.link.elf.local_sym_index != 0);
323 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;323 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;
324}324}
...@@ -438,7 +438,7 @@ fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {...@@ -438,7 +438,7 @@ fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
438}438}
439439
440pub fn populateMissingMetadata(self: *Elf) !void {440pub fn populateMissingMetadata(self: *Elf) !void {
441 assert(self.llvm_ir_module == null);441 assert(self.llvm_object == null);
442442
443 const small_ptr = switch (self.ptr_width) {443 const small_ptr = switch (self.ptr_width) {
444 .p32 => true,444 .p32 => true,
...@@ -745,7 +745,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -745,7 +745,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
745 defer tracy.end();745 defer tracy.end();
746746
747 if (build_options.have_llvm)747 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
750 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the750 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
751 // Zig source code.751 // Zig source code.
...@@ -2111,7 +2111,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2111,7 +2111,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2111}2111}
21122112
2113pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {2113pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
2114 if (self.llvm_ir_module) |_| return;2114 if (self.llvm_object) |_| return;
21152115
2116 if (decl.link.elf.local_sym_index != 0) return;2116 if (decl.link.elf.local_sym_index != 0) return;
21172117
...@@ -2149,7 +2149,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {...@@ -2149,7 +2149,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
2149}2149}
21502150
2151pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {2151pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2152 if (self.llvm_ir_module) |_| return;2152 if (self.llvm_object) |_| return;
21532153
2154 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.2154 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2155 self.freeTextBlock(&decl.link.elf);2155 self.freeTextBlock(&decl.link.elf);
...@@ -2189,7 +2189,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2189,7 +2189,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2189 defer tracy.end();2189 defer tracy.end();
21902190
2191 if (build_options.have_llvm)2191 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
2194 const typed_value = decl.typed_value.most_recent.typed_value;2194 const typed_value = decl.typed_value.most_recent.typed_value;
2195 if (typed_value.val.tag() == .extern_fn) {2195 if (typed_value.val.tag() == .extern_fn) {
...@@ -2673,7 +2673,7 @@ pub fn updateDeclExports(...@@ -2673,7 +2673,7 @@ pub fn updateDeclExports(
2673 decl: *Module.Decl,2673 decl: *Module.Decl,
2674 exports: []const *Module.Export,2674 exports: []const *Module.Export,
2675) !void {2675) !void {
2676 if (self.llvm_ir_module) |_| return;2676 if (self.llvm_object) |_| return;
26772677
2678 const tracy = trace(@src());2678 const tracy = trace(@src());
2679 defer tracy.end();2679 defer tracy.end();
...@@ -2748,7 +2748,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2748,7 +2748,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
2748 const tracy = trace(@src());2748 const tracy = trace(@src());
2749 defer tracy.end();2749 defer tracy.end();
27502750
2751 if (self.llvm_ir_module) |_| return;2751 if (self.llvm_object) |_| return;
27522752
2753 const tree = decl.container.file_scope.tree;2753 const tree = decl.container.file_scope.tree;
2754 const node_tags = tree.nodes.items(.tag);2754 const node_tags = tree.nodes.items(.tag);
...@@ -2773,7 +2773,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2773,7 +2773,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
2773}2773}
27742774
2775pub fn deleteExport(self: *Elf, exp: Export) void {2775pub fn deleteExport(self: *Elf, exp: Export) void {
2776 if (self.llvm_ir_module) |_| return;2776 if (self.llvm_object) |_| return;
27772777
2778 const sym_index = exp.sym_index orelse return;2778 const sym_index = exp.sym_index orelse return;
2779 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};2779 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};