[Git][cmucl/cmucl][native-image] 9 commits: Add complex double-double-float

Raymond Toy gitlab at common-lisp.net
Sun Feb 7 18:06:12 UTC 2021



Raymond Toy pushed to branch native-image at cmucl / cmucl


Commits:
e35e9f7a by Raymond Toy at 2021-02-06T13:33:21-08:00
Add complex double-double-float

Remove some old #if'd out code.

- - - - -
96e7aa5e by Raymond Toy at 2021-02-06T13:55:09-08:00
Add bit vector and double-float vector

- - - - -
57ceca08 by Raymond Toy at 2021-02-06T14:05:39-08:00
Add vectyor unsigned-byte 16

- - - - -
9e4049c6 by Raymond Toy at 2021-02-06T14:14:55-08:00
Add vector unsigned-byte 2

- - - - -
44913576 by Raymond Toy at 2021-02-06T14:20:12-08:00
Add vector unsigned-byte 4

- - - - -
e2cecd5f by Raymond Toy at 2021-02-06T14:38:03-08:00
Print hex values for floats

The gcc assembler can't handle most-positive-double-float (when
printed by C), so let's just print out the 32-bit words of the double
with a comment on the actual value.

- - - - -
55c9c196 by Raymond Toy at 2021-02-06T14:42:16-08:00
Add comment on where we need to apply code fixups.

- - - - -
0a553364 by Raymond Toy at 2021-02-07T09:47:06-08:00
Fix handling of code header and symbol headers

Printing of the symbol header was broken because we printed out the
unbound marker as Lba, indicating an address.  But we just want the
raw value of the unbound marker

The code header consists of multiple function header objects so we
dump each of the objects now.

Finally a few changes on printing:
  * asm_word uses %08lx to the value
  * asm_lispobj prints out the address with %08lx to be consistent
    with asm_label.

- - - - -
a31b485f by Raymond Toy at 2021-02-07T10:03:17-08:00
asm_lispobj handles immediates

If the object is an even or odd immediate, just print out the value
since it's, duh, an immediate, not some kind of address or fixnum.

asm_symbol_header doesn't need the special case for the value slot
anymore.  (We can probably replace this with just asm_boxed as we did
before.)

- - - - -


1 changed file:

- src/lisp/save.c


Changes:

=====================================
src/lisp/save.c
=====================================
@@ -407,7 +407,7 @@ asm_word(lispobj* ptr, lispobj object, FILE* f)
 {
     unsigned long val = (unsigned long) object;
     
-    fprintf(f, "\t.4byte\t0x%lx\t# %ld\n", val, val);
+    fprintf(f, "\t.4byte\t0x%08lx\t# %ld\n", val, val);
 }
 
 void
@@ -419,8 +419,12 @@ asm_lispobj(lispobj* ptr, lispobj object, FILE* f)
         fprintf(f, "0x%lx\t# fixnum %ld\n",
                 (long) object,
                 ((long) object) >> 2);
+    } else if ((object & 7) == 2 ||
+               (object & 7) == 6) {
+        /* Other immediates */
+        fprintf(f, "0x%08lx\n", object);
     } else {
-        fprintf(f, "L%lx + %lu\n", PTR(object), LowtagOf(object));
+        fprintf(f, "L%08lx + %lu\n", PTR(object), LowtagOf(object));
     }
 }
 
@@ -564,6 +568,22 @@ asm_closure_header(lispobj* ptr, lispobj object, FILE* f)
     return asm_boxed(ptr, object, f);
 }
 
