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
signaturebadge-question-mark 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 {
308308 /// `!=`. Result type is always bool.
309309 /// Uses the `bin_op` field.
310310 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
312316 /// Conditional branch.
313317 /// Result type is always noreturn; no instructions in a block follow this one.
......@@ -781,6 +785,20 @@ pub const Shuffle = struct {
781785 mask_len: u32,
782786};
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
784802/// Trailing:
785803/// 0. `Inst.Ref` for every outputs_len
786804/// 1. `Inst.Ref` for every inputs_len
......@@ -886,6 +904,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
886904 .shl_sat,
887905 .min,
888906 .max,
907 .bool_and,
908 .bool_or,
889909 => return air.typeOf(datas[inst].bin_op.lhs),
890910
891911 .sqrt,
......@@ -917,8 +937,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
917937 .is_non_err,
918938 .is_err_ptr,
919939 .is_non_err_ptr,
920 .bool_and,
921 .bool_or,
922940 => return Type.initTag(.bool),
923941
924942 .const_ty => return Type.initTag(.type),
......@@ -942,6 +960,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
942960 .aggregate_init,
943961 .union_init,
944962 .field_parent_ptr,
963 .cmp_vector,
945964 => return air.getRefType(datas[inst].ty_pl.ty),
946965
947966 .not,
src/Liveness.zig+4
......@@ -441,6 +441,10 @@ fn analyzeInst(
441441 const reduce = inst_datas[inst].reduce;
442442 return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
443443 },
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 },
444448 .aggregate_init => {
445449 const ty_pl = inst_datas[inst].ty_pl;
446450 const aggregate_ty = a.air.getRefType(ty_pl.ty);
src/Sema.zig+291-234
......@@ -397,6 +397,20 @@ pub const Block = struct {
397397 });
398398 }
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
400414 fn addAggregateInit(
401415 block: *Block,
402416 aggregate_ty: Type,
......@@ -2091,7 +2105,7 @@ fn zirEnumDecl(
20912105 });
20922106 } else if (any_values) {
20932107 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)
20952109 else
20962110 Value.zero;
20972111 last_tag_val = tag_val;
......@@ -8178,14 +8192,22 @@ fn zirShl(
81788192 defer tracy.end();
81798193
81808194 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
8195 const src = inst_data.src();
81818196 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
81828197 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
81838198 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
81848199 const lhs = sema.resolveInst(extra.lhs);
81858200 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
81878209 // 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
81908212 const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
81918213 const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
......@@ -8199,35 +8221,31 @@ fn zirShl(
81998221 }
82008222 }
82018223
8202 const lhs_ty = sema.typeOf(lhs);
8203 const rhs_ty = sema.typeOf(rhs);
8204 const target = sema.mod.getTarget();
8205
82068224 const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
82078225 if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
82088226 const rhs_val = maybe_rhs_val orelse break :rs rhs_src;
82098227
82108228 const val = switch (air_tag) {
82118229 .shl_exact => val: {
8212 const shifted = try lhs_val.shl(rhs_val, sema.arena);
8213 if (lhs_ty.zigTypeTag() == .ComptimeInt) {
8230 const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena);
8231 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
82148232 break :val shifted;
82158233 }
8216 const int_info = lhs_ty.intInfo(target);
8217 const truncated = try shifted.intTrunc(sema.arena, int_info.signedness, int_info.bits);
8218 if (truncated.compareHetero(.eq, shifted)) {
8234 const int_info = scalar_ty.intInfo(target);
8235 const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits);
8236 if (truncated.compare(.eq, shifted, lhs_ty)) {
82198237 break :val shifted;
82208238 }
82218239 return sema.addConstUndef(lhs_ty);
82228240 },
82238241
8224 .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt)
8225 try lhs_val.shl(rhs_val, sema.arena)
8242 .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
8243 try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
82268244 else
82278245 try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),
82288246
8229 .shl => if (lhs_ty.zigTypeTag() == .ComptimeInt)
8230 try lhs_val.shl(rhs_val, sema.arena)
8247 .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt)
8248 try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
82318249 else
82328250 try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),
82338251
......@@ -8242,7 +8260,7 @@ fn zirShl(
82428260 const new_rhs = if (air_tag == .shl_sat) rhs: {
82438261 // Limit the RHS type for saturating shl to be an integer as small as the LHS.
82448262 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)
82468264 {
82478265 const max_int = try sema.addConstant(
82488266 lhs_ty,
......@@ -8269,15 +8287,18 @@ fn zirShr(
82698287 defer tracy.end();
82708288
82718289 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
8290 const src = inst_data.src();
82728291 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
82738292 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
82748293 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
82758294 const lhs = sema.resolveInst(extra.lhs);
82768295 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
82788300 const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {
82798301 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
8280 const lhs_ty = sema.typeOf(lhs);
82818302 if (lhs_val.isUndef() or rhs_val.isUndef()) {
82828303 return sema.addConstUndef(lhs_ty);
82838304 }
......@@ -8287,13 +8308,12 @@ fn zirShr(
82878308 }
82888309 if (air_tag == .shr_exact) {
82898310 // Detect if any ones would be shifted out.
8290 const bits = @intCast(u16, rhs_val.toUnsignedInt());
8291 const truncated = try lhs_val.intTrunc(sema.arena, .unsigned, bits);
8311 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val);
82928312 if (!truncated.compareWithZero(.eq)) {
82938313 return sema.addConstUndef(lhs_ty);
82948314 }
82958315 }
8296 const val = try lhs_val.shr(rhs_val, sema.arena);
8316 const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena);
82978317 return sema.addConstant(lhs_ty, val);
82988318 } else {
82998319 // Even if lhs is not comptime known, we can still deduce certain things based
......@@ -8328,32 +8348,15 @@ fn zirBitwise(
83288348 const rhs = sema.resolveInst(extra.rhs);
83298349 const lhs_ty = sema.typeOf(lhs);
83308350 const rhs_ty = sema.typeOf(rhs);
8351 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
83318352
83328353 const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
83338354 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);
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
8355 const scalar_type = resolved_type.scalarType();
83428356 const scalar_tag = scalar_type.zigTypeTag();
83438357
8344 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
8345 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
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 }
8358 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
8359 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
83578360
83588361 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
83598362
......@@ -8363,16 +8366,13 @@ fn zirBitwise(
83638366
83648367 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
83658368 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 }
83698369 const result_val = switch (air_tag) {
8370 .bit_and => try lhs_val.bitwiseAnd(rhs_val, sema.arena),
8371 .bit_or => try lhs_val.bitwiseOr(rhs_val, sema.arena),
8372 .xor => try lhs_val.bitwiseXor(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, resolved_type, sema.arena),
8372 .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena),
83738373 else => unreachable,
83748374 };
8375 return sema.addConstant(scalar_type, result_val);
8375 return sema.addConstant(resolved_type, result_val);
83768376 }
83778377 }
83788378
......@@ -8399,9 +8399,9 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
83998399 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
84008400 const target = sema.mod.getTarget();
84018401 if (val.isUndef()) {
8402 return sema.addConstUndef(scalar_type);
8402 return sema.addConstUndef(operand_type);
84038403 } 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());
84058405 var elem_val_buf: Value.ElemValueBuffer = undefined;
84068406 const elems = try sema.arena.alloc(Value, vec_len);
84078407 for (elems) |*elem, i| {
......@@ -8413,8 +8413,8 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
84138413 try Value.Tag.aggregate.create(sema.arena, elems),
84148414 );
84158415 } else {
8416 const result_val = try val.bitwiseNot(scalar_type, sema.arena, target);
8417 return sema.addConstant(scalar_type, result_val);
8416 const result_val = try val.bitwiseNot(operand_type, sema.arena, target);
8417 return sema.addConstant(operand_type, result_val);
84188418 }
84198419 }
84208420
......@@ -8766,8 +8766,19 @@ fn zirNegate(
87668766 const src = inst_data.src();
87678767 const lhs_src = src;
87688768 const rhs_src = src; // TODO better source location
8769 const lhs = sema.resolveInst(.zero);
8769
87708770 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
87728783 return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
87738784}
......@@ -8985,18 +8996,8 @@ fn analyzeArithmetic(
89858996 const rhs_ty = sema.typeOf(rhs);
89868997 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
89878998 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
8988 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
8989 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
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 }
8999 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
9000
90009001 if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {
90019002 .One, .Slice => {},
90029003 .Many, .C => {
......@@ -9019,15 +9020,13 @@ fn analyzeArithmetic(
90199020 const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
90209021 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
90219022 });
9023
90229024 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
90239025 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
90249026
9025 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
9026 resolved_type.elemType()
9027 else
9028 resolved_type;
9029
9030 const scalar_tag = scalar_type.zigTypeTag();
9027 const lhs_scalar_ty = lhs_ty.scalarType();
9028 const rhs_scalar_ty = rhs_ty.scalarType();
9029 const scalar_tag = resolved_type.scalarType().zigTypeTag();
90319030
90329031 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
90339032 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
......@@ -9061,7 +9060,7 @@ fn analyzeArithmetic(
90619060 if (is_int) {
90629061 return sema.failWithUseOfUndef(block, rhs_src);
90639062 } else {
9064 return sema.addConstUndef(scalar_type);
9063 return sema.addConstUndef(resolved_type);
90659064 }
90669065 }
90679066 if (rhs_val.compareWithZero(.eq)) {
......@@ -9073,19 +9072,19 @@ fn analyzeArithmetic(
90739072 if (is_int) {
90749073 return sema.failWithUseOfUndef(block, lhs_src);
90759074 } else {
9076 return sema.addConstUndef(scalar_type);
9075 return sema.addConstUndef(resolved_type);
90779076 }
90789077 }
90799078 if (maybe_rhs_val) |rhs_val| {
90809079 if (is_int) {
90819080 return sema.addConstant(
9082 scalar_type,
9083 try lhs_val.intAdd(rhs_val, sema.arena),
9081 resolved_type,
9082 try lhs_val.intAdd(rhs_val, resolved_type, sema.arena),
90849083 );
90859084 } else {
90869085 return sema.addConstant(
9087 scalar_type,
9088 try lhs_val.floatAdd(rhs_val, scalar_type, sema.arena, target),
9086 resolved_type,
9087 try lhs_val.floatAdd(rhs_val, resolved_type, sema.arena, target),
90899088 );
90909089 }
90919090 } else break :rs .{ .src = rhs_src, .air_tag = .add };
......@@ -9102,15 +9101,15 @@ fn analyzeArithmetic(
91029101 }
91039102 if (maybe_rhs_val) |rhs_val| {
91049103 if (rhs_val.isUndef()) {
9105 return sema.addConstUndef(scalar_type);
9104 return sema.addConstUndef(resolved_type);
91069105 }
91079106 if (rhs_val.compareWithZero(.eq)) {
91089107 return casted_lhs;
91099108 }
91109109 if (maybe_lhs_val) |lhs_val| {
91119110 return sema.addConstant(
9112 scalar_type,
9113 try lhs_val.numberAddWrap(rhs_val, scalar_type, sema.arena, target),
9111 resolved_type,
9112 try lhs_val.numberAddWrap(rhs_val, resolved_type, sema.arena, target),
91149113 );
91159114 } else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
91169115 } else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
......@@ -9126,18 +9125,18 @@ fn analyzeArithmetic(
91269125 }
91279126 if (maybe_rhs_val) |rhs_val| {
91289127 if (rhs_val.isUndef()) {
9129 return sema.addConstUndef(scalar_type);
9128 return sema.addConstUndef(resolved_type);
91309129 }
91319130 if (rhs_val.compareWithZero(.eq)) {
91329131 return casted_lhs;
91339132 }
91349133 if (maybe_lhs_val) |lhs_val| {
91359134 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)
91379136 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);
91419140 } else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
91429141 } else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
91439142 },
......@@ -9154,7 +9153,7 @@ fn analyzeArithmetic(
91549153 if (is_int) {
91559154 return sema.failWithUseOfUndef(block, rhs_src);
91569155 } else {
9157 return sema.addConstUndef(scalar_type);
9156 return sema.addConstUndef(resolved_type);
91589157 }
91599158 }
91609159 if (rhs_val.compareWithZero(.eq)) {
......@@ -9166,19 +9165,19 @@ fn analyzeArithmetic(
91669165 if (is_int) {
91679166 return sema.failWithUseOfUndef(block, lhs_src);
91689167 } else {
9169 return sema.addConstUndef(scalar_type);
9168 return sema.addConstUndef(resolved_type);
91709169 }
91719170 }
91729171 if (maybe_rhs_val) |rhs_val| {
91739172 if (is_int) {
91749173 return sema.addConstant(
9175 scalar_type,
9176 try lhs_val.intSub(rhs_val, sema.arena),
9174 resolved_type,
9175 try lhs_val.intSub(rhs_val, resolved_type, sema.arena),
91779176 );
91789177 } else {
91799178 return sema.addConstant(
9180 scalar_type,
9181 try lhs_val.floatSub(rhs_val, scalar_type, sema.arena, target),
9179 resolved_type,
9180 try lhs_val.floatSub(rhs_val, resolved_type, sema.arena, target),
91829181 );
91839182 }
91849183 } else break :rs .{ .src = rhs_src, .air_tag = .sub };
......@@ -9190,7 +9189,7 @@ fn analyzeArithmetic(
91909189 // If either of the operands are undefined, the result is undefined.
91919190 if (maybe_rhs_val) |rhs_val| {
91929191 if (rhs_val.isUndef()) {
9193 return sema.addConstUndef(scalar_type);
9192 return sema.addConstUndef(resolved_type);
91949193 }
91959194 if (rhs_val.compareWithZero(.eq)) {
91969195 return casted_lhs;
......@@ -9198,12 +9197,12 @@ fn analyzeArithmetic(
91989197 }
91999198 if (maybe_lhs_val) |lhs_val| {
92009199 if (lhs_val.isUndef()) {
9201 return sema.addConstUndef(scalar_type);
9200 return sema.addConstUndef(resolved_type);
92029201 }
92039202 if (maybe_rhs_val) |rhs_val| {
92049203 return sema.addConstant(
9205 scalar_type,
9206 try lhs_val.numberSubWrap(rhs_val, scalar_type, sema.arena, target),
9204 resolved_type,
9205 try lhs_val.numberSubWrap(rhs_val, resolved_type, sema.arena, target),
92079206 );
92089207 } else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
92099208 } else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
......@@ -9214,7 +9213,7 @@ fn analyzeArithmetic(
92149213 // If either of the operands are undefined, result is undefined.
92159214 if (maybe_rhs_val) |rhs_val| {
92169215 if (rhs_val.isUndef()) {
9217 return sema.addConstUndef(scalar_type);
9216 return sema.addConstUndef(resolved_type);
92189217 }
92199218 if (rhs_val.compareWithZero(.eq)) {
92209219 return casted_lhs;
......@@ -9222,15 +9221,15 @@ fn analyzeArithmetic(
92229221 }
92239222 if (maybe_lhs_val) |lhs_val| {
92249223 if (lhs_val.isUndef()) {
9225 return sema.addConstUndef(scalar_type);
9224 return sema.addConstUndef(resolved_type);
92269225 }
92279226 if (maybe_rhs_val) |rhs_val| {
92289227 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)
92309229 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);
92349233 } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
92359234 } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
92369235 },
......@@ -9260,7 +9259,7 @@ fn analyzeArithmetic(
92609259 if (maybe_lhs_val) |lhs_val| {
92619260 if (!lhs_val.isUndef()) {
92629261 if (lhs_val.compareWithZero(.eq)) {
9263 return sema.addConstant(scalar_type, Value.zero);
9262 return sema.addConstant(resolved_type, Value.zero);
92649263 }
92659264 }
92669265 }
......@@ -9274,27 +9273,27 @@ fn analyzeArithmetic(
92749273 }
92759274 if (maybe_lhs_val) |lhs_val| {
92769275 if (lhs_val.isUndef()) {
9277 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
9276 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
92789277 if (maybe_rhs_val) |rhs_val| {
9279 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
9280 return sema.addConstUndef(scalar_type);
9278 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9279 return sema.addConstUndef(resolved_type);
92819280 }
92829281 }
92839282 return sema.failWithUseOfUndef(block, rhs_src);
92849283 }
9285 return sema.addConstUndef(scalar_type);
9284 return sema.addConstUndef(resolved_type);
92869285 }
92879286
92889287 if (maybe_rhs_val) |rhs_val| {
92899288 if (is_int) {
92909289 return sema.addConstant(
9291 scalar_type,
9292 try lhs_val.intDiv(rhs_val, sema.arena),
9290 resolved_type,
9291 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
92939292 );
92949293 } else {
92959294 return sema.addConstant(
9296 scalar_type,
9297 try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
9295 resolved_type,
9296 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
92989297 );
92999298 }
93009299 } else {
......@@ -9335,7 +9334,7 @@ fn analyzeArithmetic(
93359334 if (maybe_lhs_val) |lhs_val| {
93369335 if (!lhs_val.isUndef()) {
93379336 if (lhs_val.compareWithZero(.eq)) {
9338 return sema.addConstant(scalar_type, Value.zero);
9337 return sema.addConstant(resolved_type, Value.zero);
93399338 }
93409339 }
93419340 }
......@@ -9349,27 +9348,27 @@ fn analyzeArithmetic(
93499348 }
93509349 if (maybe_lhs_val) |lhs_val| {
93519350 if (lhs_val.isUndef()) {
9352 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
9351 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
93539352 if (maybe_rhs_val) |rhs_val| {
9354 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
9355 return sema.addConstUndef(scalar_type);
9353 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9354 return sema.addConstUndef(resolved_type);
93569355 }
93579356 }
93589357 return sema.failWithUseOfUndef(block, rhs_src);
93599358 }
9360 return sema.addConstUndef(scalar_type);
9359 return sema.addConstUndef(resolved_type);
93619360 }
93629361
93639362 if (maybe_rhs_val) |rhs_val| {
93649363 if (is_int) {
93659364 return sema.addConstant(
9366 scalar_type,
9367 try lhs_val.intDiv(rhs_val, sema.arena),
9365 resolved_type,
9366 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
93689367 );
93699368 } else {
93709369 return sema.addConstant(
9371 scalar_type,
9372 try lhs_val.floatDivTrunc(rhs_val, scalar_type, sema.arena, target),
9370 resolved_type,
9371 try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
93739372 );
93749373 }
93759374 } else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
......@@ -9398,7 +9397,7 @@ fn analyzeArithmetic(
93989397 if (maybe_lhs_val) |lhs_val| {
93999398 if (!lhs_val.isUndef()) {
94009399 if (lhs_val.compareWithZero(.eq)) {
9401 return sema.addConstant(scalar_type, Value.zero);
9400 return sema.addConstant(resolved_type, Value.zero);
94029401 }
94039402 }
94049403 }
......@@ -9412,27 +9411,27 @@ fn analyzeArithmetic(
94129411 }
94139412 if (maybe_lhs_val) |lhs_val| {
94149413 if (lhs_val.isUndef()) {
9415 if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
9414 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
94169415 if (maybe_rhs_val) |rhs_val| {
9417 if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
9418 return sema.addConstUndef(scalar_type);
9416 if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
9417 return sema.addConstUndef(resolved_type);
94199418 }
94209419 }
94219420 return sema.failWithUseOfUndef(block, rhs_src);
94229421 }
9423 return sema.addConstUndef(scalar_type);
9422 return sema.addConstUndef(resolved_type);
94249423 }
94259424
94269425 if (maybe_rhs_val) |rhs_val| {
94279426 if (is_int) {
94289427 return sema.addConstant(
9429 scalar_type,
9430 try lhs_val.intDivFloor(rhs_val, sema.arena),
9428 resolved_type,
9429 try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena),
94319430 );
94329431 } else {
94339432 return sema.addConstant(
9434 scalar_type,
9435 try lhs_val.floatDivFloor(rhs_val, scalar_type, sema.arena, target),
9433 resolved_type,
9434 try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
94369435 );
94379436 }
94389437 } else break :rs .{ .src = rhs_src, .air_tag = .div_floor };
......@@ -9460,7 +9459,7 @@ fn analyzeArithmetic(
94609459 return sema.failWithUseOfUndef(block, rhs_src);
94619460 } else {
94629461 if (lhs_val.compareWithZero(.eq)) {
9463 return sema.addConstant(scalar_type, Value.zero);
9462 return sema.addConstant(resolved_type, Value.zero);
94649463 }
94659464 }
94669465 }
......@@ -9477,14 +9476,14 @@ fn analyzeArithmetic(
94779476 if (is_int) {
94789477 // TODO: emit compile error if there is a remainder
94799478 return sema.addConstant(
9480 scalar_type,
9481 try lhs_val.intDiv(rhs_val, sema.arena),
9479 resolved_type,
9480 try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
94829481 );
94839482 } else {
94849483 // TODO: emit compile error if there is a remainder
94859484 return sema.addConstant(
9486 scalar_type,
9487 try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
9485 resolved_type,
9486 try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
94889487 );
94899488 }
94909489 } else break :rs .{ .src = rhs_src, .air_tag = .div_exact };
......@@ -9502,9 +9501,9 @@ fn analyzeArithmetic(
95029501 if (maybe_lhs_val) |lhs_val| {
95039502 if (!lhs_val.isUndef()) {
95049503 if (lhs_val.compareWithZero(.eq)) {
9505 return sema.addConstant(scalar_type, Value.zero);
9504 return sema.addConstant(resolved_type, Value.zero);
95069505 }
9507 if (lhs_val.compare(.eq, Value.one, scalar_type)) {
9506 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
95089507 return casted_rhs;
95099508 }
95109509 }
......@@ -9514,13 +9513,13 @@ fn analyzeArithmetic(
95149513 if (is_int) {
95159514 return sema.failWithUseOfUndef(block, rhs_src);
95169515 } else {
9517 return sema.addConstUndef(scalar_type);
9516 return sema.addConstUndef(resolved_type);
95189517 }
95199518 }
95209519 if (rhs_val.compareWithZero(.eq)) {
9521 return sema.addConstant(scalar_type, Value.zero);
9520 return sema.addConstant(resolved_type, Value.zero);
95229521 }
9523 if (rhs_val.compare(.eq, Value.one, scalar_type)) {
9522 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
95249523 return casted_lhs;
95259524 }
95269525 if (maybe_lhs_val) |lhs_val| {
......@@ -9528,18 +9527,18 @@ fn analyzeArithmetic(
95289527 if (is_int) {
95299528 return sema.failWithUseOfUndef(block, lhs_src);
95309529 } else {
9531 return sema.addConstUndef(scalar_type);
9530 return sema.addConstUndef(resolved_type);
95329531 }
95339532 }
95349533 if (is_int) {
95359534 return sema.addConstant(
9536 scalar_type,
9537 try lhs_val.intMul(rhs_val, sema.arena),
9535 resolved_type,
9536 try lhs_val.intMul(rhs_val, resolved_type, sema.arena),
95389537 );
95399538 } else {
95409539 return sema.addConstant(
9541 scalar_type,
9542 try lhs_val.floatMul(rhs_val, scalar_type, sema.arena, target),
9540 resolved_type,
9541 try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
95439542 );
95449543 }
95459544 } else break :rs .{ .src = lhs_src, .air_tag = .mul };
......@@ -9553,30 +9552,30 @@ fn analyzeArithmetic(
95539552 if (maybe_lhs_val) |lhs_val| {
95549553 if (!lhs_val.isUndef()) {
95559554 if (lhs_val.compareWithZero(.eq)) {
9556 return sema.addConstant(scalar_type, Value.zero);
9555 return sema.addConstant(resolved_type, Value.zero);
95579556 }
9558 if (lhs_val.compare(.eq, Value.one, scalar_type)) {
9557 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
95599558 return casted_rhs;
95609559 }
95619560 }
95629561 }
95639562 if (maybe_rhs_val) |rhs_val| {
95649563 if (rhs_val.isUndef()) {
9565 return sema.addConstUndef(scalar_type);
9564 return sema.addConstUndef(resolved_type);
95669565 }
95679566 if (rhs_val.compareWithZero(.eq)) {
9568 return sema.addConstant(scalar_type, Value.zero);
9567 return sema.addConstant(resolved_type, Value.zero);
95699568 }
9570 if (rhs_val.compare(.eq, Value.one, scalar_type)) {
9569 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
95719570 return casted_lhs;
95729571 }
95739572 if (maybe_lhs_val) |lhs_val| {
95749573 if (lhs_val.isUndef()) {
9575 return sema.addConstUndef(scalar_type);
9574 return sema.addConstUndef(resolved_type);
95769575 }
95779576 return sema.addConstant(
9578 scalar_type,
9579 try lhs_val.numberMulWrap(rhs_val, scalar_type, sema.arena, target),
9577 resolved_type,
9578 try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
95809579 );
95819580 } else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };
95829581 } else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
......@@ -9589,34 +9588,34 @@ fn analyzeArithmetic(
95899588 if (maybe_lhs_val) |lhs_val| {
95909589 if (!lhs_val.isUndef()) {
95919590 if (lhs_val.compareWithZero(.eq)) {
9592 return sema.addConstant(scalar_type, Value.zero);
9591 return sema.addConstant(resolved_type, Value.zero);
95939592 }
9594 if (lhs_val.compare(.eq, Value.one, scalar_type)) {
9593 if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
95959594 return casted_rhs;
95969595 }
95979596 }
95989597 }
95999598 if (maybe_rhs_val) |rhs_val| {
96009599 if (rhs_val.isUndef()) {
9601 return sema.addConstUndef(scalar_type);
9600 return sema.addConstUndef(resolved_type);
96029601 }
96039602 if (rhs_val.compareWithZero(.eq)) {
9604 return sema.addConstant(scalar_type, Value.zero);
9603 return sema.addConstant(resolved_type, Value.zero);
96059604 }
9606 if (rhs_val.compare(.eq, Value.one, scalar_type)) {
9605 if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
96079606 return casted_lhs;
96089607 }
96099608 if (maybe_lhs_val) |lhs_val| {
96109609 if (lhs_val.isUndef()) {
9611 return sema.addConstUndef(scalar_type);
9610 return sema.addConstUndef(resolved_type);
96129611 }
96139612
96149613 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)
96169615 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);
96209619 } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
96219620 } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
96229621 },
......@@ -9640,9 +9639,9 @@ fn analyzeArithmetic(
96409639 return sema.failWithUseOfUndef(block, lhs_src);
96419640 }
96429641 if (lhs_val.compareWithZero(.eq)) {
9643 return sema.addConstant(scalar_type, Value.zero);
9642 return sema.addConstant(resolved_type, Value.zero);
96449643 }
9645 } else if (lhs_ty.isSignedInt()) {
9644 } else if (lhs_scalar_ty.isSignedInt()) {
96469645 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
96479646 }
96489647 if (maybe_rhs_val) |rhs_val| {
......@@ -9653,7 +9652,7 @@ fn analyzeArithmetic(
96539652 return sema.failWithDivideByZero(block, rhs_src);
96549653 }
96559654 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);
96579656 // If this answer could possibly be different by doing `intMod`,
96589657 // we must emit a compile error. Otherwise, it's OK.
96599658 if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and
......@@ -9667,12 +9666,12 @@ fn analyzeArithmetic(
96679666 }
96689667 if (lhs_val.compareWithZero(.lt)) {
96699668 // Negative
9670 return sema.addConstant(scalar_type, Value.zero);
9669 return sema.addConstant(resolved_type, Value.zero);
96719670 }
9672 return sema.addConstant(scalar_type, rem_result);
9671 return sema.addConstant(resolved_type, rem_result);
96739672 }
96749673 break :rs .{ .src = lhs_src, .air_tag = .rem };
9675 } else if (rhs_ty.isSignedInt()) {
9674 } else if (rhs_scalar_ty.isSignedInt()) {
96769675 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
96779676 } else {
96789677 break :rs .{ .src = rhs_src, .air_tag = .rem };
......@@ -9694,8 +9693,8 @@ fn analyzeArithmetic(
96949693 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
96959694 }
96969695 return sema.addConstant(
9697 scalar_type,
9698 try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
9696 resolved_type,
9697 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
96999698 );
97009699 } else {
97019700 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
......@@ -9731,8 +9730,8 @@ fn analyzeArithmetic(
97319730 }
97329731 if (maybe_lhs_val) |lhs_val| {
97339732 return sema.addConstant(
9734 scalar_type,
9735 try lhs_val.intRem(rhs_val, sema.arena),
9733 resolved_type,
9734 try lhs_val.intRem(rhs_val, resolved_type, sema.arena),
97369735 );
97379736 }
97389737 break :rs .{ .src = lhs_src, .air_tag = .rem };
......@@ -9751,12 +9750,12 @@ fn analyzeArithmetic(
97519750 }
97529751 if (maybe_lhs_val) |lhs_val| {
97539752 if (lhs_val.isUndef()) {
9754 return sema.addConstUndef(scalar_type);
9753 return sema.addConstUndef(resolved_type);
97559754 }
97569755 if (maybe_rhs_val) |rhs_val| {
97579756 return sema.addConstant(
9758 scalar_type,
9759 try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
9757 resolved_type,
9758 try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
97609759 );
97619760 } else break :rs .{ .src = rhs_src, .air_tag = .rem };
97629761 } else break :rs .{ .src = lhs_src, .air_tag = .rem };
......@@ -9788,8 +9787,8 @@ fn analyzeArithmetic(
97889787 }
97899788 if (maybe_lhs_val) |lhs_val| {
97909789 return sema.addConstant(
9791 scalar_type,
9792 try lhs_val.intMod(rhs_val, sema.arena),
9790 resolved_type,
9791 try lhs_val.intMod(rhs_val, resolved_type, sema.arena),
97939792 );
97949793 }
97959794 break :rs .{ .src = lhs_src, .air_tag = .mod };
......@@ -9808,12 +9807,12 @@ fn analyzeArithmetic(
98089807 }
98099808 if (maybe_lhs_val) |lhs_val| {
98109809 if (lhs_val.isUndef()) {
9811 return sema.addConstUndef(scalar_type);
9810 return sema.addConstUndef(resolved_type);
98129811 }
98139812 if (maybe_rhs_val) |rhs_val| {
98149813 return sema.addConstant(
9815 scalar_type,
9816 try lhs_val.floatMod(rhs_val, scalar_type, sema.arena, target),
9814 resolved_type,
9815 try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
98179816 );
98189817 } else break :rs .{ .src = rhs_src, .air_tag = .mod };
98199818 } else break :rs .{ .src = lhs_src, .air_tag = .mod };
......@@ -10164,6 +10163,11 @@ fn analyzeCmp(
1016410163) CompileError!Air.Inst.Ref {
1016510164 const lhs_ty = sema.typeOf(lhs);
1016610165 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 }
1016710171 if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {
1016810172 // This operation allows any combination of integer and float types, regardless of the
1016910173 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
......@@ -10198,6 +10202,12 @@ fn cmpSelf(
1019810202 if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
1019910203 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
1020110211 if (lhs_val.compare(op, rhs_val, resolved_type)) {
1020210212 return Air.Inst.Ref.bool_true;
1020310213 } else {
......@@ -10223,16 +10233,12 @@ fn cmpSelf(
1022310233 }
1022410234 };
1022510235 try sema.requireRuntimeBlock(block, runtime_src);
10226
10227 const tag: Air.Inst.Tag = switch (op) {
10228 .lt => .cmp_lt,
10229 .lte => .cmp_lte,
10230 .eq => .cmp_eq,
10231 .gte => .cmp_gte,
10232 .gt => .cmp_gt,
10233 .neq => .cmp_neq,
10234 };
10235 // TODO handle vectors
10236 if (resolved_type.zigTypeTag() == .Vector) {
10237 const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
10238 const result_ty_ref = try sema.addType(result_ty);
10239 return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
10240 }
10241 const tag = Air.Inst.Tag.fromCmpOp(op);
1023610242 return block.addBinOp(tag, casted_lhs, casted_rhs);
1023710243}
1023810244
......@@ -11353,7 +11359,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
1135311359 const elem_ty = operand.elemType2();
1135411360 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
1135511361 return Type.Tag.vector.create(sema.arena, .{
11356 .len = operand.arrayLen(),
11362 .len = operand.vectorLen(),
1135711363 .elem_type = log2_elem_ty,
1135811364 });
1135911365 },
......@@ -13284,7 +13290,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1328413290
1328513291 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
1328613292 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) {
1328813294 error.FloatCannotFit => {
1328913295 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
1329013296 },
......@@ -13311,7 +13317,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1331113317
1331213318 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
1331313319 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);
1331513321 return sema.addConstant(dest_ty, result_val);
1331613322 }
1331713323
......@@ -13521,14 +13527,14 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1352113527 if (!is_vector) {
1352213528 return sema.addConstant(
1352313529 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),
1352513531 );
1352613532 }
1352713533 var elem_buf: Value.ElemValueBuffer = undefined;
1352813534 const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());
1352913535 for (elems) |*elem, i| {
1353013536 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);
1353213538 }
1353313539 return sema.addConstant(
1353413540 dest_ty,
......@@ -14083,13 +14089,40 @@ fn checkSimdBinOp(
1408314089) CompileError!SimdBinOp {
1408414090 const lhs_ty = sema.typeOf(uncasted_lhs);
1408514091 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 {
1408614121 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
1408714122 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
14088
14089 var vec_len: ?usize = null;
1409014123 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
14091 const lhs_len = lhs_ty.arrayLen();
14092 const rhs_len = rhs_ty.arrayLen();
14124 const lhs_len = lhs_ty.vectorLen();
14125 const rhs_len = rhs_ty.vectorLen();
1409314126 if (lhs_len != rhs_len) {
1409414127 const msg = msg: {
1409514128 const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
......@@ -14100,7 +14133,6 @@ fn checkSimdBinOp(
1410014133 };
1410114134 return sema.failWithOwnedErrorMsg(block, msg);
1410214135 }
14103 vec_len = try sema.usizeCast(block, lhs_src, lhs_len);
1410414136 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
1410514137 const msg = msg: {
1410614138 const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{
......@@ -14118,21 +14150,6 @@ fn checkSimdBinOp(
1411814150 };
1411914151 return sema.failWithOwnedErrorMsg(block, msg);
1412014152 }
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 };
1413614153}
1413714154
1413814155fn resolveExportOptions(
......@@ -14362,9 +14379,9 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1436214379 while (i < vec_len) : (i += 1) {
1436314380 const elem_val = operand_val.elemValueBuffer(i, &elem_buf);
1436414381 switch (operation) {
14365 .And => accum = try accum.bitwiseAnd(elem_val, sema.arena),
14366 .Or => accum = try accum.bitwiseOr(elem_val, sema.arena),
14367 .Xor => accum = try accum.bitwiseXor(elem_val, sema.arena),
14382 .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena),
14383 .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena),
14384 .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena),
1436814385 .Min => accum = accum.numberMin(elem_val),
1436914386 .Max => accum = accum.numberMax(elem_val),
1437014387 .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
1468314700 .Xchg => operand_val,
1468414701 .Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),
1468514702 .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),
1468714704 .Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),
14688 .Or => try stored_val.bitwiseOr (operand_val, sema.arena),
14689 .Xor => try stored_val.bitwiseXor (operand_val, sema.arena),
14705 .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena),
14706 .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena),
1469014707 .Max => stored_val.numberMax (operand_val),
1469114708 .Min => stored_val.numberMin (operand_val),
1469214709 // zig fmt: on
......@@ -17509,7 +17526,7 @@ fn coerce(
1750917526 if (val.floatHasFraction()) {
1751017527 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty });
1751117528 }
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) {
1751317530 error.FloatCannotFit => {
1751417531 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
1751517532 },
......@@ -17572,7 +17589,7 @@ fn coerce(
1757217589 },
1757317590 .Int, .ComptimeInt => int: {
1757417591 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);
1757617593 // TODO implement this compile error
1757717594 //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
1757817595 //if (!int_again_val.eql(val, inst_ty)) {
......@@ -17809,8 +17826,21 @@ fn coerceInMemoryAllowed(
1780917826 return .ok;
1781017827 }
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
1781217843 // TODO: non-pointer-like optionals
17813 // TODO: vectors
1781417844
1781517845 return .no_match;
1781617846}
......@@ -19683,19 +19713,6 @@ fn cmpNumeric(
1968319713 const lhs_ty_tag = lhs_ty.zigTypeTag();
1968419714 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
1969919716 const runtime_src: LazySrcLoc = src: {
1970019717 if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
1970119718 if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
......@@ -19881,6 +19898,46 @@ fn cmpNumeric(
1988119898 return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
1988219899}
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
1988419941fn wrapOptional(
1988519942 sema: *Sema,
1988619943 block: *Block,
......@@ -21187,7 +21244,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
2118721244 map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty });
2118821245 } else {
2118921246 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)
2119121248 else
2119221249 Value.zero;
2119321250 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 {
577577 .cmp_gte => try self.airCmp(inst, .gte),
578578 .cmp_gt => try self.airCmp(inst, .gt),
579579 .cmp_neq => try self.airCmp(inst, .neq),
580 .cmp_vector => try self.airCmpVector(inst),
580581
581582 .bool_and => try self.airBinOp(inst),
582583 .bool_or => try self.airBinOp(inst),
......@@ -2713,6 +2714,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
27132714 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
27142715}
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
27162722fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
27172723 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 {
567567 .cmp_gte => try self.airCmp(inst, .gte),
568568 .cmp_gt => try self.airCmp(inst, .gt),
569569 .cmp_neq => try self.airCmp(inst, .neq),
570 .cmp_vector => try self.airCmpVector(inst),
570571
571572 .bool_and => try self.airBinOp(inst),
572573 .bool_or => try self.airBinOp(inst),
......@@ -2894,7 +2895,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
28942895 const lhs_ty = self.air.typeOf(bin_op.lhs);
28952896
28962897 switch (lhs_ty.zigTypeTag()) {
2897 .Vector => return self.fail("TODO ARM cmp vectors", .{}),
28982898 .Optional => return self.fail("TODO ARM cmp optionals", .{}),
28992899 .Float => return self.fail("TODO ARM cmp floats", .{}),
29002900 .Int, .Bool, .Pointer, .ErrorSet, .Enum => {
......@@ -2929,6 +2929,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
29292929 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
29302930}
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
29322937fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
29332938 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 {
537537 .cmp_gte => try self.airCmp(inst, .gte),
538538 .cmp_gt => try self.airCmp(inst, .gt),
539539 .cmp_neq => try self.airCmp(inst, .neq),
540 .cmp_vector => try self.airCmpVector(inst),
540541
541542 .bool_and => try self.airBoolOp(inst),
542543 .bool_or => try self.airBoolOp(inst),
......@@ -1791,6 +1792,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
17911792 // return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
17921793}
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
17941800fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
17951801 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 {
13091309 .cmp_lte => self.airCmp(inst, .lte),
13101310 .cmp_lt => self.airCmp(inst, .lt),
13111311 .cmp_neq => self.airCmp(inst, .neq),
1312 .cmp_vector => self.airCmpVector(inst),
13121313
13131314 .array_elem_val => self.airArrayElemVal(inst),
13141315 .array_to_slice => self.airArrayToSlice(inst),
......@@ -2222,6 +2223,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
22222223 return cmp_tmp;
22232224}
22242225
2226fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2227 _ = inst;
2228 return self.fail("TODO implement airCmpVector for wasm", .{});
2229}
2230
22252231fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22262232 const br = self.air.instructions.items(.data)[inst].br;
22272233 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 {
658658 .cmp_gte => try self.airCmp(inst, .gte),
659659 .cmp_gt => try self.airCmp(inst, .gt),
660660 .cmp_neq => try self.airCmp(inst, .neq),
661 .cmp_vector => try self.airCmpVector(inst),
661662
662663 .bool_and => try self.airBoolOp(inst),
663664 .bool_or => try self.airBoolOp(inst),
......@@ -3699,6 +3700,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
36993700 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
37003701}
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
37023708fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
37033709 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
37043710 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
17151715 .cmp_eq => try airEquality(f, inst, "((", "=="),
17161716 .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
17181720 // bool_and and bool_or are non-short-circuit operations
17191721 .bool_and => try airBinOp(f, inst, " & "),
17201722 .bool_or => try airBinOp(f, inst, " | "),
src/codegen/llvm.zig+101-43
......@@ -3375,6 +3375,7 @@ pub const FuncGen = struct {
33753375 .cmp_lt => try self.airCmp(inst, .lt),
33763376 .cmp_lte => try self.airCmp(inst, .lte),
33773377 .cmp_neq => try self.airCmp(inst, .neq),
3378 .cmp_vector => try self.airCmpVector(inst),
33783379
33793380 .is_non_null => try self.airIsNonNull(inst, false, false, .NE),
33803381 .is_non_null_ptr => try self.airIsNonNull(inst, true , false, .NE),
......@@ -3640,6 +3641,20 @@ pub const FuncGen = struct {
36403641 return self.cmp(lhs, rhs, operand_ty, op);
36413642 }
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
36433658 fn cmp(
36443659 self: *FuncGen,
36453660 lhs: *const llvm.Value,
......@@ -3650,9 +3665,10 @@ pub const FuncGen = struct {
36503665 var int_buffer: Type.Payload.Bits = undefined;
36513666 var opt_buffer: Type.Payload.ElemType = undefined;
36523667
3653 const int_ty = switch (operand_ty.zigTypeTag()) {
3654 .Enum => operand_ty.intTagType(&int_buffer),
3655 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
3668 const scalar_ty = operand_ty.scalarType();
3669 const int_ty = switch (scalar_ty.zigTypeTag()) {
3670 .Enum => scalar_ty.intTagType(&int_buffer),
3671 .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
36563672 .Optional => blk: {
36573673 const payload_ty = operand_ty.optionalChild(&opt_buffer);
36583674 if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {
......@@ -3944,10 +3960,11 @@ pub const FuncGen = struct {
39443960 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
39453961 const operand = try self.resolveInst(ty_op.operand);
39463962 const operand_ty = self.air.typeOf(ty_op.operand);
3963 const operand_scalar_ty = operand_ty.scalarType();
39473964 const dest_ty = self.air.typeOfIndex(inst);
39483965 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
39493966
3950 if (operand_ty.isSignedInt()) {
3967 if (operand_scalar_ty.isSignedInt()) {
39513968 return self.builder.buildSIToFP(operand, dest_llvm_ty, "");
39523969 } else {
39533970 return self.builder.buildUIToFP(operand, dest_llvm_ty, "");
......@@ -3961,11 +3978,12 @@ pub const FuncGen = struct {
39613978 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
39623979 const operand = try self.resolveInst(ty_op.operand);
39633980 const dest_ty = self.air.typeOfIndex(inst);
3981 const dest_scalar_ty = dest_ty.scalarType();
39643982 const dest_llvm_ty = try self.dg.llvmType(dest_ty);
39653983
39663984 // TODO set fast math flag
39673985
3968 if (dest_ty.isSignedInt()) {
3986 if (dest_scalar_ty.isSignedInt()) {
39693987 return self.builder.buildFPToSI(operand, dest_llvm_ty, "");
39703988 } else {
39713989 return self.builder.buildFPToUI(operand, dest_llvm_ty, "");
......@@ -4896,9 +4914,10 @@ pub const FuncGen = struct {
48964914 const lhs = try self.resolveInst(bin_op.lhs);
48974915 const rhs = try self.resolveInst(bin_op.rhs);
48984916 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, "");
4901 if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
4919 if (scalar_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");
4920 if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
49024921 return self.builder.buildNUWAdd(lhs, rhs, "");
49034922 }
49044923
......@@ -4919,9 +4938,10 @@ pub const FuncGen = struct {
49194938 const lhs = try self.resolveInst(bin_op.lhs);
49204939 const rhs = try self.resolveInst(bin_op.rhs);
49214940 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", .{});
4924 if (inst_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
4943 if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
4944 if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
49254945
49264946 return self.builder.buildUAddSat(lhs, rhs, "");
49274947 }
......@@ -4933,9 +4953,10 @@ pub const FuncGen = struct {
49334953 const lhs = try self.resolveInst(bin_op.lhs);
49344954 const rhs = try self.resolveInst(bin_op.rhs);
49354955 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, "");
4938 if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
4958 if (scalar_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");
4959 if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
49394960 return self.builder.buildNUWSub(lhs, rhs, "");
49404961 }
49414962
......@@ -4956,9 +4977,10 @@ pub const FuncGen = struct {
49564977 const lhs = try self.resolveInst(bin_op.lhs);
49574978 const rhs = try self.resolveInst(bin_op.rhs);
49584979 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", .{});
4961 if (inst_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
4982 if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
4983 if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
49624984 return self.builder.buildUSubSat(lhs, rhs, "");
49634985 }
49644986
......@@ -4969,9 +4991,10 @@ pub const FuncGen = struct {
49694991 const lhs = try self.resolveInst(bin_op.lhs);
49704992 const rhs = try self.resolveInst(bin_op.rhs);
49714993 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, "");
4974 if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
4996 if (scalar_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");
4997 if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
49754998 return self.builder.buildNUWMul(lhs, rhs, "");
49764999 }
49775000
......@@ -4992,9 +5015,10 @@ pub const FuncGen = struct {
49925015 const lhs = try self.resolveInst(bin_op.lhs);
49935016 const rhs = try self.resolveInst(bin_op.rhs);
49945017 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", .{});
4997 if (inst_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
5020 if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
5021 if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
49985022 return self.builder.buildUMulFixSat(lhs, rhs, "");
49995023 }
50005024
......@@ -5015,12 +5039,13 @@ pub const FuncGen = struct {
50155039 const lhs = try self.resolveInst(bin_op.lhs);
50165040 const rhs = try self.resolveInst(bin_op.rhs);
50175041 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()) {
50205045 const result = self.builder.buildFDiv(lhs, rhs, "");
50215046 return self.callTrunc(result, inst_ty);
50225047 }
5023 if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
5048 if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
50245049 return self.builder.buildUDiv(lhs, rhs, "");
50255050 }
50265051
......@@ -5031,12 +5056,13 @@ pub const FuncGen = struct {
50315056 const lhs = try self.resolveInst(bin_op.lhs);
50325057 const rhs = try self.resolveInst(bin_op.rhs);
50335058 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()) {
50365062 const result = self.builder.buildFDiv(lhs, rhs, "");
50375063 return try self.callFloor(result, inst_ty);
50385064 }
5039 if (inst_ty.isSignedInt()) {
5065 if (scalar_ty.isSignedInt()) {
50405066 // const d = @divTrunc(a, b);
50415067 // const r = @rem(a, b);
50425068 // return if (r == 0) d else d - ((a < 0) ^ (b < 0));
......@@ -5062,9 +5088,10 @@ pub const FuncGen = struct {
50625088 const lhs = try self.resolveInst(bin_op.lhs);
50635089 const rhs = try self.resolveInst(bin_op.rhs);
50645090 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, "");
5067 if (inst_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
5093 if (scalar_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, "");
5094 if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
50685095 return self.builder.buildExactUDiv(lhs, rhs, "");
50695096 }
50705097
......@@ -5075,9 +5102,10 @@ pub const FuncGen = struct {
50755102 const lhs = try self.resolveInst(bin_op.lhs);
50765103 const rhs = try self.resolveInst(bin_op.rhs);
50775104 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, "");
5080 if (inst_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
5107 if (scalar_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, "");
5108 if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
50815109 return self.builder.buildURem(lhs, rhs, "");
50825110 }
50835111
......@@ -5089,8 +5117,9 @@ pub const FuncGen = struct {
50895117 const rhs = try self.resolveInst(bin_op.rhs);
50905118 const inst_ty = self.air.typeOfIndex(inst);
50915119 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()) {
50945123 const a = self.builder.buildFRem(lhs, rhs, "");
50955124 const b = self.builder.buildFAdd(a, rhs, "");
50965125 const c = self.builder.buildFRem(b, rhs, "");
......@@ -5098,7 +5127,7 @@ pub const FuncGen = struct {
50985127 const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");
50995128 return self.builder.buildSelect(ltz, c, a, "");
51005129 }
5101 if (inst_ty.isSignedInt()) {
5130 if (scalar_ty.isSignedInt()) {
51025131 const a = self.builder.buildSRem(lhs, rhs, "");
51035132 const b = self.builder.buildNSWAdd(a, rhs, "");
51045133 const c = self.builder.buildSRem(b, rhs, "");
......@@ -5323,15 +5352,22 @@ pub const FuncGen = struct {
53235352 if (self.liveness.isUnused(inst)) return null;
53245353
53255354 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5355
53265356 const lhs = try self.resolveInst(bin_op.lhs);
53275357 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
53295364 const tg = self.dg.module.getTarget();
5330 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
5331 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
5365
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), "")
53325368 else
53335369 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, "");
53355371 return self.builder.buildNUWShl(lhs, casted_rhs, "");
53365372 }
53375373
......@@ -5339,11 +5375,18 @@ pub const FuncGen = struct {
53395375 if (self.liveness.isUnused(inst)) return null;
53405376
53415377 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5378
53425379 const lhs = try self.resolveInst(bin_op.lhs);
53435380 const rhs = try self.resolveInst(bin_op.rhs);
5381
53445382 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
53455387 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))
53475390 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
53485391 else
53495392 rhs;
......@@ -5354,31 +5397,45 @@ pub const FuncGen = struct {
53545397 if (self.liveness.isUnused(inst)) return null;
53555398
53565399 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5400
53575401 const lhs = try self.resolveInst(bin_op.lhs);
53585402 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
53605409 const tg = self.dg.module.getTarget();
5361 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
5362 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
5410
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), "")
53635413 else
53645414 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, "");
53665416 return self.builder.buildUShlSat(lhs, casted_rhs, "");
53675417 }
53685418
53695419 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
5370 if (self.liveness.isUnused(inst))
5371 return null;
5420 if (self.liveness.isUnused(inst)) return null;
5421
53725422 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5423
53735424 const lhs = try self.resolveInst(bin_op.lhs);
53745425 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
53765432 const tg = self.dg.module.getTarget();
5377 const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
5378 self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
5433
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), "")
53795436 else
53805437 rhs;
5381 const is_signed_int = self.air.typeOfIndex(inst).isSignedInt();
5438 const is_signed_int = lhs_scalar_ty.isSignedInt();
53825439
53835440 if (is_exact) {
53845441 if (is_signed_int) {
......@@ -5506,7 +5563,8 @@ pub const FuncGen = struct {
55065563 if (bitcast_ok) {
55075564 const llvm_vector_ty = try self.dg.llvmType(operand_ty);
55085565 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));
55105568 } else {
55115569 // If the ABI size of the element type is not evenly divisible by size in bits;
55125570 // 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 {
266266 .mul_add => try w.writeMulAdd(s, inst),
267267 .shuffle => try w.writeShuffle(s, inst),
268268 .reduce => try w.writeReduce(s, inst),
269 .cmp_vector => try w.writeCmpVector(s, inst),
269270
270271 .add_with_overflow,
271272 .sub_with_overflow,
......@@ -402,6 +403,16 @@ const Writer = struct {
402403 try s.print(", {s}", .{@tagName(reduce.operation)});
403404 }
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
405416 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
406417 const atomic_order = w.air.instructions.items(.data)[inst].fence;
407418
......@@ -470,8 +481,8 @@ const Writer = struct {
470481 }
471482
472483 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;
474 const extra = w.air.extraData(Air.FieldParentPtr, pl_op.payload).data;
484 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
485 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
475486
476487 try w.writeOperand(s, inst, 0, extra.field_ptr);
477488 try s.print(", {d}", .{extra.field_index});
src/value.zig+726-43
......@@ -1846,8 +1846,23 @@ pub const Value = extern union {
18461846 return order(lhs, rhs).compare(op);
18471847 }
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.
18501851 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 {
18511866 return switch (op) {
18521867 .eq => lhs.eql(rhs, ty),
18531868 .neq => !lhs.eql(rhs, ty),
......@@ -1855,18 +1870,25 @@ pub const Value = extern union {
18551870 };
18561871 }
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
18581884 /// Asserts the value is comparable.
1859 /// For vectors this is only valid with op == .eq.
1885 /// Vector results will be reduced with AND.
18601886 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
18611887 switch (lhs.tag()) {
1862 .repeated => {
1863 assert(op == .eq);
1864 return lhs.castTag(.repeated).?.data.compareWithZero(.eq);
1865 },
1888 .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op),
18661889 .aggregate => {
1867 assert(op == .eq);
18681890 for (lhs.castTag(.aggregate).?.data) |elem_val| {
1869 if (!elem_val.compareWithZero(.eq)) return false;
1891 if (!elem_val.compareWithZero(op)) return false;
18701892 }
18711893 return true;
18721894 },
......@@ -2404,6 +2426,27 @@ pub const Value = extern union {
24042426 };
24052427 }
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
24072450 /// Asserts the value is a single-item pointer to an array, or an array,
24082451 /// or an unknown-length pointer, and returns the element value at the index.
24092452 pub fn elemValue(val: Value, arena: Allocator, index: usize) !Value {
......@@ -2646,25 +2689,36 @@ pub const Value = extern union {
26462689 };
26472690 }
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 {
26502704 switch (val.tag()) {
26512705 .undef, .zero, .one => return val,
26522706 .the_only_possible_value => return Value.initTag(.zero), // for i0, u0
26532707 .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);
26552709 },
26562710 .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);
26582712 },
26592713 .int_big_positive => {
26602714 const limbs = val.castTag(.int_big_positive).?.data;
26612715 const float = bigIntToFloat(limbs, true);
2662 return floatToValue(float, arena, dest_ty, target);
2716 return floatToValue(float, arena, float_ty, target);
26632717 },
26642718 .int_big_negative => {
26652719 const limbs = val.castTag(.int_big_negative).?.data;
26662720 const float = bigIntToFloat(limbs, false);
2667 return floatToValue(float, arena, dest_ty, target);
2721 return floatToValue(float, arena, float_ty, target);
26682722 },
26692723 else => unreachable,
26702724 }
......@@ -2694,7 +2748,18 @@ pub const Value = extern union {
26942748 }
26952749 }
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 {
26982763 const Limb = std.math.big.Limb;
26992764
27002765 var value = val.toFloat(f64); // TODO: f128 ?
......@@ -2724,7 +2789,7 @@ pub const Value = extern union {
27242789 else
27252790 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)) {
27282793 return result;
27292794 } else {
27302795 return error.FloatCannotFit;
......@@ -2771,18 +2836,36 @@ pub const Value = extern union {
27712836 };
27722837 }
27732838
2774 /// Supports both floats and ints; handles undefined.
2839 /// Supports both (vectors of) floats and ints; handles undefined scalars.
27752840 pub fn numberAddWrap(
27762841 lhs: Value,
27772842 rhs: Value,
27782843 ty: Type,
27792844 arena: Allocator,
27802845 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,
27812864 ) !Value {
27822865 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
27832866
27842867 if (ty.zigTypeTag() == .ComptimeInt) {
2785 return intAdd(lhs, rhs, arena);
2868 return intAdd(lhs, rhs, ty, arena);
27862869 }
27872870
27882871 if (ty.isAnyFloat()) {
......@@ -2809,13 +2892,31 @@ pub const Value = extern union {
28092892 }
28102893 }
28112894
2812 /// Supports integers only; asserts neither operand is undefined.
2895 /// Supports (vectors of) integers only; asserts neither operand is undefined.
28132896 pub fn intAddSat(
28142897 lhs: Value,
28152898 rhs: Value,
28162899 ty: Type,
28172900 arena: Allocator,
28182901 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,
28192920 ) !Value {
28202921 assert(!lhs.isUndef());
28212922 assert(!rhs.isUndef());
......@@ -2861,18 +2962,36 @@ pub const Value = extern union {
28612962 };
28622963 }
28632964
2864 /// Supports both floats and ints; handles undefined.
2965 /// Supports both (vectors of) floats and ints; handles undefined scalars.
28652966 pub fn numberSubWrap(
28662967 lhs: Value,
28672968 rhs: Value,
28682969 ty: Type,
28692970 arena: Allocator,
28702971 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,
28712990 ) !Value {
28722991 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
28732992
28742993 if (ty.zigTypeTag() == .ComptimeInt) {
2875 return intSub(lhs, rhs, arena);
2994 return intSub(lhs, rhs, ty, arena);
28762995 }
28772996
28782997 if (ty.isAnyFloat()) {
......@@ -2883,13 +3002,31 @@ pub const Value = extern union {
28833002 return overflow_result.wrapped_result;
28843003 }
28853004
2886 /// Supports integers only; asserts neither operand is undefined.
3005 /// Supports (vectors of) integers only; asserts neither operand is undefined.
28873006 pub fn intSubSat(
28883007 lhs: Value,
28893008 rhs: Value,
28903009 ty: Type,
28913010 arena: Allocator,
28923011 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,
28933030 ) !Value {
28943031 assert(!lhs.isUndef());
28953032 assert(!rhs.isUndef());
......@@ -2944,18 +3081,36 @@ pub const Value = extern union {
29443081 };
29453082 }
29463083
2947 /// Supports both floats and ints; handles undefined.
3084 /// Supports both (vectors of) floats and ints; handles undefined scalars.
29483085 pub fn numberMulWrap(
29493086 lhs: Value,
29503087 rhs: Value,
29513088 ty: Type,
29523089 arena: Allocator,
29533090 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,
29543109 ) !Value {
29553110 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
29563111
29573112 if (ty.zigTypeTag() == .ComptimeInt) {
2958 return intMul(lhs, rhs, arena);
3113 return intMul(lhs, rhs, ty, arena);
29593114 }
29603115
29613116 if (ty.isAnyFloat()) {
......@@ -2966,13 +3121,31 @@ pub const Value = extern union {
29663121 return overflow_result.wrapped_result;
29673122 }
29683123
2969 /// Supports integers only; asserts neither operand is undefined.
3124 /// Supports (vectors of) integers only; asserts neither operand is undefined.
29703125 pub fn intMulSat(
29713126 lhs: Value,
29723127 rhs: Value,
29733128 ty: Type,
29743129 arena: Allocator,
29753130 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,
29763149 ) !Value {
29773150 assert(!lhs.isUndef());
29783151 assert(!rhs.isUndef());
......@@ -3025,8 +3198,20 @@ pub const Value = extern union {
30253198 };
30263199 }
30273200
3028 /// operands must be integers; handles undefined.
3201 /// operands must be (vectors of) integers; handles undefined scalars.
30293202 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 {
30303215 if (val.isUndef()) return Value.initTag(.undef);
30313216
30323217 const info = ty.intInfo(target);
......@@ -3050,8 +3235,20 @@ pub const Value = extern union {
30503235 return fromBigInt(arena, result_bigint.toConst());
30513236 }
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
30533250 /// 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 {
30553252 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
30563253
30573254 // TODO is this a performance issue? maybe we should try the operation without
......@@ -3070,22 +3267,46 @@ pub const Value = extern union {
30703267 return fromBigInt(arena, result_bigint.toConst());
30713268 }
30723269
3073 /// operands must be integers; handles undefined.
3270 /// operands must be (vectors of) integers; handles undefined scalars.
30743271 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 {
30753284 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
30793288 const all_ones = if (ty.isSignedInt())
30803289 try Value.Tag.int_i64.create(arena, -1)
30813290 else
30823291 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);
30853306 }
30863307
30873308 /// 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 {
30893310 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
30903311
30913312 // TODO is this a performance issue? maybe we should try the operation without
......@@ -3103,8 +3324,20 @@ pub const Value = extern union {
31033324 return fromBigInt(arena, result_bigint.toConst());
31043325 }
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
31063339 /// 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 {
31083341 if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
31093342
31103343 // TODO is this a performance issue? maybe we should try the operation without
......@@ -3123,7 +3356,18 @@ pub const Value = extern union {
31233356 return fromBigInt(arena, result_bigint.toConst());
31243357 }
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 {
31273371 // TODO is this a performance issue? maybe we should try the operation without
31283372 // resorting to BigInt first.
31293373 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3139,7 +3383,18 @@ pub const Value = extern union {
31393383 return fromBigInt(allocator, result_bigint.toConst());
31403384 }
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 {
31433398 // TODO is this a performance issue? maybe we should try the operation without
31443399 // resorting to BigInt first.
31453400 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3155,7 +3410,18 @@ pub const Value = extern union {
31553410 return fromBigInt(allocator, result_bigint.toConst());
31563411 }
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 {
31593425 // TODO is this a performance issue? maybe we should try the operation without
31603426 // resorting to BigInt first.
31613427 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3180,7 +3446,18 @@ pub const Value = extern union {
31803446 return fromBigInt(allocator, result_q.toConst());
31813447 }
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 {
31843461 // TODO is this a performance issue? maybe we should try the operation without
31853462 // resorting to BigInt first.
31863463 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3205,7 +3482,18 @@ pub const Value = extern union {
32053482 return fromBigInt(allocator, result_q.toConst());
32063483 }
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 {
32093497 // TODO is this a performance issue? maybe we should try the operation without
32103498 // resorting to BigInt first.
32113499 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3232,7 +3520,18 @@ pub const Value = extern union {
32323520 return fromBigInt(allocator, result_r.toConst());
32333521 }
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 {
32363535 // TODO is this a performance issue? maybe we should try the operation without
32373536 // resorting to BigInt first.
32383537 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3270,6 +3569,17 @@ pub const Value = extern union {
32703569 }
32713570
32723571 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 {
32733583 switch (float_type.floatBits(target)) {
32743584 16 => {
32753585 const lhs_val = lhs.toFloat(f16);
......@@ -3304,6 +3614,17 @@ pub const Value = extern union {
33043614 }
33053615
33063616 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 {
33073628 switch (float_type.floatBits(target)) {
33083629 16 => {
33093630 const lhs_val = lhs.toFloat(f16);
......@@ -3337,7 +3658,18 @@ pub const Value = extern union {
33373658 }
33383659 }
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 {
33413673 // TODO is this a performance issue? maybe we should try the operation without
33423674 // resorting to BigInt first.
33433675 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3358,7 +3690,32 @@ pub const Value = extern union {
33583690 return fromBigInt(allocator, result_bigint.toConst());
33593691 }
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
33623719 var val_space: Value.BigIntSpace = undefined;
33633720 const val_bigint = val.toBigInt(&val_space);
33643721
......@@ -3372,7 +3729,18 @@ pub const Value = extern union {
33723729 return fromBigInt(allocator, result_bigint.toConst());
33733730 }
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 {
33763744 // TODO is this a performance issue? maybe we should try the operation without
33773745 // resorting to BigInt first.
33783746 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3428,6 +3796,23 @@ pub const Value = extern union {
34283796 ty: Type,
34293797 arena: Allocator,
34303798 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,
34313816 ) !Value {
34323817 // TODO is this a performance issue? maybe we should try the operation without
34333818 // resorting to BigInt first.
......@@ -3456,13 +3841,41 @@ pub const Value = extern union {
34563841 arena: Allocator,
34573842 target: Target,
34583843 ) !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);
34603862 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);
34623864 return truncated;
34633865 }
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 {
34663879 // TODO is this a performance issue? maybe we should try the operation without
34673880 // resorting to BigInt first.
34683881 var lhs_space: Value.BigIntSpace = undefined;
......@@ -3495,6 +3908,23 @@ pub const Value = extern union {
34953908 float_type: Type,
34963909 arena: Allocator,
34973910 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,
34983928 ) !Value {
34993929 switch (float_type.floatBits(target)) {
35003930 16 => {
......@@ -3532,6 +3962,23 @@ pub const Value = extern union {
35323962 float_type: Type,
35333963 arena: Allocator,
35343964 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,
35353982 ) !Value {
35363983 switch (float_type.floatBits(target)) {
35373984 16 => {
......@@ -3569,6 +4016,23 @@ pub const Value = extern union {
35694016 float_type: Type,
35704017 arena: Allocator,
35714018 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,
35724036 ) !Value {
35734037 switch (float_type.floatBits(target)) {
35744038 16 => {
......@@ -3609,6 +4073,23 @@ pub const Value = extern union {
36094073 float_type: Type,
36104074 arena: Allocator,
36114075 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,
36124093 ) !Value {
36134094 switch (float_type.floatBits(target)) {
36144095 16 => {
......@@ -3649,6 +4130,23 @@ pub const Value = extern union {
36494130 float_type: Type,
36504131 arena: Allocator,
36514132 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,
36524150 ) !Value {
36534151 switch (float_type.floatBits(target)) {
36544152 16 => {
......@@ -3689,6 +4187,23 @@ pub const Value = extern union {
36894187 float_type: Type,
36904188 arena: Allocator,
36914189 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,
36924207 ) !Value {
36934208 switch (float_type.floatBits(target)) {
36944209 16 => {
......@@ -3724,6 +4239,17 @@ pub const Value = extern union {
37244239 }
37254240
37264241 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 {
37274253 switch (float_type.floatBits(target)) {
37284254 16 => {
37294255 const f = val.toFloat(f16);
......@@ -3756,6 +4282,17 @@ pub const Value = extern union {
37564282 }
37574283
37584284 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 {
37594296 switch (float_type.floatBits(target)) {
37604297 16 => {
37614298 const f = val.toFloat(f16);
......@@ -3788,6 +4325,17 @@ pub const Value = extern union {
37884325 }
37894326
37904327 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 {
37914339 switch (float_type.floatBits(target)) {
37924340 16 => {
37934341 const f = val.toFloat(f16);
......@@ -3820,6 +4368,17 @@ pub const Value = extern union {
38204368 }
38214369
38224370 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 {
38234382 switch (float_type.floatBits(target)) {
38244383 16 => {
38254384 const f = val.toFloat(f16);
......@@ -3852,6 +4411,17 @@ pub const Value = extern union {
38524411 }
38534412
38544413 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 {
38554425 switch (float_type.floatBits(target)) {
38564426 16 => {
38574427 const f = val.toFloat(f16);
......@@ -3884,6 +4454,17 @@ pub const Value = extern union {
38844454 }
38854455
38864456 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 {
38874468 switch (float_type.floatBits(target)) {
38884469 16 => {
38894470 const f = val.toFloat(f16);
......@@ -3916,6 +4497,17 @@ pub const Value = extern union {
39164497 }
39174498
39184499 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 {
39194511 switch (float_type.floatBits(target)) {
39204512 16 => {
39214513 const f = val.toFloat(f16);
......@@ -3948,6 +4540,17 @@ pub const Value = extern union {
39484540 }
39494541
39504542 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 {
39514554 switch (float_type.floatBits(target)) {
39524555 16 => {
39534556 const f = val.toFloat(f16);
......@@ -3980,6 +4583,17 @@ pub const Value = extern union {
39804583 }
39814584
39824585 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 {
39834597 switch (float_type.floatBits(target)) {
39844598 16 => {
39854599 const f = val.toFloat(f16);
......@@ -4009,6 +4623,17 @@ pub const Value = extern union {
40094623 }
40104624
40114625 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 {
40124637 switch (float_type.floatBits(target)) {
40134638 16 => {
40144639 const f = val.toFloat(f16);
......@@ -4038,6 +4663,17 @@ pub const Value = extern union {
40384663 }
40394664
40404665 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 {
40414677 switch (float_type.floatBits(target)) {
40424678 16 => {
40434679 const f = val.toFloat(f16);
......@@ -4067,6 +4703,17 @@ pub const Value = extern union {
40674703 }
40684704
40694705 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 {
40704717 switch (float_type.floatBits(target)) {
40714718 16 => {
40724719 const f = val.toFloat(f16);
......@@ -4096,6 +4743,17 @@ pub const Value = extern union {
40964743 }
40974744
40984745 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 {
40994757 switch (float_type.floatBits(target)) {
41004758 16 => {
41014759 const f = val.toFloat(f16);
......@@ -4131,6 +4789,31 @@ pub const Value = extern union {
41314789 addend: Value,
41324790 arena: Allocator,
41334791 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,
41344817 ) Allocator.Error!Value {
41354818 switch (float_type.floatBits(target)) {
41364819 16 => {
test/behavior/vector.zig+250-100
......@@ -3,15 +3,17 @@ const builtin = @import("builtin");
33const mem = std.mem;
44const math = std.math;
55const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;
7const expectApproxEqRel = std.testing.expectApproxEqRel;
8const Vector = std.meta.Vector;
96
107test "implicit cast vector to array - bool" {
11 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
8 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
1214 const S = struct {
1315 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 };
1517 const result_array: [4]bool = a;
1618 try expect(mem.eql(bool, &result_array, &[4]bool{ true, false, true, false }));
1719 }
......@@ -21,15 +23,20 @@ test "implicit cast vector to array - bool" {
2123}
2224
2325test "vector wrap operators" {
24 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
26 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
2532 const S = struct {
2633 fn doTheTest() !void {
27 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
28 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
34 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
35 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
2936 try expect(mem.eql(i32, &@as([4]i32, v +% x), &[4]i32{ -2147483648, 2147483645, 33, 44 }));
3037 try expect(mem.eql(i32, &@as([4]i32, v -% x), &[4]i32{ 2147483646, 2147483647, 27, 36 }));
3138 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 };
3340 try expect(mem.eql(i32, &@as([4]i32, -%z), &[4]i32{ -1, -2, -3, -2147483648 }));
3441 }
3542 };
......@@ -38,11 +45,16 @@ test "vector wrap operators" {
3845}
3946
4047test "vector bin compares with mem.eql" {
41 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
48 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
4254 const S = struct {
4355 fn doTheTest() !void {
44 var v: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
45 var x: Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };
56 var v: @Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
57 var x: @Vector(4, i32) = [4]i32{ 1, 2147483647, 30, 4 };
4658 try expect(mem.eql(bool, &@as([4]bool, v == x), &[4]bool{ false, false, true, false }));
4759 try expect(mem.eql(bool, &@as([4]bool, v != x), &[4]bool{ true, true, false, true }));
4860 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" {
5668}
5769
5870test "vector int operators" {
59 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
71 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
6077 const S = struct {
6178 fn doTheTest() !void {
62 var v: Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
63 var x: Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
79 var v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
80 var x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
6481 try expect(mem.eql(i32, &@as([4]i32, v + x), &[4]i32{ 11, 22, 33, 44 }));
6582 try expect(mem.eql(i32, &@as([4]i32, v - x), &[4]i32{ 9, 18, 27, 36 }));
6683 try expect(mem.eql(i32, &@as([4]i32, v * x), &[4]i32{ 10, 40, 90, 160 }));
......@@ -72,11 +89,16 @@ test "vector int operators" {
7289}
7390
7491test "vector float operators" {
75 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
92 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
7698 const S = struct {
7799 fn doTheTest() !void {
78 var v: Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
79 var x: Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
100 var v: @Vector(4, f32) = [4]f32{ 10, 20, 30, 40 };
101 var x: @Vector(4, f32) = [4]f32{ 1, 2, 3, 4 };
80102 try expect(mem.eql(f32, &@as([4]f32, v + x), &[4]f32{ 11, 22, 33, 44 }));
81103 try expect(mem.eql(f32, &@as([4]f32, v - x), &[4]f32{ 9, 18, 27, 36 }));
82104 try expect(mem.eql(f32, &@as([4]f32, v * x), &[4]f32{ 10, 40, 90, 160 }));
......@@ -88,11 +110,16 @@ test "vector float operators" {
88110}
89111
90112test "vector bit operators" {
91 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
113 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
92119 const S = struct {
93120 fn doTheTest() !void {
94 var v: Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
95 var x: Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
121 var v: @Vector(4, u8) = [4]u8{ 0b10101010, 0b10101010, 0b10101010, 0b10101010 };
122 var x: @Vector(4, u8) = [4]u8{ 0b11110000, 0b00001111, 0b10101010, 0b01010101 };
96123 try expect(mem.eql(u8, &@as([4]u8, v ^ x), &[4]u8{ 0b01011010, 0b10100101, 0b00000000, 0b11111111 }));
97124 try expect(mem.eql(u8, &@as([4]u8, v | x), &[4]u8{ 0b11111010, 0b10101111, 0b10101010, 0b11111111 }));
98125 try expect(mem.eql(u8, &@as([4]u8, v & x), &[4]u8{ 0b10100000, 0b00001010, 0b10101010, 0b00000000 }));
......@@ -103,10 +130,15 @@ test "vector bit operators" {
103130}
104131
105132test "implicit cast vector to array" {
106 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
133 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
107139 const S = struct {
108140 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 };
110142 var result_array: [4]i32 = a;
111143 result_array = a;
112144 try expect(mem.eql(i32, &result_array, &[4]i32{ 1, 2, 3, 4 }));
......@@ -117,34 +149,50 @@ test "implicit cast vector to array" {
117149}
118150
119151test "array to vector" {
120 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
121 var foo: f32 = 3.14;
122 var arr = [4]f32{ foo, 1.5, 0.0, 0.0 };
123 var vec: Vector(4, f32) = arr;
124 _ = vec;
152 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
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();
125168}
126169
127170test "vector casts of sizes not divisible by 8" {
128 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
171 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
129177 const S = struct {
130178 fn doTheTest() !void {
131179 {
132 var v: Vector(4, u3) = [4]u3{ 5, 2, 3, 0 };
180 var v: @Vector(4, u3) = [4]u3{ 5, 2, 3, 0 };
133181 var x: [4]u3 = v;
134182 try expect(mem.eql(u3, &x, &@as([4]u3, v)));
135183 }
136184 {
137 var v: Vector(4, u2) = [4]u2{ 1, 2, 3, 0 };
185 var v: @Vector(4, u2) = [4]u2{ 1, 2, 3, 0 };
138186 var x: [4]u2 = v;
139187 try expect(mem.eql(u2, &x, &@as([4]u2, v)));
140188 }
141189 {
142 var v: Vector(4, u1) = [4]u1{ 1, 0, 1, 0 };
190 var v: @Vector(4, u1) = [4]u1{ 1, 0, 1, 0 };
143191 var x: [4]u1 = v;
144192 try expect(mem.eql(u1, &x, &@as([4]u1, v)));
145193 }
146194 {
147 var v: Vector(4, bool) = [4]bool{ false, false, true, false };
195 var v: @Vector(4, bool) = [4]bool{ false, false, true, false };
148196 var x: [4]bool = v;
149197 try expect(mem.eql(bool, &x, &@as([4]bool, v)));
150198 }
......@@ -155,14 +203,19 @@ test "vector casts of sizes not divisible by 8" {
155203}
156204
157205test "vector @splat" {
158 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
206 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
159212 const S = struct {
160213 fn testForT(comptime N: comptime_int, v: anytype) !void {
161214 const T = @TypeOf(v);
162215 var vec = @splat(N, v);
163 try expectEqual(Vector(N, T), @TypeOf(vec));
216 try expect(@Vector(N, T) == @TypeOf(vec));
164217 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);
166219 }
167220 fn doTheTest() !void {
168221 // Splats with multiple-of-8 bit types that fill a 128bit vector.
......@@ -191,10 +244,15 @@ test "vector @splat" {
191244}
192245
193246test "load vector elements via comptime index" {
194 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
247 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
195253 const S = struct {
196254 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 };
198256 try expect(v[0] == 1);
199257 try expect(v[1] == 2);
200258 try expect(loadv(&v[2]) == 3);
......@@ -209,10 +267,15 @@ test "load vector elements via comptime index" {
209267}
210268
211269test "store vector elements via comptime index" {
212 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
270 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
213276 const S = struct {
214277 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
217280 v[2] = 42;
218281 try expect(v[1] == 5);
......@@ -233,10 +296,15 @@ test "store vector elements via comptime index" {
233296}
234297
235298test "load vector elements via runtime index" {
236 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
299 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
237305 const S = struct {
238306 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 };
240308 var i: u32 = 0;
241309 try expect(v[i] == 1);
242310 i += 1;
......@@ -251,10 +319,15 @@ test "load vector elements via runtime index" {
251319}
252320
253321test "store vector elements via runtime index" {
254 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
322 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
255328 const S = struct {
256329 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 };
258331 var i: u32 = 2;
259332 v[i] = 1;
260333 try expect(v[1] == 5);
......@@ -270,9 +343,14 @@ test "store vector elements via runtime index" {
270343}
271344
272345test "initialize vector which is a struct field" {
273 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
346 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
274352 const Vec4Obj = struct {
275 data: Vector(4, f32),
353 data: @Vector(4, f32),
276354 };
277355
278356 const S = struct {
......@@ -288,33 +366,38 @@ test "initialize vector which is a struct field" {
288366}
289367
290368test "vector comparison operators" {
291 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
369 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
292375 const S = struct {
293376 fn doTheTest() !void {
294377 {
295 const v1: Vector(4, bool) = [_]bool{ true, false, true, false };
296 const v2: Vector(4, bool) = [_]bool{ false, true, false, true };
297 try expectEqual(@splat(4, true), v1 == v1);
298 try expectEqual(@splat(4, false), v1 == v2);
299 try expectEqual(@splat(4, true), v1 != v2);
300 try expectEqual(@splat(4, false), v2 != v2);
378 var v1: @Vector(4, bool) = [_]bool{ true, false, true, false };
379 var v2: @Vector(4, bool) = [_]bool{ false, true, false, true };
380 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 == v1)));
381 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 == v2)));
382 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 != v2)));
383 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v2 != v2)));
301384 }
302385 {
303 const v1 = @splat(4, @as(u32, 0xc0ffeeee));
304 const v2: Vector(4, c_uint) = v1;
305 const v3 = @splat(4, @as(u32, 0xdeadbeef));
306 try expectEqual(@splat(4, true), v1 == v2);
307 try expectEqual(@splat(4, false), v1 == v3);
308 try expectEqual(@splat(4, true), v1 != v3);
309 try expectEqual(@splat(4, false), v1 != v2);
386 var v1 = @splat(4, @as(u32, 0xc0ffeeee));
387 var v2: @Vector(4, c_uint) = v1;
388 var v3 = @splat(4, @as(u32, 0xdeadbeef));
389 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 == v2)));
390 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 == v3)));
391 try expect(mem.eql(bool, &@as([4]bool, @splat(4, true)), &@as([4]bool, v1 != v3)));
392 try expect(mem.eql(bool, &@as([4]bool, @splat(4, false)), &@as([4]bool, v1 != v2)));
310393 }
311394 {
312395 // Comptime-known LHS/RHS
313396 var v1: @Vector(4, u32) = [_]u32{ 2, 1, 2, 1 };
314397 const v2 = @splat(4, @as(u32, 2));
315398 const v3: @Vector(4, bool) = [_]bool{ true, false, true, false };
316 try expectEqual(v3, v1 == v2);
317 try expectEqual(v3, v2 == v1);
399 try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v1 == v2)));
400 try expect(mem.eql(bool, &@as([4]bool, v3), &@as([4]bool, v2 == v1)));
318401 }
319402 }
320403 };
......@@ -323,43 +406,48 @@ test "vector comparison operators" {
323406}
324407
325408test "vector division operators" {
326 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
409 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
327415 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 {
329417 if (!comptime std.meta.trait.isSignedInt(T)) {
330418 const d0 = x / y;
331419 for (@as([4]T, d0)) |v, i| {
332 try expectEqual(x[i] / y[i], v);
420 try expect(x[i] / y[i] == v);
333421 }
334422 }
335423 const d1 = @divExact(x, y);
336424 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);
338426 }
339427 const d2 = @divFloor(x, y);
340428 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);
342430 }
343431 const d3 = @divTrunc(x, y);
344432 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);
346434 }
347435 }
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 {
350438 if ((!comptime std.meta.trait.isSignedInt(T)) and @typeInfo(T) != .Float) {
351439 const r0 = x % y;
352440 for (@as([4]T, r0)) |v, i| {
353 try expectEqual(x[i] % y[i], v);
441 try expect(x[i] % y[i] == v);
354442 }
355443 }
356444 const r1 = @mod(x, y);
357445 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);
359447 }
360448 const r2 = @rem(x, y);
361449 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);
363451 }
364452 }
365453
......@@ -406,12 +494,17 @@ test "vector division operators" {
406494}
407495
408496test "vector bitwise not operator" {
409 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
497 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
410503 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 {
412505 var y = ~x;
413506 for (@as([4]T, y)) |v, i| {
414 try expectEqual(~x[i], v);
507 try expect(~x[i] == v);
415508 }
416509 }
417510 fn doTheTest() !void {
......@@ -432,23 +525,28 @@ test "vector bitwise not operator" {
432525}
433526
434527test "vector shift operators" {
435 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
528 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
436534 const S = struct {
437535 fn doTheTestShift(x: anytype, y: anytype) !void {
438536 const N = @typeInfo(@TypeOf(x)).Array.len;
439537 const TX = @typeInfo(@TypeOf(x)).Array.child;
440538 const TY = @typeInfo(@TypeOf(y)).Array.child;
441539
442 var xv = @as(Vector(N, TX), x);
443 var yv = @as(Vector(N, TY), y);
540 var xv = @as(@Vector(N, TX), x);
541 var yv = @as(@Vector(N, TY), y);
444542
445543 var z0 = xv >> yv;
446544 for (@as([N]TX, z0)) |v, i| {
447 try expectEqual(x[i] >> y[i], v);
545 try expect(x[i] >> y[i] == v);
448546 }
449547 var z1 = xv << yv;
450548 for (@as([N]TX, z1)) |v, i| {
451 try expectEqual(x[i] << y[i], v);
549 try expect(x[i] << y[i] == v);
452550 }
453551 }
454552 fn doTheTestShiftExact(x: anytype, y: anytype, dir: enum { Left, Right }) !void {
......@@ -456,13 +554,13 @@ test "vector shift operators" {
456554 const TX = @typeInfo(@TypeOf(x)).Array.child;
457555 const TY = @typeInfo(@TypeOf(y)).Array.child;
458556
459 var xv = @as(Vector(N, TX), x);
460 var yv = @as(Vector(N, TY), y);
557 var xv = @as(@Vector(N, TX), x);
558 var yv = @as(@Vector(N, TY), y);
461559
462560 var z = if (dir == .Left) @shlExact(xv, yv) else @shrExact(xv, yv);
463561 for (@as([N]TX, z)) |v, i| {
464562 const check = if (dir == .Left) x[i] << y[i] else x[i] >> y[i];
465 try expectEqual(check, v);
563 try expect(check == v);
466564 }
467565 }
468566 fn doTheTest() !void {
......@@ -663,11 +761,16 @@ test "vector reduce operation" {
663761}
664762
665763test "mask parameter of @shuffle is comptime scope" {
666 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
667 const __v4hi = std.meta.Vector(4, i16);
764 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
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);
668771 var v4_a = __v4hi{ 0, 0, 0, 0 };
669772 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){
671774 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
672775 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
673776 std.zig.c_translation.shuffleVectorIndex(0, @typeInfo(@TypeOf(v4_a)).Vector.len),
......@@ -677,13 +780,30 @@ test "mask parameter of @shuffle is comptime scope" {
677780}
678781
679782test "saturating add" {
680 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
783 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
681789 const S = struct {
682790 fn doTheTest() !void {
683 const u8x3 = std.meta.Vector(3, u8);
684 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 }));
685 const i8x3 = std.meta.Vector(3, i8);
686 try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 }));
791 { // Broken out to avoid https://github.com/ziglang/zig/issues/11251
792 const u8x3 = @Vector(3, u8);
793 var lhs = u8x3{ 255, 254, 1 };
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 }
687807 }
688808 };
689809 try S.doTheTest();
......@@ -691,11 +811,21 @@ test "saturating add" {
691811}
692812
693813test "saturating subtraction" {
694 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
814 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
695820 const S = struct {
696821 fn doTheTest() !void {
697 const u8x3 = std.meta.Vector(3, u8);
698 try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 }));
822 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
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)));
699829 }
700830 };
701831 try S.doTheTest();
......@@ -703,14 +833,24 @@ test "saturating subtraction" {
703833}
704834
705835test "saturating multiplication" {
706 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
836 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
707842 // TODO: once #9660 has been solved, remove this line
708843 if (builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
709844
710845 const S = struct {
711846 fn doTheTest() !void {
712 const u8x3 = std.meta.Vector(3, u8);
713 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 }));
847 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
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)));
714854 }
715855 };
716856
......@@ -719,11 +859,21 @@ test "saturating multiplication" {
719859}
720860
721861test "saturating shift-left" {
722 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
862 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
723868 const S = struct {
724869 fn doTheTest() !void {
725 const u8x3 = std.meta.Vector(3, u8);
726 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 }));
870 // Broken out to avoid https://github.com/ziglang/zig/issues/11251
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)));
727877 }
728878 };
729879 try S.doTheTest();