authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-21 20:05:29-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-21 20:05:29-04:00
log71413568389850e821df0784166d840de4d8f96e
treeccc577b34bc44433c78a56c4ab7065ac5ee50a2d
parent2f4473b6536ee43e51a17b02d8fad7518ab32c3b
parent7eddef423d74318ef9190864232f2e224837461e
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11237 from wsengir/stage2-vectors

stage2: implement most vector operations in Sema and LLVM backend

13 files changed, 1438 insertions(+), 425 deletions(-)

src/Air.zig+21-2
...@@ -308,6 +308,10 @@ pub const Inst = struct {...@@ -308,6 +308,10 @@ pub const Inst = struct {
308 /// `!=`. Result type is always bool.308 /// `!=`. Result type is always bool.
309 /// Uses the `bin_op` field.309 /// Uses the `bin_op` field.
310 cmp_neq,310 cmp_neq,
311 /// Conditional between two vectors.
312 /// Result type is always a vector of bools.
313 /// Uses the `ty_pl` field, payload is `VectorCmp`.
314 cmp_vector,
311315
312 /// Conditional branch.316 /// Conditional branch.
313 /// Result type is always noreturn; no instructions in a block follow this one.317 /// Result type is always noreturn; no instructions in a block follow this one.
...@@ -781,6 +785,20 @@ pub const Shuffle = struct {...@@ -781,6 +785,20 @@ pub const Shuffle = struct {
781 mask_len: u32,785 mask_len: u32,
782};786};
783787
788pub const VectorCmp = struct {
789 lhs: Inst.Ref,
790 rhs: Inst.Ref,
791 op: u32,
792
793 pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {
794 return @intToEnum(std.math.CompareOperator, @truncate(u3, self.op));
795 }
796
797 pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
798 return @enumToInt(compare_operator);
799 }
800};
801
784/// Trailing:802/// Trailing:
785/// 0. `Inst.Ref` for every outputs_len803/// 0. `Inst.Ref` for every outputs_len
786/// 1. `Inst.Ref` for every inputs_len804/// 1. `Inst.Ref` for every inputs_len
...@@ -886,6 +904,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -886,6 +904,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
886 .shl_sat,904 .shl_sat,
887 .min,905 .min,
888 .max,906 .max,
907 .bool_and,
908 .bool_or,
889 => return air.typeOf(datas[inst].bin_op.lhs),909 => return air.typeOf(datas[inst].bin_op.lhs),
890910
891 .sqrt,911 .sqrt,
...@@ -917,8 +937,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -917,8 +937,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
917 .is_non_err,937 .is_non_err,
918 .is_err_ptr,938 .is_err_ptr,
919 .is_non_err_ptr,939 .is_non_err_ptr,
920 .bool_and,
921 .bool_or,
922 => return Type.initTag(.bool),940 => return Type.initTag(.bool),
923941
924 .const_ty => return Type.initTag(.type),942 .const_ty => return Type.initTag(.type),
...@@ -942,6 +960,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -942,6 +960,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
942 .aggregate_init,960 .aggregate_init,
943 .union_init,961 .union_init,
944 .field_parent_ptr,962 .field_parent_ptr,
963 .cmp_vector,
945 => return air.getRefType(datas[inst].ty_pl.ty),964 => return air.getRefType(datas[inst].ty_pl.ty),
946965
947 .not,966 .not,
src/Liveness.zig+4
...@@ -441,6 +441,10 @@ fn analyzeInst(...@@ -441,6 +441,10 @@ fn analyzeInst(
441 const reduce = inst_datas[inst].reduce;441 const reduce = inst_datas[inst].reduce;
442 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });442 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
443 },443 },
444 .cmp_vector => {
445 const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data;
446 return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
447 },
444 .aggregate_init => {448 .aggregate_init => {
445 const ty_pl = inst_datas[inst].ty_pl;449 const ty_pl = inst_datas[inst].ty_pl;
446 const aggregate_ty = a.air.getRefType(ty_pl.ty);450 const aggregate_ty = a.air.getRefType(ty_pl.ty);
src/Sema.zig+291-234
...@@ -397,6 +397,20 @@ pub const Block = struct {...@@ -397,6 +397,20 @@ pub const Block = struct {
397 });397 });
398 }398 }
399399
400 fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator, vector_ty: Air.Inst.Ref) !Air.Inst.Ref {
401 return block.addInst(.{
402 .tag = .cmp_vector,
403 .data = .{ .ty_pl = .{
404 .ty = vector_ty,
405 .payload = try block.sema.addExtra(Air.VectorCmp{
406 .lhs = lhs,
407 .rhs = rhs,
408 .op = Air.VectorCmp.encodeOp(cmp_op),
409 }),
410 } },
411 });
412 }
413
400 fn addAggregateInit(414 fn addAggregateInit(
401 block: *Block,415 block: *Block,
402 aggregate_ty: Type,416 aggregate_ty: Type,
...@@ -2091,7 +2105,7 @@ fn zirEnumDecl(...@@ -2091,7 +2105,7 @@ fn zirEnumDecl(
2091 });2105 });
2092 } else if (any_values) {2106 } else if (any_values) {
2093 const tag_val = if (last_tag_val) |val|2107 const tag_val = if (last_tag_val) |val|
2094 try val.intAdd(Value.one, sema.arena)2108 try val.intAdd(Value.one, enum_obj.tag_ty, sema.arena)
2095 else2109 else
2096 Value.zero;2110 Value.zero;
2097 last_tag_val = tag_val;2111 last_tag_val = tag_val;
...@@ -8178,14 +8192,22 @@ fn zirShl(...@@ -8178,14 +8192,22 @@ fn zirShl(
8178 defer tracy.end();8192 defer tracy.end();
81798193
8180 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;8194 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
8195 const src = inst_data.src();
8181 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };8196 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
8182 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };8197 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
8183 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;8198 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
8184 const lhs = sema.resolveInst(extra.lhs);8199 const lhs = sema.resolveInst(extra.lhs);
8185 const rhs = sema.resolveInst(extra.rhs);8200 const rhs = sema.resolveInst(extra.rhs);
8201 const lhs_ty = sema.typeOf(lhs);
8202 const rhs_ty = sema.typeOf(rhs);
8203 const target = sema.mod.getTarget();
8204 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
8205
8206 const scalar_ty = lhs_ty.scalarType();
8207 const scalar_rhs_ty = rhs_ty.scalarType();
81868208
8187 // TODO coerce rhs if air_tag is not shl_sat8209 // TODO coerce rhs if air_tag is not shl_sat
8188 const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, sema.typeOf(rhs));8210 const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
81898211
8190 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);8212 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
8191 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);8213 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
...@@ -8199,35 +8221,31 @@ fn zirShl(...@@ -8199,35 +8221,31 @@ fn zirShl(
8199 }8221 }
8200 }8222 }
82018223
8202 const lhs_ty = sema.typeOf(lhs);
8203 const rhs_ty = sema.typeOf(rhs);
8204 const target = sema.mod.getTarget();
8205
8206 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {8224 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
8207 if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);8225 if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
8208 const rhs_val = maybe_rhs_val orelse break :rs rhs_src;8226 const rhs_val = maybe_rhs_val orelse break :rs rhs_src;
82098227
8210 const val = switch (air_tag) {8228 const val = switch (air_tag) {
8211 .shl_exact => val: {8229 .shl_exact => val: {
8212 const shifted = try lhs_val.shl(rhs_val, sema.arena);8230 const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena);
8213 if (lhs_ty.zigTypeTag() == .ComptimeInt) {8231 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
8214 break :val shifted;8232 break :val shifted;
8215 }8233 }
8216 const int_info = lhs_ty.intInfo(target);8234 const int_info = scalar_ty.intInfo(target);
8217 const truncated = try shifted.intTrunc(sema.arena, int_info.signedness, int_info.bits);8235 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits);
8218 if (truncated.compareHetero(.eq, shifted)) {8236 if (truncated.compare(.eq, shifted, lhs_ty)) {
8219 break :val shifted;8237 break :val shifted;
8220 }8238 }
8221 return sema.addConstUndef(lhs_ty);8239 return sema.addConstUndef(lhs_ty);
8222 },8240 },
82238241
8224 .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt)8242 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
8225 try lhs_val.shl(rhs_val, sema.arena)8243 try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
8226 else8244 else
8227 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),8245 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),
82288246
8229 .shl => if (lhs_ty.zigTypeTag() == .ComptimeInt)8247 .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt)
8230 try lhs_val.shl(rhs_val, sema.arena)8248 try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
8231 else8249 else
8232 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),8250 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),
82338251
...@@ -8242,7 +8260,7 @@ fn zirShl(...@@ -8242,7 +8260,7 @@ fn zirShl(
8242 const new_rhs = if (air_tag == .shl_sat) rhs: {8260 const new_rhs = if (air_tag == .shl_sat) rhs: {
8243 // Limit the RHS type for saturating shl to be an integer as small as the LHS.8261 // Limit the RHS type for saturating shl to be an integer as small as the LHS.
8244 if (rhs_is_comptime_int or8262 if (rhs_is_comptime_int or
8245 rhs_ty.intInfo(target).bits > lhs_ty.intInfo(target).bits)8263 scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits)
8246 {8264 {
8247 const max_int = try sema.addConstant(8265 const max_int = try sema.addConstant(
8248 lhs_ty,8266 lhs_ty,
...@@ -8269,15 +8287,18 @@ fn zirShr(...@@ -8269,15 +8287,18 @@ fn zirShr(
8269 defer tracy.end();8287 defer tracy.end();
82708288
8271 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;8289 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
8290 const src = inst_data.src();
8272 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };8291 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
8273 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };8292 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
8274 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;8293 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
8275 const lhs = sema.resolveInst(extra.lhs);8294 const lhs = sema.resolveInst(extra.lhs);
8276 const rhs = sema.resolveInst(extra.rhs);8295 const rhs = sema.resolveInst(extra.rhs);
8296 const lhs_ty = sema.typeOf(lhs);
8297 const rhs_ty = sema.typeOf(rhs);
8298 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
82778299
8278 const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {8300 const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {
8279 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {8301 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
8280 const lhs_ty = sema.typeOf(lhs);
8281 if (lhs_val.isUndef() or rhs_val.isUndef()) {8302 if (lhs_val.isUndef() or rhs_val.isUndef()) {
8282 return sema.addConstUndef(lhs_ty);8303 return sema.addConstUndef(lhs_ty);
8283 }8304 }
...@@ -8287,13 +8308,12 @@ fn zirShr(...@@ -8287,13 +8308,12 @@ fn zirShr(
8287 }8308 }
8288 if (air_tag == .shr_exact) {8309 if (air_tag == .shr_exact) {
8289 // Detect if any ones would be shifted out.8310 // Detect if any ones would be shifted out.
8290 const bits = @intCast(u16, rhs_val.toUnsignedInt());8311 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val);
8291 const truncated = try lhs_val.intTrunc(sema.arena, .unsigned, bits);
8292 if (!truncated.compareWithZero(.eq)) {8312 if (!truncated.compareWithZero(.eq)) {
8293 return sema.addConstUndef(lhs_ty);8313 return sema.addConstUndef(lhs_ty);
8294 }8314 }
8295 }8315 }
8296 const val = try lhs_val.shr(rhs_val, sema.arena);8316 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena);
8297 return sema.addConstant(lhs_ty, val);8317 return sema.addConstant(lhs_ty, val);
8298 } else {8318 } else {
8299 // Even if lhs is not comptime known, we can still deduce certain things based8319 // Even if lhs is not comptime known, we can still deduce certain things based
...@@ -8328,32 +8348,15 @@ fn zirBitwise(...@@ -8328,32 +8348,15 @@ fn zirBitwise(
8328 const rhs = sema.resolveInst(extra.rhs);8348 const rhs = sema.resolveInst(extra.rhs);
8329 const lhs_ty = sema.typeOf(lhs);8349 const lhs_ty = sema.typeOf(lhs);
8330 const rhs_ty = sema.typeOf(rhs);8350 const rhs_ty = sema.typeOf(rhs);
8351 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
83318352
8332 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };8353 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
8333 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });8354 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
8334 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);8355 const scalar_type = resolved_type.scalarType();
8335 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
8336
8337 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
8338 resolved_type.elemType()
8339 else
8340 resolved_type;
8341
8342 const scalar_tag = scalar_type.zigTypeTag();8356 const scalar_tag = scalar_type.zigTypeTag();
83438357
8344 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {8358 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
8345 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {8359 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
8346 return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
8347 lhs_ty.arrayLen(),
8348 rhs_ty.arrayLen(),
8349 });
8350 }
8351 } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {
8352 return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
8353 lhs_ty,
8354 rhs_ty,
8355 });
8356 }
83578360
8358 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;8361 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
83598362
...@@ -8363,16 +8366,13 @@ fn zirBitwise(...@@ -8363,16 +8366,13 @@ fn zirBitwise(
83638366
8364 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {8367 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
8365 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {8368 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
8366 if (resolved_type.zigTypeTag() == .Vector) {
8367 return sema.fail(block, src, "TODO implement zirBitwise for vectors at comptime", .{});
8368 }
8369 const result_val = switch (air_tag) {8369 const result_val = switch (air_tag) {
8370 .bit_and => try lhs_val.bitwiseAnd(rhs_val, sema.arena),8370 .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena),
8371 .bit_or => try lhs_val.bitwiseOr(rhs_val, sema.arena),8371 .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena),
8372 .xor => try lhs_val.bitwiseXor(rhs_val, sema.arena),8372 .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena),
8373 else => unreachable,8373 else => unreachable,
8374 };8374 };
8375 return sema.addConstant(scalar_type, result_val);8375 return sema.addConstant(resolved_type, result_val);
8376 }8376 }
8377 }8377 }
83788378
...@@ -8399,9 +8399,9 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -8399,9 +8399,9 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
8399 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {8399 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
8400 const target = sema.mod.getTarget();8400 const target = sema.mod.getTarget();
8401 if (val.isUndef()) {8401 if (val.isUndef()) {
8402 return sema.addConstUndef(scalar_type);8402 return sema.addConstUndef(operand_type);
8403 } else if (operand_type.zigTypeTag() == .Vector) {8403 } else if (operand_type.zigTypeTag() == .Vector) {
8404 const vec_len = try sema.usizeCast(block, operand_src, operand_type.arrayLen());8404 const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen());
8405 var elem_val_buf: Value.ElemValueBuffer = undefined;8405 var elem_val_buf: Value.ElemValueBuffer = undefined;
8406 const elems = try sema.arena.alloc(Value, vec_len);8406 const elems = try sema.arena.alloc(Value, vec_len);
8407 for (elems) |*elem, i| {8407 for (elems) |*elem, i| {
...@@ -8413,8 +8413,8 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -8413,8 +8413,8 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
8413 try Value.Tag.aggregate.create(sema.arena, elems),8413 try Value.Tag.aggregate.create(sema.arena, elems),
8414 );8414 );
8415 } else {8415 } else {
8416 const result_val = try val.bitwiseNot(scalar_type, sema.arena, target);8416 const result_val = try val.bitwiseNot(operand_type, sema.arena, target);
8417 return sema.addConstant(scalar_type, result_val);8417 return sema.addConstant(operand_type, result_val);
8418 }8418 }
8419 }8419 }
84208420
...@@ -8766,8 +8766,19 @@ fn zirNegate(...@@ -8766,8 +8766,19 @@ fn zirNegate(
8766 const src = inst_data.src();8766 const src = inst_data.src();
8767 const lhs_src = src;8767 const lhs_src = src;
8768 const rhs_src = src; // TODO better source location8768 const rhs_src = src; // TODO better source location
8769 const lhs = sema.resolveInst(.zero);8769
8770 const rhs = sema.resolveInst(inst_data.operand);8770 const rhs = sema.resolveInst(inst_data.operand);
8771 const rhs_ty = sema.typeOf(rhs);
8772 const rhs_scalar_ty = rhs_ty.scalarType();
8773
8774 if (tag_override == .sub and rhs_scalar_ty.isUnsignedInt()) {
8775 return sema.fail(block, src, "negation of type '{}'", .{rhs_ty});
8776 }
8777
8778 const lhs = if (rhs_ty.zigTypeTag() == .Vector)
8779 try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
8780 else
8781 sema.resolveInst(.zero);
87718782
8772 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);8783 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
8773}8784}
...@@ -8985,18 +8996,8 @@ fn analyzeArithmetic(...@@ -8985,18 +8996,8 @@ fn analyzeArithmetic(
8985 const rhs_ty = sema.typeOf(rhs);8996 const rhs_ty = sema.typeOf(rhs);
8986 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();8997 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
8987 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();8998 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
8988 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {8999 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
8989 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {9000
8990 return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
8991 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
8992 });
8993 }
8994 return sema.fail(block, src, "TODO implement support for vectors in Sema.analyzeArithmetic", .{});
8995 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
8996 return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
8997 lhs_ty, rhs_ty,
8998 });
8999 }
9000 if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {9001 if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {
9001 .One, .Slice => {},9002 .One, .Slice => {},
9002 .Many, .C => {9003 .Many, .C => {
...@@ -9019,15 +9020,13 @@ fn analyzeArithmetic(...@@ -9019,15 +9020,13 @@ fn analyzeArithmetic(
9019 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{9020 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
9020 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },9021 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
9021 });9022 });
9023
9022 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);9024 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
9023 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);9025 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
90249026
9025 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)9027 const lhs_scalar_ty = lhs_ty.scalarType();
9026 resolved_type.elemType()9028 const rhs_scalar_ty = rhs_ty.scalarType();
9027 else9029 const scalar_tag = resolved_type.scalarType().zigTypeTag();
9028 resolved_type;
9029
9030 const scalar_tag = scalar_type.zigTypeTag();
90319030
9032 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;9031 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
9033 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;9032 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
...@@ -9061,7 +9060,7 @@ fn analyzeArithmetic(...@@ -9061,7 +9060,7 @@ fn analyzeArithmetic(
9061 if (is_int) {9060 if (is_int) {
9062 return sema.failWithUseOfUndef(block, rhs_src);9061 return sema.failWithUseOfUndef(block, rhs_src);
9063 } else {9062 } else {
9064 return sema.addConstUndef(scalar_type);9063 return sema.addConstUndef(resolved_type);
9065 }9064 }
9066 }9065 }
9067 if (rhs_val.compareWithZero(.eq)) {9066 if (rhs_val.compareWithZero(.eq)) {
...@@ -9073,19 +9072,19 @@ fn analyzeArithmetic(...@@ -9073,19 +9072,19 @@ fn analyzeArithmetic(
9073 if (is_int) {9072 if (is_int) {
9074 return sema.failWithUseOfUndef(block, lhs_src);9073 return sema.failWithUseOfUndef(block, lhs_src);
9075 } else {9074 } else {
9076 return sema.addConstUndef(scalar_type);9075 return sema.addConstUndef(resolved_type);
9077 }9076 }
9078 }9077 }
9079 if (maybe_rhs_val) |rhs_val| {9078 if (maybe_rhs_val) |rhs_val| {
9080 if (is_int) {9079 if (is_int) {
9081 return sema.addConstant(9080 return sema.addConstant(
9082 scalar_type,9081 resolved_type,
9083 try lhs_val.intAdd(rhs_val, sema.arena),9082 try lhs_val.intAdd(rhs_val, resolved_type, sema.arena),
9084 );9083 );
9085 } else {9084 } else {
9086 return sema.addConstant(9085 return sema.addConstant(
9087 scalar_type,9086 resolved_type,
9088 try lhs_val.floatAdd(rhs_val, scalar_type, sema.arena, target),9087 try lhs_val.floatAdd(rhs_val, resolved_type, sema.arena, target),
9089 );9088 );
9090 }9089 }
9091 } else break :rs .{ .src = rhs_src, .air_tag = .add };9090 } else break :rs .{ .src = rhs_src, .air_tag = .add };
...@@ -9102,15 +9101,15 @@ fn analyzeArithmetic(...@@ -9102,15 +9101,15 @@ fn analyzeArithmetic(
9102 }9101 }
9103 if (maybe_rhs_val) |rhs_val| {9102 if (maybe_rhs_val) |rhs_val| {
9104 if (rhs_val.isUndef()) {9103 if (rhs_val.isUndef()) {
9105 return sema.addConstUndef(scalar_type);9104 return sema.addConstUndef(resolved_type);
9106 }9105 }
9107 if (rhs_val.compareWithZero(.eq)) {9106 if (rhs_val.compareWithZero(.eq)) {
9108 return casted_lhs;9107 return casted_lhs;
9109 }9108 }
9110 if (maybe_lhs_val) |lhs_val| {9109 if (maybe_lhs_val) |lhs_val| {
9111 return sema.addConstant(9110 return sema.addConstant(
9112 scalar_type,9111 resolved_type,
9113 try lhs_val.numberAddWrap(rhs_val, scalar_type, sema.arena, target),9112 try lhs_val.numberAddWrap(rhs_val, resolved_type, sema.arena, target),
9114 );9113 );
9115 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };9114 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
9116 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };9115 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
...@@ -9126,18 +9125,18 @@ fn analyzeArithmetic(...@@ -9126,18 +9125,18 @@ fn analyzeArithmetic(
9126 }9125 }
9127 if (maybe_rhs_val) |rhs_val| {9126 if (maybe_rhs_val) |rhs_val| {
9128 if (rhs_val.isUndef()) {9127 if (rhs_val.isUndef()) {
9129 return sema.addConstUndef(scalar_type);9128 return sema.addConstUndef(resolved_type);
9130 }9129 }
9131 if (rhs_val.compareWithZero(.eq)) {9130 if (rhs_val.compareWithZero(.eq)) {
9132 return casted_lhs;9131 return casted_lhs;
9133 }9132 }
9134 if (maybe_lhs_val) |lhs_val| {9133 if (maybe_lhs_val) |lhs_val| {
9135 const val = if (scalar_tag == .ComptimeInt)9134 const val = if (scalar_tag == .ComptimeInt)
9136 try lhs_val.intAdd(rhs_val, sema.arena)9135 try lhs_val.intAdd(rhs_val, resolved_type, sema.arena)
9137 else9136 else
9138 try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target);9137 try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);
91399138
9140 return sema.addConstant(scalar_type, val);9139 return sema.addConstant(resolved_type, val);
9141 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };9140 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
9142 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };9141 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
9143 },9142 },
...@@ -9154,7 +9153,7 @@ fn analyzeArithmetic(...@@ -9154,7 +9153,7 @@ fn analyzeArithmetic(
9154 if (is_int) {9153 if (is_int) {
9155 return sema.failWithUseOfUndef(block, rhs_src);9154 return sema.failWithUseOfUndef(block, rhs_src);
9156 } else {9155 } else {
9157 return sema.addConstUndef(scalar_type);9156 return sema.addConstUndef(resolved_type);
9158 }9157 }
9159 }9158 }
9160 if (rhs_val.compareWithZero(.eq)) {9159 if (rhs_val.compareWithZero(.eq)) {
...@@ -9166,19 +9165,19 @@ fn analyzeArithmetic(...@@ -9166,19 +9165,19 @@ fn analyzeArithmetic(
9166 if (is_int) {9165 if (is_int) {
9167 return sema.failWithUseOfUndef(block, lhs_src);9166 return sema.failWithUseOfUndef(block, lhs_src);
9168 } else {9167 } else {
9169 return sema.addConstUndef(scalar_type);9168 return sema.addConstUndef(resolved_type);
9170 }9169 }
9171 }9170 }
9172 if (maybe_rhs_val) |rhs_val| {9171 if (maybe_rhs_val) |rhs_val| {
9173 if (is_int) {9172 if (is_int) {
9174 return sema.addConstant(9173 return sema.addConstant(
9175 scalar_type,9174 resolved_type,
9176 try lhs_val.intSub(rhs_val, sema.arena),9175 try lhs_val.intSub(rhs_val, resolved_type, sema.arena),
9177 );9176 );
9178 } else {9177 } else {
9179 return sema.addConstant(9178 return sema.addConstant(
9180 scalar_type,9179 resolved_type,
9181 try lhs_val.floatSub(rhs_val, scalar_type, sema.arena, target),9180 try lhs_val.floatSub(rhs_val, resolved_type, sema.arena, target),
9182 );9181 );
9183 }9182 }
9184 } else break :rs .{ .src = rhs_src, .air_tag = .sub };9183 } else break :rs .{ .src = rhs_src, .air_tag = .sub };
...@@ -9190,7 +9189,7 @@ fn analyzeArithmetic(...@@ -9190,7 +9189,7 @@ fn analyzeArithmetic(
9190 // If either of the operands are undefined, the result is undefined.9189 // If either of the operands are undefined, the result is undefined.
9191 if (maybe_rhs_val) |rhs_val| {9190 if (maybe_rhs_val) |rhs_val| {
9192 if (rhs_val.isUndef()) {9191 if (rhs_val.isUndef()) {
9193 return sema.addConstUndef(scalar_type);9192 return sema.addConstUndef(resolved_type);
9194 }9193 }
9195 if (rhs_val.compareWithZero(.eq)) {9194 if (rhs_val.compareWithZero(.eq)) {
9196 return casted_lhs;9195 return casted_lhs;
...@@ -9198,12 +9197,12 @@ fn analyzeArithmetic(...@@ -9198,12 +9197,12 @@ fn analyzeArithmetic(
9198 }9197 }
9199 if (maybe_lhs_val) |lhs_val| {9198 if (maybe_lhs_val) |lhs_val| {
9200 if (lhs_val.isUndef()) {9199 if (lhs_val.isUndef()) {
9201 return sema.addConstUndef(scalar_type);9200 return sema.addConstUndef(resolved_type);
9202 }9201 }
9203 if (maybe_rhs_val) |rhs_val| {9202 if (maybe_rhs_val) |rhs_val| {
9204 return sema.addConstant(9203 return sema.addConstant(
9205 scalar_type,9204 resolved_type,
9206 try lhs_val.numberSubWrap(rhs_val, scalar_type, sema.arena, target),9205 try lhs_val.numberSubWrap(rhs_val, resolved_type, sema.arena, target),
9207 );9206 );
9208 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };9207 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
9209 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };9208 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
...@@ -9214,7 +9213,7 @@ fn analyzeArithmetic(...@@ -9214,7 +9213,7 @@ fn analyzeArithmetic(
9214 // If either of the operands are undefined, result is undefined.9213 // If either of the operands are undefined, result is undefined.
9215 if (maybe_rhs_val) |rhs_val| {9214 if (maybe_rhs_val) |rhs_val| {
9216 if (rhs_val.isUndef()) {9215 if (rhs_val.isUndef()) {
9217 return sema.addConstUndef(scalar_type);9216 return sema.addConstUndef(resolved_type);
9218 }9217 }
9219 if (rhs_val.compareWithZero(.eq)) {9218 if (rhs_val.compareWithZero(.eq)) {
9220 return casted_lhs;9219 return casted_lhs;
...@@ -9222,15 +9221,15 @@ fn analyzeArithmetic(...@@ -9222,15 +9221,15 @@ fn analyzeArithmetic(
9222 }9221 }
9223 if (maybe_lhs_val) |lhs_val| {9222 if (maybe_lhs_val) |lhs_val| {
9224 if (lhs_val.isUndef()) {9223 if (lhs_val.isUndef()) {
9225 return sema.addConstUndef(scalar_type);9224 return sema.addConstUndef(resolved_type);
9226 }9225 }
9227 if (maybe_rhs_val) |rhs_val| {9226 if (maybe_rhs_val) |rhs_val| {
9228 const val = if (scalar_tag == .ComptimeInt)9227 const val = if (scalar_tag == .ComptimeInt)
9229 try lhs_val.intSub(rhs_val, sema.arena)9228 try lhs_val.intSub(rhs_val, resolved_type, sema.arena)
9230 else9229 else
9231 try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target);9230 try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);
92329231
9233 return sema.addConstant(scalar_type, val);9232 return sema.addConstant(resolved_type, val);
9234 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };9233 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
9235 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };9234 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
9236 },9235 },
...@@ -9260,7 +9259,7 @@ fn analyzeArithmetic(...@@ -9260,7 +9259,7 @@ fn analyzeArithmetic(
9260 if (maybe_lhs_val) |lhs_val| {9259 if (maybe_lhs_val) |lhs_val| {
9261 if (!lhs_val.isUndef()) {9260 if (!lhs_val.isUndef()) {
9262 if (lhs_val.compareWithZero(.eq)) {9261 if (lhs_val.compareWithZero(.eq)) {
9263 return sema.addConstant(scalar_type, Value.zero);9262 return sema.addConstant(resolved_type, Value.zero);
9264 }9263 }
9265 }9264 }
9266 }9265 }
...@@ -9274,27 +9273,27 @@ fn analyzeArithmetic(...@@ -9274,27 +9273,27 @@ fn analyzeArithmetic(
9274 }9273 }
9275 if (maybe_lhs_val) |lhs_val| {9274 if (maybe_lhs_val) |lhs_val| {
9276 if (lhs_val.isUndef()) {9275 if (lhs_val.isUndef()) {
9277 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {9276 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9278 if (maybe_rhs_val) |rhs_val| {9277 if (maybe_rhs_val) |rhs_val| {
9279 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {9278 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9280 return sema.addConstUndef(scalar_type);9279 return sema.addConstUndef(resolved_type);
9281 }9280 }
9282 }9281 }
9283 return sema.failWithUseOfUndef(block, rhs_src);9282 return sema.failWithUseOfUndef(block, rhs_src);
9284 }9283 }
9285 return sema.addConstUndef(scalar_type);9284 return sema.addConstUndef(resolved_type);
9286 }9285 }
92879286
9288 if (maybe_rhs_val) |rhs_val| {9287 if (maybe_rhs_val) |rhs_val| {
9289 if (is_int) {9288 if (is_int) {
9290 return sema.addConstant(9289 return sema.addConstant(
9291 scalar_type,9290 resolved_type,
9292 try lhs_val.intDiv(rhs_val, sema.arena),9291 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
9293 );9292 );
9294 } else {9293 } else {
9295 return sema.addConstant(9294 return sema.addConstant(
9296 scalar_type,9295 resolved_type,
9297 try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),9296 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
9298 );9297 );
9299 }9298 }
9300 } else {9299 } else {
...@@ -9335,7 +9334,7 @@ fn analyzeArithmetic(...@@ -9335,7 +9334,7 @@ fn analyzeArithmetic(
9335 if (maybe_lhs_val) |lhs_val| {9334 if (maybe_lhs_val) |lhs_val| {
9336 if (!lhs_val.isUndef()) {9335 if (!lhs_val.isUndef()) {
9337 if (lhs_val.compareWithZero(.eq)) {9336 if (lhs_val.compareWithZero(.eq)) {
9338 return sema.addConstant(scalar_type, Value.zero);9337 return sema.addConstant(resolved_type, Value.zero);
9339 }9338 }
9340 }9339 }
9341 }9340 }
...@@ -9349,27 +9348,27 @@ fn analyzeArithmetic(...@@ -9349,27 +9348,27 @@ fn analyzeArithmetic(
9349 }9348 }
9350 if (maybe_lhs_val) |lhs_val| {9349 if (maybe_lhs_val) |lhs_val| {
9351 if (lhs_val.isUndef()) {9350 if (lhs_val.isUndef()) {
9352 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {9351 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9353 if (maybe_rhs_val) |rhs_val| {9352 if (maybe_rhs_val) |rhs_val| {
9354 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {9353 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9355 return sema.addConstUndef(scalar_type);9354 return sema.addConstUndef(resolved_type);
9356 }9355 }
9357 }9356 }
9358 return sema.failWithUseOfUndef(block, rhs_src);9357 return sema.failWithUseOfUndef(block, rhs_src);
9359 }9358 }
9360 return sema.addConstUndef(scalar_type);9359 return sema.addConstUndef(resolved_type);
9361 }9360 }
93629361
9363 if (maybe_rhs_val) |rhs_val| {9362 if (maybe_rhs_val) |rhs_val| {
9364 if (is_int) {9363 if (is_int) {
9365 return sema.addConstant(9364 return sema.addConstant(
9366 scalar_type,9365 resolved_type,
9367 try lhs_val.intDiv(rhs_val, sema.arena),9366 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
9368 );9367 );
9369 } else {9368 } else {
9370 return sema.addConstant(9369 return sema.addConstant(
9371 scalar_type,9370 resolved_type,
9372 try lhs_val.floatDivTrunc(rhs_val, scalar_type, sema.arena, target),9371 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
9373 );9372 );
9374 }9373 }
9375 } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };9374 } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
...@@ -9398,7 +9397,7 @@ fn analyzeArithmetic(...@@ -9398,7 +9397,7 @@ fn analyzeArithmetic(
9398 if (maybe_lhs_val) |lhs_val| {9397 if (maybe_lhs_val) |lhs_val| {
9399 if (!lhs_val.isUndef()) {9398 if (!lhs_val.isUndef()) {
9400 if (lhs_val.compareWithZero(.eq)) {9399 if (lhs_val.compareWithZero(.eq)) {
9401 return sema.addConstant(scalar_type, Value.zero);9400 return sema.addConstant(resolved_type, Value.zero);
9402 }9401 }
9403 }9402 }
9404 }9403 }
...@@ -9412,27 +9411,27 @@ fn analyzeArithmetic(...@@ -9412,27 +9411,27 @@ fn analyzeArithmetic(
9412 }9411 }
9413 if (maybe_lhs_val) |lhs_val| {9412 if (maybe_lhs_val) |lhs_val| {
9414 if (lhs_val.isUndef()) {9413 if (lhs_val.isUndef()) {
9415 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {9414 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
9416 if (maybe_rhs_val) |rhs_val| {9415 if (maybe_rhs_val) |rhs_val| {
9417 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {9416 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9418 return sema.addConstUndef(scalar_type);9417 return sema.addConstUndef(resolved_type);
9419 }9418 }
9420 }9419 }
9421 return sema.failWithUseOfUndef(block, rhs_src);9420 return sema.failWithUseOfUndef(block, rhs_src);
9422 }9421 }
9423 return sema.addConstUndef(scalar_type);9422 return sema.addConstUndef(resolved_type);
9424 }9423 }
94259424
9426 if (maybe_rhs_val) |rhs_val| {9425 if (maybe_rhs_val) |rhs_val| {
9427 if (is_int) {9426 if (is_int) {
9428 return sema.addConstant(9427 return sema.addConstant(
9429 scalar_type,9428 resolved_type,
9430 try lhs_val.intDivFloor(rhs_val, sema.arena),9429 try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena),
9431 );9430 );
9432 } else {9431 } else {
9433 return sema.addConstant(9432 return sema.addConstant(
9434 scalar_type,9433 resolved_type,
9435 try lhs_val.floatDivFloor(rhs_val, scalar_type, sema.arena, target),9434 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
9436 );9435 );
9437 }9436 }
9438 } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };9437 } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };
...@@ -9460,7 +9459,7 @@ fn analyzeArithmetic(...@@ -9460,7 +9459,7 @@ fn analyzeArithmetic(
9460 return sema.failWithUseOfUndef(block, rhs_src);9459 return sema.failWithUseOfUndef(block, rhs_src);
9461 } else {9460 } else {
9462 if (lhs_val.compareWithZero(.eq)) {9461 if (lhs_val.compareWithZero(.eq)) {
9463 return sema.addConstant(scalar_type, Value.zero);9462 return sema.addConstant(resolved_type, Value.zero);
9464 }9463 }
9465 }9464 }
9466 }9465 }
...@@ -9477,14 +9476,14 @@ fn analyzeArithmetic(...@@ -9477,14 +9476,14 @@ fn analyzeArithmetic(
9477 if (is_int) {9476 if (is_int) {
9478 // TODO: emit compile error if there is a remainder9477 // TODO: emit compile error if there is a remainder
9479 return sema.addConstant(9478 return sema.addConstant(
9480 scalar_type,9479 resolved_type,
9481 try lhs_val.intDiv(rhs_val, sema.arena),9480 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
9482 );9481 );
9483 } else {9482 } else {
9484 // TODO: emit compile error if there is a remainder9483 // TODO: emit compile error if there is a remainder
9485 return sema.addConstant(9484 return sema.addConstant(
9486 scalar_type,9485 resolved_type,
9487 try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),9486 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
9488 );9487 );
9489 }9488 }
9490 } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };9489 } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };
...@@ -9502,9 +9501,9 @@ fn analyzeArithmetic(...@@ -9502,9 +9501,9 @@ fn analyzeArithmetic(
9502 if (maybe_lhs_val) |lhs_val| {9501 if (maybe_lhs_val) |lhs_val| {
9503 if (!lhs_val.isUndef()) {9502 if (!lhs_val.isUndef()) {
9504 if (lhs_val.compareWithZero(.eq)) {9503 if (lhs_val.compareWithZero(.eq)) {
9505 return sema.addConstant(scalar_type, Value.zero);9504 return sema.addConstant(resolved_type, Value.zero);
9506 }9505 }
9507 if (lhs_val.compare(.eq, Value.one, scalar_type)) {9506 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
9508 return casted_rhs;9507 return casted_rhs;
9509 }9508 }
9510 }9509 }
...@@ -9514,13 +9513,13 @@ fn analyzeArithmetic(...@@ -9514,13 +9513,13 @@ fn analyzeArithmetic(
9514 if (is_int) {9513 if (is_int) {
9515 return sema.failWithUseOfUndef(block, rhs_src);9514 return sema.failWithUseOfUndef(block, rhs_src);
9516 } else {9515 } else {
9517 return sema.addConstUndef(scalar_type);9516 return sema.addConstUndef(resolved_type);
9518 }9517 }
9519 }9518 }
9520 if (rhs_val.compareWithZero(.eq)) {9519 if (rhs_val.compareWithZero(.eq)) {
9521 return sema.addConstant(scalar_type, Value.zero);9520 return sema.addConstant(resolved_type, Value.zero);
9522 }9521 }
9523 if (rhs_val.compare(.eq, Value.one, scalar_type)) {9522 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
9524 return casted_lhs;9523 return casted_lhs;
9525 }9524 }
9526 if (maybe_lhs_val) |lhs_val| {9525 if (maybe_lhs_val) |lhs_val| {
...@@ -9528,18 +9527,18 @@ fn analyzeArithmetic(...@@ -9528,18 +9527,18 @@ fn analyzeArithmetic(
9528 if (is_int) {9527 if (is_int) {
9529 return sema.failWithUseOfUndef(block, lhs_src);9528 return sema.failWithUseOfUndef(block, lhs_src);
9530 } else {9529 } else {
9531 return sema.addConstUndef(scalar_type);9530 return sema.addConstUndef(resolved_type);
9532 }9531 }
9533 }9532 }
9534 if (is_int) {9533 if (is_int) {
9535 return sema.addConstant(9534 return sema.addConstant(
9536 scalar_type,9535 resolved_type,
9537 try lhs_val.intMul(rhs_val, sema.arena),9536 try lhs_val.intMul(rhs_val, resolved_type, sema.arena),
9538 );9537 );
9539 } else {9538 } else {
9540 return sema.addConstant(9539 return sema.addConstant(
9541 scalar_type,9540 resolved_type,
9542 try lhs_val.floatMul(rhs_val, scalar_type, sema.arena, target),9541 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
9543 );9542 );
9544 }9543 }
9545 } else break :rs .{ .src = lhs_src, .air_tag = .mul };9544 } else break :rs .{ .src = lhs_src, .air_tag = .mul };
...@@ -9553,30 +9552,30 @@ fn analyzeArithmetic(...@@ -9553,30 +9552,30 @@ fn analyzeArithmetic(
9553 if (maybe_lhs_val) |lhs_val| {9552 if (maybe_lhs_val) |lhs_val| {
9554 if (!lhs_val.isUndef()) {9553 if (!lhs_val.isUndef()) {
9555 if (lhs_val.compareWithZero(.eq)) {9554 if (lhs_val.compareWithZero(.eq)) {
9556 return sema.addConstant(scalar_type, Value.zero);9555 return sema.addConstant(resolved_type, Value.zero);
9557 }9556 }
9558 if (lhs_val.compare(.eq, Value.one, scalar_type)) {9557 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
9559 return casted_rhs;9558 return casted_rhs;
9560 }9559 }
9561 }9560 }
9562 }9561 }
9563 if (maybe_rhs_val) |rhs_val| {9562 if (maybe_rhs_val) |rhs_val| {
9564 if (rhs_val.isUndef()) {9563 if (rhs_val.isUndef()) {
9565 return sema.addConstUndef(scalar_type);9564 return sema.addConstUndef(resolved_type);
9566 }9565 }
9567 if (rhs_val.compareWithZero(.eq)) {9566 if (rhs_val.compareWithZero(.eq)) {
9568 return sema.addConstant(scalar_type, Value.zero);9567 return sema.addConstant(resolved_type, Value.zero);
9569 }9568 }
9570 if (rhs_val.compare(.eq, Value.one, scalar_type)) {9569 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
9571 return casted_lhs;9570 return casted_lhs;
9572 }9571 }
9573 if (maybe_lhs_val) |lhs_val| {9572 if (maybe_lhs_val) |lhs_val| {
9574 if (lhs_val.isUndef()) {9573 if (lhs_val.isUndef()) {
9575 return sema.addConstUndef(scalar_type);9574 return sema.addConstUndef(resolved_type);
9576 }9575 }
9577 return sema.addConstant(9576 return sema.addConstant(
9578 scalar_type,9577 resolved_type,
9579 try lhs_val.numberMulWrap(rhs_val, scalar_type, sema.arena, target),9578 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
9580 );9579 );
9581 } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };9580 } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };
9582 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };9581 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
...@@ -9589,34 +9588,34 @@ fn analyzeArithmetic(...@@ -9589,34 +9588,34 @@ fn analyzeArithmetic(
9589 if (maybe_lhs_val) |lhs_val| {9588 if (maybe_lhs_val) |lhs_val| {
9590 if (!lhs_val.isUndef()) {9589 if (!lhs_val.isUndef()) {
9591 if (lhs_val.compareWithZero(.eq)) {9590 if (lhs_val.compareWithZero(.eq)) {
9592 return sema.addConstant(scalar_type, Value.zero);9591 return sema.addConstant(resolved_type, Value.zero);
9593 }9592 }
9594 if (lhs_val.compare(.eq, Value.one, scalar_type)) {9593 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
9595 return casted_rhs;9594 return casted_rhs;
9596 }9595 }
9597 }9596 }
9598 }9597 }
9599 if (maybe_rhs_val) |rhs_val| {9598 if (maybe_rhs_val) |rhs_val| {
9600 if (rhs_val.isUndef()) {9599 if (rhs_val.isUndef()) {
9601 return sema.addConstUndef(scalar_type);9600 return sema.addConstUndef(resolved_type);
9602 }9601 }
9603 if (rhs_val.compareWithZero(.eq)) {9602 if (rhs_val.compareWithZero(.eq)) {
9604 return sema.addConstant(scalar_type, Value.zero);9603 return sema.addConstant(resolved_type, Value.zero);
9605 }9604 }
9606 if (rhs_val.compare(.eq, Value.one, scalar_type)) {9605 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
9607 return casted_lhs;9606 return casted_lhs;
9608 }9607 }
9609 if (maybe_lhs_val) |lhs_val| {9608 if (maybe_lhs_val) |lhs_val| {
9610 if (lhs_val.isUndef()) {9609 if (lhs_val.isUndef()) {
9611 return sema.addConstUndef(scalar_type);9610 return sema.addConstUndef(resolved_type);
9612 }9611 }
96139612
9614 const val = if (scalar_tag == .ComptimeInt)9613 const val = if (scalar_tag == .ComptimeInt)
9615 try lhs_val.intMul(rhs_val, sema.arena)9614 try lhs_val.intMul(rhs_val, resolved_type, sema.arena)
9616 else9615 else
9617 try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target);9616 try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, target);
96189617
9619 return sema.addConstant(scalar_type, val);9618 return sema.addConstant(resolved_type, val);
9620 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };9619 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
9621 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };9620 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
9622 },9621 },
...@@ -9640,9 +9639,9 @@ fn analyzeArithmetic(...@@ -9640,9 +9639,9 @@ fn analyzeArithmetic(
9640 return sema.failWithUseOfUndef(block, lhs_src);9639 return sema.failWithUseOfUndef(block, lhs_src);
9641 }9640 }
9642 if (lhs_val.compareWithZero(.eq)) {9641 if (lhs_val.compareWithZero(.eq)) {
9643 return sema.addConstant(scalar_type, Value.zero);9642 return sema.addConstant(resolved_type, Value.zero);
9644 }9643 }
9645 } else if (lhs_ty.isSignedInt()) {9644 } else if (lhs_scalar_ty.isSignedInt()) {
9646 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);9645 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
9647 }9646 }
9648 if (maybe_rhs_val) |rhs_val| {9647 if (maybe_rhs_val) |rhs_val| {
...@@ -9653,7 +9652,7 @@ fn analyzeArithmetic(...@@ -9653,7 +9652,7 @@ fn analyzeArithmetic(
9653 return sema.failWithDivideByZero(block, rhs_src);9652 return sema.failWithDivideByZero(block, rhs_src);
9654 }9653 }
9655 if (maybe_lhs_val) |lhs_val| {9654 if (maybe_lhs_val) |lhs_val| {
9656 const rem_result = try lhs_val.intRem(rhs_val, sema.arena);9655 const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena);
9657 // If this answer could possibly be different by doing `intMod`,9656 // If this answer could possibly be different by doing `intMod`,
9658 // we must emit a compile error. Otherwise, it's OK.9657 // we must emit a compile error. Otherwise, it's OK.
9659 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and9658 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and
...@@ -9667,12 +9666,12 @@ fn analyzeArithmetic(...@@ -9667,12 +9666,12 @@ fn analyzeArithmetic(
9667 }9666 }
9668 if (lhs_val.compareWithZero(.lt)) {9667 if (lhs_val.compareWithZero(.lt)) {
9669 // Negative9668 // Negative
9670 return sema.addConstant(scalar_type, Value.zero);9669 return sema.addConstant(resolved_type, Value.zero);
9671 }9670 }
9672 return sema.addConstant(scalar_type, rem_result);9671 return sema.addConstant(resolved_type, rem_result);
9673 }9672 }
9674 break :rs .{ .src = lhs_src, .air_tag = .rem };9673 break :rs .{ .src = lhs_src, .air_tag = .rem };
9675 } else if (rhs_ty.isSignedInt()) {9674 } else if (rhs_scalar_ty.isSignedInt()) {
9676 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);9675 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
9677 } else {9676 } else {
9678 break :rs .{ .src = rhs_src, .air_tag = .rem };9677 break :rs .{ .src = rhs_src, .air_tag = .rem };
...@@ -9694,8 +9693,8 @@ fn analyzeArithmetic(...@@ -9694,8 +9693,8 @@ fn analyzeArithmetic(
9694 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);9693 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
9695 }9694 }
9696 return sema.addConstant(9695 return sema.addConstant(
9697 scalar_type,9696 resolved_type,
9698 try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),9697 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
9699 );9698 );
9700 } else {9699 } else {
9701 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);9700 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
...@@ -9731,8 +9730,8 @@ fn analyzeArithmetic(...@@ -9731,8 +9730,8 @@ fn analyzeArithmetic(
9731 }9730 }
9732 if (maybe_lhs_val) |lhs_val| {9731 if (maybe_lhs_val) |lhs_val| {
9733 return sema.addConstant(9732 return sema.addConstant(
9734 scalar_type,9733 resolved_type,
9735 try lhs_val.intRem(rhs_val, sema.arena),9734 try lhs_val.intRem(rhs_val, resolved_type, sema.arena),
9736 );9735 );
9737 }9736 }
9738 break :rs .{ .src = lhs_src, .air_tag = .rem };9737 break :rs .{ .src = lhs_src, .air_tag = .rem };
...@@ -9751,12 +9750,12 @@ fn analyzeArithmetic(...@@ -9751,12 +9750,12 @@ fn analyzeArithmetic(
9751 }9750 }
9752 if (maybe_lhs_val) |lhs_val| {9751 if (maybe_lhs_val) |lhs_val| {
9753 if (lhs_val.isUndef()) {9752 if (lhs_val.isUndef()) {
9754 return sema.addConstUndef(scalar_type);9753 return sema.addConstUndef(resolved_type);
9755 }9754 }
9756 if (maybe_rhs_val) |rhs_val| {9755 if (maybe_rhs_val) |rhs_val| {
9757 return sema.addConstant(9756 return sema.addConstant(
9758 scalar_type,9757 resolved_type,
9759 try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),9758 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
9760 );9759 );
9761 } else break :rs .{ .src = rhs_src, .air_tag = .rem };9760 } else break :rs .{ .src = rhs_src, .air_tag = .rem };
9762 } else break :rs .{ .src = lhs_src, .air_tag = .rem };9761 } else break :rs .{ .src = lhs_src, .air_tag = .rem };
...@@ -9788,8 +9787,8 @@ fn analyzeArithmetic(...@@ -9788,8 +9787,8 @@ fn analyzeArithmetic(
9788 }9787 }
9789 if (maybe_lhs_val) |lhs_val| {9788 if (maybe_lhs_val) |lhs_val| {
9790 return sema.addConstant(9789 return sema.addConstant(
9791 scalar_type,9790 resolved_type,
9792 try lhs_val.intMod(rhs_val, sema.arena),9791 try lhs_val.intMod(rhs_val, resolved_type, sema.arena),
9793 );9792 );
9794 }9793 }
9795 break :rs .{ .src = lhs_src, .air_tag = .mod };9794 break :rs .{ .src = lhs_src, .air_tag = .mod };
...@@ -9808,12 +9807,12 @@ fn analyzeArithmetic(...@@ -9808,12 +9807,12 @@ fn analyzeArithmetic(
9808 }9807 }
9809 if (maybe_lhs_val) |lhs_val| {9808 if (maybe_lhs_val) |lhs_val| {
9810 if (lhs_val.isUndef()) {9809 if (lhs_val.isUndef()) {
9811 return sema.addConstUndef(scalar_type);9810 return sema.addConstUndef(resolved_type);
9812 }9811 }
9813 if (maybe_rhs_val) |rhs_val| {9812 if (maybe_rhs_val) |rhs_val| {
9814 return sema.addConstant(9813 return sema.addConstant(
9815 scalar_type,9814 resolved_type,
9816 try lhs_val.floatMod(rhs_val, scalar_type, sema.arena, target),9815 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
9817 );9816 );
9818 } else break :rs .{ .src = rhs_src, .air_tag = .mod };9817 } else break :rs .{ .src = rhs_src, .air_tag = .mod };
9819 } else break :rs .{ .src = lhs_src, .air_tag = .mod };9818 } else break :rs .{ .src = lhs_src, .air_tag = .mod };
...@@ -10164,6 +10163,11 @@ fn analyzeCmp(...@@ -10164,6 +10163,11 @@ fn analyzeCmp(
10164) CompileError!Air.Inst.Ref {10163) CompileError!Air.Inst.Ref {
10165 const lhs_ty = sema.typeOf(lhs);10164 const lhs_ty = sema.typeOf(lhs);
10166 const rhs_ty = sema.typeOf(rhs);10165 const rhs_ty = sema.typeOf(rhs);
10166 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
10167
10168 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
10169 return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src);
10170 }
10167 if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {10171 if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {
10168 // This operation allows any combination of integer and float types, regardless of the10172 // This operation allows any combination of integer and float types, regardless of the
10169 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for10173 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
...@@ -10198,6 +10202,12 @@ fn cmpSelf(...@@ -10198,6 +10202,12 @@ fn cmpSelf(
10198 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {10202 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
10199 if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);10203 if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
1020010204
10205 if (resolved_type.zigTypeTag() == .Vector) {
10206 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
10207 const cmp_val = try lhs_val.compareVector(op, rhs_val, resolved_type, sema.arena);
10208 return sema.addConstant(result_ty, cmp_val);
10209 }
10210
10201 if (lhs_val.compare(op, rhs_val, resolved_type)) {10211 if (lhs_val.compare(op, rhs_val, resolved_type)) {
10202 return Air.Inst.Ref.bool_true;10212 return Air.Inst.Ref.bool_true;
10203 } else {10213 } else {
...@@ -10223,16 +10233,12 @@ fn cmpSelf(...@@ -10223,16 +10233,12 @@ fn cmpSelf(
10223 }10233 }
10224 };10234 };
10225 try sema.requireRuntimeBlock(block, runtime_src);10235 try sema.requireRuntimeBlock(block, runtime_src);
1022610236 if (resolved_type.zigTypeTag() == .Vector) {
10227 const tag: Air.Inst.Tag = switch (op) {10237 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
10228 .lt => .cmp_lt,10238 const result_ty_ref = try sema.addType(result_ty);
10229 .lte => .cmp_lte,10239 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
10230 .eq => .cmp_eq,10240 }
10231 .gte => .cmp_gte,10241 const tag = Air.Inst.Tag.fromCmpOp(op);
10232 .gt => .cmp_gt,
10233 .neq => .cmp_neq,
10234 };
10235 // TODO handle vectors
10236 return block.addBinOp(tag, casted_lhs, casted_rhs);10242 return block.addBinOp(tag, casted_lhs, casted_rhs);
10237}10243}
1023810244
...@@ -11353,7 +11359,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi...@@ -11353,7 +11359,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
11353 const elem_ty = operand.elemType2();11359 const elem_ty = operand.elemType2();
11354 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);11360 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
11355 return Type.Tag.vector.create(sema.arena, .{11361 return Type.Tag.vector.create(sema.arena, .{
11356 .len = operand.arrayLen(),11362 .len = operand.vectorLen(),
11357 .elem_type = log2_elem_ty,11363 .elem_type = log2_elem_ty,
11358 });11364 });
11359 },11365 },
...@@ -13284,7 +13290,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -13284,7 +13290,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1328413290
13285 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {13291 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
13286 const target = sema.mod.getTarget();13292 const target = sema.mod.getTarget();
13287 const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {13293 const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) {
13288 error.FloatCannotFit => {13294 error.FloatCannotFit => {
13289 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });13295 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
13290 },13296 },
...@@ -13311,7 +13317,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -13311,7 +13317,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1331113317
13312 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {13318 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
13313 const target = sema.mod.getTarget();13319 const target = sema.mod.getTarget();
13314 const result_val = try val.intToFloat(sema.arena, dest_ty, target);13320 const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
13315 return sema.addConstant(dest_ty, result_val);13321 return sema.addConstant(dest_ty, result_val);
13316 }13322 }
1331713323
...@@ -13521,14 +13527,14 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13521,14 +13527,14 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13521 if (!is_vector) {13527 if (!is_vector) {
13522 return sema.addConstant(13528 return sema.addConstant(
13523 dest_ty,13529 dest_ty,
13524 try val.intTrunc(sema.arena, dest_info.signedness, dest_info.bits),13530 try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits),
13525 );13531 );
13526 }13532 }
13527 var elem_buf: Value.ElemValueBuffer = undefined;13533 var elem_buf: Value.ElemValueBuffer = undefined;
13528 const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());13534 const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());
13529 for (elems) |*elem, i| {13535 for (elems) |*elem, i| {
13530 const elem_val = val.elemValueBuffer(i, &elem_buf);13536 const elem_val = val.elemValueBuffer(i, &elem_buf);
13531 elem.* = try elem_val.intTrunc(sema.arena, dest_info.signedness, dest_info.bits);13537 elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits);
13532 }13538 }
13533 return sema.addConstant(13539 return sema.addConstant(
13534 dest_ty,13540 dest_ty,
...@@ -14083,13 +14089,40 @@ fn checkSimdBinOp(...@@ -14083,13 +14089,40 @@ fn checkSimdBinOp(
14083) CompileError!SimdBinOp {14089) CompileError!SimdBinOp {
14084 const lhs_ty = sema.typeOf(uncasted_lhs);14090 const lhs_ty = sema.typeOf(uncasted_lhs);
14085 const rhs_ty = sema.typeOf(uncasted_rhs);14091 const rhs_ty = sema.typeOf(uncasted_rhs);
14092
14093 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
14094 var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
14095 const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
14096 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
14097 });
14098 const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
14099 const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
14100
14101 return SimdBinOp{
14102 .len = vec_len,
14103 .lhs = lhs,
14104 .rhs = rhs,
14105 .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs),
14106 .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs),
14107 .result_ty = result_ty,
14108 .scalar_ty = result_ty.scalarType(),
14109 };
14110}
14111
14112fn checkVectorizableBinaryOperands(
14113 sema: *Sema,
14114 block: *Block,
14115 src: LazySrcLoc,
14116 lhs_ty: Type,
14117 rhs_ty: Type,
14118 lhs_src: LazySrcLoc,
14119 rhs_src: LazySrcLoc,
14120) CompileError!void {
14086 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();14121 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
14087 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();14122 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
14088
14089 var vec_len: ?usize = null;
14090 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {14123 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
14091 const lhs_len = lhs_ty.arrayLen();14124 const lhs_len = lhs_ty.vectorLen();
14092 const rhs_len = rhs_ty.arrayLen();14125 const rhs_len = rhs_ty.vectorLen();
14093 if (lhs_len != rhs_len) {14126 if (lhs_len != rhs_len) {
14094 const msg = msg: {14127 const msg = msg: {
14095 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});14128 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
...@@ -14100,7 +14133,6 @@ fn checkSimdBinOp(...@@ -14100,7 +14133,6 @@ fn checkSimdBinOp(
14100 };14133 };
14101 return sema.failWithOwnedErrorMsg(block, msg);14134 return sema.failWithOwnedErrorMsg(block, msg);
14102 }14135 }
14103 vec_len = try sema.usizeCast(block, lhs_src, lhs_len);
14104 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {14136 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
14105 const msg = msg: {14137 const msg = msg: {
14106 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{14138 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{
...@@ -14118,21 +14150,6 @@ fn checkSimdBinOp(...@@ -14118,21 +14150,6 @@ fn checkSimdBinOp(
14118 };14150 };
14119 return sema.failWithOwnedErrorMsg(block, msg);14151 return sema.failWithOwnedErrorMsg(block, msg);
14120 }14152 }
14121 const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
14122 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
14123 });
14124 const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
14125 const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
14126
14127 return SimdBinOp{
14128 .len = vec_len,
14129 .lhs = lhs,
14130 .rhs = rhs,
14131 .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs),
14132 .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs),
14133 .result_ty = result_ty,
14134 .scalar_ty = result_ty.scalarType(),
14135 };
14136}14153}
1413714154
14138fn resolveExportOptions(14155fn resolveExportOptions(
...@@ -14362,9 +14379,9 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -14362,9 +14379,9 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
14362 while (i < vec_len) : (i += 1) {14379 while (i < vec_len) : (i += 1) {
14363 const elem_val = operand_val.elemValueBuffer(i, &elem_buf);14380 const elem_val = operand_val.elemValueBuffer(i, &elem_buf);
14364 switch (operation) {14381 switch (operation) {
14365 .And => accum = try accum.bitwiseAnd(elem_val, sema.arena),14382 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena),
14366 .Or => accum = try accum.bitwiseOr(elem_val, sema.arena),14383 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena),
14367 .Xor => accum = try accum.bitwiseXor(elem_val, sema.arena),14384 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena),
14368 .Min => accum = accum.numberMin(elem_val),14385 .Min => accum = accum.numberMin(elem_val),
14369 .Max => accum = accum.numberMax(elem_val),14386 .Max => accum = accum.numberMax(elem_val),
14370 .Add => accum = try accum.numberAddWrap(elem_val, scalar_ty, sema.arena, target),14387 .Add => accum = try accum.numberAddWrap(elem_val, scalar_ty, sema.arena, target),
...@@ -14683,10 +14700,10 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -14683,10 +14700,10 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
14683 .Xchg => operand_val,14700 .Xchg => operand_val,
14684 .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),14701 .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),
14685 .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target),14702 .Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target),
14686 .And => try stored_val.bitwiseAnd (operand_val, sema.arena),14703 .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena),
14687 .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),14704 .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),
14688 .Or => try stored_val.bitwiseOr (operand_val, sema.arena),14705 .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena),
14689 .Xor => try stored_val.bitwiseXor (operand_val, sema.arena),14706 .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena),
14690 .Max => stored_val.numberMax (operand_val),14707 .Max => stored_val.numberMax (operand_val),
14691 .Min => stored_val.numberMin (operand_val),14708 .Min => stored_val.numberMin (operand_val),
14692 // zig fmt: on14709 // zig fmt: on
...@@ -17509,7 +17526,7 @@ fn coerce(...@@ -17509,7 +17526,7 @@ fn coerce(
17509 if (val.floatHasFraction()) {17526 if (val.floatHasFraction()) {
17510 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty });17527 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty });
17511 }17528 }
17512 const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {17529 const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) {
17513 error.FloatCannotFit => {17530 error.FloatCannotFit => {
17514 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });17531 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
17515 },17532 },
...@@ -17572,7 +17589,7 @@ fn coerce(...@@ -17572,7 +17589,7 @@ fn coerce(
17572 },17589 },
17573 .Int, .ComptimeInt => int: {17590 .Int, .ComptimeInt => int: {
17574 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int;17591 const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int;
17575 const result_val = try val.intToFloat(sema.arena, dest_ty, target);17592 const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target);
17576 // TODO implement this compile error17593 // TODO implement this compile error
17577 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);17594 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
17578 //if (!int_again_val.eql(val, inst_ty)) {17595 //if (!int_again_val.eql(val, inst_ty)) {
...@@ -17809,8 +17826,21 @@ fn coerceInMemoryAllowed(...@@ -17809,8 +17826,21 @@ fn coerceInMemoryAllowed(
17809 return .ok;17826 return .ok;
17810 }17827 }
1781117828
17829 // Vectors
17830 if (dest_tag == .Vector and src_tag == .Vector) vectors: {
17831 const dest_len = dest_ty.vectorLen();
17832 const src_len = src_ty.vectorLen();
17833 if (dest_len != src_len) break :vectors;
17834
17835 const dest_elem_ty = dest_ty.scalarType();
17836 const src_elem_ty = src_ty.scalarType();
17837 const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
17838 if (child == .no_match) break :vectors;
17839
17840 return .ok;
17841 }
17842
17812 // TODO: non-pointer-like optionals17843 // TODO: non-pointer-like optionals
17813 // TODO: vectors
1781417844
17815 return .no_match;17845 return .no_match;
17816}17846}
...@@ -19683,19 +19713,6 @@ fn cmpNumeric(...@@ -19683,19 +19713,6 @@ fn cmpNumeric(
19683 const lhs_ty_tag = lhs_ty.zigTypeTag();19713 const lhs_ty_tag = lhs_ty.zigTypeTag();
19684 const rhs_ty_tag = rhs_ty.zigTypeTag();19714 const rhs_ty_tag = rhs_ty.zigTypeTag();
1968519715
19686 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
19687 if (lhs_ty.vectorLen() != rhs_ty.vectorLen()) {
19688 return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
19689 lhs_ty.vectorLen(), rhs_ty.vectorLen(),
19690 });
19691 }
19692 return sema.fail(block, src, "TODO implement support for vectors in cmpNumeric", .{});
19693 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
19694 return sema.fail(block, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
19695 lhs_ty, rhs_ty,
19696 });
19697 }
19698
19699 const runtime_src: LazySrcLoc = src: {19716 const runtime_src: LazySrcLoc = src: {
19700 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {19717 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
19701 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {19718 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
...@@ -19881,6 +19898,46 @@ fn cmpNumeric(...@@ -19881,6 +19898,46 @@ fn cmpNumeric(
19881 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);19898 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
19882}19899}
1988319900
19901/// Asserts that lhs and rhs types are both vectors.
19902fn cmpVector(
19903 sema: *Sema,
19904 block: *Block,
19905 src: LazySrcLoc,
19906 lhs: Air.Inst.Ref,
19907 rhs: Air.Inst.Ref,
19908 op: std.math.CompareOperator,
19909 lhs_src: LazySrcLoc,
19910 rhs_src: LazySrcLoc,
19911) CompileError!Air.Inst.Ref {
19912 const lhs_ty = sema.typeOf(lhs);
19913 const rhs_ty = sema.typeOf(rhs);
19914 assert(lhs_ty.zigTypeTag() == .Vector);
19915 assert(rhs_ty.zigTypeTag() == .Vector);
19916 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
19917
19918 const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.@"bool");
19919
19920 const runtime_src: LazySrcLoc = src: {
19921 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
19922 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
19923 if (lhs_val.isUndef() or rhs_val.isUndef()) {
19924 return sema.addConstUndef(result_ty);
19925 }
19926 const cmp_val = try lhs_val.compareVector(op, rhs_val, lhs_ty, sema.arena);
19927 return sema.addConstant(result_ty, cmp_val);
19928 } else {
19929 break :src rhs_src;
19930 }
19931 } else {
19932 break :src lhs_src;
19933 }
19934 };
19935
19936 try sema.requireRuntimeBlock(block, runtime_src);
19937 const result_ty_inst = try sema.addType(result_ty);
19938 return block.addCmpVector(lhs, rhs, op, result_ty_inst);
19939}
19940
19884fn wrapOptional(19941fn wrapOptional(
19885 sema: *Sema,19942 sema: *Sema,
19886 block: *Block,19943 block: *Block,
...@@ -21187,7 +21244,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -21187,7 +21244,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
21187 map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty });21244 map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty });
21188 } else {21245 } else {
21189 const val = if (last_tag_val) |val|21246 const val = if (last_tag_val) |val|
21190 try val.intAdd(Value.one, sema.arena)21247 try val.intAdd(Value.one, int_tag_ty, sema.arena)
21191 else21248 else
21192 Value.zero;21249 Value.zero;
21193 last_tag_val = val;21250 last_tag_val = val;
src/arch/aarch64/CodeGen.zig+6
...@@ -577,6 +577,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -577,6 +577,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
577 .cmp_gte => try self.airCmp(inst, .gte),577 .cmp_gte => try self.airCmp(inst, .gte),
578 .cmp_gt => try self.airCmp(inst, .gt),578 .cmp_gt => try self.airCmp(inst, .gt),
579 .cmp_neq => try self.airCmp(inst, .neq),579 .cmp_neq => try self.airCmp(inst, .neq),
580 .cmp_vector => try self.airCmpVector(inst),
580581
581 .bool_and => try self.airBinOp(inst),582 .bool_and => try self.airBinOp(inst),
582 .bool_or => try self.airBinOp(inst),583 .bool_or => try self.airBinOp(inst),
...@@ -2713,6 +2714,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2713,6 +2714,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2713 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2714 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2714}2715}
27152716
2717fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
2718 _ = inst;
2719 return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
2720}
2721
2716fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {2722fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
2717 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;2723 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
27182724
src/arch/arm/CodeGen.zig+6-1
...@@ -567,6 +567,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -567,6 +567,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
567 .cmp_gte => try self.airCmp(inst, .gte),567 .cmp_gte => try self.airCmp(inst, .gte),
568 .cmp_gt => try self.airCmp(inst, .gt),568 .cmp_gt => try self.airCmp(inst, .gt),
569 .cmp_neq => try self.airCmp(inst, .neq),569 .cmp_neq => try self.airCmp(inst, .neq),
570 .cmp_vector => try self.airCmpVector(inst),
570571
571 .bool_and => try self.airBinOp(inst),572 .bool_and => try self.airBinOp(inst),
572 .bool_or => try self.airBinOp(inst),573 .bool_or => try self.airBinOp(inst),
...@@ -2894,7 +2895,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2894,7 +2895,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2894 const lhs_ty = self.air.typeOf(bin_op.lhs);2895 const lhs_ty = self.air.typeOf(bin_op.lhs);
28952896
2896 switch (lhs_ty.zigTypeTag()) {2897 switch (lhs_ty.zigTypeTag()) {
2897 .Vector => return self.fail("TODO ARM cmp vectors", .{}),
2898 .Optional => return self.fail("TODO ARM cmp optionals", .{}),2898 .Optional => return self.fail("TODO ARM cmp optionals", .{}),
2899 .Float => return self.fail("TODO ARM cmp floats", .{}),2899 .Float => return self.fail("TODO ARM cmp floats", .{}),
2900 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {2900 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {
...@@ -2929,6 +2929,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -2929,6 +2929,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
2929 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2929 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2930}2930}
29312931
2932fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
2933 _ = inst;
2934 return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
2935}
2936
2932fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {2937fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
2933 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;2938 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
29342939
src/arch/riscv64/CodeGen.zig+6
...@@ -537,6 +537,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -537,6 +537,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
537 .cmp_gte => try self.airCmp(inst, .gte),537 .cmp_gte => try self.airCmp(inst, .gte),
538 .cmp_gt => try self.airCmp(inst, .gt),538 .cmp_gt => try self.airCmp(inst, .gt),
539 .cmp_neq => try self.airCmp(inst, .neq),539 .cmp_neq => try self.airCmp(inst, .neq),
540 .cmp_vector => try self.airCmpVector(inst),
540541
541 .bool_and => try self.airBoolOp(inst),542 .bool_and => try self.airBoolOp(inst),
542 .bool_or => try self.airBoolOp(inst),543 .bool_or => try self.airBoolOp(inst),
...@@ -1791,6 +1792,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -1791,6 +1792,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
1791 // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1792 // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1792}1793}
17931794
1795fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
1796 _ = inst;
1797 return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
1798}
1799
1794fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {1800fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
1795 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;1801 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
17961802
src/arch/wasm/CodeGen.zig+6
...@@ -1309,6 +1309,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1309,6 +1309,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1309 .cmp_lte => self.airCmp(inst, .lte),1309 .cmp_lte => self.airCmp(inst, .lte),
1310 .cmp_lt => self.airCmp(inst, .lt),1310 .cmp_lt => self.airCmp(inst, .lt),
1311 .cmp_neq => self.airCmp(inst, .neq),1311 .cmp_neq => self.airCmp(inst, .neq),
1312 .cmp_vector => self.airCmpVector(inst),
13121313
1313 .array_elem_val => self.airArrayElemVal(inst),1314 .array_elem_val => self.airArrayElemVal(inst),
1314 .array_to_slice => self.airArrayToSlice(inst),1315 .array_to_slice => self.airArrayToSlice(inst),
...@@ -2222,6 +2223,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2222,6 +2223,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2222 return cmp_tmp;2223 return cmp_tmp;
2223}2224}
22242225
2226fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2227 _ = inst;
2228 return self.fail("TODO implement airCmpVector for wasm", .{});
2229}
2230
2225fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2231fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2226 const br = self.air.instructions.items(.data)[inst].br;2232 const br = self.air.instructions.items(.data)[inst].br;
2227 const block = self.blocks.get(br.block_inst).?;2233 const block = self.blocks.get(br.block_inst).?;
src/arch/x86_64/CodeGen.zig+6
...@@ -658,6 +658,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -658,6 +658,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
658 .cmp_gte => try self.airCmp(inst, .gte),658 .cmp_gte => try self.airCmp(inst, .gte),
659 .cmp_gt => try self.airCmp(inst, .gt),659 .cmp_gt => try self.airCmp(inst, .gt),
660 .cmp_neq => try self.airCmp(inst, .neq),660 .cmp_neq => try self.airCmp(inst, .neq),
661 .cmp_vector => try self.airCmpVector(inst),
661662
662 .bool_and => try self.airBoolOp(inst),663 .bool_and => try self.airBoolOp(inst),
663 .bool_or => try self.airBoolOp(inst),664 .bool_or => try self.airBoolOp(inst),
...@@ -3699,6 +3700,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {...@@ -3699,6 +3700,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
3699 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });3700 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
3700}3701}
37013702
3703fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
3704 _ = inst;
3705 return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
3706}
3707
3702fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {3708fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
3703 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;3709 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
3704 const payload = try self.addExtra(Mir.DbgLineColumn{3710 const payload = try self.addExtra(Mir.DbgLineColumn{
src/codegen/c.zig+2
...@@ -1715,6 +1715,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1715,6 +1715,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1715 .cmp_eq => try airEquality(f, inst, "((", "=="),1715 .cmp_eq => try airEquality(f, inst, "((", "=="),
1716 .cmp_neq => try airEquality(f, inst, "!((", "!="),1716 .cmp_neq => try airEquality(f, inst, "!((", "!="),
17171717
1718 .cmp_vector => return f.fail("TODO: C backend: implement binary op for tag '{s}'", .{@tagName(Air.Inst.Tag.cmp_vector)}),
1719
1718 // bool_and and bool_or are non-short-circuit operations1720 // bool_and and bool_or are non-short-circuit operations
1719 .bool_and => try airBinOp(f, inst, " & "),1721 .bool_and => try airBinOp(f, inst, " & "),
1720 .bool_or => try airBinOp(f, inst, " | "),1722 .bool_or => try airBinOp(f, inst, " | "),
src/codegen/llvm.zig+101-43
...@@ -3375,6 +3375,7 @@ pub const FuncGen = struct {...@@ -3375,6 +3375,7 @@ pub const FuncGen = struct {
3375 .cmp_lt => try self.airCmp(inst, .lt),3375 .cmp_lt => try self.airCmp(inst, .lt),
3376 .cmp_lte => try self.airCmp(inst, .lte),3376 .cmp_lte => try self.airCmp(inst, .lte),
3377 .cmp_neq => try self.airCmp(inst, .neq),3377 .cmp_neq => try self.airCmp(inst, .neq),
3378 .cmp_vector => try self.airCmpVector(inst),
33783379
3379 .is_non_null => try self.airIsNonNull(inst, false, false, .NE),3380 .is_non_null => try self.airIsNonNull(inst, false, false, .NE),
3380 .is_non_null_ptr => try self.airIsNonNull(inst, true , false, .NE),3381 .is_non_null_ptr => try self.airIsNonNull(inst, true , false, .NE),
...@@ -3640,6 +3641,20 @@ pub const FuncGen = struct {...@@ -3640,6 +3641,20 @@ pub const FuncGen = struct {
3640 return self.cmp(lhs, rhs, operand_ty, op);3641 return self.cmp(lhs, rhs, operand_ty, op);
3641 }3642 }
36423643
3644 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3645 if (self.liveness.isUnused(inst)) return null;
3646
3647 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3648 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
3649
3650 const lhs = try self.resolveInst(extra.lhs);
3651 const rhs = try self.resolveInst(extra.rhs);
3652 const vec_ty = self.air.typeOf(extra.lhs);
3653 const cmp_op = extra.compareOperator();
3654
3655 return self.cmp(lhs, rhs, vec_ty, cmp_op);
3656 }
3657
3643 fn cmp(3658 fn cmp(
3644 self: *FuncGen,3659 self: *FuncGen,
3645 lhs: *const llvm.Value,3660 lhs: *const llvm.Value,
...@@ -3650,9 +3665,10 @@ pub const FuncGen = struct {...@@ -3650,9 +3665,10 @@ pub const FuncGen = struct {
3650 var int_buffer: Type.Payload.Bits = undefined;3665 var int_buffer: Type.Payload.Bits = undefined;
3651 var opt_buffer: Type.Payload.ElemType = undefined;3666 var opt_buffer: Type.Payload.ElemType = undefined;
36523667
3653 const int_ty = switch (operand_ty.zigTypeTag()) {3668 const scalar_ty = operand_ty.scalarType();
3654 .Enum => operand_ty.intTagType(&int_buffer),3669 const int_ty = switch (scalar_ty.zigTypeTag()) {
3655 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,3670 .Enum => scalar_ty.intTagType(&int_buffer),
3671 .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
3656 .Optional => blk: {3672 .Optional => blk: {
3657 const payload_ty = operand_ty.optionalChild(&opt_buffer);3673 const payload_ty = operand_ty.optionalChild(&opt_buffer);
3658 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {3674 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {
...@@ -3944,10 +3960,11 @@ pub const FuncGen = struct {...@@ -3944,10 +3960,11 @@ pub const FuncGen = struct {
3944 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3960 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3945 const operand = try self.resolveInst(ty_op.operand);3961 const operand = try self.resolveInst(ty_op.operand);
3946 const operand_ty = self.air.typeOf(ty_op.operand);3962 const operand_ty = self.air.typeOf(ty_op.operand);
3963 const operand_scalar_ty = operand_ty.scalarType();
3947 const dest_ty = self.air.typeOfIndex(inst);3964 const dest_ty = self.air.typeOfIndex(inst);
3948 const dest_llvm_ty = try self.dg.llvmType(dest_ty);3965 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
39493966
3950 if (operand_ty.isSignedInt()) {3967 if (operand_scalar_ty.isSignedInt()) {
3951 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");3968 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");
3952 } else {3969 } else {
3953 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");3970 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");
...@@ -3961,11 +3978,12 @@ pub const FuncGen = struct {...@@ -3961,11 +3978,12 @@ pub const FuncGen = struct {
3961 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3978 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3962 const operand = try self.resolveInst(ty_op.operand);3979 const operand = try self.resolveInst(ty_op.operand);
3963 const dest_ty = self.air.typeOfIndex(inst);3980 const dest_ty = self.air.typeOfIndex(inst);
3981 const dest_scalar_ty = dest_ty.scalarType();
3964 const dest_llvm_ty = try self.dg.llvmType(dest_ty);3982 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
39653983
3966 // TODO set fast math flag3984 // TODO set fast math flag
39673985
3968 if (dest_ty.isSignedInt()) {3986 if (dest_scalar_ty.isSignedInt()) {
3969 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");3987 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");
3970 } else {3988 } else {
3971 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");3989 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");
...@@ -4896,9 +4914,10 @@ pub const FuncGen = struct {...@@ -4896,9 +4914,10 @@ pub const FuncGen = struct {
4896 const lhs = try self.resolveInst(bin_op.lhs);4914 const lhs = try self.resolveInst(bin_op.lhs);
4897 const rhs = try self.resolveInst(bin_op.rhs);4915 const rhs = try self.resolveInst(bin_op.rhs);
4898 const inst_ty = self.air.typeOfIndex(inst);4916 const inst_ty = self.air.typeOfIndex(inst);
4917 const scalar_ty = inst_ty.scalarType();
48994918
4900 if (inst_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");4919 if (scalar_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");
4901 if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");4920 if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
4902 return self.builder.buildNUWAdd(lhs, rhs, "");4921 return self.builder.buildNUWAdd(lhs, rhs, "");
4903 }4922 }
49044923
...@@ -4919,9 +4938,10 @@ pub const FuncGen = struct {...@@ -4919,9 +4938,10 @@ pub const FuncGen = struct {
4919 const lhs = try self.resolveInst(bin_op.lhs);4938 const lhs = try self.resolveInst(bin_op.lhs);
4920 const rhs = try self.resolveInst(bin_op.rhs);4939 const rhs = try self.resolveInst(bin_op.rhs);
4921 const inst_ty = self.air.typeOfIndex(inst);4940 const inst_ty = self.air.typeOfIndex(inst);
4941 const scalar_ty = inst_ty.scalarType();
49224942
4923 if (inst_ty.isAnyFloat()) return self.todo("saturating float add", .{});4943 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
4924 if (inst_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");4944 if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
49254945
4926 return self.builder.buildUAddSat(lhs, rhs, "");4946 return self.builder.buildUAddSat(lhs, rhs, "");
4927 }4947 }
...@@ -4933,9 +4953,10 @@ pub const FuncGen = struct {...@@ -4933,9 +4953,10 @@ pub const FuncGen = struct {
4933 const lhs = try self.resolveInst(bin_op.lhs);4953 const lhs = try self.resolveInst(bin_op.lhs);
4934 const rhs = try self.resolveInst(bin_op.rhs);4954 const rhs = try self.resolveInst(bin_op.rhs);
4935 const inst_ty = self.air.typeOfIndex(inst);4955 const inst_ty = self.air.typeOfIndex(inst);
4956 const scalar_ty = inst_ty.scalarType();
49364957
4937 if (inst_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");4958 if (scalar_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");
4938 if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");4959 if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
4939 return self.builder.buildNUWSub(lhs, rhs, "");4960 return self.builder.buildNUWSub(lhs, rhs, "");
4940 }4961 }
49414962
...@@ -4956,9 +4977,10 @@ pub const FuncGen = struct {...@@ -4956,9 +4977,10 @@ pub const FuncGen = struct {
4956 const lhs = try self.resolveInst(bin_op.lhs);4977 const lhs = try self.resolveInst(bin_op.lhs);
4957 const rhs = try self.resolveInst(bin_op.rhs);4978 const rhs = try self.resolveInst(bin_op.rhs);
4958 const inst_ty = self.air.typeOfIndex(inst);4979 const inst_ty = self.air.typeOfIndex(inst);
4980 const scalar_ty = inst_ty.scalarType();
49594981
4960 if (inst_ty.isAnyFloat()) return self.todo("saturating float sub", .{});4982 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
4961 if (inst_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");4983 if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
4962 return self.builder.buildUSubSat(lhs, rhs, "");4984 return self.builder.buildUSubSat(lhs, rhs, "");
4963 }4985 }
49644986
...@@ -4969,9 +4991,10 @@ pub const FuncGen = struct {...@@ -4969,9 +4991,10 @@ pub const FuncGen = struct {
4969 const lhs = try self.resolveInst(bin_op.lhs);4991 const lhs = try self.resolveInst(bin_op.lhs);
4970 const rhs = try self.resolveInst(bin_op.rhs);4992 const rhs = try self.resolveInst(bin_op.rhs);
4971 const inst_ty = self.air.typeOfIndex(inst);4993 const inst_ty = self.air.typeOfIndex(inst);
4994 const scalar_ty = inst_ty.scalarType();
49724995
4973 if (inst_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");4996 if (scalar_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");
4974 if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");4997 if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
4975 return self.builder.buildNUWMul(lhs, rhs, "");4998 return self.builder.buildNUWMul(lhs, rhs, "");
4976 }4999 }
49775000
...@@ -4992,9 +5015,10 @@ pub const FuncGen = struct {...@@ -4992,9 +5015,10 @@ pub const FuncGen = struct {
4992 const lhs = try self.resolveInst(bin_op.lhs);5015 const lhs = try self.resolveInst(bin_op.lhs);
4993 const rhs = try self.resolveInst(bin_op.rhs);5016 const rhs = try self.resolveInst(bin_op.rhs);
4994 const inst_ty = self.air.typeOfIndex(inst);5017 const inst_ty = self.air.typeOfIndex(inst);
5018 const scalar_ty = inst_ty.scalarType();
49955019
4996 if (inst_ty.isAnyFloat()) return self.todo("saturating float mul", .{});5020 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
4997 if (inst_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");5021 if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
4998 return self.builder.buildUMulFixSat(lhs, rhs, "");5022 return self.builder.buildUMulFixSat(lhs, rhs, "");
4999 }5023 }
50005024
...@@ -5015,12 +5039,13 @@ pub const FuncGen = struct {...@@ -5015,12 +5039,13 @@ pub const FuncGen = struct {
5015 const lhs = try self.resolveInst(bin_op.lhs);5039 const lhs = try self.resolveInst(bin_op.lhs);
5016 const rhs = try self.resolveInst(bin_op.rhs);5040 const rhs = try self.resolveInst(bin_op.rhs);
5017 const inst_ty = self.air.typeOfIndex(inst);5041 const inst_ty = self.air.typeOfIndex(inst);
5042 const scalar_ty = inst_ty.scalarType();
50185043
5019 if (inst_ty.isRuntimeFloat()) {5044 if (scalar_ty.isRuntimeFloat()) {
5020 const result = self.builder.buildFDiv(lhs, rhs, "");5045 const result = self.builder.buildFDiv(lhs, rhs, "");
5021 return self.callTrunc(result, inst_ty);5046 return self.callTrunc(result, inst_ty);
5022 }5047 }
5023 if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");5048 if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
5024 return self.builder.buildUDiv(lhs, rhs, "");5049 return self.builder.buildUDiv(lhs, rhs, "");
5025 }5050 }
50265051
...@@ -5031,12 +5056,13 @@ pub const FuncGen = struct {...@@ -5031,12 +5056,13 @@ pub const FuncGen = struct {
5031 const lhs = try self.resolveInst(bin_op.lhs);5056 const lhs = try self.resolveInst(bin_op.lhs);
5032 const rhs = try self.resolveInst(bin_op.rhs);5057 const rhs = try self.resolveInst(bin_op.rhs);
5033 const inst_ty = self.air.typeOfIndex(inst);5058 const inst_ty = self.air.typeOfIndex(inst);
5059 const scalar_ty = inst_ty.scalarType();
50345060
5035 if (inst_ty.isRuntimeFloat()) {5061 if (scalar_ty.isRuntimeFloat()) {
5036 const result = self.builder.buildFDiv(lhs, rhs, "");5062 const result = self.builder.buildFDiv(lhs, rhs, "");
5037 return try self.callFloor(result, inst_ty);5063 return try self.callFloor(result, inst_ty);
5038 }5064 }
5039 if (inst_ty.isSignedInt()) {5065 if (scalar_ty.isSignedInt()) {
5040 // const d = @divTrunc(a, b);5066 // const d = @divTrunc(a, b);
5041 // const r = @rem(a, b);5067 // const r = @rem(a, b);
5042 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));5068 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));
...@@ -5062,9 +5088,10 @@ pub const FuncGen = struct {...@@ -5062,9 +5088,10 @@ pub const FuncGen = struct {
5062 const lhs = try self.resolveInst(bin_op.lhs);5088 const lhs = try self.resolveInst(bin_op.lhs);
5063 const rhs = try self.resolveInst(bin_op.rhs);5089 const rhs = try self.resolveInst(bin_op.rhs);
5064 const inst_ty = self.air.typeOfIndex(inst);5090 const inst_ty = self.air.typeOfIndex(inst);
5091 const scalar_ty = inst_ty.scalarType();
50655092
5066 if (inst_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, "");5093 if (scalar_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, "");
5067 if (inst_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");5094 if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
5068 return self.builder.buildExactUDiv(lhs, rhs, "");5095 return self.builder.buildExactUDiv(lhs, rhs, "");
5069 }5096 }
50705097
...@@ -5075,9 +5102,10 @@ pub const FuncGen = struct {...@@ -5075,9 +5102,10 @@ pub const FuncGen = struct {
5075 const lhs = try self.resolveInst(bin_op.lhs);5102 const lhs = try self.resolveInst(bin_op.lhs);
5076 const rhs = try self.resolveInst(bin_op.rhs);5103 const rhs = try self.resolveInst(bin_op.rhs);
5077 const inst_ty = self.air.typeOfIndex(inst);5104 const inst_ty = self.air.typeOfIndex(inst);
5105 const scalar_ty = inst_ty.scalarType();
50785106
5079 if (inst_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, "");5107 if (scalar_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, "");
5080 if (inst_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");5108 if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
5081 return self.builder.buildURem(lhs, rhs, "");5109 return self.builder.buildURem(lhs, rhs, "");
5082 }5110 }
50835111
...@@ -5089,8 +5117,9 @@ pub const FuncGen = struct {...@@ -5089,8 +5117,9 @@ pub const FuncGen = struct {
5089 const rhs = try self.resolveInst(bin_op.rhs);5117 const rhs = try self.resolveInst(bin_op.rhs);
5090 const inst_ty = self.air.typeOfIndex(inst);5118 const inst_ty = self.air.typeOfIndex(inst);
5091 const inst_llvm_ty = try self.dg.llvmType(inst_ty);5119 const inst_llvm_ty = try self.dg.llvmType(inst_ty);
5120 const scalar_ty = inst_ty.scalarType();
50925121
5093 if (inst_ty.isRuntimeFloat()) {5122 if (scalar_ty.isRuntimeFloat()) {
5094 const a = self.builder.buildFRem(lhs, rhs, "");5123 const a = self.builder.buildFRem(lhs, rhs, "");
5095 const b = self.builder.buildFAdd(a, rhs, "");5124 const b = self.builder.buildFAdd(a, rhs, "");
5096 const c = self.builder.buildFRem(b, rhs, "");5125 const c = self.builder.buildFRem(b, rhs, "");
...@@ -5098,7 +5127,7 @@ pub const FuncGen = struct {...@@ -5098,7 +5127,7 @@ pub const FuncGen = struct {
5098 const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");5127 const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");
5099 return self.builder.buildSelect(ltz, c, a, "");5128 return self.builder.buildSelect(ltz, c, a, "");
5100 }5129 }
5101 if (inst_ty.isSignedInt()) {5130 if (scalar_ty.isSignedInt()) {
5102 const a = self.builder.buildSRem(lhs, rhs, "");5131 const a = self.builder.buildSRem(lhs, rhs, "");
5103 const b = self.builder.buildNSWAdd(a, rhs, "");5132 const b = self.builder.buildNSWAdd(a, rhs, "");
5104 const c = self.builder.buildSRem(b, rhs, "");5133 const c = self.builder.buildSRem(b, rhs, "");
...@@ -5323,15 +5352,22 @@ pub const FuncGen = struct {...@@ -5323,15 +5352,22 @@ pub const FuncGen = struct {
5323 if (self.liveness.isUnused(inst)) return null;5352 if (self.liveness.isUnused(inst)) return null;
53245353
5325 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5354 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5355
5326 const lhs = try self.resolveInst(bin_op.lhs);5356 const lhs = try self.resolveInst(bin_op.lhs);
5327 const rhs = try self.resolveInst(bin_op.rhs);5357 const rhs = try self.resolveInst(bin_op.rhs);
5328 const lhs_type = self.air.typeOf(bin_op.lhs);5358
5359 const lhs_ty = self.air.typeOf(bin_op.lhs);
5360 const rhs_ty = self.air.typeOf(bin_op.rhs);
5361 const lhs_scalar_ty = lhs_ty.scalarType();
5362 const rhs_scalar_ty = rhs_ty.scalarType();
5363
5329 const tg = self.dg.module.getTarget();5364 const tg = self.dg.module.getTarget();
5330 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))5365
5331 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")5366 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
5367 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
5332 else5368 else
5333 rhs;5369 rhs;
5334 if (lhs_type.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");5370 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
5335 return self.builder.buildNUWShl(lhs, casted_rhs, "");5371 return self.builder.buildNUWShl(lhs, casted_rhs, "");
5336 }5372 }
53375373
...@@ -5339,11 +5375,18 @@ pub const FuncGen = struct {...@@ -5339,11 +5375,18 @@ pub const FuncGen = struct {
5339 if (self.liveness.isUnused(inst)) return null;5375 if (self.liveness.isUnused(inst)) return null;
53405376
5341 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5377 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5378
5342 const lhs = try self.resolveInst(bin_op.lhs);5379 const lhs = try self.resolveInst(bin_op.lhs);
5343 const rhs = try self.resolveInst(bin_op.rhs);5380 const rhs = try self.resolveInst(bin_op.rhs);
5381
5344 const lhs_type = self.air.typeOf(bin_op.lhs);5382 const lhs_type = self.air.typeOf(bin_op.lhs);
5383 const rhs_type = self.air.typeOf(bin_op.rhs);
5384 const lhs_scalar_ty = lhs_type.scalarType();
5385 const rhs_scalar_ty = rhs_type.scalarType();
5386
5345 const tg = self.dg.module.getTarget();5387 const tg = self.dg.module.getTarget();
5346 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))5388
5389 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
5347 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")5390 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
5348 else5391 else
5349 rhs;5392 rhs;
...@@ -5354,31 +5397,45 @@ pub const FuncGen = struct {...@@ -5354,31 +5397,45 @@ pub const FuncGen = struct {
5354 if (self.liveness.isUnused(inst)) return null;5397 if (self.liveness.isUnused(inst)) return null;
53555398
5356 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5399 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5400
5357 const lhs = try self.resolveInst(bin_op.lhs);5401 const lhs = try self.resolveInst(bin_op.lhs);
5358 const rhs = try self.resolveInst(bin_op.rhs);5402 const rhs = try self.resolveInst(bin_op.rhs);
5359 const lhs_type = self.air.typeOf(bin_op.lhs);5403
5404 const lhs_ty = self.air.typeOf(bin_op.lhs);
5405 const rhs_ty = self.air.typeOf(bin_op.rhs);
5406 const lhs_scalar_ty = lhs_ty.scalarType();
5407 const rhs_scalar_ty = rhs_ty.scalarType();
5408
5360 const tg = self.dg.module.getTarget();5409 const tg = self.dg.module.getTarget();
5361 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))5410
5362 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")5411 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
5412 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
5363 else5413 else
5364 rhs;5414 rhs;
5365 if (lhs_type.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");5415 if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
5366 return self.builder.buildUShlSat(lhs, casted_rhs, "");5416 return self.builder.buildUShlSat(lhs, casted_rhs, "");
5367 }5417 }
53685418
5369 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {5419 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
5370 if (self.liveness.isUnused(inst))5420 if (self.liveness.isUnused(inst)) return null;
5371 return null;5421
5372 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5423
5373 const lhs = try self.resolveInst(bin_op.lhs);5424 const lhs = try self.resolveInst(bin_op.lhs);
5374 const rhs = try self.resolveInst(bin_op.rhs);5425 const rhs = try self.resolveInst(bin_op.rhs);
5375 const lhs_type = self.air.typeOf(bin_op.lhs);5426
5427 const lhs_ty = self.air.typeOf(bin_op.lhs);
5428 const rhs_ty = self.air.typeOf(bin_op.rhs);
5429 const lhs_scalar_ty = lhs_ty.scalarType();
5430 const rhs_scalar_ty = rhs_ty.scalarType();
5431
5376 const tg = self.dg.module.getTarget();5432 const tg = self.dg.module.getTarget();
5377 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))5433
5378 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")5434 const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
5435 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
5379 else5436 else
5380 rhs;5437 rhs;
5381 const is_signed_int = self.air.typeOfIndex(inst).isSignedInt();5438 const is_signed_int = lhs_scalar_ty.isSignedInt();
53825439
5383 if (is_exact) {5440 if (is_exact) {
5384 if (is_signed_int) {5441 if (is_signed_int) {
...@@ -5506,7 +5563,8 @@ pub const FuncGen = struct {...@@ -5506,7 +5563,8 @@ pub const FuncGen = struct {
5506 if (bitcast_ok) {5563 if (bitcast_ok) {
5507 const llvm_vector_ty = try self.dg.llvmType(operand_ty);5564 const llvm_vector_ty = try self.dg.llvmType(operand_ty);
5508 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");5565 const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
5509 _ = self.builder.buildStore(operand, casted_ptr);5566 const llvm_store = self.builder.buildStore(operand, casted_ptr);
5567 llvm_store.setAlignment(inst_ty.abiAlignment(target));
5510 } else {5568 } else {
5511 // If the ABI size of the element type is not evenly divisible by size in bits;5569 // If the ABI size of the element type is not evenly divisible by size in bits;
5512 // a simple bitcast will not work, and we fall back to extractelement.5570 // a simple bitcast will not work, and we fall back to extractelement.
src/print_air.zig+13-2
...@@ -266,6 +266,7 @@ const Writer = struct {...@@ -266,6 +266,7 @@ const Writer = struct {
266 .mul_add => try w.writeMulAdd(s, inst),266 .mul_add => try w.writeMulAdd(s, inst),
267 .shuffle => try w.writeShuffle(s, inst),267 .shuffle => try w.writeShuffle(s, inst),
268 .reduce => try w.writeReduce(s, inst),268 .reduce => try w.writeReduce(s, inst),
269 .cmp_vector => try w.writeCmpVector(s, inst),
269270
270 .add_with_overflow,271 .add_with_overflow,
271 .sub_with_overflow,272 .sub_with_overflow,
...@@ -402,6 +403,16 @@ const Writer = struct {...@@ -402,6 +403,16 @@ const Writer = struct {
402 try s.print(", {s}", .{@tagName(reduce.operation)});403 try s.print(", {s}", .{@tagName(reduce.operation)});
403 }404 }
404405
406 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
407 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
408 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
409
410 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
411 try w.writeOperand(s, inst, 0, extra.lhs);
412 try s.writeAll(", ");
413 try w.writeOperand(s, inst, 1, extra.rhs);
414 }
415
405 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {416 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
406 const atomic_order = w.air.instructions.items(.data)[inst].fence;417 const atomic_order = w.air.instructions.items(.data)[inst].fence;
407418
...@@ -470,8 +481,8 @@ const Writer = struct {...@@ -470,8 +481,8 @@ const Writer = struct {
470 }481 }
471482
472 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {483 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
473 const pl_op = w.air.instructions.items(.data)[inst].ty_pl;484 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
474 const extra = w.air.extraData(Air.FieldParentPtr, pl_op.payload).data;485 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
475486
476 try w.writeOperand(s, inst, 0, extra.field_ptr);487 try w.writeOperand(s, inst, 0, extra.field_ptr);
477 try s.print(", {d}", .{extra.field_index});488 try s.print(", {d}", .{extra.field_index});
src/value.zig+726-43
...@@ -1846,8 +1846,23 @@ pub const Value = extern union {...@@ -1846,8 +1846,23 @@ pub const Value = extern union {
1846 return order(lhs, rhs).compare(op);1846 return order(lhs, rhs).compare(op);
1847 }1847 }
18481848
1849 /// Asserts the value is comparable. Both operands have type `ty`.1849 /// Asserts the values are comparable. Both operands have type `ty`.
1850 /// Vector results will be reduced with AND.
1850 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {1851 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {
1852 if (ty.zigTypeTag() == .Vector) {
1853 var i: usize = 0;
1854 while (i < ty.vectorLen()) : (i += 1) {
1855 if (!compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType())) {
1856 return false;
1857 }
1858 }
1859 return true;
1860 }
1861 return compareScalar(lhs, op, rhs, ty);
1862 }
1863
1864 /// Asserts the values are comparable. Both operands have type `ty`.
1865 pub fn compareScalar(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {
1851 return switch (op) {1866 return switch (op) {
1852 .eq => lhs.eql(rhs, ty),1867 .eq => lhs.eql(rhs, ty),
1853 .neq => !lhs.eql(rhs, ty),1868 .neq => !lhs.eql(rhs, ty),
...@@ -1855,18 +1870,25 @@ pub const Value = extern union {...@@ -1855,18 +1870,25 @@ pub const Value = extern union {
1855 };1870 };
1856 }1871 }
18571872
1873 /// Asserts the values are comparable vectors of type `ty`.
1874 pub fn compareVector(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, allocator: Allocator) !Value {
1875 assert(ty.zigTypeTag() == .Vector);
1876 const result_data = try allocator.alloc(Value, ty.vectorLen());
1877 for (result_data) |*scalar, i| {
1878 const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType());
1879 scalar.* = if (res_bool) Value.@"true" else Value.@"false";
1880 }
1881 return Value.Tag.aggregate.create(allocator, result_data);
1882 }
1883
1858 /// Asserts the value is comparable.1884 /// Asserts the value is comparable.
1859 /// For vectors this is only valid with op == .eq.1885 /// Vector results will be reduced with AND.
1860 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {1886 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
1861 switch (lhs.tag()) {1887 switch (lhs.tag()) {
1862 .repeated => {1888 .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op),
1863 assert(op == .eq);
1864 return lhs.castTag(.repeated).?.data.compareWithZero(.eq);
1865 },
1866 .aggregate => {1889 .aggregate => {
1867 assert(op == .eq);
1868 for (lhs.castTag(.aggregate).?.data) |elem_val| {1890 for (lhs.castTag(.aggregate).?.data) |elem_val| {
1869 if (!elem_val.compareWithZero(.eq)) return false;1891 if (!elem_val.compareWithZero(op)) return false;
1870 }1892 }
1871 return true;1893 return true;
1872 },1894 },
...@@ -2404,6 +2426,27 @@ pub const Value = extern union {...@@ -2404,6 +2426,27 @@ pub const Value = extern union {
2404 };2426 };
2405 }2427 }
24062428
2429 /// Index into a vector-like `Value`. Asserts `index` is a valid index for `val`.
2430 /// Some scalar values are considered vector-like to avoid needing to allocate
2431 /// a new `repeated` each time a constant is used.
2432 pub fn indexVectorlike(val: Value, index: usize) Value {
2433 return switch (val.tag()) {
2434 .aggregate => val.castTag(.aggregate).?.data[index],
2435
2436 .repeated => val.castTag(.repeated).?.data,
2437 // These values will implicitly be treated as `repeated`.
2438 .zero,
2439 .one,
2440 .bool_false,
2441 .bool_true,
2442 .int_i64,
2443 .int_u64,
2444 => val,
2445
2446 else => unreachable,
2447 };
2448 }
2449
2407 /// Asserts the value is a single-item pointer to an array, or an array,2450 /// Asserts the value is a single-item pointer to an array, or an array,
2408 /// or an unknown-length pointer, and returns the element value at the index.2451 /// or an unknown-length pointer, and returns the element value at the index.
2409 pub fn elemValue(val: Value, arena: Allocator, index: usize) !Value {2452 pub fn elemValue(val: Value, arena: Allocator, index: usize) !Value {
...@@ -2646,25 +2689,36 @@ pub const Value = extern union {...@@ -2646,25 +2689,36 @@ pub const Value = extern union {
2646 };2689 };
2647 }2690 }
26482691
2649 pub fn intToFloat(val: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {2692 pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value {
2693 if (int_ty.zigTypeTag() == .Vector) {
2694 const result_data = try arena.alloc(Value, int_ty.vectorLen());
2695 for (result_data) |*scalar, i| {
2696 scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target);
2697 }
2698 return Value.Tag.aggregate.create(arena, result_data);
2699 }
2700 return intToFloatScalar(val, arena, float_ty, target);
2701 }
2702
2703 pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value {
2650 switch (val.tag()) {2704 switch (val.tag()) {
2651 .undef, .zero, .one => return val,2705 .undef, .zero, .one => return val,
2652 .the_only_possible_value => return Value.initTag(.zero), // for i0, u02706 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
2653 .int_u64 => {2707 .int_u64 => {
2654 return intToFloatInner(val.castTag(.int_u64).?.data, arena, dest_ty, target);2708 return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target);
2655 },2709 },
2656 .int_i64 => {2710 .int_i64 => {
2657 return intToFloatInner(val.castTag(.int_i64).?.data, arena, dest_ty, target);2711 return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target);
2658 },2712 },
2659 .int_big_positive => {2713 .int_big_positive => {
2660 const limbs = val.castTag(.int_big_positive).?.data;2714 const limbs = val.castTag(.int_big_positive).?.data;
2661 const float = bigIntToFloat(limbs, true);2715 const float = bigIntToFloat(limbs, true);
2662 return floatToValue(float, arena, dest_ty, target);2716 return floatToValue(float, arena, float_ty, target);
2663 },2717 },
2664 .int_big_negative => {2718 .int_big_negative => {
2665 const limbs = val.castTag(.int_big_negative).?.data;2719 const limbs = val.castTag(.int_big_negative).?.data;
2666 const float = bigIntToFloat(limbs, false);2720 const float = bigIntToFloat(limbs, false);
2667 return floatToValue(float, arena, dest_ty, target);2721 return floatToValue(float, arena, float_ty, target);
2668 },2722 },
2669 else => unreachable,2723 else => unreachable,
2670 }2724 }
...@@ -2694,7 +2748,18 @@ pub const Value = extern union {...@@ -2694,7 +2748,18 @@ pub const Value = extern union {
2694 }2748 }
2695 }2749 }
26962750
2697 pub fn floatToInt(val: Value, arena: Allocator, dest_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {2751 pub fn floatToInt(val: Value, arena: Allocator, float_ty: Type, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
2752 if (float_ty.zigTypeTag() == .Vector) {
2753 const result_data = try arena.alloc(Value, float_ty.vectorLen());
2754 for (result_data) |*scalar, i| {
2755 scalar.* = try floatToIntScalar(val.indexVectorlike(i), arena, int_ty.scalarType(), target);
2756 }
2757 return Value.Tag.aggregate.create(arena, result_data);
2758 }
2759 return floatToIntScalar(val, arena, int_ty, target);
2760 }
2761
2762 pub fn floatToIntScalar(val: Value, arena: Allocator, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
2698 const Limb = std.math.big.Limb;2763 const Limb = std.math.big.Limb;
26992764
2700 var value = val.toFloat(f64); // TODO: f128 ?2765 var value = val.toFloat(f64); // TODO: f128 ?
...@@ -2724,7 +2789,7 @@ pub const Value = extern union {...@@ -2724,7 +2789,7 @@ pub const Value = extern union {
2724 else2789 else
2725 try Value.Tag.int_big_positive.create(arena, result_limbs);2790 try Value.Tag.int_big_positive.create(arena, result_limbs);
27262791
2727 if (result.intFitsInType(dest_ty, target)) {2792 if (result.intFitsInType(int_ty, target)) {
2728 return result;2793 return result;
2729 } else {2794 } else {
2730 return error.FloatCannotFit;2795 return error.FloatCannotFit;
...@@ -2771,18 +2836,36 @@ pub const Value = extern union {...@@ -2771,18 +2836,36 @@ pub const Value = extern union {
2771 };2836 };
2772 }2837 }
27732838
2774 /// Supports both floats and ints; handles undefined.2839 /// Supports both (vectors of) floats and ints; handles undefined scalars.
2775 pub fn numberAddWrap(2840 pub fn numberAddWrap(
2776 lhs: Value,2841 lhs: Value,
2777 rhs: Value,2842 rhs: Value,
2778 ty: Type,2843 ty: Type,
2779 arena: Allocator,2844 arena: Allocator,
2780 target: Target,2845 target: Target,
2846 ) !Value {
2847 if (ty.zigTypeTag() == .Vector) {
2848 const result_data = try arena.alloc(Value, ty.vectorLen());
2849 for (result_data) |*scalar, i| {
2850 scalar.* = try numberAddWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
2851 }
2852 return Value.Tag.aggregate.create(arena, result_data);
2853 }
2854 return numberAddWrapScalar(lhs, rhs, ty, arena, target);
2855 }
2856
2857 /// Supports both floats and ints; handles undefined.
2858 pub fn numberAddWrapScalar(
2859 lhs: Value,
2860 rhs: Value,
2861 ty: Type,
2862 arena: Allocator,
2863 target: Target,
2781 ) !Value {2864 ) !Value {
2782 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);2865 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
27832866
2784 if (ty.zigTypeTag() == .ComptimeInt) {2867 if (ty.zigTypeTag() == .ComptimeInt) {
2785 return intAdd(lhs, rhs, arena);2868 return intAdd(lhs, rhs, ty, arena);
2786 }2869 }
27872870
2788 if (ty.isAnyFloat()) {2871 if (ty.isAnyFloat()) {
...@@ -2809,13 +2892,31 @@ pub const Value = extern union {...@@ -2809,13 +2892,31 @@ pub const Value = extern union {
2809 }2892 }
2810 }2893 }
28112894
2812 /// Supports integers only; asserts neither operand is undefined.2895 /// Supports (vectors of) integers only; asserts neither operand is undefined.
2813 pub fn intAddSat(2896 pub fn intAddSat(
2814 lhs: Value,2897 lhs: Value,
2815 rhs: Value,2898 rhs: Value,
2816 ty: Type,2899 ty: Type,
2817 arena: Allocator,2900 arena: Allocator,
2818 target: Target,2901 target: Target,
2902 ) !Value {
2903 if (ty.zigTypeTag() == .Vector) {
2904 const result_data = try arena.alloc(Value, ty.vectorLen());
2905 for (result_data) |*scalar, i| {
2906 scalar.* = try intAddSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
2907 }
2908 return Value.Tag.aggregate.create(arena, result_data);
2909 }
2910 return intAddSatScalar(lhs, rhs, ty, arena, target);
2911 }
2912
2913 /// Supports integers only; asserts neither operand is undefined.
2914 pub fn intAddSatScalar(
2915 lhs: Value,
2916 rhs: Value,
2917 ty: Type,
2918 arena: Allocator,
2919 target: Target,
2819 ) !Value {2920 ) !Value {
2820 assert(!lhs.isUndef());2921 assert(!lhs.isUndef());
2821 assert(!rhs.isUndef());2922 assert(!rhs.isUndef());
...@@ -2861,18 +2962,36 @@ pub const Value = extern union {...@@ -2861,18 +2962,36 @@ pub const Value = extern union {
2861 };2962 };
2862 }2963 }
28632964
2864 /// Supports both floats and ints; handles undefined.2965 /// Supports both (vectors of) floats and ints; handles undefined scalars.
2865 pub fn numberSubWrap(2966 pub fn numberSubWrap(
2866 lhs: Value,2967 lhs: Value,
2867 rhs: Value,2968 rhs: Value,
2868 ty: Type,2969 ty: Type,
2869 arena: Allocator,2970 arena: Allocator,
2870 target: Target,2971 target: Target,
2972 ) !Value {
2973 if (ty.zigTypeTag() == .Vector) {
2974 const result_data = try arena.alloc(Value, ty.vectorLen());
2975 for (result_data) |*scalar, i| {
2976 scalar.* = try numberSubWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
2977 }
2978 return Value.Tag.aggregate.create(arena, result_data);
2979 }
2980 return numberSubWrapScalar(lhs, rhs, ty, arena, target);
2981 }
2982
2983 /// Supports both floats and ints; handles undefined.
2984 pub fn numberSubWrapScalar(
2985 lhs: Value,
2986 rhs: Value,
2987 ty: Type,
2988 arena: Allocator,
2989 target: Target,
2871 ) !Value {2990 ) !Value {
2872 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);2991 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
28732992
2874 if (ty.zigTypeTag() == .ComptimeInt) {2993 if (ty.zigTypeTag() == .ComptimeInt) {
2875 return intSub(lhs, rhs, arena);2994 return intSub(lhs, rhs, ty, arena);
2876 }2995 }
28772996
2878 if (ty.isAnyFloat()) {2997 if (ty.isAnyFloat()) {
...@@ -2883,13 +3002,31 @@ pub const Value = extern union {...@@ -2883,13 +3002,31 @@ pub const Value = extern union {
2883 return overflow_result.wrapped_result;3002 return overflow_result.wrapped_result;
2884 }3003 }
28853004
2886 /// Supports integers only; asserts neither operand is undefined.3005 /// Supports (vectors of) integers only; asserts neither operand is undefined.
2887 pub fn intSubSat(3006 pub fn intSubSat(
2888 lhs: Value,3007 lhs: Value,
2889 rhs: Value,3008 rhs: Value,
2890 ty: Type,3009 ty: Type,
2891 arena: Allocator,3010 arena: Allocator,
2892 target: Target,3011 target: Target,
3012 ) !Value {
3013 if (ty.zigTypeTag() == .Vector) {
3014 const result_data = try arena.alloc(Value, ty.vectorLen());
3015 for (result_data) |*scalar, i| {
3016 scalar.* = try intSubSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3017 }
3018 return Value.Tag.aggregate.create(arena, result_data);
3019 }
3020 return intSubSatScalar(lhs, rhs, ty, arena, target);
3021 }
3022
3023 /// Supports integers only; asserts neither operand is undefined.
3024 pub fn intSubSatScalar(
3025 lhs: Value,
3026 rhs: Value,
3027 ty: Type,
3028 arena: Allocator,
3029 target: Target,
2893 ) !Value {3030 ) !Value {
2894 assert(!lhs.isUndef());3031 assert(!lhs.isUndef());
2895 assert(!rhs.isUndef());3032 assert(!rhs.isUndef());
...@@ -2944,18 +3081,36 @@ pub const Value = extern union {...@@ -2944,18 +3081,36 @@ pub const Value = extern union {
2944 };3081 };
2945 }3082 }
29463083
2947 /// Supports both floats and ints; handles undefined.3084 /// Supports both (vectors of) floats and ints; handles undefined scalars.
2948 pub fn numberMulWrap(3085 pub fn numberMulWrap(
2949 lhs: Value,3086 lhs: Value,
2950 rhs: Value,3087 rhs: Value,
2951 ty: Type,3088 ty: Type,
2952 arena: Allocator,3089 arena: Allocator,
2953 target: Target,3090 target: Target,
3091 ) !Value {
3092 if (ty.zigTypeTag() == .Vector) {
3093 const result_data = try arena.alloc(Value, ty.vectorLen());
3094 for (result_data) |*scalar, i| {
3095 scalar.* = try numberMulWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3096 }
3097 return Value.Tag.aggregate.create(arena, result_data);
3098 }
3099 return numberMulWrapScalar(lhs, rhs, ty, arena, target);
3100 }
3101
3102 /// Supports both floats and ints; handles undefined.
3103 pub fn numberMulWrapScalar(
3104 lhs: Value,
3105 rhs: Value,
3106 ty: Type,
3107 arena: Allocator,
3108 target: Target,
2954 ) !Value {3109 ) !Value {
2955 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);3110 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
29563111
2957 if (ty.zigTypeTag() == .ComptimeInt) {3112 if (ty.zigTypeTag() == .ComptimeInt) {
2958 return intMul(lhs, rhs, arena);3113 return intMul(lhs, rhs, ty, arena);
2959 }3114 }
29603115
2961 if (ty.isAnyFloat()) {3116 if (ty.isAnyFloat()) {
...@@ -2966,13 +3121,31 @@ pub const Value = extern union {...@@ -2966,13 +3121,31 @@ pub const Value = extern union {
2966 return overflow_result.wrapped_result;3121 return overflow_result.wrapped_result;
2967 }3122 }
29683123
2969 /// Supports integers only; asserts neither operand is undefined.3124 /// Supports (vectors of) integers only; asserts neither operand is undefined.
2970 pub fn intMulSat(3125 pub fn intMulSat(
2971 lhs: Value,3126 lhs: Value,
2972 rhs: Value,3127 rhs: Value,
2973 ty: Type,3128 ty: Type,
2974 arena: Allocator,3129 arena: Allocator,
2975 target: Target,3130 target: Target,
3131 ) !Value {
3132 if (ty.zigTypeTag() == .Vector) {
3133 const result_data = try arena.alloc(Value, ty.vectorLen());
3134 for (result_data) |*scalar, i| {
3135 scalar.* = try intMulSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3136 }
3137 return Value.Tag.aggregate.create(arena, result_data);
3138 }
3139 return intMulSatScalar(lhs, rhs, ty, arena, target);
3140 }
3141
3142 /// Supports (vectors of) integers only; asserts neither operand is undefined.
3143 pub fn intMulSatScalar(
3144 lhs: Value,
3145 rhs: Value,
3146 ty: Type,
3147 arena: Allocator,
3148 target: Target,
2976 ) !Value {3149 ) !Value {
2977 assert(!lhs.isUndef());3150 assert(!lhs.isUndef());
2978 assert(!rhs.isUndef());3151 assert(!rhs.isUndef());
...@@ -3025,8 +3198,20 @@ pub const Value = extern union {...@@ -3025,8 +3198,20 @@ pub const Value = extern union {
3025 };3198 };
3026 }3199 }
30273200
3028 /// operands must be integers; handles undefined.3201 /// operands must be (vectors of) integers; handles undefined scalars.
3029 pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, target: Target) !Value {3202 pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, target: Target) !Value {
3203 if (ty.zigTypeTag() == .Vector) {
3204 const result_data = try arena.alloc(Value, ty.vectorLen());
3205 for (result_data) |*scalar, i| {
3206 scalar.* = try bitwiseNotScalar(val.indexVectorlike(i), ty.scalarType(), arena, target);
3207 }
3208 return Value.Tag.aggregate.create(arena, result_data);
3209 }
3210 return bitwiseNotScalar(val, ty, arena, target);
3211 }
3212
3213 /// operands must be integers; handles undefined.
3214 pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, target: Target) !Value {
3030 if (val.isUndef()) return Value.initTag(.undef);3215 if (val.isUndef()) return Value.initTag(.undef);
30313216
3032 const info = ty.intInfo(target);3217 const info = ty.intInfo(target);
...@@ -3050,8 +3235,20 @@ pub const Value = extern union {...@@ -3050,8 +3235,20 @@ pub const Value = extern union {
3050 return fromBigInt(arena, result_bigint.toConst());3235 return fromBigInt(arena, result_bigint.toConst());
3051 }3236 }
30523237
3238 /// operands must be (vectors of) integers; handles undefined scalars.
3239 pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3240 if (ty.zigTypeTag() == .Vector) {
3241 const result_data = try allocator.alloc(Value, ty.vectorLen());
3242 for (result_data) |*scalar, i| {
3243 scalar.* = try bitwiseAndScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3244 }
3245 return Value.Tag.aggregate.create(allocator, result_data);
3246 }
3247 return bitwiseAndScalar(lhs, rhs, allocator);
3248 }
3249
3053 /// operands must be integers; handles undefined.3250 /// operands must be integers; handles undefined.
3054 pub fn bitwiseAnd(lhs: Value, rhs: Value, arena: Allocator) !Value {3251 pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
3055 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);3252 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
30563253
3057 // TODO is this a performance issue? maybe we should try the operation without3254 // TODO is this a performance issue? maybe we should try the operation without
...@@ -3070,22 +3267,46 @@ pub const Value = extern union {...@@ -3070,22 +3267,46 @@ pub const Value = extern union {
3070 return fromBigInt(arena, result_bigint.toConst());3267 return fromBigInt(arena, result_bigint.toConst());
3071 }3268 }
30723269
3073 /// operands must be integers; handles undefined.3270 /// operands must be (vectors of) integers; handles undefined scalars.
3074 pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value {3271 pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value {
3272 if (ty.zigTypeTag() == .Vector) {
3273 const result_data = try arena.alloc(Value, ty.vectorLen());
3274 for (result_data) |*scalar, i| {
3275 scalar.* = try bitwiseNandScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3276 }
3277 return Value.Tag.aggregate.create(arena, result_data);
3278 }
3279 return bitwiseNandScalar(lhs, rhs, ty, arena, target);
3280 }
3281
3282 /// operands must be integers; handles undefined.
3283 pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value {
3075 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);3284 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
30763285
3077 const anded = try bitwiseAnd(lhs, rhs, arena);3286 const anded = try bitwiseAnd(lhs, rhs, ty, arena);
30783287
3079 const all_ones = if (ty.isSignedInt())3288 const all_ones = if (ty.isSignedInt())
3080 try Value.Tag.int_i64.create(arena, -1)3289 try Value.Tag.int_i64.create(arena, -1)
3081 else3290 else
3082 try ty.maxInt(arena, target);3291 try ty.maxInt(arena, target);
30833292
3084 return bitwiseXor(anded, all_ones, arena);3293 return bitwiseXor(anded, all_ones, ty, arena);
3294 }
3295
3296 /// operands must be (vectors of) integers; handles undefined scalars.
3297 pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3298 if (ty.zigTypeTag() == .Vector) {
3299 const result_data = try allocator.alloc(Value, ty.vectorLen());
3300 for (result_data) |*scalar, i| {
3301 scalar.* = try bitwiseOrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3302 }
3303 return Value.Tag.aggregate.create(allocator, result_data);
3304 }
3305 return bitwiseOrScalar(lhs, rhs, allocator);
3085 }3306 }
30863307
3087 /// operands must be integers; handles undefined.3308 /// operands must be integers; handles undefined.
3088 pub fn bitwiseOr(lhs: Value, rhs: Value, arena: Allocator) !Value {3309 pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
3089 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);3310 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
30903311
3091 // TODO is this a performance issue? maybe we should try the operation without3312 // TODO is this a performance issue? maybe we should try the operation without
...@@ -3103,8 +3324,20 @@ pub const Value = extern union {...@@ -3103,8 +3324,20 @@ pub const Value = extern union {
3103 return fromBigInt(arena, result_bigint.toConst());3324 return fromBigInt(arena, result_bigint.toConst());
3104 }3325 }
31053326
3327 /// operands must be (vectors of) integers; handles undefined scalars.
3328 pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3329 if (ty.zigTypeTag() == .Vector) {
3330 const result_data = try allocator.alloc(Value, ty.vectorLen());
3331 for (result_data) |*scalar, i| {
3332 scalar.* = try bitwiseXorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3333 }
3334 return Value.Tag.aggregate.create(allocator, result_data);
3335 }
3336 return bitwiseXorScalar(lhs, rhs, allocator);
3337 }
3338
3106 /// operands must be integers; handles undefined.3339 /// operands must be integers; handles undefined.
3107 pub fn bitwiseXor(lhs: Value, rhs: Value, arena: Allocator) !Value {3340 pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
3108 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);3341 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
31093342
3110 // TODO is this a performance issue? maybe we should try the operation without3343 // TODO is this a performance issue? maybe we should try the operation without
...@@ -3123,7 +3356,18 @@ pub const Value = extern union {...@@ -3123,7 +3356,18 @@ pub const Value = extern union {
3123 return fromBigInt(arena, result_bigint.toConst());3356 return fromBigInt(arena, result_bigint.toConst());
3124 }3357 }
31253358
3126 pub fn intAdd(lhs: Value, rhs: Value, allocator: Allocator) !Value {3359 pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3360 if (ty.zigTypeTag() == .Vector) {
3361 const result_data = try allocator.alloc(Value, ty.vectorLen());
3362 for (result_data) |*scalar, i| {
3363 scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3364 }
3365 return Value.Tag.aggregate.create(allocator, result_data);
3366 }
3367 return intAddScalar(lhs, rhs, allocator);
3368 }
3369
3370 pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3127 // TODO is this a performance issue? maybe we should try the operation without3371 // TODO is this a performance issue? maybe we should try the operation without
3128 // resorting to BigInt first.3372 // resorting to BigInt first.
3129 var lhs_space: Value.BigIntSpace = undefined;3373 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3139,7 +3383,18 @@ pub const Value = extern union {...@@ -3139,7 +3383,18 @@ pub const Value = extern union {
3139 return fromBigInt(allocator, result_bigint.toConst());3383 return fromBigInt(allocator, result_bigint.toConst());
3140 }3384 }
31413385
3142 pub fn intSub(lhs: Value, rhs: Value, allocator: Allocator) !Value {3386 pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3387 if (ty.zigTypeTag() == .Vector) {
3388 const result_data = try allocator.alloc(Value, ty.vectorLen());
3389 for (result_data) |*scalar, i| {
3390 scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3391 }
3392 return Value.Tag.aggregate.create(allocator, result_data);
3393 }
3394 return intSubScalar(lhs, rhs, allocator);
3395 }
3396
3397 pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3143 // TODO is this a performance issue? maybe we should try the operation without3398 // TODO is this a performance issue? maybe we should try the operation without
3144 // resorting to BigInt first.3399 // resorting to BigInt first.
3145 var lhs_space: Value.BigIntSpace = undefined;3400 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3155,7 +3410,18 @@ pub const Value = extern union {...@@ -3155,7 +3410,18 @@ pub const Value = extern union {
3155 return fromBigInt(allocator, result_bigint.toConst());3410 return fromBigInt(allocator, result_bigint.toConst());
3156 }3411 }
31573412
3158 pub fn intDiv(lhs: Value, rhs: Value, allocator: Allocator) !Value {3413 pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3414 if (ty.zigTypeTag() == .Vector) {
3415 const result_data = try allocator.alloc(Value, ty.vectorLen());
3416 for (result_data) |*scalar, i| {
3417 scalar.* = try intDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3418 }
3419 return Value.Tag.aggregate.create(allocator, result_data);
3420 }
3421 return intDivScalar(lhs, rhs, allocator);
3422 }
3423
3424 pub fn intDivScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3159 // TODO is this a performance issue? maybe we should try the operation without3425 // TODO is this a performance issue? maybe we should try the operation without
3160 // resorting to BigInt first.3426 // resorting to BigInt first.
3161 var lhs_space: Value.BigIntSpace = undefined;3427 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3180,7 +3446,18 @@ pub const Value = extern union {...@@ -3180,7 +3446,18 @@ pub const Value = extern union {
3180 return fromBigInt(allocator, result_q.toConst());3446 return fromBigInt(allocator, result_q.toConst());
3181 }3447 }
31823448
3183 pub fn intDivFloor(lhs: Value, rhs: Value, allocator: Allocator) !Value {3449 pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3450 if (ty.zigTypeTag() == .Vector) {
3451 const result_data = try allocator.alloc(Value, ty.vectorLen());
3452 for (result_data) |*scalar, i| {
3453 scalar.* = try intDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3454 }
3455 return Value.Tag.aggregate.create(allocator, result_data);
3456 }
3457 return intDivFloorScalar(lhs, rhs, allocator);
3458 }
3459
3460 pub fn intDivFloorScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3184 // TODO is this a performance issue? maybe we should try the operation without3461 // TODO is this a performance issue? maybe we should try the operation without
3185 // resorting to BigInt first.3462 // resorting to BigInt first.
3186 var lhs_space: Value.BigIntSpace = undefined;3463 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3205,7 +3482,18 @@ pub const Value = extern union {...@@ -3205,7 +3482,18 @@ pub const Value = extern union {
3205 return fromBigInt(allocator, result_q.toConst());3482 return fromBigInt(allocator, result_q.toConst());
3206 }3483 }
32073484
3208 pub fn intRem(lhs: Value, rhs: Value, allocator: Allocator) !Value {3485 pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3486 if (ty.zigTypeTag() == .Vector) {
3487 const result_data = try allocator.alloc(Value, ty.vectorLen());
3488 for (result_data) |*scalar, i| {
3489 scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3490 }
3491 return Value.Tag.aggregate.create(allocator, result_data);
3492 }
3493 return intRemScalar(lhs, rhs, allocator);
3494 }
3495
3496 pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3209 // TODO is this a performance issue? maybe we should try the operation without3497 // TODO is this a performance issue? maybe we should try the operation without
3210 // resorting to BigInt first.3498 // resorting to BigInt first.
3211 var lhs_space: Value.BigIntSpace = undefined;3499 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3232,7 +3520,18 @@ pub const Value = extern union {...@@ -3232,7 +3520,18 @@ pub const Value = extern union {
3232 return fromBigInt(allocator, result_r.toConst());3520 return fromBigInt(allocator, result_r.toConst());
3233 }3521 }
32343522
3235 pub fn intMod(lhs: Value, rhs: Value, allocator: Allocator) !Value {3523 pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3524 if (ty.zigTypeTag() == .Vector) {
3525 const result_data = try allocator.alloc(Value, ty.vectorLen());
3526 for (result_data) |*scalar, i| {
3527 scalar.* = try intModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3528 }
3529 return Value.Tag.aggregate.create(allocator, result_data);
3530 }
3531 return intModScalar(lhs, rhs, allocator);
3532 }
3533
3534 pub fn intModScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3236 // TODO is this a performance issue? maybe we should try the operation without3535 // TODO is this a performance issue? maybe we should try the operation without
3237 // resorting to BigInt first.3536 // resorting to BigInt first.
3238 var lhs_space: Value.BigIntSpace = undefined;3537 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3270,6 +3569,17 @@ pub const Value = extern union {...@@ -3270,6 +3569,17 @@ pub const Value = extern union {
3270 }3569 }
32713570
3272 pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {3571 pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
3572 if (float_type.zigTypeTag() == .Vector) {
3573 const result_data = try arena.alloc(Value, float_type.vectorLen());
3574 for (result_data) |*scalar, i| {
3575 scalar.* = try floatRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
3576 }
3577 return Value.Tag.aggregate.create(arena, result_data);
3578 }
3579 return floatRemScalar(lhs, rhs, float_type, arena, target);
3580 }
3581
3582 pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
3273 switch (float_type.floatBits(target)) {3583 switch (float_type.floatBits(target)) {
3274 16 => {3584 16 => {
3275 const lhs_val = lhs.toFloat(f16);3585 const lhs_val = lhs.toFloat(f16);
...@@ -3304,6 +3614,17 @@ pub const Value = extern union {...@@ -3304,6 +3614,17 @@ pub const Value = extern union {
3304 }3614 }
33053615
3306 pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {3616 pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
3617 if (float_type.zigTypeTag() == .Vector) {
3618 const result_data = try arena.alloc(Value, float_type.vectorLen());
3619 for (result_data) |*scalar, i| {
3620 scalar.* = try floatModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
3621 }
3622 return Value.Tag.aggregate.create(arena, result_data);
3623 }
3624 return floatModScalar(lhs, rhs, float_type, arena, target);
3625 }
3626
3627 pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
3307 switch (float_type.floatBits(target)) {3628 switch (float_type.floatBits(target)) {
3308 16 => {3629 16 => {
3309 const lhs_val = lhs.toFloat(f16);3630 const lhs_val = lhs.toFloat(f16);
...@@ -3337,7 +3658,18 @@ pub const Value = extern union {...@@ -3337,7 +3658,18 @@ pub const Value = extern union {
3337 }3658 }
3338 }3659 }
33393660
3340 pub fn intMul(lhs: Value, rhs: Value, allocator: Allocator) !Value {3661 pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3662 if (ty.zigTypeTag() == .Vector) {
3663 const result_data = try allocator.alloc(Value, ty.vectorLen());
3664 for (result_data) |*scalar, i| {
3665 scalar.* = try intMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3666 }
3667 return Value.Tag.aggregate.create(allocator, result_data);
3668 }
3669 return intMulScalar(lhs, rhs, allocator);
3670 }
3671
3672 pub fn intMulScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3341 // TODO is this a performance issue? maybe we should try the operation without3673 // TODO is this a performance issue? maybe we should try the operation without
3342 // resorting to BigInt first.3674 // resorting to BigInt first.
3343 var lhs_space: Value.BigIntSpace = undefined;3675 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3358,7 +3690,32 @@ pub const Value = extern union {...@@ -3358,7 +3690,32 @@ pub const Value = extern union {
3358 return fromBigInt(allocator, result_bigint.toConst());3690 return fromBigInt(allocator, result_bigint.toConst());
3359 }3691 }
33603692
3361 pub fn intTrunc(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {3693 pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
3694 if (ty.zigTypeTag() == .Vector) {
3695 const result_data = try allocator.alloc(Value, ty.vectorLen());
3696 for (result_data) |*scalar, i| {
3697 scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, bits);
3698 }
3699 return Value.Tag.aggregate.create(allocator, result_data);
3700 }
3701 return intTruncScalar(val, allocator, signedness, bits);
3702 }
3703
3704 /// This variant may vectorize on `bits`. Asserts that `bits` is a (vector of) `u16`.
3705 pub fn intTruncBitsAsValue(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: Value) !Value {
3706 if (ty.zigTypeTag() == .Vector) {
3707 const result_data = try allocator.alloc(Value, ty.vectorLen());
3708 for (result_data) |*scalar, i| {
3709 scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, @intCast(u16, bits.indexVectorlike(i).toUnsignedInt()));
3710 }
3711 return Value.Tag.aggregate.create(allocator, result_data);
3712 }
3713 return intTruncScalar(val, allocator, signedness, @intCast(u16, bits.toUnsignedInt()));
3714 }
3715
3716 pub fn intTruncScalar(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
3717 if (bits == 0) return Value.zero;
3718
3362 var val_space: Value.BigIntSpace = undefined;3719 var val_space: Value.BigIntSpace = undefined;
3363 const val_bigint = val.toBigInt(&val_space);3720 const val_bigint = val.toBigInt(&val_space);
33643721
...@@ -3372,7 +3729,18 @@ pub const Value = extern union {...@@ -3372,7 +3729,18 @@ pub const Value = extern union {
3372 return fromBigInt(allocator, result_bigint.toConst());3729 return fromBigInt(allocator, result_bigint.toConst());
3373 }3730 }
33743731
3375 pub fn shl(lhs: Value, rhs: Value, allocator: Allocator) !Value {3732 pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3733 if (ty.zigTypeTag() == .Vector) {
3734 const result_data = try allocator.alloc(Value, ty.vectorLen());
3735 for (result_data) |*scalar, i| {
3736 scalar.* = try shlScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3737 }
3738 return Value.Tag.aggregate.create(allocator, result_data);
3739 }
3740 return shlScalar(lhs, rhs, allocator);
3741 }
3742
3743 pub fn shlScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3376 // TODO is this a performance issue? maybe we should try the operation without3744 // TODO is this a performance issue? maybe we should try the operation without
3377 // resorting to BigInt first.3745 // resorting to BigInt first.
3378 var lhs_space: Value.BigIntSpace = undefined;3746 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3428,6 +3796,23 @@ pub const Value = extern union {...@@ -3428,6 +3796,23 @@ pub const Value = extern union {
3428 ty: Type,3796 ty: Type,
3429 arena: Allocator,3797 arena: Allocator,
3430 target: Target,3798 target: Target,
3799 ) !Value {
3800 if (ty.zigTypeTag() == .Vector) {
3801 const result_data = try arena.alloc(Value, ty.vectorLen());
3802 for (result_data) |*scalar, i| {
3803 scalar.* = try shlSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3804 }
3805 return Value.Tag.aggregate.create(arena, result_data);
3806 }
3807 return shlSatScalar(lhs, rhs, ty, arena, target);
3808 }
3809
3810 pub fn shlSatScalar(
3811 lhs: Value,
3812 rhs: Value,
3813 ty: Type,
3814 arena: Allocator,
3815 target: Target,
3431 ) !Value {3816 ) !Value {
3432 // TODO is this a performance issue? maybe we should try the operation without3817 // TODO is this a performance issue? maybe we should try the operation without
3433 // resorting to BigInt first.3818 // resorting to BigInt first.
...@@ -3456,13 +3841,41 @@ pub const Value = extern union {...@@ -3456,13 +3841,41 @@ pub const Value = extern union {
3456 arena: Allocator,3841 arena: Allocator,
3457 target: Target,3842 target: Target,
3458 ) !Value {3843 ) !Value {
3459 const shifted = try lhs.shl(rhs, arena);3844 if (ty.zigTypeTag() == .Vector) {
3845 const result_data = try arena.alloc(Value, ty.vectorLen());
3846 for (result_data) |*scalar, i| {
3847 scalar.* = try shlTruncScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
3848 }
3849 return Value.Tag.aggregate.create(arena, result_data);
3850 }
3851 return shlTruncScalar(lhs, rhs, ty, arena, target);
3852 }
3853
3854 pub fn shlTruncScalar(
3855 lhs: Value,
3856 rhs: Value,
3857 ty: Type,
3858 arena: Allocator,
3859 target: Target,
3860 ) !Value {
3861 const shifted = try lhs.shl(rhs, ty, arena);
3460 const int_info = ty.intInfo(target);3862 const int_info = ty.intInfo(target);
3461 const truncated = try shifted.intTrunc(arena, int_info.signedness, int_info.bits);3863 const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits);
3462 return truncated;3864 return truncated;
3463 }3865 }
34643866
3465 pub fn shr(lhs: Value, rhs: Value, allocator: Allocator) !Value {3867 pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
3868 if (ty.zigTypeTag() == .Vector) {
3869 const result_data = try allocator.alloc(Value, ty.vectorLen());
3870 for (result_data) |*scalar, i| {
3871 scalar.* = try shrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
3872 }
3873 return Value.Tag.aggregate.create(allocator, result_data);
3874 }
3875 return shrScalar(lhs, rhs, allocator);
3876 }
3877
3878 pub fn shrScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
3466 // TODO is this a performance issue? maybe we should try the operation without3879 // TODO is this a performance issue? maybe we should try the operation without
3467 // resorting to BigInt first.3880 // resorting to BigInt first.
3468 var lhs_space: Value.BigIntSpace = undefined;3881 var lhs_space: Value.BigIntSpace = undefined;
...@@ -3495,6 +3908,23 @@ pub const Value = extern union {...@@ -3495,6 +3908,23 @@ pub const Value = extern union {
3495 float_type: Type,3908 float_type: Type,
3496 arena: Allocator,3909 arena: Allocator,
3497 target: Target,3910 target: Target,
3911 ) !Value {
3912 if (float_type.zigTypeTag() == .Vector) {
3913 const result_data = try arena.alloc(Value, float_type.vectorLen());
3914 for (result_data) |*scalar, i| {
3915 scalar.* = try floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
3916 }
3917 return Value.Tag.aggregate.create(arena, result_data);
3918 }
3919 return floatAddScalar(lhs, rhs, float_type, arena, target);
3920 }
3921
3922 pub fn floatAddScalar(
3923 lhs: Value,
3924 rhs: Value,
3925 float_type: Type,
3926 arena: Allocator,
3927 target: Target,
3498 ) !Value {3928 ) !Value {
3499 switch (float_type.floatBits(target)) {3929 switch (float_type.floatBits(target)) {
3500 16 => {3930 16 => {
...@@ -3532,6 +3962,23 @@ pub const Value = extern union {...@@ -3532,6 +3962,23 @@ pub const Value = extern union {
3532 float_type: Type,3962 float_type: Type,
3533 arena: Allocator,3963 arena: Allocator,
3534 target: Target,3964 target: Target,
3965 ) !Value {
3966 if (float_type.zigTypeTag() == .Vector) {
3967 const result_data = try arena.alloc(Value, float_type.vectorLen());
3968 for (result_data) |*scalar, i| {
3969 scalar.* = try floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
3970 }
3971 return Value.Tag.aggregate.create(arena, result_data);
3972 }
3973 return floatSubScalar(lhs, rhs, float_type, arena, target);
3974 }
3975
3976 pub fn floatSubScalar(
3977 lhs: Value,
3978 rhs: Value,
3979 float_type: Type,
3980 arena: Allocator,
3981 target: Target,
3535 ) !Value {3982 ) !Value {
3536 switch (float_type.floatBits(target)) {3983 switch (float_type.floatBits(target)) {
3537 16 => {3984 16 => {
...@@ -3569,6 +4016,23 @@ pub const Value = extern union {...@@ -3569,6 +4016,23 @@ pub const Value = extern union {
3569 float_type: Type,4016 float_type: Type,
3570 arena: Allocator,4017 arena: Allocator,
3571 target: Target,4018 target: Target,
4019 ) !Value {
4020 if (float_type.zigTypeTag() == .Vector) {
4021 const result_data = try arena.alloc(Value, float_type.vectorLen());
4022 for (result_data) |*scalar, i| {
4023 scalar.* = try floatDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4024 }
4025 return Value.Tag.aggregate.create(arena, result_data);
4026 }
4027 return floatDivScalar(lhs, rhs, float_type, arena, target);
4028 }
4029
4030 pub fn floatDivScalar(
4031 lhs: Value,
4032 rhs: Value,
4033 float_type: Type,
4034 arena: Allocator,
4035 target: Target,
3572 ) !Value {4036 ) !Value {
3573 switch (float_type.floatBits(target)) {4037 switch (float_type.floatBits(target)) {
3574 16 => {4038 16 => {
...@@ -3609,6 +4073,23 @@ pub const Value = extern union {...@@ -3609,6 +4073,23 @@ pub const Value = extern union {
3609 float_type: Type,4073 float_type: Type,
3610 arena: Allocator,4074 arena: Allocator,
3611 target: Target,4075 target: Target,
4076 ) !Value {
4077 if (float_type.zigTypeTag() == .Vector) {
4078 const result_data = try arena.alloc(Value, float_type.vectorLen());
4079 for (result_data) |*scalar, i| {
4080 scalar.* = try floatDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4081 }
4082 return Value.Tag.aggregate.create(arena, result_data);
4083 }
4084 return floatDivFloorScalar(lhs, rhs, float_type, arena, target);
4085 }
4086
4087 pub fn floatDivFloorScalar(
4088 lhs: Value,
4089 rhs: Value,
4090 float_type: Type,
4091 arena: Allocator,
4092 target: Target,
3612 ) !Value {4093 ) !Value {
3613 switch (float_type.floatBits(target)) {4094 switch (float_type.floatBits(target)) {
3614 16 => {4095 16 => {
...@@ -3649,6 +4130,23 @@ pub const Value = extern union {...@@ -3649,6 +4130,23 @@ pub const Value = extern union {
3649 float_type: Type,4130 float_type: Type,
3650 arena: Allocator,4131 arena: Allocator,
3651 target: Target,4132 target: Target,
4133 ) !Value {
4134 if (float_type.zigTypeTag() == .Vector) {
4135 const result_data = try arena.alloc(Value, float_type.vectorLen());
4136 for (result_data) |*scalar, i| {
4137 scalar.* = try floatDivTruncScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4138 }
4139 return Value.Tag.aggregate.create(arena, result_data);
4140 }
4141 return floatDivTruncScalar(lhs, rhs, float_type, arena, target);
4142 }
4143
4144 pub fn floatDivTruncScalar(
4145 lhs: Value,
4146 rhs: Value,
4147 float_type: Type,
4148 arena: Allocator,
4149 target: Target,
3652 ) !Value {4150 ) !Value {
3653 switch (float_type.floatBits(target)) {4151 switch (float_type.floatBits(target)) {
3654 16 => {4152 16 => {
...@@ -3689,6 +4187,23 @@ pub const Value = extern union {...@@ -3689,6 +4187,23 @@ pub const Value = extern union {
3689 float_type: Type,4187 float_type: Type,
3690 arena: Allocator,4188 arena: Allocator,
3691 target: Target,4189 target: Target,
4190 ) !Value {
4191 if (float_type.zigTypeTag() == .Vector) {
4192 const result_data = try arena.alloc(Value, float_type.vectorLen());
4193 for (result_data) |*scalar, i| {
4194 scalar.* = try floatMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
4195 }
4196 return Value.Tag.aggregate.create(arena, result_data);
4197 }
4198 return floatMulScalar(lhs, rhs, float_type, arena, target);
4199 }
4200
4201 pub fn floatMulScalar(
4202 lhs: Value,
4203 rhs: Value,
4204 float_type: Type,
4205 arena: Allocator,
4206 target: Target,
3692 ) !Value {4207 ) !Value {
3693 switch (float_type.floatBits(target)) {4208 switch (float_type.floatBits(target)) {
3694 16 => {4209 16 => {
...@@ -3724,6 +4239,17 @@ pub const Value = extern union {...@@ -3724,6 +4239,17 @@ pub const Value = extern union {
3724 }4239 }
37254240
3726 pub fn sqrt(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4241 pub fn sqrt(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4242 if (float_type.zigTypeTag() == .Vector) {
4243 const result_data = try arena.alloc(Value, float_type.vectorLen());
4244 for (result_data) |*scalar, i| {
4245 scalar.* = try sqrtScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4246 }
4247 return Value.Tag.aggregate.create(arena, result_data);
4248 }
4249 return sqrtScalar(val, float_type, arena, target);
4250 }
4251
4252 pub fn sqrtScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3727 switch (float_type.floatBits(target)) {4253 switch (float_type.floatBits(target)) {
3728 16 => {4254 16 => {
3729 const f = val.toFloat(f16);4255 const f = val.toFloat(f16);
...@@ -3756,6 +4282,17 @@ pub const Value = extern union {...@@ -3756,6 +4282,17 @@ pub const Value = extern union {
3756 }4282 }
37574283
3758 pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4284 pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4285 if (float_type.zigTypeTag() == .Vector) {
4286 const result_data = try arena.alloc(Value, float_type.vectorLen());
4287 for (result_data) |*scalar, i| {
4288 scalar.* = try sinScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4289 }
4290 return Value.Tag.aggregate.create(arena, result_data);
4291 }
4292 return sinScalar(val, float_type, arena, target);
4293 }
4294
4295 pub fn sinScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3759 switch (float_type.floatBits(target)) {4296 switch (float_type.floatBits(target)) {
3760 16 => {4297 16 => {
3761 const f = val.toFloat(f16);4298 const f = val.toFloat(f16);
...@@ -3788,6 +4325,17 @@ pub const Value = extern union {...@@ -3788,6 +4325,17 @@ pub const Value = extern union {
3788 }4325 }
37894326
3790 pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4327 pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4328 if (float_type.zigTypeTag() == .Vector) {
4329 const result_data = try arena.alloc(Value, float_type.vectorLen());
4330 for (result_data) |*scalar, i| {
4331 scalar.* = try cosScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4332 }
4333 return Value.Tag.aggregate.create(arena, result_data);
4334 }
4335 return cosScalar(val, float_type, arena, target);
4336 }
4337
4338 pub fn cosScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3791 switch (float_type.floatBits(target)) {4339 switch (float_type.floatBits(target)) {
3792 16 => {4340 16 => {
3793 const f = val.toFloat(f16);4341 const f = val.toFloat(f16);
...@@ -3820,6 +4368,17 @@ pub const Value = extern union {...@@ -3820,6 +4368,17 @@ pub const Value = extern union {
3820 }4368 }
38214369
3822 pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4370 pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4371 if (float_type.zigTypeTag() == .Vector) {
4372 const result_data = try arena.alloc(Value, float_type.vectorLen());
4373 for (result_data) |*scalar, i| {
4374 scalar.* = try expScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4375 }
4376 return Value.Tag.aggregate.create(arena, result_data);
4377 }
4378 return expScalar(val, float_type, arena, target);
4379 }
4380
4381 pub fn expScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3823 switch (float_type.floatBits(target)) {4382 switch (float_type.floatBits(target)) {
3824 16 => {4383 16 => {
3825 const f = val.toFloat(f16);4384 const f = val.toFloat(f16);
...@@ -3852,6 +4411,17 @@ pub const Value = extern union {...@@ -3852,6 +4411,17 @@ pub const Value = extern union {
3852 }4411 }
38534412
3854 pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4413 pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4414 if (float_type.zigTypeTag() == .Vector) {
4415 const result_data = try arena.alloc(Value, float_type.vectorLen());
4416 for (result_data) |*scalar, i| {
4417 scalar.* = try exp2Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4418 }
4419 return Value.Tag.aggregate.create(arena, result_data);
4420 }
4421 return exp2Scalar(val, float_type, arena, target);
4422 }
4423
4424 pub fn exp2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3855 switch (float_type.floatBits(target)) {4425 switch (float_type.floatBits(target)) {
3856 16 => {4426 16 => {
3857 const f = val.toFloat(f16);4427 const f = val.toFloat(f16);
...@@ -3884,6 +4454,17 @@ pub const Value = extern union {...@@ -3884,6 +4454,17 @@ pub const Value = extern union {
3884 }4454 }
38854455
3886 pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4456 pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4457 if (float_type.zigTypeTag() == .Vector) {
4458 const result_data = try arena.alloc(Value, float_type.vectorLen());
4459 for (result_data) |*scalar, i| {
4460 scalar.* = try logScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4461 }
4462 return Value.Tag.aggregate.create(arena, result_data);
4463 }
4464 return logScalar(val, float_type, arena, target);
4465 }
4466
4467 pub fn logScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3887 switch (float_type.floatBits(target)) {4468 switch (float_type.floatBits(target)) {
3888 16 => {4469 16 => {
3889 const f = val.toFloat(f16);4470 const f = val.toFloat(f16);
...@@ -3916,6 +4497,17 @@ pub const Value = extern union {...@@ -3916,6 +4497,17 @@ pub const Value = extern union {
3916 }4497 }
39174498
3918 pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4499 pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4500 if (float_type.zigTypeTag() == .Vector) {
4501 const result_data = try arena.alloc(Value, float_type.vectorLen());
4502 for (result_data) |*scalar, i| {
4503 scalar.* = try log2Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4504 }
4505 return Value.Tag.aggregate.create(arena, result_data);
4506 }
4507 return log2Scalar(val, float_type, arena, target);
4508 }
4509
4510 pub fn log2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3919 switch (float_type.floatBits(target)) {4511 switch (float_type.floatBits(target)) {
3920 16 => {4512 16 => {
3921 const f = val.toFloat(f16);4513 const f = val.toFloat(f16);
...@@ -3948,6 +4540,17 @@ pub const Value = extern union {...@@ -3948,6 +4540,17 @@ pub const Value = extern union {
3948 }4540 }
39494541
3950 pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4542 pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4543 if (float_type.zigTypeTag() == .Vector) {
4544 const result_data = try arena.alloc(Value, float_type.vectorLen());
4545 for (result_data) |*scalar, i| {
4546 scalar.* = try log10Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4547 }
4548 return Value.Tag.aggregate.create(arena, result_data);
4549 }
4550 return log10Scalar(val, float_type, arena, target);
4551 }
4552
4553 pub fn log10Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3951 switch (float_type.floatBits(target)) {4554 switch (float_type.floatBits(target)) {
3952 16 => {4555 16 => {
3953 const f = val.toFloat(f16);4556 const f = val.toFloat(f16);
...@@ -3980,6 +4583,17 @@ pub const Value = extern union {...@@ -3980,6 +4583,17 @@ pub const Value = extern union {
3980 }4583 }
39814584
3982 pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4585 pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4586 if (float_type.zigTypeTag() == .Vector) {
4587 const result_data = try arena.alloc(Value, float_type.vectorLen());
4588 for (result_data) |*scalar, i| {
4589 scalar.* = try fabsScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4590 }
4591 return Value.Tag.aggregate.create(arena, result_data);
4592 }
4593 return fabsScalar(val, float_type, arena, target);
4594 }
4595
4596 pub fn fabsScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
3983 switch (float_type.floatBits(target)) {4597 switch (float_type.floatBits(target)) {
3984 16 => {4598 16 => {
3985 const f = val.toFloat(f16);4599 const f = val.toFloat(f16);
...@@ -4009,6 +4623,17 @@ pub const Value = extern union {...@@ -4009,6 +4623,17 @@ pub const Value = extern union {
4009 }4623 }
40104624
4011 pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4625 pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4626 if (float_type.zigTypeTag() == .Vector) {
4627 const result_data = try arena.alloc(Value, float_type.vectorLen());
4628 for (result_data) |*scalar, i| {
4629 scalar.* = try floorScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4630 }
4631 return Value.Tag.aggregate.create(arena, result_data);
4632 }
4633 return floorScalar(val, float_type, arena, target);
4634 }
4635
4636 pub fn floorScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4012 switch (float_type.floatBits(target)) {4637 switch (float_type.floatBits(target)) {
4013 16 => {4638 16 => {
4014 const f = val.toFloat(f16);4639 const f = val.toFloat(f16);
...@@ -4038,6 +4663,17 @@ pub const Value = extern union {...@@ -4038,6 +4663,17 @@ pub const Value = extern union {
4038 }4663 }
40394664
4040 pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4665 pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4666 if (float_type.zigTypeTag() == .Vector) {
4667 const result_data = try arena.alloc(Value, float_type.vectorLen());
4668 for (result_data) |*scalar, i| {
4669 scalar.* = try ceilScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4670 }
4671 return Value.Tag.aggregate.create(arena, result_data);
4672 }
4673 return ceilScalar(val, float_type, arena, target);
4674 }
4675
4676 pub fn ceilScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4041 switch (float_type.floatBits(target)) {4677 switch (float_type.floatBits(target)) {
4042 16 => {4678 16 => {
4043 const f = val.toFloat(f16);4679 const f = val.toFloat(f16);
...@@ -4067,6 +4703,17 @@ pub const Value = extern union {...@@ -4067,6 +4703,17 @@ pub const Value = extern union {
4067 }4703 }
40684704
4069 pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4705 pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4706 if (float_type.zigTypeTag() == .Vector) {
4707 const result_data = try arena.alloc(Value, float_type.vectorLen());
4708 for (result_data) |*scalar, i| {
4709 scalar.* = try roundScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4710 }
4711 return Value.Tag.aggregate.create(arena, result_data);
4712 }
4713 return roundScalar(val, float_type, arena, target);
4714 }
4715
4716 pub fn roundScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4070 switch (float_type.floatBits(target)) {4717 switch (float_type.floatBits(target)) {
4071 16 => {4718 16 => {
4072 const f = val.toFloat(f16);4719 const f = val.toFloat(f16);
...@@ -4096,6 +4743,17 @@ pub const Value = extern union {...@@ -4096,6 +4743,17 @@ pub const Value = extern union {
4096 }4743 }
40974744
4098 pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {4745 pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4746 if (float_type.zigTypeTag() == .Vector) {
4747 const result_data = try arena.alloc(Value, float_type.vectorLen());
4748 for (result_data) |*scalar, i| {
4749 scalar.* = try truncScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
4750 }
4751 return Value.Tag.aggregate.create(arena, result_data);
4752 }
4753 return truncScalar(val, float_type, arena, target);
4754 }
4755
4756 pub fn truncScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
4099 switch (float_type.floatBits(target)) {4757 switch (float_type.floatBits(target)) {
4100 16 => {4758 16 => {
4101 const f = val.toFloat(f16);4759 const f = val.toFloat(f16);
...@@ -4131,6 +4789,31 @@ pub const Value = extern union {...@@ -4131,6 +4789,31 @@ pub const Value = extern union {
4131 addend: Value,4789 addend: Value,
4132 arena: Allocator,4790 arena: Allocator,
4133 target: Target,4791 target: Target,
4792 ) Allocator.Error!Value {
4793 if (float_type.zigTypeTag() == .Vector) {
4794 const result_data = try arena.alloc(Value, float_type.vectorLen());
4795 for (result_data) |*scalar, i| {
4796 scalar.* = try mulAddScalar(
4797 float_type.scalarType(),
4798 mulend1.indexVectorlike(i),
4799 mulend2.indexVectorlike(i),
4800 addend.indexVectorlike(i),
4801 arena,
4802 target,
4803 );
4804 }
4805 return Value.Tag.aggregate.create(arena, result_data);
4806 }
4807 return mulAddScalar(float_type, mulend1, mulend2, addend, arena, target);
4808 }
4809
4810 pub fn mulAddScalar(
4811 float_type: Type,
4812 mulend1: Value,
4813 mulend2: Value,
4814 addend: Value,
4815 arena: Allocator,
4816 target: Target,
4134 ) Allocator.Error!Value {4817 ) Allocator.Error!Value {
4135 switch (float_type.floatBits(target)) {4818 switch (float_type.floatBits(target)) {
4136 16 => {4819 16 => {
test/behavior/vector.zig+250-100
...@@ -3,15 +3,17 @@ const builtin = @import("builtin");...@@ -3,15 +3,17 @@ const builtin = @import("builtin");
3const mem = std.mem;3const mem = std.mem;
4const math = std.math;4const math = std.math;
5const expect = std.testing.expect;5const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;
7const expectApproxEqRel = std.testing.expectApproxEqRel;
8const Vector = std.meta.Vector;
96
10test "implicit cast vector to array - bool" {7test "implicit cast vector to array - bool" {
11 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13
12 const S = struct {14 const S = struct {
13 fn doTheTest() !void {15 fn doTheTest() !void {
14 const a: Vector(4, bool) = [_]bool{ true, false, true, false };16 const a: @Vector(4, bool) = [_]bool{ true, false, true, false };
15 const result_array: [4]bool = a;17 const result_array: [4]bool = a;
16 try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false }));18 try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false }));
17 }19 }
...@@ -21,15 +23,20 @@ test "implicit cast vector to array - bool" {...@@ -21,15 +23,20 @@ test "implicit cast vector to array - bool" {
21}23}
2224
23test "vector wrap operators" {25test "vector wrap operators" {
24 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
31
25 const S = struct {32 const S = struct {
26 fn doTheTest() !void {33 fn doTheTest() !void {
27 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };34 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
28 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };35 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
29 try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 }));36 try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 }));
30 try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 }));37 try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 }));
31 try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 }));38 try expect(mem.eql(i32, &@as([4]i32, v *% x), &[4]i32{ 2147483647, 2, 90, 160 }));
32 var z: Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };39 var z: @Vector(4, i32) = [4]i32{ 1, 2, 3, -2147483648 };
33 try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 }));40 try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 }));
34 }41 }
35 };42 };
...@@ -38,11 +45,16 @@ test "vector wrap operators" {...@@ -38,11 +45,16 @@ test "vector wrap operators" {
38}45}
3946
40test "vector bin compares with mem.eql" {47test "vector bin compares with mem.eql" {
41 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
53
42 const S = struct {54 const S = struct {
43 fn doTheTest() !void {55 fn doTheTest() !void {
44 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };56 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
45 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };57 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };
46 try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false }));58 try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false }));
47 try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true }));59 try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true }));
48 try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false }));60 try expect(mem.eql(bool, &@as([4]bool, v < x), &[4]bool{ false, true, false, false }));
...@@ -56,11 +68,16 @@ test "vector bin compares with mem.eql" {...@@ -56,11 +68,16 @@ test "vector bin compares with mem.eql" {
56}68}
5769
58test "vector int operators" {70test "vector int operators" {
59 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76
60 const S = struct {77 const S = struct {
61 fn doTheTest() !void {78 fn doTheTest() !void {
62 var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };79 var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
63 var x: Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };80 var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
64 try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 }));81 try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 }));
65 try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 }));82 try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 }));
66 try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 }));83 try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 }));
...@@ -72,11 +89,16 @@ test "vector int operators" {...@@ -72,11 +89,16 @@ test "vector int operators" {
72}89}
7390
74test "vector float operators" {91test "vector float operators" {
75 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
97
76 const S = struct {98 const S = struct {
77 fn doTheTest() !void {99 fn doTheTest() !void {
78 var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };100 var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
79 var x: Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };101 var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
80 try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 }));102 try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 }));
81 try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 }));103 try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 }));
82 try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 }));104 try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 }));
...@@ -88,11 +110,16 @@ test "vector float operators" {...@@ -88,11 +110,16 @@ test "vector float operators" {
88}110}
89111
90test "vector bit operators" {112test "vector bit operators" {
91 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO113 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
118
92 const S = struct {119 const S = struct {
93 fn doTheTest() !void {120 fn doTheTest() !void {
94 var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };121 var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
95 var x: Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };122 var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
96 try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));123 try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
97 try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));124 try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
98 try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));125 try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
...@@ -103,10 +130,15 @@ test "vector bit operators" {...@@ -103,10 +130,15 @@ test "vector bit operators" {
103}130}
104131
105test "implicit cast vector to array" {132test "implicit cast vector to array" {
106 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138
107 const S = struct {139 const S = struct {
108 fn doTheTest() !void {140 fn doTheTest() !void {
109 var a: Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };141 var a: @Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
110 var result_array: [4]i32 = a;142 var result_array: [4]i32 = a;
111 result_array = a;143 result_array = a;
112 try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 }));144 try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 }));
...@@ -117,34 +149,50 @@ test "implicit cast vector to array" {...@@ -117,34 +149,50 @@ test "implicit cast vector to array" {
117}149}
118150
119test "array to vector" {151test "array to vector" {
120 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
121 var foo: f32 = 3.14;153 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
122 var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };154 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
123 var vec: Vector(4, f32) = arr;155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124 _ = vec;156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157
158 const S = struct {
159 fn doTheTest() !void {
160 var foo: f32 = 3.14;
161 var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
162 var vec: @Vector(4, f32) = arr;
163 try expect(mem.eql(f32, &@as([4]f32, vec), &arr));
164 }
165 };
166 try S.doTheTest();
167 comptime try S.doTheTest();
125}168}
126169
127test "vector casts of sizes not divisible by 8" {170test "vector casts of sizes not divisible by 8" {
128 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO171 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
172 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
176
129 const S = struct {177 const S = struct {
130 fn doTheTest() !void {178 fn doTheTest() !void {
131 {179 {
132 var v: Vector(4, u3) = [4]u3{ 5, 2, 3, 0 };180 var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0 };
133 var x: [4]u3 = v;181 var x: [4]u3 = v;
134 try expect(mem.eql(u3, &x, &@as([4]u3, v)));182 try expect(mem.eql(u3, &x, &@as([4]u3, v)));
135 }183 }
136 {184 {
137 var v: Vector(4, u2) = [4]u2{ 1, 2, 3, 0 };185 var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0 };
138 var x: [4]u2 = v;186 var x: [4]u2 = v;
139 try expect(mem.eql(u2, &x, &@as([4]u2, v)));187 try expect(mem.eql(u2, &x, &@as([4]u2, v)));
140 }188 }
141 {189 {
142 var v: Vector(4, u1) = [4]u1{ 1, 0, 1, 0 };190 var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0 };
143 var x: [4]u1 = v;191 var x: [4]u1 = v;
144 try expect(mem.eql(u1, &x, &@as([4]u1, v)));192 try expect(mem.eql(u1, &x, &@as([4]u1, v)));
145 }193 }
146 {194 {
147 var v: Vector(4, bool) = [4]bool{ false, false, true, false };195 var v: @Vector(4, bool) = [4]bool{ false, false, true, false };
148 var x: [4]bool = v;196 var x: [4]bool = v;
149 try expect(mem.eql(bool, &x, &@as([4]bool, v)));197 try expect(mem.eql(bool, &x, &@as([4]bool, v)));
150 }198 }
...@@ -155,14 +203,19 @@ test "vector casts of sizes not divisible by 8" {...@@ -155,14 +203,19 @@ test "vector casts of sizes not divisible by 8" {
155}203}
156204
157test "vector @splat" {205test "vector @splat" {
158 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO206 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
209 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
210 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
211
159 const S = struct {212 const S = struct {
160 fn testForT(comptime N: comptime_int, v: anytype) !void {213 fn testForT(comptime N: comptime_int, v: anytype) !void {
161 const T = @TypeOf(v);214 const T = @TypeOf(v);
162 var vec = @splat(N, v);215 var vec = @splat(N, v);
163 try expectEqual(Vector(N, T), @TypeOf(vec));216 try expect(@Vector(N, T) == @TypeOf(vec));
164 var as_array = @as([N]T, vec);217 var as_array = @as([N]T, vec);
165 for (as_array) |elem| try expectEqual(v, elem);218 for (as_array) |elem| try expect(v == elem);
166 }219 }
167 fn doTheTest() !void {220 fn doTheTest() !void {
168 // Splats with multiple-of-8 bit types that fill a 128bit vector.221 // Splats with multiple-of-8 bit types that fill a 128bit vector.
...@@ -191,10 +244,15 @@ test "vector @splat" {...@@ -191,10 +244,15 @@ test "vector @splat" {
191}244}
192245
193test "load vector elements via comptime index" {246test "load vector elements via comptime index" {
194 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO247 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
249 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252
195 const S = struct {253 const S = struct {
196 fn doTheTest() !void {254 fn doTheTest() !void {
197 var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };255 var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
198 try expect(v[0] == 1);256 try expect(v[0] == 1);
199 try expect(v[1] == 2);257 try expect(v[1] == 2);
200 try expect(loadv(&v[2]) == 3);258 try expect(loadv(&v[2]) == 3);
...@@ -209,10 +267,15 @@ test "load vector elements via comptime index" {...@@ -209,10 +267,15 @@ test "load vector elements via comptime index" {
209}267}
210268
211test "store vector elements via comptime index" {269test "store vector elements via comptime index" {
212 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
271 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
275
213 const S = struct {276 const S = struct {
214 fn doTheTest() !void {277 fn doTheTest() !void {
215 var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };278 var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
216279
217 v[2] = 42;280 v[2] = 42;
218 try expect(v[1] == 5);281 try expect(v[1] == 5);
...@@ -233,10 +296,15 @@ test "store vector elements via comptime index" {...@@ -233,10 +296,15 @@ test "store vector elements via comptime index" {
233}296}
234297
235test "load vector elements via runtime index" {298test "load vector elements via runtime index" {
236 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
304
237 const S = struct {305 const S = struct {
238 fn doTheTest() !void {306 fn doTheTest() !void {
239 var v: Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };307 var v: @Vector(4, i32) = [_]i32{ 1, 2, 3, undefined };
240 var i: u32 = 0;308 var i: u32 = 0;
241 try expect(v[i] == 1);309 try expect(v[i] == 1);
242 i += 1;310 i += 1;
...@@ -251,10 +319,15 @@ test "load vector elements via runtime index" {...@@ -251,10 +319,15 @@ test "load vector elements via runtime index" {
251}319}
252320
253test "store vector elements via runtime index" {321test "store vector elements via runtime index" {
254 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO322 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
325 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
326 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
327
255 const S = struct {328 const S = struct {
256 fn doTheTest() !void {329 fn doTheTest() !void {
257 var v: Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };330 var v: @Vector(4, i32) = [_]i32{ 1, 5, 3, undefined };
258 var i: u32 = 2;331 var i: u32 = 2;
259 v[i] = 1;332 v[i] = 1;
260 try expect(v[1] == 5);333 try expect(v[1] == 5);
...@@ -270,9 +343,14 @@ test "store vector elements via runtime index" {...@@ -270,9 +343,14 @@ test "store vector elements via runtime index" {
270}343}
271344
272test "initialize vector which is a struct field" {345test "initialize vector which is a struct field" {
273 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO346 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
347 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
348 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
349 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
351
274 const Vec4Obj = struct {352 const Vec4Obj = struct {
275 data: Vector(4, f32),353 data: @Vector(4, f32),
276 };354 };
277355
278 const S = struct {356 const S = struct {
...@@ -288,33 +366,38 @@ test "initialize vector which is a struct field" {...@@ -288,33 +366,38 @@ test "initialize vector which is a struct field" {
288}366}
289367
290test "vector comparison operators" {368test "vector comparison operators" {
291 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO369 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
370 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374
292 const S = struct {375 const S = struct {
293 fn doTheTest() !void {376 fn doTheTest() !void {
294 {377 {
295 const v1: Vector(4, bool) = [_]bool{ true, false, true, false };378 var v1: @Vector(4, bool) = [_]bool{ true, false, true, false };
296 const v2: Vector(4, bool) = [_]bool{ false, true, false, true };379 var v2: @Vector(4, bool) = [_]bool{ false, true, false, true };
297 try expectEqual(@splat(4, true), v1 == v1);380 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 == v1)));
298 try expectEqual(@splat(4, false), v1 == v2);381 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 == v2)));
299 try expectEqual(@splat(4, true), v1 != v2);382 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 != v2)));
300 try expectEqual(@splat(4, false), v2 != v2);383 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v2 != v2)));
301 }384 }
302 {385 {
303 const v1 = @splat(4, @as(u32, 0xc0ffeeee));386 var v1 = @splat(4, @as(u32, 0xc0ffeeee));
304 const v2: Vector(4, c_uint) = v1;387 var v2: @Vector(4, c_uint) = v1;
305 const v3 = @splat(4, @as(u32, 0xdeadbeef));388 var v3 = @splat(4, @as(u32, 0xdeadbeef));
306 try expectEqual(@splat(4, true), v1 == v2);389 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 == v2)));
307 try expectEqual(@splat(4, false), v1 == v3);390 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 == v3)));
308 try expectEqual(@splat(4, true), v1 != v3);391 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 != v3)));
309 try expectEqual(@splat(4, false), v1 != v2);392 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 != v2)));
310 }393 }
311 {394 {
312 // Comptime-known LHS/RHS395 // Comptime-known LHS/RHS
313 var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 };396 var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 };
314 const v2 = @splat(4, @as(u32, 2));397 const v2 = @splat(4, @as(u32, 2));
315 const v3: @Vector(4, bool) = [_]bool{ true, false, true, false };398 const v3: @Vector(4, bool) = [_]bool{ true, false, true, false };
316 try expectEqual(v3, v1 == v2);399 try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v1 == v2)));
317 try expectEqual(v3, v2 == v1);400 try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v2 == v1)));
318 }401 }
319 }402 }
320 };403 };
...@@ -323,43 +406,48 @@ test "vector comparison operators" {...@@ -323,43 +406,48 @@ test "vector comparison operators" {
323}406}
324407
325test "vector division operators" {408test "vector division operators" {
326 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO409 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
410 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
411 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
414
327 const S = struct {415 const S = struct {
328 fn doTheTestDiv(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void {416 fn doTheTestDiv(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
329 if (!comptime std.meta.trait.isSignedInt(T)) {417 if (!comptime std.meta.trait.isSignedInt(T)) {
330 const d0 = x / y;418 const d0 = x / y;
331 for (@as([4]T, d0)) |v, i| {419 for (@as([4]T, d0)) |v, i| {
332 try expectEqual(x[i] / y[i], v);420 try expect(x[i] / y[i] == v);
333 }421 }
334 }422 }
335 const d1 = @divExact(x, y);423 const d1 = @divExact(x, y);
336 for (@as([4]T, d1)) |v, i| {424 for (@as([4]T, d1)) |v, i| {
337 try expectEqual(@divExact(x[i], y[i]), v);425 try expect(@divExact(x[i], y[i]) == v);
338 }426 }
339 const d2 = @divFloor(x, y);427 const d2 = @divFloor(x, y);
340 for (@as([4]T, d2)) |v, i| {428 for (@as([4]T, d2)) |v, i| {
341 try expectEqual(@divFloor(x[i], y[i]), v);429 try expect(@divFloor(x[i], y[i]) == v);
342 }430 }
343 const d3 = @divTrunc(x, y);431 const d3 = @divTrunc(x, y);
344 for (@as([4]T, d3)) |v, i| {432 for (@as([4]T, d3)) |v, i| {
345 try expectEqual(@divTrunc(x[i], y[i]), v);433 try expect(@divTrunc(x[i], y[i]) == v);
346 }434 }
347 }435 }
348436
349 fn doTheTestMod(comptime T: type, x: Vector(4, T), y: Vector(4, T)) !void {437 fn doTheTestMod(comptime T: type, x: @Vector(4, T), y: @Vector(4, T)) !void {
350 if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {438 if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {
351 const r0 = x % y;439 const r0 = x % y;
352 for (@as([4]T, r0)) |v, i| {440 for (@as([4]T, r0)) |v, i| {
353 try expectEqual(x[i] % y[i], v);441 try expect(x[i] % y[i] == v);
354 }442 }
355 }443 }
356 const r1 = @mod(x, y);444 const r1 = @mod(x, y);
357 for (@as([4]T, r1)) |v, i| {445 for (@as([4]T, r1)) |v, i| {
358 try expectEqual(@mod(x[i], y[i]), v);446 try expect(@mod(x[i], y[i]) == v);
359 }447 }
360 const r2 = @rem(x, y);448 const r2 = @rem(x, y);
361 for (@as([4]T, r2)) |v, i| {449 for (@as([4]T, r2)) |v, i| {
362 try expectEqual(@rem(x[i], y[i]), v);450 try expect(@rem(x[i], y[i]) == v);
363 }451 }
364 }452 }
365453
...@@ -406,12 +494,17 @@ test "vector division operators" {...@@ -406,12 +494,17 @@ test "vector division operators" {
406}494}
407495
408test "vector bitwise not operator" {496test "vector bitwise not operator" {
409 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
502
410 const S = struct {503 const S = struct {
411 fn doTheTestNot(comptime T: type, x: Vector(4, T)) !void {504 fn doTheTestNot(comptime T: type, x: @Vector(4, T)) !void {
412 var y = ~x;505 var y = ~x;
413 for (@as([4]T, y)) |v, i| {506 for (@as([4]T, y)) |v, i| {
414 try expectEqual(~x[i], v);507 try expect(~x[i] == v);
415 }508 }
416 }509 }
417 fn doTheTest() !void {510 fn doTheTest() !void {
...@@ -432,23 +525,28 @@ test "vector bitwise not operator" {...@@ -432,23 +525,28 @@ test "vector bitwise not operator" {
432}525}
433526
434test "vector shift operators" {527test "vector shift operators" {
435 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO528 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
529 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533
436 const S = struct {534 const S = struct {
437 fn doTheTestShift(x: anytype, y: anytype) !void {535 fn doTheTestShift(x: anytype, y: anytype) !void {
438 const N = @typeInfo(@TypeOf(x)).Array.len;536 const N = @typeInfo(@TypeOf(x)).Array.len;
439 const TX = @typeInfo(@TypeOf(x)).Array.child;537 const TX = @typeInfo(@TypeOf(x)).Array.child;
440 const TY = @typeInfo(@TypeOf(y)).Array.child;538 const TY = @typeInfo(@TypeOf(y)).Array.child;
441539
442 var xv = @as(Vector(N, TX), x);540 var xv = @as(@Vector(N, TX), x);
443 var yv = @as(Vector(N, TY), y);541 var yv = @as(@Vector(N, TY), y);
444542
445 var z0 = xv >> yv;543 var z0 = xv >> yv;
446 for (@as([N]TX, z0)) |v, i| {544 for (@as([N]TX, z0)) |v, i| {
447 try expectEqual(x[i] >> y[i], v);545 try expect(x[i] >> y[i] == v);
448 }546 }
449 var z1 = xv << yv;547 var z1 = xv << yv;
450 for (@as([N]TX, z1)) |v, i| {548 for (@as([N]TX, z1)) |v, i| {
451 try expectEqual(x[i] << y[i], v);549 try expect(x[i] << y[i] == v);
452 }550 }
453 }551 }
454 fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void {552 fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void {
...@@ -456,13 +554,13 @@ test "vector shift operators" {...@@ -456,13 +554,13 @@ test "vector shift operators" {
456 const TX = @typeInfo(@TypeOf(x)).Array.child;554 const TX = @typeInfo(@TypeOf(x)).Array.child;
457 const TY = @typeInfo(@TypeOf(y)).Array.child;555 const TY = @typeInfo(@TypeOf(y)).Array.child;
458556
459 var xv = @as(Vector(N, TX), x);557 var xv = @as(@Vector(N, TX), x);
460 var yv = @as(Vector(N, TY), y);558 var yv = @as(@Vector(N, TY), y);
461559
462 var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv);560 var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv);
463 for (@as([N]TX, z)) |v, i| {561 for (@as([N]TX, z)) |v, i| {
464 const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i];562 const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i];
465 try expectEqual(check, v);563 try expect(check == v);
466 }564 }
467 }565 }
468 fn doTheTest() !void {566 fn doTheTest() !void {
...@@ -663,11 +761,16 @@ test "vector reduce operation" {...@@ -663,11 +761,16 @@ test "vector reduce operation" {
663}761}
664762
665test "mask parameter of @shuffle is comptime scope" {763test "mask parameter of @shuffle is comptime scope" {
666 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO764 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
667 const __v4hi = std.meta.Vector(4, i16);765 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
767 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
768 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
769
770 const __v4hi = @Vector(4, i16);
668 var v4_a = __v4hi{ 0, 0, 0, 0 };771 var v4_a = __v4hi{ 0, 0, 0, 0 };
669 var v4_b = __v4hi{ 0, 0, 0, 0 };772 var v4_b = __v4hi{ 0, 0, 0, 0 };
670 var shuffled: __v4hi = @shuffle(i16, v4_a, v4_b, std.meta.Vector(4, i32){773 var shuffled: __v4hi = @shuffle(i16, v4_a, v4_b, @Vector(4, i32){
671 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),774 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
672 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),775 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
673 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),776 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
...@@ -677,13 +780,30 @@ test "mask parameter of @shuffle is comptime scope" {...@@ -677,13 +780,30 @@ test "mask parameter of @shuffle is comptime scope" {
677}780}
678781
679test "saturating add" {782test "saturating add" {
680 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO783 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
784 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
785 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
788
681 const S = struct {789 const S = struct {
682 fn doTheTest() !void {790 fn doTheTest() !void {
683 const u8x3 = std.meta.Vector(3, u8);791 { // Broken out to avoid https://github.com/ziglang/zig/issues/11251
684 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 }));792 const u8x3 = @Vector(3, u8);
685 const i8x3 = std.meta.Vector(3, i8);793 var lhs = u8x3{ 255, 254, 1 };
686 try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 }));794 var rhs = u8x3{ 1, 2, 255 };
795 var result = lhs +| rhs;
796 const expected = u8x3{ 255, 255, 255 };
797 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
798 }
799 { // Broken out to avoid https://github.com/ziglang/zig/issues/11251
800 const i8x3 = @Vector(3, i8);
801 var lhs = i8x3{ 127, 126, 1 };
802 var rhs = i8x3{ 1, 2, 127 };
803 var result = lhs +| rhs;
804 const expected = i8x3{ 127, 127, 127 };
805 try expect(mem.eql(i8, &@as([3]i8, expected), &@as([3]i8, result)));
806 }
687 }807 }
688 };808 };
689 try S.doTheTest();809 try S.doTheTest();
...@@ -691,11 +811,21 @@ test "saturating add" {...@@ -691,11 +811,21 @@ test "saturating add" {
691}811}
692812
693test "saturating subtraction" {813test "saturating subtraction" {
694 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO814 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
815 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
816 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
817 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
819
695 const S = struct {820 const S = struct {
696 fn doTheTest() !void {821 fn doTheTest() !void {
697 const u8x3 = std.meta.Vector(3, u8);822 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
698 try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 }));823 const u8x3 = @Vector(3, u8);
824 var lhs = u8x3{ 0, 0, 0 };
825 var rhs = u8x3{ 255, 255, 255 };
826 var result = lhs -| rhs;
827 const expected = u8x3{ 0, 0, 0 };
828 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
699 }829 }
700 };830 };
701 try S.doTheTest();831 try S.doTheTest();
...@@ -703,14 +833,24 @@ test "saturating subtraction" {...@@ -703,14 +833,24 @@ test "saturating subtraction" {
703}833}
704834
705test "saturating multiplication" {835test "saturating multiplication" {
706 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO836 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
837 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
839 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
840 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
841
707 // TODO: once #9660 has been solved, remove this line842 // TODO: once #9660 has been solved, remove this line
708 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;843 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
709844
710 const S = struct {845 const S = struct {
711 fn doTheTest() !void {846 fn doTheTest() !void {
712 const u8x3 = std.meta.Vector(3, u8);847 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
713 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 }));848 const u8x3 = @Vector(3, u8);
849 var lhs = u8x3{ 2, 2, 2 };
850 var rhs = u8x3{ 255, 255, 255 };
851 var result = lhs *| rhs;
852 const expected = u8x3{ 255, 255, 255 };
853 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
714 }854 }
715 };855 };
716856
...@@ -719,11 +859,21 @@ test "saturating multiplication" {...@@ -719,11 +859,21 @@ test "saturating multiplication" {
719}859}
720860
721test "saturating shift-left" {861test "saturating shift-left" {
722 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO862 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
863 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
864 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
865 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
867
723 const S = struct {868 const S = struct {
724 fn doTheTest() !void {869 fn doTheTest() !void {
725 const u8x3 = std.meta.Vector(3, u8);870 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
726 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 }));871 const u8x3 = @Vector(3, u8);
872 var lhs = u8x3{ 1, 1, 1 };
873 var rhs = u8x3{ 255, 255, 255 };
874 var result = lhs <<| rhs;
875 const expected = u8x3{ 255, 255, 255 };
876 try expect(mem.eql(u8, &@as([3]u8, expected), &@as([3]u8, result)));
727 }877 }
728 };878 };
729 try S.doTheTest();879 try S.doTheTest();