+int
+asm_symbol_header(lispobj* ptr, lispobj object, FILE* f)
+{
+    struct symbol* sym = (struct symbol*) ptr;
+    
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "symbol header");
+    asm_lispobj(&sym->value, sym->value, f);
+    asm_lispobj(&sym->hash, sym->hash, f);
+    asm_lispobj(&sym->plist, sym->plist, f);
+    asm_lispobj(&sym->name, sym->name, f);
+    asm_lispobj(&sym->package, sym->package, f);
+
+    return 1 + HeaderValue(object);
+}
+
 int
 asm_complex_vector(lispobj* ptr, lispobj object, FILE* f)
 {
@@ -578,6 +598,8 @@ asm_code_header(lispobj* ptr, lispobj object, FILE* f)
     int ncode_words;
     int nwords;
     int k;
+    lispobj fheaderl;
+    struct function *fheaderp;
 
     code = (struct code *) ptr;
     ncode_words = fixnum_value(code->code_size);
@@ -597,12 +619,66 @@ asm_code_header(lispobj* ptr, lispobj object, FILE* f)
         asm_lispobj(ptr + k + 1, ptr[k + 1], f);
     }
 
-    fprintf(f, "# Code bytes?\n");
-    
-    for (; k < nwords; ++k) {
-        fprintf(f, "\t.4byte\t0x%lx\n", ptr[k + 1]);
+    fheaderl = code->entry_points;
+    while (fheaderl != NIL) {
+        int code_words;
+        int fheader_len;
+        
+	fheaderp = (struct function *) PTR(fheaderl);
+        fheader_len = HeaderValue(fheaderp->header);
+#if 0
+        fprintf(f, "# fheaderp %p\n", (void*) fheaderp);
+        fprintf(f, "#   ->header 0x%lx\n", fheaderp->header);
+        fprintf(f, "#   ->self 0x%lx\n", fheaderp->self);
+        fprintf(f, "#   ->next 0x%lx\n", fheaderp->next);
+        fprintf(f, "#   ->name 0x%lx\n", fheaderp->name);
+        fprintf(f, "#   ->arglist 0x%lx\n", fheaderp->arglist);
+        fprintf(f, "#   ->type 0x%lx\n", fheaderp->type);
+        fprintf(f, "#   ->code %p\n", &fheaderp->code);
+#endif
+        asm_label((lispobj*)fheaderp, *((lispobj*)fheaderp), f);
+        asm_header_word(&fheaderp->header, fheaderp->header, f, "function header");
+        fprintf(f, "\t.4byte\tL%lx\n", fheaderp->self);
+        asm_lispobj(&fheaderp->next, fheaderp->next, f);
+        asm_lispobj(&fheaderp->name, fheaderp->name, f);
+        asm_lispobj(&fheaderp->arglist, fheaderp->arglist, f);
+        asm_lispobj(&fheaderp->type, fheaderp->type, f);
+        asm_label((lispobj*)fheaderp->code, 0, f);
+
+        /* We've sent out 6 of the total code words */
+        ncode_words -= fheader_len;
+        
+        /*
+         * TODO: Adopt trans_code or apply_code_fixups to process the code
+         * here so we can relocate everthing.
+         */
+        fprintf(f, "# Code bytes\n");
+
+        /* Dump out code between here and the next function header */
+        if (fheaderp->next != NIL) {
+            code_words = (fheaderp->next - fheaderl) / 4 - fheader_len;
+        } else {
+            code_words = ncode_words;
+        }
+        
+        fprintf(f, "# fheaderp->next %p code words %d ncode_words %d\n",
+                (void*)fheaderp->next, code_words, ncode_words);
+
+        {
+            uint32_t* code_data = (uint32_t*) fheaderp->code;
+            
+            for (k = 0; k < code_words; ++k) {
+                fprintf(f, "\t.4byte\t0x%08x\t# %p\n", code_data[k],
+                        fheaderp->code + 4*k);
+            }
+        }
+        
+        ncode_words -= code_words;
+        
+	fheaderl = fheaderp->next;
     }
-    
+
+    asm_align(f);
     return nwords;
 }
 
@@ -659,9 +735,42 @@ asm_simple_string(lispobj* where, lispobj object, FILE* f)
     return nwords;
 }
 
