Greetings, and thanks for your feedback! Stavros Macrakis <macra...@gmail.com> writes:
> Assuming that clause 2 applies to the loop in member > > 2) GCL will unroll loops over constant (and non-constant) lists up to > *src-loop-unroll-limit* (default 20) > > then this whole discussion is moot, since the vast majority (95%) of constant > lists of symbols are length 6 or less, and those are the often-used cases. > Unrolling the loop just allows the compiler to easily see the type of each element one at a time. But as this is later than the decision to compute the type integer on x, and as one does not know the unroll will succeed until it does, it will not help in avoiding the former unless there is an additional pass, or a backup/retry. Backup/retries can be exponentially bad in compile time in egregious nested cases. > Re > > 5) GCL will not attempt to aggregate the types across all elements of a > list, i.e. this whole list is of type symbol, so pull that out of the loop as > well. This > seems ill-advised and unpractical to me at least at the moment. > > I'm surprised by this, and don't understand why it would be "ill-advised and > unpractical", but as I say it's moot if (2) is applied. The cleanest optimizations are lisp code inserts in the function source which make sense in the generic case, and can be pruned by the compiler in special cases. Setting separate compiler-macros, inline property strings, or special compiler handler functions for a given function is fragile and error prone. We've made a lot of progress cleaning up a lot of the latter. It would be easy to add a check on the list alongside the check on x in the source to prune this extra branch in the test, but at the cost of an extra traversal of the list in the generic case, which seems like a loser. > > 3) GCL will pull the type-of on unknown x out of the loop and use it as a > key to a switch table inside the loop. > > Of course, this is unnecessary if arg 2 is a list of symbols, since eq > applies to all data types. In some styles of code, it might be faster to test > (and (symbolp x) (or > (eq x 'c1) (eq x 'c2) ...)), but in the case of Maxima this will almost > always slow things down rather than speed them up. > > The expression (member x '(a b c...) :test #'eq) strikes me as verbose and > pedantic. Code should be easily readable by humans, and the extra clause is > clearly > semantically unnecessary. memq is a bit better, but shouldn't be necessary > (there is nothing wrong with writing functions which encapsulate some useful > piece > of Common Lisp functionality). If a particular compiler chooses not to > optimize that idiom, I'd say that's the compiler's problem. But according to > Camm's > explanation, GCL does optimize it. So there's no issue. I agree in preferring the simple expression and relying on the compiler to do the right thing. I cannot think at the moment of any instance in GCL's own code which specifies :test #'eq. Take care, > > -s > > On Sat, May 3, 2025 at 6:37 AM Camm Maguire <c...@maguirefamily.org> wrote: > > Greetings! > > This is what is happening, with a twist. > > Since we don't know that *all* elements of the list will allow eql->eq > ahead of time (optimization 5), one runtime check on x is done outside > the loop to see if we can do eql->eq on that basis, e.g. an integer x0 > is computed. The test then becomes (if x0 (eq a b) (eql a b)), and then > eql goes to eq based on b anyway, so at the C level we have (if x0 (eq a > b) (eq a b)). All eql code in the example you cite has been eliminated. > We have no optimization trying to recognize identical branches and > eliminate the if. So instead of one machine instruction, you have two, > switch x0, (eq a b). > > Take care, > > David Scherfgen via Maxima-discuss > <maxima-disc...@lists.sourceforge.net> writes: > > > Thanks for the explanation, Camm. > > > > Optimizations 2) and 1) should suffice for this very common case in > Maxima's source to be optimized in GCL (just like SBCL does), optimization 5) > shouldn't > be > > necessary. > > > > Let's take the example (member x '(a b c)), i.e. unknown x and a list of > literal symbols. > > > > Via 2), GCL should unroll that into (or (eql x 'a) (eql x 'b) (eql x 'c)). > > > > Via 1), GCL should replace each of the (eql ...) with (eq ...), as one of > the arguments is a literal symbol. > > > > But that doesn't seem to be what's happening, right? > > > > Best regards > > David Scherfgen > > > > Camm Maguire <c...@maguirefamily.org> schrieb am Fr., 2. Mai 2025, 22:28: > > > > Greetings! Glad you noticed this. > > > > This touches on 4 optimizations currently in place in the compiler, and > > one that is not. > > > > 1) GCL will optimize eql to eq when it can infer the types on either arg > > that would permit this. > > > > 2) GCL will unroll loops over constant (and non-constant) lists up to > > *src-loop-unroll-limit* (default 20) > > > > 3) GCL will pull the type-of on unknown x out of the loop and use it as > > a key to a switch table inside the loop. > > > > 4) GCL will replace the loop entirely with its known result when > > possible. > > > > 5) GCL will not attempt to aggregate the types across all elements of a > > list, i.e. this whole list is of type symbol, so pull that out of the > > loop as well. This seems ill-advised and unpractical to me at least at > > the moment. > > > > You can get more info on what is happening by setting > > compiler::*annotate* to t before running disassemble. If you only want > > the C code and not the disassembly, (setq > > compiler::*disassemble-objdump* nil). > > > > You can also see the lisp source of member: > > > > ('si::fle is shorthand for 'function-lambda-expression) > > > > > ============================================================================= > > (si::fle 'member) > > > ============================================================================= > > (LAMBDA > > (SYSTEM::ITEM LIST &KEY SYSTEM::KEY SYSTEM::TEST SYSTEM::TEST-NOT) > > (DECLARE (OPTIMIZE (SAFETY 1))) (CHECK-TYPE LIST PROPER-LIST) > > (CHECK-TYPE SYSTEM::TEST (OR NULL SYSTEM::FUNCTION-DESIGNATOR)) > > (CHECK-TYPE SYSTEM::TEST-NOT (OR NULL SYSTEM::FUNCTION-DESIGNATOR)) > > (CHECK-TYPE SYSTEM::KEY (OR NULL SYSTEM::FUNCTION-DESIGNATOR)) > > (BLOCK > > MEMBER > > (LET* > > ((#:G568 > > (COERCE (OR SYSTEM::TEST SYSTEM::TEST-NOT #'EQL) 'FUNCTION)) > > (#:G569 > > (IF > > (EQ #:G568 #'EQ) 0 > > (IF > > (EQ #:G568 #'EQL) 1 > > (IF > > (EQ #:G568 #'EQUAL) 2 > > (IF (EQ #:G568 #'EQUALP) 3 (IF (EQ #:G568 #'FUNCALL) 4 5)))))) > > (#:G570 (IF SYSTEM::KEY (COERCE SYSTEM::KEY 'FUNCTION))) > > (#:G570 (IF (NOT (EQ #:G570 #'IDENTITY)) #:G570))) > > (AND > > SYSTEM::TEST SYSTEM::TEST-NOT > > (ERROR "both test and test not supplied")) > > (LET* > > NIL > > (LABELS > > ((SYSTEM::KEY > > (SYSTEM::X) (IF #:G570 (FUNCALL #:G570 SYSTEM::X) SYSTEM::X)) > > (SYSTEM::TEST-NO-KEY > > (SYSTEM::X SYSTEM::Y) > > (IF > > (CASE > > #:G569 (0 (EQ SYSTEM::X SYSTEM::Y)) > > (1 (EQL SYSTEM::X SYSTEM::Y)) (2 (EQUAL SYSTEM::X SYSTEM::Y)) > > (3 (EQUALP SYSTEM::X SYSTEM::Y)) > > (4 (FUNCALL SYSTEM::X SYSTEM::Y)) > > (OTHERWISE (FUNCALL #:G568 SYSTEM::X SYSTEM::Y))) > > (NOT SYSTEM::TEST-NOT) SYSTEM::TEST-NOT)) > > (SYSTEM::TEST > > (SYSTEM::X SYSTEM::Y) > > (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y)))) > > (DECLARE (IGNORABLE #'SYSTEM::TEST)) > > (IF > > (CASE > > #:G569 > > ((1 2 3) > > (OR > > (CASE > > #:G569 (1 (EQL-IS-EQ SYSTEM::ITEM)) > > (2 (EQUAL-IS-EQ SYSTEM::ITEM)) > > (3 (EQUALP-IS-EQ SYSTEM::ITEM)))))) > > (SETQ #:G569 0)) > > (MACROLET > > ((SYSTEM::COLLECT > > (SYSTEM::A SYSTEM::B SYSTEM::C) > > (LIST > > 'LET (LIST (LIST 'SYSTEM::TMP SYSTEM::A)) > > (LIST > > 'SETQ SYSTEM::C > > (LIST > > 'IF SYSTEM::C > > (LIST 'CDR (LIST 'RPLACD SYSTEM::C 'SYSTEM::TMP)) > > (LIST 'SETQ SYSTEM::B 'SYSTEM::TMP)))))) > > (IF > > (NOT > > (MAPL > > (LAMBDA > > (SYSTEM::X) > > (IF > > (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X)) > > (RETURN-FROM MEMBER SYSTEM::X))) > > LIST)) > > NIL))))))) > > > ============================================================================= > > > > Some examples: > > > > > ============================================================================= > > Unknown x & y, (disassemble '(lambda (x y) (member x y)) > > loop not unrolled, type-of x pulled out, eql used unless runtime > > determination of x allows eq. > > > ============================================================================= > > static object LI1__CMP_ANON___gazonk_2205667_0(register object V3,object > V4) > > { VMB1 VMS1 VMV1 > > /*(MEMBER X Y)*/ > > {register fixnum V5; > > V5= 1; > > /*(EQL-IS-EQ SYSTEM::ITEM)*/ > > switch(/* (APPLIED TP4 SYSTEM::X) */tp4(V3)){ > > case -1: > > goto T7; > > T7:; > > goto T5; > > > > case 1: > > goto T8; > > T8:; > > case 2: > > goto T9; > > T9:; > > case 3: > > goto T10; > > T10:; > > case 4: > > goto T11; > > T11:; > > case 5: > > goto T12; > > T12:; > > case 6: > > goto T13; > > T13:; > > goto T3; > > > > default: > > goto T14; > > T14:; > > goto T5; > > > > goto T3; > > } > > goto T3; > > > > /* END (EQL-IS-EQ SYSTEM::ITEM)*/ > > goto T5; > > T5:; > > V5= 0; > > goto T2; > > > > goto T3; > > T3:; > > goto T2; > > T2:; > > /*(MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > /*(SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /*(SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > {register object V6; > > V6= (V4); > > goto T24; > > T24:; > > if(((V6))==Cnil){ > > goto T26; > > } > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V5){ > > case 0: > > goto T36; > > T36:; > > if(!(((V3))==(/* (SYSTEM::KEY SYSTEM::Y) */(V6)->c.c_car))){ > > goto T33; > > } > > goto T34; > > > > case 1: > > goto T37; > > T37:; > > if(!(eql((V3),/* (SYSTEM::KEY SYSTEM::Y) */(V6)->c.c_car))){ > > goto T33; > > } > > goto T34; > > > > goto T33; > > } > > goto T33; > > > > goto T34; > > T34:; > > goto T32; > > > > goto T33; > > T33:; > > goto T30; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T32; > > T32:; > > {object V8 = (V6); > > VMR1(V8);} > > goto T30; > > T30:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > {object V9; > > V9= /* (APPLIED CDR SYSTEM::X) */V6->c.c_cdr; > > V6= (V9); > > goto T24; > > } > > goto T26; > > T26:; > > goto T22; > > > > goto T22; > > } > > /* END (SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > goto T22; > > T22:; > > if(((V4))==Cnil){ > > goto T20; > > } > > /* END (SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /* END (MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > goto T17; > > > > goto T20; > > T20:; > > {object V10 = Cnil; > > VMR1(V10);} > > goto T17; > > T17:; > > {object V11 = Cnil; > > VMR1(V11);}} > > /* END (MEMBER X Y)*/ > > } > > > ============================================================================= > > symbol x, unknown y, (disassemble '(lambda (x y) (declare (symbol x)) > (member x y))) > > loop not unrolled, eql->eq, no typing > > > ============================================================================= > > static object LI1__CMP_ANON___gazonk_2205667_0(register object V3,object > V4) > > { VMB1 VMS1 VMV1 > > /*(MEMBER X Y)*/ > > /*(MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > /*(SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /*(SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > {register object V5; > > V5= (V4); > > goto T9; > > T9:; > > if(((V5))==Cnil){ > > goto T11; > > } > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > if(!(((V3))==(/* (SYSTEM::KEY SYSTEM::Y) */(V5)->c.c_car))){ > > goto T18; > > } > > goto T17; > > > > goto T18; > > T18:; > > goto T15; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T17; > > T17:; > > {object V7 = (V5); > > VMR1(V7);} > > goto T15; > > T15:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > {object V8; > > V8= /* (APPLIED CDR SYSTEM::X) */V5->c.c_cdr; > > V5= (V8); > > goto T9; > > } > > goto T11; > > T11:; > > goto T7; > > > > goto T7; > > } > > /* END (SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > goto T7; > > T7:; > > if(((V4))==Cnil){ > > goto T5; > > } > > /* END (SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /* END (MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > goto T2; > > > > goto T5; > > T5:; > > {object V9 = Cnil; > > VMR1(V9);} > > goto T2; > > T2:; > > {object V10 = Cnil; > > VMR1(V10);} > > /* END (MEMBER X Y)*/ > > } > > > ============================================================================= > > Unknown x, known list, (disassemble '(lambda (x y z w) (member x (list y > z w)))) > > loop unrolled, type-of x pulled out > > > ============================================================================= > > static object LI1__CMP_ANON___gazonk_2205667_1(object V5,object V6,object > V7,object V8) > > { VMB1 VMS1 VMV1 > > /*(MEMBER X (LIST Y Z ...))*/ > > {object V9; > > V9= list(3,(V6),(V7),(V8)); > > {fixnum V10; > > V10= 1; > > /*(EQL-IS-EQ SYSTEM::ITEM)*/ > > switch(/* (APPLIED TP4 SYSTEM::X) */tp4(V5)){ > > case -1: > > goto T8; > > T8:; > > goto T6; > > > > case 1: > > goto T9; > > T9:; > > case 2: > > goto T10; > > T10:; > > case 3: > > goto T11; > > T11:; > > case 4: > > goto T12; > > T12:; > > case 5: > > goto T13; > > T13:; > > case 6: > > goto T14; > > T14:; > > goto T4; > > > > default: > > goto T15; > > T15:; > > goto T6; > > > > goto T4; > > } > > goto T4; > > > > /* END (EQL-IS-EQ SYSTEM::ITEM)*/ > > goto T6; > > T6:; > > V10= 0; > > goto T3; > > > > goto T4; > > T4:; > > goto T3; > > T3:; > > /*(MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > /*(SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /*(SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T27; > > T27:; > > if(!(((V5))==((V6)))){ > > goto T24; > > } > > goto T25; > > > > case 1: > > goto T28; > > T28:; > > if(!(eql((V5),(V6)))){ > > goto T24; > > } > > goto T25; > > > > goto T24; > > } > > goto T24; > > > > goto T25; > > T25:; > > goto T23; > > > > goto T24; > > T24:; > > goto T21; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T23; > > T23:; > > {object V11 = (V9); > > VMR1(V11);} > > goto T21; > > T21:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T37; > > T37:; > > if(!(((V5))==((V7)))){ > > goto T34; > > } > > goto T35; > > > > case 1: > > goto T38; > > T38:; > > if(!(eql((V5),(V7)))){ > > goto T34; > > } > > goto T35; > > > > goto T34; > > } > > goto T34; > > > > goto T35; > > T35:; > > goto T33; > > > > goto T34; > > T34:; > > goto T31; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T33; > > T33:; > > {object V12 = /* (CDR SYSTEM::X) */V9->c.c_cdr; > > VMR1(V12);} > > goto T31; > > T31:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T47; > > T47:; > > if(!(((V5))==((V8)))){ > > goto T44; > > } > > goto T45; > > > > case 1: > > goto T48; > > T48:; > > if(!(eql((V5),(V8)))){ > > goto T44; > > } > > goto T45; > > > > goto T44; > > } > > goto T44; > > > > goto T45; > > T45:; > > goto T43; > > > > goto T44; > > T44:; > > goto T41; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T43; > > T43:; > > {object V13 = /* (CDR SYSTEM::X) */V9->c.c_cdr->c.c_cdr; > > VMR1(V13);} > > goto T41; > > T41:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /* END (SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /* END (SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /* END (SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /* END (SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /* END (MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > {object V14 = Cnil; > > VMR1(V14);}}} > > /* END (MEMBER X (LIST Y Z ...))*/ > > } > > > ============================================================================= > > Known result, (disassemble '(lambda (x y z w) (declare (symbol z)) > > (member z (list 3 z w)))) > > loop eliminated > > > ============================================================================= > > static object LI1__CMP_ANON___gazonk_2205667_1(object V5,object V6,object > V7,object V8) > > { VMB1 VMS1 VMV1 > > /*(MEMBER Z (LIST 3 Z ...))*/ > > {object V9; > > V9= list(3,make_fixnum(3),(V7),(V8)); > > /*(MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > /*(SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /*(SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /*(SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > {object V10 = /* (CDR SYSTEM::X) */V9->c.c_cdr; > > VMR1(V10);} > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /* END (SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /* END (SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /* END (SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /* END (MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/} > > /* END (MEMBER Z (LIST 3 Z ...))*/ > > } > > > ============================================================================= > > Unknown x, known list of symbols (disassemble '(lambda (x y z w) > > (declare (symbol y z w )) (member x (list y z w)))) > > loop unrolled, type-of x pulled out, when x is e.g. integer eql still > > optimized to eq element wise as all list elements are symbol. > > > ============================================================================= > > static object LI1__CMP_ANON___gazonk_2205667_1(object V5,object V6,object > V7,object V8) > > { VMB1 VMS1 VMV1 > > /*(MEMBER X (LIST Y Z ...))*/ > > {object V9; > > V9= list(3,(V6),(V7),(V8)); > > {fixnum V10; > > V10= 1; > > /*(EQL-IS-EQ SYSTEM::ITEM)*/ > > switch(/* (APPLIED TP4 SYSTEM::X) */tp4(V5)){ > > case -1: > > goto T8; > > T8:; > > goto T6; > > > > case 1: > > goto T9; > > T9:; > > case 2: > > goto T10; > > T10:; > > case 3: > > goto T11; > > T11:; > > case 4: > > goto T12; > > T12:; > > case 5: > > goto T13; > > T13:; > > case 6: > > goto T14; > > T14:; > > goto T4; > > > > default: > > goto T15; > > T15:; > > goto T6; > > > > goto T4; > > } > > goto T4; > > > > /* END (EQL-IS-EQ SYSTEM::ITEM)*/ > > goto T6; > > T6:; > > V10= 0; > > goto T3; > > > > goto T4; > > T4:; > > goto T3; > > T3:; > > /*(MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > /*(SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /*(SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T27; > > T27:; > > if(!(((V5))==((V6)))){ > > goto T24; > > } > > goto T25; > > > > case 1: > > goto T28; > > T28:; > > if(!(((V5))==((V6)))){ > > goto T24; > > } > > goto T25; > > > > goto T24; > > } > > goto T24; > > > > goto T25; > > T25:; > > goto T23; > > > > goto T24; > > T24:; > > goto T21; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T23; > > T23:; > > {object V11 = (V9); > > VMR1(V11);} > > goto T21; > > T21:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T37; > > T37:; > > if(!(((V5))==((V7)))){ > > goto T34; > > } > > goto T35; > > > > case 1: > > goto T38; > > T38:; > > if(!(((V5))==((V7)))){ > > goto T34; > > } > > goto T35; > > > > goto T34; > > } > > goto T34; > > > > goto T35; > > T35:; > > goto T33; > > > > goto T34; > > T34:; > > goto T31; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T33; > > T33:; > > {object V12 = /* (CDR SYSTEM::X) */V9->c.c_cdr; > > VMR1(V12);} > > goto T31; > > T31:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /*((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /*(SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > /*(SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > switch(V10){ > > case 0: > > goto T47; > > T47:; > > if(!(((V5))==((V8)))){ > > goto T44; > > } > > goto T45; > > > > case 1: > > goto T48; > > T48:; > > if(!(((V5))==((V8)))){ > > goto T44; > > } > > goto T45; > > > > goto T44; > > } > > goto T44; > > > > goto T45; > > T45:; > > goto T43; > > > > goto T44; > > T44:; > > goto T41; > > > > /* END (SYSTEM::TEST-NO-KEY SYSTEM::X (SYSTEM::KEY SYSTEM::Y))*/ > > /* END (SYSTEM::TEST SYSTEM::ITEM (CAR SYSTEM::X))*/ > > goto T43; > > T43:; > > {object V13 = /* (CDR SYSTEM::X) */V9->c.c_cdr->c.c_cdr; > > VMR1(V13);} > > goto T41; > > T41:; > > /* END ((LAMBDA (SYSTEM::X) (DECLARE #) ...) SYSTEM::X)*/ > > /* END (SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /* END (SYSTEM::LMAP SYSTEM::F (CDR SYSTEM::X))*/ > > /* END (SYSTEM::LMAP SYSTEM::F SYSTEM::X)*/ > > /* END (SYSTEM::LMAPR SYSTEM::FUN LIST)*/ > > /* END (MAPL (LAMBDA (SYSTEM::X) (IF # #)) LIST)*/ > > {object V14 = Cnil; > > VMR1(V14);}}} > > /* END (MEMBER X (LIST Y Z ...))*/ > > } > > > ============================================================================= > > > > Take care, > > > > David Scherfgen via Maxima-discuss > > <maxima-disc...@lists.sourceforge.net> writes: > > > > > Hello, > > > > > > I noticed that GCL 2.7.1 compiles these functions differently: > > > > > > (defun f (x) (member x '(a b c))) > > > (defun g (x) (member x '(a b c) :test #'eq)) > > > > > > I suppose that's because F uses the default EQL as the test. I tried to > understand the C code it generated, but it was incomprehensible to me. > Anyways, > I > > saw > > > that the second function, G, had inlined the MEMBER call into (OR (EQ X > 'A) (EQ X 'B) (EQ Y 'C)), which is reasonable. But why does F get compiled > > differently? > > > > > > Shouldn't the compiler notice that the second argument to MEMBER is a > literal list of symbols and automatically use EQ instead of the default EQL > test? > > That > > > would be an easy and safe optimization. > > > > > > The same goes for the case where the first argument to MEMBER is a > literal symbol. > > > > > > Maxima is full of such instances where MEMBER is used as a shorter way > to write (OR (EQ ...) (EQ ...) ...), and ":test #'eq" has mostly been removed > because > > it was > > > believed that any modern Lisp compiler would apply this optimization > automatically. At least SBCL does. (CCL doesn't, I have filed a report > already.) > > > > > > Best regards > > > David Scherfgen > > > > > > _______________________________________________ > > > Maxima-discuss mailing list > > > maxima-disc...@lists.sourceforge.net > > > https://lists.sourceforge.net/lists/listinfo/maxima-discuss > > > > > > > -- > > Camm Maguire c...@maguirefamily.org > > ========================================================================== > > "The earth is but one country, and mankind its citizens." -- Baha'u'llah > > > > _______________________________________________ > > Maxima-discuss mailing list > > maxima-disc...@lists.sourceforge.net > > https://lists.sourceforge.net/lists/listinfo/maxima-discuss > > > > -- > Camm Maguire c...@maguirefamily.org > ========================================================================== > "The earth is but one country, and mankind its citizens." -- Baha'u'llah > > _______________________________________________ > Maxima-discuss mailing list > maxima-disc...@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/maxima-discuss > -- Camm Maguire c...@maguirefamily.org ========================================================================== "The earth is but one country, and mankind its citizens." -- Baha'u'llah