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
232232install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os")
233233install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows.zig" DESTINATION "${ZIG_STD_DEST}/os")
234234install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
235install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
236235install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
237236install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special")
238237install(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 {
11931193 BuiltinFnIdTruncate,
11941194 BuiltinFnIdIntType,
11951195 BuiltinFnIdSetDebugSafety,
1196 BuiltinFnIdSetFloatMode,
11961197 BuiltinFnIdTypeName,
11971198 BuiltinFnIdCanImplicitCast,
11981199 BuiltinFnIdSetGlobalAlign,
......@@ -1580,6 +1581,8 @@ struct ScopeDecls {
15801581 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> decl_table;
15811582 bool safety_off;
15821583 AstNode *safety_set_node;
1584 bool fast_math_off;
1585 AstNode *fast_math_set_node;
15831586 ImportTableEntry *import;
15841587 // If this is a scope from a container, this is the type entry, otherwise null
15851588 TypeTableEntry *container_type;
......@@ -1593,6 +1596,8 @@ struct ScopeBlock {
15931596 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
15941597 bool safety_off;
15951598 AstNode *safety_set_node;
1599 bool fast_math_off;
1600 AstNode *fast_math_set_node;
15961601};
15971602
15981603// This scope is created from every defer expression.
......@@ -1720,6 +1725,7 @@ enum IrInstructionId {
17201725 IrInstructionIdToPtrType,
17211726 IrInstructionIdPtrTypeChild,
17221727 IrInstructionIdSetDebugSafety,
1728 IrInstructionIdSetFloatMode,
17231729 IrInstructionIdArrayType,
17241730 IrInstructionIdSliceType,
17251731 IrInstructionIdAsm,
......@@ -2078,6 +2084,13 @@ struct IrInstructionSetDebugSafety {
20782084 IrInstruction *debug_safety_on;
20792085};
20802086
2087struct IrInstructionSetFloatMode {
2088 IrInstruction base;
2089
2090 IrInstruction *scope_value;
2091 IrInstruction *mode_value;
2092};
2093
20812094struct IrInstructionArrayType {
20822095 IrInstruction base;
20832096
......@@ -2550,4 +2563,9 @@ static const size_t enum_gen_union_index = 1;
25502563static const size_t err_union_err_index = 0;
25512564static const size_t err_union_payload_index = 1;
25522565
2566enum FloatMode {
2567 FloatModeStrict,
2568 FloatModeOptimized,
2569};
2570
25532571#endif
src/codegen.cpp+55-11
......@@ -581,6 +581,24 @@ static LLVMValueRef get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntr
581581 }
582582}
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
584602static bool ir_want_debug_safety(CodeGen *g, IrInstruction *instruction) {
585603 if (g->build_mode == BuildModeFastRelease)
586604 return false;
......@@ -1151,9 +1169,12 @@ enum DivKind {
11511169 DivKindExact,
11521170};
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,
11551174 TypeTableEntry *type_entry, DivKind div_kind)
11561175{
1176 ZigLLVMSetFastMath(g->builder, want_fast_math);
1177
11571178 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
11581179 if (want_debug_safety) {
11591180 LLVMValueRef is_zero_bit;
......@@ -1287,9 +1308,12 @@ enum RemKind {
12871308 RemKindMod,
12881309};
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,
12911313 TypeTableEntry *type_entry, RemKind rem_kind)
12921314{
1315 ZigLLVMSetFastMath(g->builder, want_fast_math);
1316
12931317 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
12941318 if (want_debug_safety) {
12951319 LLVMValueRef is_zero_bit;
......@@ -1372,6 +1396,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
13721396 case IrBinOpCmpLessOrEq:
13731397 case IrBinOpCmpGreaterOrEq:
13741398 if (type_entry->id == TypeTableEntryIdFloat) {
1399 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
13751400 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
13761401 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
13771402 } else if (type_entry->id == TypeTableEntryIdInt) {
......@@ -1396,6 +1421,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
13961421 case IrBinOpAdd:
13971422 case IrBinOpAddWrap:
13981423 if (type_entry->id == TypeTableEntryIdFloat) {
1424 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
13991425 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
14001426 } else if (type_entry->id == TypeTableEntryIdInt) {
14011427 bool is_wrapping = (op_id == IrBinOpAddWrap);
......@@ -1442,6 +1468,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
14421468 case IrBinOpSub:
14431469 case IrBinOpSubWrap:
14441470 if (type_entry->id == TypeTableEntryIdFloat) {
1471 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
14451472 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
14461473 } else if (type_entry->id == TypeTableEntryIdInt) {
14471474 bool is_wrapping = (op_id == IrBinOpSubWrap);
......@@ -1460,6 +1487,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
14601487 case IrBinOpMult:
14611488 case IrBinOpMultWrap:
14621489 if (type_entry->id == TypeTableEntryIdFloat) {
1490 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
14631491 return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
14641492 } else if (type_entry->id == TypeTableEntryIdInt) {
14651493 bool is_wrapping = (op_id == IrBinOpMultWrap);
......@@ -1476,17 +1504,23 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
14761504 zig_unreachable();
14771505 }
14781506 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);
14801509 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);
14821512 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);
14841515 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);
14861518 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);
14881521 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);
14901524 }
14911525 zig_unreachable();
14921526}
......@@ -1602,6 +1636,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
16021636 }
16031637 case CastOpFloatToInt:
16041638 assert(wanted_type->id == TypeTableEntryIdInt);
1639 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &cast_instruction->base));
16051640 if (wanted_type->data.integral.is_signed) {
16061641 return LLVMBuildFPToSI(g->builder, expr_val, wanted_type->type_ref, "");
16071642 } else {
......@@ -1774,6 +1809,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
17741809 case IrUnOpNegationWrap:
17751810 {
17761811 if (expr_type->id == TypeTableEntryIdFloat) {
1812 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &un_op_instruction->base));
17771813 return LLVMBuildFNeg(g->builder, expr, "");
17781814 } else if (expr_type->id == TypeTableEntryIdInt) {
17791815 if (op_id == IrUnOpNegationWrap) {
......@@ -2986,6 +3022,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
29863022 case IrInstructionIdPtrTypeChild:
29873023 case IrInstructionIdFieldPtr:
29883024 case IrInstructionIdSetDebugSafety:
3025 case IrInstructionIdSetFloatMode:
29893026 case IrInstructionIdArrayType:
29903027 case IrInstructionIdSliceType:
29913028 case IrInstructionIdSizeOf:
......@@ -4432,6 +4469,7 @@ static void define_builtin_fns(CodeGen *g) {
44324469 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
44334470 create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2);
44344471 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
4472 create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
44354473 create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
44364474 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
44374475 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
......@@ -4588,6 +4626,15 @@ static void define_builtin_compile_vars(CodeGen *g) {
45884626 }
45894627 buf_appendf(contents, "};\n\n");
45904628 }
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 }
45914638 buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian));
45924639 buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
45934640 buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
......@@ -4674,9 +4721,6 @@ static void init(CodeGen *g) {
46744721 g->builder = LLVMCreateBuilder();
46754722 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);
46764723
4677 ZigLLVMSetFastMath(g->builder, true);
4678
4679
46804724 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
46814725 const char *flags = "";
46824726 unsigned runtime_version = 0;
src/ir.cpp+136-6
......@@ -297,6 +297,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetDebugSafety *
297297 return IrInstructionIdSetDebugSafety;
298298}
299299
300static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFloatMode *) {
301 return IrInstructionIdSetFloatMode;
302}
303
300304static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayType *) {
301305 return IrInstructionIdArrayType;
302306}
......@@ -1190,6 +1194,19 @@ static IrInstruction *ir_build_set_debug_safety(IrBuilder *irb, Scope *scope, As
11901194 return &instruction->base;
11911195}
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
11931210static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size,
11941211 IrInstruction *child_type)
11951212{
......@@ -2361,6 +2378,14 @@ static IrInstruction *ir_instruction_setdebugsafety_get_dep(IrInstructionSetDebu
23612378 }
23622379}
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
23642389static IrInstruction *ir_instruction_arraytype_get_dep(IrInstructionArrayType *instruction, size_t index) {
23652390 switch (index) {
23662391 case 0: return instruction->size;
......@@ -2897,6 +2922,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
28972922 return ir_instruction_ptrtypechild_get_dep((IrInstructionPtrTypeChild *) instruction, index);
28982923 case IrInstructionIdSetDebugSafety:
28992924 return ir_instruction_setdebugsafety_get_dep((IrInstructionSetDebugSafety *) instruction, index);
2925 case IrInstructionIdSetFloatMode:
2926 return ir_instruction_setfloatmode_get_dep((IrInstructionSetFloatMode *) instruction, index);
29002927 case IrInstructionIdArrayType:
29012928 return ir_instruction_arraytype_get_dep((IrInstructionArrayType *) instruction, index);
29022929 case IrInstructionIdSliceType:
......@@ -3841,6 +3868,20 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
38413868
38423869 return ir_build_set_debug_safety(irb, scope, node, arg0_value, arg1_value);
38433870 }
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 }
38443885 case BuiltinFnIdSizeof:
38453886 {
38463887 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -7740,6 +7781,16 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
77407781 return result;
77417782}
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
77437794static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
77447795 IrInstructionReturn *return_instruction)
77457796{
......@@ -10556,7 +10607,7 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
1055610607 AstNode *source_node = set_debug_safety_instruction->base.source_node;
1055710608 if (*safety_set_node_ptr) {
1055810609 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"));
1056010611 add_error_note(ira->codegen, msg, *safety_set_node_ptr, buf_sprintf("first set here"));
1056110612 return ira->codegen->builtin_types.entry_invalid;
1056210613 }
......@@ -10567,6 +10618,86 @@ static TypeTableEntry *ir_analyze_instruction_set_debug_safety(IrAnalyze *ira,
1056710618 return ira->codegen->builtin_types.entry_void;
1056810619}
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
1057010701static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1057110702 IrInstructionSliceType *slice_type_instruction)
1057210703{
......@@ -11864,11 +11995,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
1186411995 if (type_is_invalid(type_entry))
1186511996 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"));
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;
11998 ConstExprValue *var_value = get_builtin_value(ira->codegen, "TypeId");
1187211999 assert(var_value->type->id == TypeTableEntryIdMetaType);
1187312000 TypeTableEntry *result_type = var_value->data.x_type;
1187412001
......@@ -13271,6 +13398,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1327113398 return ir_analyze_instruction_set_global_linkage(ira, (IrInstructionSetGlobalLinkage *)instruction);
1327213399 case IrInstructionIdSetDebugSafety:
1327313400 return ir_analyze_instruction_set_debug_safety(ira, (IrInstructionSetDebugSafety *)instruction);
13401 case IrInstructionIdSetFloatMode:
13402 return ir_analyze_instruction_set_float_mode(ira, (IrInstructionSetFloatMode *)instruction);
1327413403 case IrInstructionIdSliceType:
1327513404 return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
1327613405 case IrInstructionIdAsm:
......@@ -13482,6 +13611,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1348213611 case IrInstructionIdReturn:
1348313612 case IrInstructionIdUnreachable:
1348413613 case IrInstructionIdSetDebugSafety:
13614 case IrInstructionIdSetFloatMode:
1348513615 case IrInstructionIdImport:
1348613616 case IrInstructionIdCompileErr:
1348713617 case IrInstructionIdCompileLog:
src/ir_print.cpp+11
......@@ -358,6 +358,14 @@ static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety
358358 fprintf(irp->f, ")");
359359}
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
361369static void ir_print_array_type(IrPrint *irp, IrInstructionArrayType *instruction) {
362370 fprintf(irp->f, "[");
363371 ir_print_other_instruction(irp, instruction->size);
......@@ -965,6 +973,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
965973 case IrInstructionIdSetDebugSafety:
966974 ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction);
967975 break;
976 case IrInstructionIdSetFloatMode:
977 ir_print_set_float_mode(irp, (IrInstructionSetFloatMode *)instruction);
978 break;
968979 case IrInstructionIdArrayType:
969980 ir_print_array_type(irp, (IrInstructionArrayType *)instruction);
970981 break;
std/math.zig+79-5
......@@ -252,18 +252,92 @@ fn testRem() {
252252
253253fn isNan(comptime T: type, x: T) -> bool {
254254 assert(@typeId(T) == builtin.TypeId.Float);
255 const bits = floatBits(x);
256255 if (T == f32) {
256 const bits = bitCast(u32, x);
257257 return (bits & 0x7fffffff) > 0x7f800000;
258258 } else if (T == f64) {
259 const bits = bitCast(u64, x);
259260 return (bits & (@maxValue(u64) >> 1)) > (u64(0x7ff) << 52);
261 } else if (T == c_longdouble) {
262 @compileError("TODO support isNan for c_longdouble");
260263 } else {
261264 unreachable;
262265 }
263266}
264267
265fn floatBits(comptime T: type, x: T) -> @IntType(false, T.bit_count) {
266 assert(@typeId(T) == builtin.TypeId.Float);
267 const uint = @IntType(false, T.bit_count);
268 return *@intToPtr(&const uint, &x);
268// TODO this should be a builtin
269fn bitCast(comptime DestType: type, value: var) -> DestType {
270 assert(@sizeOf(DestType) == @sizeOf(@typeOf(value)));
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);
269343}
test/cases/eval.zig+11-1
......@@ -1,4 +1,5 @@
11const assert = @import("std").debug.assert;
2const builtin = @import("builtin");
23
34test "compileTimeRecursion" {
45 assert(some_data.len == 21);
......@@ -222,7 +223,7 @@ test "comptimeIterateOverFnPtrList" {
222223 assert(performFn('w', 99) == 99);
223224}
224225
225test "evalSetDebugSafetyAtCompileTime" {
226test "eval @setDebugSafety at compile-time" {
226227 const result = comptime fnWithSetDebugSafety();
227228 assert(result == 1234);
228229}
......@@ -232,6 +233,15 @@ fn fnWithSetDebugSafety() -> i32{
232233 return 1234;
233234}
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
237247const SimpleStruct = struct {
test/compile_errors.zig+18
......@@ -1835,4 +1835,22 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
18351835 \\}
18361836 ,
18371837 ".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");
18381856}