Re: SBCL tells me it is deleting unreachable code that is almost surely reachable
Stavros Macrakis <[email protected]>
| Newsgroups | gmane.comp.mathematics.maxima.general |
|---|---|
| Message-ID | <CACLVabXNSEXh5=WstXMjSosvLoysoEw=ejyOSM+teC-HGTNozA@mail.gmail.com> |
Sorry, this was muddled: The *and *is so that we depend only on the boolean value, not the list value of *member: *for example, *(member 'b '(a b c))* returns *(b c)*, which then has to be tested to see whether it's* nil *in the function case, and in the inline case, each conditional has to return a different value. I meant The *and *is so that we depend only on the boolean value, not the list value of *member*. (Recall that, for example, *(member 'b '(a b c))* returns *(b c)*.) When we're using *member* in a *cond*, all we care about is the truth value, so the function case has the extra overhead of checking whether the return value is non-nil. The inline version doesn't have that overhead in the *cond* case, but it has to do a little more work to return the full value of *member*. This still feels convoluted as an explanation, but as Pascal said, "I have made this letter longer than usual because I lack the time to make it shorter." On Wed, Apr 15, 2026 at 6:06 PM Stavros Macrakis <[email protected]> wrote: > On Wed, Apr 15, 2026 at 4:07 PM Raymond Toy <[email protected]> wrote: > ... > >> On 4/15/26 10:12 AM, Stavros Macrakis wrote: >> >> Looking at the generated code, I see that with *optimize speed:0 space:3*, >> SBCL calls *member-eq*, even though that takes more space. Apparently it >> uses an inaccurate heuristic to estimate space usage. >> >> Surely a simple function call to member-eq takes less space than inlining >> 3 comparisons and branches >> > > Sounds plausible, and presumably that's what the *space* heuristic is > based on, but... > > Here's the test: > > (disassemble > (lambda (x) > (declare (optimize (space *X*) (speed *Y*))) > (and (member x '(a b c)) t))) > > The *and *is so that we depend only on the boolean value, not the list > value of *member: *for example, *(member 'b '(a b c))* returns *(b c)*, > which then has to be tested to see whether it's* nil *in the function > case, and in the inline case, each conditional has to return a different > value. > > In SBCL: > With speed=3, and space=0, it inlines, and compiles to 47 bytes. > With speed=3, and space=3, it inlines, and compiles to 47 bytes. > With speed=0 and space=0, it inlines, and compiles to 55 bytes. > With speed=0 and space=3, it calls *member*, and compiles to 66 bytes. > > -s > > (%i1) :lisp (disassemble (lambda (x) (declare (optimize (space 0) (speed > 3))) (and (member x '(a b c)) t))) > > ; disassembly for (LAMBDA (X)) > ; Size: 47 bytes. Origin: #x10013BADF0 ; (LAMBDA > (X)) > ; DF0: 4184442469 > <http://voice.google.com/calls?a=nc,%2B14184442469> > <http://voice.google.com/calls?a=nc,%2B14184442469> TEST AL, > [R12+105] ; safepoint > ; DF5: 483B15B4FFFFFF CMP RDX, [RIP-76] ; 'A > ; DFC: 7508 JNE L2 > ; DFE: L0: 498D542488 LEA RDX, [R12-120] ; T > ; E03: L1: C9 LEAVE > ; E04: F8 CLC > ; E05: C3 RET > ; E06: L2: 483B15ABFFFFFF CMP RDX, [RIP-85] ; 'B > ; E0D: 74EF JE L0 > ; E0F: 483B15AAFFFFFF CMP RDX, [RIP-86] ; 'C > ; E16: 74E6 JE L0 > ; E18: 498BD4 MOV RDX, R12 ; NIL > ; E1B: EBE6 JMP L1 > ; E1D: CC0F INT3 15 ; Invalid > argument count trap > NIL > (%i1) :lisp (disassemble (lambda (x) (declare (optimize (space 3) (speed > 3))) (and (member x '(a b c)) t))) > > ; disassembly for (LAMBDA (X)) > ; Size: 47 bytes. Origin: #x10013BAE90 ; (LAMBDA > (X)) > ; 90: 4184442469 TEST AL, [R12+105] ; safepoint > ; 95: 483B15B4FFFFFF CMP RDX, [RIP-76] ; 'A > ; 9C: 7508 JNE L2 > ; 9E: L0: 498D542488 LEA RDX, [R12-120] ; T > ; A3: L1: C9 LEAVE > ; A4: F8 CLC > ; A5: C3 RET > ; A6: L2: 483B15ABFFFFFF CMP RDX, [RIP-85] ; 'B > ; AD: 74EF JE L0 > ; AF: 483B15AAFFFFFF CMP RDX, [RIP-86] ; 'C > ; B6: 74E6 JE L0 > ; B8: 498BD4 MOV RDX, R12 ; NIL > ; BB: EBE6 JMP L1 > ; BD: CC0F INT3 15 ; Invalid > argument count trap > NIL > (%i1) :lisp (disassemble (lambda (x) (declare (optimize (space 0) (speed > 0))) (and (member x '(a b c)) t))) > > ; disassembly for (LAMBDA (X)) > ; Size: 55 bytes. Origin: #x10013BAF34 ; (LAMBDA > (X)) > ; 34: 498B4510 MOV RAX, [R13+16] ; > thread.binding-stack-pointer > ; 38: 488945F8 MOV [RBP-8], RAX > ; 3C: 4184442469 TEST AL, [R12+105] ; safepoint > ; 41: 483B35A8FFFFFF CMP RSI, [RIP-88] ; 'A > ; 48: 7508 JNE L2 > ; 4A: L0: 498D542488 LEA RDX, [R12-120] ; T > ; 4F: L1: C9 LEAVE > ; 50: F8 CLC > ; 51: C3 RET > ; 52: L2: 483B359FFFFFFF CMP RSI, [RIP-97] ; 'B > ; 59: 74EF JE L0 > ; 5B: 483B359EFFFFFF CMP RSI, [RIP-98] ; 'C > ; 62: 74E6 JE L0 > ; 64: 498BD4 MOV RDX, R12 ; NIL > ; 67: EBE6 JMP L1 > ; 69: CC0F INT3 15 ; Invalid > argument count trap > NIL > (%i1) :lisp (disassemble (lambda (x) (declare (optimize (space 3) (speed > 0))) (and (member x '(a b c)) t))) > > ; disassembly for (LAMBDA (X)) > ; Size: 66 bytes. Origin: #x10013BAFD8 ; (LAMBDA > (X)) > ; AFD8: 498B4510 MOV RAX, [R13+16] ; > thread.binding-stack-pointer > ; AFDC: 488945F8 MOV [RBP-8], RAX > ; AFE0: 4184442469 TEST AL, [R12+105] ; safepoint > ; AFE5: 4883EC10 SUB RSP, 16 > ; AFE9: 498BD0 MOV RDX, R8 > ; AFEC: 488B3DADFFFFFF MOV RDI, [RIP-83] ; '(A B C) > ; AFF3: 48892C24 MOV [RSP], RBP > ; AFF7: 488BEC MOV RBP, RSP > ; AFFA: 498B442429 MOV RAX, [R12+41] ; > LISP-LINKAGE-TABLE > ; AFFF: FF9028070000 CALL [RAX+1832] ; > SB-KERNEL:%MEMBER > ; B005: 4C8B45F0 MOV R8, [RBP-16] > ; B009: 4C39E2 CMP RDX, R12 ; NIL > ; B00C: 498D542488 LEA RDX, [R12-120] ; T > ; B011: 490F44D4 CMOVE RDX, R12 ; NIL > ; B015: C9 LEAVE > ; B016: F8 CLC > ; B017: C3 RET > ; B018: CC0F INT3 15 ; Invalid > argument count trap > NIL > _______________________________________________ Maxima-discuss mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/maxima-discuss