Commit 4f5e065d6e

Andrew Kelley <andrew@ziglang.org>
2020-07-14 05:47:47
stage2: add ZIR support for BoolNot
1 parent 14cef9d
Changed files (4)
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}),
         }
     }
 
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,
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);
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);