| author | |
| committer | |
| log | baaec94fe427efad4fe46ee3ffde53184cbd0ae9 |
| tree | a2fca56ce6507b78e3f2900565766e713ed52dd5 |
| parent | cd8d8add9153b17b4579c2e8951ac3f3f42e1bcd |
- similar to Sema.analyzeArithmetic but uses accepts Zir.Inst.Extended.InstData
- missing support for Pointer types and comptime arithmetic2 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 | 535 | return rvalue(gz, rl, .void_value, node); |
| 536 | 536 | }, |
| 537 | 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 | 539 | return rvalue(gz, rl, .void_value, node); |
| 540 | 540 | }, |
| 541 | 541 | .assign_bit_shift_right => { |
| ... | ... | @@ -568,7 +568,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 568 | 568 | return rvalue(gz, rl, .void_value, node); |
| 569 | 569 | }, |
| 570 | 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 | 572 | return rvalue(gz, rl, .void_value, node); |
| 573 | 573 | }, |
| 574 | 574 | .assign_mod => { |
| ... | ... | @@ -584,7 +584,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 584 | 584 | return rvalue(gz, rl, .void_value, node); |
| 585 | 585 | }, |
| 586 | 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 | 588 | return rvalue(gz, rl, .void_value, node); |
| 589 | 589 | }, |
| 590 | 590 | .assign_mul => { |
| ... | ... | @@ -596,26 +596,28 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 596 | 596 | return rvalue(gz, rl, .void_value, node); |
| 597 | 597 | }, |
| 598 | 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 | 600 | return rvalue(gz, rl, .void_value, node); |
| 601 | 601 | }, |
| 602 | 602 | |
| 603 | 603 | // zig fmt: off |
| 604 | 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 | 605 | .bit_shift_right => return shiftOp(gz, scope, rl, node, node_datas[node].lhs, node_datas[node].rhs, .shr), |
| 607 | 606 | |
| 608 | 607 | .add => return simpleBinOp(gz, scope, rl, node, .add), |
| 609 | 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 | 609 | .sub => return simpleBinOp(gz, scope, rl, node, .sub), |
| 612 | 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 | 611 | .mul => return simpleBinOp(gz, scope, rl, node, .mul), |
| 615 | 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 | 613 | .div => return simpleBinOp(gz, scope, rl, node, .div), |
| 618 | 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 | 621 | .bit_and => { |
| 620 | 622 | const current_ampersand_token = main_tokens[node]; |
| 621 | 623 | if (token_tags[current_ampersand_token + 1] == .ampersand) { |
| ... | ... | @@ -2713,9 +2715,7 @@ fn assignOp( |
| 2713 | 2715 | _ = try gz.addBin(.store, lhs_ptr, result); |
| 2714 | 2716 | } |
| 2715 | 2717 | |
| 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 | |
| 2718 | fn binOpExt( | |
| 2718 | fn simpleBinOpExt( | |
| 2719 | 2719 | gz: *GenZir, |
| 2720 | 2720 | scope: *Scope, |
| 2721 | 2721 | rl: ResultLoc, |
| ... | ... | @@ -2735,9 +2735,7 @@ fn binOpExt( |
| 2735 | 2735 | return rvalue(gz, rl, result, infix_node); |
| 2736 | 2736 | } |
| 2737 | 2737 | |
| 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 | |
| 2740 | fn assignBinOpExt( | |
| 2738 | fn assignOpExt( | |
| 2741 | 2739 | gz: *GenZir, |
| 2742 | 2740 | scope: *Scope, |
| 2743 | 2741 | infix_node: Ast.Node.Index, |
src/Sema.zig+84-6| ... | ... | @@ -6164,7 +6164,7 @@ fn zirNegate( |
| 6164 | 6164 | const lhs = sema.resolveInst(.zero); |
| 6165 | 6165 | const rhs = sema.resolveInst(inst_data.operand); |
| 6166 | 6166 | |
| 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 | } |
| 6169 | 6169 | |
| 6170 | 6170 | fn zirArithmetic( |
| ... | ... | @@ -6184,7 +6184,7 @@ fn zirArithmetic( |
| 6184 | 6184 | const lhs = sema.resolveInst(extra.lhs); |
| 6185 | 6185 | const rhs = sema.resolveInst(extra.rhs); |
| 6186 | 6186 | |
| 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 | } |
| 6189 | 6189 | |
| 6190 | 6190 | fn zirOverflowArithmetic( |
| ... | ... | @@ -6216,11 +6216,90 @@ fn zirSatArithmetic( |
| 6216 | 6216 | const lhs = sema.resolveInst(extra.lhs); |
| 6217 | 6217 | const rhs = sema.resolveInst(extra.rhs); |
| 6218 | 6218 | |
| 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 | ||
| 6222 | fn 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 | } |
| 6221 | 6302 | |
| 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 | |
| 6224 | 6303 | fn analyzeArithmetic( |
| 6225 | 6304 | sema: *Sema, |
| 6226 | 6305 | block: *Scope.Block, |
| ... | ... | @@ -6231,7 +6310,6 @@ fn analyzeArithmetic( |
| 6231 | 6310 | src: LazySrcLoc, |
| 6232 | 6311 | lhs_src: LazySrcLoc, |
| 6233 | 6312 | rhs_src: LazySrcLoc, |
| 6234 | opt_extended: ?Zir.Inst.Extended.InstData, | |
| 6235 | 6313 | ) CompileError!Air.Inst.Ref { |
| 6236 | 6314 | const lhs_ty = sema.typeOf(lhs); |
| 6237 | 6315 | const rhs_ty = sema.typeOf(rhs); |