Commit d8e99164d3

Andrew Kelley <andrew@ziglang.org>
2022-04-29 02:11:42
AstGen: encode negativity into float literals
rather than a separate negation instruction. closes #11545
1 parent 18d6523
Changed files (1)
src/AstGen.zig
@@ -694,11 +694,11 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
         .bool_and => return boolBinOp(gz, scope, rl, node, .bool_br_and),
         .bool_or  => return boolBinOp(gz, scope, rl, node, .bool_br_or),
 
-        .bool_not => return boolNot(gz, scope, rl, node),
-        .bit_not  => return bitNot(gz, scope, rl, node),
+        .bool_not => return simpleUnOp(gz, scope, rl, node, bool_rl, node_datas[node].lhs, .bool_not),
+        .bit_not  => return simpleUnOp(gz, scope, rl, node, .none, node_datas[node].lhs, .bit_not),
 
-        .negation      => return negation(gz, scope, rl, node, .negate),
-        .negation_wrap => return negation(gz, scope, rl, node, .negate_wrap),
+        .negation      => return   negation(gz, scope, rl, node),
+        .negation_wrap => return simpleUnOp(gz, scope, rl, node, .none, node_datas[node].lhs, .negate_wrap),
 
         .identifier => return identifier(gz, scope, rl, node),
 
@@ -748,7 +748,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
         },
         .@"return" => return ret(gz, scope, node),
         .field_access => return fieldAccess(gz, scope, rl, node),
-        .float_literal => return floatLiteral(gz, rl, node),
+        .float_literal => return floatLiteral(gz, rl, node, .positive),
 
         .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)),
         .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)),
@@ -3029,42 +3029,6 @@ fn assignShiftSat(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerE
     _ = try gz.addBin(.store, lhs_ptr, result);
 }
 
-fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
-    const astgen = gz.astgen;
-    const tree = astgen.tree;
-    const node_datas = tree.nodes.items(.data);
-
-    const operand = try expr(gz, scope, bool_rl, node_datas[node].lhs);
-    const result = try gz.addUnNode(.bool_not, operand, node);
-    return rvalue(gz, rl, result, node);
-}
-
-fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
-    const astgen = gz.astgen;
-    const tree = astgen.tree;
-    const node_datas = tree.nodes.items(.data);
-
-    const operand = try expr(gz, scope, .none, node_datas[node].lhs);
-    const result = try gz.addUnNode(.bit_not, operand, node);
-    return rvalue(gz, rl, result, node);
-}
-
-fn negation(
-    gz: *GenZir,
-    scope: *Scope,
-    rl: ResultLoc,
-    node: Ast.Node.Index,
-    tag: Zir.Inst.Tag,
-) InnerError!Zir.Inst.Ref {
-    const astgen = gz.astgen;
-    const tree = astgen.tree;
-    const node_datas = tree.nodes.items(.data);
-
-    const operand = try expr(gz, scope, .none, node_datas[node].lhs);
-    const result = try gz.addUnNode(tag, operand, node);
-    return rvalue(gz, rl, result, node);
-}
-
 fn ptrType(
     gz: *GenZir,
     scope: *Scope,
@@ -6728,14 +6692,16 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Z
     return rvalue(gz, rl, result, node);
 }
 
-fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref {
+const Sign = enum { negative, positive };
+
+fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index, sign: Sign) InnerError!Zir.Inst.Ref {
     const astgen = gz.astgen;
     const tree = astgen.tree;
     const main_tokens = tree.nodes.items(.main_token);
 
     const main_token = main_tokens[node];
     const bytes = tree.tokenSlice(main_token);
-    const float_number: f128 = if (bytes.len > 2 and bytes[1] == 'x') hex: {
+    const unsigned_float_number: f128 = if (bytes.len > 2 and bytes[1] == 'x') hex: {
         assert(bytes[0] == '0'); // validated by tokenizer
         break :hex std.fmt.parseHexFloat(f128, bytes) catch |err| switch (err) {
             error.InvalidCharacter => unreachable, // validated by tokenizer
@@ -6744,6 +6710,10 @@ fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir
     } else std.fmt.parseFloat(f128, bytes) catch |err| switch (err) {
         error.InvalidCharacter => unreachable, // validated by tokenizer
     };
+    const float_number = switch (sign) {
+        .negative => -unsigned_float_number,
+        .positive => unsigned_float_number,
+    };
     // If the value fits into a f64 without losing any precision, store it that way.
     @setFloatMode(.Strict);
     const smaller_float = @floatCast(f64, float_number);
@@ -7651,6 +7621,29 @@ fn simpleUnOp(
     return rvalue(gz, rl, result, node);
 }
 
+fn negation(
+    gz: *GenZir,
+    scope: *Scope,
+    rl: ResultLoc,
+    node: Ast.Node.Index,
+) InnerError!Zir.Inst.Ref {
+    const astgen = gz.astgen;
+    const tree = astgen.tree;
+    const node_tags = tree.nodes.items(.tag);
+    const node_datas = tree.nodes.items(.data);
+
+    // Check for float literal as the sub-expression because we want to preserve
+    // its negativity rather than having it go through comptime subtraction.
+    const operand_node = node_datas[node].lhs;
+    if (node_tags[operand_node] == .float_literal) {
+        return floatLiteral(gz, rl, operand_node, .negative);
+    }
+
+    const operand = try expr(gz, scope, .none, operand_node);
+    const result = try gz.addUnNode(.negate, operand, node);
+    return rvalue(gz, rl, result, node);
+}
+
 fn cmpxchg(
     gz: *GenZir,
     scope: *Scope,