| author | |
| committer | |
| log | cdeea3b0943b070d49d8d8d0855f9a38843e3ecc |
| tree | 541557cd87bddd0fb76cadd34e2cb9d20495a4bf |
| parent | 50a29f7c213d4a906839dfd625b6280663348781 |
18 files changed, 416 insertions(+), 0 deletions(-)
doc/langref.html.in+22| ... | @@ -7988,6 +7988,17 @@ test "@hasDecl" { | ... | @@ -7988,6 +7988,17 @@ test "@hasDecl" { |
| 7988 | </p> | 7988 | </p> |
| 7989 | {#header_close#} | 7989 | {#header_close#} |
| 7990 | 7990 | ||
| 7991 | {#header_open|@maximum#} | ||
| 7992 | <pre>{#syntax#}@maximum(a: T, b: T) T{#endsyntax#}</pre> | ||
| 7993 | <p> | ||
| 7994 | 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. | ||
| 7995 | </p> | ||
| 7996 | <p> | ||
| 7997 | 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. | ||
| 7998 | </p> | ||
| 7999 | {#see_also|@minimum|SIMD|Vectors#} | ||
| 8000 | {#header_close#} | ||
| 8001 | |||
| 7991 | {#header_open|@memcpy#} | 8002 | {#header_open|@memcpy#} |
| 7992 | <pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre> | 8003 | <pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre> |
| 7993 | <p> | 8004 | <p> |
| ... | @@ -8025,6 +8036,17 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre> | ... | @@ -8025,6 +8036,17 @@ mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre> |
| 8025 | mem.set(u8, dest, c);{#endsyntax#}</pre> | 8036 | mem.set(u8, dest, c);{#endsyntax#}</pre> |
| 8026 | {#header_close#} | 8037 | {#header_close#} |
| 8027 | 8038 | ||
| 8039 | {#header_open|@minimum#} | ||
| 8040 | <pre>{#syntax#}@minimum(a: T, b: T) T{#endsyntax#}</pre> | ||
| 8041 | <p> | ||
| 8042 | 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. | ||
| 8043 | </p> | ||
| 8044 | <p> | ||
| 8045 | 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. | ||
| 8046 | </p> | ||
| 8047 | {#see_also|@maximum|SIMD|Vectors#} | ||
| 8048 | {#header_close#} | ||
| 8049 | |||
| 8028 | {#header_open|@wasmMemorySize#} | 8050 | {#header_open|@wasmMemorySize#} |
| 8029 | <pre>{#syntax#}@wasmMemorySize(index: u32) u32{#endsyntax#}</pre> | 8051 | <pre>{#syntax#}@wasmMemorySize(index: u32) u32{#endsyntax#}</pre> |
| 8030 | <p> | 8052 | <p> |
src/AstGen.zig+21| ... | @@ -2098,8 +2098,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner | ... | @@ -2098,8 +2098,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner |
| 2098 | .builtin_call, | 2098 | .builtin_call, |
| 2099 | .field_ptr_type, | 2099 | .field_ptr_type, |
| 2100 | .field_parent_ptr, | 2100 | .field_parent_ptr, |
| 2101 | .maximum, | ||
| 2101 | .memcpy, | 2102 | .memcpy, |
| 2102 | .memset, | 2103 | .memset, |
| 2104 | .minimum, | ||
| 2103 | .builtin_async_call, | 2105 | .builtin_async_call, |
| 2104 | .c_import, | 2106 | .c_import, |
| 2105 | .@"resume", | 2107 | .@"resume", |
| ... | @@ -7227,6 +7229,25 @@ fn builtinCall( | ... | @@ -7227,6 +7229,25 @@ fn builtinCall( |
| 7227 | return rvalue(gz, rl, result, node); | 7229 | return rvalue(gz, rl, result, node); |
| 7228 | }, | 7230 | }, |
| 7229 | 7231 | ||
| 7232 | .maximum => { | ||
| 7233 | const a = try expr(gz, scope, .none, params[0]); | ||
| 7234 | const b = try expr(gz, scope, .none, params[1]); | ||
| 7235 | const result = try gz.addPlNode(.maximum, node, Zir.Inst.Bin{ | ||
| 7236 | .lhs = a, | ||
| 7237 | .rhs = b, | ||
| 7238 | }); | ||
| 7239 | return rvalue(gz, rl, result, node); | ||
| 7240 | }, | ||
| 7241 | .minimum => { | ||
| 7242 | const a = try expr(gz, scope, .none, params[0]); | ||
| 7243 | const b = try expr(gz, scope, .none, params[1]); | ||
| 7244 | const result = try gz.addPlNode(.minimum, node, Zir.Inst.Bin{ | ||
| 7245 | .lhs = a, | ||
| 7246 | .rhs = b, | ||
| 7247 | }); | ||
| 7248 | return rvalue(gz, rl, result, node); | ||
| 7249 | }, | ||
| 7250 | |||
| 7230 | .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), | 7251 | .add_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .add_with_overflow), |
| 7231 | .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), | 7252 | .sub_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .sub_with_overflow), |
| 7232 | .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), | 7253 | .mul_with_overflow => return overflowArithmetic(gz, scope, rl, node, params, .mul_with_overflow), |
src/BuiltinFn.zig+16| ... | @@ -57,8 +57,10 @@ pub const Tag = enum { | ... | @@ -57,8 +57,10 @@ pub const Tag = enum { |
| 57 | int_to_error, | 57 | int_to_error, |
| 58 | int_to_float, | 58 | int_to_float, |
| 59 | int_to_ptr, | 59 | int_to_ptr, |
| 60 | maximum, | ||
| 60 | memcpy, | 61 | memcpy, |
| 61 | memset, | 62 | memset, |
| 63 | minimum, | ||
| 62 | wasm_memory_size, | 64 | wasm_memory_size, |
| 63 | wasm_memory_grow, | 65 | wasm_memory_grow, |
| 64 | mod, | 66 | mod, |
| ... | @@ -518,6 +520,13 @@ pub const list = list: { | ... | @@ -518,6 +520,13 @@ pub const list = list: { |
| 518 | .param_count = 2, | 520 | .param_count = 2, |
| 519 | }, | 521 | }, |
| 520 | }, | 522 | }, |
| 523 | .{ | ||
| 524 | "@maximum", | ||
| 525 | .{ | ||
| 526 | .tag = .maximum, | ||
| 527 | .param_count = 2, | ||
| 528 | }, | ||
| 529 | }, | ||
| 521 | .{ | 530 | .{ |
| 522 | "@memcpy", | 531 | "@memcpy", |
| 523 | .{ | 532 | .{ |
| ... | @@ -532,6 +541,13 @@ pub const list = list: { | ... | @@ -532,6 +541,13 @@ pub const list = list: { |
| 532 | .param_count = 3, | 541 | .param_count = 3, |
| 533 | }, | 542 | }, |
| 534 | }, | 543 | }, |
| 544 | .{ | ||
| 545 | "@minimum", | ||
| 546 | .{ | ||
| 547 | .tag = .minimum, | ||
| 548 | .param_count = 2, | ||
| 549 | }, | ||
| 550 | }, | ||
| 535 | .{ | 551 | .{ |
| 536 | "@wasmMemorySize", | 552 | "@wasmMemorySize", |
| 537 | .{ | 553 | .{ |
src/Sema.zig+14| ... | @@ -346,8 +346,10 @@ pub fn analyzeBody( | ... | @@ -346,8 +346,10 @@ pub fn analyzeBody( |
| 346 | .builtin_call => try sema.zirBuiltinCall(block, inst), | 346 | .builtin_call => try sema.zirBuiltinCall(block, inst), |
| 347 | .field_ptr_type => try sema.zirFieldPtrType(block, inst), | 347 | .field_ptr_type => try sema.zirFieldPtrType(block, inst), |
| 348 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), | 348 | .field_parent_ptr => try sema.zirFieldParentPtr(block, inst), |
| 349 | .maximum => try sema.zirMaximum(block, inst), | ||
| 349 | .memcpy => try sema.zirMemcpy(block, inst), | 350 | .memcpy => try sema.zirMemcpy(block, inst), |
| 350 | .memset => try sema.zirMemset(block, inst), | 351 | .memset => try sema.zirMemset(block, inst), |
| 352 | .minimum => try sema.zirMinimum(block, inst), | ||
| 351 | .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), | 353 | .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst), |
| 352 | .@"resume" => try sema.zirResume(block, inst), | 354 | .@"resume" => try sema.zirResume(block, inst), |
| 353 | .@"await" => try sema.zirAwait(block, inst, false), | 355 | .@"await" => try sema.zirAwait(block, inst, false), |
| ... | @@ -6148,6 +6150,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Com | ... | @@ -6148,6 +6150,12 @@ fn zirFieldParentPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Com |
| 6148 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{}); | 6150 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldParentPtr", .{}); |
| 6149 | } | 6151 | } |
| 6150 | 6152 | ||
| 6153 | fn zirMaximum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 6154 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 6155 | const src = inst_data.src(); | ||
| 6156 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMaximum", .{}); | ||
| 6157 | } | ||
| 6158 | |||
| 6151 | fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6159 | fn zirMemcpy(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6152 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6160 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6153 | const src = inst_data.src(); | 6161 | const src = inst_data.src(); |
| ... | @@ -6160,6 +6168,12 @@ fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -6160,6 +6168,12 @@ fn zirMemset(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro |
| 6160 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{}); | 6168 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMemset", .{}); |
| 6161 | } | 6169 | } |
| 6162 | 6170 | ||
| 6171 | fn zirMinimum(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 6172 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | ||
| 6173 | const src = inst_data.src(); | ||
| 6174 | return sema.mod.fail(&block.base, src, "TODO: Sema.zirMinimum", .{}); | ||
| 6175 | } | ||
| 6176 | |||
| 6163 | fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6177 | fn zirBuiltinAsyncCall(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 6164 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 6178 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 6165 | const src = inst_data.src(); | 6179 | const src = inst_data.src(); |
src/Zir.zig+12| ... | @@ -915,12 +915,18 @@ pub const Inst = struct { | ... | @@ -915,12 +915,18 @@ pub const Inst = struct { |
| 915 | /// Implements the `@fieldParentPtr` builtin. | 915 | /// Implements the `@fieldParentPtr` builtin. |
| 916 | /// Uses the `pl_node` union field with payload `FieldParentPtr`. | 916 | /// Uses the `pl_node` union field with payload `FieldParentPtr`. |
| 917 | field_parent_ptr, | 917 | field_parent_ptr, |
| 918 | /// Implements the `@maximum` builtin. | ||
| 919 | /// Uses the `pl_node` union field with payload `Bin` | ||
| 920 | maximum, | ||
| 918 | /// Implements the `@memcpy` builtin. | 921 | /// Implements the `@memcpy` builtin. |
| 919 | /// Uses the `pl_node` union field with payload `Memcpy`. | 922 | /// Uses the `pl_node` union field with payload `Memcpy`. |
| 920 | memcpy, | 923 | memcpy, |
| 921 | /// Implements the `@memset` builtin. | 924 | /// Implements the `@memset` builtin. |
| 922 | /// Uses the `pl_node` union field with payload `Memset`. | 925 | /// Uses the `pl_node` union field with payload `Memset`. |
| 923 | memset, | 926 | memset, |
| 927 | /// Implements the `@minimum` builtin. | ||
| 928 | /// Uses the `pl_node` union field with payload `Bin` | ||
| 929 | minimum, | ||
| 924 | /// Implements the `@asyncCall` builtin. | 930 | /// Implements the `@asyncCall` builtin. |
| 925 | /// Uses the `pl_node` union field with payload `AsyncCall`. | 931 | /// Uses the `pl_node` union field with payload `AsyncCall`. |
| 926 | builtin_async_call, | 932 | builtin_async_call, |
| ... | @@ -1192,8 +1198,10 @@ pub const Inst = struct { | ... | @@ -1192,8 +1198,10 @@ pub const Inst = struct { |
| 1192 | .builtin_call, | 1198 | .builtin_call, |
| 1193 | .field_ptr_type, | 1199 | .field_ptr_type, |
| 1194 | .field_parent_ptr, | 1200 | .field_parent_ptr, |
| 1201 | .maximum, | ||
| 1195 | .memcpy, | 1202 | .memcpy, |
| 1196 | .memset, | 1203 | .memset, |
| 1204 | .minimum, | ||
| 1197 | .builtin_async_call, | 1205 | .builtin_async_call, |
| 1198 | .c_import, | 1206 | .c_import, |
| 1199 | .@"resume", | 1207 | .@"resume", |
| ... | @@ -1463,8 +1471,10 @@ pub const Inst = struct { | ... | @@ -1463,8 +1471,10 @@ pub const Inst = struct { |
| 1463 | .builtin_call = .pl_node, | 1471 | .builtin_call = .pl_node, |
| 1464 | .field_ptr_type = .bin, | 1472 | .field_ptr_type = .bin, |
| 1465 | .field_parent_ptr = .pl_node, | 1473 | .field_parent_ptr = .pl_node, |
| 1474 | .maximum = .pl_node, | ||
| 1466 | .memcpy = .pl_node, | 1475 | .memcpy = .pl_node, |
| 1467 | .memset = .pl_node, | 1476 | .memset = .pl_node, |
| 1477 | .minimum = .pl_node, | ||
| 1468 | .builtin_async_call = .pl_node, | 1478 | .builtin_async_call = .pl_node, |
| 1469 | .c_import = .pl_node, | 1479 | .c_import = .pl_node, |
| 1470 | 1480 | ||
| ... | @@ -3020,6 +3030,8 @@ const Writer = struct { | ... | @@ -3020,6 +3030,8 @@ const Writer = struct { |
| 3020 | .bitcast, | 3030 | .bitcast, |
| 3021 | .bitcast_result_ptr, | 3031 | .bitcast_result_ptr, |
| 3022 | .vector_type, | 3032 | .vector_type, |
| 3033 | .maximum, | ||
| 3034 | .minimum, | ||
| 3023 | => try self.writePlNodeBin(stream, inst), | 3035 | => try self.writePlNodeBin(stream, inst), |
| 3024 | 3036 | ||
| 3025 | .@"export" => try self.writePlNodeExport(stream, inst), | 3037 | .@"export" => try self.writePlNodeExport(stream, inst), |
src/stage1/all_types.hpp+4| ... | @@ -1796,6 +1796,8 @@ enum BuiltinFnId { | ... | @@ -1796,6 +1796,8 @@ enum BuiltinFnId { |
| 1796 | BuiltinFnIdWasmMemoryGrow, | 1796 | BuiltinFnIdWasmMemoryGrow, |
| 1797 | BuiltinFnIdSrc, | 1797 | BuiltinFnIdSrc, |
| 1798 | BuiltinFnIdReduce, | 1798 | BuiltinFnIdReduce, |
| 1799 | BuiltinFnIdMaximum, | ||
| 1800 | BuiltinFnIdMinimum, | ||
| 1799 | }; | 1801 | }; |
| 1800 | 1802 | ||
| 1801 | struct BuiltinFnEntry { | 1803 | struct BuiltinFnEntry { |
| ... | @@ -2938,6 +2940,8 @@ enum IrBinOp { | ... | @@ -2938,6 +2940,8 @@ enum IrBinOp { |
| 2938 | IrBinOpRemMod, | 2940 | IrBinOpRemMod, |
| 2939 | IrBinOpArrayCat, | 2941 | IrBinOpArrayCat, |
| 2940 | IrBinOpArrayMult, | 2942 | IrBinOpArrayMult, |
| 2943 | IrBinOpMaximum, | ||
| 2944 | IrBinOpMinimum, | ||
| 2941 | }; | 2945 | }; |
| 2942 | 2946 | ||
| 2943 | struct Stage1ZirInstBinOp { | 2947 | struct Stage1ZirInstBinOp { |
src/stage1/astgen.cpp+30| ... | @@ -4686,6 +4686,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast | ... | @@ -4686,6 +4686,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast |
| 4686 | arg0_value, arg1_value); | 4686 | arg0_value, arg1_value); |
| 4687 | return ir_lval_wrap(ag, scope, splat, lval, result_loc); | 4687 | return ir_lval_wrap(ag, scope, splat, lval, result_loc); |
| 4688 | } | 4688 | } |
| 4689 | case BuiltinFnIdMaximum: | ||
| 4690 | { | ||
| 4691 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4692 | Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); | ||
| 4693 | if (arg0_value == ag->codegen->invalid_inst_src) | ||
| 4694 | return arg0_value; | ||
| 4695 | |||
| 4696 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4697 | Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); | ||
| 4698 | if (arg1_value == ag->codegen->invalid_inst_src) | ||
| 4699 | return arg1_value; | ||
| 4700 | |||
| 4701 | Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMaximum, arg0_value, arg1_value, true); | ||
| 4702 | return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); | ||
| 4703 | } | ||
| 4689 | case BuiltinFnIdMemcpy: | 4704 | case BuiltinFnIdMemcpy: |
| 4690 | { | 4705 | { |
| 4691 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4706 | 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 | ... | @@ -4726,6 +4741,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast |
| 4726 | Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value); | 4741 | Stage1ZirInst *ir_memset = ir_build_memset_src(ag, scope, node, arg0_value, arg1_value, arg2_value); |
| 4727 | return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc); | 4742 | return ir_lval_wrap(ag, scope, ir_memset, lval, result_loc); |
| 4728 | } | 4743 | } |
| 4744 | case BuiltinFnIdMinimum: | ||
| 4745 | { | ||
| 4746 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 4747 | Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope); | ||
| 4748 | if (arg0_value == ag->codegen->invalid_inst_src) | ||
| 4749 | return arg0_value; | ||
| 4750 | |||
| 4751 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 4752 | Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope); | ||
| 4753 | if (arg1_value == ag->codegen->invalid_inst_src) | ||
| 4754 | return arg1_value; | ||
| 4755 | |||
| 4756 | Stage1ZirInst *bin_op = ir_build_bin_op(ag, scope, node, IrBinOpMinimum, arg0_value, arg1_value, true); | ||
| 4757 | return ir_lval_wrap(ag, scope, bin_op, lval, result_loc); | ||
| 4758 | } | ||
| 4729 | case BuiltinFnIdWasmMemorySize: | 4759 | case BuiltinFnIdWasmMemorySize: |
| 4730 | { | 4760 | { |
| 4731 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 4761 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
src/stage1/bigfloat.cpp+24| ... | @@ -191,6 +191,30 @@ void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { | ... | @@ -191,6 +191,30 @@ void bigfloat_sqrt(BigFloat *dest, const BigFloat *op) { |
| 191 | f128M_sqrt(&op->value, &dest->value); | 191 | f128M_sqrt(&op->value, &dest->value); |
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | ||
| 195 | if (bigfloat_is_nan(op1)) { | ||
| 196 | bigfloat_init_bigfloat(dest, op2); | ||
| 197 | } else if (bigfloat_is_nan(op2)) { | ||
| 198 | bigfloat_init_bigfloat(dest, op1); | ||
| 199 | } else if (f128M_lt(&op1->value, &op2->value)) { | ||
| 200 | bigfloat_init_bigfloat(dest, op1); | ||
| 201 | } else { | ||
| 202 | bigfloat_init_bigfloat(dest, op2); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { | ||
| 207 | if (bigfloat_is_nan(op1)) { | ||
| 208 | bigfloat_init_bigfloat(dest, op2); | ||
| 209 | } else if (bigfloat_is_nan(op2)) { | ||
| 210 | bigfloat_init_bigfloat(dest, op1); | ||
| 211 | } else if (f128M_lt(&op1->value, &op2->value)) { | ||
| 212 | bigfloat_init_bigfloat(dest, op2); | ||
| 213 | } else { | ||
| 214 | bigfloat_init_bigfloat(dest, op1); | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 194 | bool bigfloat_is_nan(const BigFloat *op) { | 218 | bool bigfloat_is_nan(const BigFloat *op) { |
| 195 | return f128M_isSignalingNaN(&op->value); | 219 | return f128M_isSignalingNaN(&op->value); |
| 196 | } | 220 | } |
src/stage1/bigfloat.hpp+3| ... | @@ -45,9 +45,12 @@ void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2 | ... | @@ -45,9 +45,12 @@ void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2 |
| 45 | void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | 45 | void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); |
| 46 | void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | 46 | void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); |
| 47 | void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); | 47 | void bigfloat_sqrt(BigFloat *dest, const BigFloat *op); |
| 48 | void bigfloat_min(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | ||
| 49 | void bigfloat_max(BigFloat *dest, const BigFloat *op1, const BigFloat *op2); | ||
| 48 | void bigfloat_append_buf(Buf *buf, const BigFloat *op); | 50 | void bigfloat_append_buf(Buf *buf, const BigFloat *op); |
| 49 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); | 51 | Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2); |
| 50 | 52 | ||
| 53 | |||
| 51 | bool bigfloat_is_nan(const BigFloat *op); | 54 | bool bigfloat_is_nan(const BigFloat *op); |
| 52 | 55 | ||
| 53 | // convenience functions | 56 | // convenience functions |
src/stage1/bigint.cpp+20| ... | @@ -448,6 +448,26 @@ bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { | ... | @@ -448,6 +448,26 @@ bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result) { |
| 448 | } | 448 | } |
| 449 | #endif | 449 | #endif |
| 450 | 450 | ||
| 451 | void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2) { | ||
| 452 | switch (bigint_cmp(op1, op2)) { | ||
| 453 | case CmpEQ: | ||
| 454 | case CmpLT: | ||
| 455 | return bigint_init_bigint(dest, op2); | ||
| 456 | case CmpGT: | ||
| 457 | return bigint_init_bigint(dest, op1); | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) { | ||
| 462 | switch (bigint_cmp(op1, op2)) { | ||
| 463 | case CmpEQ: | ||
| 464 | case CmpLT: | ||
| 465 | return bigint_init_bigint(dest, op1); | ||
| 466 | case CmpGT: | ||
| 467 | return bigint_init_bigint(dest, op2); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 451 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { | 471 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { |
| 452 | if (op1->digit_count == 0) { | 472 | if (op1->digit_count == 0) { |
| 453 | return bigint_init_bigint(dest, op2); | 473 | return bigint_init_bigint(dest, op2); |
src/stage1/bigint.hpp+2| ... | @@ -56,6 +56,8 @@ bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed); | ... | @@ -56,6 +56,8 @@ bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed); |
| 56 | void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); | 56 | void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian); |
| 57 | void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, | 57 | void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian, |
| 58 | bool is_signed); | 58 | bool is_signed); |
| 59 | void bigint_max(BigInt* dest, const BigInt *op1, const BigInt *op2); | ||
| 60 | void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2); | ||
| 59 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); | 61 | void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 60 | void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); | 62 | void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed); |
| 61 | void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); | 63 | void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2); |
src/stage1/codegen.cpp+26| ... | @@ -3248,6 +3248,30 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, | ... | @@ -3248,6 +3248,30 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, Stage1Air *executable, |
| 3248 | case IrBinOpRemMod: | 3248 | case IrBinOpRemMod: |
| 3249 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), | 3249 | return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 3250 | op1_value, op2_value, operand_type, RemKindMod); | 3250 | op1_value, op2_value, operand_type, RemKindMod); |
| 3251 | case IrBinOpMaximum: | ||
| 3252 | if (scalar_type->id == ZigTypeIdFloat) { | ||
| 3253 | return ZigLLVMBuildMaxNum(g->builder, op1_value, op2_value, ""); | ||
| 3254 | } else if (scalar_type->id == ZigTypeIdInt) { | ||
| 3255 | if (scalar_type->data.integral.is_signed) { | ||
| 3256 | return ZigLLVMBuildSMax(g->builder, op1_value, op2_value, ""); | ||
| 3257 | } else { | ||
| 3258 | return ZigLLVMBuildUMax(g->builder, op1_value, op2_value, ""); | ||
| 3259 | } | ||
| 3260 | } else { | ||
| 3261 | zig_unreachable(); | ||
| 3262 | } | ||
| 3263 | case IrBinOpMinimum: | ||
| 3264 | if (scalar_type->id == ZigTypeIdFloat) { | ||
| 3265 | return ZigLLVMBuildMinNum(g->builder, op1_value, op2_value, ""); | ||
| 3266 | } else if (scalar_type->id == ZigTypeIdInt) { | ||
| 3267 | if (scalar_type->data.integral.is_signed) { | ||
| 3268 | return ZigLLVMBuildSMin(g->builder, op1_value, op2_value, ""); | ||
| 3269 | } else { | ||
| 3270 | return ZigLLVMBuildUMin(g->builder, op1_value, op2_value, ""); | ||
| 3271 | } | ||
| 3272 | } else { | ||
| 3273 | zig_unreachable(); | ||
| 3274 | } | ||
| 3251 | } | 3275 | } |
| 3252 | zig_unreachable(); | 3276 | zig_unreachable(); |
| 3253 | } | 3277 | } |
| ... | @@ -8990,6 +9014,8 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -8990,6 +9014,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 8990 | create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2); | 9014 | create_builtin_fn(g, BuiltinFnIdWasmMemoryGrow, "wasmMemoryGrow", 2); |
| 8991 | create_builtin_fn(g, BuiltinFnIdSrc, "src", 0); | 9015 | create_builtin_fn(g, BuiltinFnIdSrc, "src", 0); |
| 8992 | create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); | 9016 | create_builtin_fn(g, BuiltinFnIdReduce, "reduce", 2); |
| 9017 | create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2); | ||
| 9018 | create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2); | ||
| 8993 | } | 9019 | } |
| 8994 | 9020 | ||
| 8995 | static const char *bool_to_str(bool b) { | 9021 | static const char *bool_to_str(bool b) { |
src/stage1/ir.cpp+120| ... | @@ -3311,6 +3311,108 @@ static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { | ... | @@ -3311,6 +3311,108 @@ static void float_mod(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { |
| 3311 | } | 3311 | } |
| 3312 | } | 3312 | } |
| 3313 | 3313 | ||
| 3314 | static void float_max(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { | ||
| 3315 | assert(op1->type == op2->type); | ||
| 3316 | out_val->type = op1->type; | ||
| 3317 | if (op1->type->id == ZigTypeIdComptimeFloat) { | ||
| 3318 | bigfloat_max(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); | ||
| 3319 | } else if (op1->type->id == ZigTypeIdFloat) { | ||
| 3320 | switch (op1->type->data.floating.bit_count) { | ||
| 3321 | case 16: | ||
| 3322 | if (zig_f16_isNaN(op1->data.x_f16)) { | ||
| 3323 | out_val->data.x_f16 = op2->data.x_f16; | ||
| 3324 | } else if (zig_f16_isNaN(op2->data.x_f16)) { | ||
| 3325 | out_val->data.x_f16 = op1->data.x_f16; | ||
| 3326 | } else { | ||
| 3327 | out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op2->data.x_f16 : op1->data.x_f16; | ||
| 3328 | } | ||
| 3329 | return; | ||
| 3330 | case 32: | ||
| 3331 | if (op1->data.x_f32 != op1->data.x_f32) { | ||
| 3332 | out_val->data.x_f32 = op2->data.x_f32; | ||
| 3333 | } else if (op2->data.x_f32 != op2->data.x_f32) { | ||
| 3334 | out_val->data.x_f32 = op1->data.x_f32; | ||
| 3335 | } else { | ||
| 3336 | out_val->data.x_f32 = op1->data.x_f32 > op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; | ||
| 3337 | } | ||
| 3338 | return; | ||
| 3339 | case 64: | ||
| 3340 | if (op1->data.x_f64 != op1->data.x_f64) { | ||
| 3341 | out_val->data.x_f64 = op2->data.x_f64; | ||
| 3342 | } else if (op2->data.x_f64 != op2->data.x_f64) { | ||
| 3343 | out_val->data.x_f64 = op1->data.x_f64; | ||
| 3344 | } else { | ||
| 3345 | out_val->data.x_f64 = op1->data.x_f64 > op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; | ||
| 3346 | } | ||
| 3347 | return; | ||
| 3348 | case 128: | ||
| 3349 | if (zig_f128_isNaN(&op1->data.x_f128)) { | ||
| 3350 | out_val->data.x_f128 = op2->data.x_f128; | ||
| 3351 | } else if (zig_f128_isNaN(&op2->data.x_f128)) { | ||
| 3352 | out_val->data.x_f128 = op1->data.x_f128; | ||
| 3353 | } else { | ||
| 3354 | out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op2->data.x_f128 : op1->data.x_f128; | ||
| 3355 | } | ||
| 3356 | return; | ||
| 3357 | default: | ||
| 3358 | zig_unreachable(); | ||
| 3359 | } | ||
| 3360 | } else { | ||
| 3361 | zig_unreachable(); | ||
| 3362 | } | ||
| 3363 | } | ||
| 3364 | |||
| 3365 | static void float_min(ZigValue *out_val, ZigValue *op1, ZigValue *op2) { | ||
| 3366 | assert(op1->type == op2->type); | ||
| 3367 | out_val->type = op1->type; | ||
| 3368 | if (op1->type->id == ZigTypeIdComptimeFloat) { | ||
| 3369 | bigfloat_min(&out_val->data.x_bigfloat, &op1->data.x_bigfloat, &op2->data.x_bigfloat); | ||
| 3370 | } else if (op1->type->id == ZigTypeIdFloat) { | ||
| 3371 | switch (op1->type->data.floating.bit_count) { | ||
| 3372 | case 16: | ||
| 3373 | if (zig_f16_isNaN(op1->data.x_f16)) { | ||
| 3374 | out_val->data.x_f16 = op2->data.x_f16; | ||
| 3375 | } else if (zig_f16_isNaN(op2->data.x_f16)) { | ||
| 3376 | out_val->data.x_f16 = op1->data.x_f16; | ||
| 3377 | } else { | ||
| 3378 | out_val->data.x_f16 = f16_lt(op1->data.x_f16, op2->data.x_f16) ? op1->data.x_f16 : op2->data.x_f16; | ||
| 3379 | } | ||
| 3380 | return; | ||
| 3381 | case 32: | ||
| 3382 | if (op1->data.x_f32 != op1->data.x_f32) { | ||
| 3383 | out_val->data.x_f32 = op2->data.x_f32; | ||
| 3384 | } else if (op2->data.x_f32 != op2->data.x_f32) { | ||
| 3385 | out_val->data.x_f32 = op1->data.x_f32; | ||
| 3386 | } else { | ||
| 3387 | out_val->data.x_f32 = op1->data.x_f32 < op2->data.x_f32 ? op1->data.x_f32 : op2->data.x_f32; | ||
| 3388 | } | ||
| 3389 | return; | ||
| 3390 | case 64: | ||
| 3391 | if (op1->data.x_f64 != op1->data.x_f64) { | ||
| 3392 | out_val->data.x_f64 = op2->data.x_f64; | ||
| 3393 | } else if (op2->data.x_f64 != op2->data.x_f64) { | ||
| 3394 | out_val->data.x_f64 = op1->data.x_f64; | ||
| 3395 | } else { | ||
| 3396 | out_val->data.x_f64 = op1->data.x_f32 < op2->data.x_f64 ? op1->data.x_f64 : op2->data.x_f64; | ||
| 3397 | } | ||
| 3398 | return; | ||
| 3399 | case 128: | ||
| 3400 | if (zig_f128_isNaN(&op1->data.x_f128)) { | ||
| 3401 | out_val->data.x_f128 = op2->data.x_f128; | ||
| 3402 | } else if (zig_f128_isNaN(&op2->data.x_f128)) { | ||
| 3403 | out_val->data.x_f128 = op1->data.x_f128; | ||
| 3404 | } else { | ||
| 3405 | out_val->data.x_f128 = f128M_lt(&op1->data.x_f128, &op2->data.x_f128) ? op1->data.x_f128 : op2->data.x_f128; | ||
| 3406 | } | ||
| 3407 | return; | ||
| 3408 | default: | ||
| 3409 | zig_unreachable(); | ||
| 3410 | } | ||
| 3411 | } else { | ||
| 3412 | zig_unreachable(); | ||
| 3413 | } | ||
| 3414 | } | ||
| 3415 | |||
| 3314 | static void float_negate(ZigValue *out_val, ZigValue *op) { | 3416 | static void float_negate(ZigValue *out_val, ZigValue *op) { |
| 3315 | out_val->type = op->type; | 3417 | out_val->type = op->type; |
| 3316 | if (op->type->id == ZigTypeIdComptimeFloat) { | 3418 | if (op->type->id == ZigTypeIdComptimeFloat) { |
| ... | @@ -9704,6 +9806,20 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s | ... | @@ -9704,6 +9806,20 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, Scope *scope, AstNode *s |
| 9704 | float_mod(out_val, op1_val, op2_val); | 9806 | float_mod(out_val, op1_val, op2_val); |
| 9705 | } | 9807 | } |
| 9706 | break; | 9808 | break; |
| 9809 | case IrBinOpMaximum: | ||
| 9810 | if (is_int) { | ||
| 9811 | bigint_max(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | ||
| 9812 | } else { | ||
| 9813 | float_max(out_val, op1_val, op2_val); | ||
| 9814 | } | ||
| 9815 | break; | ||
| 9816 | case IrBinOpMinimum: | ||
| 9817 | if (is_int) { | ||
| 9818 | bigint_min(&out_val->data.x_bigint, &op1_val->data.x_bigint, &op2_val->data.x_bigint); | ||
| 9819 | } else { | ||
| 9820 | float_min(out_val, op1_val, op2_val); | ||
| 9821 | } | ||
| 9822 | break; | ||
| 9707 | } | 9823 | } |
| 9708 | 9824 | ||
| 9709 | if (type_entry->id == ZigTypeIdInt) { | 9825 | if (type_entry->id == ZigTypeIdInt) { |
| ... | @@ -9904,6 +10020,8 @@ static bool ok_float_op(IrBinOp op) { | ... | @@ -9904,6 +10020,8 @@ static bool ok_float_op(IrBinOp op) { |
| 9904 | case IrBinOpRemRem: | 10020 | case IrBinOpRemRem: |
| 9905 | case IrBinOpRemMod: | 10021 | case IrBinOpRemMod: |
| 9906 | case IrBinOpRemUnspecified: | 10022 | case IrBinOpRemUnspecified: |
| 10023 | case IrBinOpMaximum: | ||
| 10024 | case IrBinOpMinimum: | ||
| 9907 | return true; | 10025 | return true; |
| 9908 | 10026 | ||
| 9909 | case IrBinOpBoolOr: | 10027 | case IrBinOpBoolOr: |
| ... | @@ -10894,6 +11012,8 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns | ... | @@ -10894,6 +11012,8 @@ static Stage1AirInst *ir_analyze_instruction_bin_op(IrAnalyze *ira, Stage1ZirIns |
| 10894 | case IrBinOpRemUnspecified: | 11012 | case IrBinOpRemUnspecified: |
| 10895 | case IrBinOpRemRem: | 11013 | case IrBinOpRemRem: |
| 10896 | case IrBinOpRemMod: | 11014 | case IrBinOpRemMod: |
| 11015 | case IrBinOpMaximum: | ||
| 11016 | case IrBinOpMinimum: | ||
| 10897 | return ir_analyze_bin_op_math(ira, bin_op_instruction); | 11017 | return ir_analyze_bin_op_math(ira, bin_op_instruction); |
| 10898 | case IrBinOpArrayCat: | 11018 | case IrBinOpArrayCat: |
| 10899 | return ir_analyze_array_cat(ira, bin_op_instruction); | 11019 | return ir_analyze_array_cat(ira, bin_op_instruction); |
src/stage1/ir_print.cpp+4| ... | @@ -733,6 +733,10 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { | ... | @@ -733,6 +733,10 @@ static const char *ir_bin_op_id_str(IrBinOp op_id) { |
| 733 | return "++"; | 733 | return "++"; |
| 734 | case IrBinOpArrayMult: | 734 | case IrBinOpArrayMult: |
| 735 | return "**"; | 735 | return "**"; |
| 736 | case IrBinOpMaximum: | ||
| 737 | return "@maximum"; | ||
| 738 | case IrBinOpMinimum: | ||
| 739 | return "@minimum"; | ||
| 736 | } | 740 | } |
| 737 | zig_unreachable(); | 741 | zig_unreachable(); |
| 738 | } | 742 | } |
src/zig_llvm.cpp+30| ... | @@ -458,6 +458,36 @@ LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef | ... | @@ -458,6 +458,36 @@ LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef |
| 458 | return wrap(call_inst); | 458 | return wrap(call_inst); |
| 459 | } | 459 | } |
| 460 | 460 | ||
| 461 | LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 462 | CallInst *call_inst = unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS), name); | ||
| 463 | return wrap(call_inst); | ||
| 464 | } | ||
| 465 | |||
| 466 | LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 467 | CallInst *call_inst = unwrap(B)->CreateMinNum(unwrap(LHS), unwrap(RHS), name); | ||
| 468 | return wrap(call_inst); | ||
| 469 | } | ||
| 470 | |||
| 471 | LLVMValueRef ZigLLVMBuildUMax(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 472 | CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::umax, unwrap(LHS), unwrap(RHS), nullptr, name); | ||
| 473 | return wrap(call_inst); | ||
| 474 | } | ||
| 475 | |||
| 476 | LLVMValueRef ZigLLVMBuildUMin(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 477 | CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::umin, unwrap(LHS), unwrap(RHS), nullptr, name); | ||
| 478 | return wrap(call_inst); | ||
| 479 | } | ||
| 480 | |||
| 481 | LLVMValueRef ZigLLVMBuildSMax(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 482 | CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::smax, unwrap(LHS), unwrap(RHS), nullptr, name); | ||
| 483 | return wrap(call_inst); | ||
| 484 | } | ||
| 485 | |||
| 486 | LLVMValueRef ZigLLVMBuildSMin(LLVMBuilderRef B, LLVMValueRef LHS, LLVMValueRef RHS, const char *name) { | ||
| 487 | CallInst *call_inst = unwrap(B)->CreateBinaryIntrinsic(Intrinsic::smin, unwrap(LHS), unwrap(RHS), nullptr, name); | ||
| 488 | return wrap(call_inst); | ||
| 489 | } | ||
| 490 | |||
| 461 | void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) { | 491 | void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) { |
| 462 | assert( isa<Function>(unwrap(fn)) ); | 492 | assert( isa<Function>(unwrap(fn)) ); |
| 463 | Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn)); | 493 | Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn)); |
src/zig_llvm.h+9| ... | @@ -129,6 +129,14 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, | ... | @@ -129,6 +129,14 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, |
| 129 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size, | 129 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size, |
| 130 | unsigned Align, bool isVolatile); | 130 | unsigned Align, bool isVolatile); |
| 131 | 131 | ||
| 132 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMaxNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 133 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMinNum(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 134 | |||
| 135 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildUMax(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 136 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildUMin(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 137 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSMax(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 138 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildSMin(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, const char* name); | ||
| 139 | |||
| 132 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | 140 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, |
| 133 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | 141 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, |
| 134 | LLVMAtomicOrdering failure_ordering, bool is_weak); | 142 | LLVMAtomicOrdering failure_ordering, bool is_weak); |
| ... | @@ -142,6 +150,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu | ... | @@ -142,6 +150,7 @@ ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValu |
| 142 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | 150 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, |
| 143 | const char *name); | 151 | const char *name); |
| 144 | 152 | ||
| 153 | |||
| 145 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder, | 154 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder, |
| 146 | struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name); | 155 | struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name); |
| 147 | 156 |
test/behavior.zig+1| ... | @@ -105,6 +105,7 @@ test { | ... | @@ -105,6 +105,7 @@ test { |
| 105 | _ = @import("behavior/inttoptr.zig"); | 105 | _ = @import("behavior/inttoptr.zig"); |
| 106 | _ = @import("behavior/ir_block_deps.zig"); | 106 | _ = @import("behavior/ir_block_deps.zig"); |
| 107 | _ = @import("behavior/math.zig"); | 107 | _ = @import("behavior/math.zig"); |
| 108 | _ = @import("behavior/maximum_minimum.zig"); | ||
| 108 | _ = @import("behavior/merge_error_sets.zig"); | 109 | _ = @import("behavior/merge_error_sets.zig"); |
| 109 | _ = @import("behavior/misc.zig"); | 110 | _ = @import("behavior/misc.zig"); |
| 110 | _ = @import("behavior/muladd.zig"); | 111 | _ = @import("behavior/muladd.zig"); |
test/behavior/maximum_minimum.zig created+58| ... | @@ -0,0 +1,58 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const mem = std.mem; | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const expectEqual = std.testing.expectEqual; | ||
| 6 | const Vector = std.meta.Vector; | ||
| 7 | |||
| 8 | test "@maximum" { | ||
| 9 | const S = struct { | ||
| 10 | fn doTheTest() !void { | ||
| 11 | try expectEqual(@as(i32, 10), @maximum(@as(i32, -3), @as(i32, 10))); | ||
| 12 | try expectEqual(@as(f32, 3.2), @maximum(@as(f32, 3.2), @as(f32, 0.68))); | ||
| 13 | |||
| 14 | var a: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 15 | var b: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 16 | var x = @maximum(a, b); | ||
| 17 | try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 2147483647, 2147483647, 30, 40 })); | ||
| 18 | |||
| 19 | var c: Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 }; | ||
| 20 | var d: Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 }; | ||
| 21 | var y = @maximum(c, d); | ||
| 22 | try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ 0, 0.42, -0.64, 7.8 })); | ||
| 23 | |||
| 24 | var e: Vector(2, f32) = [2]f32{ 0, std.math.qnan_f32 }; | ||
| 25 | var f: Vector(2, f32) = [2]f32{ std.math.qnan_f32, 0 }; | ||
| 26 | var z = @maximum(e, f); | ||
| 27 | try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 })); | ||
| 28 | } | ||
| 29 | }; | ||
| 30 | try S.doTheTest(); | ||
| 31 | comptime try S.doTheTest(); | ||
| 32 | } | ||
| 33 | |||
| 34 | test "@minimum" { | ||
| 35 | const S = struct { | ||
| 36 | fn doTheTest() !void { | ||
| 37 | try expectEqual(@as(i32, -3), @minimum(@as(i32, -3), @as(i32, 10))); | ||
| 38 | try expectEqual(@as(f32, 0.68), @minimum(@as(f32, 3.2), @as(f32, 0.68))); | ||
| 39 | |||
| 40 | var a: Vector(4, i32) = [4]i32{ 2147483647, -2, 30, 40 }; | ||
| 41 | var b: Vector(4, i32) = [4]i32{ 1, 2147483647, 3, 4 }; | ||
| 42 | var x = @minimum(a, b); | ||
| 43 | try expect(mem.eql(i32, &@as([4]i32, x), &[4]i32{ 1, -2, 3, 4 })); | ||
| 44 | |||
| 45 | var c: Vector(4, f32) = [4]f32{ 0, 0.4, -2.4, 7.8 }; | ||
| 46 | var d: Vector(4, f32) = [4]f32{ -0.23, 0.42, -0.64, 0.9 }; | ||
| 47 | var y = @minimum(c, d); | ||
| 48 | try expect(mem.eql(f32, &@as([4]f32, y), &[4]f32{ -0.23, 0.4, -2.4, 0.9 })); | ||
| 49 | |||
| 50 | var e: Vector(2, f32) = [2]f32{ 0, std.math.qnan_f32 }; | ||
| 51 | var f: Vector(2, f32) = [2]f32{ std.math.qnan_f32, 0 }; | ||
| 52 | var z = @maximum(e, f); | ||
| 53 | try expect(mem.eql(f32, &@as([2]f32, z), &[2]f32{ 0, 0 })); | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | try S.doTheTest(); | ||
| 57 | comptime try S.doTheTest(); | ||
| 58 | } | ||