Module Name: src Committed By: rillig Date: Thu Jan 2 03:46:27 UTC 2025
Modified Files: src/tests/usr.bin/xlint/lint1: msg_132.c src/usr.bin/xlint/lint1: tree.c Log Message: lint: compute integer constraints for xor and minus These operators allow lint to correctly track the possible values in expressions that sign-extend an integer. To generate a diff of this commit: cvs rdiff -u -r1.48 -r1.49 src/tests/usr.bin/xlint/lint1/msg_132.c cvs rdiff -u -r1.665 -r1.666 src/usr.bin/xlint/lint1/tree.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/usr.bin/xlint/lint1/msg_132.c diff -u src/tests/usr.bin/xlint/lint1/msg_132.c:1.48 src/tests/usr.bin/xlint/lint1/msg_132.c:1.49 --- src/tests/usr.bin/xlint/lint1/msg_132.c:1.48 Wed Jan 1 14:09:28 2025 +++ src/tests/usr.bin/xlint/lint1/msg_132.c Thu Jan 2 03:46:27 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: msg_132.c,v 1.48 2025/01/01 14:09:28 rillig Exp $ */ +/* $NetBSD: msg_132.c,v 1.49 2025/01/02 03:46:27 rillig Exp $ */ # 3 "msg_132.c" // Test for message: conversion from '%s' to '%s' may lose accuracy [132] @@ -327,10 +327,59 @@ test_ic_plus(void) /* expect+1: warning: conversion from 'unsigned long long' to 'unsigned char' may lose accuracy [132] */ u8 = 256 + u64 % 1; + // XXX: No warnings since portable_rank_cmp is the same for both sides. + bits.u11 = bits.u10 + bits.u10 + 1; + bits.u11 = bits.u10 + bits.u10 + 2; + bits.u11 = bits.u10 + 1024; + bits.u11 = bits.u10 + 1025; + + u8 = bits.u7 + bits.u7 + 1; + /* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */ + u8 = bits.u7 + bits.u7 + 2; + u8 = bits.u7 + 128; + /* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */ + u8 = bits.u7 + 129; + + // The result of the second '+' wraps around, thus the warning, + // even though the final result fits in a u16. + /* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */ + u16 = u32 % 0x00010000 + 0x80000000 + 0x80000000; + + /* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */ + u16 = u32 % 0x00010000 + 0xffff8000; + /* expect+1: warning: conversion from 'unsigned int' to 'short' may lose accuracy [132] */ + s16 = u32 % 0x00010000 + 0xffff8000; + + /* expect+1: warning: conversion from 'long long' to 'unsigned short' may lose accuracy [132] */ + u16 = s64 % 0x00010000 + 0xffffffffLL + -0xffffffffLL; + /* expect+1: warning: conversion from 'int' to 'unsigned short' may lose accuracy [132] */ + u16 = s32 % 0x00010000 + 0x7fff0000 + -0x7fff0000; + /* expect+1: warning: conversion from 'unsigned int' to 'unsigned short' may lose accuracy [132] */ + u16 = u32 % 0x00010000 + 0xffff0000 + 0x00010000; + s8 = '0' + s64 % 10; } void +test_ic_minus(void) +{ + // Shift the range [0x00 to 0xff] to [-0x80 to 0x7f]. + s8 = (s64 & 0xff) - 0x80; + + // Sign-extend the lowest bits. + s8 = ((s64 & 0xff) ^ 0x80) - 0x80; + s16 = ((s64 & 0xffff) ^ 0x8000) - 0x8000; + /* expect+1: warning: extra bits set to 0 in conversion of 'unsigned int' to 'long long', op '&' [309] */ + s32 = ((s64 & 0xffffffff) ^ 0x80000000) - 0x80000000; + + // Trying to sign-extend, but with off-by-one errors. + /* expect+1: warning: conversion from 'long long' to 'signed char' may lose accuracy [132] */ + s8 = ((s64 & 0xff) ^ 0x80) - 0x7f; + /* expect+1: warning: conversion from 'long long' to 'signed char' may lose accuracy [132] */ + s8 = ((s64 & 0xff) ^ 0x80) - 0x81; +} + +void test_ic_shl(void) { u64 = u64 << u64; @@ -392,6 +441,20 @@ test_ic_bitand(void) } void +test_ic_bitxor(void) +{ + /* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */ + u8 = u8 ^ u16; + u16 = u8 ^ u16; + + // Sign-extend. + s8 = (u8 ^ 0x80) - 0x80; + s16 = (u16 ^ 0x8000) - 0x8000; + s32 = (u32 ^ 0x80000000) - 0x80000000; + s64 = (u64 ^ 0x8000000000000000) - 0x8000000000000000; +} + +void test_ic_bitor(void) { /* expect+1: warning: conversion from 'int' to 'unsigned char' may lose accuracy [132] */ Index: src/usr.bin/xlint/lint1/tree.c diff -u src/usr.bin/xlint/lint1/tree.c:1.665 src/usr.bin/xlint/lint1/tree.c:1.666 --- src/usr.bin/xlint/lint1/tree.c:1.665 Wed Jan 1 14:09:28 2025 +++ src/usr.bin/xlint/lint1/tree.c Thu Jan 2 03:46:27 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.665 2025/01/01 14:09:28 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.666 2025/01/02 03:46:27 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) -__RCSID("$NetBSD: tree.c,v 1.665 2025/01/01 14:09:28 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.666 2025/01/02 03:46:27 rillig Exp $"); #endif #include <float.h> @@ -83,43 +83,46 @@ u64_max(uint64_t a, uint64_t b) return a > b ? a : b; } -static int64_t -si_min_value(const type_t *tp) +static uint64_t +ui_max_value(const type_t *tp) { - uint64_t mask = value_bits(size_in_bits(tp->t_tspec)); - return -(int64_t)(mask >> 1) - 1; + return value_bits(size_in_bits(tp->t_tspec)); } static int64_t si_max_value(const type_t *tp) { - uint64_t mask = value_bits(size_in_bits(tp->t_tspec)); - return (int64_t)(mask >> 1); + return (int64_t)(ui_max_value(tp) >> 1); } -static uint64_t -ui_max_value(const type_t *tp) +static int64_t +si_min_value(const type_t *tp) { - return value_bits(size_in_bits(tp->t_tspec)); + return -si_max_value(tp) - 1; } static int64_t si_plus_sat(const type_t *tp, int64_t a, int64_t b) { - if (a >= 0) { + if (b >= 0) { int64_t max = si_max_value(tp); - return b <= max - a ? a + b : max; + return a <= max - b ? a + b : max; } else { int64_t min = si_min_value(tp); - return b >= min - a ? a + b : min; + return a >= min - b ? a + b : min; } } -static uint64_t -ui_plus_sat(const type_t *tp, uint64_t a, uint64_t b) +static int64_t +si_minus_sat(const type_t *tp, int64_t a, int64_t b) { - uint64_t max = ui_max_value(tp); - return b <= max - a ? a + b : max; + if (b >= 0) { + int64_t min = si_min_value(tp); + return a >= min + b ? a - b : min; + } else { + int64_t max = si_max_value(tp); + return a <= max + b ? a - b : max; + } } static uint64_t @@ -175,10 +178,11 @@ ic_any(const type_t *tp) { integer_constraints c; - uint64_t vbits = value_bits(width_in_bits(tp)); + unsigned width = width_in_bits(tp); + uint64_t vbits = value_bits(width); if (is_uinteger(tp->t_tspec)) { - c.smin = INT64_MIN; - c.smax = INT64_MAX; + c.smin = width < 64 ? 0 : INT64_MIN; + c.smax = width < 64 ? (int64_t)vbits : INT64_MAX; c.umin = 0; c.umax = vbits; c.bclr = ~c.umax; @@ -260,13 +264,55 @@ ic_mod(const type_t *tp, integer_constra static integer_constraints ic_plus(const type_t *tp, integer_constraints a, integer_constraints b) { - bool maybe_signed = ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b); + if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)) { + integer_constraints c; + c.smin = si_plus_sat(tp, a.smin, b.smin); + c.smax = si_plus_sat(tp, a.smax, b.smax); + c.umin = 0; + c.umax = UINT64_MAX; + c.bclr = 0; + return c; + } + uint64_t max = ui_max_value(tp); integer_constraints c; - c.smin = maybe_signed ? si_plus_sat(tp, a.smin, b.smin) : INT64_MIN; - c.smax = maybe_signed ? si_plus_sat(tp, a.smax, b.smax) : INT64_MAX; - c.umin = maybe_signed ? 0 : ui_plus_sat(tp, a.umin, b.umin); - c.umax = maybe_signed ? UINT64_MAX : ui_plus_sat(tp, a.umax, b.umax); + c.smin = INT64_MIN; + c.smax = INT64_MAX; + if (b.umax <= max - a.umax) { + c.umin = a.umin + b.umin; + c.umax = a.umax + b.umax; + } else { + c.umin = 0; + c.umax = max; + } + c.bclr = ~u64_fill_right(c.umax); + return c; +} + +static integer_constraints +ic_minus(const type_t *tp, integer_constraints a, integer_constraints b) +{ + if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)) { + integer_constraints c; + c.smin = si_minus_sat(tp, a.smin, b.smax); + c.smax = si_minus_sat(tp, a.smax, b.smin); + c.umin = 0; + c.umax = UINT64_MAX; + c.bclr = 0; + return c; + } + + integer_constraints c; + c.smin = si_minus_sat(tp, a.smin, b.smax); + c.smax = si_minus_sat(tp, a.smax, b.smin); + if (a.umin >= b.umax) { + c.umin = a.umin - b.umax; + c.umax = a.umax - b.umin; + } else { + c.umin = 0; + c.umax = is_uinteger(tp->t_tspec) ? ui_max_value(tp) + : UINT64_MAX; + } c.bclr = ~u64_fill_right(c.umax); return c; } @@ -337,6 +383,21 @@ ic_bitand(integer_constraints a, integer } static integer_constraints +ic_bitxor(const type_t *tp, integer_constraints a, integer_constraints b) +{ + integer_constraints c = ic_any(tp); + if (ic_maybe_signed(tp, &a) || ic_maybe_signed(tp, &b)) + return c; + c.umax = a.umax | b.umax; + if (c.umax >> 63 == 0) { + c.smin = 0; + c.smax = (int64_t)c.umax; + } + c.bclr = a.bclr & b.bclr; + return c; +} + +static integer_constraints ic_bitor(integer_constraints a, integer_constraints b) { integer_constraints c; @@ -417,6 +478,10 @@ ic_expr(const tnode_t *tn) lc = ic_expr(before_conversion(tn->u.ops.left)); rc = ic_expr(before_conversion(tn->u.ops.right)); return ic_plus(tn->tn_type, lc, rc); + case MINUS: + lc = ic_expr(before_conversion(tn->u.ops.left)); + rc = ic_expr(before_conversion(tn->u.ops.right)); + return ic_minus(tn->tn_type, lc, rc); case SHL: lc = ic_expr(tn->u.ops.left); rc = ic_expr(tn->u.ops.right); @@ -429,6 +494,10 @@ ic_expr(const tnode_t *tn) lc = ic_expr(tn->u.ops.left); rc = ic_expr(tn->u.ops.right); return ic_bitand(lc, rc); + case BITXOR: + lc = ic_expr(tn->u.ops.left); + rc = ic_expr(tn->u.ops.right); + return ic_bitxor(tn->tn_type, lc, rc); case BITOR: lc = ic_expr(tn->u.ops.left); rc = ic_expr(tn->u.ops.right);