cgen: fix unsigned/signed integer comparisons

pull/5401/head
Uwe Krüger 2020-06-17 02:54:27 +02:00 committed by GitHub
parent 02f9b5d0e4
commit ddb1770af2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 0 deletions

View File

@ -41,6 +41,8 @@ const (
'class', 'class',
'typename' 'typename'
] ]
cmp_str = ['eq', 'ne', 'gt', 'lt', 'ge', 'le'] // same order as in token.Kind
cmp_rev = ['eq', 'ne', 'le', 'ge', 'lt', 'gt'] // when operands are switched
) )
struct Gen { struct Gen {
@ -1688,11 +1690,21 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
// g.infix_op = node.op // g.infix_op = node.op
left_type := if node.left_type == table.t_type { g.cur_generic_type } else { node.left_type } left_type := if node.left_type == table.t_type { g.cur_generic_type } else { node.left_type }
left_sym := g.table.get_type_symbol(left_type) left_sym := g.table.get_type_symbol(left_type)
unaliased_left := if left_sym.kind == .alias {
(left_sym.info as table.Alias).parent_typ
} else {
left_type
}
if node.op in [.key_is, .not_is] { if node.op in [.key_is, .not_is] {
g.is_expr(node) g.is_expr(node)
return return
} }
right_sym := g.table.get_type_symbol(node.right_type) right_sym := g.table.get_type_symbol(node.right_type)
unaliased_right := if right_sym.kind == .alias {
(right_sym.info as table.Alias).parent_typ
} else {
node.right_type
}
if left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in { if left_type == table.ustring_type_idx && node.op != .key_in && node.op != .not_in {
fn_name := match node.op { fn_name := match node.op {
.plus { .plus {
@ -1837,6 +1849,20 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) {
} }
g.write(' }))') g.write(' }))')
} }
} else if unaliased_left.idx() in [table.u32_type_idx, table.u64_type_idx] && unaliased_right.is_signed() && node.op in [.eq, .ne, .gt, .lt, .ge, .le] {
bitsize := if unaliased_left.idx() == table.u32_type_idx && unaliased_right.idx() != table.i64_type_idx { 32 } else { 64 }
g.write('_us${bitsize}_${cmp_str[int(node.op)-int(token.Kind.eq)]}(')
g.expr(node.left)
g.write(',')
g.expr(node.right)
g.write(')')
} else if unaliased_right.idx() in [table.u32_type_idx, table.u64_type_idx] && unaliased_left.is_signed() && node.op in [.eq, .ne, .gt, .lt, .ge, .le] {
bitsize := if unaliased_right.idx() == table.u32_type_idx && unaliased_left.idx() != table.i64_type_idx { 32 } else { 64 }
g.write('_us${bitsize}_${cmp_rev[int(node.op)-int(token.Kind.eq)]}(')
g.expr(node.right)
g.write(',')
g.expr(node.left)
g.write(')')
} else { } else {
a := left_sym.name[0].is_capital() || left_sym.name.contains('.') a := left_sym.name[0].is_capital() || left_sym.name.contains('.')
b := left_sym.kind != .alias b := left_sym.kind != .alias

View File

@ -211,6 +211,21 @@ void* g_live_info = NULL;
#define _IN(typ, val, arr) array_##typ##_contains(arr, val) #define _IN(typ, val, arr) array_##typ##_contains(arr, val)
#define _IN_MAP(val, m) map_exists(m, val) #define _IN_MAP(val, m) map_exists(m, val)
// unsigned/signed comparisons
static inline bool _us32_gt(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a > b; }
static inline bool _us32_ge(uint32_t a, int32_t b) { return a >= INT32_MAX || (int32_t)a >= b; }
static inline bool _us32_eq(uint32_t a, int32_t b) { return a <= INT32_MAX && (int32_t)a == b; }
static inline bool _us32_ne(uint32_t a, int32_t b) { return a > INT32_MAX || (int32_t)a != b; }
static inline bool _us32_le(uint32_t a, int32_t b) { return a <= INT32_MAX && (int32_t)a <= b; }
static inline bool _us32_lt(uint32_t a, int32_t b) { return a < INT32_MAX && (int32_t)a < b; }
static inline bool _us64_gt(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a > b; }
static inline bool _us64_ge(uint64_t a, int64_t b) { return a >= INT64_MAX || (int64_t)a >= b; }
static inline bool _us64_eq(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a == b; }
static inline bool _us64_ne(uint64_t a, int64_t b) { return a > INT64_MAX || (int64_t)a != b; }
static inline bool _us64_le(uint64_t a, int64_t b) { return a <= INT64_MAX && (int64_t)a <= b; }
static inline bool _us64_lt(uint64_t a, int64_t b) { return a < INT64_MAX && (int64_t)a < b; }
#if defined(__MINGW32__) || defined(__MINGW64__) #if defined(__MINGW32__) || defined(__MINGW64__)
#undef PRId64 #undef PRId64
#undef PRIi64 #undef PRIi64

View File

@ -0,0 +1,22 @@
fn test_cmp_signed() {
assert i8(3) > i16(-10)
assert i16(-9) > int(-11)
assert i64(-12) <= i8(-12)
assert i64(-43232554) < i8(-126)
}
fn test_cmp_unsigned() {
assert byte(3) < u16(10)
assert u16(40000) > u32(200)
assert u64(18161419857654944321) >= byte(12)
assert u64(40000) < u16(40001)
}
fn test_cmp_unsigned_signed() {
assert byte(12) > i8(-12)
assert i16(-27) < u32(65463356)
assert u32(8543) > int(-7523)
assert i64(-89) <= u64(567)
assert int(-1) != u32(0xffffffff)
assert !(u64(0xfffffffffffffffe) == i64(-2))
}