authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-20 23:06:32-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-05-20 23:06:32-04:00
log29b488245daa9210ed9b5e1ffb7290024677f0db
tree7bcee7504f7caa5f72c8d83bbf066aa494306a70
parent051ee8e626111445c27d6c868cb0cdec6df7409e

add setFloatMode builtin and std.math.floor

* 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
232install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")232install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
233install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os")233install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os")
234install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")234install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
235install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
236install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")235install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
237install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")236install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
238install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special")237install(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 null1587 // 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};
15971602
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};
20802086
2087struct IrInstructionSetFloatMode {
2088 IrInstruction base;
2089
2090 IrInstruction *scope_value;
2091 IrInstruction *mode_value;
2092};
2093
2081struct IrInstructionArrayType {2094struct IrInstructionArrayType {
2082 IrInstruction base;2095 IrInstruction base;
20832096
...@@ -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;
2550static const size_t err_union_err_index = 0;2563static const size_t err_union_err_index = 0;
2551static const size_t err_union_payload_index = 1;2564static const size_t err_union_payload_index = 1;
25522565
2566enum FloatMode {
2567 FloatModeStrict,
2568 FloatModeOptimized,
2569};
2570
2553#endif2571#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}
583583
584static 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
584static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {602static 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};
11531171
1154static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2,1172static 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};
12891310
1290static LLVMValueRef gen_rem(CodeGen *g, bool want_debug_safety, LLVMValueRef val1, LLVMValueRef val2,1311static 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);
46764723
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}
299299
300static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFloatMode *) {
301 return IrInstructionIdSetFloatMode;
302}
303
300static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {304static 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}
11921196
1197static 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
1193static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size,1210static 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}
23632380
2381static 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
2364static IrInstruction *ir_instruction_arraytype_get_dep(IrInstructionArrayType *instruction, size_t index) {2389static 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
38413868
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}
77427783
7784static 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
7743static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,7794static 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}
1056910620
10621static 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
10570static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,10701static 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;
1186611997
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;
1187412001
...@@ -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}
360360
361static 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
361static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) {369static 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() {
252252
253fn isNan(comptime T: type, x: T) -> bool {253fn 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}
264267
265fn 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);269fn 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
274pub 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
283fn 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
304fn 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
333test "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 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const builtin = @import("builtin");
23
3test "compileTimeRecursion" {4test "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}
224225
225test "evalSetDebugSafetyAtCompileTime" {226test "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}
234235
236test "eval @setFloatMode at compile-time" {
237 const result = comptime fnWithFloatMode();
238 assert(result == 1234.0);
239}
240
241fn fnWithFloatMode() -> f32 {
242 @setFloatMode(this, builtin.FloatMode.Strict);
243 return 1234.0;
244}
235245
236246
237const SimpleStruct = struct {247const 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}