+int
+asm_vector_bit(lispobj* ptr, lispobj object, FILE* f)
+{
+    struct vector *vector;
+    int length, nwords;
+    unsigned long* data;
+    int k;
+    
+
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+#ifdef __x86_64
+    nwords = CEILING(NWORDS(length, 64) + 2, 2);
+#else
+    nwords = CEILING(NWORDS(length, 32) + 2, 2);
+#endif
+
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "simple bit-vector");
+    asm_lispobj(ptr + 1, ptr[1], f);
+
+    data = vector->data;
+
+    for (k = 0; k < nwords - 2; ++k) {
+        fprintf(f, "\t.4byte\t0x%lx\n", data[k]);
+    }
+    
+    return nwords;
+
+}
+
+
 void
 print_float(FILE* f, float value)
 {
+#if 0
     if (isfinite(value)) {
         fprintf(f, "\t.float\t%.15g\n", value);
     } else {
@@ -674,6 +783,17 @@ print_float(FILE* f, float value)
         val.f = value;
         fprintf(f, "\t.4byte\t0x%x\n", val.a);
     }
+#else
+    union 
+    {
+            uint32_t a;
+            float f;
+    } val;
+
+    val.f = value;
+    fprintf(f, "\t.4byte\t0x%x\t# %lg\n", val.a, value);
+#endif
+
 }
 
 int
@@ -684,7 +804,6 @@ asm_single_float(lispobj* ptr, lispobj object, FILE* f)
     asm_label(ptr, object, f);
     asm_header_word(ptr, object, f, "single float");
     print_float(f, obj->value);
-    
 
     return 2;
 }
@@ -692,8 +811,9 @@ asm_single_float(lispobj* ptr, lispobj object, FILE* f)
 void
 print_double(FILE* f, double value)
 {
+#if 0    
     if (isfinite(value)) {
-        fprintf(f, "\t.double\t%.15g\n", value);
+        fprintf(f, "\t.double\t%.16lg\n", value);
     } else {
         union 
         {
@@ -706,6 +826,18 @@ print_double(FILE* f, double value)
         fprintf(f, "\t.4byte\t0x%x\n", val.a[0]);
         fprintf(f, "\t.4byte\t0x%x\n", val.a[1]);
     }
+#else
+    union 
+    {
+        uint32_t a[2];
+        double d;
+    } val;
+
+    val.d = value;
+    fprintf(f, "\t.4byte\t0x%x\t# %.18lg\n", val.a[0], value);
+    fprintf(f, "\t.4byte\t0x%x\n", val.a[1]);
+    
+#endif
 }
 
 int
@@ -751,9 +883,41 @@ asm_complex_single_float(lispobj* ptr, lispobj object, FILE* f)
     return CEILING(1 + HeaderValue(object), 2);
 }
 
+int
+asm_complex_double_float(lispobj* ptr, lispobj object, FILE* f)
+{
+    struct complex_double_float* obj = (struct complex_double_float*) ptr;
+    
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "complex double-float");
+    asm_lispobj(&obj->filler, obj->filler, f);
+    
+    print_double(f, obj->real);
+    print_double(f, obj->imag);
     
+    return CEILING(1 + HeaderValue(object), 2);
+}
+
 int
-asm_vector_unsigned_byte_8(lispobj* ptr, lispobj object, FILE* f)
+asm_complex_double_double_float(lispobj* ptr, lispobj object, FILE* f)
+{
+    struct complex_double_double_float* obj = (struct complex_double_double_float*) ptr;
+    
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "complex double-float");
+    asm_lispobj(&obj->filler, obj->filler, f);
+    
+    print_double(f, obj->real_hi);
+    print_double(f, obj->real_lo);
+    print_double(f, obj->imag_hi);
+    print_double(f, obj->imag_lo);
+    
+    return CEILING(1 + HeaderValue(object), 2);
+}
+
+    
+int
+asm_vector_unsigned_byte_2(lispobj* ptr, lispobj object, FILE* f)
 {
     struct vector *vector;
     int length, nwords;
@@ -763,12 +927,12 @@ asm_vector_unsigned_byte_8(lispobj* ptr, lispobj object, FILE* f)
     vector = (struct vector *) ptr;
     length = fixnum_value(vector->length);
 #ifdef __x86_64
-    nwords = CEILING(NWORDS(length, 8) + 2, 2);
+    nwords = CEILING(NWORDS(length, 32) + 2, 2);
 #else
-    nwords = CEILING(NWORDS(length, 4) + 2, 2);
+    nwords = CEILING(NWORDS(length, 16) + 2, 2);
 #endif
     asm_label(ptr, object, f);
-    asm_header_word(ptr, object, f, "vector unsigned_byte 8");
+    asm_header_word(ptr, object, f, "vector unsigned_byte 2");
     asm_lispobj(ptr + 1, ptr[1], f);
     
     data = vector->data;
@@ -777,12 +941,14 @@ asm_vector_unsigned_byte_8(lispobj* ptr, lispobj object, FILE* f)
     for (k = 0; k < nwords - 2; ++k) {
         fprintf(f, "\t.4byte\t0x%lx\n", data[k]);
     }
+
+    asm_align(f);
     
     return nwords;
 }
 
 int
