|
From: Jerry J. <log...@gm...> - 2017-02-24 21:44:44
|
It's great that development on clisp has picked back up. Thanks, Sam
and Bruno, for all your work.
Fedora recently rebuilt all packages with GCC 7. The i386 and x86_64
builds succeeded, but the 32-bit ARM build failed, like so:
(PROGN (DEFMETHOD UPDATE-INSTANCE-FOR-REDEFINED-CLASS :BEFORE ((POS
X-Y-POSITION) ADDED DELETED PLIST &KEY) (LET ((X (GETF PLIST 'X)) (Y
(GETF PLIST 'Y))) (SETF (POSITION-RHO POS) (SQRT (+ (* X X) (* Y Y)))
(POSITION-THETA POS) (ATAN Y X)))) (DEFCLASS X-Y-POSITION
(ABSTRACT-POSITION) ((RHO :INITFORM 0 :ACCESSOR POSITION-RHO) (THETA
:INITFORM 0 :ACCESSOR POSITION-THETA))) (DEFMETHOD POSITION-X ((POS
X-Y-POSITION)) (WITH-SLOTS (RHO THETA) POS (* RHO (COS THETA))))
(DEFMETHOD (SETF POSITION-X) (NEW-X (POS X-Y-POSITION)) (WITH-SLOTS
(RHO THETA) POS (LET ((Y (POSITION-Y POS))) (SETQ RHO (SQRT (+ (*
NEW-X NEW-X) (* Y Y))) THETA (ATAN Y NEW-X)) NEW-X))) (DEFMETHOD
POSITION-Y ((POS X-Y-POSITION)) (WITH-SLOTS (RHO THETA) POS (* RHO
(SIN THETA)))) (DEFMETHOD (SETF POSITION-Y) (NEW-Y (POS X-Y-POSITION))
(WITH-SLOTS (RHO THETA) POS (LET ((X (POSITION-X POS))) (SETQ RHO
(SQRT (+ (* X X) (* NEW-Y NEW-Y))) THETA (ATAN NEW-Y X)) NEW-Y)))
(LIST (TYPE-OF I) (POSITION-X I) (POSITION-Y I) (POSITION-RHO I)
(POSITION-THETA I)))
WARNING: DEFCLASS: Class X-Y-POSITION (or one of its ancestors) is being
redefined, instances are obsolete
WARNING: Removing method
#1=#<STANDARD-WRITER-METHOD (#2=#<BUILT-IN-CLASS T>
#3=#<STANDARD-CLASS X-Y-POSITION :VERSION 1>)>
from an already called generic function
#<STANDARD-GENERIC-FUNCTION (SETF POSITION-Y)>
WARNING: Removing method
#1=#<STANDARD-WRITER-METHOD (#2=#<BUILT-IN-CLASS T>
#3=#<STANDARD-CLASS X-Y-POSITION :VERSION 1>)>
from an already called generic function
#<STANDARD-GENERIC-FUNCTION (SETF POSITION-X)>
WARNING: DEFCLASS: Class X-Y-POSITION (or one of its ancestors) is being
redefined, instances are obsolete
*** - Internal error: statement in file "../src/record.d", line 1543 has been
reached!!
Real time: 29.498787 sec.
Run time: 28.986 sec.
Space: 35364284 Bytes
GC: 70, GC time: 0.853 sec.
Please see <http://clisp.org/impnotes/faq.html#faq-bugs> for bug
reporting instructions.
Bye.
After fruitlessly staring at the source code for awhile, trying to
divine how this could possibly happen, I decided to stare at the
preprocessed code instead. I made it more readable by removing some
extra parentheses, reformatting, replacing some equivalent types, and
calculating some compile-time constants:
obj = mv_space[0];
((Instance)((unsigned long)obj-1UL))->tfl |= 2048UL;
{
break_sems.einzeln[1] = 1;
{
Instance ptr = (Instance)((unsigned
long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL);
ptr->tfl |= 256UL;
ptr->inst_class_version = obj;
break_sems.einzeln[1] = 0;
}
}
if (!(((((Record)((unsigned
long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL))->tfl >> 8) & 0xFF) &
1UL))
error_notreached("../src/record.d",1543);
It dawned on me that this might be an aliasing issue. The pointer
derived from ((unsigned long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL)
is visible in this scope twice, once cast to an Instance (pointer to
an anonymous struct) and once cast to a Record (record_ *). I tried
building with -fno-strict-aliasing and sure enough, the build
succeeded.
What do you think about changing line 1543 to:
ASSERT(record_flags(TheInstance(STACK_(2+4+2*kept_slots))) &
instflags_forwarded_B);
, or maybe making an Instance_flags(obj) macro that expands to
record_flags(TheInstance(obj))? That makes the two pointers have the
same type, thereby solving the aliasing issue. I have done a test
build with this change and it does indeed fix the problem. Regards,
--
Jerry James
http://www.jamezone.org/
|
|
From: Bruno H. <br...@cl...> - 2017-02-26 17:45:08
|
Hi Jerry, You wrote in <https://sourceforge.net/p/clisp/mailman/message/35687181/>: > *** - Internal error: statement in file "../src/record.d", line 1543 has been > reached!! > Real time: 29.498787 sec. > ... > After fruitlessly staring at the source code for awhile, trying to > divine how this could possibly happen, I decided to stare at the > preprocessed code instead. I made it more readable by removing some > extra parentheses, reformatting, replacing some equivalent types, and > calculating some compile-time constants: > > obj = mv_space[0]; > ((Instance)((unsigned long)obj-1UL))->tfl |= 2048UL; > { > break_sems.einzeln[1] = 1; > { > Instance ptr = (Instance)((unsigned > long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL); > ptr->tfl |= 256UL; > ptr->inst_class_version = obj; > break_sems.einzeln[1] = 0; > } > } > if (!(((((Record)((unsigned > long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL))->tfl >> 8) & 0xFF) & > 1UL)) > error_notreached("../src/record.d",1543); > > It dawned on me that this might be an aliasing issue. The pointer > derived from ((unsigned long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL) > is visible in this scope twice, once cast to an Instance (pointer to > an anonymous struct) and once cast to a Record (record_ *). I tried > building with -fno-strict-aliasing and sure enough, the build > succeeded. Wow! You hit the nail on the head. > What do you think about changing line 1543 to: > > ASSERT(record_flags(TheInstance(STACK_(2+4+2*kept_slots))) & > instflags_forwarded_B); > > , or maybe making an Instance_flags(obj) macro that expands to > record_flags(TheInstance(obj))? That makes the two pointers have the > same type, thereby solving the aliasing issue. The clisp code has many situations like this. It's not only between TheRecord and TheInstance, but surely also between TheRecord and ThePackage, TheRecord and TheHashtable, TheVarobject and TheSstring, and so on. Therefore the result of the solution you are hinting at would be a huge union type with 50 alternatives. At a lot of clisp code to rewrite. I'm choosing the follow way you went: add a compiler option. Basically, I want a compiler that translates that statements I wrote, not a compiler that makes optimizations on the premise that the code I wrote is buggy when it violates the letter of C99. Bruno --- a/src/makemake.in Sun Feb 26 18:27:03 2017 +0100 +++ b/src/makemake.in Sun Feb 26 18:30:41 2017 +0100 @@ -1325,6 +1327,23 @@ fi +# We access the same memory through pointers of different types, for example +# as TheVarobject(obj)->..., TheRecord(obj)->..., TheInstance(obj)->... . +# This violates the strict type-based aliasing rules of C. In other words, we +# still use C as a portable assembler, but now the compilers want to outsmart +# us. There are two ways to tell them not to do this: to use union types, or +# specific compiler options. I prefer to do it through compiler options. +if [ $XCC_GCC = true ] ; then + XCFLAGS=$XCFLAGS' -fno-strict-aliasing' +else + if [ "$HSYSOS" = aix ] ; then # for xlc + XCFLAGS=$XCFLAGS' -qalias=noansi' + fi + if [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc + XCFLAGS=$XCFLAGS' -xalias_level=weak' + fi +fi + if [ "${with_dynamic_modules}" != no ]; then # not on msvc # Support for dynamic loading. eval "`./libtool --tag=CC --config | grep '^pic_flag='`" |
|
From: Sam S. <sd...@gn...> - 2017-02-27 18:12:27
|
Hi Bruno, > * Bruno Haible <oe...@py...> [2017-02-26 18:44:58 +0100]: > > You wrote in > <https://sourceforge.net/p/clisp/mailman/message/35687181/>: Do you have code to get this reference automatically? >> It dawned on me that this might be an aliasing issue. The pointer >> derived from ((unsigned long)STACK[-1-(long)(2+4+2*kept_slots)]-1UL) >> is visible in this scope twice, once cast to an Instance (pointer to >> an anonymous struct) and once cast to a Record (record_ *). I tried >> building with -fno-strict-aliasing and sure enough, the build >> succeeded. > > Wow! You hit the nail on the head. Without posting any (or at least not much) assembly, could you please explain what gcc does with -fstrict-aliasing? Specifically, I always thought that float f; unsigned int i = *(unsigned int *)&f; is compiled to an inline memcpy or something. what does gcc do instead when it detects aliasing? (you can assume that I read http://stackoverflow.com/q/98650/850781 and http://stackoverflow.com/q/98340/850781 carefully, but no more than that). > --- a/src/makemake.in Sun Feb 26 18:27:03 2017 +0100 > +++ b/src/makemake.in Sun Feb 26 18:30:41 2017 +0100 > @@ -1325,6 +1327,23 @@ > > fi > > +# We access the same memory through pointers of different types, for example > +# as TheVarobject(obj)->..., TheRecord(obj)->..., TheInstance(obj)->... . > +# This violates the strict type-based aliasing rules of C. In other words, we > +# still use C as a portable assembler, but now the compilers want to outsmart > +# us. There are two ways to tell them not to do this: to use union types, or > +# specific compiler options. I prefer to do it through compiler options. > +if [ $XCC_GCC = true ] ; then > + XCFLAGS=$XCFLAGS' -fno-strict-aliasing' > +else > + if [ "$HSYSOS" = aix ] ; then # for xlc > + XCFLAGS=$XCFLAGS' -qalias=noansi' > + fi > + if [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc > + XCFLAGS=$XCFLAGS' -xalias_level=weak' > + fi > +fi > + > if [ "${with_dynamic_modules}" != no ]; then # not on msvc > # Support for dynamic loading. > eval "`./libtool --tag=CC --config | grep '^pic_flag='`" shouldn't it be something like --8<---------------cut here---------------start------------->8--- diff -r 208ade5c97ca src/makemake.in --- a/src/makemake.in Sun Feb 26 20:07:47 2017 -0500 +++ b/src/makemake.in Mon Feb 27 13:05:45 2017 -0500 @@ -1335,13 +1335,12 @@ fi # specific compiler options. I prefer to do it through compiler options. if [ $XCC_GCC = true ] ; then XCFLAGS=$XCFLAGS' -fno-strict-aliasing' -else - if [ "$HSYSOS" = aix ] ; then # for xlc +elif [ "$HSYSOS" = aix ] ; then # for xlc XCFLAGS=$XCFLAGS' -qalias=noansi' - fi - if [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc +elif [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc XCFLAGS=$XCFLAGS' -xalias_level=weak' - fi +elif [ "${with_debug}" != no ]; then + echo "$0: WARNING: how to disable strict aliasing with ${XCC} on ${HSYSOS}?" >&2 fi if [ "${with_dynamic_modules}" != no ]; then # not on msvc --8<---------------cut here---------------end--------------->8--- -- Sam Steingold (http://sds.podval.org/) on darwin Ns 10.3.1504 http://steingoldpsychology.com http://www.childpsy.net http://memri.org http://think-israel.org http://camera.org http://www.dhimmitude.org He who laughs last did not get the joke. |
|
From: Bruno H. <br...@cl...> - 2017-02-27 21:36:17
|
Hi Sam, > > You wrote in > > <https://sourceforge.net/p/clisp/mailman/message/35687181/>: > > Do you have code to get this reference automatically? No, I look it up through the web interface of Sourceforge. > Without posting any (or at least not much) assembly, could you please > explain what gcc does with -fstrict-aliasing? 1) It makes assumptions. Specifically it assumes that two pointers A* and B* cannot point to the same memory address if A and B are the same type and neither A* and B* is 'char *'. 2) It makes optimizations based on these assumptions. For example, it can eliminate memory accesses A* p; B* q; x = *p; *q = y; x = *p; => A* p; B* q; x = *p; *q = y; or reorder code: A* p; B* q; x = *p; *q = y; => A* p; B* q; *q = y; x = *p; but it can do much more optimizations. > diff -r 208ade5c97ca src/makemake.in > --- a/src/makemake.in Sun Feb 26 20:07:47 2017 -0500 > +++ b/src/makemake.in Mon Feb 27 13:05:45 2017 -0500 > @@ -1335,13 +1335,12 @@ fi > # specific compiler options. I prefer to do it through compiler options. > if [ $XCC_GCC = true ] ; then > XCFLAGS=$XCFLAGS' -fno-strict-aliasing' > -else > - if [ "$HSYSOS" = aix ] ; then # for xlc > +elif [ "$HSYSOS" = aix ] ; then # for xlc > XCFLAGS=$XCFLAGS' -qalias=noansi' > - fi > - if [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc > +elif [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc > XCFLAGS=$XCFLAGS' -xalias_level=weak' > - fi > +elif [ "${with_debug}" != no ]; then > + echo "$0: WARNING: how to disable strict aliasing with ${XCC} on ${HSYSOS}?" >&2 > fi > > if [ "${with_dynamic_modules}" != no ]; then # not on msvc The users of the configure script are most often our users, not ourselves, therefore such a warning it not very helpful. It'd be more helpful to find out the option for other compilers. The code already handles gcc, clang, xlc, and Sun Studio cc. What other compilers may be reasonably used to compile clisp? Can you look up the corresponding option? Bruno |
|
From: Sam S. <sd...@gn...> - 2017-02-27 23:22:38
|
Hi Bruno,
> * Bruno Haible <oe...@py...> [2017-02-27 22:36:07 +0100]:
>
>> diff -r 208ade5c97ca src/makemake.in
>> --- a/src/makemake.in Sun Feb 26 20:07:47 2017 -0500
>> +++ b/src/makemake.in Mon Feb 27 13:05:45 2017 -0500
>> @@ -1335,13 +1335,12 @@ fi
>> # specific compiler options. I prefer to do it through compiler options.
>> if [ $XCC_GCC = true ] ; then
>> XCFLAGS=$XCFLAGS' -fno-strict-aliasing'
>> -else
>> - if [ "$HSYSOS" = aix ] ; then # for xlc
>> +elif [ "$HSYSOS" = aix ] ; then # for xlc
>> XCFLAGS=$XCFLAGS' -qalias=noansi'
>> - fi
>> - if [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc
>> +elif [ -n "$XCC_SUNPRO" ] ; then # for SUNWspro cc
>> XCFLAGS=$XCFLAGS' -xalias_level=weak'
>> - fi
>> +elif [ "${with_debug}" != no ]; then
>> + echo "$0: WARNING: how to disable strict aliasing with ${XCC} on ${HSYSOS}?" >&2
>> fi
>>
>> if [ "${with_dynamic_modules}" != no ]; then # not on msvc
>
> The users of the configure script are most often our users, not ourselves,
> therefore such a warning it not very helpful.
On a second thought, this appears like a clear case for an autoconf test:
check whether the default compiler does strict aliasing optimizations
and, if it does, try to disable them, and if we cannot disable them,
fail configure.
--
Sam Steingold (http://sds.podval.org/) on darwin Ns 10.3.1504
http://steingoldpsychology.com http://www.childpsy.net https://jihadwatch.org
http://www.dhimmitude.org http://www.memritv.org http://islamexposedonline.com
There are two ways to win an argument with a woman. Neither works.
|
|
From: Bruno H. <br...@cl...> - 2017-02-27 23:49:05
|
Sam, > On a second thought, this appears like a clear case for an autoconf test: > check whether the default compiler does strict aliasing optimizations > and, if it does, try to disable them, and if we cannot disable them, > fail configure. Yes. Excellent idea! Even with compilers that we have never heard of, this will do the right thing: bark at high optimization levels, and be silent when not optimizing. Bruno |
|
From: Pascal B. <pj...@in...> - 2017-02-27 23:54:28
|
> On 28 Feb 2017, at 00:48, Bruno Haible <br...@cl...> wrote: > > Sam, > >> On a second thought, this appears like a clear case for an autoconf test: >> check whether the default compiler does strict aliasing optimizations >> and, if it does, try to disable them, and if we cannot disable them, >> fail configure. > > Yes. Excellent idea! Even with compilers that we have never heard of, this will > do the right thing: bark at high optimization levels, and be silent when not > optimizing. The thing with optimizations is that you don’t get to decide when the compiler will apply them. So, the actual test program you will have to compile while configuring, will be the actual program. Only so, you can be sure whether the compiler did the optimization. -- __Pascal J. Bourguignon__ |
|
From: Bruno H. <br...@cl...> - 2017-02-28 00:31:39
|
Pascal, > >> On a second thought, this appears like a clear case for an autoconf test: > >> check whether the default compiler does strict aliasing optimizations > >> and, if it does, try to disable them, and if we cannot disable them, > >> fail configure. > > > > Yes. Excellent idea! Even with compilers that we have never heard of, this will > > do the right thing: bark at high optimization levels, and be silent when not > > optimizing. > > > > The thing with optimizations is that you don’t get to decide when the compiler will apply them. > So, the actual test program you will have to compile while configuring, will be the actual program. Only so, you can be sure whether the compiler did the optimization. I'm not so pessimistic. I guess it's possible to write a test that checks 1, 2, or 3 typical optimizations a compiler would do based on type-based aliasing analysis. Bruno |
|
From: Jason M. <ja...@mi...> - 2017-02-28 01:58:54
|
So we don't reinvent the wheel, John Regehr maintains a set of testcases for how compilers optimize undefined behaviors here: https://github.com/regehr/ub-canaries In particular see: https://github.com/regehr/ub-canaries/tree/master/strict-aliasing On 00:54 Tue 28 Feb , Pascal Bourguignon wrote: > On 28 Feb 2017, at 00:48, Bruno Haible <[1]br...@cl...> wrote: > > Sam, > > On a second thought, this appears like a clear case for an autoconf > test: > check whether the default compiler does strict aliasing > optimizations > and, if it does, try to disable them, and if we cannot disable them, > fail configure. > > Yes. Excellent idea! Even with compilers that we have never heard of, > this will > do the right thing: bark at high optimization levels, and be silent > when not > optimizing. > > The thing with optimizations is that you don’t get to decide when the > compiler will apply them. > > So, the actual test program you will have to compile while configuring, > will be the actual program. Only so, you can be sure whether the > compiler did the optimization. > -- > __Pascal J. Bourguignon__ > > References > > 1. mailto:br...@cl... > ------------------------------------------------------------------------------ > Check out the vibrant tech community on one of the world's most > engaging tech sites, SlashDot.org! http://sdm.link/slashdot > _______________________________________________ > clisp-devel mailing list > cli...@li... > https://lists.sourceforge.net/lists/listinfo/clisp-devel |