Re: car/cdr chain optimization

Douglas Katzman via Sbcl-help <[email protected]> Mon, 3 Feb 2025 18:59:39 -0500
Newsgroups gmane.lisp.steel-bank.general
Message-ID <CAOrNasyXa9dZOjOvo8-Amx2VjGWaBWJp54JWC8SnGNfy2-FYKQ@mail.gmail.com>
The SBCL compiler is pretty much unaware of the concept of common
subexpression elimination.  One of my thoughts about how to really improve
it to compile into LLVM IR.  That idea brings with it a world of issues to
resolve in order to get there, but gives a glimmer of hope toward availing
ourselves of modern compiler techniques.
I wanted to see what would happen if we compile a C program that is nearly
equivalent to your EQ expression with type-check - does LLVM eliminate the
redundant read and type-check? Indeed it does. I've attached the source and
asm.  The asm contains only 3 memory loads (one is disguised as a CMP in
mem-to-reg form) and 2 conditional branches.  See attached if you're
curious.

_______________________________________________
Sbcl-help mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-help
silly.s (application/octet-stream, 910 B) - not displayed
silly.c (application/octet-stream, 830 B)
extern void lose(char *fmt, ...) __attribute__ ((noreturn));

typedef unsigned long lispobj;
struct cons {
    lispobj car;
    lispobj cdr;
};

static inline int consp(lispobj x) { return (((int)x - 7) & 15) == 0; }
#define predict_consp(x) __builtin_expect(consp(x),1)
static inline lispobj get_car(lispobj x) { return ((struct cons*)(x-7))->car; }
static inline lispobj get_cdr(lispobj x) { return ((struct cons*)(x-7))->cdr; }
static inline lispobj checking_car(lispobj x) {
  if (predict_consp(x)) return get_car(x); else lose("not a cons: %p", (void*)x);
}
static inline lispobj checking_cdr(lispobj x) {
  if (predict_consp(x)) return get_cdr(x); else lose("not a cons: %p", (void*)x);
}

char foopred(lispobj x) {
  if (checking_car(checking_cdr(x)) ==
      checking_cdr(checking_cdr(x))) return 'y'; else return 'n';
}