mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Add #+feature integer-division-by-zero:<string>
This commit is contained in:
@@ -352,12 +352,24 @@ u64 get_vet_flag_from_name(String const &name) {
|
|||||||
enum OptInFeatureFlags : u64 {
|
enum OptInFeatureFlags : u64 {
|
||||||
OptInFeatureFlag_NONE = 0,
|
OptInFeatureFlag_NONE = 0,
|
||||||
OptInFeatureFlag_DynamicLiterals = 1u<<0,
|
OptInFeatureFlag_DynamicLiterals = 1u<<0,
|
||||||
|
|
||||||
|
OptInFeatureFlag_IntegerDivisionByZero_Trap = 1u<<1,
|
||||||
|
OptInFeatureFlag_IntegerDivisionByZero_Zero = 1u<<2,
|
||||||
|
|
||||||
|
OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap|OptInFeatureFlag_IntegerDivisionByZero_Zero,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
u64 get_feature_flag_from_name(String const &name) {
|
u64 get_feature_flag_from_name(String const &name) {
|
||||||
if (name == "dynamic-literals") {
|
if (name == "dynamic-literals") {
|
||||||
return OptInFeatureFlag_DynamicLiterals;
|
return OptInFeatureFlag_DynamicLiterals;
|
||||||
}
|
}
|
||||||
|
if (name == "integer-division-by-zero:trap") {
|
||||||
|
return OptInFeatureFlag_IntegerDivisionByZero_Trap;
|
||||||
|
}
|
||||||
|
if (name == "integer-division-by-zero:zero") {
|
||||||
|
return OptInFeatureFlag_IntegerDivisionByZero_Zero;
|
||||||
|
}
|
||||||
return OptInFeatureFlag_NONE;
|
return OptInFeatureFlag_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-4
@@ -129,7 +129,7 @@ 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);
|
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node);
|
||||||
|
|
||||||
enum LoadDirectiveResult {
|
enum LoadDirectiveResult {
|
||||||
LoadDirective_Success = 0,
|
LoadDirective_Success = 0,
|
||||||
@@ -4311,7 +4311,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
|||||||
|
|
||||||
if (fail) {
|
if (fail) {
|
||||||
if (is_type_integer(x->type) || (x->mode == Addressing_Constant && x->value.kind == ExactValue_Integer)) {
|
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) {
|
if (check_for_integer_division_by_zero(c, node) == IntegerDivisionByZero_Zero) {
|
||||||
// Okay
|
// Okay
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -4371,7 +4371,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ
|
|||||||
match_exact_values(&a, &b);
|
match_exact_values(&a, &b);
|
||||||
|
|
||||||
|
|
||||||
if (check_for_integer_division_by_zero(node) == IntegerDivisionByZero_Zero &&
|
if (check_for_integer_division_by_zero(c, node) == IntegerDivisionByZero_Zero &&
|
||||||
b.kind == ExactValue_Integer && big_int_is_zero(&b.value_integer) &&
|
b.kind == ExactValue_Integer && big_int_is_zero(&b.value_integer) &&
|
||||||
(op.kind == Token_QuoEq || op.kind == Token_Mod || op.kind == Token_ModMod)) {
|
(op.kind == Token_QuoEq || op.kind == Token_Mod || op.kind == Token_ModMod)) {
|
||||||
if (op.kind == Token_QuoEq) {
|
if (op.kind == Token_QuoEq) {
|
||||||
@@ -9638,8 +9638,15 @@ 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) {
|
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) {
|
||||||
// TODO(bill): per file `#+feature` flags
|
// TODO(bill): per file `#+feature` flags
|
||||||
|
u64 flags = check_feature_flags(c, node);
|
||||||
|
if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) != 0) {
|
||||||
|
return IntegerDivisionByZero_Trap;
|
||||||
|
}
|
||||||
|
if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) != 0) {
|
||||||
|
return IntegerDivisionByZero_Zero;
|
||||||
|
}
|
||||||
return build_context.integer_division_by_zero_behaviour;
|
return build_context.integer_division_by_zero_behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,8 +283,26 @@ 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) {
|
gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) {
|
||||||
// TODO(bill): per file `#+feature` flags
|
AstFile *file = nullptr;
|
||||||
|
|
||||||
|
if (p->body && p->body->file()) {
|
||||||
|
file = p->body->file();
|
||||||
|
} else if (p->type_expr && p->type_expr->file()) {
|
||||||
|
file = p->type_expr->file();
|
||||||
|
} else if (p->entity && p->entity->file) {
|
||||||
|
file = p->entity->file;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != nullptr && file->feature_flags_set) {
|
||||||
|
u64 flags = file->feature_flags;
|
||||||
|
if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) {
|
||||||
|
return IntegerDivisionByZero_Trap;
|
||||||
|
}
|
||||||
|
if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) {
|
||||||
|
return IntegerDivisionByZero_Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
return build_context.integer_division_by_zero_behaviour;
|
return build_context.integer_division_by_zero_behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,7 +1161,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L
|
|||||||
|
|
||||||
incoming_values[1] = zero;
|
incoming_values[1] = zero;
|
||||||
|
|
||||||
switch (lb_check_for_integer_division_by_zero(p)) {
|
switch (lb_check_for_integer_division_by_zero_behaviour(p)) {
|
||||||
case IntegerDivisionByZero_Trap:
|
case IntegerDivisionByZero_Trap:
|
||||||
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
||||||
LLVMBuildUnreachable(p->builder);
|
LLVMBuildUnreachable(p->builder);
|
||||||
@@ -1158,7 +1176,7 @@ gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, L
|
|||||||
|
|
||||||
LLVMValueRef res = incoming_values[0];
|
LLVMValueRef res = incoming_values[0];
|
||||||
|
|
||||||
switch (lb_check_for_integer_division_by_zero(p)) {
|
switch (lb_check_for_integer_division_by_zero_behaviour(p)) {
|
||||||
case IntegerDivisionByZero_Trap:
|
case IntegerDivisionByZero_Trap:
|
||||||
res = incoming_values[0];
|
res = incoming_values[0];
|
||||||
break;
|
break;
|
||||||
@@ -1226,7 +1244,7 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV
|
|||||||
*/
|
*/
|
||||||
incoming_values[1] = lhs;
|
incoming_values[1] = lhs;
|
||||||
|
|
||||||
switch (lb_check_for_integer_division_by_zero(p)) {
|
switch (lb_check_for_integer_division_by_zero_behaviour(p)) {
|
||||||
case IntegerDivisionByZero_Trap:
|
case IntegerDivisionByZero_Trap:
|
||||||
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
||||||
LLVMBuildUnreachable(p->builder);
|
LLVMBuildUnreachable(p->builder);
|
||||||
@@ -1241,7 +1259,7 @@ gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLV
|
|||||||
|
|
||||||
LLVMValueRef res = incoming_values[0];
|
LLVMValueRef res = incoming_values[0];
|
||||||
|
|
||||||
switch (lb_check_for_integer_division_by_zero(p)) {
|
switch (lb_check_for_integer_division_by_zero_behaviour(p)) {
|
||||||
case IntegerDivisionByZero_Trap:
|
case IntegerDivisionByZero_Trap:
|
||||||
res = incoming_values[0];
|
res = incoming_values[0];
|
||||||
break;
|
break;
|
||||||
|
|||||||
+31
-13
@@ -6289,7 +6289,7 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
|
|||||||
return any_correct;
|
return any_correct;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal String vet_tag_get_token(String s, String *out) {
|
gb_internal String vet_tag_get_token(String s, String *out, bool allow_colon) {
|
||||||
s = string_trim_whitespace(s);
|
s = string_trim_whitespace(s);
|
||||||
isize n = 0;
|
isize n = 0;
|
||||||
while (n < s.len) {
|
while (n < s.len) {
|
||||||
@@ -6297,7 +6297,7 @@ gb_internal String vet_tag_get_token(String s, String *out) {
|
|||||||
isize width = utf8_decode(&s[n], s.len-n, &rune);
|
isize width = utf8_decode(&s[n], s.len-n, &rune);
|
||||||
if (n == 0 && rune == '!') {
|
if (n == 0 && rune == '!') {
|
||||||
|
|
||||||
} else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-') {
|
} else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-' && !(allow_colon && rune == ':')) {
|
||||||
isize k = gb_max(gb_max(n, width), 1);
|
isize k = gb_max(gb_max(n, width), 1);
|
||||||
*out = substring(s, k, s.len);
|
*out = substring(s, k, s.len);
|
||||||
return substring(s, 0, k);
|
return substring(s, 0, k);
|
||||||
@@ -6323,7 +6323,7 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) {
|
|||||||
u64 vet_not_flags = 0;
|
u64 vet_not_flags = 0;
|
||||||
|
|
||||||
while (s.len > 0) {
|
while (s.len > 0) {
|
||||||
String p = string_trim_whitespace(vet_tag_get_token(s, &s));
|
String p = string_trim_whitespace(vet_tag_get_token(s, &s, /*allow_colon*/false));
|
||||||
if (p.len == 0) {
|
if (p.len == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -6391,7 +6391,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
|
|||||||
u64 feature_not_flags = 0;
|
u64 feature_not_flags = 0;
|
||||||
|
|
||||||
while (s.len > 0) {
|
while (s.len > 0) {
|
||||||
String p = string_trim_whitespace(vet_tag_get_token(s, &s));
|
String p = string_trim_whitespace(vet_tag_get_token(s, &s, /*allow_colon*/true));
|
||||||
if (p.len == 0) {
|
if (p.len == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -6413,26 +6413,44 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) {
|
|||||||
} else {
|
} else {
|
||||||
feature_flags |= flag;
|
feature_flags |= flag;
|
||||||
}
|
}
|
||||||
|
if (is_notted) {
|
||||||
|
switch (flag) {
|
||||||
|
case OptInFeatureFlag_IntegerDivisionByZero_Trap:
|
||||||
|
case OptInFeatureFlag_IntegerDivisionByZero_Zero:
|
||||||
|
syntax_error(token_for_pos, "Feature flag does not support notting with '!' - '%.*s'", LIT(p));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
|
syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p));
|
||||||
error_line("\tExpected one of the following\n");
|
error_line("\tExpected one of the following\n");
|
||||||
error_line("\tdynamic-literals\n");
|
error_line("\tdynamic-literals\n");
|
||||||
|
error_line("\tinteger-division-by-zero:trap\n");
|
||||||
|
error_line("\tinteger-division-by-zero:zero\n");
|
||||||
return OptInFeatureFlag_NONE;
|
return OptInFeatureFlag_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 res = OptInFeatureFlag_NONE;
|
||||||
|
|
||||||
if (feature_flags == 0 && feature_not_flags == 0) {
|
if (feature_flags == 0 && feature_not_flags == 0) {
|
||||||
return OptInFeatureFlag_NONE;
|
res = OptInFeatureFlag_NONE;
|
||||||
}
|
} else if (feature_flags == 0 && feature_not_flags != 0) {
|
||||||
if (feature_flags == 0 && feature_not_flags != 0) {
|
res = OptInFeatureFlag_NONE &~ feature_not_flags;
|
||||||
return OptInFeatureFlag_NONE &~ feature_not_flags;
|
} else if (feature_flags != 0 && feature_not_flags == 0) {
|
||||||
}
|
res = feature_flags;
|
||||||
if (feature_flags != 0 && feature_not_flags == 0) {
|
} else {
|
||||||
return feature_flags;
|
|
||||||
}
|
|
||||||
GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
|
GB_ASSERT(feature_flags != 0 && feature_not_flags != 0);
|
||||||
return feature_flags &~ feature_not_flags;
|
res = feature_flags &~ feature_not_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res & OptInFeatureFlag_IntegerDivisionByZero_ALL) ==
|
||||||
|
OptInFeatureFlag_IntegerDivisionByZero_ALL) {
|
||||||
|
syntax_error(token_for_pos, "Only one integer-division-by-zero feature flag can be enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal String dir_from_path(String path) {
|
gb_internal String dir_from_path(String path) {
|
||||||
|
|||||||
Reference in New Issue
Block a user