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
535535 return rvalue(gz, rl, .void_value, node);
536536 },
537537 .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);
539539 return rvalue(gz, rl, .void_value, node);
540540 },
541541 .assign_bit_shift_right => {
......@@ -568,7 +568,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
568568 return rvalue(gz, rl, .void_value, node);
569569 },
570570 .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);
572572 return rvalue(gz, rl, .void_value, node);
573573 },
574574 .assign_mod => {
......@@ -584,7 +584,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
584584 return rvalue(gz, rl, .void_value, node);
585585 },
586586 .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);
588588 return rvalue(gz, rl, .void_value, node);
589589 },
590590 .assign_mul => {
......@@ -596,26 +596,28 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
596596 return rvalue(gz, rl, .void_value, node);
597597 },
598598 .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);
600600 return rvalue(gz, rl, .void_value, node);
601601 },
602602
603603 // zig fmt: off
604604 .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),
606605 .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr),
607606
608607 .add => return simpleBinOp(gz, scope, rl, node, .add),
609608 .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),
611609 .sub => return simpleBinOp(gz, scope, rl, node, .sub),
612610 .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),
614611 .mul => return simpleBinOp(gz, scope, rl, node, .mul),
615612 .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),
617613 .div => return simpleBinOp(gz, scope, rl, node, .div),
618614 .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
619621 .bit_and => {
620622 const current_ampersand_token = main_tokens[node];
621623 if (token_tags[current_ampersand_token + 1] == .ampersand) {
......@@ -2713,9 +2715,7 @@ fn assignOp(
27132715 _ = try gz.addBin(.store, lhs_ptr, result);
27142716}
27152717
2716// TODO: is there an existing way to do this?
2717// TODO: likely rename this to reflect result_loc == .none or add more params to make it more general
2718fn binOpExt(
2718fn simpleBinOpExt(
27192719 gz: *GenZir,
27202720 scope: *Scope,
27212721 rl: ResultLoc,
......@@ -2735,9 +2735,7 @@ fn binOpExt(
27352735 return rvalue(gz, rl, result, infix_node);
27362736}
27372737
2738// TODO: is there an existing method to accomplish this?
2739// TODO: likely rename this to indicate rhs type coercion or add more params to make it more general
2740fn assignBinOpExt(
2738fn assignOpExt(
27412739 gz: *GenZir,
27422740 scope: *Scope,
27432741 infix_node: Ast.Node.Index,
src/Sema.zig+84-6
......@@ -6164,7 +6164,7 @@ fn zirNegate(
61646164 const lhs = sema.resolveInst(.zero);
61656165 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);
61686168}
61696169
61706170fn zirArithmetic(
......@@ -6184,7 +6184,7 @@ fn zirArithmetic(
61846184 const lhs = sema.resolveInst(extra.lhs);
61856185 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);
61886188}
61896189
61906190fn zirOverflowArithmetic(
......@@ -6216,11 +6216,90 @@ fn zirSatArithmetic(
62166216 const lhs = sema.resolveInst(extra.lhs);
62176217 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);
62206301}
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
62246303fn analyzeArithmetic(
62256304 sema: *Sema,
62266305 block: *Scope.Block,
......@@ -6231,7 +6310,6 @@ fn analyzeArithmetic(
62316310 src: LazySrcLoc,
62326311 lhs_src: LazySrcLoc,
62336312 rhs_src: LazySrcLoc,
6234 opt_extended: ?Zir.Inst.Extended.InstData,
62356313) CompileError!Air.Inst.Ref {
62366314 const lhs_ty = sema.typeOf(lhs);
62376315 const rhs_ty = sema.typeOf(rhs);