From ddb1770af26bd6814b0ec8e53b650ce2e7fc4a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kr=C3=BCger?= <45282134+UweKrueger@users.noreply.github.com> Date: Wed, 17 Jun 2020 02:54:27 +0200 Subject: [PATCH] cgen: fix unsigned/signed integer comparisons --- vlib/v/gen/cgen.v | 26 ++++++++++++++++++++++++++ vlib/v/gen/cheaders.v | 15 +++++++++++++++ vlib/v/tests/int_cmp_test.v | 22 ++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 vlib/v/tests/int_cmp_test.v diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index af7f840bd2..caedad1108 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -41,6 +41,8 @@ const ( 'class', '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 { @@ -1688,11 +1690,21 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { // g.infix_op = node.op 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) + 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] { g.is_expr(node) return } 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 { fn_name := match node.op { .plus { @@ -1837,6 +1849,20 @@ fn (mut g Gen) infix_expr(node ast.InfixExpr) { } 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 { a := left_sym.name[0].is_capital() || left_sym.name.contains('.') b := left_sym.kind != .alias diff --git a/vlib/v/gen/cheaders.v b/vlib/v/gen/cheaders.v index 34637ddaae..9d804506d5 100644 --- a/vlib/v/gen/cheaders.v +++ b/vlib/v/gen/cheaders.v @@ -211,6 +211,21 @@ void* g_live_info = NULL; #define _IN(typ, val, arr) array_##typ##_contains(arr, 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__) #undef PRId64 #undef PRIi64 diff --git a/vlib/v/tests/int_cmp_test.v b/vlib/v/tests/int_cmp_test.v new file mode 100644 index 0000000000..3032f43bd7 --- /dev/null +++ b/vlib/v/tests/int_cmp_test.v @@ -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)) +}