Use CALL/RET for pushing and returning to continuations on amd64.
authorTaylor R Campbell <campbell@mumble.net>
Sat, 29 Dec 2018 01:11:00 +0000 (01:11 +0000)
committerTaylor R Campbell <campbell@mumble.net>
Tue, 13 Aug 2019 14:37:02 +0000 (14:37 +0000)
Calls now look like:

  ;; (assign (register #x123) (cons-pointer tag (entry:continuation cont)))
  (CALL (@PCR pushed))
  (JMP (@PCR cont))
pushed:
  (OR Q (@R ,rsp) (&U ,tag))
  ...
  (JMP (@PCR uuo-link))

Returns now look like:

  ;; (pop-return)
  (AND Q (@R ,rsp) (R ,regnum:datum-mask))
  (RET)

These should happen in pairs, so that we can take advantage of the
CPU's return address branch target prediction stack rather than
abusing the indirect jump branch target predictor.

WARNING: This changes the amd64 compiled code interface, so new
compiled code requires a new microcode.  (A new microcode might be
able to handle existing compiled code just fine.)

src/compiler/machines/x86-64/rules1.scm
src/compiler/machines/x86-64/rules3.scm
src/microcode/cmpintmd/x86-64.c
src/microcode/cmpintmd/x86-64.h

index a327bcb157923f704c312a35463803ea9227d930..5f6acf4d05971567feca9ccd14ae2f019a49a2b4 100644 (file)
@@ -175,7 +175,12 @@ USA.
 
 (define-rule statement
   (ASSIGN (REGISTER (? target)) (ENTRY:CONTINUATION (? label)))
-  (load-pc-relative-address (target-register-reference target) label 8))
+  (let* ((target (target-register-reference target))
+        (get-pc (generate-label 'GET-PC)))
+    (LAP (CALL (@PCR ,get-pc))
+        (JMP (@PCRO ,label 8))
+       (LABEL ,get-pc)
+        (POP Q ,target))))
 
 (define-rule statement
   ;; This is an intermediate rule -- not intended to produce code.
@@ -195,8 +200,28 @@ USA.
          (CONS-POINTER (MACHINE-CONSTANT (? type))
                        (ENTRY:CONTINUATION (? label))))
   (assert (= type type-code:compiled-return))
-  (load-pc-relative-address/typed (target-register-reference target)
-                                 type label 8))
+  (let* ((target (target-register-reference target))
+        (temp (temporary-register-reference))
+        (pushed (generate-label 'PUSHED)))
+    (LAP (CALL (@PCR ,pushed))
+        (JMP (@PCRO ,label 8))
+       (LABEL ,pushed)
+        (POP Q ,target)
+        (MOV Q ,temp (&U ,(make-non-pointer-literal type 0)))
+        (OR Q ,target ,temp))))
+
+(define-rule statement
+  (ASSIGN (PRE-INCREMENT (REGISTER 4) -1)
+         (CONS-POINTER (MACHINE-CONSTANT (? type))
+                       (ENTRY:CONTINUATION (? label))))
+  (assert (= type type-code:compiled-return))
+  (let* ((temp (temporary-register-reference))
+        (pushed (generate-label 'PUSHED)))
+    (LAP (CALL (@PCR ,pushed))
+        (JMP (@PCRO ,label 8))
+       (LABEL ,pushed)
+        (MOV Q ,temp (&U ,(make-non-pointer-literal type 0)))
+        (OR Q (@R 4) ,temp))))
 
 (define-rule statement
   (ASSIGN (REGISTER (? target)) (VARIABLE-CACHE (? name)))
index 8f49c4707fbbb1ea932aa1e0cfc100e3ec5564aa..74c747be83bd5a2b574e3f11fba46ee1aedc0d84 100644 (file)
@@ -39,9 +39,8 @@ USA.
     (cond ((null? checks)
           (current-bblock-continue!
            (make-new-sblock
-            (LAP (POP Q (R ,rax))      ; continuation
-                 (AND Q (R ,rax) (R ,regnum:datum-mask)) ; clear type
-                 (JMP (R ,rax))))))
+            (LAP (AND Q (@R ,rsp) (R ,regnum:datum-mask))
+                 (RET)))))
          ((block-association 'POP-RETURN)
           => current-bblock-continue!)
          (else
@@ -50,9 +49,8 @@ USA.
                   (let ((interrupt-label (generate-label 'INTERRUPT)))
                     (LAP (CMP Q (R ,regnum:free-pointer) ,reg:compiled-memtop)
                          (JGE (@PCR ,interrupt-label))
-                         (POP Q (R ,rax)) ; continuation
-                         (AND Q (R ,rax) (R ,regnum:datum-mask)) ; clear type
-                         (JMP (R ,rax))
+                         (AND Q (@R ,rsp) (R ,regnum:datum-mask))
+                         (RET)
                          (LABEL ,interrupt-label)
                          ,@(invoke-hook
                             entry:compiler-interrupt-continuation-2))))))
index be21835ae4ea40078868108c8c0df5bfff2481f5..19e168e3b151ae7c69d582b418e2474ef9b4f4d2 100644 (file)
@@ -63,6 +63,17 @@ write_cc_entry_offset (cc_entry_offset_t * ceo, insn_t * address)
     = (((ceo->offset) << 1) | ((ceo->continued_p) ? 1 : 0));
   return (false);
 }
+
+insn_t *
+cc_return_address_to_entry_address (insn_t * pc)
+{
+  if ((pc[0]) == 0xeb)         /* JMP rel8 */
+    return ((pc + 2) + (* ((int8_t *) &pc[1])) - 8);
+  else if ((pc[0]) == 0xe9)    /* JMP rel32 */
+    return ((pc + 5) + (* ((int32_t *) &pc[1])) - 8);
+  else
+    return (pc - 8);
+}
 \f
 /* Compiled closures */
 
index d48aee366a059ada0998987de926e1b640fb419d..4acce547298130e6bf8597f1e93860884a492dd5 100644 (file)
@@ -161,7 +161,9 @@ typedef uint8_t insn_t;
 #define CC_RETURN_ADDRESS_PTR(r)       0
 #define CC_RETURN_ADDRESS_PC(r)                (r)
 
-#define CC_RETURN_ADDRESS_TO_ENTRY_ADDRESS(r)  (((insn_t *) (r)) - 8)
+insn_t * cc_return_address_to_entry_address (insn_t *);
+
+#define CC_RETURN_ADDRESS_TO_ENTRY_ADDRESS cc_return_address_to_entry_address
 \f
 #define EMBEDDED_CLOSURE_ADDRS_P 1