From f01f79df0512ef16dc1ae681edf75e6924a8cf2e Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Wed, 5 Aug 2020 23:11:33 +0200 Subject: shift-assign: fix linearization of shift-assign The result of a shift-assigns has the same type as the left operand but the shift itself must be done on the promoted type. The usual conversions are not done for shifts. The problem is that this promoted type is not stored explicitly in the data structure. This is specific to shift-assigns because for other operations, for example add-assign, the usual conversions must be done and the resulting type can be found on the RHS. Since at linearization, the LHS and the RHS must have the same type, the solution is to cast the RHS to LHS's promoted type during evaluation. This solve a bunch of problems with shift-assigns, like doing logical shift when an arithmetic shift was needed. Fixes: efdefb100d086aaabf20d475c3d1a65cbceeb534 Signed-off-by: Luc Van Oostenryck --- evaluate.c | 6 +++++- validation/linear/bug-assign-op0.c | 1 - validation/linear/shift-assign1.c | 1 - validation/shift-undef.c | 16 ++++++++-------- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/evaluate.c b/evaluate.c index dddea761..6d8ecd7f 100644 --- a/evaluate.c +++ b/evaluate.c @@ -1342,8 +1342,12 @@ static int evaluate_assign_op(struct expression *expr) return 1; } else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) { // shifts do integer promotions, but that's it. + unrestrict(expr->left, tclass, &t); + target = integer_promotion(t); + unrestrict(expr->right, sclass, &s); - target = integer_promotion(s); + source = integer_promotion(s); + expr->right = cast_to(expr->right, source); goto Cast; } else if (!(sclass & TYPE_RESTRICT)) goto usual; diff --git a/validation/linear/bug-assign-op0.c b/validation/linear/bug-assign-op0.c index 0cabc622..b351bb51 100644 --- a/validation/linear/bug-assign-op0.c +++ b/validation/linear/bug-assign-op0.c @@ -46,7 +46,6 @@ unsigned int sldivu(unsigned int u, long s) /* * check-name: bug-assign-op0 * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-start asr: diff --git a/validation/linear/shift-assign1.c b/validation/linear/shift-assign1.c index 9b3137bb..4c96fc28 100644 --- a/validation/linear/shift-assign1.c +++ b/validation/linear/shift-assign1.c @@ -45,7 +45,6 @@ u64 u64u64(u64 a, u64 b) { a >>= b; return a; } /* * check-name: shift-assign1 * check-command: test-linearize -Wno-decl $file - * check-known-to-fail * * check-output-start s16s16: diff --git a/validation/shift-undef.c b/validation/shift-undef.c index 4e94fa23..613c6b95 100644 --- a/validation/shift-undef.c +++ b/validation/shift-undef.c @@ -140,23 +140,23 @@ shift-undef.c:32:11: warning: shift too big (100) for type int shift-undef.c:33:11: warning: shift too big (101) for type unsigned int shift-undef.c:34:11: warning: shift too big (102) for type unsigned int shift-undef.c:35:11: warning: shift count is negative (-1) -shift-undef.c:36:11: warning: shift count is negative (-2) -shift-undef.c:37:11: warning: shift count is negative (-3) +shift-undef.c:36:11: warning: shift too big (4294967294) for type unsigned int +shift-undef.c:37:11: warning: shift too big (4294967293) for type unsigned int shift-undef.c:38:25: warning: shift too big (103) for type int shift-undef.c:39:25: warning: shift too big (104) for type unsigned int shift-undef.c:40:25: warning: shift too big (105) for type unsigned int shift-undef.c:41:25: warning: shift count is negative (-4) -shift-undef.c:42:25: warning: shift count is negative (-5) -shift-undef.c:43:25: warning: shift count is negative (-6) +shift-undef.c:42:25: warning: shift too big (4294967291) for type unsigned int +shift-undef.c:43:25: warning: shift too big (4294967290) for type unsigned int shift-undef.c:44:30: warning: shift too big (106) for type int shift-undef.c:45:30: warning: shift too big (107) for type unsigned int shift-undef.c:46:30: warning: shift too big (108) for type unsigned int shift-undef.c:47:30: warning: shift count is negative (-7) -shift-undef.c:48:30: warning: shift count is negative (-8) -shift-undef.c:49:30: warning: shift count is negative (-9) +shift-undef.c:48:30: warning: shift too big (4294967288) for type unsigned int +shift-undef.c:49:30: warning: shift too big (4294967287) for type unsigned int shift-undef.c:50:26: warning: shift too big (109) for type int -shift-undef.c:51:26: warning: shift too big (110) for type int -shift-undef.c:52:26: warning: shift too big (111) for type int +shift-undef.c:51:26: warning: shift too big (110) for type unsigned int +shift-undef.c:52:26: warning: shift too big (111) for type unsigned int shift-undef.c:53:26: warning: shift count is negative (-10) shift-undef.c:54:26: warning: shift count is negative (-11) shift-undef.c:55:26: warning: shift count is negative (-12) -- cgit 1.2.3-korg