authorgravatar for twostepted@gmail.comTravis Staloch <twostepted@gmail.com> 2021-09-14 18:34:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-28 17:04:18-07:00
logbaaec94fe427efad4fe46ee3ffde53184cbd0ae9
treea2fca56ce6507b78e3f2900565766e713ed52dd5
parentcd8d8add9153b17b4579c2e8951ac3f3f42e1bcd

sat-arithmetic: create Sema.analyzeSatArithmetic

- similar to Sema.analyzeArithmetic but uses accepts Zir.Inst.Extended.InstData - missing support for Pointer types and comptime arithmetic

2 files changed, 96 insertions(+), 20 deletions(-)

src/AstGen.zig+12-14
...@@ -535,7 +535,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -535,7 +535,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
535 return rvalue(gz, rl, .void_value, node);535 return rvalue(gz, rl, .void_value, node);
536 },536 },
537 .assign_bit_shift_left_sat => {537 .assign_bit_shift_left_sat => {
538 try assignBinOpExt(gz, scope, node, .shl_with_saturation, Zir.Inst.SaturatingArithmetic);538 try assignOpExt(gz, scope, node, .shl_with_saturation, Zir.Inst.SaturatingArithmetic);
539 return rvalue(gz, rl, .void_value, node);539 return rvalue(gz, rl, .void_value, node);
540 },540 },
541 .assign_bit_shift_right => {541 .assign_bit_shift_right => {
...@@ -568,7 +568,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -568,7 +568,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
568 return rvalue(gz, rl, .void_value, node);568 return rvalue(gz, rl, .void_value, node);
569 },569 },
570 .assign_sub_sat => {570 .assign_sub_sat => {
571 try assignBinOpExt(gz, scope, node, .sub_with_saturation, Zir.Inst.SaturatingArithmetic);571 try assignOpExt(gz, scope, node, .sub_with_saturation, Zir.Inst.SaturatingArithmetic);
572 return rvalue(gz, rl, .void_value, node);572 return rvalue(gz, rl, .void_value, node);
573 },573 },
574 .assign_mod => {574 .assign_mod => {
...@@ -584,7 +584,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -584,7 +584,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
584 return rvalue(gz, rl, .void_value, node);584 return rvalue(gz, rl, .void_value, node);
585 },585 },
586 .assign_add_sat => {586 .assign_add_sat => {
587 try assignBinOpExt(gz, scope, node, .add_with_saturation, Zir.Inst.SaturatingArithmetic);587 try assignOpExt(gz, scope, node, .add_with_saturation, Zir.Inst.SaturatingArithmetic);
588 return rvalue(gz, rl, .void_value, node);588 return rvalue(gz, rl, .void_value, node);
589 },589 },
590 .assign_mul => {590 .assign_mul => {
...@@ -596,26 +596,28 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr...@@ -596,26 +596,28 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
596 return rvalue(gz, rl, .void_value, node);596 return rvalue(gz, rl, .void_value, node);
597 },597 },
598 .assign_mul_sat => {598 .assign_mul_sat => {
599 try assignBinOpExt(gz, scope, node, .mul_with_saturation, Zir.Inst.SaturatingArithmetic);599 try assignOpExt(gz, scope, node, .mul_with_saturation, Zir.Inst.SaturatingArithmetic);
600 return rvalue(gz, rl, .void_value, node);600 return rvalue(gz, rl, .void_value, node);
601 },601 },
602602
603 // zig fmt: off603 // zig fmt: off
604 .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),604 .bit_shift_left => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl),
605 .bit_shift_left_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl_with_saturation, Zir.Inst.SaturatingArithmetic),
606 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),605 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
607606
608 .add => return simpleBinOp(gz, scope, rl, node, .add),607 .add => return simpleBinOp(gz, scope, rl, node, .add),
609 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),608 .add_wrap => return simpleBinOp(gz, scope, rl, node, .addwrap),
610 .add_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .add_with_saturation, Zir.Inst.SaturatingArithmetic),
611 .sub => return simpleBinOp(gz, scope, rl, node, .sub),609 .sub => return simpleBinOp(gz, scope, rl, node, .sub),
612 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),610 .sub_wrap => return simpleBinOp(gz, scope, rl, node, .subwrap),
613 .sub_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .sub_with_saturation, Zir.Inst.SaturatingArithmetic),
614 .mul => return simpleBinOp(gz, scope, rl, node, .mul),611 .mul => return simpleBinOp(gz, scope, rl, node, .mul),
615 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),612 .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap),
616 .mul_sat => return binOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .mul_with_saturation, Zir.Inst.SaturatingArithmetic),
617 .div => return simpleBinOp(gz, scope, rl, node, .div),613 .div => return simpleBinOp(gz, scope, rl, node, .div),
618 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),614 .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem),
615
616 .add_sat => return simpleBinOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .add_with_saturation, Zir.Inst.SaturatingArithmetic),
617 .sub_sat => return simpleBinOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .sub_with_saturation, Zir.Inst.SaturatingArithmetic),
618 .mul_sat => return simpleBinOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .mul_with_saturation, Zir.Inst.SaturatingArithmetic),
619 .bit_shift_left_sat => return simpleBinOpExt(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shl_with_saturation, Zir.Inst.SaturatingArithmetic),
620
619 .bit_and => {621 .bit_and => {
620 const current_ampersand_token = main_tokens[node];622 const current_ampersand_token = main_tokens[node];
621 if (token_tags[current_ampersand_token + 1] == .ampersand) {623 if (token_tags[current_ampersand_token + 1] == .ampersand) {
...@@ -2713,9 +2715,7 @@ fn assignOp(...@@ -2713,9 +2715,7 @@ fn assignOp(
2713 _ = try gz.addBin(.store, lhs_ptr, result);2715 _ = try gz.addBin(.store, lhs_ptr, result);
2714}2716}
27152717
2716// TODO: is there an existing way to do this?2718fn simpleBinOpExt(
2717// TODO: likely rename this to reflect result_loc == .none or add more params to make it more general
2718fn binOpExt(
2719 gz: *GenZir,2719 gz: *GenZir,
2720 scope: *Scope,2720 scope: *Scope,
2721 rl: ResultLoc,2721 rl: ResultLoc,
...@@ -2735,9 +2735,7 @@ fn binOpExt(...@@ -2735,9 +2735,7 @@ fn binOpExt(
2735 return rvalue(gz, rl, result, infix_node);2735 return rvalue(gz, rl, result, infix_node);
2736}2736}
27372737
2738// TODO: is there an existing method to accomplish this?2738fn assignOpExt(
2739// TODO: likely rename this to indicate rhs type coercion or add more params to make it more general
2740fn assignBinOpExt(
2741 gz: *GenZir,2739 gz: *GenZir,
2742 scope: *Scope,2740 scope: *Scope,
2743 infix_node: Ast.Node.Index,2741 infix_node: Ast.Node.Index,
src/Sema.zig+84-6
...@@ -6164,7 +6164,7 @@ fn zirNegate(...@@ -6164,7 +6164,7 @@ fn zirNegate(
6164 const lhs = sema.resolveInst(.zero);6164 const lhs = sema.resolveInst(.zero);
6165 const rhs = sema.resolveInst(inst_data.operand);6165 const rhs = sema.resolveInst(inst_data.operand);
61666166
6167 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src, null);6167 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
6168}6168}
61696169
6170fn zirArithmetic(6170fn zirArithmetic(
...@@ -6184,7 +6184,7 @@ fn zirArithmetic(...@@ -6184,7 +6184,7 @@ fn zirArithmetic(
6184 const lhs = sema.resolveInst(extra.lhs);6184 const lhs = sema.resolveInst(extra.lhs);
6185 const rhs = sema.resolveInst(extra.rhs);6185 const rhs = sema.resolveInst(extra.rhs);
61866186
6187 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, null);6187 return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src);
6188}6188}
61896189
6190fn zirOverflowArithmetic(6190fn zirOverflowArithmetic(
...@@ -6216,11 +6216,90 @@ fn zirSatArithmetic(...@@ -6216,11 +6216,90 @@ fn zirSatArithmetic(
6216 const lhs = sema.resolveInst(extra.lhs);6216 const lhs = sema.resolveInst(extra.lhs);
6217 const rhs = sema.resolveInst(extra.rhs);6217 const rhs = sema.resolveInst(extra.rhs);
62186218
6219 return sema.analyzeArithmetic(block, .extended, lhs, rhs, sema.src, lhs_src, rhs_src, extended);6219 return sema.analyzeSatArithmetic(block, lhs, rhs, sema.src, lhs_src, rhs_src, extended);
6220}
6221
6222fn analyzeSatArithmetic(
6223 sema: *Sema,
6224 block: *Scope.Block,
6225 lhs: Air.Inst.Ref,
6226 rhs: Air.Inst.Ref,
6227 src: LazySrcLoc,
6228 lhs_src: LazySrcLoc,
6229 rhs_src: LazySrcLoc,
6230 extended: Zir.Inst.Extended.InstData,
6231) CompileError!Air.Inst.Ref {
6232 const lhs_ty = sema.typeOf(lhs);
6233 const rhs_ty = sema.typeOf(rhs);
6234 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
6235 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
6236 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
6237 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
6238 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
6239 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
6240 });
6241 }
6242 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});
6243 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
6244 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
6245 lhs_ty, rhs_ty,
6246 });
6247 }
6248
6249 if (lhs_zig_ty_tag == .Pointer or rhs_zig_ty_tag == .Pointer)
6250 return sema.mod.fail(&block.base, src, "TODO implement support for pointers in zirSatArithmetic", .{});
6251
6252 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
6253 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
6254 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
6255 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
6256
6257 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
6258 resolved_type.elemType()
6259 else
6260 resolved_type;
6261
6262 const scalar_tag = scalar_type.zigTypeTag();
6263
6264 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
6265
6266 if (!is_int)
6267 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{
6268 @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag),
6269 });
6270
6271 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
6272 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
6273 if (lhs_val.isUndef() or rhs_val.isUndef()) {
6274 return sema.addConstUndef(resolved_type);
6275 }
6276 // incase rhs is 0, simply return lhs without doing any calculations
6277 if (rhs_val.compareWithZero(.eq)) {
6278 switch (extended.opcode) {
6279 .add_with_saturation, .sub_with_saturation => return sema.addConstant(scalar_type, lhs_val),
6280 else => {},
6281 }
6282 }
6283
6284 return sema.mod.fail(&block.base, src, "TODO implement comptime saturating arithmetic for operand '{s}'", .{@tagName(extended.opcode)});
6285 } else {
6286 try sema.requireRuntimeBlock(block, rhs_src);
6287 }
6288 } else {
6289 try sema.requireRuntimeBlock(block, lhs_src);
6290 }
6291
6292 const air_tag: Air.Inst.Tag = switch (extended.opcode) {
6293 .add_with_saturation => .addsat,
6294 .sub_with_saturation => .subsat,
6295 .mul_with_saturation => .mulsat,
6296 .shl_with_saturation => .shl_sat,
6297 else => return sema.mod.fail(&block.base, src, "TODO implement arithmetic for extended opcode '{s}'", .{@tagName(extended.opcode)}),
6298 };
6299
6300 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
6220}6301}
62216302
6222// TODO: audit - not sure if its a good idea to reuse this, adding `opt_extended` param
6223// FIXME: somehow, rhs of <<| is required to be Log2T. this should accept T
6224fn analyzeArithmetic(6303fn analyzeArithmetic(
6225 sema: *Sema,6304 sema: *Sema,
6226 block: *Scope.Block,6305 block: *Scope.Block,
...@@ -6231,7 +6310,6 @@ fn analyzeArithmetic(...@@ -6231,7 +6310,6 @@ fn analyzeArithmetic(
6231 src: LazySrcLoc,6310 src: LazySrcLoc,
6232 lhs_src: LazySrcLoc,6311 lhs_src: LazySrcLoc,
6233 rhs_src: LazySrcLoc,6312 rhs_src: LazySrcLoc,
6234 opt_extended: ?Zir.Inst.Extended.InstData,
6235) CompileError!Air.Inst.Ref {6313) CompileError!Air.Inst.Ref {
6236 const lhs_ty = sema.typeOf(lhs);6314 const lhs_ty = sema.typeOf(lhs);
6237 const rhs_ty = sema.typeOf(rhs);6315 const rhs_ty = sema.typeOf(rhs);