mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Define the behaviour of integer division by zero
This commit is contained in:
@@ -404,6 +404,11 @@ String linker_choices[Linker_COUNT] = {
|
|||||||
str_lit("radlink"),
|
str_lit("radlink"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum IntegerDivisionByZeroKind : u8 {
|
||||||
|
IntegerDivisionByZero_Trap,
|
||||||
|
IntegerDivisionByZero_Zero,
|
||||||
|
};
|
||||||
|
|
||||||
// This stores the information for the specify architecture of this build
|
// This stores the information for the specify architecture of this build
|
||||||
struct BuildContext {
|
struct BuildContext {
|
||||||
// Constants
|
// Constants
|
||||||
@@ -485,6 +490,8 @@ struct BuildContext {
|
|||||||
bool keep_object_files;
|
bool keep_object_files;
|
||||||
bool disallow_do;
|
bool disallow_do;
|
||||||
|
|
||||||
|
IntegerDivisionByZeroKind integer_division_by_zero_behaviour;
|
||||||
|
|
||||||
LinkerChoice linker_choice;
|
LinkerChoice linker_choice;
|
||||||
|
|
||||||
StringSet custom_attributes;
|
StringSet custom_attributes;
|
||||||
|
|||||||
+50
-2
@@ -129,6 +129,8 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
|
|||||||
|
|
||||||
gb_internal bool is_exact_value_zero(ExactValue const &v);
|
gb_internal bool is_exact_value_zero(ExactValue const &v);
|
||||||
|
|
||||||
|
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(Ast *node);
|
||||||
|
|
||||||
enum LoadDirectiveResult {
|
enum LoadDirectiveResult {
|
||||||
LoadDirective_Success = 0,
|
LoadDirective_Success = 0,
|
||||||
LoadDirective_Error = 1,
|
LoadDirective_Error = 1,
|
||||||
@@ -4308,7 +4310,25 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fail) {
|
if (fail) {
|
||||||
error(y->expr, "Division by zero not allowed");
|
if (is_type_integer(x->type) || (x->mode == Addressing_Constant && x->value.kind == ExactValue_Integer)) {
|
||||||
|
if (check_for_integer_division_by_zero(node) == IntegerDivisionByZero_Zero) {
|
||||||
|
// Okay
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (op.kind) {
|
||||||
|
case Token_Mod:
|
||||||
|
case Token_ModMod:
|
||||||
|
case Token_ModEq:
|
||||||
|
case Token_ModModEq:
|
||||||
|
error(y->expr, "Division by zero through '%.*s' not allowed", LIT(token_strings[op.kind]));
|
||||||
|
break;
|
||||||
|
case Token_Quo:
|
||||||
|
case Token_QuoEq:
|
||||||
|
error(y->expr, "Division by zero not allowed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
x->mode = Addressing_Invalid;
|
x->mode = Addressing_Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -4348,7 +4368,30 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x->value = exact_binary_operator_value(op.kind, a, b);
|
match_exact_values(&a, &b);
|
||||||
|
|
||||||
|
|
||||||
|
if (check_for_integer_division_by_zero(node) == IntegerDivisionByZero_Zero &&
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
// x%0 == x
|
||||||
|
/*
|
||||||
|
NOTE(bill): @integer division by zero rules
|
||||||
|
|
||||||
|
truncated: r = a - b*trunc(a/b)
|
||||||
|
floored: r = a - b*floor(a/b)
|
||||||
|
|
||||||
|
IFF a/0 == 0, then (a%0 == a) or (a%%0 == a)
|
||||||
|
*/
|
||||||
|
x->value = a;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x->value = exact_binary_operator_value(op.kind, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_type_typed(x->type)) {
|
if (is_type_typed(x->type)) {
|
||||||
if (node != nullptr) {
|
if (node != nullptr) {
|
||||||
@@ -9595,6 +9638,11 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom
|
|||||||
return cl->elems.count > 0;
|
return cl->elems.count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(Ast *node) {
|
||||||
|
// TODO(bill): per file `#+feature` flags
|
||||||
|
return build_context.integer_division_by_zero_behaviour;
|
||||||
|
}
|
||||||
|
|
||||||
gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) {
|
||||||
ExprKind kind = Expr_Expr;
|
ExprKind kind = Expr_Expr;
|
||||||
ast_node(cl, CompoundLit, node);
|
ast_node(cl, CompoundLit, node);
|
||||||
|
|||||||
+161
-27
@@ -283,6 +283,12 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero(lbProcedure *p) {
|
||||||
|
// TODO(bill): per file `#+feature` flags
|
||||||
|
return build_context.integer_division_by_zero_behaviour;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
|
gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
|
||||||
GB_ASSERT(is_type_array_like(type));
|
GB_ASSERT(is_type_array_like(type));
|
||||||
Type *elem_type = base_array_type(type);
|
Type *elem_type = base_array_type(type);
|
||||||
@@ -354,7 +360,6 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
z = LLVMBuildAdd(p->builder, x, y, "");
|
z = LLVMBuildAdd(p->builder, x, y, "");
|
||||||
@@ -366,17 +371,15 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu
|
|||||||
z = LLVMBuildMul(p->builder, x, y, "");
|
z = LLVMBuildMul(p->builder, x, y, "");
|
||||||
break;
|
break;
|
||||||
case Token_Quo:
|
case Token_Quo:
|
||||||
if (is_type_unsigned(integral_type)) {
|
{
|
||||||
z = LLVMBuildUDiv(p->builder, x, y, "");
|
auto *call = is_type_unsigned(integral_type) ? LLVMBuildUDiv : LLVMBuildSDiv;
|
||||||
} else {
|
z = call(p->builder, x, y, "");
|
||||||
z = LLVMBuildSDiv(p->builder, x, y, "");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Token_Mod:
|
case Token_Mod:
|
||||||
if (is_type_unsigned(integral_type)) {
|
{
|
||||||
z = LLVMBuildURem(p->builder, x, y, "");
|
auto *call = is_type_unsigned(integral_type) ? LLVMBuildURem : LLVMBuildSRem;
|
||||||
} else {
|
z = call(p->builder, x, y, "");
|
||||||
z = LLVMBuildSRem(p->builder, x, y, "");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Token_ModMod:
|
case Token_ModMod:
|
||||||
@@ -1111,6 +1114,150 @@ gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue l
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, bool is_signed) {
|
||||||
|
LLVMTypeRef type = LLVMTypeOf(rhs);
|
||||||
|
GB_ASSERT(LLVMTypeOf(lhs) == type);
|
||||||
|
|
||||||
|
auto *call = is_signed ? LLVMBuildSDiv : LLVMBuildUDiv;
|
||||||
|
|
||||||
|
|
||||||
|
LLVMValueRef incoming_values[2] = {};
|
||||||
|
LLVMBasicBlockRef incoming_blocks[2] = {};
|
||||||
|
|
||||||
|
lbBlock *safe_block = lb_create_block(p, "div.safe");
|
||||||
|
lbBlock *edge_case_block = lb_create_block(p, "div.edge");
|
||||||
|
lbBlock *done_block = lb_create_block(p, "div.done");
|
||||||
|
|
||||||
|
LLVMValueRef zero = LLVMConstNull(type);
|
||||||
|
LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, "");
|
||||||
|
lbValue cond = {dem_check, t_untyped_bool};
|
||||||
|
|
||||||
|
lb_emit_if(p, cond, safe_block, edge_case_block);
|
||||||
|
|
||||||
|
lb_start_block(p, safe_block);
|
||||||
|
incoming_values[0] = call(p->builder, lhs, rhs, "");
|
||||||
|
|
||||||
|
lb_emit_jump(p, done_block);
|
||||||
|
|
||||||
|
lb_start_block(p, edge_case_block);
|
||||||
|
|
||||||
|
incoming_values[1] = zero;
|
||||||
|
|
||||||
|
switch (lb_check_for_integer_division_by_zero(p)) {
|
||||||
|
case IntegerDivisionByZero_Trap:
|
||||||
|
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
||||||
|
LLVMBuildUnreachable(p->builder);
|
||||||
|
break;
|
||||||
|
case IntegerDivisionByZero_Zero:
|
||||||
|
// Already fine
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_emit_jump(p, done_block);
|
||||||
|
lb_start_block(p, done_block);
|
||||||
|
|
||||||
|
LLVMValueRef res = incoming_values[0];
|
||||||
|
|
||||||
|
switch (lb_check_for_integer_division_by_zero(p)) {
|
||||||
|
case IntegerDivisionByZero_Trap:
|
||||||
|
res = incoming_values[0];
|
||||||
|
break;
|
||||||
|
case IntegerDivisionByZero_Zero:
|
||||||
|
res = LLVMBuildPhi(p->builder, type, "");
|
||||||
|
|
||||||
|
GB_ASSERT(p->curr_block->preds.count >= 2);
|
||||||
|
incoming_blocks[0] = p->curr_block->preds[0]->block;
|
||||||
|
incoming_blocks[1] = p->curr_block->preds[1]->block;
|
||||||
|
|
||||||
|
LLVMAddIncoming(res, incoming_values, incoming_blocks, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, bool is_unsigned, bool is_floored) {
|
||||||
|
LLVMTypeRef type = LLVMTypeOf(rhs);
|
||||||
|
GB_ASSERT(LLVMTypeOf(lhs) == type);
|
||||||
|
|
||||||
|
LLVMValueRef incoming_values[2] = {};
|
||||||
|
LLVMBasicBlockRef incoming_blocks[2] = {};
|
||||||
|
|
||||||
|
lbBlock *safe_block = lb_create_block(p, "div.safe");
|
||||||
|
lbBlock *edge_case_block = lb_create_block(p, "div.edge");
|
||||||
|
lbBlock *done_block = lb_create_block(p, "div.done");
|
||||||
|
|
||||||
|
LLVMValueRef zero = LLVMConstNull(type);
|
||||||
|
LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, "");
|
||||||
|
lbValue cond = {dem_check, t_untyped_bool};
|
||||||
|
|
||||||
|
lb_emit_if(p, cond, safe_block, edge_case_block);
|
||||||
|
|
||||||
|
lb_start_block(p, safe_block);
|
||||||
|
|
||||||
|
if (is_floored) { // %%
|
||||||
|
if (is_unsigned) {
|
||||||
|
incoming_values[0] = LLVMBuildURem(p->builder, lhs, rhs, "");
|
||||||
|
} else {
|
||||||
|
LLVMValueRef a = LLVMBuildSRem(p->builder, lhs, rhs, "");
|
||||||
|
LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs, "");
|
||||||
|
LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs, "");
|
||||||
|
incoming_values[0] = c;
|
||||||
|
}
|
||||||
|
} else { // %
|
||||||
|
if (is_unsigned) {
|
||||||
|
incoming_values[0] = LLVMBuildURem(p->builder, lhs, rhs, "");
|
||||||
|
} else {
|
||||||
|
incoming_values[0] = LLVMBuildSRem(p->builder, lhs, rhs, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_emit_jump(p, done_block);
|
||||||
|
|
||||||
|
lb_start_block(p, edge_case_block);
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE(bill): @integer division by zero rules
|
||||||
|
|
||||||
|
truncated: r = a - b*trunc(a/b)
|
||||||
|
floored: r = a - b*floor(a/b)
|
||||||
|
|
||||||
|
IFF a/0 == 0, then (a%0 == a) or (a%%0 == a)
|
||||||
|
*/
|
||||||
|
incoming_values[1] = lhs;
|
||||||
|
|
||||||
|
switch (lb_check_for_integer_division_by_zero(p)) {
|
||||||
|
case IntegerDivisionByZero_Trap:
|
||||||
|
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
||||||
|
LLVMBuildUnreachable(p->builder);
|
||||||
|
break;
|
||||||
|
case IntegerDivisionByZero_Zero:
|
||||||
|
// Already fine
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lb_emit_jump(p, done_block);
|
||||||
|
lb_start_block(p, done_block);
|
||||||
|
|
||||||
|
LLVMValueRef res = incoming_values[0];
|
||||||
|
|
||||||
|
switch (lb_check_for_integer_division_by_zero(p)) {
|
||||||
|
case IntegerDivisionByZero_Trap:
|
||||||
|
res = incoming_values[0];
|
||||||
|
break;
|
||||||
|
case IntegerDivisionByZero_Zero:
|
||||||
|
res = LLVMBuildPhi(p->builder, type, "");
|
||||||
|
|
||||||
|
GB_ASSERT(p->curr_block->preds.count >= 2);
|
||||||
|
incoming_blocks[0] = p->curr_block->preds[0]->block;
|
||||||
|
incoming_blocks[1] = p->curr_block->preds[1]->block;
|
||||||
|
|
||||||
|
LLVMAddIncoming(res, incoming_values, incoming_blocks, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
||||||
@@ -1350,33 +1497,20 @@ handle_op:;
|
|||||||
if (is_type_float(integral_type)) {
|
if (is_type_float(integral_type)) {
|
||||||
res.value = LLVMBuildFDiv(p->builder, lhs.value, rhs.value, "");
|
res.value = LLVMBuildFDiv(p->builder, lhs.value, rhs.value, "");
|
||||||
return res;
|
return res;
|
||||||
} else if (is_type_unsigned(integral_type)) {
|
} else {
|
||||||
res.value = LLVMBuildUDiv(p->builder, lhs.value, rhs.value, "");
|
res.value = lb_integer_division(p, lhs.value, rhs.value, !is_type_unsigned(integral_type));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
res.value = LLVMBuildSDiv(p->builder, lhs.value, rhs.value, "");
|
|
||||||
return res;
|
|
||||||
case Token_Mod:
|
case Token_Mod:
|
||||||
if (is_type_float(integral_type)) {
|
if (is_type_float(integral_type)) {
|
||||||
res.value = LLVMBuildFRem(p->builder, lhs.value, rhs.value, "");
|
res.value = LLVMBuildFRem(p->builder, lhs.value, rhs.value, "");
|
||||||
return res;
|
return res;
|
||||||
} else if (is_type_unsigned(integral_type)) {
|
|
||||||
res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, "");
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
res.value = LLVMBuildSRem(p->builder, lhs.value, rhs.value, "");
|
res.value = lb_integer_modulo(p, lhs.value, rhs.value, is_type_unsigned(integral_type), /*is_floored*/false);
|
||||||
return res;
|
return res;
|
||||||
case Token_ModMod:
|
case Token_ModMod:
|
||||||
if (is_type_unsigned(integral_type)) {
|
res.value = lb_integer_modulo(p, lhs.value, rhs.value, is_type_unsigned(integral_type), /*is_floored*/true);
|
||||||
res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, "");
|
return res;
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
LLVMValueRef a = LLVMBuildSRem(p->builder, lhs.value, rhs.value, "");
|
|
||||||
LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs.value, "");
|
|
||||||
LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs.value, "");
|
|
||||||
res.value = c;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Token_And:
|
case Token_And:
|
||||||
res.value = LLVMBuildAnd(p->builder, lhs.value, rhs.value, "");
|
res.value = LLVMBuildAnd(p->builder, lhs.value, rhs.value, "");
|
||||||
|
|||||||
+29
-1
@@ -392,6 +392,8 @@ enum BuildFlagKind {
|
|||||||
|
|
||||||
BuildFlag_PrintLinkerFlags,
|
BuildFlag_PrintLinkerFlags,
|
||||||
|
|
||||||
|
BuildFlag_IntegerDivisionByZero,
|
||||||
|
|
||||||
// internal use only
|
// internal use only
|
||||||
BuildFlag_InternalFastISel,
|
BuildFlag_InternalFastISel,
|
||||||
BuildFlag_InternalIgnoreLazy,
|
BuildFlag_InternalIgnoreLazy,
|
||||||
@@ -613,6 +615,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
|
|
||||||
add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build);
|
add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build);
|
||||||
|
|
||||||
|
add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check);
|
||||||
|
|
||||||
|
|
||||||
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
|
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
|
||||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
|
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
|
||||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
|
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
|
||||||
@@ -1515,7 +1520,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
} else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) {
|
} else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) {
|
||||||
build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix;
|
build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix;
|
||||||
} else {
|
} else {
|
||||||
gb_printf_err("-error-pos-style options are 'unix', 'odin' and 'default' (odin)\n");
|
gb_printf_err("-error-pos-style options are 'unix', 'odin', and 'default' (odin)\n");
|
||||||
bad_flags = true;
|
bad_flags = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1539,6 +1544,18 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
build_context.print_linker_flags = true;
|
build_context.print_linker_flags = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildFlag_IntegerDivisionByZero:
|
||||||
|
GB_ASSERT(value.kind == ExactValue_String);
|
||||||
|
if (str_eq_ignore_case(value.value_string, "trap")) {
|
||||||
|
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");
|
||||||
|
bad_flags = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BuildFlag_InternalFastISel:
|
case BuildFlag_InternalFastISel:
|
||||||
build_context.fast_isel = true;
|
build_context.fast_isel = true;
|
||||||
break;
|
break;
|
||||||
@@ -2561,7 +2578,18 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
|||||||
if (print_flag("-ignore-warnings")) {
|
if (print_flag("-ignore-warnings")) {
|
||||||
print_usage_line(2, "Ignores warning messages.");
|
print_usage_line(2, "Ignores warning messages.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
if (print_flag("-integer-division-by-zero:<strng>")) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check) {
|
||||||
if (print_flag("-json-errors")) {
|
if (print_flag("-json-errors")) {
|
||||||
print_usage_line(2, "Prints the error messages as json to stderr.");
|
print_usage_line(2, "Prints the error messages as json to stderr.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user