From a3ec92940dc1dda1f91d654e08b7bba36bc2300d Mon Sep 17 00:00:00 2001 From: dkf Date: Sat, 18 Sep 2004 19:17:10 +0000 Subject: Make sure large shifts shift for real. [Bug 868467] --- ChangeLog | 5 ++++ generic/tclExecute.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++----- tests/expr.test | 13 +++++++- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index c2f5a8a..7298a82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2004-09-18 Donal K. Fellows + + * generic/tclExecute.c (TEBC-INST_LSHIFT,INST_RSHIFT): Ensure that + large shifts end up shifting correctly. [Bug 868467] + 2004-09-15 Daniel Steffen * tests/load.test (load-2.3): adopted fix for failure on darwin diff --git a/generic/tclExecute.c b/generic/tclExecute.c index b0a94fe..ef4f379 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclExecute.c,v 1.94.2.8 2004/09/10 15:30:02 msofer Exp $ + * RCS: @(#) $Id: tclExecute.c,v 1.94.2.9 2004/09/18 19:17:12 dkf Exp $ */ #include "tclInt.h" @@ -3058,11 +3058,42 @@ TclExecuteByteCode(interp, codePtr) #ifdef TCL_COMPILE_DEBUG w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ - wResult = w << i2; + wResult = w; + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + wResult = Tcl_LongAsWide(0); + } else if (i2 > 60) { + wResult = w << 30; + wResult <<= 30; + wResult <<= i2-60; + } else if (i2 > 30) { + wResult = w << 30; + wResult <<= i2-30; + } else { + wResult = w << i2; + } doWide = 1; break; } - iResult = i << i2; + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + iResult = 0; + } else if (i2 > 60) { + iResult = i << 30; + iResult <<= 30; + iResult <<= i2-60; + } else if (i2 > 30) { + iResult = i << 30; + iResult <<= i2-30; + } else { + iResult = i << i2; + } break; case INST_RSHIFT: /* @@ -3079,17 +3110,55 @@ TclExecuteByteCode(interp, codePtr) w2 = Tcl_LongAsWide(i2); #endif /* TCL_COMPILE_DEBUG */ if (w < 0) { - wResult = ~((~w) >> i2); + wResult = ~w; + } else { + wResult = w; + } + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + wResult = Tcl_LongAsWide(0); + } else if (i2 > 60) { + wResult >>= 30; + wResult >>= 30; + wResult >>= i2-60; + } else if (i2 > 30) { + wResult >>= 30; + wResult >>= i2-30; } else { - wResult = w >> i2; + wResult >>= i2; + } + if (w < 0) { + wResult = ~wResult; } doWide = 1; break; } if (i < 0) { - iResult = ~((~i) >> i2); + iResult = ~i; + } else { + iResult = i; + } + /* + * Shift in steps when the shift gets large to prevent + * annoying compiler/processor bugs. [Bug 868467] + */ + if (i2 >= 64) { + iResult = 0; + } else if (i2 > 60) { + iResult >>= 30; + iResult >>= 30; + iResult >>= i2-60; + } else if (i2 > 30) { + iResult >>= 30; + iResult >>= i2-30; } else { - iResult = i >> i2; + iResult >>= i2; + } + if (i < 0) { + iResult = ~iResult; } break; case INST_BITOR: diff --git a/tests/expr.test b/tests/expr.test index 6ef1c41..b4b6917 100644 --- a/tests/expr.test +++ b/tests/expr.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: expr.test,v 1.17.2.1 2003/03/27 13:49:22 dkf Exp $ +# RCS: @(#) $Id: expr.test,v 1.17.2.2 2004/09/18 19:17:13 dkf Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -806,6 +806,17 @@ test expr-22.8 {non-numeric floats} nonPortable { list [catch {expr {1 / Inf}} msg] $msg } {1 {can't use infinite floating-point value as operand of "/"}} +# Some compilers get this wrong; ensure that we work around it correctly +test expr-24.1 {expr edge cases; shifting} {expr int(5)>>31} 0 +test expr-24.2 {expr edge cases; shifting} {expr int(5)>>63} 0 +test expr-24.3 {expr edge cases; shifting} {expr wide(5)>>31} 0 +test expr-24.4 {expr edge cases; shifting} {expr wide(5)>>63} 0 +test expr-24.5 {expr edge cases; shifting} nonPortable {expr int(5)<<31} 0 +test expr-24.6 {expr edge cases; shifting} {expr int(5)<<63} 0 +test expr-24.7 {expr edge cases; shifting} {expr wide(5)<<31} 10737418240 +test expr-24.8 {expr edge cases; shifting} nonPortable {expr wide(5)<<63} -9223372036854775808 +test expr-24.9 {expr edge cases; shifting} {expr 5>>32} 0 + # cleanup if {[info exists a]} { unset a -- cgit v0.12