From 61ca6a411cc0e8c746e480d7a05423242e49ea45 Mon Sep 17 00:00:00 2001 From: Lutz Euler Date: Mon, 6 May 2013 14:04:02 +0200 Subject: [PATCH] Make %EMIT-ALIGNMENT be more friendly to multi-byte NOPs. 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 | 2 ++ src/compiler/assem.lisp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 32fd625..411d233 100644 --- 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. diff --git a/src/compiler/assem.lisp b/src/compiler/assem.lisp index 401d9a5..dfb1275 100644 --- a/src/compiler/assem.lisp +++ b/src/compiler/assem.lisp @@ -910,14 +910,14 @@ (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)) -- 1.7.10.4