stage2: implement @setFloatMode

This commit is contained in:
Veikka Tuominen 2022-07-21 14:40:00 +03:00
parent 585c160c20
commit d75fa86d70
14 changed files with 494 additions and 122 deletions

View file

@ -813,6 +813,7 @@ test "conversion to f32" {
test "conversion to f80" { test "conversion to f80" {
if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64) if (builtin.zig_backend == .stage1 and builtin.cpu.arch != .x86_64)
return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408 return error.SkipZigTest; // https://github.com/ziglang/zig/issues/11408
if (std.debug.runtime_safety) return error.SkipZigTest;
const intToFloat = @import("./int_to_float.zig").intToFloat; const intToFloat = @import("./int_to_float.zig").intToFloat;

View file

@ -38,11 +38,15 @@ pub const Inst = struct {
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
add, add,
/// Same as `add` with optimized float mode.
add_optimized,
/// Integer addition. Wrapping is defined to be twos complement wrapping. /// Integer addition. Wrapping is defined to be twos complement wrapping.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
addwrap, addwrap,
/// Same as `addwrap` with optimized float mode.
addwrap_optimized,
/// Saturating integer addition. /// Saturating integer addition.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
@ -53,11 +57,15 @@ pub const Inst = struct {
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
sub, sub,
/// Same as `sub` with optimized float mode.
sub_optimized,
/// Integer subtraction. Wrapping is defined to be twos complement wrapping. /// Integer subtraction. Wrapping is defined to be twos complement wrapping.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
subwrap, subwrap,
/// Same as `sub` with optimized float mode.
subwrap_optimized,
/// Saturating integer subtraction. /// Saturating integer subtraction.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
@ -68,11 +76,15 @@ pub const Inst = struct {
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
mul, mul,
/// Same as `mul` with optimized float mode.
mul_optimized,
/// Integer multiplication. Wrapping is defined to be twos complement wrapping. /// Integer multiplication. Wrapping is defined to be twos complement wrapping.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
mulwrap, mulwrap,
/// Same as `mulwrap` with optimized float mode.
mulwrap_optimized,
/// Saturating integer multiplication. /// Saturating integer multiplication.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
@ -83,32 +95,44 @@ pub const Inst = struct {
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
div_float, div_float,
/// Same as `div_float` with optimized float mode.
div_float_optimized,
/// Truncating integer or float division. For integers, wrapping is undefined behavior. /// Truncating integer or float division. For integers, wrapping is undefined behavior.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
div_trunc, div_trunc,
/// Same as `div_trunc` with optimized float mode.
div_trunc_optimized,
/// Flooring integer or float division. For integers, wrapping is undefined behavior. /// Flooring integer or float division. For integers, wrapping is undefined behavior.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
div_floor, div_floor,
/// Same as `div_floor` with optimized float mode.
div_floor_optimized,
/// Integer or float division. Guaranteed no remainder. /// Integer or float division. Guaranteed no remainder.
/// For integers, wrapping is undefined behavior. /// For integers, wrapping is undefined behavior.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
div_exact, div_exact,
/// Same as `div_exact` with optimized float mode.
div_exact_optimized,
/// Integer or float remainder division. /// Integer or float remainder division.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
rem, rem,
/// Same as `rem` with optimized float mode.
rem_optimized,
/// Integer or float modulus division. /// Integer or float modulus division.
/// Both operands are guaranteed to be the same type, and the result type /// Both operands are guaranteed to be the same type, and the result type
/// is the same as both operands. /// is the same as both operands.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
mod, mod,
/// Same as `mod` with optimized float mode.
mod_optimized,
/// Add an offset to a pointer, returning a new pointer. /// Add an offset to a pointer, returning a new pointer.
/// The offset is in element type units, not bytes. /// The offset is in element type units, not bytes.
/// Wrapping is undefined behavior. /// Wrapping is undefined behavior.
@ -293,29 +317,45 @@ pub const Inst = struct {
/// LHS of zero. /// LHS of zero.
/// Uses the `un_op` field. /// Uses the `un_op` field.
neg, neg,
/// Same as `neg` with optimized float mode.
neg_optimized,
/// `<`. Result type is always bool. /// `<`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_lt, cmp_lt,
/// Same as `cmp_lt` with optimized float mode.
cmp_lt_optimized,
/// `<=`. Result type is always bool. /// `<=`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_lte, cmp_lte,
/// Same as `cmp_lte` with optimized float mode.
cmp_lte_optimized,
/// `==`. Result type is always bool. /// `==`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_eq, cmp_eq,
/// Same as `cmp_eq` with optimized float mode.
cmp_eq_optimized,
/// `>=`. Result type is always bool. /// `>=`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_gte, cmp_gte,
/// Same as `cmp_gte` with optimized float mode.
cmp_gte_optimized,
/// `>`. Result type is always bool. /// `>`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_gt, cmp_gt,
/// Same as `cmp_gt` with optimized float mode.
cmp_gt_optimized,
/// `!=`. Result type is always bool. /// `!=`. Result type is always bool.
/// Uses the `bin_op` field. /// Uses the `bin_op` field.
cmp_neq, cmp_neq,
/// Same as `cmp_neq` with optimized float mode.
cmp_neq_optimized,
/// Conditional between two vectors. /// Conditional between two vectors.
/// Result type is always a vector of bools. /// Result type is always a vector of bools.
/// Uses the `ty_pl` field, payload is `VectorCmp`. /// Uses the `ty_pl` field, payload is `VectorCmp`.
cmp_vector, cmp_vector,
/// Same as `cmp_vector` with optimized float mode.
cmp_vector_optimized,
/// Conditional branch. /// Conditional branch.
/// Result type is always noreturn; no instructions in a block follow this one. /// Result type is always noreturn; no instructions in a block follow this one.
@ -553,6 +593,8 @@ pub const Inst = struct {
/// Given a float operand, return the integer with the closest mathematical meaning. /// Given a float operand, return the integer with the closest mathematical meaning.
/// Uses the `ty_op` field. /// Uses the `ty_op` field.
float_to_int, float_to_int,
/// Same as `float_to_int` with optimized float mode.
float_to_int_optimized,
/// Given an integer operand, return the float with the closest mathematical meaning. /// Given an integer operand, return the float with the closest mathematical meaning.
/// Uses the `ty_op` field. /// Uses the `ty_op` field.
int_to_float, int_to_float,
@ -564,6 +606,8 @@ pub const Inst = struct {
/// * min, max, add, mul => integer or float /// * min, max, add, mul => integer or float
/// Uses the `reduce` field. /// Uses the `reduce` field.
reduce, reduce,
/// Same as `reduce` with optimized float mode.
reduce_optimized,
/// Given an integer, bool, float, or pointer operand, return a vector with all elements /// Given an integer, bool, float, or pointer operand, return a vector with all elements
/// equal to the scalar value. /// equal to the scalar value.
/// Uses the `ty_op` field. /// Uses the `ty_op` field.
@ -676,25 +720,25 @@ pub const Inst = struct {
/// Sets the operand as the current error return trace, /// Sets the operand as the current error return trace,
set_err_return_trace, set_err_return_trace,
pub fn fromCmpOp(op: std.math.CompareOperator) Tag { pub fn fromCmpOp(op: std.math.CompareOperator, optimized: bool) Tag {
return switch (op) { switch (op) {
.lt => .cmp_lt, .lt => return if (optimized) .cmp_lt_optimized else .cmp_lt,
.lte => .cmp_lte, .lte => return if (optimized) .cmp_lte_optimized else .cmp_lte,
.eq => .cmp_eq, .eq => return if (optimized) .cmp_eq_optimized else .cmp_eq,
.gte => .cmp_gte, .gte => return if (optimized) .cmp_gte_optimized else .cmp_gte,
.gt => .cmp_gt, .gt => return if (optimized) .cmp_gt_optimized else .cmp_gt,
.neq => .cmp_neq, .neq => return if (optimized) .cmp_neq_optimized else .cmp_neq,
}; }
} }
pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator { pub fn toCmpOp(tag: Tag) ?std.math.CompareOperator {
return switch (tag) { return switch (tag) {
.cmp_lt => .lt, .cmp_lt, .cmp_lt_optimized => .lt,
.cmp_lte => .lte, .cmp_lte, .cmp_lte_optimized => .lte,
.cmp_eq => .eq, .cmp_eq, .cmp_eq_optimized => .eq,
.cmp_gte => .gte, .cmp_gte, .cmp_gte_optimized => .gte,
.cmp_gt => .gt, .cmp_gt, .cmp_gt_optimized => .gt,
.cmp_neq => .neq, .cmp_neq, .cmp_neq_optimized => .neq,
else => null, else => null,
}; };
} }
@ -959,6 +1003,18 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.max, .max,
.bool_and, .bool_and,
.bool_or, .bool_or,
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
=> return air.typeOf(datas[inst].bin_op.lhs), => return air.typeOf(datas[inst].bin_op.lhs),
.sqrt, .sqrt,
@ -976,6 +1032,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.round, .round,
.trunc_float, .trunc_float,
.neg, .neg,
.neg_optimized,
=> return air.typeOf(datas[inst].un_op), => return air.typeOf(datas[inst].un_op),
.cmp_lt, .cmp_lt,
@ -984,6 +1041,12 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.cmp_gte, .cmp_gte,
.cmp_gt, .cmp_gt,
.cmp_neq, .cmp_neq,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_lt_errors_len, .cmp_lt_errors_len,
.is_null, .is_null,
.is_non_null, .is_non_null,
@ -1018,6 +1081,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.union_init, .union_init,
.field_parent_ptr, .field_parent_ptr,
.cmp_vector, .cmp_vector,
.cmp_vector_optimized,
.add_with_overflow, .add_with_overflow,
.sub_with_overflow, .sub_with_overflow,
.mul_with_overflow, .mul_with_overflow,
@ -1054,6 +1118,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.struct_field_ptr_index_3, .struct_field_ptr_index_3,
.array_to_slice, .array_to_slice,
.float_to_int, .float_to_int,
.float_to_int_optimized,
.int_to_float, .int_to_float,
.splat, .splat,
.get_union_tag, .get_union_tag,
@ -1129,7 +1194,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
return ptr_ty.elemType(); return ptr_ty.elemType();
}, },
.reduce => return air.typeOf(datas[inst].reduce.operand).childType(), .reduce, .reduce_optimized => return air.typeOf(datas[inst].reduce.operand).childType(),
.mul_add => return air.typeOf(datas[inst].pl_op.operand), .mul_add => return air.typeOf(datas[inst].pl_op.operand),
.select => { .select => {

View file

@ -173,6 +173,25 @@ pub fn categorizeOperand(
.shr_exact, .shr_exact,
.min, .min,
.max, .max,
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
=> { => {
const o = air_datas[inst].bin_op; const o = air_datas[inst].bin_op;
if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
@ -239,6 +258,7 @@ pub fn categorizeOperand(
.struct_field_ptr_index_3, .struct_field_ptr_index_3,
.array_to_slice, .array_to_slice,
.float_to_int, .float_to_int,
.float_to_int_optimized,
.int_to_float, .int_to_float,
.get_union_tag, .get_union_tag,
.clz, .clz,
@ -381,12 +401,12 @@ pub fn categorizeOperand(
if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); if (extra.b == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
return .none; return .none;
}, },
.reduce => { .reduce, .reduce_optimized => {
const reduce = air_datas[inst].reduce; const reduce = air_datas[inst].reduce;
if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); if (reduce.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
return .none; return .none;
}, },
.cmp_vector => { .cmp_vector, .cmp_vector_optimized => {
const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data; const extra = air.extraData(Air.VectorCmp, air_datas[inst].ty_pl.payload).data;
if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none); if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .none);
if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none); if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .none);
@ -701,29 +721,47 @@ fn analyzeInst(
switch (inst_tags[inst]) { switch (inst_tags[inst]) {
.add, .add,
.add_optimized,
.addwrap, .addwrap,
.addwrap_optimized,
.add_sat, .add_sat,
.sub, .sub,
.sub_optimized,
.subwrap, .subwrap,
.subwrap_optimized,
.sub_sat, .sub_sat,
.mul, .mul,
.mul_optimized,
.mulwrap, .mulwrap,
.mulwrap_optimized,
.mul_sat, .mul_sat,
.div_float, .div_float,
.div_float_optimized,
.div_trunc, .div_trunc,
.div_trunc_optimized,
.div_floor, .div_floor,
.div_floor_optimized,
.div_exact, .div_exact,
.div_exact_optimized,
.rem, .rem,
.rem_optimized,
.mod, .mod,
.mod_optimized,
.bit_and, .bit_and,
.bit_or, .bit_or,
.xor, .xor,
.cmp_lt, .cmp_lt,
.cmp_lt_optimized,
.cmp_lte, .cmp_lte,
.cmp_lte_optimized,
.cmp_eq, .cmp_eq,
.cmp_eq_optimized,
.cmp_gte, .cmp_gte,
.cmp_gte_optimized,
.cmp_gt, .cmp_gt,
.cmp_gt_optimized,
.cmp_neq, .cmp_neq,
.cmp_neq_optimized,
.bool_and, .bool_and,
.bool_or, .bool_or,
.store, .store,
@ -794,6 +832,7 @@ fn analyzeInst(
.struct_field_ptr_index_3, .struct_field_ptr_index_3,
.array_to_slice, .array_to_slice,
.float_to_int, .float_to_int,
.float_to_int_optimized,
.int_to_float, .int_to_float,
.get_union_tag, .get_union_tag,
.clz, .clz,
@ -836,6 +875,7 @@ fn analyzeInst(
.round, .round,
.trunc_float, .trunc_float,
.neg, .neg,
.neg_optimized,
.cmp_lt_errors_len, .cmp_lt_errors_len,
.set_err_return_trace, .set_err_return_trace,
=> { => {
@ -903,11 +943,11 @@ fn analyzeInst(
const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data; const extra = a.air.extraData(Air.Shuffle, inst_datas[inst].ty_pl.payload).data;
return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none }); return trackOperands(a, new_set, inst, main_tomb, .{ extra.a, extra.b, .none });
}, },
.reduce => { .reduce, .reduce_optimized => {
const reduce = inst_datas[inst].reduce; const reduce = inst_datas[inst].reduce;
return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none }); return trackOperands(a, new_set, inst, main_tomb, .{ reduce.operand, .none, .none });
}, },
.cmp_vector => { .cmp_vector, .cmp_vector_optimized => {
const extra = a.air.extraData(Air.VectorCmp, inst_datas[inst].ty_pl.payload).data; 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 }); return trackOperands(a, new_set, inst, main_tomb, .{ extra.lhs, extra.rhs, .none });
}, },

View file

@ -144,6 +144,9 @@ pub const Block = struct {
/// when null, it is determined by build mode, changed by @setRuntimeSafety /// when null, it is determined by build mode, changed by @setRuntimeSafety
want_safety: ?bool = null, want_safety: ?bool = null,
/// What mode to generate float operations in, set by @setFloatMode
float_mode: std.builtin.FloatMode = .Strict,
c_import_buf: ?*std.ArrayList(u8) = null, c_import_buf: ?*std.ArrayList(u8) = null,
/// type of `err` in `else => |err|` /// type of `err` in `else => |err|`
@ -206,6 +209,7 @@ pub const Block = struct {
.runtime_loop = parent.runtime_loop, .runtime_loop = parent.runtime_loop,
.runtime_index = parent.runtime_index, .runtime_index = parent.runtime_index,
.want_safety = parent.want_safety, .want_safety = parent.want_safety,
.float_mode = parent.float_mode,
.c_import_buf = parent.c_import_buf, .c_import_buf = parent.c_import_buf,
.switch_else_err_ty = parent.switch_else_err_ty, .switch_else_err_ty = parent.switch_else_err_ty,
}; };
@ -414,7 +418,7 @@ 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 { 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(.{ return block.addInst(.{
.tag = .cmp_vector, .tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
.data = .{ .ty_pl = .{ .data = .{ .ty_pl = .{
.ty = vector_ty, .ty = vector_ty,
.payload = try block.sema.addExtra(Air.VectorCmp{ .payload = try block.sema.addExtra(Air.VectorCmp{
@ -714,10 +718,10 @@ fn analyzeBodyInner(
.closure_get => try sema.zirClosureGet(block, inst), .closure_get => try sema.zirClosureGet(block, inst),
.cmp_lt => try sema.zirCmp(block, inst, .lt), .cmp_lt => try sema.zirCmp(block, inst, .lt),
.cmp_lte => try sema.zirCmp(block, inst, .lte), .cmp_lte => try sema.zirCmp(block, inst, .lte),
.cmp_eq => try sema.zirCmpEq(block, inst, .eq, .cmp_eq), .cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
.cmp_gte => try sema.zirCmp(block, inst, .gte), .cmp_gte => try sema.zirCmp(block, inst, .gte),
.cmp_gt => try sema.zirCmp(block, inst, .gt), .cmp_gt => try sema.zirCmp(block, inst, .gt),
.cmp_neq => try sema.zirCmpEq(block, inst, .neq, .cmp_neq), .cmp_neq => try sema.zirCmpEq(block, inst, .neq, Air.Inst.Tag.fromCmpOp(.neq, block.float_mode == .Optimized)),
.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
.decl_ref => try sema.zirDeclRef(block, inst), .decl_ref => try sema.zirDeclRef(block, inst),
.decl_val => try sema.zirDeclVal(block, inst), .decl_val => try sema.zirDeclVal(block, inst),
@ -4705,6 +4709,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
.inlining = parent_block.inlining, .inlining = parent_block.inlining,
.is_comptime = parent_block.is_comptime, .is_comptime = parent_block.is_comptime,
.want_safety = parent_block.want_safety, .want_safety = parent_block.want_safety,
.float_mode = parent_block.float_mode,
}; };
defer child_block.instructions.deinit(gpa); defer child_block.instructions.deinit(gpa);
@ -5042,13 +5047,7 @@ fn zirSetCold(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known"); block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", "operand to @setFloatMode must be comptime known");
switch (float_mode) {
.Strict => return,
.Optimized => {
// TODO implement optimized float mode
},
}
} }
fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@ -8092,7 +8091,7 @@ fn intCast(
const ok = if (is_vector) ok: { const ok = if (is_vector) ok: {
const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty)); const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte, try sema.addType(operand_ty));
const all_in_range = try block.addInst(.{ const all_in_range = try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = is_in_range, .operand = is_in_range,
.operation = .And, .operation = .And,
@ -8109,7 +8108,7 @@ fn intCast(
const ok = if (is_vector) ok: { const ok = if (is_vector) ok: {
const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty)); const is_in_range = try block.addCmpVector(diff, dest_max, .lte, try sema.addType(operand_ty));
const all_in_range = try block.addInst(.{ const all_in_range = try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = is_in_range, .operand = is_in_range,
.operation = .And, .operation = .And,
@ -8130,7 +8129,7 @@ fn intCast(
const zero_inst = try sema.addConstant(operand_ty, zero_val); const zero_inst = try sema.addConstant(operand_ty, zero_val);
const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty)); const is_in_range = try block.addCmpVector(operand, zero_inst, .gte, try sema.addType(operand_ty));
const all_in_range = try block.addInst(.{ const all_in_range = try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = is_in_range, .operand = is_in_range,
.operation = .And, .operation = .And,
@ -9391,7 +9390,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
} else { } else {
for (items) |item_ref| { for (items) |item_ref| {
const item = try sema.resolveInst(item_ref); const item = try sema.resolveInst(item_ref);
const cmp_ok = try case_block.addBinOp(.cmp_eq, operand, item); const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
if (any_ok != .none) { if (any_ok != .none) {
any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok); any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
} else { } else {
@ -9411,12 +9410,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
// operand >= first and operand <= last // operand >= first and operand <= last
const range_first_ok = try case_block.addBinOp( const range_first_ok = try case_block.addBinOp(
.cmp_gte, if (case_block.float_mode == .Optimized) .cmp_gte_optimized else .cmp_gte,
operand, operand,
item_first, item_first,
); );
const range_last_ok = try case_block.addBinOp( const range_last_ok = try case_block.addBinOp(
.cmp_lte, if (case_block.float_mode == .Optimized) .cmp_lte_optimized else .cmp_lte,
operand, operand,
item_last, item_last,
); );
@ -10023,7 +10022,7 @@ fn zirShl(
const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector) const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
try block.addInst(.{ try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = ov_bit, .operand = ov_bit,
.operation = .Or, .operation = .Or,
@ -10120,7 +10119,7 @@ fn zirShr(
const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: { const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty)); const eql = try block.addCmpVector(lhs, back, .eq, try sema.addType(rhs_ty));
break :ok try block.addInst(.{ break :ok try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = eql, .operand = eql,
.operation = .And, .operation = .And,
@ -10719,7 +10718,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target)); return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, target));
} }
try sema.requireRuntimeBlock(block, src, null); try sema.requireRuntimeBlock(block, src, null);
return block.addUnOp(.neg, rhs); return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs);
} }
const lhs = if (rhs_ty.zigTypeTag() == .Vector) const lhs = if (rhs_ty.zigTypeTag() == .Vector)
@ -11078,6 +11077,7 @@ fn analyzeArithmetic(
return casted_lhs; return casted_lhs;
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
if (is_int) { if (is_int) {
@ -11100,8 +11100,8 @@ fn analyzeArithmetic(
try sema.floatAdd(lhs_val, rhs_val, resolved_type), try sema.floatAdd(lhs_val, rhs_val, resolved_type),
); );
} }
} else break :rs .{ .src = rhs_src, .air_tag = .add }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .add }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.addwrap => { .addwrap => {
// Integers only; floats are checked above. // Integers only; floats are checked above.
@ -11112,6 +11112,7 @@ fn analyzeArithmetic(
return casted_rhs; return casted_rhs;
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
if (maybe_rhs_val) |rhs_val| { if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) { if (rhs_val.isUndef()) {
return sema.addConstUndef(resolved_type); return sema.addConstUndef(resolved_type);
@ -11124,8 +11125,8 @@ fn analyzeArithmetic(
resolved_type, resolved_type,
try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type), try sema.numberAddWrap(block, src, lhs_val, rhs_val, resolved_type),
); );
} else break :rs .{ .src = lhs_src, .air_tag = .addwrap }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
} else break :rs .{ .src = rhs_src, .air_tag = .addwrap }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
}, },
.add_sat => { .add_sat => {
// Integers only; floats are checked above. // Integers only; floats are checked above.
@ -11173,6 +11174,7 @@ fn analyzeArithmetic(
return casted_lhs; return casted_lhs;
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
if (is_int) { if (is_int) {
@ -11195,8 +11197,8 @@ fn analyzeArithmetic(
try sema.floatSub(lhs_val, rhs_val, resolved_type), try sema.floatSub(lhs_val, rhs_val, resolved_type),
); );
} }
} else break :rs .{ .src = rhs_src, .air_tag = .sub }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .sub }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.subwrap => { .subwrap => {
// Integers only; floats are checked above. // Integers only; floats are checked above.
@ -11210,6 +11212,7 @@ fn analyzeArithmetic(
return casted_lhs; return casted_lhs;
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
return sema.addConstUndef(resolved_type); return sema.addConstUndef(resolved_type);
@ -11219,8 +11222,8 @@ fn analyzeArithmetic(
resolved_type, resolved_type,
try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type), try sema.numberSubWrap(block, src, lhs_val, rhs_val, resolved_type),
); );
} else break :rs .{ .src = rhs_src, .air_tag = .subwrap }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .subwrap }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.sub_sat => { .sub_sat => {
// Integers only; floats are checked above. // Integers only; floats are checked above.
@ -11327,14 +11330,14 @@ fn analyzeArithmetic(
if (is_int) { if (is_int) {
break :rs .{ .src = rhs_src, .air_tag = .div_trunc }; break :rs .{ .src = rhs_src, .air_tag = .div_trunc };
} else { } else {
break :rs .{ .src = rhs_src, .air_tag = .div_float }; break :rs .{ .src = rhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float };
} }
} }
} else { } else {
if (is_int) { if (is_int) {
break :rs .{ .src = lhs_src, .air_tag = .div_trunc }; break :rs .{ .src = lhs_src, .air_tag = .div_trunc };
} else { } else {
break :rs .{ .src = lhs_src, .air_tag = .div_float }; break :rs .{ .src = lhs_src, .air_tag = if (block.float_mode == .Optimized) .div_float_optimized else .div_float };
} }
} }
}, },
@ -11373,6 +11376,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src); return sema.failWithDivideByZero(block, rhs_src);
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_trunc_optimized else .div_trunc;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
@ -11398,8 +11402,8 @@ fn analyzeArithmetic(
try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatDivTrunc(rhs_val, resolved_type, sema.arena, target),
); );
} }
} else break :rs .{ .src = rhs_src, .air_tag = .div_trunc }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .div_trunc }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.div_floor => { .div_floor => {
// For integers: // For integers:
@ -11436,6 +11440,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src); return sema.failWithDivideByZero(block, rhs_src);
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_floor_optimized else .div_floor;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) { if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
@ -11461,8 +11466,8 @@ fn analyzeArithmetic(
try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatDivFloor(rhs_val, resolved_type, sema.arena, target),
); );
} }
} else break :rs .{ .src = rhs_src, .air_tag = .div_floor }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .div_floor }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.div_exact => { .div_exact => {
// For integers: // For integers:
@ -11498,6 +11503,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src); return sema.failWithDivideByZero(block, rhs_src);
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .div_exact_optimized else .div_exact;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (maybe_rhs_val) |rhs_val| { if (maybe_rhs_val) |rhs_val| {
if (is_int) { if (is_int) {
@ -11513,8 +11519,8 @@ fn analyzeArithmetic(
try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatDiv(rhs_val, resolved_type, sema.arena, target),
); );
} }
} else break :rs .{ .src = rhs_src, .air_tag = .div_exact }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .div_exact }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.mul => { .mul => {
// For integers: // For integers:
@ -11535,6 +11541,7 @@ fn analyzeArithmetic(
} }
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
if (maybe_rhs_val) |rhs_val| { if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) { if (rhs_val.isUndef()) {
if (is_int) { if (is_int) {
@ -11570,8 +11577,8 @@ fn analyzeArithmetic(
try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, target),
); );
} }
} else break :rs .{ .src = lhs_src, .air_tag = .mul }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
} else break :rs .{ .src = rhs_src, .air_tag = .mul }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
}, },
.mulwrap => { .mulwrap => {
// Integers only; floats are handled above. // Integers only; floats are handled above.
@ -11588,6 +11595,7 @@ fn analyzeArithmetic(
} }
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
if (maybe_rhs_val) |rhs_val| { if (maybe_rhs_val) |rhs_val| {
if (rhs_val.isUndef()) { if (rhs_val.isUndef()) {
return sema.addConstUndef(resolved_type); return sema.addConstUndef(resolved_type);
@ -11606,8 +11614,8 @@ fn analyzeArithmetic(
resolved_type, resolved_type,
try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target), try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, target),
); );
} else break :rs .{ .src = lhs_src, .air_tag = .mulwrap }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
} else break :rs .{ .src = rhs_src, .air_tag = .mulwrap }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
}, },
.mul_sat => { .mul_sat => {
// Integers only; floats are checked above. // Integers only; floats are checked above.
@ -11777,6 +11785,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src); return sema.failWithDivideByZero(block, rhs_src);
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .rem_optimized else .rem;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
return sema.addConstUndef(resolved_type); return sema.addConstUndef(resolved_type);
@ -11786,8 +11795,8 @@ fn analyzeArithmetic(
resolved_type, resolved_type,
try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target),
); );
} else break :rs .{ .src = rhs_src, .air_tag = .rem }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .rem }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
.mod => { .mod => {
// For integers: // For integers:
@ -11834,6 +11843,7 @@ fn analyzeArithmetic(
return sema.failWithDivideByZero(block, rhs_src); return sema.failWithDivideByZero(block, rhs_src);
} }
} }
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mod_optimized else .mod;
if (maybe_lhs_val) |lhs_val| { if (maybe_lhs_val) |lhs_val| {
if (lhs_val.isUndef()) { if (lhs_val.isUndef()) {
return sema.addConstUndef(resolved_type); return sema.addConstUndef(resolved_type);
@ -11843,8 +11853,8 @@ fn analyzeArithmetic(
resolved_type, resolved_type,
try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target), try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target),
); );
} else break :rs .{ .src = rhs_src, .air_tag = .mod }; } else break :rs .{ .src = rhs_src, .air_tag = air_tag };
} else break :rs .{ .src = lhs_src, .air_tag = .mod }; } else break :rs .{ .src = lhs_src, .air_tag = air_tag };
}, },
else => unreachable, else => unreachable,
} }
@ -11874,7 +11884,7 @@ fn analyzeArithmetic(
const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty); const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector) const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)
try block.addInst(.{ try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = ov_bit, .operand = ov_bit,
.operation = .Or, .operation = .Or,
@ -11890,13 +11900,17 @@ fn analyzeArithmetic(
} }
} }
switch (rs.air_tag) { switch (rs.air_tag) {
.div_float, .div_exact, .div_trunc, .div_floor => { // zig fmt: off
.div_float, .div_exact, .div_trunc, .div_floor, .div_float_optimized,
.div_exact_optimized, .div_trunc_optimized, .div_floor_optimized
// zig fmt: on
=> if (scalar_tag == .Int or block.float_mode == .Optimized) {
const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val); const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type)); const ok = try block.addCmpVector(casted_rhs, zero, .neq, try sema.addType(resolved_type));
break :ok try block.addInst(.{ break :ok try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = ok, .operand = ok,
.operation = .And, .operation = .And,
@ -11904,17 +11918,17 @@ fn analyzeArithmetic(
}); });
} else ok: { } else ok: {
const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
break :ok try block.addBinOp(.cmp_neq, casted_rhs, zero); break :ok try block.addBinOp(if (block.float_mode == .Optimized) .cmp_neq_optimized else .cmp_neq, casted_rhs, zero);
}; };
try sema.addSafetyCheck(block, ok, .divide_by_zero); try sema.addSafetyCheck(block, ok, .divide_by_zero);
}, },
.rem, .mod => { .rem, .mod, .rem_optimized, .mod_optimized => {
const ok = if (resolved_type.zigTypeTag() == .Vector) ok: { const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero); const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val); const zero = try sema.addConstant(sema.typeOf(casted_rhs), zero_val);
const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type)); const ok = try block.addCmpVector(casted_rhs, zero, if (scalar_tag == .Int) .gt else .neq, try sema.addType(resolved_type));
break :ok try block.addInst(.{ break :ok try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = ok, .operand = ok,
.operation = .And, .operation = .And,
@ -11922,13 +11936,19 @@ fn analyzeArithmetic(
}); });
} else ok: { } else ok: {
const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
break :ok try block.addBinOp(if (scalar_tag == .Int) .cmp_gt else .cmp_neq, casted_rhs, zero); const air_tag = if (scalar_tag == .Int)
Air.Inst.Tag.cmp_gt
else if (block.float_mode == .Optimized)
Air.Inst.Tag.cmp_neq_optimized
else
Air.Inst.Tag.cmp_neq;
break :ok try block.addBinOp(air_tag, casted_rhs, zero);
}; };
try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative); try sema.addSafetyCheck(block, ok, .remainder_division_zero_negative);
}, },
else => {}, else => {},
} }
if (rs.air_tag == .div_exact) { if (rs.air_tag == .div_exact or rs.air_tag == .div_exact_optimized) {
const result = try block.addBinOp(.div_exact, casted_lhs, casted_rhs); const result = try block.addBinOp(.div_exact, casted_lhs, casted_rhs);
const ok = if (scalar_tag == .Float) ok: { const ok = if (scalar_tag == .Float) ok: {
const floored = try block.addUnOp(.floor, result); const floored = try block.addUnOp(.floor, result);
@ -11936,14 +11956,14 @@ fn analyzeArithmetic(
if (resolved_type.zigTypeTag() == .Vector) { if (resolved_type.zigTypeTag() == .Vector) {
const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type)); const eql = try block.addCmpVector(result, floored, .eq, try sema.addType(resolved_type));
break :ok try block.addInst(.{ break :ok try block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = eql, .operand = eql,
.operation = .And, .operation = .And,
} }, } },
}); });
} else { } else {
const is_in_range = try block.addBinOp(.cmp_eq, result, floored); const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, result, floored);
break :ok is_in_range; break :ok is_in_range;
} }
} else ok: { } else ok: {
@ -11962,7 +11982,7 @@ fn analyzeArithmetic(
}); });
} else { } else {
const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero); const zero = try sema.addConstant(sema.typeOf(casted_rhs), Value.zero);
const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero); const is_in_range = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, remainder, zero);
break :ok is_in_range; break :ok is_in_range;
} }
}; };
@ -12476,7 +12496,7 @@ fn cmpSelf(
const result_ty_ref = try sema.addType(result_ty); const result_ty_ref = try sema.addType(result_ty);
return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref); return block.addCmpVector(casted_lhs, casted_rhs, op, result_ty_ref);
} }
const tag = Air.Inst.Tag.fromCmpOp(op); const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
return block.addBinOp(tag, casted_lhs, casted_rhs); return block.addBinOp(tag, casted_lhs, casted_rhs);
} }
@ -15954,12 +15974,12 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
} }
try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
const result = try block.addTyOp(.float_to_int, dest_ty, operand); const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
if (block.wantSafety()) { if (block.wantSafety()) {
const back = try block.addTyOp(.int_to_float, operand_ty, result); const back = try block.addTyOp(.int_to_float, operand_ty, result);
const diff = try block.addBinOp(.sub, operand, back); const diff = try block.addBinOp(.sub, operand, back);
const ok_pos = try block.addBinOp(.cmp_lt, diff, try sema.addConstant(operand_ty, Value.one)); const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one));
const ok_neg = try block.addBinOp(.cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one)); const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one));
const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg); const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds); try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
} }
@ -17194,7 +17214,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
try sema.requireRuntimeBlock(block, inst_data.src(), operand_src); try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
return block.addInst(.{ return block.addInst(.{
.tag = .reduce, .tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{ .data = .{ .reduce = .{
.operand = operand, .operand = operand,
.operation = operation, .operation = operation,
@ -24489,7 +24509,7 @@ fn cmpNumeric(
}; };
const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs); return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
} }
// For mixed unsigned integer sizes, implicit cast both operands to the larger integer. // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
// For mixed signed and unsigned integers, implicit cast both operands to a signed // For mixed signed and unsigned integers, implicit cast both operands to a signed
@ -24610,7 +24630,7 @@ fn cmpNumeric(
const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src); const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src); const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
return block.addBinOp(Air.Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs); return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
} }
/// Asserts that lhs and rhs types are both vectors. /// Asserts that lhs and rhs types are both vectors.

