Make %EMIT-ALIGNMENT be more friendly to multi-byte NOPs.
authorLutz Euler <lutz.euler@freenet.de>
Mon, 6 May 2013 12:04:02 +0000 (14:04 +0200)
committerLutz Euler <lutz.euler@freenet.de>
Mon, 6 May 2013 12:04:02 +0000 (14:04 +0200)
When %EMIT-ALIGNMENT needs to tighten the alignment, it used to emit
a fixed-size skip first and an alignment note afterwards. On x86-64,
where block headers are aligned using multi-byte NOPs, this could
lead to emitting one more such NOP than needed to span the desired
range, unnecessarily increasing the number of machine instructions
the processor needs to decode.

To avoid that, change %EMIT-ALIGNMENT to only emit an alignment note
(covering both the fixed-size skip and the alignment note from the
original version) in this situation.

An example of the difference, from the disassembly of
SB-C::FLATTEN-LIST:

Before:

  896: L0:   8F4508           POP QWORD PTR [RBP+8]
  899:       0F1F00           NOP
  89C:       0F1F4000         NOP
  8A0: L1:   4881F917001020   CMP RCX, 537919511

Afterwards:

  896: L0:   8F4508           POP QWORD PTR [RBP+8]
  899:       0F1F8000000000   NOP
  8A0: L1:   4881F917001020   CMP RCX, 537919511

NEWS
src/compiler/assem.lisp

diff --git a/NEWS b/NEWS
index 32fd625..411d233 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,8 @@ changes relative to sbcl-1.1.7:
   * bug fix: disassembler missing ",8" on SHLD
   * optimization: faster ISQRT on fixnums and small bignums
   * optimization: faster and smaller INTEGER-LENGTH on fixnums on x86-64.
+  * optimization: On x86-64, the number of multi-byte NOP instructions used
+    for code alignment is now always minimal.
 
 changes in sbcl-1.1.7 relative to sbcl-1.1.6:
   * enhancement: TRACE :PRINT-ALL handles multiple-valued forms.
index 401d9a5..dfb1275 100644 (file)
         (offset (- (segment-current-posn segment)
                    (segment-sync-posn segment))))
     (cond ((> bits alignment)
-           ;; We need more bits of alignment. First emit enough noise
-           ;; to get back in sync with alignment, and then emit an
-           ;; alignment note to cover the rest.
-           (let ((slop (logand offset (1- (ash 1 alignment)))))
-             (unless (zerop slop)
-               (emit-skip segment (- (ash 1 alignment) slop) pattern)))
-           (let ((size (logand (1- (ash 1 bits))
-                               (lognot (1- (ash 1 alignment))))))
+           ;; We need more bits of alignment. Emit an alignment note.
+           ;; The ALIGNMENT many least significant bits of (- OFFSET)
+           ;; give the amount of bytes to skip to get back in sync with
+           ;; ALIGNMENT, and one-bits to the left of that up to position
+           ;; BITS provide the remaining amount.
+           (let ((size (deposit-field (- offset)
+                                      (byte 0 alignment)
+                                      (1- (ash 1 bits)))))
              (aver (> size 0))
              (emit-annotation segment (make-alignment bits size pattern))
              (emit-skip segment size pattern))