| author | |
| committer | |
| log | 29b488245daa9210ed9b5e1ffb7290024677f0db |
| tree | 7bcee7504f7caa5f72c8d83bbf066aa494306a70 |
| parent | 051ee8e626111445c27d6c868cb0cdec6df7409e |
* skip installing std/rand_test.zig as it's not needed beyond running
the std lib tests
* add std.math.floor function
* add setFloatMode builtin function to choose between
builtin.FloatMode.Optimized (default) and builtin.FloatMode.Strict
(Optimized is equivalent to -ffast-math in gcc)8 files changed, 328 insertions(+), 24 deletions(-)
CMakeLists.txt-1| ... | @@ -232,7 +232,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_S | ... | @@ -232,7 +232,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_S |
| 232 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os") | 232 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 233 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os") | 233 | install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os") |
| 234 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") | 234 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") |
| 235 | install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}") | ||
| 236 | install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") | 235 | install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") |
| 237 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special") | 236 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special") |
| 238 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special") | 237 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special") |
src/all_types.hpp+18| ... | @@ -1193,6 +1193,7 @@ enum BuiltinFnId { | ... | @@ -1193,6 +1193,7 @@ enum BuiltinFnId { |
| 1193 | BuiltinFnIdTruncate, | 1193 | BuiltinFnIdTruncate, |
| 1194 | BuiltinFnIdIntType, | 1194 | BuiltinFnIdIntType, |
| 1195 | BuiltinFnIdSetDebugSafety, | 1195 | BuiltinFnIdSetDebugSafety, |
| 1196 | BuiltinFnIdSetFloatMode, | ||
| 1196 | BuiltinFnIdTypeName, | 1197 | BuiltinFnIdTypeName, |
| 1197 | BuiltinFnIdCanImplicitCast, | 1198 | BuiltinFnIdCanImplicitCast, |
| 1198 | BuiltinFnIdSetGlobalAlign, | 1199 | BuiltinFnIdSetGlobalAlign, |
| ... | @@ -1580,6 +1581,8 @@ struct ScopeDecls { | ... | @@ -1580,6 +1581,8 @@ struct ScopeDecls { |
| 1580 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table; | 1581 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table; |
| 1581 | bool safety_off; | 1582 | bool safety_off; |
| 1582 | AstNode *safety_set_node; | 1583 | AstNode *safety_set_node; |
| 1584 | bool fast_math_off; | ||
| 1585 | AstNode *fast_math_set_node; | ||
| 1583 | ImportTableEntry *import; | 1586 | ImportTableEntry *import; |
| 1584 | // If this is a scope from a container, this is the type entry, otherwise null | 1587 | // If this is a scope from a container, this is the type entry, otherwise null |
| 1585 | TypeTableEntry *container_type; | 1588 | TypeTableEntry *container_type; |
| ... | @@ -1593,6 +1596,8 @@ struct ScopeBlock { | ... | @@ -1593,6 +1596,8 @@ struct ScopeBlock { |
| 1593 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; | 1596 | HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; |
| 1594 | bool safety_off; | 1597 | bool safety_off; |
| 1595 | AstNode *safety_set_node; | 1598 | AstNode *safety_set_node; |
| 1599 | bool fast_math_off; | ||
| 1600 | AstNode *fast_math_set_node; | ||
| 1596 | }; | 1601 | }; |
| 1597 | 1602 | ||
| 1598 | // This scope is created from every defer expression. | 1603 | // This scope is created from every defer expression. |
| ... | @@ -1720,6 +1725,7 @@ enum IrInstructionId { | ... | @@ -1720,6 +1725,7 @@ enum IrInstructionId { |
| 1720 | IrInstructionIdToPtrType, | 1725 | IrInstructionIdToPtrType, |
| 1721 | IrInstructionIdPtrTypeChild, | 1726 | IrInstructionIdPtrTypeChild, |
| 1722 | IrInstructionIdSetDebugSafety, | 1727 | IrInstructionIdSetDebugSafety, |
| 1728 | IrInstructionIdSetFloatMode, | ||
| 1723 | IrInstructionIdArrayType, | 1729 | IrInstructionIdArrayType, |
| 1724 | IrInstructionIdSliceType, | 1730 | IrInstructionIdSliceType, |
| 1725 | IrInstructionIdAsm, | 1731 | IrInstructionIdAsm, |
| ... | @@ -2078,6 +2084,13 @@ struct IrInstructionSetDebugSafety { | ... | @@ -2078,6 +2084,13 @@ struct IrInstructionSetDebugSafety { |
| 2078 | IrInstruction *debug_safety_on; | 2084 | IrInstruction *debug_safety_on; |
| 2079 | }; | 2085 | }; |
| 2080 | 2086 | ||
| 2087 | struct IrInstructionSetFloatMode { | ||
| 2088 | IrInstruction base; | ||
| 2089 | |||
| 2090 | IrInstruction *scope_value; | ||
| 2091 | IrInstruction *mode_value; | ||
| 2092 | }; | ||
| 2093 | |||
| 2081 | struct IrInstructionArrayType { | 2094 | struct IrInstructionArrayType { |
| 2082 | IrInstruction base; | 2095 | IrInstruction base; |
| 2083 | 2096 | ||
| ... | @@ -2550,4 +2563,9 @@ static const size_t enum_gen_union_index = 1; | ... | @@ -2550,4 +2563,9 @@ static const size_t enum_gen_union_index = 1; |
| 2550 | static const size_t err_union_err_index = 0; | 2563 | static const size_t err_union_err_index = 0; |
| 2551 | static const size_t err_union_payload_index = 1; | 2564 | static const size_t err_union_payload_index = 1; |
| 2552 | 2565 | ||
| 2566 | enum FloatMode { | ||
| 2567 | FloatModeStrict, | ||
| 2568 | FloatModeOptimized, | ||
| 2569 | }; | ||
| 2570 | |||
| 2553 | #endif | 2571 | #endif |
src/codegen.cpp+55-11| ... | @@ -581,6 +581,24 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr | ... | @@ -581,6 +581,24 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr |
| 581 | } | 581 | } |
| 582 | } | 582 | } |
| 583 | 583 | ||
| 584 | static bool ir_want_fast_math(CodeGen *g, IrInstruction *instruction) { | ||
| 585 | // TODO memoize | ||
| 586 | Scope *scope = instruction->scope; | ||
| 587 | while (scope) { | ||
| 588 | if (scope->id == ScopeIdBlock) { | ||
| 589 | ScopeBlock *block_scope = (ScopeBlock *)scope; | ||
| 590 | if (block_scope->fast_math_set_node) | ||
| 591 | return !block_scope->fast_math_off; | ||
| 592 | } else if (scope->id == ScopeIdDecls) { | ||
| 593 | ScopeDecls *decls_scope = (ScopeDecls *)scope; | ||
| 594 | if (decls_scope->fast_math_set_node) | ||
| 595 | return !decls_scope->fast_math_off; | ||
| 596 | } | ||
| 597 | scope = scope->parent; | ||
| 598 | } | ||
| 599 | return true; | ||
| 600 | } | ||
| 601 | |||
| 584 | static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { | 602 | static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) { |
| 585 | if (g->build_mode == BuildModeFastRelease) | 603 | if (g->build_mode == BuildModeFastRelease) |
| 586 | return false; | 604 | return false; |
| ... | @@ -1151,9 +1169,12 @@ enum DivKind { | ... | @@ -1151,9 +1169,12 @@ enum DivKind { |
| 1151 | DivKindExact, | 1169 | DivKindExact, |
| 1152 | }; | 1170 | }; |
| 1153 | 1171 | ||
| 1154 | static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2, | 1172 | static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_math, |
| 1173 | LLVMValueRef val1, LLVMValueRef val2, | ||
| 1155 | TypeTableEntry *type_entry, DivKind div_kind) | 1174 | TypeTableEntry *type_entry, DivKind div_kind) |
| 1156 | { | 1175 | { |
| 1176 | ZigLLVMSetFastMath(g->builder, want_fast_math); | ||
| 1177 | |||
| 1157 | LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); | 1178 | LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); |
| 1158 | if (want_debug_safety) { | 1179 | if (want_debug_safety) { |
| 1159 | LLVMValueRef is_zero_bit; | 1180 | LLVMValueRef is_zero_bit; |
| ... | @@ -1287,9 +1308,12 @@ enum RemKind { | ... | @@ -1287,9 +1308,12 @@ enum RemKind { |
| 1287 | RemKindMod, | 1308 | RemKindMod, |
| 1288 | }; | 1309 | }; |
| 1289 | 1310 | ||
| 1290 | static LLVMValueRef gen_rem(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2, | 1311 | static LLVMValueRef gen_rem(CodeGen *g, bool want_debug_safety, bool want_fast_math, |
| 1312 | LLVMValueRef val1, LLVMValueRef val2, | ||
| 1291 | TypeTableEntry *type_entry, RemKind rem_kind) | 1313 | TypeTableEntry *type_entry, RemKind rem_kind) |
| 1292 | { | 1314 | { |
| 1315 | ZigLLVMSetFastMath(g->builder, want_fast_math); | ||
| 1316 | |||
| 1293 | LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); | 1317 | LLVMValueRef zero = LLVMConstNull(type_entry->type_ref); |
| 1294 | if (want_debug_safety) { | 1318 | if (want_debug_safety) { |
| 1295 | LLVMValueRef is_zero_bit; | 1319 | LLVMValueRef is_zero_bit; |
| ... | @@ -1372,6 +1396,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1372,6 +1396,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1372 | case IrBinOpCmpLessOrEq: | 1396 | case IrBinOpCmpLessOrEq: |
| 1373 | case IrBinOpCmpGreaterOrEq: | 1397 | case IrBinOpCmpGreaterOrEq: |
| 1374 | if (type_entry->id == TypeTableEntryIdFloat) { | 1398 | if (type_entry->id == TypeTableEntryIdFloat) { |
| 1399 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | ||
| 1375 | LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); | 1400 | LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); |
| 1376 | return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); | 1401 | return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, ""); |
| 1377 | } else if (type_entry->id == TypeTableEntryIdInt) { | 1402 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| ... | @@ -1396,6 +1421,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1396,6 +1421,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1396 | case IrBinOpAdd: | 1421 | case IrBinOpAdd: |
| 1397 | case IrBinOpAddWrap: | 1422 | case IrBinOpAddWrap: |
| 1398 | if (type_entry->id == TypeTableEntryIdFloat) { | 1423 | if (type_entry->id == TypeTableEntryIdFloat) { |
| 1424 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | ||
| 1399 | return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); | 1425 | return LLVMBuildFAdd(g->builder, op1_value, op2_value, ""); |
| 1400 | } else if (type_entry->id == TypeTableEntryIdInt) { | 1426 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| 1401 | bool is_wrapping = (op_id == IrBinOpAddWrap); | 1427 | bool is_wrapping = (op_id == IrBinOpAddWrap); |
| ... | @@ -1442,6 +1468,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1442,6 +1468,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1442 | case IrBinOpSub: | 1468 | case IrBinOpSub: |
| 1443 | case IrBinOpSubWrap: | 1469 | case IrBinOpSubWrap: |
| 1444 | if (type_entry->id == TypeTableEntryIdFloat) { | 1470 | if (type_entry->id == TypeTableEntryIdFloat) { |
| 1471 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | ||
| 1445 | return LLVMBuildFSub(g->builder, op1_value, op2_value, ""); | 1472 | return LLVMBuildFSub(g->builder, op1_value, op2_value, ""); |
| 1446 | } else if (type_entry->id == TypeTableEntryIdInt) { | 1473 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| 1447 | bool is_wrapping = (op_id == IrBinOpSubWrap); | 1474 | bool is_wrapping = (op_id == IrBinOpSubWrap); |
| ... | @@ -1460,6 +1487,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1460,6 +1487,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1460 | case IrBinOpMult: | 1487 | case IrBinOpMult: |
| 1461 | case IrBinOpMultWrap: | 1488 | case IrBinOpMultWrap: |
| 1462 | if (type_entry->id == TypeTableEntryIdFloat) { | 1489 | if (type_entry->id == TypeTableEntryIdFloat) { |
| 1490 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base)); | ||
| 1463 | return LLVMBuildFMul(g->builder, op1_value, op2_value, ""); | 1491 | return LLVMBuildFMul(g->builder, op1_value, op2_value, ""); |
| 1464 | } else if (type_entry->id == TypeTableEntryIdInt) { | 1492 | } else if (type_entry->id == TypeTableEntryIdInt) { |
| 1465 | bool is_wrapping = (op_id == IrBinOpMultWrap); | 1493 | bool is_wrapping = (op_id == IrBinOpMultWrap); |
| ... | @@ -1476,17 +1504,23 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, | ... | @@ -1476,17 +1504,23 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1476 | zig_unreachable(); | 1504 | zig_unreachable(); |
| 1477 | } | 1505 | } |
| 1478 | case IrBinOpDivUnspecified: | 1506 | case IrBinOpDivUnspecified: |
| 1479 | return gen_div(g, want_debug_safety, op1_value, op2_value, type_entry, DivKindFloat); | 1507 | return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1508 | op1_value, op2_value, type_entry, DivKindFloat); | ||
| 1480 | case IrBinOpDivExact: | 1509 | case IrBinOpDivExact: |
| 1481 | return gen_div(g, want_debug_safety, op1_value, op2_value, type_entry, DivKindExact); | 1510 | return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1511 | op1_value, op2_value, type_entry, DivKindExact); | ||
| 1482 | case IrBinOpDivTrunc: | 1512 | case IrBinOpDivTrunc: |
| 1483 | return gen_div(g, want_debug_safety, op1_value, op2_value, type_entry, DivKindTrunc); | 1513 | return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1514 | op1_value, op2_value, type_entry, DivKindTrunc); | ||
| 1484 | case IrBinOpDivFloor: | 1515 | case IrBinOpDivFloor: |
| 1485 | return gen_div(g, want_debug_safety, op1_value, op2_value, type_entry, DivKindFloor); | 1516 | return gen_div(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1517 | op1_value, op2_value, type_entry, DivKindFloor); | ||
| 1486 | case IrBinOpRemRem: | 1518 | case IrBinOpRemRem: |
| 1487 | return gen_rem(g, want_debug_safety, op1_value, op2_value, type_entry, RemKindRem); | 1519 | return gen_rem(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1520 | op1_value, op2_value, type_entry, RemKindRem); | ||
| 1488 | case IrBinOpRemMod: | 1521 | case IrBinOpRemMod: |
| 1489 | return gen_rem(g, want_debug_safety, op1_value, op2_value, type_entry, RemKindMod); | 1522 | return gen_rem(g, want_debug_safety, ir_want_fast_math(g, &bin_op_instruction->base), |
| 1523 | op1_value, op2_value, type_entry, RemKindMod); | ||
| 1490 | } | 1524 | } |
| 1491 | zig_unreachable(); | 1525 | zig_unreachable(); |
| 1492 | } | 1526 | } |
| ... | @@ -1602,6 +1636,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, | ... | @@ -1602,6 +1636,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 1602 | } | 1636 | } |
| 1603 | case CastOpFloatToInt: | 1637 | case CastOpFloatToInt: |
| 1604 | assert(wanted_type->id == TypeTableEntryIdInt); | 1638 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 1639 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base)); | ||
| 1605 | if (wanted_type->data.integral.is_signed) { | 1640 | if (wanted_type->data.integral.is_signed) { |
| 1606 | return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, ""); | 1641 | return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, ""); |
| 1607 | } else { | 1642 | } else { |
| ... | @@ -1774,6 +1809,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst | ... | @@ -1774,6 +1809,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst |
| 1774 | case IrUnOpNegationWrap: | 1809 | case IrUnOpNegationWrap: |
| 1775 | { | 1810 | { |
| 1776 | if (expr_type->id == TypeTableEntryIdFloat) { | 1811 | if (expr_type->id == TypeTableEntryIdFloat) { |
| 1812 | ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base)); | ||
| 1777 | return LLVMBuildFNeg(g->builder, expr, ""); | 1813 | return LLVMBuildFNeg(g->builder, expr, ""); |
| 1778 | } else if (expr_type->id == TypeTableEntryIdInt) { | 1814 | } else if (expr_type->id == TypeTableEntryIdInt) { |
| 1779 | if (op_id == IrUnOpNegationWrap) { | 1815 | if (op_id == IrUnOpNegationWrap) { |
| ... | @@ -2986,6 +3022,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -2986,6 +3022,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2986 | case IrInstructionIdPtrTypeChild: | 3022 | case IrInstructionIdPtrTypeChild: |
| 2987 | case IrInstructionIdFieldPtr: | 3023 | case IrInstructionIdFieldPtr: |
| 2988 | case IrInstructionIdSetDebugSafety: | 3024 | case IrInstructionIdSetDebugSafety: |
| 3025 | case IrInstructionIdSetFloatMode: | ||
| 2989 | case IrInstructionIdArrayType: | 3026 | case IrInstructionIdArrayType: |
| 2990 | case IrInstructionIdSliceType: | 3027 | case IrInstructionIdSliceType: |
| 2991 | case IrInstructionIdSizeOf: | 3028 | case IrInstructionIdSizeOf: |
| ... | @@ -4432,6 +4469,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4432,6 +4469,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4432 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); | 4469 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 4433 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); | 4470 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); |
| 4434 | create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); | 4471 | create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); |
| 4472 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); | ||
| 4435 | create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2); | 4473 | create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2); |
| 4436 | create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); | 4474 | create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); |
| 4437 | create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); | 4475 | create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); |
| ... | @@ -4588,6 +4626,15 @@ static void define_builtin_compile_vars(CodeGen *g) { | ... | @@ -4588,6 +4626,15 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 4588 | } | 4626 | } |
| 4589 | buf_appendf(contents, "};\n\n"); | 4627 | buf_appendf(contents, "};\n\n"); |
| 4590 | } | 4628 | } |
| 4629 | { | ||
| 4630 | buf_appendf(contents, | ||
| 4631 | "pub const FloatMode = enum {\n" | ||
| 4632 | " Strict,\n" | ||
| 4633 | " Optimized,\n" | ||
| 4634 | "};\n\n"); | ||
| 4635 | assert(FloatModeStrict == 0); | ||
| 4636 | assert(FloatModeOptimized == 1); | ||
| 4637 | } | ||
| 4591 | buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian)); | 4638 | buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian)); |
| 4592 | buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); | 4639 | buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); |
| 4593 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); | 4640 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); |
| ... | @@ -4674,9 +4721,6 @@ static void init(CodeGen *g) { | ... | @@ -4674,9 +4721,6 @@ static void init(CodeGen *g) { |
| 4674 | g->builder = LLVMCreateBuilder(); | 4721 | g->builder = LLVMCreateBuilder(); |
| 4675 | g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true); | 4722 | g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true); |
| 4676 | 4723 | ||
| 4677 | ZigLLVMSetFastMath(g->builder, true); | ||
| 4678 | |||
| 4679 | |||
| 4680 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); | 4724 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); |
| 4681 | const char *flags = ""; | 4725 | const char *flags = ""; |
| 4682 | unsigned runtime_version = 0; | 4726 | unsigned runtime_version = 0; |
src/ir.cpp+136-6| ... | @@ -297,6 +297,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety * | ... | @@ -297,6 +297,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety * |
| 297 | return IrInstructionIdSetDebugSafety; | 297 | return IrInstructionIdSetDebugSafety; |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFloatMode *) { | ||
| 301 | return IrInstructionIdSetFloatMode; | ||
| 302 | } | ||
| 303 | |||
| 300 | static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { | 304 | static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) { |
| 301 | return IrInstructionIdArrayType; | 305 | return IrInstructionIdArrayType; |
| 302 | } | 306 | } |
| ... | @@ -1190,6 +1194,19 @@ static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, As | ... | @@ -1190,6 +1194,19 @@ static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, As |
| 1190 | return &instruction->base; | 1194 | return &instruction->base; |
| 1191 | } | 1195 | } |
| 1192 | 1196 | ||
| 1197 | static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstNode *source_node, | ||
| 1198 | IrInstruction *scope_value, IrInstruction *mode_value) | ||
| 1199 | { | ||
| 1200 | IrInstructionSetFloatMode *instruction = ir_build_instruction<IrInstructionSetFloatMode>(irb, scope, source_node); | ||
| 1201 | instruction->scope_value = scope_value; | ||
| 1202 | instruction->mode_value = mode_value; | ||
| 1203 | |||
| 1204 | ir_ref_instruction(scope_value, irb->current_basic_block); | ||
| 1205 | ir_ref_instruction(mode_value, irb->current_basic_block); | ||
| 1206 | |||
| 1207 | return &instruction->base; | ||
| 1208 | } | ||
| 1209 | |||
| 1193 | static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size, | 1210 | static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size, |
| 1194 | IrInstruction *child_type) | 1211 | IrInstruction *child_type) |
| 1195 | { | 1212 | { |
| ... | @@ -2361,6 +2378,14 @@ static IrInstruction *ir_instruction_setdebugsafety_get_dep(IrInstructionSetDebu | ... | @@ -2361,6 +2378,14 @@ static IrInstruction *ir_instruction_setdebugsafety_get_dep(IrInstructionSetDebu |
| 2361 | } | 2378 | } |
| 2362 | } | 2379 | } |
| 2363 | 2380 | ||
| 2381 | static IrInstruction *ir_instruction_setfloatmode_get_dep(IrInstructionSetFloatMode *instruction, size_t index) { | ||
| 2382 | switch (index) { | ||
| 2383 | case 0: return instruction->scope_value; | ||
| 2384 | case 1: return instruction->mode_value; | ||
| 2385 | default: return nullptr; | ||
| 2386 | } | ||
| 2387 | } | ||
| 2388 | |||
| 2364 | static IrInstruction *ir_instruction_arraytype_get_dep(IrInstructionArrayType *instruction, size_t index) { | 2389 | static IrInstruction *ir_instruction_arraytype_get_dep(IrInstructionArrayType *instruction, size_t index) { |
| 2365 | switch (index) { | 2390 | switch (index) { |
| 2366 | case 0: return instruction->size; | 2391 | case 0: return instruction->size; |
| ... | @@ -2897,6 +2922,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -2897,6 +2922,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 2897 | return ir_instruction_ptrtypechild_get_dep((IrInstructionPtrTypeChild *) instruction, index); | 2922 | return ir_instruction_ptrtypechild_get_dep((IrInstructionPtrTypeChild *) instruction, index); |
| 2898 | case IrInstructionIdSetDebugSafety: | 2923 | case IrInstructionIdSetDebugSafety: |
| 2899 | return ir_instruction_setdebugsafety_get_dep((IrInstructionSetDebugSafety *) instruction, index); | 2924 | return ir_instruction_setdebugsafety_get_dep((IrInstructionSetDebugSafety *) instruction, index); |
| 2925 | case IrInstructionIdSetFloatMode: | ||
| 2926 | return ir_instruction_setfloatmode_get_dep((IrInstructionSetFloatMode *) instruction, index); | ||
| 2900 | case IrInstructionIdArrayType: | 2927 | case IrInstructionIdArrayType: |
| 2901 | return ir_instruction_arraytype_get_dep((IrInstructionArrayType *) instruction, index); | 2928 | return ir_instruction_arraytype_get_dep((IrInstructionArrayType *) instruction, index); |
| 2902 | case IrInstructionIdSliceType: | 2929 | case IrInstructionIdSliceType: |
| ... | @@ -3841,6 +3868,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -3841,6 +3868,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 3841 | 3868 | ||
| 3842 | return ir_build_set_debug_safety(irb, scope, node, arg0_value, arg1_value); | 3869 | return ir_build_set_debug_safety(irb, scope, node, arg0_value, arg1_value); |
| 3843 | } | 3870 | } |
| 3871 | case BuiltinFnIdSetFloatMode: | ||
| 3872 | { | ||
| 3873 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | ||
| 3874 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | ||
| 3875 | if (arg0_value == irb->codegen->invalid_instruction) | ||
| 3876 | return arg0_value; | ||
| 3877 | |||
| 3878 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | ||
| 3879 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | ||
| 3880 | if (arg1_value == irb->codegen->invalid_instruction) | ||
| 3881 | return arg1_value; | ||
| 3882 | |||
| 3883 | return ir_build_set_float_mode(irb, scope, node, arg0_value, arg1_value); | ||
| 3884 | } | ||
| 3844 | case BuiltinFnIdSizeof: | 3885 | case BuiltinFnIdSizeof: |
| 3845 | { | 3886 | { |
| 3846 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 3887 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -7740,6 +7781,16 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { | ... | @@ -7740,6 +7781,16 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 7740 | return result; | 7781 | return result; |
| 7741 | } | 7782 | } |
| 7742 | 7783 | ||
| 7784 | static ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | ||
| 7785 | Tld *tld = codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str(name)); | ||
| 7786 | resolve_top_level_decl(codegen, tld, false); | ||
| 7787 | assert(tld->id == TldIdVar); | ||
| 7788 | TldVar *tld_var = (TldVar *)tld; | ||
| 7789 | ConstExprValue *var_value = tld_var->var->value; | ||
| 7790 | assert(var_value != nullptr); | ||
| 7791 | return var_value; | ||
| 7792 | } | ||
| 7793 | |||
| 7743 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, | 7794 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 7744 | IrInstructionReturn *return_instruction) | 7795 | IrInstructionReturn *return_instruction) |
| 7745 | { | 7796 | { |
| ... | @@ -10556,7 +10607,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, | ... | @@ -10556,7 +10607,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, |
| 10556 | AstNode *source_node = set_debug_safety_instruction->base.source_node; | 10607 | AstNode *source_node = set_debug_safety_instruction->base.source_node; |
| 10557 | if (*safety_set_node_ptr) { | 10608 | if (*safety_set_node_ptr) { |
| 10558 | ErrorMsg *msg = ir_add_error_node(ira, source_node, | 10609 | ErrorMsg *msg = ir_add_error_node(ira, source_node, |
| 10559 | buf_sprintf("function test attribute set twice")); | 10610 | buf_sprintf("debug safety set twice for same scope")); |
| 10560 | add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here")); | 10611 | add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here")); |
| 10561 | return ira->codegen->builtin_types.entry_invalid; | 10612 | return ira->codegen->builtin_types.entry_invalid; |
| 10562 | } | 10613 | } |
| ... | @@ -10567,6 +10618,86 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, | ... | @@ -10567,6 +10618,86 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira, |
| 10567 | return ira->codegen->builtin_types.entry_void; | 10618 | return ira->codegen->builtin_types.entry_void; |
| 10568 | } | 10619 | } |
| 10569 | 10620 | ||
| 10621 | static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, | ||
| 10622 | IrInstructionSetFloatMode *instruction) | ||
| 10623 | { | ||
| 10624 | IrInstruction *target_instruction = instruction->scope_value->other; | ||
| 10625 | TypeTableEntry *target_type = target_instruction->value.type; | ||
| 10626 | if (type_is_invalid(target_type)) | ||
| 10627 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10628 | ConstExprValue *target_val = ir_resolve_const(ira, target_instruction, UndefBad); | ||
| 10629 | if (!target_val) | ||
| 10630 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10631 | |||
| 10632 | if (ira->new_irb.exec->is_inline) { | ||
| 10633 | // ignore setFloatMode when running functions at compile time | ||
| 10634 | ir_build_const_from(ira, &instruction->base); | ||
| 10635 | return ira->codegen->builtin_types.entry_void; | ||
| 10636 | } | ||
| 10637 | |||
| 10638 | bool *fast_math_off_ptr; | ||
| 10639 | AstNode **fast_math_set_node_ptr; | ||
| 10640 | if (target_type->id == TypeTableEntryIdBlock) { | ||
| 10641 | ScopeBlock *block_scope = (ScopeBlock *)target_val->data.x_block; | ||
| 10642 | fast_math_off_ptr = &block_scope->fast_math_off; | ||
| 10643 | fast_math_set_node_ptr = &block_scope->fast_math_set_node; | ||
| 10644 | } else if (target_type->id == TypeTableEntryIdFn) { | ||
| 10645 | FnTableEntry *target_fn = target_val->data.x_fn.fn_entry; | ||
| 10646 | assert(target_fn->def_scope); | ||
| 10647 | fast_math_off_ptr = &target_fn->def_scope->fast_math_off; | ||
| 10648 | fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node; | ||
| 10649 | } else if (target_type->id == TypeTableEntryIdMetaType) { | ||
| 10650 | ScopeDecls *decls_scope; | ||
| 10651 | TypeTableEntry *type_arg = target_val->data.x_type; | ||
| 10652 | if (type_arg->id == TypeTableEntryIdStruct) { | ||
| 10653 | decls_scope = type_arg->data.structure.decls_scope; | ||
| 10654 | } else if (type_arg->id == TypeTableEntryIdEnum) { | ||
| 10655 | decls_scope = type_arg->data.enumeration.decls_scope; | ||
| 10656 | } else if (type_arg->id == TypeTableEntryIdUnion) { | ||
| 10657 | decls_scope = type_arg->data.unionation.decls_scope; | ||
| 10658 | } else { | ||
| 10659 | ir_add_error_node(ira, target_instruction->source_node, | ||
| 10660 | buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&type_arg->name))); | ||
| 10661 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10662 | } | ||
| 10663 | fast_math_off_ptr = &decls_scope->fast_math_off; | ||
| 10664 | fast_math_set_node_ptr = &decls_scope->fast_math_set_node; | ||
| 10665 | } else { | ||
| 10666 | ir_add_error_node(ira, target_instruction->source_node, | ||
| 10667 | buf_sprintf("expected scope reference, found type '%s'", buf_ptr(&target_type->name))); | ||
| 10668 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10669 | } | ||
| 10670 | |||
| 10671 | ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode"); | ||
| 10672 | assert(float_mode_val->type->id == TypeTableEntryIdMetaType); | ||
| 10673 | TypeTableEntry *float_mode_enum_type = float_mode_val->data.x_type; | ||
| 10674 | |||
| 10675 | IrInstruction *float_mode_value = instruction->mode_value->other; | ||
| 10676 | if (type_is_invalid(float_mode_value->value.type)) | ||
| 10677 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10678 | IrInstruction *casted_value = ir_implicit_cast(ira, float_mode_value, float_mode_enum_type); | ||
| 10679 | if (type_is_invalid(casted_value->value.type)) | ||
| 10680 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10681 | ConstExprValue *mode_val = ir_resolve_const(ira, casted_value, UndefBad); | ||
| 10682 | if (!mode_val) | ||
| 10683 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10684 | |||
| 10685 | bool want_fast_math = (mode_val->data.x_enum.tag == FloatModeOptimized); | ||
| 10686 | |||
| 10687 | AstNode *source_node = instruction->base.source_node; | ||
| 10688 | if (*fast_math_set_node_ptr) { | ||
| 10689 | ErrorMsg *msg = ir_add_error_node(ira, source_node, | ||
| 10690 | buf_sprintf("float mode set twice for same scope")); | ||
| 10691 | add_error_note(ira->codegen, msg, *fast_math_set_node_ptr, buf_sprintf("first set here")); | ||
| 10692 | return ira->codegen->builtin_types.entry_invalid; | ||
| 10693 | } | ||
| 10694 | *fast_math_set_node_ptr = source_node; | ||
| 10695 | *fast_math_off_ptr = !want_fast_math; | ||
| 10696 | |||
| 10697 | ir_build_const_from(ira, &instruction->base); | ||
| 10698 | return ira->codegen->builtin_types.entry_void; | ||
| 10699 | } | ||
| 10700 | |||
| 10570 | static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, | 10701 | static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 10571 | IrInstructionSliceType *slice_type_instruction) | 10702 | IrInstructionSliceType *slice_type_instruction) |
| 10572 | { | 10703 | { |
| ... | @@ -11864,11 +11995,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, | ... | @@ -11864,11 +11995,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 11864 | if (type_is_invalid(type_entry)) | 11995 | if (type_is_invalid(type_entry)) |
| 11865 | return ira->codegen->builtin_types.entry_invalid; | 11996 | return ira->codegen->builtin_types.entry_invalid; |
| 11866 | 11997 | ||
| 11867 | Tld *tld = ira->codegen->compile_var_import->decls_scope->decl_table.get(buf_create_from_str("TypeId")); | 11998 | ConstExprValue *var_value = get_builtin_value(ira->codegen, "TypeId"); |
| 11868 | resolve_top_level_decl(ira->codegen, tld, false); | ||
| 11869 | assert(tld->id == TldIdVar); | ||
| 11870 | TldVar *tld_var = (TldVar *)tld; | ||
| 11871 | ConstExprValue *var_value = tld_var->var->value; | ||
| 11872 | assert(var_value->type->id == TypeTableEntryIdMetaType); | 11999 | assert(var_value->type->id == TypeTableEntryIdMetaType); |
| 11873 | TypeTableEntry *result_type = var_value->data.x_type; | 12000 | TypeTableEntry *result_type = var_value->data.x_type; |
| 11874 | 12001 | ||
| ... | @@ -13271,6 +13398,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -13271,6 +13398,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 13271 | return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); | 13398 | return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction); |
| 13272 | case IrInstructionIdSetDebugSafety: | 13399 | case IrInstructionIdSetDebugSafety: |
| 13273 | return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); | 13400 | return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction); |
| 13401 | case IrInstructionIdSetFloatMode: | ||
| 13402 | return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction); | ||
| 13274 | case IrInstructionIdSliceType: | 13403 | case IrInstructionIdSliceType: |
| 13275 | return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); | 13404 | return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); |
| 13276 | case IrInstructionIdAsm: | 13405 | case IrInstructionIdAsm: |
| ... | @@ -13482,6 +13611,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -13482,6 +13611,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 13482 | case IrInstructionIdReturn: | 13611 | case IrInstructionIdReturn: |
| 13483 | case IrInstructionIdUnreachable: | 13612 | case IrInstructionIdUnreachable: |
| 13484 | case IrInstructionIdSetDebugSafety: | 13613 | case IrInstructionIdSetDebugSafety: |
| 13614 | case IrInstructionIdSetFloatMode: | ||
| 13485 | case IrInstructionIdImport: | 13615 | case IrInstructionIdImport: |
| 13486 | case IrInstructionIdCompileErr: | 13616 | case IrInstructionIdCompileErr: |
| 13487 | case IrInstructionIdCompileLog: | 13617 | case IrInstructionIdCompileLog: |
src/ir_print.cpp+11| ... | @@ -358,6 +358,14 @@ static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety | ... | @@ -358,6 +358,14 @@ static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety |
| 358 | fprintf(irp->f, ")"); | 358 | fprintf(irp->f, ")"); |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | static void ir_print_set_float_mode(IrPrint *irp, IrInstructionSetFloatMode *instruction) { | ||
| 362 | fprintf(irp->f, "@setFloatMode("); | ||
| 363 | ir_print_other_instruction(irp, instruction->scope_value); | ||
| 364 | fprintf(irp->f, ", "); | ||
| 365 | ir_print_other_instruction(irp, instruction->mode_value); | ||
| 366 | fprintf(irp->f, ")"); | ||
| 367 | } | ||
| 368 | |||
| 361 | static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) { | 369 | static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) { |
| 362 | fprintf(irp->f, "["); | 370 | fprintf(irp->f, "["); |
| 363 | ir_print_other_instruction(irp, instruction->size); | 371 | ir_print_other_instruction(irp, instruction->size); |
| ... | @@ -965,6 +973,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -965,6 +973,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 965 | case IrInstructionIdSetDebugSafety: | 973 | case IrInstructionIdSetDebugSafety: |
| 966 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); | 974 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); |
| 967 | break; | 975 | break; |
| 976 | case IrInstructionIdSetFloatMode: | ||
| 977 | ir_print_set_float_mode(irp, (IrInstructionSetFloatMode *)instruction); | ||
| 978 | break; | ||
| 968 | case IrInstructionIdArrayType: | 979 | case IrInstructionIdArrayType: |
| 969 | ir_print_array_type(irp, (IrInstructionArrayType *)instruction); | 980 | ir_print_array_type(irp, (IrInstructionArrayType *)instruction); |
| 970 | break; | 981 | break; |
std/math.zig+79-5| ... | @@ -252,18 +252,92 @@ fn testRem() { | ... | @@ -252,18 +252,92 @@ fn testRem() { |
| 252 | 252 | ||
| 253 | fn isNan(comptime T: type, x: T) -> bool { | 253 | fn isNan(comptime T: type, x: T) -> bool { |
| 254 | assert(@typeId(T) == builtin.TypeId.Float); | 254 | assert(@typeId(T) == builtin.TypeId.Float); |
| 255 | const bits = floatBits(x); | ||
| 256 | if (T == f32) { | 255 | if (T == f32) { |
| 256 | const bits = bitCast(u32, x); | ||
| 257 | return (bits & 0x7fffffff) > 0x7f800000; | 257 | return (bits & 0x7fffffff) > 0x7f800000; |
| 258 | } else if (T == f64) { | 258 | } else if (T == f64) { |
| 259 | const bits = bitCast(u64, x); | ||
| 259 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52); | 260 | return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52); |
| 261 | } else if (T == c_longdouble) { | ||
| 262 | @compileError("TODO support isNan for c_longdouble"); | ||
| 260 | } else { | 263 | } else { |
| 261 | unreachable; | 264 | unreachable; |
| 262 | } | 265 | } |
| 263 | } | 266 | } |
| 264 | 267 | ||
| 265 | fn floatBits(comptime T: type, x: T) -> @IntType(false, T.bit_count) { | 268 | // TODO this should be a builtin |
| 266 | assert(@typeId(T) == builtin.TypeId.Float); | 269 | fn bitCast(comptime DestType: type, value: var) -> DestType { |
| 267 | const uint = @IntType(false, T.bit_count); | 270 | assert(@sizeOf(DestType) == @sizeOf(@typeOf(value))); |
| 268 | return *@intToPtr(&const uint, &x); | 271 | return *@ptrCast(&const DestType, &value); |
| 272 | } | ||
| 273 | |||
| 274 | pub fn floor(x: var) -> @typeOf(x) { | ||
| 275 | switch (@typeOf(x)) { | ||
| 276 | f32 => floor_f32(x), | ||
| 277 | f64 => floor_f64(x), | ||
| 278 | c_longdouble => @compileError("TODO support floor for c_longdouble"), | ||
| 279 | else => @compileError("Invalid type for floor: " ++ @typeName(@typeOf(x))), | ||
| 280 | } | ||
| 281 | } | ||
| 282 | |||
| 283 | fn floor_f32(x: f32) -> f32 { | ||
| 284 | var i = bitCast(u32, x); | ||
| 285 | const e = i32((i >> 23) & 0xff) -% 0x7f; | ||
| 286 | if (e >= 23) | ||
| 287 | return x; | ||
| 288 | if (e >= 0) { | ||
| 289 | const m = bitCast(u32, 0x007fffff >> e); | ||
| 290 | if ((i & m) == 0) | ||
| 291 | return x; | ||
| 292 | if (i >> 31 != 0) | ||
| 293 | i +%= m; | ||
| 294 | i &= ~m; | ||
| 295 | } else { | ||
| 296 | if (i >> 31 == 0) | ||
| 297 | return 0; | ||
| 298 | if (i <<% 1 != 0) | ||
| 299 | return -1.0; | ||
| 300 | } | ||
| 301 | return bitCast(f32, i); | ||
| 302 | } | ||
| 303 | |||
| 304 | fn floor_f64(x: f64) -> f64 { | ||
| 305 | const DBL_EPSILON = 2.22044604925031308085e-16; | ||
| 306 | const toint = 1.0 / DBL_EPSILON; | ||
| 307 | |||
| 308 | var i = bitCast(u64, x); | ||
| 309 | const e = (i >> 52) & 0x7ff; | ||
| 310 | |||
| 311 | if (e >= 0x3ff +% 52 or x == 0) | ||
| 312 | return x; | ||
| 313 | // y = int(x) - x, where int(x) is an integer neighbor of x | ||
| 314 | const y = { | ||
| 315 | @setFloatMode(this, builtin.FloatMode.Strict); | ||
| 316 | if (i >> 63 != 0) { | ||
| 317 | x - toint + toint - x | ||
| 318 | } else { | ||
| 319 | x + toint - toint - x | ||
| 320 | } | ||
| 321 | }; | ||
| 322 | // special case because of non-nearest rounding modes | ||
| 323 | if (e <= 0x3ff - 1) { | ||
| 324 | if (i >> 63 != 0) | ||
| 325 | return -1.0; | ||
| 326 | return 0.0; | ||
| 327 | } | ||
| 328 | if (y > 0) | ||
| 329 | return x + y - 1; | ||
| 330 | return x + y; | ||
| 331 | } | ||
| 332 | |||
| 333 | test "math.floor" { | ||
| 334 | assert(floor(f32(1.234)) == 1.0); | ||
| 335 | assert(floor(f32(-1.234)) == -2.0); | ||
| 336 | assert(floor(f32(999.0)) == 999.0); | ||
| 337 | assert(floor(f32(-999.0)) == -999.0); | ||
| 338 | |||
| 339 | assert(floor(f64(1.234)) == 1.0); | ||
| 340 | assert(floor(f64(-1.234)) == -2.0); | ||
| 341 | assert(floor(f64(999.0)) == 999.0); | ||
| 342 | assert(floor(f64(-999.0)) == -999.0); | ||
| 269 | } | 343 | } |
test/cases/eval.zig+11-1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const assert = @import("std").debug.assert; | 1 | const assert = @import("std").debug.assert; |
| 2 | const builtin = @import("builtin"); | ||
| 2 | 3 | ||
| 3 | test "compileTimeRecursion" { | 4 | test "compileTimeRecursion" { |
| 4 | assert(some_data.len == 21); | 5 | assert(some_data.len == 21); |
| ... | @@ -222,7 +223,7 @@ test "comptimeIterateOverFnPtrList" { | ... | @@ -222,7 +223,7 @@ test "comptimeIterateOverFnPtrList" { |
| 222 | assert(performFn('w', 99) == 99); | 223 | assert(performFn('w', 99) == 99); |
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | test "evalSetDebugSafetyAtCompileTime" { | 226 | test "eval @setDebugSafety at compile-time" { |
| 226 | const result = comptime fnWithSetDebugSafety(); | 227 | const result = comptime fnWithSetDebugSafety(); |
| 227 | assert(result == 1234); | 228 | assert(result == 1234); |
| 228 | } | 229 | } |
| ... | @@ -232,6 +233,15 @@ fn fnWithSetDebugSafety() -> i32{ | ... | @@ -232,6 +233,15 @@ fn fnWithSetDebugSafety() -> i32{ |
| 232 | return 1234; | 233 | return 1234; |
| 233 | } | 234 | } |
| 234 | 235 | ||
| 236 | test "eval @setFloatMode at compile-time" { | ||
| 237 | const result = comptime fnWithFloatMode(); | ||
| 238 | assert(result == 1234.0); | ||
| 239 | } | ||
| 240 | |||
| 241 | fn fnWithFloatMode() -> f32 { | ||
| 242 | @setFloatMode(this, builtin.FloatMode.Strict); | ||
| 243 | return 1234.0; | ||
| 244 | } | ||
| 235 | 245 | ||
| 236 | 246 | ||
| 237 | const SimpleStruct = struct { | 247 | const SimpleStruct = struct { |
test/compile_errors.zig+18| ... | @@ -1835,4 +1835,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -1835,4 +1835,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1835 | \\} | 1835 | \\} |
| 1836 | , | 1836 | , |
| 1837 | ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); | 1837 | ".tmp_source.zig:3:20: error: cast from 'u16' to 'u8' truncates bits"); |
| 1838 | |||
| 1839 | cases.add("@setDebugSafety twice for same scope", | ||
| 1840 | \\export fn foo() { | ||
| 1841 | \\ @setDebugSafety(this, false); | ||
| 1842 | \\ @setDebugSafety(this, false); | ||
| 1843 | \\} | ||
| 1844 | , | ||
| 1845 | ".tmp_source.zig:3:5: error: debug safety set twice for same scope", | ||
| 1846 | ".tmp_source.zig:2:5: note: first set here"); | ||
| 1847 | |||
| 1848 | cases.add("@setFloatMode twice for same scope", | ||
| 1849 | \\export fn foo() { | ||
| 1850 | \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); | ||
| 1851 | \\ @setFloatMode(this, @import("builtin").FloatMode.Optimized); | ||
| 1852 | \\} | ||
| 1853 | , | ||
| 1854 | ".tmp_source.zig:3:5: error: float mode set twice for same scope", | ||
| 1855 | ".tmp_source.zig:2:5: note: first set here"); | ||
| 1838 | } | 1856 | } |