View file

@ -729,6 +729,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
.wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return self.fail("TODO implement optimized float mode", .{}),
.wasm_memory_size => unreachable, .wasm_memory_size => unreachable,
.wasm_memory_grow => unreachable, .wasm_memory_grow => unreachable,
// zig fmt: on // zig fmt: on

View file

@ -744,6 +744,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
.wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return self.fail("TODO implement optimized float mode", .{}),
.wasm_memory_size => unreachable, .wasm_memory_size => unreachable,
.wasm_memory_grow => unreachable, .wasm_memory_grow => unreachable,
// zig fmt: on // zig fmt: on

View file

@ -669,6 +669,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
.wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return self.fail("TODO implement optimized float mode", .{}),
.wasm_memory_size => unreachable, .wasm_memory_size => unreachable,
.wasm_memory_grow => unreachable, .wasm_memory_grow => unreachable,
// zig fmt: on // zig fmt: on

View file

@ -681,6 +681,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"), .wrap_errunion_payload => @panic("TODO try self.airWrapErrUnionPayload(inst)"),
.wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> @panic("TODO implement optimized float mode"),
.wasm_memory_size => unreachable, .wasm_memory_size => unreachable,
.wasm_memory_grow => unreachable, .wasm_memory_grow => unreachable,
// zig fmt: on // zig fmt: on

View file

@ -1622,6 +1622,30 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.err_return_trace, .err_return_trace,
.set_err_return_trace, .set_err_return_trace,
=> |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}), => |tag| return self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return self.fail("TODO implement optimized float mode", .{}),
}; };
} }

View file

@ -751,6 +751,30 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
.wrap_errunion_err => try self.airWrapErrUnionErr(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return self.fail("TODO implement optimized float mode", .{}),
.wasm_memory_size => unreachable, .wasm_memory_size => unreachable,
.wasm_memory_grow => unreachable, .wasm_memory_grow => unreachable,
// zig fmt: on // zig fmt: on

View file

@ -1928,6 +1928,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.wasm_memory_size => try airWasmMemorySize(f, inst), .wasm_memory_size => try airWasmMemorySize(f, inst),
.wasm_memory_grow => try airWasmMemoryGrow(f, inst), .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.neg_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
.cmp_vector_optimized,
.reduce_optimized,
.float_to_int_optimized,
=> return f.fail("TODO implement optimized float mode", .{}),
// zig fmt: on // zig fmt: on
}; };
switch (result_value) { switch (result_value) {

View file

@ -3984,21 +3984,21 @@ pub const FuncGen = struct {
for (body) |inst, i| { for (body) |inst, i| {
const opt_value: ?*const llvm.Value = switch (air_tags[inst]) { const opt_value: ?*const llvm.Value = switch (air_tags[inst]) {
// zig fmt: off // zig fmt: off
.add => try self.airAdd(inst), .add => try self.airAdd(inst, false),
.addwrap => try self.airAddWrap(inst), .addwrap => try self.airAddWrap(inst, false),
.add_sat => try self.airAddSat(inst), .add_sat => try self.airAddSat(inst),
.sub => try self.airSub(inst), .sub => try self.airSub(inst, false),
.subwrap => try self.airSubWrap(inst), .subwrap => try self.airSubWrap(inst, false),
.sub_sat => try self.airSubSat(inst), .sub_sat => try self.airSubSat(inst),
.mul => try self.airMul(inst), .mul => try self.airMul(inst, false),
.mulwrap => try self.airMulWrap(inst), .mulwrap => try self.airMulWrap(inst, false),
.mul_sat => try self.airMulSat(inst), .mul_sat => try self.airMulSat(inst),
.div_float => try self.airDivFloat(inst), .div_float => try self.airDivFloat(inst, false),
.div_trunc => try self.airDivTrunc(inst), .div_trunc => try self.airDivTrunc(inst, false),
.div_floor => try self.airDivFloor(inst), .div_floor => try self.airDivFloor(inst, false),
.div_exact => try self.airDivExact(inst), .div_exact => try self.airDivExact(inst, false),
.rem => try self.airRem(inst), .rem => try self.airRem(inst, false),
.mod => try self.airMod(inst), .mod => try self.airMod(inst, false),
.ptr_add => try self.airPtrAdd(inst), .ptr_add => try self.airPtrAdd(inst),
.ptr_sub => try self.airPtrSub(inst), .ptr_sub => try self.airPtrSub(inst),
.shl => try self.airShl(inst), .shl => try self.airShl(inst),
@ -4009,6 +4009,19 @@ pub const FuncGen = struct {
.slice => try self.airSlice(inst), .slice => try self.airSlice(inst),
.mul_add => try self.airMulAdd(inst), .mul_add => try self.airMulAdd(inst),
.add_optimized => try self.airAdd(inst, true),
.addwrap_optimized => try self.airAddWrap(inst, true),
.sub_optimized => try self.airSub(inst, true),
.subwrap_optimized => try self.airSubWrap(inst, true),
.mul_optimized => try self.airMul(inst, true),
.mulwrap_optimized => try self.airMulWrap(inst, true),
.div_float_optimized => try self.airDivFloat(inst, true),
.div_trunc_optimized => try self.airDivTrunc(inst, true),
.div_floor_optimized => try self.airDivFloor(inst, true),
.div_exact_optimized => try self.airDivExact(inst, true),
.rem_optimized => try self.airRem(inst, true),
.mod_optimized => try self.airMod(inst, true),
.add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"), .add_with_overflow => try self.airOverflow(inst, "llvm.sadd.with.overflow", "llvm.uadd.with.overflow"),
.sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"), .sub_with_overflow => try self.airOverflow(inst, "llvm.ssub.with.overflow", "llvm.usub.with.overflow"),
.mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"), .mul_with_overflow => try self.airOverflow(inst, "llvm.smul.with.overflow", "llvm.umul.with.overflow"),
@ -4034,16 +4047,26 @@ pub const FuncGen = struct {
.ceil => try self.airUnaryOp(inst, .ceil), .ceil => try self.airUnaryOp(inst, .ceil),
.round => try self.airUnaryOp(inst, .round), .round => try self.airUnaryOp(inst, .round),
.trunc_float => try self.airUnaryOp(inst, .trunc), .trunc_float => try self.airUnaryOp(inst, .trunc),
.neg => try self.airUnaryOp(inst, .neg),
.cmp_eq => try self.airCmp(inst, .eq), .neg => try self.airNeg(inst, false),
.cmp_gt => try self.airCmp(inst, .gt), .neg_optimized => try self.airNeg(inst, true),
.cmp_gte => try self.airCmp(inst, .gte),
.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), .cmp_eq => try self.airCmp(inst, .eq, false),
.cmp_gt => try self.airCmp(inst, .gt, false),
.cmp_gte => try self.airCmp(inst, .gte, false),
.cmp_lt => try self.airCmp(inst, .lt, false),
.cmp_lte => try self.airCmp(inst, .lte, false),
.cmp_neq => try self.airCmp(inst, .neq, false),
.cmp_eq_optimized => try self.airCmp(inst, .eq, true),
.cmp_gt_optimized => try self.airCmp(inst, .gt, true),
.cmp_gte_optimized => try self.airCmp(inst, .gte, true),
.cmp_lt_optimized => try self.airCmp(inst, .lt, true),
.cmp_lte_optimized => try self.airCmp(inst, .lte, true),
.cmp_neq_optimized => try self.airCmp(inst, .neq, true),
.cmp_vector => try self.airCmpVector(inst, false),
.cmp_vector_optimized => try self.airCmpVector(inst, true),
.cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst),
.is_non_null => try self.airIsNonNull(inst, false, .NE), .is_non_null => try self.airIsNonNull(inst, false, .NE),
@ -4093,8 +4116,10 @@ pub const FuncGen = struct {
.ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0), .ptr_slice_ptr_ptr => try self.airPtrSliceFieldPtr(inst, 0),
.ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1), .ptr_slice_len_ptr => try self.airPtrSliceFieldPtr(inst, 1),
.float_to_int => try self.airFloatToInt(inst, false),
.float_to_int_optimized => try self.airFloatToInt(inst, true),
.array_to_slice => try self.airArrayToSlice(inst), .array_to_slice => try self.airArrayToSlice(inst),
.float_to_int => try self.airFloatToInt(inst),
.int_to_float => try self.airIntToFloat(inst), .int_to_float => try self.airIntToFloat(inst),
.cmpxchg_weak => try self.airCmpxchg(inst, true), .cmpxchg_weak => try self.airCmpxchg(inst, true),
.cmpxchg_strong => try self.airCmpxchg(inst, false), .cmpxchg_strong => try self.airCmpxchg(inst, false),
@ -4115,11 +4140,13 @@ pub const FuncGen = struct {
.splat => try self.airSplat(inst), .splat => try self.airSplat(inst),
.select => try self.airSelect(inst), .select => try self.airSelect(inst),
.shuffle => try self.airShuffle(inst), .shuffle => try self.airShuffle(inst),
.reduce => try self.airReduce(inst),
.aggregate_init => try self.airAggregateInit(inst), .aggregate_init => try self.airAggregateInit(inst),
.union_init => try self.airUnionInit(inst), .union_init => try self.airUnionInit(inst),
.prefetch => try self.airPrefetch(inst), .prefetch => try self.airPrefetch(inst),
.reduce => try self.airReduce(inst, false),
.reduce_optimized => try self.airReduce(inst, true),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered), .atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic), .atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
.atomic_store_release => try self.airAtomicStore(inst, .Release), .atomic_store_release => try self.airAtomicStore(inst, .Release),
@ -4485,8 +4512,9 @@ pub const FuncGen = struct {
return null; return null;
} }
fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator) !?*const llvm.Value { fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -4496,8 +4524,9 @@ pub const FuncGen = struct {
return self.cmp(lhs, rhs, operand_ty, op); return self.cmp(lhs, rhs, operand_ty, op);
} }
fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
@ -4943,10 +4972,12 @@ pub const FuncGen = struct {
return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, ""); return self.builder.buildCall(libc_fn, &params, params.len, .C, .Auto, "");
} }
fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) if (self.liveness.isUnused(inst))
return null; return null;
self.builder.setFastMath(want_fast_math);
const target = self.dg.module.getTarget(); const target = self.dg.module.getTarget();
const ty_op = self.air.instructions.items(.data)[inst].ty_op; const ty_op = self.air.instructions.items(.data)[inst].ty_op;
@ -6095,8 +6126,9 @@ pub const FuncGen = struct {
return self.builder.buildInsertValue(partial, len, 1, ""); return self.builder.buildInsertValue(partial, len, 1, "");
} }
fn airAdd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6109,8 +6141,9 @@ pub const FuncGen = struct {
return self.builder.buildNUWAdd(lhs, rhs, ""); return self.builder.buildNUWAdd(lhs, rhs, "");
} }
fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6134,8 +6167,9 @@ pub const FuncGen = struct {
return self.builder.buildUAddSat(lhs, rhs, ""); return self.builder.buildUAddSat(lhs, rhs, "");
} }
fn airSub(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6148,8 +6182,9 @@ pub const FuncGen = struct {
return self.builder.buildNUWSub(lhs, rhs, ""); return self.builder.buildNUWSub(lhs, rhs, "");
} }
fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6172,8 +6207,9 @@ pub const FuncGen = struct {
return self.builder.buildUSubSat(lhs, rhs, ""); return self.builder.buildUSubSat(lhs, rhs, "");
} }
fn airMul(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6186,8 +6222,9 @@ pub const FuncGen = struct {
return self.builder.buildNUWMul(lhs, rhs, ""); return self.builder.buildNUWMul(lhs, rhs, "");
} }
fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6210,8 +6247,9 @@ pub const FuncGen = struct {
return self.builder.buildUMulFixSat(lhs, rhs, ""); return self.builder.buildUMulFixSat(lhs, rhs, "");
} }
fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6221,8 +6259,9 @@ pub const FuncGen = struct {
return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs }); return self.buildFloatOp(.div, inst_ty, 2, .{ lhs, rhs });
} }
fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6238,8 +6277,9 @@ pub const FuncGen = struct {
return self.builder.buildUDiv(lhs, rhs, ""); return self.builder.buildUDiv(lhs, rhs, "");
} }
fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6270,8 +6310,9 @@ pub const FuncGen = struct {
return self.builder.buildUDiv(lhs, rhs, ""); return self.builder.buildUDiv(lhs, rhs, "");
} }
fn airDivExact(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6284,8 +6325,9 @@ pub const FuncGen = struct {
return self.builder.buildExactUDiv(lhs, rhs, ""); return self.builder.buildExactUDiv(lhs, rhs, "");
} }
fn airRem(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -6298,8 +6340,9 @@ pub const FuncGen = struct {
return self.builder.buildURem(lhs, rhs, ""); return self.builder.buildURem(lhs, rhs, "");
} }
fn airMod(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const bin_op = self.air.instructions.items(.data)[inst].bin_op; const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const lhs = try self.resolveInst(bin_op.lhs); const lhs = try self.resolveInst(bin_op.lhs);
@ -7613,6 +7656,17 @@ pub const FuncGen = struct {
return self.buildFloatOp(op, operand_ty, 1, .{operand}); return self.buildFloatOp(op, operand_ty, 1, .{operand});
} }
fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const operand_ty = self.air.typeOf(un_op);
return self.buildFloatOp(.neg, operand_ty, 1, .{operand});
}
fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value { fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
@ -7927,8 +7981,9 @@ pub const FuncGen = struct {
return self.builder.buildShuffleVector(a, b, llvm_mask_value, ""); return self.builder.buildShuffleVector(a, b, llvm_mask_value, "");
} }
fn airReduce(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null; if (self.liveness.isUnused(inst)) return null;
self.builder.setFastMath(want_fast_math);
const reduce = self.air.instructions.items(.data)[inst].reduce; const reduce = self.air.instructions.items(.data)[inst].reduce;
const operand = try self.resolveInst(reduce.operand); const operand = try self.resolveInst(reduce.operand);

View file

@ -941,6 +941,9 @@ pub const Builder = opaque {
pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce; pub const buildFPMulReduce = ZigLLVMBuildFPMulReduce;
extern fn ZigLLVMBuildFPMulReduce(B: *const Builder, Acc: *const Value, Val: *const Value) *const Value; extern fn ZigLLVMBuildFPMulReduce(B: *const Builder, Acc: *const Value, Val: *const Value) *const Value;
pub const setFastMath = ZigLLVMSetFastMath;
extern fn ZigLLVMSetFastMath(B: *const Builder, on_state: bool) void;
}; };
pub const MDString = opaque { pub const MDString = opaque {

View file

@ -138,6 +138,24 @@ const Writer = struct {
.set_union_tag, .set_union_tag,
.min, .min,
.max, .max,
.add_optimized,
.addwrap_optimized,
.sub_optimized,
.subwrap_optimized,
.mul_optimized,
.mulwrap_optimized,
.div_float_optimized,
.div_trunc_optimized,
.div_floor_optimized,
.div_exact_optimized,
.rem_optimized,
.mod_optimized,
.cmp_lt_optimized,
.cmp_lte_optimized,
.cmp_eq_optimized,
.cmp_gte_optimized,
.cmp_gt_optimized,
.cmp_neq_optimized,
=> try w.writeBinOp(s, inst), => try w.writeBinOp(s, inst),
.is_null, .is_null,
@ -169,6 +187,7 @@ const Writer = struct {
.round, .round,
.trunc_float, .trunc_float,
.neg, .neg,
.neg_optimized,
.cmp_lt_errors_len, .cmp_lt_errors_len,
.set_err_return_trace, .set_err_return_trace,
=> try w.writeUnOp(s, inst), => try w.writeUnOp(s, inst),
@ -216,6 +235,7 @@ const Writer = struct {
.int_to_float, .int_to_float,
.splat, .splat,
.float_to_int, .float_to_int,
.float_to_int_optimized,
.get_union_tag, .get_union_tag,
.clz, .clz,
.ctz, .ctz,
@ -280,8 +300,8 @@ const Writer = struct {
.mul_add => try w.writeMulAdd(s, inst), .mul_add => try w.writeMulAdd(s, inst),
.select => try w.writeSelect(s, inst), .select => try w.writeSelect(s, inst),
.shuffle => try w.writeShuffle(s, inst), .shuffle => try w.writeShuffle(s, inst),
.reduce => try w.writeReduce(s, inst), .reduce, .reduce_optimized => try w.writeReduce(s, inst),
.cmp_vector => try w.writeCmpVector(s, inst), .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
.dbg_block_begin, .dbg_block_end => {}, .dbg_block_begin, .dbg_block_end => {},
} }