diff --git a/src/build_settings.cpp b/src/build_settings.cpp index e21e7da12..a6dce5233 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -355,8 +355,9 @@ enum OptInFeatureFlags : u64 { OptInFeatureFlag_IntegerDivisionByZero_Trap = 1u<<1, OptInFeatureFlag_IntegerDivisionByZero_Zero = 1u<<2, + OptInFeatureFlag_IntegerDivisionByZero_Self = 1u<<3, - OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap|OptInFeatureFlag_IntegerDivisionByZero_Zero, + OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap|OptInFeatureFlag_IntegerDivisionByZero_Zero|OptInFeatureFlag_IntegerDivisionByZero_Self, }; @@ -370,6 +371,9 @@ u64 get_feature_flag_from_name(String const &name) { if (name == "integer-division-by-zero:zero") { return OptInFeatureFlag_IntegerDivisionByZero_Zero; } + if (name == "integer-division-by-zero:self") { + return OptInFeatureFlag_IntegerDivisionByZero_Self; + } return OptInFeatureFlag_NONE; } @@ -419,6 +423,7 @@ String linker_choices[Linker_COUNT] = { enum IntegerDivisionByZeroKind : u8 { IntegerDivisionByZero_Trap, IntegerDivisionByZero_Zero, + IntegerDivisionByZero_Self, }; // This stores the information for the specify architecture of this build diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b68fe0ed0..782080c93 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4311,7 +4311,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ if (fail) { if (is_type_integer(x->type) || (x->mode == Addressing_Constant && x->value.kind == ExactValue_Integer)) { - if (check_for_integer_division_by_zero(c, node) == IntegerDivisionByZero_Zero) { + if (check_for_integer_division_by_zero(c, node) != IntegerDivisionByZero_Trap) { // Okay break; } @@ -4371,14 +4371,19 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ match_exact_values(&a, &b); - if (check_for_integer_division_by_zero(c, node) == IntegerDivisionByZero_Zero && + IntegerDivisionByZeroKind zero_behaviour = check_for_integer_division_by_zero(c, node); + if (zero_behaviour != IntegerDivisionByZero_Trap && b.kind == ExactValue_Integer && big_int_is_zero(&b.value_integer) && (op.kind == Token_QuoEq || op.kind == Token_Mod || op.kind == Token_ModMod)) { if (op.kind == Token_QuoEq) { - // x/0 == 0 - x->value = b; + if (zero_behaviour == IntegerDivisionByZero_Zero) { + // x/0 == 0 + x->value = b; + } else { + // x/0 == x + x->value = a; + } } else { - // x%0 == x /* NOTE(bill): @integer division by zero rules @@ -4386,8 +4391,16 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ floored: r = a - b*floor(a/b) IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) + IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) */ - x->value = a; + + if (zero_behaviour == IntegerDivisionByZero_Zero) { + // x%0 == x + x->value = a; + } else { + // x%0 == 0 + x->value = b; + } } } else { x->value = exact_binary_operator_value(op.kind, a, b); @@ -9647,6 +9660,9 @@ gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(Checker if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) != 0) { return IntegerDivisionByZero_Zero; } + if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Self) != 0) { + return IntegerDivisionByZero_Self; + } return build_context.integer_division_by_zero_behaviour; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index b20aef742..b44d2215e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -302,6 +302,9 @@ gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_beha if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { return IntegerDivisionByZero_Zero; } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { + return IntegerDivisionByZero_Self; + } } return build_context.integer_division_by_zero_behaviour; } @@ -1159,7 +1162,6 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L lb_start_block(p, edge_case_block); - incoming_values[1] = zero; switch (lb_check_for_integer_division_by_zero_behaviour(p)) { case IntegerDivisionByZero_Trap: @@ -1167,7 +1169,10 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L LLVMBuildUnreachable(p->builder); break; case IntegerDivisionByZero_Zero: - // Already fine + incoming_values[1] = zero; + break; + case IntegerDivisionByZero_Self: + incoming_values[1] = lhs; break; } @@ -1178,6 +1183,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L switch (lb_check_for_integer_division_by_zero_behaviour(p)) { case IntegerDivisionByZero_Trap: + case IntegerDivisionByZero_Self: res = incoming_values[0]; break; case IntegerDivisionByZero_Zero: @@ -1242,7 +1248,6 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) */ - incoming_values[1] = lhs; switch (lb_check_for_integer_division_by_zero_behaviour(p)) { case IntegerDivisionByZero_Trap: @@ -1250,7 +1255,10 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV LLVMBuildUnreachable(p->builder); break; case IntegerDivisionByZero_Zero: - // Already fine + incoming_values[1] = lhs; + break; + case IntegerDivisionByZero_Self: + incoming_values[1] = zero; break; } @@ -1261,6 +1269,7 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV switch (lb_check_for_integer_division_by_zero_behaviour(p)) { case IntegerDivisionByZero_Trap: + case IntegerDivisionByZero_Self: res = incoming_values[0]; break; case IntegerDivisionByZero_Zero: diff --git a/src/main.cpp b/src/main.cpp index 0bfab0344..2f0b1c19b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1550,8 +1550,10 @@ gb_internal bool parse_build_flags(Array args) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Trap; } else if (str_eq_ignore_case(value.value_string, "zero")) { build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Zero; - } else { - gb_printf_err("-integer-division-by-zero options are 'trap' and 'zero'.\n"); + } else if (str_eq_ignore_case(value.value_string, "self")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Self; + }else { + gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', and 'self'.\n"); bad_flags = true; } break; @@ -2585,7 +2587,8 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(2, "Specifies the default behaviour for integer division by zero."); print_usage_line(2, "Available Options:"); print_usage_line(3, "-integer-division-by-zero:trap Trap on division/modulo/remainder by zero"); - print_usage_line(3, "-integer-division-by-zero:zero x/0 == 0 and x%%0 == x and x%%%%0 == 0"); + print_usage_line(3, "-integer-division-by-zero:zero x/0 == 0 and x%%0 == x and x%%%%0 == x"); + print_usage_line(3, "-integer-division-by-zero:self x/0 == x and x%%0 == 0 and x%%%%0 == 0"); } } diff --git a/src/parser.cpp b/src/parser.cpp index 58d7acfa5..c63ffe747 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6428,6 +6428,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { error_line("\tdynamic-literals\n"); error_line("\tinteger-division-by-zero:trap\n"); error_line("\tinteger-division-by-zero:zero\n"); + error_line("\tinteger-division-by-zero:self\n"); return OptInFeatureFlag_NONE; } }