diff --git a/src/llvm_backend.zig b/src/llvm_backend.zig index cd1d7029b4..2e7615d6ed 100644 --- a/src/llvm_backend.zig +++ b/src/llvm_backend.zig @@ -148,6 +148,9 @@ pub const LLVMIRModule = struct { gpa: *Allocator, err_msg: ?*Compilation.ErrorMsg = null, + // TODO: The fields below should really move into a different struct, + // because they are only valid when generating a function + /// This stores the LLVM values used in a function, such that they can be /// referred to in other instructions. This table is cleared before every function is generated. func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.Value) = .{}, @@ -156,6 +159,11 @@ pub const LLVMIRModule = struct { args: []*const llvm.Value = &[_]*const llvm.Value{}, arg_index: usize = 0, + entry_block: *const llvm.BasicBlock = undefined, + /// This fields stores the last alloca instruction, such that we can append more alloca instructions + /// to the top of the function. + latest_alloca_inst: ?*const llvm.Value = null, + pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule { const self = try allocator.create(LLVMIRModule); errdefer allocator.destroy(self); @@ -332,8 +340,9 @@ pub const LLVMIRModule = struct { bb.deleteBasicBlock(); } - const entry_block = llvm_func.appendBasicBlock("Entry"); - self.builder.positionBuilderAtEnd(entry_block); + self.entry_block = llvm_func.appendBasicBlock("Entry"); + self.builder.positionBuilderAtEnd(self.entry_block); + self.latest_alloca_inst = null; const instructions = func.body.instructions; for (instructions) |inst| { @@ -476,7 +485,7 @@ pub const LLVMIRModule = struct { const arg_val = self.args[self.arg_index]; self.arg_index += 1; - const ptr_val = self.builder.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src), ""); + const ptr_val = self.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src)); _ = self.builder.buildStore(arg_val, ptr_val); return self.builder.buildLoad(ptr_val, ""); } @@ -488,7 +497,29 @@ pub const LLVMIRModule = struct { // TODO: figure out a way to get the name of the var decl. // TODO: set alignment and volatile - return self.builder.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src), ""); + return self.buildAlloca(try self.getLLVMType(pointee_type, inst.base.src)); + } + + /// Use this instead of builder.buildAlloca, because this function makes sure to + /// put the alloca instruction at the top of the function! + fn buildAlloca(self: *LLVMIRModule, t: *const llvm.Type) *const llvm.Value { + if (self.latest_alloca_inst) |latest_alloc| { + // builder.positionBuilder adds it before the instruction, + // but we want to put it after the last alloca instruction. + self.builder.positionBuilder(self.entry_block, latest_alloc.getNextInstruction().?); + } else { + // There might have been other instructions emitted before the + // first alloca has been generated. However the alloca should still + // be first in the function. + if (self.entry_block.getFirstInstruction()) |first_inst| { + self.builder.positionBuilder(self.entry_block, first_inst); + } + } + defer self.builder.positionBuilderAtEnd(self.entry_block); + + const val = self.builder.buildAlloca(t, ""); + self.latest_alloca_inst = val; + return val; } fn genStore(self: *LLVMIRModule, inst: *Inst.BinOp) !?*const llvm.Value { diff --git a/src/llvm_bindings.zig b/src/llvm_bindings.zig index 690c28e1a0..4a3c37cef7 100644 --- a/src/llvm_bindings.zig +++ b/src/llvm_bindings.zig @@ -17,6 +17,9 @@ pub const Value = opaque { pub const getFirstBasicBlock = LLVMGetFirstBasicBlock; extern fn LLVMGetFirstBasicBlock(Fn: *const Value) ?*const BasicBlock; + pub const getNextInstruction = LLVMGetNextInstruction; + extern fn LLVMGetNextInstruction(Inst: *const Value) ?*const Value; + // Helper functions // TODO: Do we want to put these functions here? It allows for convienient function calls // on Value: llvm_fn.addFnAttr("noreturn") @@ -138,6 +141,9 @@ pub const Builder = opaque { pub const disposeBuilder = LLVMDisposeBuilder; extern fn LLVMDisposeBuilder(Builder: *const Builder) void; + pub const positionBuilder = LLVMPositionBuilder; + extern fn LLVMPositionBuilder(Builder: *const Builder, Block: *const BasicBlock, Instr: *const Value) void; + pub const positionBuilderAtEnd = LLVMPositionBuilderAtEnd; extern fn LLVMPositionBuilderAtEnd(Builder: *const Builder, Block: *const BasicBlock) void; @@ -196,6 +202,9 @@ pub const Builder = opaque { pub const BasicBlock = opaque { pub const deleteBasicBlock = LLVMDeleteBasicBlock; extern fn LLVMDeleteBasicBlock(BB: *const BasicBlock) void; + + pub const getFirstInstruction = LLVMGetFirstInstruction; + extern fn LLVMGetFirstInstruction(BB: *const BasicBlock) ?*const Value; }; pub const TargetMachine = opaque {