-asm_vector_unsigned_byte_32(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_unsigned_byte_4(lispobj* ptr, lispobj object, FILE* f)
 {
     struct vector *vector;
     int length, nwords;
@@ -792,13 +958,12 @@ asm_vector_unsigned_byte_32(lispobj* ptr, lispobj object, FILE* f)
     vector = (struct vector *) ptr;
     length = fixnum_value(vector->length);
 #ifdef __x86_64
-    nwords = CEILING(NWORDS(length, 2) + 2, 2);
+    nwords = CEILING(NWORDS(length, 16) + 2, 2);
 #else
-    nwords = CEILING(length + 2, 2);
+    nwords = CEILING(NWORDS(length, 8) + 2, 2);
 #endif
-
     asm_label(ptr, object, f);
-    asm_header_word(ptr, object, f, "vector unsigned_byte 32");
+    asm_header_word(ptr, object, f, "vector unsigned_byte 4");
     asm_lispobj(ptr + 1, ptr[1], f);
     
     data = vector->data;
@@ -807,113 +972,186 @@ asm_vector_unsigned_byte_32(lispobj* ptr, lispobj object, FILE* f)
     for (k = 0; k < nwords - 2; ++k) {
         fprintf(f, "\t.4byte\t0x%lx\n", data[k]);
     }
+
+    asm_align(f);
     
     return nwords;
 }
 
 int
-asm_bignum(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_unsigned_byte_8(lispobj* ptr, lispobj object, FILE* f)
 {
-    int len = 1 + HeaderValue(object);
+    struct vector *vector;
+    int length, nwords;
+    unsigned long* data;
     int k;
-
-    len = CEILING(len, 2);
     
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+#ifdef __x86_64
+    nwords = CEILING(NWORDS(length, 8) + 2, 2);
+#else
+    nwords = CEILING(NWORDS(length, 4) + 2, 2);
+#endif
     asm_label(ptr, object, f);
-    asm_header_word(ptr, object, f, "bignum");
+    asm_header_word(ptr, object, f, "vector unsigned_byte 8");
+    asm_lispobj(ptr + 1, ptr[1], f);
     
-    for (k = 1; k < len; ++k) {
-        fprintf(f, "\t.4byte\t0x%lx\t# %lu\n", ptr[k], ptr[k]);
-    }
+    data = vector->data;
 
-    return len;
+    /* Minus 2 for the header and length words */
+    for (k = 0; k < nwords - 2; ++k) {
+        fprintf(f, "\t.4byte\t0x%lx\n", data[k]);
+    }
+    
+    return nwords;
 }
 
 int
-asm_sap(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_unsigned_byte_16(lispobj* ptr, lispobj object, FILE* f)
 {
+    struct vector *vector;
+    int length, nwords;
+    uint16_t* data;
+    int k;
+    
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+#ifdef __x86_64
+    nwords = CEILING(NWORDS(length, 4) + 2, 2);
+#else
+    nwords = CEILING(NWORDS(length, 2) + 2, 2);
+#endif
     asm_label(ptr, object, f);
-    asm_header_word(ptr, object, f, "sap");
-    /* Just print out the raw value of the address */
-    fprintf(f, "\t.4byte\t0x%lx\n", ptr[1]);
+    asm_header_word(ptr, object, f, "vector unsigned_byte 16");
+    asm_lispobj(ptr + 1, ptr[1], f);
+    
+    data = (uint16_t*) vector->data;
 
-    return 2;
-}
+    /* Minus 2 for the header and length words */
+    for (k = 0; k < length; ++k) {
+        fprintf(f, "\t.4byte\t0x%x\n", data[k]);
+    }
+
+    asm_align(f);
     
-#if 0
-int
-asm_catch_block(lispobj* ptr, lispobj object, FILE* f)
-{
-    return asm_boxed(ptr, object, f);
+    return nwords;
 }
 
 int
-asm_catch_block(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_unsigned_byte_32(lispobj* ptr, lispobj object, FILE* f)
 {
-    return asm_boxed(ptr, object, f);
-}
+    struct vector *vector;
+    int length, nwords;
+    unsigned long* data;
+    int k;
+    
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+#ifdef __x86_64
+    nwords = CEILING(NWORDS(length, 2) + 2, 2);
+#else
+    nwords = CEILING(length + 2, 2);
+#endif
 
-int
-asm_closure(lispobj* ptr, lispobj object, FILE* f)
-{
-    return asm_boxed(ptr, object, f);
-}
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "vector unsigned_byte 32");
+    asm_lispobj(ptr + 1, ptr[1], f);
+    
+    data = vector->data;
 
-int
-asm_code(lispobj* ptr, lispobj object, FILE* f)
-{
-    return asm_boxed(ptr, object, f);
+    /* Minus 2 for the header and length words */
+    for (k = 0; k < nwords - 2; ++k) {
+        fprintf(f, "\t.4byte\t0x%lx\n", data[k]);
+    }
+    
+    return nwords;
 }
 
 int
-asm_complex(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_double_float(lispobj* ptr, lispobj object, FILE* f)
 {
-    return asm_boxed(ptr, object, f);
-}
+    struct vector *vector;
+    int length, nwords;
+    const double* data;
+    int k;
+    
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+#ifdef __x86_64
+    nwords = CEILING(length + 2, 2);
+#else
+    nwords = length * 2 + 2;	/* alignment guaranteed */
+#endif
 
-int
-asm_complex_double_double_float(lispobj* ptr, lispobj object, FILE* f)
-{
     asm_label(ptr, object, f);
-    asm_lispobj(ptr, object, f);
+    asm_header_word(ptr, object, f, "vector double-float");
     asm_lispobj(ptr + 1, ptr[1], f);
-
-    double* d = (double*) (ptr + 2);
     
-    for (k = 0; k < 4; ++k) {
-        fprintf(f, "\t.double\t%.15lg\n", d[k]);
+    data = (const double*) vector->data;
+
+
+    for (k = 0; k < length; ++k) {
+        print_double(f, data[k]);
     }
 
-    return HeaderValue(object);
+    return nwords;
 }
 
 int
-asm_complex_double_float(lispobj* ptr, lispobj object, FILE* f)
+asm_vector_double_double_float(lispobj* ptr, lispobj object, FILE* f)
 {
+    struct vector *vector;
+    int length, nwords;
+    const double* data;
+    int k;
+    
+    vector = (struct vector *) ptr;
+    length = fixnum_value(vector->length);
+    nwords = CEILING(length * 4 + 2, 2);
+
     asm_label(ptr, object, f);
-    asm_lispobj(ptr, object, f);
+    asm_header_word(ptr, object, f, "vector double-float");
     asm_lispobj(ptr + 1, ptr[1], f);
+    
+    data = (const double*) vector->data;
 
-    double* d = ptr + 2;
-    fprintf(f, "\t.double\t%.15lg, %.15lg\n", d[0], d[1]);
+    for (k = 0; k < 2*length; ++k) {
+        print_double(f, data[k]);
+    }
 
-    return HeaderValue(object);
+    return nwords;
 }
 
 int
-asm_complex_double_float(lispobj* ptr, lispobj object, FILE* f)
+asm_bignum(lispobj* ptr, lispobj object, FILE* f)
 {
-    asm_label(ptr, object, f);
-    asm_lispobj(ptr, object, f);
+    int len = 1 + HeaderValue(object);
+    int k;
 
-    double* d = ptr + 2;
-    fprintf(f, "\t.double\t%.15lg, %.15lg\n", d[0], d[1]);
+    len = CEILING(len, 2);
+    
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "bignum");
+    
+    for (k = 1; k < len; ++k) {
+        fprintf(f, "\t.4byte\t0x%lx\t# %lu\n", ptr[k], ptr[k]);
+    }
 
-    return HeaderValue(object);
+    return len;
 }
 
-#endif
+int
+asm_sap(lispobj* ptr, lispobj object, FILE* f)
+{
+    asm_label(ptr, object, f);
+    asm_header_word(ptr, object, f, "sap");
+    /* Just print out the raw value of the address */
+    fprintf(f, "\t.4byte\t0x%lx\n", ptr[1]);
 
+    return 2;
+}
+    
 void
 init_asmtab(void)
 {
@@ -941,11 +1179,19 @@ init_asmtab(void)
     asmtab[type_DoubleDoubleFloat] = asm_double_double_float;
     asmtab[type_Complex] = asm_boxed;
     asmtab[type_ComplexSingleFloat] = asm_complex_single_float;
+    asmtab[type_ComplexDoubleFloat] = asm_complex_double_float;
+    asmtab[type_ComplexDoubleDoubleFloat] = asm_complex_double_double_float;
     asmtab[type_SimpleArray] = asm_boxed;
     asmtab[type_SimpleString] = asm_simple_string;
+    asmtab[type_SimpleBitVector] = asm_vector_bit;
     asmtab[type_SimpleVector] = asm_simple_vector;
+    asmtab[type_SimpleArrayUnsignedByte2] = asm_vector_unsigned_byte_2;
+    asmtab[type_SimpleArrayUnsignedByte4] = asm_vector_unsigned_byte_4;
     asmtab[type_SimpleArrayUnsignedByte8] = asm_vector_unsigned_byte_8;
+    asmtab[type_SimpleArrayUnsignedByte16] = asm_vector_unsigned_byte_16;
     asmtab[type_SimpleArrayUnsignedByte32] = asm_vector_unsigned_byte_32;
+    asmtab[type_SimpleArrayDoubleFloat] = asm_vector_double_float;
+    asmtab[type_SimpleArrayDoubleDoubleFloat] = asm_vector_double_double_float;
     asmtab[type_ComplexString] = asm_boxed;
     asmtab[type_ComplexVector] = asm_boxed;
     asmtab[type_CodeHeader] = asm_code_header;
@@ -953,7 +1199,7 @@ init_asmtab(void)
     asmtab[type_FuncallableInstanceHeader] = asm_closure_header;
     /* Just use asm_boxed or have a special version for a value cell? */
     asmtab[type_ValueCellHeader] = asm_boxed;
-    asmtab[type_SymbolHeader] = asm_boxed;
+    asmtab[type_SymbolHeader] = asm_symbol_header;
     asmtab[type_BaseChar] = asm_immediate;
     asmtab[type_Sap] = asm_sap;
     asmtab[type_InstanceHeader] = asm_boxed;
@@ -966,6 +1212,9 @@ write_asm_object(const char *dir, int id, os_vm_address_t start, os_vm_address_t
     char asm_file[PATH_MAX];
     FILE* f;
     
+    printf("write_asm_object space %d start %p end %p\n",
+           id, start, end);
+    
     snprintf(asm_file, PATH_MAX, "%s/space-%d.s", dir, id);
     f = fopen(asm_file, "w");
 



View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/07991ccceb9f092900f7b556f6bea589236816a3...a31b485f9d7223dd1bdf6d21485f229582734c99

-- 
View it on GitLab: https://gitlab.common-lisp.net/cmucl/cmucl/-/compare/07991ccceb9f092900f7b556f6bea589236816a3...a31b485f9d7223dd1bdf6d21485f229582734c99
You're receiving this email because of your account on gitlab.common-lisp.net.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/cmucl-cvs/attachments/20210207/dde8df82/attachment-0001.html>


More information about the cmucl-cvs mailing list