AstGen: encode negativity into float literals

rather than a separate negation instruction. closes #11545
This commit is contained in:
Andrew Kelley 2022-04-28 17:11:42 -07:00
parent 18d6523888
commit d8e99164d3

View File

@ -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,