From 4f5e065d6ec10cb27589995bf5d6390647f783f2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 13 Jul 2020 20:47:47 -0700 Subject: [PATCH] stage2: add ZIR support for BoolNot --- src-self-hosted/Module.zig | 12 ++++++++++++ src-self-hosted/codegen.zig | 7 +++++++ src-self-hosted/ir.zig | 10 ++++++++++ src-self-hosted/zir.zig | 30 ++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 993313d947..1ed655a055 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2566,6 +2566,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In .condbr => return self.analyzeInstCondBr(scope, old_inst.cast(zir.Inst.CondBr).?), .isnull => return self.analyzeInstIsNull(scope, old_inst.cast(zir.Inst.IsNull).?), .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.cast(zir.Inst.IsNonNull).?), + .boolnot => return self.analyzeInstBoolNot(scope, old_inst.cast(zir.Inst.BoolNot).?), } } @@ -3243,6 +3244,17 @@ fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *zir.Inst.Cmp) InnerError! return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{}); } +fn analyzeInstBoolNot(self: *Module, scope: *Scope, inst: *zir.Inst.BoolNot) InnerError!*Inst { + const uncasted_operand = try self.resolveInst(scope, inst.positionals.operand); + const bool_type = Type.initTag(.bool); + const operand = try self.coerce(scope, bool_type, uncasted_operand); + if (try self.resolveDefinedValue(scope, operand)) |val| { + 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 }); +} + fn analyzeInstIsNull(self: *Module, scope: *Scope, inst: *zir.Inst.IsNull) InnerError!*Inst { const operand = try self.resolveInst(scope, inst.positionals.operand); return self.analyzeIsNull(scope, inst.base.src, operand, true); diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 143ad787b7..731c039d9c 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -407,6 +407,13 @@ const Function = struct { .retvoid => return self.genRetVoid(inst.cast(ir.Inst.RetVoid).?, arch), .sub => return self.genSub(inst.cast(ir.Inst.Sub).?, arch), .unreach => return MCValue{ .unreach = {} }, + .not => return self.genNot(inst.cast(ir.Inst.Not).?, arch), + } + } + + fn genNot(self: *Function, inst: *ir.Inst.Not, comptime arch: std.Target.Cpu.Arch) !MCValue { + switch (arch) { + else => return self.fail(inst.base.src, "TODO implement NOT for {}", .{self.target.cpu.arch}), } } diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 74da3430a7..6c0c807468 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -60,6 +60,7 @@ pub const Inst = struct { retvoid, sub, unreach, + not, }; pub fn cast(base: *Inst, comptime T: type) ?*T { @@ -194,6 +195,15 @@ pub const Inst = struct { false_death_count: u32 = 0, }; + pub const Not = struct { + pub const base_tag = Tag.not; + + base: Inst, + args: struct { + operand: *Inst, + }, + }; + pub const Constant = struct { pub const base_tag = Tag.constant; base: Inst, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 0dfbdd20a0..45ced54255 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -56,6 +56,7 @@ pub const Inst = struct { declval, /// Same as declval but the parameter is a `*Module.Decl` rather than a name. declval_in_module, + boolnot, /// String Literal. Makes an anonymous Decl and then takes a pointer to it. str, int, @@ -115,6 +116,7 @@ pub const Inst = struct { .cmp, .isnull, .isnonnull, + .boolnot, => false, .condbr, @@ -143,6 +145,7 @@ pub const Inst = struct { .declval_in_module => DeclValInModule, .compileerror => CompileError, .@"const" => Const, + .boolnot => BoolNot, .str => Str, .int => Int, .inttype => IntType, @@ -299,6 +302,16 @@ pub const Inst = struct { kw_args: struct {}, }; + pub const BoolNot = struct { + pub const base_tag = Tag.boolnot; + base: Inst, + + positionals: struct { + operand: *Inst, + }, + kw_args: struct {}, + }; + pub const Str = struct { pub const base_tag = Tag.str; base: Inst, @@ -762,6 +775,7 @@ const Writer = struct { .declval_in_module => return self.writeInstToStreamGeneric(stream, .declval_in_module, inst), .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, inst), .@"const" => return self.writeInstToStreamGeneric(stream, .@"const", inst), + .boolnot => return self.writeInstToStreamGeneric(stream, .boolnot, inst), .str => return self.writeInstToStreamGeneric(stream, .str, inst), .int => return self.writeInstToStreamGeneric(stream, .int, inst), .inttype => return self.writeInstToStreamGeneric(stream, .inttype, inst), @@ -1658,6 +1672,22 @@ const EmitZIR = struct { }; for (body.instructions) |inst| { const new_inst = switch (inst.tag) { + .not => blk: { + const old_inst = inst.cast(ir.Inst.Not).?; + assert(inst.ty.zigTypeTag() == .Bool); + const new_inst = try self.arena.allocator.create(Inst.BoolNot); + new_inst.* = .{ + .base = .{ + .src = inst.src, + .tag = Inst.BoolNot.base_tag, + }, + .positionals = .{ + .operand = try self.resolveInst(new_body, old_inst.args.operand), + }, + .kw_args = .{}, + }; + break :blk &new_inst.base; + }, .add => blk: { const old_inst = inst.cast(ir.Inst.Add).?; const new_inst = try self.arena.allocator.create(Inst.Add);