authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-13 12:02:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-13 12:02:55-07:00
log2a701a92c403dda47a61848a38998b474442d805
tree52f69e339df727aae1a29a6009d3a4c0860e181c
parentfc302f00a9de5de0490f4a66720e75946763c695

stage2: LLVM backend: fix crash adding alloca

The logic for `buildAlloca` had a null deref when the latest alloca was the last instruction in the entry block. Now the logic is simplified to always insert alloca instructions first before all other instructions. There is no longer a need to track `entry_block` or `latest_alloca_inst`; these fields are deleted frem `FuncGen`.

1 files changed, 8 insertions(+), 22 deletions(-)

src/codegen/llvm.zig+8-22
......@@ -448,8 +448,6 @@ pub const Object = struct {
448448 .args = args.toOwnedSlice(),
449449 .arg_index = 0,
450450 .func_inst_table = .{},
451 .entry_block = entry_block,
452 .latest_alloca_inst = null,
453451 .llvm_func = llvm_func,
454452 .blocks = .{},
455453 .single_threaded = module.comp.bin_file.options.single_threaded,
......@@ -1285,11 +1283,6 @@ pub const FuncGen = struct {
12851283 args: []*const llvm.Value,
12861284 arg_index: usize,
12871285
1288 entry_block: *const llvm.BasicBlock,
1289 /// This fields stores the last alloca instruction, such that we can append
1290 /// more alloca instructions to the top of the function.
1291 latest_alloca_inst: ?*const llvm.Value,
1292
12931286 llvm_func: *const llvm.Value,
12941287
12951288 /// This data structure is used to implement breaking to blocks.
......@@ -2658,26 +2651,19 @@ pub const FuncGen = struct {
26582651
26592652 /// Use this instead of builder.buildAlloca, because this function makes sure to
26602653 /// put the alloca instruction at the top of the function!
2661 fn buildAlloca(self: *FuncGen, t: *const llvm.Type) *const llvm.Value {
2654 fn buildAlloca(self: *FuncGen, llvm_ty: *const llvm.Type) *const llvm.Value {
26622655 const prev_block = self.builder.getInsertBlock();
2663 defer self.builder.positionBuilderAtEnd(prev_block);
26642656
2665 if (self.latest_alloca_inst) |latest_alloc| {
2666 // builder.positionBuilder adds it before the instruction,
2667 // but we want to put it after the last alloca instruction.
2668 self.builder.positionBuilder(self.entry_block, latest_alloc.getNextInstruction().?);
2657 const entry_block = self.llvm_func.getFirstBasicBlock().?;
2658 if (entry_block.getFirstInstruction()) |first_inst| {
2659 self.builder.positionBuilder(entry_block, first_inst);
26692660 } else {
2670 // There might have been other instructions emitted before the
2671 // first alloca has been generated. However the alloca should still
2672 // be first in the function.
2673 if (self.entry_block.getFirstInstruction()) |first_inst| {
2674 self.builder.positionBuilder(self.entry_block, first_inst);
2675 }
2661 self.builder.positionBuilderAtEnd(entry_block);
26762662 }
26772663
2678 const val = self.builder.buildAlloca(t, "");
2679 self.latest_alloca_inst = val;
2680 return val;
2664 const alloca = self.builder.buildAlloca(llvm_ty, "");
2665 self.builder.positionBuilderAtEnd(prev_block);
2666 return alloca;
26812667 }
26822668
26832669 fn airStore(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {