mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 23:29:03 +00:00
minimum/maximum builtins
This commit is contained in:
parent
50a29f7c21
commit
cdeea3b094
18 changed files with 416 additions and 0 deletions
|
|
@ -7988,6 +7988,17 @@ test "@hasDecl" {
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@maximum#}
|
||||||
|
<pre>{#syntax#}@maximum(a: T, b: T) T{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Returns the maximum value of {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#}. This builtin accepts integers, floats, and vectors of either. In the latter case, the operation is performed element wise.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned.
|
||||||
|
</p>
|
||||||
|
{#see_also|@minimum|SIMD|Vectors#}
|
||||||
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@memcpy#}
|
{#header_open|@memcpy#}
|
||||||
<pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre>
|
<pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
|
|
@ -8025,6 +8036,17 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>
|
||||||
mem.set(u8, dest, c);{#endsyntax#}</pre>
|
mem.set(u8, dest, c);{#endsyntax#}</pre>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@minimum#}
|
||||||
|
<pre>{#syntax#}@minimum(a: T, b: T) T{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Returns the minimum value of {#syntax#}a{#endsyntax#} and {#syntax#}b{#endsyntax#}. This builtin accepts integers, floats, and vectors of either. In the latter case, the operation is performed element wise.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
NaNs are handled as follows: if one of the operands of a (pairwise) operation is NaN, the other operand is returned. If both operands are NaN, NaN is returned.
|
||||||
|
</p>
|
||||||
|
{#see_also|@maximum|SIMD|Vectors#}
|
||||||
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@wasmMemorySize#}
|
{#header_open|@wasmMemorySize#}
|
||||||
<pre>{#syntax#}@wasmMemorySize(index: u32) u32{#endsyntax#}</pre>
|
<pre>{#syntax#}@wasmMemorySize(index: u32) u32{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
||||||
|
|
@ -2098,8 +2098,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
|
||||||
.builtin_call,
|
.builtin_call,
|
||||||
.field_ptr_type,
|
.field_ptr_type,
|
||||||
.field_parent_ptr,
|
.field_parent_ptr,
|
||||||
|
.maximum,
|
||||||
.memcpy,
|
.memcpy,
|
||||||
.memset,
|
.memset,
|
||||||
|
.minimum,
|
||||||
.builtin_async_call,
|
.builtin_async_call,
|
||||||
.c_import,
|
.c_import,
|
||||||
.@"resume",
|
.@"resume",
|
||||||
|
|
@ -7227,6 +7229,25 @@ fn builtinCall(
|
||||||
return rvalue(gz, rl, result, node);
|
return rvalue(gz, rl, result, node);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.maximum => {
|
||||||
|
const a = try expr(gz, scope, .none, params[0]);
|
||||||
|
const b = try expr(gz, scope, .none, params[1]);
|
||||||
|
const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{
|
||||||
|
.lhs = a,
|
||||||
|
.rhs = b,
|
||||||
|
});
|
||||||
|
return rvalue(gz, rl, result, node);
|
||||||
|
},
|
||||||
|
.minimum => {
|
||||||
|
const a = try expr(gz, scope, .none, params[0]);
|
||||||
|
const b = try expr(gz, scope, .none, params[1]);
|
||||||
|
const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{
|
||||||
|
.lhs = a,
|
||||||
|
.rhs = b,
|
||||||
|
});
|
||||||
|
return rvalue(gz, rl, result, node);
|
||||||
|
},
|
||||||
|
|
||||||
.add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
|
.add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow),
|
||||||
.sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
|
.sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow),
|
||||||
.mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow),
|
.mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow),
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,10 @@ pub const Tag = enum {
|
||||||
int_to_error,
|
int_to_error,
|
||||||
int_to_float,
|
int_to_float,
|
||||||
int_to_ptr,
|
int_to_ptr,
|
||||||
|
maximum,
|
||||||
memcpy,
|
memcpy,
|
||||||
memset,
|
memset,
|
||||||
|
minimum,
|
||||||
wasm_memory_size,
|
wasm_memory_size,
|
||||||
wasm_memory_grow,
|
wasm_memory_grow,
|
||||||
mod,
|
mod,
|
||||||
|
|
@ -518,6 +520,13 @@ pub const list = list: {
|
||||||
.param_count = 2,
|
.param_count = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@maximum",
|
||||||
|
.{
|
||||||
|
.tag = .maximum,
|
||||||
|
.param_count = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
.{
|
.{
|
||||||
"@memcpy",
|
"@memcpy",
|
||||||
.{
|
.{
|
||||||
|
|
@ -532,6 +541,13 @@ pub const list = list: {
|
||||||
.param_count = 3,
|
.param_count = 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@minimum",
|
||||||
|
.{
|
||||||
|
.tag = .minimum,
|
||||||
|
.param_count = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
.{
|
.{
|
||||||
"@wasmMemorySize",
|
"@wasmMemorySize",
|
||||||
.{
|
.{
|
||||||
|
|
|
||||||
14
src/Sema.zig
14
src/Sema.zig
|
|
@ -346,8 +346,10 @@ pub fn analyzeBody(
|
||||||
.builtin_call => try sema.zirBuiltinCall(block, inst),
|
.builtin_call => try sema.zirBuiltinCall(block, inst),
|
||||||
.field_ptr_type => try sema.zirFieldPtrType(block, inst),
|
.field_ptr_type => try sema.zirFieldPtrType(block, inst),
|
||||||
.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
|
.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
|
||||||
|
.maximum => try sema.zirMaximum(block, inst),
|
||||||
.memcpy => try sema.zirMemcpy(block, inst),
|
.memcpy => try sema.zirMemcpy(block, inst),
|
||||||
.memset => try sema.zirMemset(block, inst),
|
.memset => try sema.zirMemset(block, inst),
|
||||||
|
.minimum => try sema.zirMinimum(block, inst),
|
||||||
.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
|
.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
|
||||||
.@"resume" => try sema.zirResume(block, inst),
|
.@"resume" => try sema.zirResume(block, inst),
|
||||||
.@"await" => try sema.zirAwait(block, inst, false),
|
.@"await" => try sema.zirAwait(block, inst, false),
|
||||||
|
|
@ -6148,6 +6150,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Com
|
||||||
return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{});
|
return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn zirMaximum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
|
const src = inst_data.src();
|
||||||
|
return sema.mod.fail(&block.base, src, "TODO: Sema.zirMaximum", .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
const src = inst_data.src();
|
const src = inst_data.src();
|
||||||
|
|
@ -6160,6 +6168,12 @@ fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
|
||||||
return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{});
|
return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn zirMinimum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
|
const src = inst_data.src();
|
||||||
|
return sema.mod.fail(&block.base, src, "TODO: Sema.zirMinimum", .{});
|
||||||
|
}
|
||||||
|
|
||||||
fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||||
const src = inst_data.src();
|
const src = inst_data.src();
|
||||||
|
|
|
||||||
12
src/Zir.zig
12
src/Zir.zig
|
|
@ -915,12 +915,18 @@ pub const Inst = struct {
|
||||||
/// Implements the `@fieldParentPtr` builtin.
|
/// Implements the `@fieldParentPtr` builtin.
|
||||||
/// Uses the `pl_node` union field with payload `FieldParentPtr`.
|
/// Uses the `pl_node` union field with payload `FieldParentPtr`.
|
||||||
field_parent_ptr,
|
field_parent_ptr,
|
||||||
|
/// Implements the `@maximum` builtin.
|
||||||
|
/// Uses the `pl_node` union field with payload `Bin`
|
||||||
|
maximum,
|
||||||
/// Implements the `@memcpy` builtin.
|
/// Implements the `@memcpy` builtin.
|
||||||
/// Uses the `pl_node` union field with payload `Memcpy`.
|
/// Uses the `pl_node` union field with payload `Memcpy`.
|
||||||
memcpy,
|
memcpy,
|
||||||
/// Implements the `@memset` builtin.
|
/// Implements the `@memset` builtin.
|
||||||
/// Uses the `pl_node` union field with payload `Memset`.
|
/// Uses the `pl_node` union field with payload `Memset`.
|
||||||
memset,
|
memset,
|
||||||
|
/// Implements the `@minimum` builtin.
|
||||||
|
/// Uses the `pl_node` union field with payload `Bin`
|
||||||
|
minimum,
|
||||||
/// Implements the `@asyncCall` builtin.
|
/// Implements the `@asyncCall` builtin.
|
||||||
/// Uses the `pl_node` union field with payload `AsyncCall`.
|
/// Uses the `pl_node` union field with payload `AsyncCall`.
|
||||||
builtin_async_call,
|
builtin_async_call,
|
||||||
|
|
@ -1192,8 +1198,10 @@ pub const Inst = struct {
|
||||||
.builtin_call,
|
.builtin_call,
|
||||||
.field_ptr_type,
|
.field_ptr_type,
|
||||||
.field_parent_ptr,
|
.field_parent_ptr,
|
||||||
|
.maximum,
|
||||||
.memcpy,
|
.memcpy,
|
||||||
.memset,
|
.memset,
|
||||||
|
.minimum,
|
||||||
.builtin_async_call,
|
.builtin_async_call,
|
||||||
.c_import,
|
.c_import,
|
||||||
.@"resume",
|
.@"resume",
|
||||||
|
|
@ -1463,8 +1471,10 @@ pub const Inst = struct {
|
||||||
.builtin_call = .pl_node,
|
.builtin_call = .pl_node,
|
||||||
.field_ptr_type = .bin,
|
.field_ptr_type = .bin,
|
||||||
.field_parent_ptr = .pl_node,
|
.field_parent_ptr = .pl_node,
|
||||||
|
.maximum = .pl_node,
|
||||||
.memcpy = .pl_node,
|
.memcpy = .pl_node,
|
||||||
.memset = .pl_node,
|
.memset = .pl_node,
|
||||||
|
.minimum = .pl_node,
|
||||||
.builtin_async_call = .pl_node,
|
.builtin_async_call = .pl_node,
|
||||||
.c_import = .pl_node,
|
.c_import = .pl_node,
|
||||||
|
|
||||||
|
|
@ -3020,6 +3030,8 @@ const Writer = struct {
|
||||||
.bitcast,
|
.bitcast,
|
||||||
.bitcast_result_ptr,
|
.bitcast_result_ptr,
|
||||||
.vector_type,
|
.vector_type,
|
||||||
|
.maximum,
|
||||||
|
.minimum,
|
||||||
=> try self.writePlNodeBin(stream, inst),
|
=> try self.writePlNodeBin(stream, inst),
|
||||||
|
|
||||||
.@"export" => try self.writePlNodeExport(stream, inst),
|
.@"export" => try self.writePlNodeExport(stream, inst),
|
||||||
|
|
|
||||||
|
|
@ -1796,6 +1796,8 @@ enum BuiltinFnId {
|
||||||
BuiltinFnIdWasmMemoryGrow,
|
BuiltinFnIdWasmMemoryGrow,
|
||||||
BuiltinFnIdSrc,
|
BuiltinFnIdSrc,
|
||||||
BuiltinFnIdReduce,
|
BuiltinFnIdReduce,
|
||||||
|
BuiltinFnIdMaximum,
|
||||||
|
BuiltinFnIdMinimum,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuiltinFnEntry {
|
struct BuiltinFnEntry {
|
||||||
|
|
@ -2938,6 +2940,8 @@ enum IrBinOp {
|
||||||
IrBinOpRemMod,
|
IrBinOpRemMod,
|
||||||
IrBinOpArrayCat,
|
IrBinOpArrayCat,
|
||||||
IrBinOpArrayMult,
|
IrBinOpArrayMult,
|
||||||
|
IrBinOpMaximum,
|
||||||
|
IrBinOpMinimum,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stage1ZirInstBinOp {
|
struct Stage1ZirInstBinOp {
|
||||||
|
|
|
||||||
|
|
@ -4686,6 +4686,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
||||||
arg0_value, arg1_value);
|
arg0_value, arg1_value);
|
||||||
return ir_lval_wrap(ag, scope, splat, lval, result_loc);
|
return ir_lval_wrap(ag, scope, splat, lval, result_loc);
|
||||||
}
|
}
|
||||||
|
case BuiltinFnIdMaximum:
|
||||||
|
{
|
||||||
|
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||||
|
Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope);
|
||||||
|
if (arg0_value == ag->codegen->invalid_inst_src)
|
||||||
|
return arg0_value;
|
||||||
|
|
||||||
|
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||||
|
Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);
|
||||||
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
|
return arg1_value;
|
||||||
|
|
||||||
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMaximum, arg0_value, arg1_value, true);
|
||||||
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
|
}
|
||||||
case BuiltinFnIdMemcpy:
|
case BuiltinFnIdMemcpy:
|
||||||
{
|
{
|
||||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||||
|
|
@ -4726,6 +4741,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
|
||||||
Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value);
|
Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value);
|
||||||
return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc);
|
return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc);
|
||||||
}
|
}
|
||||||
|
case BuiltinFnIdMinimum:
|
||||||
|
{
|
||||||
|
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||||
|
Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope);
|
||||||
|
if (arg0_value == ag->codegen->invalid_inst_src)
|
||||||
|
return arg0_value;
|
||||||
|
|
||||||
|
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||||
|
Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);
|
||||||
|
if (arg1_value == ag->codegen->invalid_inst_src)
|
||||||
|
return arg1_value;
|
||||||
|
|
||||||
|
Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMinimum, arg0_value, arg1_value, true);
|
||||||
|
return ir_lval_wrap(ag, scope, bin_op, lval, result_loc);
|
||||||
|
}
|
||||||
case BuiltinFnIdWasmMemorySize:
|
case BuiltinFnIdWasmMemorySize:
|
||||||
{
|
{
|
||||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,30 @@ void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) {
|
||||||
f128M_sqrt(&op->value, &dest->value);
|
f128M_sqrt(&op->value, &dest->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
if (bigfloat_is_nan(op1)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op2);
|
||||||
|
} else if (bigfloat_is_nan(op2)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op1);
|
||||||
|
} else if (f128M_lt(&op1->value, &op2->value)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op1);
|
||||||
|
} else {
|
||||||
|
bigfloat_init_bigfloat(dest, op2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
if (bigfloat_is_nan(op1)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op2);
|
||||||
|
} else if (bigfloat_is_nan(op2)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op1);
|
||||||
|
} else if (f128M_lt(&op1->value, &op2->value)) {
|
||||||
|
bigfloat_init_bigfloat(dest, op2);
|
||||||
|
} else {
|
||||||
|
bigfloat_init_bigfloat(dest, op1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool bigfloat_is_nan(const BigFloat *op) {
|
bool bigfloat_is_nan(const BigFloat *op) {
|
||||||
return f128M_isSignalingNaN(&op->value);
|
return f128M_isSignalingNaN(&op->value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,9 +45,12 @@ void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2
|
||||||
void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
void bigfloat_sqrt(BigFloat *dest, const BigFloat *op);
|
void bigfloat_sqrt(BigFloat *dest, const BigFloat *op);
|
||||||
|
void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
void bigfloat_append_buf(Buf *buf, const BigFloat *op);
|
void bigfloat_append_buf(Buf *buf, const BigFloat *op);
|
||||||
Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
|
Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
|
||||||
|
|
||||||
|
|
||||||
bool bigfloat_is_nan(const BigFloat *op);
|
bool bigfloat_is_nan(const BigFloat *op);
|
||||||
|
|
||||||
// convenience functions
|
// convenience functions
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,26 @@ bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2) {
|
||||||
|
switch (bigint_cmp(op1, op2)) {
|
||||||
|
case CmpEQ:
|
||||||
|
case CmpLT:
|
||||||
|
return bigint_init_bigint(dest, op2);
|
||||||
|
case CmpGT:
|
||||||
|
return bigint_init_bigint(dest, op1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) {
|
||||||
|
switch (bigint_cmp(op1, op2)) {
|
||||||
|
case CmpEQ:
|
||||||
|
case CmpLT:
|
||||||
|
return bigint_init_bigint(dest, op1);
|
||||||
|
case CmpGT:
|
||||||
|
return bigint_init_bigint(dest, op2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
|
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) {
|
||||||
if (op1->digit_count == 0) {
|
if (op1->digit_count == 0) {
|
||||||
return bigint_init_bigint(dest, op2);
|
return bigint_init_bigint(dest, op2);
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,8 @@ bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed);
|
||||||
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian);
|
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian);
|
||||||
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian,
|
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian,
|
||||||
bool is_signed);
|
bool is_signed);
|
||||||
|
void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2);
|
||||||
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||||
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
|
||||||
|
|
@ -3248,6 +3248,30 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable,
|
||||||
case IrBinOpRemMod:
|
case IrBinOpRemMod:
|
||||||
return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
|
return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
|
||||||
op1_value, op2_value, operand_type, RemKindMod);
|
op1_value, op2_value, operand_type, RemKindMod);
|
||||||
|
case IrBinOpMaximum:
|
||||||
|
if (scalar_type->id == ZigTypeIdFloat) {
|
||||||
|
return ZigLLVMBuildMaxNum(g->builder, op1_value, op2_value, "");
|
||||||
|
} else if (scalar_type->id == ZigTypeIdInt) {
|
||||||
|
if (scalar_type->data.integral.is_signed) {
|
||||||
|
return ZigLLVMBuildSMax(g->builder, op1_value, op2_value, "");
|
||||||
|
} else {
|
||||||
|
return ZigLLVMBuildUMax(g->builder, op1_value, op2_value, "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
case IrBinOpMinimum:
|
||||||
|
if (scalar_type->id == ZigTypeIdFloat) {
|
||||||
|
return ZigLLVMBuildMinNum(g->builder, op1_value, op2_value, "");
|
||||||
|
} else if (scalar_type->id == ZigTypeIdInt) {
|
||||||
|
if (scalar_type->data.integral.is_signed) {
|
||||||
|
return ZigLLVMBuildSMin(g->builder, op1_value, op2_value, "");
|
||||||
|
} else {
|
||||||
|
return ZigLLVMBuildUMin(g->builder, op1_value, op2_value, "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
@ -8990,6 +9014,8 @@ static void define_builtin_fns(CodeGen *g) {
|
||||||
create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
|
create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2);
|
||||||
create_builtin_fn(g, BuiltinFnIdSrc, "src", 0);
|
create_builtin_fn(g, BuiltinFnIdSrc, "src", 0);
|
||||||
create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
|
create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2);
|
||||||
|
create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
|
||||||
|
create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *bool_to_str(bool b) {
|
static const char *bool_to_str(bool b) {
|
||||||
|
|
|
||||||
|
|
@ -3311,6 +3311,108 @@ static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
|
||||||
|
assert(op1->type == op2->type);
|
||||||
|
out_val->type = op1->type;
|
||||||
|
if (op1->type->id == ZigTypeIdComptimeFloat) {
|
||||||
|
bigfloat_max(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
|
||||||
|
} else if (op1->type->id == ZigTypeIdFloat) {
|
||||||
|
switch (op1->type->data.floating.bit_count) {
|
||||||
|
case 16:
|
||||||
|
if (zig_f16_isNaN(op1->data.x_f16)) {
|
||||||
|
out_val->data.x_f16 = op2->data.x_f16;
|
||||||
|
} else if (zig_f16_isNaN(op2->data.x_f16)) {
|
||||||
|
out_val->data.x_f16 = op1->data.x_f16;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op2->data.x_f16 : op1->data.x_f16;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 32:
|
||||||
|
if (op1->data.x_f32 != op1->data.x_f32) {
|
||||||
|
out_val->data.x_f32 = op2->data.x_f32;
|
||||||
|
} else if (op2->data.x_f32 != op2->data.x_f32) {
|
||||||
|
out_val->data.x_f32 = op1->data.x_f32;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f32 = op1->data.x_f32 > op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 64:
|
||||||
|
if (op1->data.x_f64 != op1->data.x_f64) {
|
||||||
|
out_val->data.x_f64 = op2->data.x_f64;
|
||||||
|
} else if (op2->data.x_f64 != op2->data.x_f64) {
|
||||||
|
out_val->data.x_f64 = op1->data.x_f64;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 128:
|
||||||
|
if (zig_f128_isNaN(&op1->data.x_f128)) {
|
||||||
|
out_val->data.x_f128 = op2->data.x_f128;
|
||||||
|
} else if (zig_f128_isNaN(&op2->data.x_f128)) {
|
||||||
|
out_val->data.x_f128 = op1->data.x_f128;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op2->data.x_f128 : op1->data.x_f128;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) {
|
||||||
|
assert(op1->type == op2->type);
|
||||||
|
out_val->type = op1->type;
|
||||||
|
if (op1->type->id == ZigTypeIdComptimeFloat) {
|
||||||
|
bigfloat_min(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat);
|
||||||
|
} else if (op1->type->id == ZigTypeIdFloat) {
|
||||||
|
switch (op1->type->data.floating.bit_count) {
|
||||||
|
case 16:
|
||||||
|
if (zig_f16_isNaN(op1->data.x_f16)) {
|
||||||
|
out_val->data.x_f16 = op2->data.x_f16;
|
||||||
|
} else if (zig_f16_isNaN(op2->data.x_f16)) {
|
||||||
|
out_val->data.x_f16 = op1->data.x_f16;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op1->data.x_f16 : op2->data.x_f16;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 32:
|
||||||
|
if (op1->data.x_f32 != op1->data.x_f32) {
|
||||||
|
out_val->data.x_f32 = op2->data.x_f32;
|
||||||
|
} else if (op2->data.x_f32 != op2->data.x_f32) {
|
||||||
|
out_val->data.x_f32 = op1->data.x_f32;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f32 = op1->data.x_f32 < op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 64:
|
||||||
|
if (op1->data.x_f64 != op1->data.x_f64) {
|
||||||
|
out_val->data.x_f64 = op2->data.x_f64;
|
||||||
|
} else if (op2->data.x_f64 != op2->data.x_f64) {
|
||||||
|
out_val->data.x_f64 = op1->data.x_f64;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case 128:
|
||||||
|
if (zig_f128_isNaN(&op1->data.x_f128)) {
|
||||||
|
out_val->data.x_f128 = op2->data.x_f128;
|
||||||
|
} else if (zig_f128_isNaN(&op2->data.x_f128)) {
|
||||||
|
out_val->data.x_f128 = op1->data.x_f128;
|
||||||
|
} else {
|
||||||
|
out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op1->data.x_f128 : op2->data.x_f128;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void float_negate(ZigValue *out_val, ZigValue *op) {
|
static void float_negate(ZigValue *out_val, ZigValue *op) {
|
||||||
out_val->type = op->type;
|
out_val->type = op->type;
|
||||||
if (op->type->id == ZigTypeIdComptimeFloat) {
|
if (op->type->id == ZigTypeIdComptimeFloat) {
|
||||||
|
|
@ -9704,6 +9806,20 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s
|
||||||
float_mod(out_val, op1_val, op2_val);
|
float_mod(out_val, op1_val, op2_val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case IrBinOpMaximum:
|
||||||
|
if (is_int) {
|
||||||
|
bigint_max(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||||
|
} else {
|
||||||
|
float_max(out_val, op1_val, op2_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IrBinOpMinimum:
|
||||||
|
if (is_int) {
|
||||||
|
bigint_min(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint);
|
||||||
|
} else {
|
||||||
|
float_min(out_val, op1_val, op2_val);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_entry->id == ZigTypeIdInt) {
|
if (type_entry->id == ZigTypeIdInt) {
|
||||||
|
|
@ -9904,6 +10020,8 @@ static bool ok_float_op(IrBinOp op) {
|
||||||
case IrBinOpRemRem:
|
case IrBinOpRemRem:
|
||||||
case IrBinOpRemMod:
|
case IrBinOpRemMod:
|
||||||
case IrBinOpRemUnspecified:
|
case IrBinOpRemUnspecified:
|
||||||
|
case IrBinOpMaximum:
|
||||||
|
case IrBinOpMinimum:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case IrBinOpBoolOr:
|
case IrBinOpBoolOr:
|
||||||
|
|
@ -10894,6 +11012,8 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns
|
||||||
case IrBinOpRemUnspecified:
|
case IrBinOpRemUnspecified:
|
||||||
case IrBinOpRemRem:
|
case IrBinOpRemRem:
|
||||||
case IrBinOpRemMod:
|
case IrBinOpRemMod:
|
||||||
|
case IrBinOpMaximum:
|
||||||
|
case IrBinOpMinimum:
|
||||||
return ir_analyze_bin_op_math(ira, bin_op_instruction);
|
return ir_analyze_bin_op_math(ira, bin_op_instruction);
|
||||||
case IrBinOpArrayCat:
|
case IrBinOpArrayCat:
|
||||||
return ir_analyze_array_cat(ira, bin_op_instruction);
|
return ir_analyze_array_cat(ira, bin_op_instruction);
|
||||||
|
|
|
||||||
|
|
@ -733,6 +733,10 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) {
|
||||||
return "++";
|
return "++";
|
||||||
case IrBinOpArrayMult:
|
case IrBinOpArrayMult:
|
||||||
return "**";
|
return "**";
|
||||||
|
case IrBinOpMaximum:
|
||||||
|
return "@maximum";
|
||||||
|
case IrBinOpMinimum:
|
||||||
|
return "@minimum";
|
||||||
}
|
}
|
||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -458,6 +458,36 @@ LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef
|
||||||
return wrap(call_inst);
|
return wrap(call_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS), name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateMinNum(unwrap(LHS), unwrap(RHS), name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildUMax(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::umax, unwrap(LHS), unwrap(RHS), nullptr, name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildUMin(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::umin, unwrap(LHS), unwrap(RHS), nullptr, name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildSMax(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::smax, unwrap(LHS), unwrap(RHS), nullptr, name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
LLVMValueRef ZigLLVMBuildSMin(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) {
|
||||||
|
CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::smin, unwrap(LHS), unwrap(RHS), nullptr, name);
|
||||||
|
return wrap(call_inst);
|
||||||
|
}
|
||||||
|
|
||||||
void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
|
void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
|
||||||
assert( isa<Function>(unwrap(fn)) );
|
assert( isa<Function>(unwrap(fn)) );
|
||||||
Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));
|
Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,14 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst,
|
||||||
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
|
||||||
unsigned Align, bool isVolatile);
|
unsigned Align, bool isVolatile);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildUMax(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildUMin(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSMax(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSMin(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name);
|
||||||
|
|
||||||
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
|
||||||
LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
|
LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
|
||||||
LLVMAtomicOrdering failure_ordering, bool is_weak);
|
LLVMAtomicOrdering failure_ordering, bool is_weak);
|
||||||
|
|
@ -142,6 +150,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu
|
||||||
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
|
||||||
ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
|
ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
|
||||||
struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
|
struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ test {
|
||||||
_ = @import("behavior/inttoptr.zig");
|
_ = @import("behavior/inttoptr.zig");
|
||||||
_ = @import("behavior/ir_block_deps.zig");
|
_ = @import("behavior/ir_block_deps.zig");
|
||||||
_ = @import("behavior/math.zig");
|
_ = @import("behavior/math.zig");
|
||||||
|
_ = @import("behavior/maximum_minimum.zig");
|
||||||
_ = @import("behavior/merge_error_sets.zig");
|
_ = @import("behavior/merge_error_sets.zig");
|
||||||
_ = @import("behavior/misc.zig");
|
_ = @import("behavior/misc.zig");
|
||||||
_ = @import("behavior/muladd.zig");
|
_ = @import("behavior/muladd.zig");
|
||||||
|
|
|
||||||
58
test/behavior/maximum_minimum.zig
Normal file
58
test/behavior/maximum_minimum.zig
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const mem = std.mem;
|
||||||
|
const expect = std.testing.expect;
|
||||||
|
const expectEqual = std.testing.expectEqual;
|
||||||
|
const Vector = std.meta.Vector;
|
||||||
|
|
||||||
|
test "@maximum" {
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest() !void {
|
||||||
|
try expectEqual(@as(i32, 10), @maximum(@as(i32, -3), @as(i32, 10)));
|
||||||
|
try expectEqual(@as(f32, 3.2), @maximum(@as(f32, 3.2), @as(f32, 0.68)));
|
||||||
|
|
||||||
|
var a: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
|
||||||
|
var b: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
|
||||||
|
var x = @maximum(a, b);
|
||||||
|
try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 2147483647, 2147483647, 30, 40 }));
|
||||||
|
|
||||||
|
var c: Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 };
|
||||||
|
var d: Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 };
|
||||||
|
var y = @maximum(c, d);
|
||||||
|
try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ 0, 0.42, -0.64, 7.8 }));
|
||||||
|
|
||||||
|
var e: Vector(2, f32) = [2]f32{ 0, std.math.qnan_f32 };
|
||||||
|
var f: Vector(2, f32) = [2]f32{ std.math.qnan_f32, 0 };
|
||||||
|
var z = @maximum(e, f);
|
||||||
|
try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try S.doTheTest();
|
||||||
|
comptime try S.doTheTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@minimum" {
|
||||||
|
const S = struct {
|
||||||
|
fn doTheTest() !void {
|
||||||
|
try expectEqual(@as(i32, -3), @minimum(@as(i32, -3), @as(i32, 10)));
|
||||||
|
try expectEqual(@as(f32, 0.68), @minimum(@as(f32, 3.2), @as(f32, 0.68)));
|
||||||
|
|
||||||
|
var a: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 };
|
||||||
|
var b: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 };
|
||||||
|
var x = @minimum(a, b);
|
||||||
|
try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 1, -2, 3, 4 }));
|
||||||
|
|
||||||
|
var c: Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 };
|
||||||
|
var d: Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 };
|
||||||
|
var y = @minimum(c, d);
|
||||||
|
try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ -0.23, 0.4, -2.4, 0.9 }));
|
||||||
|
|
||||||
|
var e: Vector(2, f32) = [2]f32{ 0, std.math.qnan_f32 };
|
||||||
|
var f: Vector(2, f32) = [2]f32{ std.math.qnan_f32, 0 };
|
||||||
|
var z = @maximum(e, f);
|
||||||
|
try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try S.doTheTest();
|
||||||
|
comptime try S.doTheTest();
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue