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