aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-21 20:05:29 -0400
committerGitHub <noreply@github.com>2022-03-21 20:05:29 -0400
commit71413568389850e821df0784166d840de4d8f96e (patch)
treeccc577b34bc44433c78a56c4ab7065ac5ee50a2d /src
parent2f4473b6536ee43e51a17b02d8fad7518ab32c3b (diff)
parent7eddef423d74318ef9190864232f2e224837461e (diff)
downloadzig-71413568389850e821df0784166d840de4d8f96e.tar.gz
zig-71413568389850e821df0784166d840de4d8f96e.zip
Merge pull request #11237 from wsengir/stage2-vectors
stage2: implement most vector operations in Sema and LLVM backend
Diffstat (limited to 'src')
-rw-r--r--src/Air.zig23
-rw-r--r--src/Liveness.zig4
-rw-r--r--src/Sema.zig525
-rw-r--r--src/arch/aarch64/CodeGen.zig6
-rw-r--r--src/arch/arm/CodeGen.zig7
-rw-r--r--src/arch/riscv64/CodeGen.zig6
-rw-r--r--src/arch/wasm/CodeGen.zig6
-rw-r--r--src/arch/x86_64/CodeGen.zig6
-rw-r--r--src/codegen/c.zig2
-rw-r--r--src/codegen/llvm.zig144
-rw-r--r--src/print_air.zig15
-rw-r--r--src/value.zig769
12 files changed, 1188 insertions, 325 deletions
diff --git a/src/Air.zig b/src/Air.zig
index 2d717f442d..e0f765ddc0 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -308,6 +308,10 @@ pub const Inst = struct {
/// `!=`. Result type is always bool.
/// Uses the `bin_op` field.
cmp_neq,
+ /// Conditional between two vectors.
+ /// Result type is always a vector of bools.
+ /// Uses the `ty_pl` field, payload is `VectorCmp`.
+ cmp_vector,
/// Conditional branch.
/// Result type is always noreturn; no instructions in a block follow this one.
@@ -781,6 +785,20 @@ pub const Shuffle = struct {
mask_len: u32,
};
+pub const VectorCmp = struct {
+ lhs: Inst.Ref,
+ rhs: Inst.Ref,
+ op: u32,
+
+ pub fn compareOperator(self: VectorCmp) std.math.CompareOperator {
+ return @intToEnum(std.math.CompareOperator, @truncate(u3, self.op));
+ }
+
+ pub fn encodeOp(compare_operator: std.math.CompareOperator) u32 {
+ return @enumToInt(compare_operator);
+ }
+};
+
/// Trailing:
/// 0. `Inst.Ref` for every outputs_len
/// 1. `Inst.Ref` for every inputs_len
@@ -886,6 +904,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.shl_sat,
.min,
.max,
+ .bool_and,
+ .bool_or,
=> return air.typeOf(datas[inst].bin_op.lhs),
.sqrt,
@@ -917,8 +937,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.is_non_err,
.is_err_ptr,
.is_non_err_ptr,
- .bool_and,
- .bool_or,
=> return Type.initTag(.bool),
.const_ty => return Type.initTag(.type),
@@ -942,6 +960,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.aggregate_init,
.union_init,
.field_parent_ptr,
+ .cmp_vector,
=> return air.getRefType(datas[inst].ty_pl.ty),
.not,
diff --git a/src/Liveness.zig b/src/Liveness.zig
index dd93d44f72..79521e7a94 100644
--- a/src/Liveness.zig
+++ b/src/Liveness.zig
@@ -441,6 +441,10 @@ fn analyzeInst(
const reduce = inst_datas[inst].reduce;
return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
},
+ .cmp_vector => {
+ const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data;
+ return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
+ },
.aggregate_init => {
const ty_pl = inst_datas[inst].ty_pl;
const aggregate_ty = a.air.getRefType(ty_pl.ty);
diff --git a/src/Sema.zig b/src/Sema.zig
index 7674121ba6..208f33cf7c 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -397,6 +397,20 @@ pub const Block = struct {
});
}
+ 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 {
+ return block.addInst(.{
+ .tag = .cmp_vector,
+ .data = .{ .ty_pl = .{
+ .ty = vector_ty,
+ .payload = try block.sema.addExtra(Air.VectorCmp{
+ .lhs = lhs,
+ .rhs = rhs,
+ .op = Air.VectorCmp.encodeOp(cmp_op),
+ }),
+ } },
+ });
+ }
+
fn addAggregateInit(
block: *Block,
aggregate_ty: Type,
@@ -2091,7 +2105,7 @@ fn zirEnumDecl(
});
} else if (any_values) {
const tag_val = if (last_tag_val) |val|
- try val.intAdd(Value.one, sema.arena)
+ try val.intAdd(Value.one, enum_obj.tag_ty, sema.arena)
else
Value.zero;
last_tag_val = tag_val;
@@ -8178,14 +8192,22 @@ fn zirShl(
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const lhs = sema.resolveInst(extra.lhs);
const rhs = sema.resolveInst(extra.rhs);
+ const lhs_ty = sema.typeOf(lhs);
+ const rhs_ty = sema.typeOf(rhs);
+ const target = sema.mod.getTarget();
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
+
+ const scalar_ty = lhs_ty.scalarType();
+ const scalar_rhs_ty = rhs_ty.scalarType();
// TODO coerce rhs if air_tag is not shl_sat
- const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, sema.typeOf(rhs));
+ const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
const maybe_lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs);
@@ -8199,35 +8221,31 @@ fn zirShl(
}
}
- const lhs_ty = sema.typeOf(lhs);
- const rhs_ty = sema.typeOf(rhs);
- const target = sema.mod.getTarget();
-
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
const rhs_val = maybe_rhs_val orelse break :rs rhs_src;
const val = switch (air_tag) {
.shl_exact => val: {
- const shifted = try lhs_val.shl(rhs_val, sema.arena);
- if (lhs_ty.zigTypeTag() == .ComptimeInt) {
+ const shifted = try lhs_val.shl(rhs_val, lhs_ty, sema.arena);
+ if (scalar_ty.zigTypeTag() == .ComptimeInt) {
break :val shifted;
}
- const int_info = lhs_ty.intInfo(target);
- const truncated = try shifted.intTrunc(sema.arena, int_info.signedness, int_info.bits);
- if (truncated.compareHetero(.eq, shifted)) {
+ const int_info = scalar_ty.intInfo(target);
+ const truncated = try shifted.intTrunc(lhs_ty, sema.arena, int_info.signedness, int_info.bits);
+ if (truncated.compare(.eq, shifted, lhs_ty)) {
break :val shifted;
}
return sema.addConstUndef(lhs_ty);
},
- .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt)
- try lhs_val.shl(rhs_val, sema.arena)
+ .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
+ try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
else
try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, target),
- .shl => if (lhs_ty.zigTypeTag() == .ComptimeInt)
- try lhs_val.shl(rhs_val, sema.arena)
+ .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt)
+ try lhs_val.shl(rhs_val, lhs_ty, sema.arena)
else
try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, target),
@@ -8242,7 +8260,7 @@ fn zirShl(
const new_rhs = if (air_tag == .shl_sat) rhs: {
// Limit the RHS type for saturating shl to be an integer as small as the LHS.
if (rhs_is_comptime_int or
- rhs_ty.intInfo(target).bits > lhs_ty.intInfo(target).bits)
+ scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits)
{
const max_int = try sema.addConstant(
lhs_ty,
@@ -8269,15 +8287,18 @@ fn zirShr(
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const lhs = sema.resolveInst(extra.lhs);
const rhs = sema.resolveInst(extra.rhs);
+ const lhs_ty = sema.typeOf(lhs);
+ const rhs_ty = sema.typeOf(rhs);
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
- const lhs_ty = sema.typeOf(lhs);
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(lhs_ty);
}
@@ -8287,13 +8308,12 @@ fn zirShr(
}
if (air_tag == .shr_exact) {
// Detect if any ones would be shifted out.
- const bits = @intCast(u16, rhs_val.toUnsignedInt());
- const truncated = try lhs_val.intTrunc(sema.arena, .unsigned, bits);
+ const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val);
if (!truncated.compareWithZero(.eq)) {
return sema.addConstUndef(lhs_ty);
}
}
- const val = try lhs_val.shr(rhs_val, sema.arena);
+ const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena);
return sema.addConstant(lhs_ty, val);
} else {
// Even if lhs is not comptime known, we can still deduce certain things based
@@ -8328,32 +8348,15 @@ fn zirBitwise(
const rhs = sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
- const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
- const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
-
- const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
- resolved_type.elemType()
- else
- resolved_type;
-
+ const scalar_type = resolved_type.scalarType();
const scalar_tag = scalar_type.zigTypeTag();
- if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
- if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
- return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
- lhs_ty.arrayLen(),
- rhs_ty.arrayLen(),
- });
- }
- } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {
- return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
- lhs_ty,
- rhs_ty,
- });
- }
+ const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
+ const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
@@ -8363,16 +8366,13 @@ fn zirBitwise(
if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
- if (resolved_type.zigTypeTag() == .Vector) {
- return sema.fail(block, src, "TODO implement zirBitwise for vectors at comptime", .{});
- }
const result_val = switch (air_tag) {
- .bit_and => try lhs_val.bitwiseAnd(rhs_val, sema.arena),
- .bit_or => try lhs_val.bitwiseOr(rhs_val, sema.arena),
- .xor => try lhs_val.bitwiseXor(rhs_val, sema.arena),
+ .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena),
+ .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena),
+ .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena),
else => unreachable,
};
- return sema.addConstant(scalar_type, result_val);
+ return sema.addConstant(resolved_type, result_val);
}
}
@@ -8399,9 +8399,9 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
const target = sema.mod.getTarget();
if (val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(operand_type);
} else if (operand_type.zigTypeTag() == .Vector) {
- const vec_len = try sema.usizeCast(block, operand_src, operand_type.arrayLen());
+ const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen());
var elem_val_buf: Value.ElemValueBuffer = undefined;
const elems = try sema.arena.alloc(Value, vec_len);
for (elems) |*elem, i| {
@@ -8413,8 +8413,8 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
try Value.Tag.aggregate.create(sema.arena, elems),
);
} else {
- const result_val = try val.bitwiseNot(scalar_type, sema.arena, target);
- return sema.addConstant(scalar_type, result_val);
+ const result_val = try val.bitwiseNot(operand_type, sema.arena, target);
+ return sema.addConstant(operand_type, result_val);
}
}
@@ -8766,8 +8766,19 @@ fn zirNegate(
const src = inst_data.src();
const lhs_src = src;
const rhs_src = src; // TODO better source location
- const lhs = sema.resolveInst(.zero);
+
const rhs = sema.resolveInst(inst_data.operand);
+ const rhs_ty = sema.typeOf(rhs);
+ const rhs_scalar_ty = rhs_ty.scalarType();
+
+ if (tag_override == .sub and rhs_scalar_ty.isUnsignedInt()) {
+ return sema.fail(block, src, "negation of type '{}'", .{rhs_ty});
+ }
+
+ const lhs = if (rhs_ty.zigTypeTag() == .Vector)
+ try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
+ else
+ sema.resolveInst(.zero);
return sema.analyzeArithmetic(block, tag_override, lhs, rhs, src, lhs_src, rhs_src);
}
@@ -8985,18 +8996,8 @@ fn analyzeArithmetic(
const rhs_ty = sema.typeOf(rhs);
const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
- if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
- if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
- return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
- lhs_ty.arrayLen(), rhs_ty.arrayLen(),
- });
- }
- return sema.fail(block, src, "TODO implement support for vectors in Sema.analyzeArithmetic", .{});
- } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
- return sema.fail(block, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
- lhs_ty, rhs_ty,
- });
- }
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
+
if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {
.One, .Slice => {},
.Many, .C => {
@@ -9019,15 +9020,13 @@ fn analyzeArithmetic(
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{
.override = &[_]LazySrcLoc{ lhs_src, rhs_src },
});
+
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
- resolved_type.elemType()
- else
- resolved_type;
-
- const scalar_tag = scalar_type.zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType();
+ const scalar_tag = resolved_type.scalarType().zigTypeTag();
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
@@ -9061,7 +9060,7 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (rhs_val.compareWithZero(.eq)) {
@@ -9073,19 +9072,19 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intAdd(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intAdd(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatAdd(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatAdd(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = .add };
@@ -9102,15 +9101,15 @@ fn analyzeArithmetic(
}
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.numberAddWrap(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.numberAddWrap(rhs_val, resolved_type, sema.arena, target),
);
} else break :rs .{ .src = lhs_src, .air_tag = .addwrap };
} else break :rs .{ .src = rhs_src, .air_tag = .addwrap };
@@ -9126,18 +9125,18 @@ fn analyzeArithmetic(
}
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
const val = if (scalar_tag == .ComptimeInt)
- try lhs_val.intAdd(rhs_val, sema.arena)
+ try lhs_val.intAdd(rhs_val, resolved_type, sema.arena)
else
- try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target);
+ try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, target);
- return sema.addConstant(scalar_type, val);
+ return sema.addConstant(resolved_type, val);
} else break :rs .{ .src = lhs_src, .air_tag = .add_sat };
} else break :rs .{ .src = rhs_src, .air_tag = .add_sat };
},
@@ -9154,7 +9153,7 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (rhs_val.compareWithZero(.eq)) {
@@ -9166,19 +9165,19 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intSub(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intSub(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatSub(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatSub(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = .sub };
@@ -9190,7 +9189,7 @@ fn analyzeArithmetic(
// If either of the operands are undefined, the result is undefined.
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
return casted_lhs;
@@ -9198,12 +9197,12 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.numberSubWrap(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.numberSubWrap(rhs_val, resolved_type, sema.arena, target),
);
} else break :rs .{ .src = rhs_src, .air_tag = .subwrap };
} else break :rs .{ .src = lhs_src, .air_tag = .subwrap };
@@ -9214,7 +9213,7 @@ fn analyzeArithmetic(
// If either of the operands are undefined, result is undefined.
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
return casted_lhs;
@@ -9222,15 +9221,15 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
const val = if (scalar_tag == .ComptimeInt)
- try lhs_val.intSub(rhs_val, sema.arena)
+ try lhs_val.intSub(rhs_val, resolved_type, sema.arena)
else
- try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target);
+ try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, target);
- return sema.addConstant(scalar_type, val);
+ return sema.addConstant(resolved_type, val);
} else break :rs .{ .src = rhs_src, .air_tag = .sub_sat };
} else break :rs .{ .src = lhs_src, .air_tag = .sub_sat };
},
@@ -9260,7 +9259,7 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
}
}
@@ -9274,27 +9273,27 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
+ if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
- return sema.addConstUndef(scalar_type);
+ if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
+ return sema.addConstUndef(resolved_type);
}
}
return sema.failWithUseOfUndef(block, rhs_src);
}
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intDiv(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
);
}
} else {
@@ -9335,7 +9334,7 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
}
}
@@ -9349,27 +9348,27 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
+ if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
- return sema.addConstUndef(scalar_type);
+ if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
+ return sema.addConstUndef(resolved_type);
}
}
return sema.failWithUseOfUndef(block, rhs_src);
}
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intDiv(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatDivTrunc(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
@@ -9398,7 +9397,7 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
}
}
@@ -9412,27 +9411,27 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- if (lhs_ty.isSignedInt() and rhs_ty.isSignedInt()) {
+ if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.compare(.neq, Value.negative_one, scalar_type)) {
- return sema.addConstUndef(scalar_type);
+ if (rhs_val.compare(.neq, Value.negative_one, rhs_ty)) {
+ return sema.addConstUndef(resolved_type);
}
}
return sema.failWithUseOfUndef(block, rhs_src);
}
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intDivFloor(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intDivFloor(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatDivFloor(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = .div_floor };
@@ -9460,7 +9459,7 @@ fn analyzeArithmetic(
return sema.failWithUseOfUndef(block, rhs_src);
} else {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
}
}
@@ -9477,14 +9476,14 @@ fn analyzeArithmetic(
if (is_int) {
// TODO: emit compile error if there is a remainder
return sema.addConstant(
- scalar_type,
- try lhs_val.intDiv(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intDiv(rhs_val, resolved_type, sema.arena),
);
} else {
// TODO: emit compile error if there is a remainder
return sema.addConstant(
- scalar_type,
- try lhs_val.floatDiv(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = .div_exact };
@@ -9502,9 +9501,9 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (lhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
return casted_rhs;
}
}
@@ -9514,13 +9513,13 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (rhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (rhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
@@ -9528,18 +9527,18 @@ fn analyzeArithmetic(
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
}
if (is_int) {
return sema.addConstant(
- scalar_type,
- try lhs_val.intMul(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intMul(rhs_val, resolved_type, sema.arena),
);
} else {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatMul(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
);
}
} else break :rs .{ .src = lhs_src, .air_tag = .mul };
@@ -9553,30 +9552,30 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (lhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
return casted_rhs;
}
}
}
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (rhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
return sema.addConstant(
- scalar_type,
- try lhs_val.numberMulWrap(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
);
} else break :rs .{ .src = lhs_src, .air_tag = .mulwrap };
} else break :rs .{ .src = rhs_src, .air_tag = .mulwrap };
@@ -9589,34 +9588,34 @@ fn analyzeArithmetic(
if (maybe_lhs_val) |lhs_val| {
if (!lhs_val.isUndef()) {
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (lhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (lhs_val.compare(.eq, Value.one, lhs_ty)) {
return casted_rhs;
}
}
}
if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (rhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- if (rhs_val.compare(.eq, Value.one, scalar_type)) {
+ if (rhs_val.compare(.eq, Value.one, rhs_ty)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
const val = if (scalar_tag == .ComptimeInt)
- try lhs_val.intMul(rhs_val, sema.arena)
+ try lhs_val.intMul(rhs_val, resolved_type, sema.arena)
else
- try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target);
+ try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, target);
- return sema.addConstant(scalar_type, val);
+ return sema.addConstant(resolved_type, val);
} else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
} else break :rs .{ .src = rhs_src, .air_tag = .mul_sat };
},
@@ -9640,9 +9639,9 @@ fn analyzeArithmetic(
return sema.failWithUseOfUndef(block, lhs_src);
}
if (lhs_val.compareWithZero(.eq)) {
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- } else if (lhs_ty.isSignedInt()) {
+ } else if (lhs_scalar_ty.isSignedInt()) {
return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
}
if (maybe_rhs_val) |rhs_val| {
@@ -9653,7 +9652,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src);
}
if (maybe_lhs_val) |lhs_val| {
- const rem_result = try lhs_val.intRem(rhs_val, sema.arena);
+ const rem_result = try lhs_val.intRem(rhs_val, resolved_type, sema.arena);
// If this answer could possibly be different by doing `intMod`,
// we must emit a compile error. Otherwise, it's OK.
if (rhs_val.compareWithZero(.lt) != lhs_val.compareWithZero(.lt) and
@@ -9667,12 +9666,12 @@ fn analyzeArithmetic(
}
if (lhs_val.compareWithZero(.lt)) {
// Negative
- return sema.addConstant(scalar_type, Value.zero);
+ return sema.addConstant(resolved_type, Value.zero);
}
- return sema.addConstant(scalar_type, rem_result);
+ return sema.addConstant(resolved_type, rem_result);
}
break :rs .{ .src = lhs_src, .air_tag = .rem };
- } else if (rhs_ty.isSignedInt()) {
+ } else if (rhs_scalar_ty.isSignedInt()) {
return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
} else {
break :rs .{ .src = rhs_src, .air_tag = .rem };
@@ -9694,8 +9693,8 @@ fn analyzeArithmetic(
return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
}
return sema.addConstant(
- scalar_type,
- try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
);
} else {
return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
@@ -9731,8 +9730,8 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.intRem(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intRem(rhs_val, resolved_type, sema.arena),
);
}
break :rs .{ .src = lhs_src, .air_tag = .rem };
@@ -9751,12 +9750,12 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatRem(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
);
} else break :rs .{ .src = rhs_src, .air_tag = .rem };
} else break :rs .{ .src = lhs_src, .air_tag = .rem };
@@ -9788,8 +9787,8 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.intMod(rhs_val, sema.arena),
+ resolved_type,
+ try lhs_val.intMod(rhs_val, resolved_type, sema.arena),
);
}
break :rs .{ .src = lhs_src, .air_tag = .mod };
@@ -9808,12 +9807,12 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) {
- return sema.addConstUndef(scalar_type);
+ return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
return sema.addConstant(
- scalar_type,
- try lhs_val.floatMod(rhs_val, scalar_type, sema.arena, target),
+ resolved_type,
+ try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
);
} else break :rs .{ .src = rhs_src, .air_tag = .mod };
} else break :rs .{ .src = lhs_src, .air_tag = .mod };
@@ -10164,6 +10163,11 @@ fn analyzeCmp(
) CompileError!Air.Inst.Ref {
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
+
+ if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
+ return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src);
+ }
if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {
// This operation allows any combination of integer and float types, regardless of the
// signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
@@ -10198,6 +10202,12 @@ fn cmpSelf(
if (try sema.resolveMaybeUndefVal(block, rhs_src, casted_rhs)) |rhs_val| {
if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
+ if (resolved_type.zigTypeTag() == .Vector) {
+ const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
+ const cmp_val = try lhs_val.compareVector(op, rhs_val, resolved_type, sema.arena);
+ return sema.addConstant(result_ty, cmp_val);
+ }
+
if (lhs_val.compare(op, rhs_val, resolved_type)) {
return Air.Inst.Ref.bool_true;
} else {
@@ -10223,16 +10233,12 @@ fn cmpSelf(
}
};
try sema.requireRuntimeBlock(block, runtime_src);
-
- const tag: Air.Inst.Tag = switch (op) {
- .lt => .cmp_lt,
- .lte => .cmp_lte,
- .eq => .cmp_eq,
- .gte => .cmp_gte,
- .gt => .cmp_gt,
- .neq => .cmp_neq,
- };
- // TODO handle vectors
+ if (resolved_type.zigTypeTag() == .Vector) {
+ const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.@"bool");
+ const result_ty_ref = try sema.addType(result_ty);
+ return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
+ }
+ const tag = Air.Inst.Tag.fromCmpOp(op);
return block.addBinOp(tag, casted_lhs, casted_rhs);
}
@@ -11353,7 +11359,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
const elem_ty = operand.elemType2();
const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
return Type.Tag.vector.create(sema.arena, .{
- .len = operand.arrayLen(),
+ .len = operand.vectorLen(),
.elem_type = log2_elem_ty,
});
},
@@ -13284,7 +13290,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
const target = sema.mod.getTarget();
- const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
+ const result_val = val.floatToInt(sema.arena, operand_ty, dest_ty, target) catch |err| switch (err) {
error.FloatCannotFit => {
return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
},
@@ -13311,7 +13317,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
const target = sema.mod.getTarget();
- const result_val = try val.intToFloat(sema.arena, dest_ty, target);
+ const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
return sema.addConstant(dest_ty, result_val);
}
@@ -13521,14 +13527,14 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (!is_vector) {
return sema.addConstant(
dest_ty,
- try val.intTrunc(sema.arena, dest_info.signedness, dest_info.bits),
+ try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits),
);
}
var elem_buf: Value.ElemValueBuffer = undefined;
const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());
for (elems) |*elem, i| {
const elem_val = val.elemValueBuffer(i, &elem_buf);
- elem.* = try elem_val.intTrunc(sema.arena, dest_info.signedness, dest_info.bits);
+ elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits);
}
return sema.addConstant(
dest_ty,
@@ -14083,13 +14089,40 @@ fn checkSimdBinOp(
) CompileError!SimdBinOp {
const lhs_ty = sema.typeOf(uncasted_lhs);
const rhs_ty = sema.typeOf(uncasted_rhs);
+
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
+ var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
+ const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
+ .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
+ });
+ const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
+ const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
+
+ return SimdBinOp{
+ .len = vec_len,
+ .lhs = lhs,
+ .rhs = rhs,
+ .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs),
+ .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs),
+ .result_ty = result_ty,
+ .scalar_ty = result_ty.scalarType(),
+ };
+}
+
+fn checkVectorizableBinaryOperands(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ lhs_ty: Type,
+ rhs_ty: Type,
+ lhs_src: LazySrcLoc,
+ rhs_src: LazySrcLoc,
+) CompileError!void {
const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
-
- var vec_len: ?usize = null;
if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
- const lhs_len = lhs_ty.arrayLen();
- const rhs_len = rhs_ty.arrayLen();
+ const lhs_len = lhs_ty.vectorLen();
+ const rhs_len = rhs_ty.vectorLen();
if (lhs_len != rhs_len) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
@@ -14100,7 +14133,6 @@ fn checkSimdBinOp(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- vec_len = try sema.usizeCast(block, lhs_src, lhs_len);
} else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{
@@ -14118,21 +14150,6 @@ fn checkSimdBinOp(
};
return sema.failWithOwnedErrorMsg(block, msg);
}
- const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
- .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
- });
- const lhs = try sema.coerce(block, result_ty, uncasted_lhs, lhs_src);
- const rhs = try sema.coerce(block, result_ty, uncasted_rhs, rhs_src);
-
- return SimdBinOp{
- .len = vec_len,
- .lhs = lhs,
- .rhs = rhs,
- .lhs_val = try sema.resolveMaybeUndefVal(block, lhs_src, lhs),
- .rhs_val = try sema.resolveMaybeUndefVal(block, rhs_src, rhs),
- .result_ty = result_ty,
- .scalar_ty = result_ty.scalarType(),
- };
}
fn resolveExportOptions(
@@ -14362,9 +14379,9 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
while (i < vec_len) : (i += 1) {
const elem_val = operand_val.elemValueBuffer(i, &elem_buf);
switch (operation) {
- .And => accum = try accum.bitwiseAnd(elem_val, sema.arena),
- .Or => accum = try accum.bitwiseOr(elem_val, sema.arena),
- .Xor => accum = try accum.bitwiseXor(elem_val, sema.arena),
+ .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena),
+ .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena),
+ .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena),
.Min => accum = accum.numberMin(elem_val),
.Max => accum = accum.numberMax(elem_val),
.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
.Xchg => operand_val,
.Add => try stored_val.numberAddWrap(operand_val, operand_ty, sema.arena, target),
.Sub => try stored_val.numberSubWrap(operand_val, operand_ty, sema.arena, target),
- .And => try stored_val.bitwiseAnd (operand_val, sema.arena),
+ .And => try stored_val.bitwiseAnd (operand_val, operand_ty, sema.arena),
.Nand => try stored_val.bitwiseNand (operand_val, operand_ty, sema.arena, target),
- .Or => try stored_val.bitwiseOr (operand_val, sema.arena),
- .Xor => try stored_val.bitwiseXor (operand_val, sema.arena),
+ .Or => try stored_val.bitwiseOr (operand_val, operand_ty, sema.arena),
+ .Xor => try stored_val.bitwiseXor (operand_val, operand_ty, sema.arena),
.Max => stored_val.numberMax (operand_val),
.Min => stored_val.numberMin (operand_val),
// zig fmt: on
@@ -17509,7 +17526,7 @@ fn coerce(
if (val.floatHasFraction()) {
return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val.fmtValue(inst_ty), dest_ty });
}
- const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
+ const result_val = val.floatToInt(sema.arena, inst_ty, dest_ty, target) catch |err| switch (err) {
error.FloatCannotFit => {
return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
},
@@ -17572,7 +17589,7 @@ fn coerce(
},
.Int, .ComptimeInt => int: {
const val = (try sema.resolveDefinedValue(block, inst_src, inst)) orelse break :int;
- const result_val = try val.intToFloat(sema.arena, dest_ty, target);
+ const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target);
// TODO implement this compile error
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
//if (!int_again_val.eql(val, inst_ty)) {
@@ -17809,8 +17826,21 @@ fn coerceInMemoryAllowed(
return .ok;
}
+ // Vectors
+ if (dest_tag == .Vector and src_tag == .Vector) vectors: {
+ const dest_len = dest_ty.vectorLen();
+ const src_len = src_ty.vectorLen();
+ if (dest_len != src_len) break :vectors;
+
+ const dest_elem_ty = dest_ty.scalarType();
+ const src_elem_ty = src_ty.scalarType();
+ const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
+ if (child == .no_match) break :vectors;
+
+ return .ok;
+ }
+
// TODO: non-pointer-like optionals
- // TODO: vectors
return .no_match;
}
@@ -19683,19 +19713,6 @@ fn cmpNumeric(
const lhs_ty_tag = lhs_ty.zigTypeTag();
const rhs_ty_tag = rhs_ty.zigTypeTag();
- if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
- if (lhs_ty.vectorLen() != rhs_ty.vectorLen()) {
- return sema.fail(block, src, "vector length mismatch: {d} and {d}", .{
- lhs_ty.vectorLen(), rhs_ty.vectorLen(),
- });
- }
- return sema.fail(block, src, "TODO implement support for vectors in cmpNumeric", .{});
- } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
- return sema.fail(block, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
- lhs_ty, rhs_ty,
- });
- }
-
const runtime_src: LazySrcLoc = src: {
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
@@ -19881,6 +19898,46 @@ fn cmpNumeric(
return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
}
+/// Asserts that lhs and rhs types are both vectors.
+fn cmpVector(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ lhs: Air.Inst.Ref,
+ rhs: Air.Inst.Ref,
+ op: std.math.CompareOperator,
+ lhs_src: LazySrcLoc,
+ rhs_src: LazySrcLoc,
+) CompileError!Air.Inst.Ref {
+ const lhs_ty = sema.typeOf(lhs);
+ const rhs_ty = sema.typeOf(rhs);
+ assert(lhs_ty.zigTypeTag() == .Vector);
+ assert(rhs_ty.zigTypeTag() == .Vector);
+ try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
+
+ const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.@"bool");
+
+ const runtime_src: LazySrcLoc = src: {
+ if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
+ if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ return sema.addConstUndef(result_ty);
+ }
+ const cmp_val = try lhs_val.compareVector(op, rhs_val, lhs_ty, sema.arena);
+ return sema.addConstant(result_ty, cmp_val);
+ } else {
+ break :src rhs_src;
+ }
+ } else {
+ break :src lhs_src;
+ }
+ };
+
+ try sema.requireRuntimeBlock(block, runtime_src);
+ const result_ty_inst = try sema.addType(result_ty);
+ return block.addCmpVector(lhs, rhs, op, result_ty_inst);
+}
+
fn wrapOptional(
sema: *Sema,
block: *Block,
@@ -21187,7 +21244,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
map.putAssumeCapacityContext(copied_val, {}, .{ .ty = int_tag_ty });
} else {
const val = if (last_tag_val) |val|
- try val.intAdd(Value.one, sema.arena)
+ try val.intAdd(Value.one, int_tag_ty, sema.arena)
else
Value.zero;
last_tag_val = val;
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index c9121c8859..9c2d5890a7 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -577,6 +577,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.cmp_gte => try self.airCmp(inst, .gte),
.cmp_gt => try self.airCmp(inst, .gt),
.cmp_neq => try self.airCmp(inst, .neq),
+ .cmp_vector => try self.airCmpVector(inst),
.bool_and => try self.airBinOp(inst),
.bool_or => try self.airBinOp(inst),
@@ -2713,6 +2714,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
+}
+
fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index 921bc92c72..0b9f9eb2e2 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -567,6 +567,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.cmp_gte => try self.airCmp(inst, .gte),
.cmp_gt => try self.airCmp(inst, .gt),
.cmp_neq => try self.airCmp(inst, .neq),
+ .cmp_vector => try self.airCmpVector(inst),
.bool_and => try self.airBinOp(inst),
.bool_or => try self.airBinOp(inst),
@@ -2894,7 +2895,6 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
const lhs_ty = self.air.typeOf(bin_op.lhs);
switch (lhs_ty.zigTypeTag()) {
- .Vector => return self.fail("TODO ARM cmp vectors", .{}),
.Optional => return self.fail("TODO ARM cmp optionals", .{}),
.Float => return self.fail("TODO ARM cmp floats", .{}),
.Int, .Bool, .Pointer, .ErrorSet, .Enum => {
@@ -2929,6 +2929,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
+}
+
fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig
index 14beedd2a9..3b73fef51f 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -537,6 +537,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.cmp_gte => try self.airCmp(inst, .gte),
.cmp_gt => try self.airCmp(inst, .gt),
.cmp_neq => try self.airCmp(inst, .neq),
+ .cmp_vector => try self.airCmpVector(inst),
.bool_and => try self.airBoolOp(inst),
.bool_or => try self.airBoolOp(inst),
@@ -1791,6 +1792,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
// return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
+}
+
fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index c60c321572..8d515e9365 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1309,6 +1309,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.cmp_lte => self.airCmp(inst, .lte),
.cmp_lt => self.airCmp(inst, .lt),
.cmp_neq => self.airCmp(inst, .neq),
+ .cmp_vector => self.airCmpVector(inst),
.array_elem_val => self.airArrayElemVal(inst),
.array_to_slice => self.airArrayToSlice(inst),
@@ -2222,6 +2223,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
return cmp_tmp;
}
+fn airCmpVector(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+ _ = inst;
+ return self.fail("TODO implement airCmpVector for wasm", .{});
+}
+
fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const br = self.air.instructions.items(.data)[inst].br;
const block = self.blocks.get(br.block_inst).?;
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 72f12cf4e9..598511a631 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -658,6 +658,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.cmp_gte => try self.airCmp(inst, .gte),
.cmp_gt => try self.airCmp(inst, .gt),
.cmp_neq => try self.airCmp(inst, .neq),
+ .cmp_vector => try self.airCmpVector(inst),
.bool_and => try self.airBoolOp(inst),
.bool_or => try self.airBoolOp(inst),
@@ -3699,6 +3700,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
+fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void {
+ _ = inst;
+ return self.fail("TODO implement airCmpVector for {}", .{self.target.cpu.arch});
+}
+
fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
const payload = try self.addExtra(Mir.DbgLineColumn{
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 23ccdc007b..f5a1036479 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1715,6 +1715,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.cmp_eq => try airEquality(f, inst, "((", "=="),
.cmp_neq => try airEquality(f, inst, "!((", "!="),
+ .cmp_vector => return f.fail("TODO: C backend: implement binary op for tag '{s}'", .{@tagName(Air.Inst.Tag.cmp_vector)}),
+
// bool_and and bool_or are non-short-circuit operations
.bool_and => try airBinOp(f, inst, " & "),
.bool_or => try airBinOp(f, inst, " | "),
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 139c1f25cb..107b059765 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -3375,6 +3375,7 @@ pub const FuncGen = struct {
.cmp_lt => try self.airCmp(inst, .lt),
.cmp_lte => try self.airCmp(inst, .lte),
.cmp_neq => try self.airCmp(inst, .neq),
+ .cmp_vector => try self.airCmpVector(inst),
.is_non_null => try self.airIsNonNull(inst, false, false, .NE),
.is_non_null_ptr => try self.airIsNonNull(inst, true , false, .NE),
@@ -3640,6 +3641,20 @@ pub const FuncGen = struct {
return self.cmp(lhs, rhs, operand_ty, op);
}
+ fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+ const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
+
+ const lhs = try self.resolveInst(extra.lhs);
+ const rhs = try self.resolveInst(extra.rhs);
+ const vec_ty = self.air.typeOf(extra.lhs);
+ const cmp_op = extra.compareOperator();
+
+ return self.cmp(lhs, rhs, vec_ty, cmp_op);
+ }
+
fn cmp(
self: *FuncGen,
lhs: *const llvm.Value,
@@ -3650,9 +3665,10 @@ pub const FuncGen = struct {
var int_buffer: Type.Payload.Bits = undefined;
var opt_buffer: Type.Payload.ElemType = undefined;
- const int_ty = switch (operand_ty.zigTypeTag()) {
- .Enum => operand_ty.intTagType(&int_buffer),
- .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
+ const scalar_ty = operand_ty.scalarType();
+ const int_ty = switch (scalar_ty.zigTypeTag()) {
+ .Enum => scalar_ty.intTagType(&int_buffer),
+ .Int, .Bool, .Pointer, .ErrorSet => scalar_ty,
.Optional => blk: {
const payload_ty = operand_ty.optionalChild(&opt_buffer);
if (!payload_ty.hasRuntimeBitsIgnoreComptime() or operand_ty.isPtrLikeOptional()) {
@@ -3944,10 +3960,11 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.air.typeOf(ty_op.operand);
+ const operand_scalar_ty = operand_ty.scalarType();
const dest_ty = self.air.typeOfIndex(inst);
const dest_llvm_ty = try self.dg.llvmType(dest_ty);
- if (operand_ty.isSignedInt()) {
+ if (operand_scalar_ty.isSignedInt()) {
return self.builder.buildSIToFP(operand, dest_llvm_ty, "");
} else {
return self.builder.buildUIToFP(operand, dest_llvm_ty, "");
@@ -3961,11 +3978,12 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const operand = try self.resolveInst(ty_op.operand);
const dest_ty = self.air.typeOfIndex(inst);
+ const dest_scalar_ty = dest_ty.scalarType();
const dest_llvm_ty = try self.dg.llvmType(dest_ty);
// TODO set fast math flag
- if (dest_ty.isSignedInt()) {
+ if (dest_scalar_ty.isSignedInt()) {
return self.builder.buildFPToSI(operand, dest_llvm_ty, "");
} else {
return self.builder.buildFPToUI(operand, dest_llvm_ty, "");
@@ -4896,9 +4914,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");
- if (inst_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.builder.buildFAdd(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildNSWAdd(lhs, rhs, "");
return self.builder.buildNUWAdd(lhs, rhs, "");
}
@@ -4919,9 +4938,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.todo("saturating float add", .{});
- if (inst_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
+ if (scalar_ty.isSignedInt()) return self.builder.buildSAddSat(lhs, rhs, "");
return self.builder.buildUAddSat(lhs, rhs, "");
}
@@ -4933,9 +4953,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");
- if (inst_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.builder.buildFSub(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildNSWSub(lhs, rhs, "");
return self.builder.buildNUWSub(lhs, rhs, "");
}
@@ -4956,9 +4977,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
- if (inst_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
+ if (scalar_ty.isSignedInt()) return self.builder.buildSSubSat(lhs, rhs, "");
return self.builder.buildUSubSat(lhs, rhs, "");
}
@@ -4969,9 +4991,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");
- if (inst_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.builder.buildFMul(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildNSWMul(lhs, rhs, "");
return self.builder.buildNUWMul(lhs, rhs, "");
}
@@ -4992,9 +5015,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
- if (inst_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
+ if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
+ if (scalar_ty.isSignedInt()) return self.builder.buildSMulFixSat(lhs, rhs, "");
return self.builder.buildUMulFixSat(lhs, rhs, "");
}
@@ -5015,12 +5039,13 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isRuntimeFloat()) {
+ if (scalar_ty.isRuntimeFloat()) {
const result = self.builder.buildFDiv(lhs, rhs, "");
return self.callTrunc(result, inst_ty);
}
- if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
return self.builder.buildUDiv(lhs, rhs, "");
}
@@ -5031,12 +5056,13 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isRuntimeFloat()) {
+ if (scalar_ty.isRuntimeFloat()) {
const result = self.builder.buildFDiv(lhs, rhs, "");
return try self.callFloor(result, inst_ty);
}
- if (inst_ty.isSignedInt()) {
+ if (scalar_ty.isSignedInt()) {
// const d = @divTrunc(a, b);
// const r = @rem(a, b);
// return if (r == 0) d else d - ((a < 0) ^ (b < 0));
@@ -5062,9 +5088,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, "");
- if (inst_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
+ if (scalar_ty.isRuntimeFloat()) return self.builder.buildFDiv(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildExactSDiv(lhs, rhs, "");
return self.builder.buildExactUDiv(lhs, rhs, "");
}
@@ -5075,9 +5102,10 @@ pub const FuncGen = struct {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, "");
- if (inst_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
+ if (scalar_ty.isRuntimeFloat()) return self.builder.buildFRem(lhs, rhs, "");
+ if (scalar_ty.isSignedInt()) return self.builder.buildSRem(lhs, rhs, "");
return self.builder.buildURem(lhs, rhs, "");
}
@@ -5089,8 +5117,9 @@ pub const FuncGen = struct {
const rhs = try self.resolveInst(bin_op.rhs);
const inst_ty = self.air.typeOfIndex(inst);
const inst_llvm_ty = try self.dg.llvmType(inst_ty);
+ const scalar_ty = inst_ty.scalarType();
- if (inst_ty.isRuntimeFloat()) {
+ if (scalar_ty.isRuntimeFloat()) {
const a = self.builder.buildFRem(lhs, rhs, "");
const b = self.builder.buildFAdd(a, rhs, "");
const c = self.builder.buildFRem(b, rhs, "");
@@ -5098,7 +5127,7 @@ pub const FuncGen = struct {
const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");
return self.builder.buildSelect(ltz, c, a, "");
}
- if (inst_ty.isSignedInt()) {
+ if (scalar_ty.isSignedInt()) {
const a = self.builder.buildSRem(lhs, rhs, "");
const b = self.builder.buildNSWAdd(a, rhs, "");
const c = self.builder.buildSRem(b, rhs, "");
@@ -5323,15 +5352,22 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst)) return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- const lhs_type = self.air.typeOf(bin_op.lhs);
+
+ const lhs_ty = self.air.typeOf(bin_op.lhs);
+ const rhs_ty = self.air.typeOf(bin_op.rhs);
+ const lhs_scalar_ty = lhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType();
+
const tg = self.dg.module.getTarget();
- const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
- self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
+
+ const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
+ self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
else
rhs;
- if (lhs_type.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
+ if (lhs_scalar_ty.isSignedInt()) return self.builder.buildNSWShl(lhs, casted_rhs, "");
return self.builder.buildNUWShl(lhs, casted_rhs, "");
}
@@ -5339,11 +5375,18 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst)) return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
+
const lhs_type = self.air.typeOf(bin_op.lhs);
+ const rhs_type = self.air.typeOf(bin_op.rhs);
+ const lhs_scalar_ty = lhs_type.scalarType();
+ const rhs_scalar_ty = rhs_type.scalarType();
+
const tg = self.dg.module.getTarget();
- const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
+
+ const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
else
rhs;
@@ -5354,31 +5397,45 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst)) return null;
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- const lhs_type = self.air.typeOf(bin_op.lhs);
+
+ const lhs_ty = self.air.typeOf(bin_op.lhs);
+ const rhs_ty = self.air.typeOf(bin_op.rhs);
+ const lhs_scalar_ty = lhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType();
+
const tg = self.dg.module.getTarget();
- const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
- self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
+
+ const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
+ self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
else
rhs;
- if (lhs_type.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
+ if (lhs_scalar_ty.isSignedInt()) return self.builder.buildSShlSat(lhs, casted_rhs, "");
return self.builder.buildUShlSat(lhs, casted_rhs, "");
}
fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*const llvm.Value {
- if (self.liveness.isUnused(inst))
- return null;
+ if (self.liveness.isUnused(inst)) return null;
+
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
- const lhs_type = self.air.typeOf(bin_op.lhs);
+
+ const lhs_ty = self.air.typeOf(bin_op.lhs);
+ const rhs_ty = self.air.typeOf(bin_op.rhs);
+ const lhs_scalar_ty = lhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType();
+
const tg = self.dg.module.getTarget();
- const casted_rhs = if (self.air.typeOf(bin_op.rhs).bitSize(tg) < lhs_type.bitSize(tg))
- self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_type), "")
+
+ const casted_rhs = if (rhs_scalar_ty.bitSize(tg) < lhs_scalar_ty.bitSize(tg))
+ self.builder.buildZExt(rhs, try self.dg.llvmType(lhs_ty), "")
else
rhs;
- const is_signed_int = self.air.typeOfIndex(inst).isSignedInt();
+ const is_signed_int = lhs_scalar_ty.isSignedInt();
if (is_exact) {
if (is_signed_int) {
@@ -5506,7 +5563,8 @@ pub const FuncGen = struct {
if (bitcast_ok) {
const llvm_vector_ty = try self.dg.llvmType(operand_ty);
const casted_ptr = self.builder.buildBitCast(array_ptr, llvm_vector_ty.pointerType(0), "");
- _ = self.builder.buildStore(operand, casted_ptr);
+ const llvm_store = self.builder.buildStore(operand, casted_ptr);
+ llvm_store.setAlignment(inst_ty.abiAlignment(target));
} else {
// If the ABI size of the element type is not evenly divisible by size in bits;
// a simple bitcast will not work, and we fall back to extractelement.
diff --git a/src/print_air.zig b/src/print_air.zig
index fb970e3b08..c6b27a6cd6 100644
--- a/src/print_air.zig
+++ b/src/print_air.zig
@@ -266,6 +266,7 @@ const Writer = struct {
.mul_add => try w.writeMulAdd(s, inst),
.shuffle => try w.writeShuffle(s, inst),
.reduce => try w.writeReduce(s, inst),
+ .cmp_vector => try w.writeCmpVector(s, inst),
.add_with_overflow,
.sub_with_overflow,
@@ -402,6 +403,16 @@ const Writer = struct {
try s.print(", {s}", .{@tagName(reduce.operation)});
}
+ fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
+ const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
+ const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
+
+ try s.print("{s}, ", .{@tagName(extra.compareOperator())});
+ try w.writeOperand(s, inst, 0, extra.lhs);
+ try s.writeAll(", ");
+ try w.writeOperand(s, inst, 1, extra.rhs);
+ }
+
fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const atomic_order = w.air.instructions.items(.data)[inst].fence;
@@ -470,8 +481,8 @@ const Writer = struct {
}
fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
- const pl_op = w.air.instructions.items(.data)[inst].ty_pl;
- const extra = w.air.extraData(Air.FieldParentPtr, pl_op.payload).data;
+ const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
+ const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
try w.writeOperand(s, inst, 0, extra.field_ptr);
try s.print(", {d}", .{extra.field_index});
diff --git a/src/value.zig b/src/value.zig
index 76ab20c7ab..454b1d76a2 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1846,8 +1846,23 @@ pub const Value = extern union {
return order(lhs, rhs).compare(op);
}
- /// Asserts the value is comparable. Both operands have type `ty`.
+ /// Asserts the values are comparable. Both operands have type `ty`.
+ /// Vector results will be reduced with AND.
pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {
+ if (ty.zigTypeTag() == .Vector) {
+ var i: usize = 0;
+ while (i < ty.vectorLen()) : (i += 1) {
+ if (!compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return compareScalar(lhs, op, rhs, ty);
+ }
+
+ /// Asserts the values are comparable. Both operands have type `ty`.
+ pub fn compareScalar(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type) bool {
return switch (op) {
.eq => lhs.eql(rhs, ty),
.neq => !lhs.eql(rhs, ty),
@@ -1855,18 +1870,25 @@ pub const Value = extern union {
};
}
+ /// Asserts the values are comparable vectors of type `ty`.
+ pub fn compareVector(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ assert(ty.zigTypeTag() == .Vector);
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType());
+ scalar.* = if (res_bool) Value.@"true" else Value.@"false";
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+
/// Asserts the value is comparable.
- /// For vectors this is only valid with op == .eq.
+ /// Vector results will be reduced with AND.
pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
switch (lhs.tag()) {
- .repeated => {
- assert(op == .eq);
- return lhs.castTag(.repeated).?.data.compareWithZero(.eq);
- },
+ .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op),
.aggregate => {
- assert(op == .eq);
for (lhs.castTag(.aggregate).?.data) |elem_val| {
- if (!elem_val.compareWithZero(.eq)) return false;
+ if (!elem_val.compareWithZero(op)) return false;
}
return true;
},
@@ -2404,6 +2426,27 @@ pub const Value = extern union {
};
}
+ /// Index into a vector-like `Value`. Asserts `index` is a valid index for `val`.
+ /// Some scalar values are considered vector-like to avoid needing to allocate
+ /// a new `repeated` each time a constant is used.
+ pub fn indexVectorlike(val: Value, index: usize) Value {
+ return switch (val.tag()) {
+ .aggregate => val.castTag(.aggregate).?.data[index],
+
+ .repeated => val.castTag(.repeated).?.data,
+ // These values will implicitly be treated as `repeated`.
+ .zero,
+ .one,
+ .bool_false,
+ .bool_true,
+ .int_i64,
+ .int_u64,
+ => val,
+
+ else => unreachable,
+ };
+ }
+
/// Asserts the value is a single-item pointer to an array, or an array,
/// or an unknown-length pointer, and returns the element value at the index.
pub fn elemValue(val: Value, arena: Allocator, index: usize) !Value {
@@ -2646,25 +2689,36 @@ pub const Value = extern union {
};
}
- pub fn intToFloat(val: Value, arena: Allocator, dest_ty: Type, target: Target) !Value {
+ pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value {
+ if (int_ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, int_ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return intToFloatScalar(val, arena, float_ty, target);
+ }
+
+ pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value {
switch (val.tag()) {
.undef, .zero, .one => return val,
.the_only_possible_value => return Value.initTag(.zero), // for i0, u0
.int_u64 => {
- return intToFloatInner(val.castTag(.int_u64).?.data, arena, dest_ty, target);
+ return intToFloatInner(val.castTag(.int_u64).?.data, arena, float_ty, target);
},
.int_i64 => {
- return intToFloatInner(val.castTag(.int_i64).?.data, arena, dest_ty, target);
+ return intToFloatInner(val.castTag(.int_i64).?.data, arena, float_ty, target);
},
.int_big_positive => {
const limbs = val.castTag(.int_big_positive).?.data;
const float = bigIntToFloat(limbs, true);
- return floatToValue(float, arena, dest_ty, target);
+ return floatToValue(float, arena, float_ty, target);
},
.int_big_negative => {
const limbs = val.castTag(.int_big_negative).?.data;
const float = bigIntToFloat(limbs, false);
- return floatToValue(float, arena, dest_ty, target);
+ return floatToValue(float, arena, float_ty, target);
},
else => unreachable,
}
@@ -2694,7 +2748,18 @@ pub const Value = extern union {
}
}
- pub fn floatToInt(val: Value, arena: Allocator, dest_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
+ pub fn floatToInt(val: Value, arena: Allocator, float_ty: Type, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
+ if (float_ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatToIntScalar(val.indexVectorlike(i), arena, int_ty.scalarType(), target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatToIntScalar(val, arena, int_ty, target);
+ }
+
+ pub fn floatToIntScalar(val: Value, arena: Allocator, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
const Limb = std.math.big.Limb;
var value = val.toFloat(f64); // TODO: f128 ?
@@ -2724,7 +2789,7 @@ pub const Value = extern union {
else
try Value.Tag.int_big_positive.create(arena, result_limbs);
- if (result.intFitsInType(dest_ty, target)) {
+ if (result.intFitsInType(int_ty, target)) {
return result;
} else {
return error.FloatCannotFit;
@@ -2771,7 +2836,7 @@ pub const Value = extern union {
};
}
- /// Supports both floats and ints; handles undefined.
+ /// Supports both (vectors of) floats and ints; handles undefined scalars.
pub fn numberAddWrap(
lhs: Value,
rhs: Value,
@@ -2779,10 +2844,28 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try numberAddWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return numberAddWrapScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports both floats and ints; handles undefined.
+ pub fn numberAddWrapScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
if (ty.zigTypeTag() == .ComptimeInt) {
- return intAdd(lhs, rhs, arena);
+ return intAdd(lhs, rhs, ty, arena);
}
if (ty.isAnyFloat()) {
@@ -2809,7 +2892,7 @@ pub const Value = extern union {
}
}
- /// Supports integers only; asserts neither operand is undefined.
+ /// Supports (vectors of) integers only; asserts neither operand is undefined.
pub fn intAddSat(
lhs: Value,
rhs: Value,
@@ -2817,6 +2900,24 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intAddSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return intAddSatScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports integers only; asserts neither operand is undefined.
+ pub fn intAddSatScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
assert(!lhs.isUndef());
assert(!rhs.isUndef());
@@ -2861,7 +2962,7 @@ pub const Value = extern union {
};
}
- /// Supports both floats and ints; handles undefined.
+ /// Supports both (vectors of) floats and ints; handles undefined scalars.
pub fn numberSubWrap(
lhs: Value,
rhs: Value,
@@ -2869,10 +2970,28 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try numberSubWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return numberSubWrapScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports both floats and ints; handles undefined.
+ pub fn numberSubWrapScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
if (ty.zigTypeTag() == .ComptimeInt) {
- return intSub(lhs, rhs, arena);
+ return intSub(lhs, rhs, ty, arena);
}
if (ty.isAnyFloat()) {
@@ -2883,7 +3002,7 @@ pub const Value = extern union {
return overflow_result.wrapped_result;
}
- /// Supports integers only; asserts neither operand is undefined.
+ /// Supports (vectors of) integers only; asserts neither operand is undefined.
pub fn intSubSat(
lhs: Value,
rhs: Value,
@@ -2891,6 +3010,24 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intSubSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return intSubSatScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports integers only; asserts neither operand is undefined.
+ pub fn intSubSatScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
assert(!lhs.isUndef());
assert(!rhs.isUndef());
@@ -2944,7 +3081,7 @@ pub const Value = extern union {
};
}
- /// Supports both floats and ints; handles undefined.
+ /// Supports both (vectors of) floats and ints; handles undefined scalars.
pub fn numberMulWrap(
lhs: Value,
rhs: Value,
@@ -2952,10 +3089,28 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try numberMulWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return numberMulWrapScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports both floats and ints; handles undefined.
+ pub fn numberMulWrapScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
if (ty.zigTypeTag() == .ComptimeInt) {
- return intMul(lhs, rhs, arena);
+ return intMul(lhs, rhs, ty, arena);
}
if (ty.isAnyFloat()) {
@@ -2966,7 +3121,7 @@ pub const Value = extern union {
return overflow_result.wrapped_result;
}
- /// Supports integers only; asserts neither operand is undefined.
+ /// Supports (vectors of) integers only; asserts neither operand is undefined.
pub fn intMulSat(
lhs: Value,
rhs: Value,
@@ -2974,6 +3129,24 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intMulSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return intMulSatScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// Supports (vectors of) integers only; asserts neither operand is undefined.
+ pub fn intMulSatScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
assert(!lhs.isUndef());
assert(!rhs.isUndef());
@@ -3025,8 +3198,20 @@ pub const Value = extern union {
};
}
- /// operands must be integers; handles undefined.
+ /// operands must be (vectors of) integers; handles undefined scalars.
pub fn bitwiseNot(val: Value, ty: Type, arena: Allocator, target: Target) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try bitwiseNotScalar(val.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return bitwiseNotScalar(val, ty, arena, target);
+ }
+
+ /// operands must be integers; handles undefined.
+ pub fn bitwiseNotScalar(val: Value, ty: Type, arena: Allocator, target: Target) !Value {
if (val.isUndef()) return Value.initTag(.undef);
const info = ty.intInfo(target);
@@ -3050,8 +3235,20 @@ pub const Value = extern union {
return fromBigInt(arena, result_bigint.toConst());
}
+ /// operands must be (vectors of) integers; handles undefined scalars.
+ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try bitwiseAndScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return bitwiseAndScalar(lhs, rhs, allocator);
+ }
+
/// operands must be integers; handles undefined.
- pub fn bitwiseAnd(lhs: Value, rhs: Value, arena: Allocator) !Value {
+ pub fn bitwiseAndScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
// TODO is this a performance issue? maybe we should try the operation without
@@ -3070,22 +3267,46 @@ pub const Value = extern union {
return fromBigInt(arena, result_bigint.toConst());
}
- /// operands must be integers; handles undefined.
+ /// operands must be (vectors of) integers; handles undefined scalars.
pub fn bitwiseNand(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try bitwiseNandScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return bitwiseNandScalar(lhs, rhs, ty, arena, target);
+ }
+
+ /// operands must be integers; handles undefined.
+ pub fn bitwiseNandScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, target: Target) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
- const anded = try bitwiseAnd(lhs, rhs, arena);
+ const anded = try bitwiseAnd(lhs, rhs, ty, arena);
const all_ones = if (ty.isSignedInt())
try Value.Tag.int_i64.create(arena, -1)
else
try ty.maxInt(arena, target);
- return bitwiseXor(anded, all_ones, arena);
+ return bitwiseXor(anded, all_ones, ty, arena);
+ }
+
+ /// operands must be (vectors of) integers; handles undefined scalars.
+ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try bitwiseOrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return bitwiseOrScalar(lhs, rhs, allocator);
}
/// operands must be integers; handles undefined.
- pub fn bitwiseOr(lhs: Value, rhs: Value, arena: Allocator) !Value {
+ pub fn bitwiseOrScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
// TODO is this a performance issue? maybe we should try the operation without
@@ -3103,8 +3324,20 @@ pub const Value = extern union {
return fromBigInt(arena, result_bigint.toConst());
}
+ /// operands must be (vectors of) integers; handles undefined scalars.
+ pub fn bitwiseXor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try bitwiseXorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return bitwiseXorScalar(lhs, rhs, allocator);
+ }
+
/// operands must be integers; handles undefined.
- pub fn bitwiseXor(lhs: Value, rhs: Value, arena: Allocator) !Value {
+ pub fn bitwiseXorScalar(lhs: Value, rhs: Value, arena: Allocator) !Value {
if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
// TODO is this a performance issue? maybe we should try the operation without
@@ -3123,7 +3356,18 @@ pub const Value = extern union {
return fromBigInt(arena, result_bigint.toConst());
}
- pub fn intAdd(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intAddScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3139,7 +3383,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_bigint.toConst());
}
- pub fn intSub(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intSubScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3155,7 +3410,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_bigint.toConst());
}
- pub fn intDiv(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intDivScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intDivScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3180,7 +3446,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_q.toConst());
}
- pub fn intDivFloor(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intDivFloor(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intDivFloorScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intDivFloorScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3205,7 +3482,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_q.toConst());
}
- pub fn intRem(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intRem(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intRemScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intRemScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3232,7 +3520,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_r.toConst());
}
- pub fn intMod(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intMod(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intModScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intModScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3270,6 +3569,17 @@ pub const Value = extern union {
}
pub fn floatRem(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatRemScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatRemScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatRemScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3304,6 +3614,17 @@ pub const Value = extern union {
}
pub fn floatMod(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatModScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatModScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatModScalar(lhs: Value, rhs: Value, float_type: Type, arena: Allocator, target: Target) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3337,7 +3658,18 @@ pub const Value = extern union {
}
}
- pub fn intMul(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn intMul(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intMulScalar(lhs, rhs, allocator);
+ }
+
+ pub fn intMulScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3358,7 +3690,32 @@ pub const Value = extern union {
return fromBigInt(allocator, result_bigint.toConst());
}
- pub fn intTrunc(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
+ pub fn intTrunc(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, bits);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intTruncScalar(val, allocator, signedness, bits);
+ }
+
+ /// This variant may vectorize on `bits`. Asserts that `bits` is a (vector of) `u16`.
+ pub fn intTruncBitsAsValue(val: Value, ty: Type, allocator: Allocator, signedness: std.builtin.Signedness, bits: Value) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try intTruncScalar(val.indexVectorlike(i), allocator, signedness, @intCast(u16, bits.indexVectorlike(i).toUnsignedInt()));
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return intTruncScalar(val, allocator, signedness, @intCast(u16, bits.toUnsignedInt()));
+ }
+
+ pub fn intTruncScalar(val: Value, allocator: Allocator, signedness: std.builtin.Signedness, bits: u16) !Value {
+ if (bits == 0) return Value.zero;
+
var val_space: Value.BigIntSpace = undefined;
const val_bigint = val.toBigInt(&val_space);
@@ -3372,7 +3729,18 @@ pub const Value = extern union {
return fromBigInt(allocator, result_bigint.toConst());
}
- pub fn shl(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn shl(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try shlScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return shlScalar(lhs, rhs, allocator);
+ }
+
+ pub fn shlScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3429,6 +3797,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try shlSatScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return shlSatScalar(lhs, rhs, ty, arena, target);
+ }
+
+ pub fn shlSatScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
const info = ty.intInfo(target);
@@ -3456,13 +3841,41 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
- const shifted = try lhs.shl(rhs, arena);
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try shlTruncScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return shlTruncScalar(lhs, rhs, ty, arena, target);
+ }
+
+ pub fn shlTruncScalar(
+ lhs: Value,
+ rhs: Value,
+ ty: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
+ const shifted = try lhs.shl(rhs, ty, arena);
const int_info = ty.intInfo(target);
- const truncated = try shifted.intTrunc(arena, int_info.signedness, int_info.bits);
+ const truncated = try shifted.intTrunc(ty, arena, int_info.signedness, int_info.bits);
return truncated;
}
- pub fn shr(lhs: Value, rhs: Value, allocator: Allocator) !Value {
+ pub fn shr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator) !Value {
+ if (ty.zigTypeTag() == .Vector) {
+ const result_data = try allocator.alloc(Value, ty.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try shrScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator);
+ }
+ return Value.Tag.aggregate.create(allocator, result_data);
+ }
+ return shrScalar(lhs, rhs, allocator);
+ }
+
+ pub fn shrScalar(lhs: Value, rhs: Value, allocator: Allocator) !Value {
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
@@ -3496,6 +3909,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatAddScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatAddScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3533,6 +3963,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatSubScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatSubScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3570,6 +4017,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatDivScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatDivScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatDivScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3610,6 +4074,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatDivFloorScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatDivFloorScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatDivFloorScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3650,6 +4131,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatDivTruncScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatDivTruncScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatDivTruncScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3690,6 +4188,23 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) !Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floatMulScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floatMulScalar(lhs, rhs, float_type, arena, target);
+ }
+
+ pub fn floatMulScalar(
+ lhs: Value,
+ rhs: Value,
+ float_type: Type,
+ arena: Allocator,
+ target: Target,
+ ) !Value {
switch (float_type.floatBits(target)) {
16 => {
const lhs_val = lhs.toFloat(f16);
@@ -3724,6 +4239,17 @@ pub const Value = extern union {
}
pub fn sqrt(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try sqrtScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return sqrtScalar(val, float_type, arena, target);
+ }
+
+ pub fn sqrtScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3756,6 +4282,17 @@ pub const Value = extern union {
}
pub fn sin(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try sinScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return sinScalar(val, float_type, arena, target);
+ }
+
+ pub fn sinScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3788,6 +4325,17 @@ pub const Value = extern union {
}
pub fn cos(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try cosScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return cosScalar(val, float_type, arena, target);
+ }
+
+ pub fn cosScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3820,6 +4368,17 @@ pub const Value = extern union {
}
pub fn exp(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try expScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return expScalar(val, float_type, arena, target);
+ }
+
+ pub fn expScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3852,6 +4411,17 @@ pub const Value = extern union {
}
pub fn exp2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try exp2Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return exp2Scalar(val, float_type, arena, target);
+ }
+
+ pub fn exp2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3884,6 +4454,17 @@ pub const Value = extern union {
}
pub fn log(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try logScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return logScalar(val, float_type, arena, target);
+ }
+
+ pub fn logScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3916,6 +4497,17 @@ pub const Value = extern union {
}
pub fn log2(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try log2Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return log2Scalar(val, float_type, arena, target);
+ }
+
+ pub fn log2Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3948,6 +4540,17 @@ pub const Value = extern union {
}
pub fn log10(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try log10Scalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return log10Scalar(val, float_type, arena, target);
+ }
+
+ pub fn log10Scalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -3980,6 +4583,17 @@ pub const Value = extern union {
}
pub fn fabs(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try fabsScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return fabsScalar(val, float_type, arena, target);
+ }
+
+ pub fn fabsScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -4009,6 +4623,17 @@ pub const Value = extern union {
}
pub fn floor(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try floorScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return floorScalar(val, float_type, arena, target);
+ }
+
+ pub fn floorScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -4038,6 +4663,17 @@ pub const Value = extern union {
}
pub fn ceil(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try ceilScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return ceilScalar(val, float_type, arena, target);
+ }
+
+ pub fn ceilScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -4067,6 +4703,17 @@ pub const Value = extern union {
}
pub fn round(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try roundScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return roundScalar(val, float_type, arena, target);
+ }
+
+ pub fn roundScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -4096,6 +4743,17 @@ pub const Value = extern union {
}
pub fn trunc(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try truncScalar(val.indexVectorlike(i), float_type.scalarType(), arena, target);
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return truncScalar(val, float_type, arena, target);
+ }
+
+ pub fn truncScalar(val: Value, float_type: Type, arena: Allocator, target: Target) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const f = val.toFloat(f16);
@@ -4132,6 +4790,31 @@ pub const Value = extern union {
arena: Allocator,
target: Target,
) Allocator.Error!Value {
+ if (float_type.zigTypeTag() == .Vector) {
+ const result_data = try arena.alloc(Value, float_type.vectorLen());
+ for (result_data) |*scalar, i| {
+ scalar.* = try mulAddScalar(
+ float_type.scalarType(),
+ mulend1.indexVectorlike(i),
+ mulend2.indexVectorlike(i),
+ addend.indexVectorlike(i),
+ arena,
+ target,
+ );
+ }
+ return Value.Tag.aggregate.create(arena, result_data);
+ }
+ return mulAddScalar(float_type, mulend1, mulend2, addend, arena, target);
+ }
+
+ pub fn mulAddScalar(
+ float_type: Type,
+ mulend1: Value,
+ mulend2: Value,
+ addend: Value,
+ arena: Allocator,
+ target: Target,
+ ) Allocator.Error!Value {
switch (float_type.floatBits(target)) {
16 => {
const m1 = mulend1.toFloat(f16);