From ef91b11295a549a8173c488d9fd5b3f69b419829 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 20 Jul 2020 13:11:07 -0700 Subject: stage2: register allocator processes operand deaths also rework the IR data structures --- src-self-hosted/Module.zig | 223 ++++++++++++++++++++++++++++++++------------- 1 file changed, 162 insertions(+), 61 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 72e5f6cd63..25136b5289 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1349,8 +1349,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Module.Body) !Type { try self.analyzeBody(&block_scope.base, body); for (block_scope.instructions.items) |inst| { - if (inst.cast(Inst.Ret)) |ret| { - const val = try self.resolveConstValue(&block_scope.base, ret.args.operand); + if (inst.castTag(.ret)) |ret| { + const val = try self.resolveConstValue(&block_scope.base, ret.operand); return val.toType(); } else { return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); @@ -1938,16 +1938,132 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const }; } -fn addNewInstArgs( +fn addNoOp( self: *Module, block: *Scope.Block, src: usize, ty: Type, - comptime T: type, - args: Inst.Args(T), + comptime tag: Inst.Tag, +) !*Inst { + const inst = try block.arena.create(tag.Type()); + inst.* = .{ + .base = .{ + .tag = tag, + .ty = ty, + .src = src, + }, + }; + try block.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + +fn addUnOp( + self: *Module, + block: *Scope.Block, + src: usize, + ty: Type, + tag: Inst.Tag, + operand: *Inst, +) !*Inst { + const inst = try block.arena.create(Inst.UnOp); + inst.* = .{ + .base = .{ + .tag = tag, + .ty = ty, + .src = src, + }, + .operand = operand, + }; + try block.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + +fn addBinOp( + self: *Module, + block: *Scope.Block, + src: usize, + ty: Type, + tag: Inst.Tag, + lhs: *Inst, + rhs: *Inst, +) !*Inst { + const inst = try block.arena.create(Inst.BinOp); + inst.* = .{ + .base = .{ + .tag = tag, + .ty = ty, + .src = src, + }, + .lhs = lhs, + .rhs = rhs, + }; + try block.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + +fn addBr( + self: *Module, + scope_block: *Scope.Block, + src: usize, + target_block: *Inst.Block, + operand: *Inst, +) !*Inst { + const inst = try scope_block.arena.create(Inst.Br); + inst.* = .{ + .base = .{ + .tag = .br, + .ty = Type.initTag(.noreturn), + .src = src, + }, + .operand = operand, + .block = target_block, + }; + try scope_block.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + +fn addCondBr( + self: *Module, + block: *Scope.Block, + src: usize, + condition: *Inst, + then_body: ir.Body, + else_body: ir.Body, ) !*Inst { - const inst = try self.addNewInst(block, src, ty, T); - inst.args = args; + const inst = try block.arena.create(Inst.CondBr); + inst.* = .{ + .base = .{ + .tag = .condbr, + .ty = Type.initTag(.noreturn), + .src = src, + }, + .condition = condition, + .then_body = then_body, + .else_body = else_body, + }; + try block.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + +fn addCall( + self: *Module, + block: *Scope.Block, + src: usize, + ty: Type, + func: *Inst, + args: []const *Inst, +) !*Inst { + const inst = try block.arena.create(Inst.Call); + inst.* = .{ + .base = .{ + .tag = .call, + .ty = ty, + .src = src, + }, + .func = func, + .args = args, + }; + try block.instructions.append(self.gpa, &inst.base); return &inst.base; } @@ -2017,7 +2133,6 @@ fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime .ty = ty, .src = src, }, - .args = undefined, }; try block.instructions.append(self.gpa, &inst.base); return inst; @@ -2269,7 +2384,7 @@ fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError! }); } const param_type = fn_ty.fnParamType(param_index); - return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, {}); + return self.addNoOp(b, inst.base.src, param_type, .arg); } fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst { @@ -2285,7 +2400,7 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr .ty = undefined, // Set after analysis. .src = inst.base.src, }, - .args = undefined, + .body = undefined, }; var child_block: Scope.Block = .{ @@ -2316,13 +2431,13 @@ fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerEr // to emit a jump instruction to after the block when it encounters the break. try parent_block.instructions.append(self.gpa, &block_inst.base); block_inst.base.ty = try self.resolvePeerTypes(scope, label.results.items); - block_inst.args.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) }; + block_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) }; return &block_inst.base; } fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst { const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, {}); + return self.addNoOp(b, inst.base.src, Type.initTag(.void), .breakpoint); } fn analyzeInstBreak(self: *Module, scope: *Scope, inst: *zir.Inst.Break) InnerError!*Inst { @@ -2350,10 +2465,7 @@ fn analyzeBreak( if (label.zir_block == zir_block) { try label.results.append(self.gpa, operand); const b = try self.requireRuntimeBlock(scope, src); - return self.addNewInstArgs(b, src, Type.initTag(.noreturn), Inst.Br, .{ - .block = label.block_inst, - .operand = operand, - }); + return self.addBr(b, src, label.block_inst, operand); } } opt_block = block.parent; @@ -2484,10 +2596,7 @@ fn analyzeInstCall(self: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerErro } const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, .{ - .func = func, - .args = casted_args, - }); + return self.addCall(b, inst.base.src, Type.initTag(.void), func, casted_args); } fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst { @@ -2570,14 +2679,14 @@ fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.As) InnerError!*Ins } fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToInt) InnerError!*Inst { - const ptr = try self.resolveInst(scope, ptrtoint.positionals.ptr); + const ptr = try self.resolveInst(scope, ptrtoint.positionals.operand); if (ptr.ty.zigTypeTag() != .Pointer) { - return self.fail(scope, ptrtoint.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}); + return self.fail(scope, ptrtoint.positionals.operand.src, "expected pointer, found '{}'", .{ptr.ty}); } // TODO handle known-pointer-address const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src); const ty = Type.initTag(.usize); - return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, .{ .ptr = ptr }); + return self.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr); } fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst { @@ -2734,10 +2843,7 @@ fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *zir.Inst.Add) InnerError! } const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, lhs.ty, Inst.Add, .{ - .lhs = lhs, - .rhs = rhs, - }); + return self.addBinOp(b, inst.base.src, lhs.ty, .add, lhs, rhs); } return self.fail(scope, inst.base.src, "TODO analyze add for {} + {}", .{ lhs.ty.zigTypeTag(), rhs.ty.zigTypeTag() }); } @@ -2783,14 +2889,22 @@ fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerEr } const b = try self.requireRuntimeBlock(scope, assembly.base.src); - return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, .{ + const inst = try b.arena.create(Inst.Assembly); + inst.* = .{ + .base = .{ + .tag = .assembly, + .ty = return_type, + .src = assembly.base.src, + }, .asm_source = asm_source, .is_volatile = assembly.kw_args.@"volatile", .output = output, .inputs = inputs, .clobbers = clobbers, .args = args, - }); + }; + try b.instructions.append(self.gpa, &inst.base); + return &inst.base; } fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError!*Inst { @@ -2818,15 +2932,12 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError! return self.constBool(scope, inst.base.src, if (op == .eq) is_null else !is_null); } const b = try self.requireRuntimeBlock(scope, inst.base.src); - switch (op) { - .eq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNull, .{ - .operand = opt_operand, - }), - .neq => return self.addNewInstArgs(b, inst.base.src, Type.initTag(.bool), Inst.IsNonNull, .{ - .operand = opt_operand, - }), + const inst_tag: Inst.Tag = switch (op) { + .eq => .isnull, + .neq => .isnonnull, else => unreachable, - } + }; + return self.addUnOp(b, inst.base.src, Type.initTag(.bool), inst_tag, opt_operand); } else if (is_equality_cmp and ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr()))) { @@ -2861,7 +2972,7 @@ fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.BoolNot) Inn return self.constBool(scope, inst.base.src, !val.toBool()); } const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, bool_type, Inst.Not, .{ .operand = operand }); + return self.addUnOp(b, inst.base.src, bool_type, .not, operand); } fn analyzeInstIsNull(self: *Module, scope: *Scope, inst: *zir.Inst.IsNull) InnerError!*Inst { @@ -2879,7 +2990,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner const cond = try self.coerce(scope, Type.initTag(.bool), uncasted_cond); if (try self.resolveDefinedValue(scope, cond)) |cond_val| { - const body = if (cond_val.toBool()) &inst.positionals.true_body else &inst.positionals.false_body; + const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body; try self.analyzeBody(scope, body.*); return self.constVoid(scope, inst.base.src); } @@ -2894,7 +3005,7 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner .arena = parent_block.arena, }; defer true_block.instructions.deinit(self.gpa); - try self.analyzeBody(&true_block.base, inst.positionals.true_body); + try self.analyzeBody(&true_block.base, inst.positionals.then_body); var false_block: Scope.Block = .{ .parent = parent_block, @@ -2904,13 +3015,11 @@ fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *zir.Inst.CondBr) Inner .arena = parent_block.arena, }; defer false_block.instructions.deinit(self.gpa); - try self.analyzeBody(&false_block.base, inst.positionals.false_body); + try self.analyzeBody(&false_block.base, inst.positionals.else_body); - return self.addNewInstArgs(parent_block, inst.base.src, Type.initTag(.noreturn), Inst.CondBr, Inst.Args(Inst.CondBr){ - .condition = cond, - .true_body = .{ .instructions = try scope.arena().dupe(*Inst, true_block.instructions.items) }, - .false_body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) }, - }); + const then_body: ir.Body = .{ .instructions = try scope.arena().dupe(*Inst, true_block.instructions.items) }; + const else_body: ir.Body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) }; + return self.addCondBr(parent_block, inst.base.src, cond, then_body, else_body); } fn wantSafety(self: *Module, scope: *Scope) bool { @@ -2926,20 +3035,20 @@ fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *zir.Inst.Unrea const b = try self.requireRuntimeBlock(scope, unreach.base.src); if (self.wantSafety(scope)) { // TODO Once we have a panic function to call, call it here instead of this. - _ = try self.addNewInstArgs(b, unreach.base.src, Type.initTag(.void), Inst.Breakpoint, {}); + _ = try self.addNoOp(b, unreach.base.src, Type.initTag(.void), .breakpoint); } - return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); + return self.addNoOp(b, unreach.base.src, Type.initTag(.noreturn), .unreach); } fn analyzeInstRet(self: *Module, scope: *Scope, inst: *zir.Inst.Return) InnerError!*Inst { const operand = try self.resolveInst(scope, inst.positionals.operand); const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, .{ .operand = operand }); + return self.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand); } fn analyzeInstRetVoid(self: *Module, scope: *Scope, inst: *zir.Inst.ReturnVoid) InnerError!*Inst { const b = try self.requireRuntimeBlock(scope, inst.base.src); - return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.RetVoid, {}); + return self.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid); } fn analyzeBody(self: *Module, scope: *Scope, body: zir.Module.Body) !void { @@ -3027,11 +3136,7 @@ fn cmpNumeric( }; const casted_lhs = try self.coerce(scope, dest_type, lhs); const casted_rhs = try self.coerce(scope, dest_type, rhs); - return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, .{ - .lhs = casted_lhs, - .rhs = casted_rhs, - .op = op, - }); + return self.addBinOp(b, src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs); } // For mixed unsigned integer sizes, implicit cast both operands to the larger integer. // For mixed signed and unsigned integers, implicit cast both operands to a signed @@ -3131,11 +3236,7 @@ fn cmpNumeric( const casted_lhs = try self.coerce(scope, dest_type, lhs); const casted_rhs = try self.coerce(scope, dest_type, rhs); - return self.addNewInstArgs(b, src, Type.initTag(.bool), Inst.Cmp, .{ - .lhs = casted_lhs, - .rhs = casted_rhs, - .op = op, - }); + return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs); } fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { @@ -3236,7 +3337,7 @@ fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { } // TODO validate the type size and other compile errors const b = try self.requireRuntimeBlock(scope, inst.src); - return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, .{ .operand = inst }); + return self.addUnOp(b, inst.src, dest_type, .bitcast, inst); } fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst { -- cgit v1.2.3