| ... | ... | @@ -148,6 +148,9 @@ pub const LLVMIRModule = struct { |
| 148 | 148 | gpa: *Allocator, |
| 149 | 149 | err_msg: ?*Compilation.ErrorMsg = null, |
| 150 | 150 | |
| 151 | // TODO: The fields below should really move into a different struct, |
| 152 | // because they are only valid when generating a function |
| 153 | |
| 151 | 154 | /// This stores the LLVM values used in a function, such that they can be |
| 152 | 155 | /// referred to in other instructions. This table is cleared before every function is generated. |
| 153 | 156 | func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.Value) = .{}, |
| ... | ... | @@ -156,6 +159,11 @@ pub const LLVMIRModule = struct { |
| 156 | 159 | args: []*const llvm.Value = &[_]*const llvm.Value{}, |
| 157 | 160 | arg_index: usize = 0, |
| 158 | 161 | |
| 162 | entry_block: *const llvm.BasicBlock = undefined, |
| 163 | /// This fields stores the last alloca instruction, such that we can append more alloca instructions |
| 164 | /// to the top of the function. |
| 165 | latest_alloca_inst: ?*const llvm.Value = null, |
| 166 | |
| 159 | 167 | pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule { |
| 160 | 168 | const self = try allocator.create(LLVMIRModule); |
| 161 | 169 | errdefer allocator.destroy(self); |
| ... | ... | @@ -332,8 +340,9 @@ pub const LLVMIRModule = struct { |
| 332 | 340 | bb.deleteBasicBlock(); |
| 333 | 341 | } |
| 334 | 342 | |
| 335 | | const entry_block = llvm_func.appendBasicBlock("Entry"); |
| 336 | | self.builder.positionBuilderAtEnd(entry_block); |
| 343 | self.entry_block = llvm_func.appendBasicBlock("Entry"); |
| 344 | self.builder.positionBuilderAtEnd(self.entry_block); |
| 345 | self.latest_alloca_inst = null; |
| 337 | 346 | |
| 338 | 347 | const instructions = func.body.instructions; |
| 339 | 348 | for (instructions) |inst| { |
| ... | ... | @@ -476,7 +485,7 @@ pub const LLVMIRModule = struct { |
| 476 | 485 | const arg_val = self.args[self.arg_index]; |
| 477 | 486 | self.arg_index += 1; |
| 478 | 487 | |
| 479 | | const ptr_val = self.builder.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src), ""); |
| 488 | const ptr_val = self.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src)); |
| 480 | 489 | _ = self.builder.buildStore(arg_val, ptr_val); |
| 481 | 490 | return self.builder.buildLoad(ptr_val, ""); |
| 482 | 491 | } |
| ... | ... | @@ -488,7 +497,29 @@ pub const LLVMIRModule = struct { |
| 488 | 497 | |
| 489 | 498 | // TODO: figure out a way to get the name of the var decl. |
| 490 | 499 | // TODO: set alignment and volatile |
| 491 | | return self.builder.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src), ""); |
| 500 | return self.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src)); |
| 501 | } |
| 502 | |
| 503 | /// Use this instead of builder.buildAlloca, because this function makes sure to |
| 504 | /// put the alloca instruction at the top of the function! |
| 505 | fn buildAlloca(self: *LLVMIRModule, t: *const llvm.Type) *const llvm.Value { |
| 506 | if (self.latest_alloca_inst) |latest_alloc| { |
| 507 | // builder.positionBuilder adds it before the instruction, |
| 508 | // but we want to put it after the last alloca instruction. |
| 509 | self.builder.positionBuilder(self.entry_block, latest_alloc.getNextInstruction().?); |
| 510 | } else { |
| 511 | // There might have been other instructions emitted before the |
| 512 | // first alloca has been generated. However the alloca should still |
| 513 | // be first in the function. |
| 514 | if (self.entry_block.getFirstInstruction()) |first_inst| { |
| 515 | self.builder.positionBuilder(self.entry_block, first_inst); |
| 516 | } |
| 517 | } |
| 518 | defer self.builder.positionBuilderAtEnd(self.entry_block); |
| 519 | |
| 520 | const val = self.builder.buildAlloca(t, ""); |
| 521 | self.latest_alloca_inst = val; |
| 522 | return val; |
| 492 | 523 | } |
| 493 | 524 | |
| 494 | 525 | fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { |