;; SPDX-License-Identifier: BSD-2-Clause
;; Copyright 1996-2017 The NASM Authors - All Rights Reserved

;
; Smart alignment macros
;
USE: smartalign

%imacro alignmode 1-2.nolist
  %ifidni %1,nop
    %define __?ALIGN_JMP_THRESHOLD?__ 16

    %define __?ALIGN_16BIT_1B?__ 0x90
    %define __?ALIGN_16BIT_GROUP?__ 1

    %define __?ALIGN_32BIT_1B?__ 0x90
    %define __?ALIGN_32BIT_GROUP?__ 1

    %define __?ALIGN_64BIT_1B?__ 0x90
    %define __?ALIGN_64BIT_GROUP?__ 1
  %elifidni %1,generic
    %define __?ALIGN_JMP_THRESHOLD?__ 8

    %define __?ALIGN_16BIT_1B?__ 0x90
    %define __?ALIGN_16BIT_2B?__ 0x89,0xf6
    %define __?ALIGN_16BIT_3B?__ 0x8d,0x74,0x00
    %define __?ALIGN_16BIT_4B?__ 0x8d,0xb4,0x00,0x00
    %define __?ALIGN_16BIT_5B?__ 0x8d,0xb4,0x00,0x00,0x90
    %define __?ALIGN_16BIT_6B?__ 0x8d,0xb4,0x00,0x00,0x89,0xff
    %define __?ALIGN_16BIT_7B?__ 0x8d,0xb4,0x00,0x00,0x8d,0x7d,0x00
    %define __?ALIGN_16BIT_8B?__ 0x8d,0xb4,0x00,0x00,0x8d,0xbd,0x00,0x00
    %define __?ALIGN_16BIT_GROUP?__ 8

    %define __?ALIGN_32BIT_1B?__ 0x90
    %define __?ALIGN_32BIT_2B?__ 0x89,0xf6
    %define __?ALIGN_32BIT_3B?__ 0x8d,0x76,0x00
    %define __?ALIGN_32BIT_4B?__ 0x8d,0x74,0x26,0x00
    %define __?ALIGN_32BIT_5B?__ 0x90,0x8d,0x74,0x26,0x00
    %define __?ALIGN_32BIT_6B?__ 0x8d,0xb6,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_7B?__ 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_GROUP?__ 7

    %define __?ALIGN_64BIT_1B?__ 0x90
    %define __?ALIGN_64BIT_2B?__ 0x66,0x90
    %define __?ALIGN_64BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_64BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_64BIT_GROUP?__ 4
  %elifidni %1,k8
    %define __?ALIGN_JMP_THRESHOLD?__ 16

    %define __?ALIGN_16BIT_1B?__ 0x90
    %define __?ALIGN_16BIT_2B?__ 0x66,0x90
    %define __?ALIGN_16BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_16BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_16BIT_GROUP?__ 4

    %define __?ALIGN_32BIT_1B?__ 0x90
    %define __?ALIGN_32BIT_2B?__ 0x66,0x90
    %define __?ALIGN_32BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_32BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_32BIT_GROUP?__ 4

    %define __?ALIGN_64BIT_1B?__ 0x90
    %define __?ALIGN_64BIT_2B?__ 0x66,0x90
    %define __?ALIGN_64BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_64BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_64BIT_GROUP?__ 4
  %elifidni %1,k7
    %define __?ALIGN_JMP_THRESHOLD?__ 16

    %define __?ALIGN_16BIT_1B?__ 0x90
    %define __?ALIGN_16BIT_2B?__ 0x66,0x90
    %define __?ALIGN_16BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_16BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_64BIT_GROUP?__ 4

    %define __?ALIGN_32BIT_1B?__ 0x90
    %define __?ALIGN_32BIT_2B?__ 0x8b,0xc0
    %define __?ALIGN_32BIT_3B?__ 0x8d,0x04,0x20
    %define __?ALIGN_32BIT_4B?__ 0x8d,0x44,0x20,0x00
    %define __?ALIGN_32BIT_5B?__ 0x8d,0x44,0x20,0x00,0x90
    %define __?ALIGN_32BIT_6B?__ 0x8d,0x80,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_7B?__ 0x8d,0x04,0x05,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_GROUP?__ 7

    %define __?ALIGN_64BIT_1B?__ 0x90
    %define __?ALIGN_64BIT_2B?__ 0x66,0x90
    %define __?ALIGN_64BIT_3B?__ 0x66,0x66,0x90
    %define __?ALIGN_64BIT_4B?__ 0x66,0x66,0x66,0x90
    %define __?ALIGN_64BIT_GROUP?__ 4
  %elifidni %1,p6
    %define __?ALIGN_JMP_THRESHOLD?__ 16

    %define __?ALIGN_16BIT_1B?__ 0x90
    %define __?ALIGN_16BIT_2B?__ 0x66,0x90
    %define __?ALIGN_16BIT_3B?__ 0x0f,0x1f,0x00
    %define __?ALIGN_16BIT_4B?__ 0x0f,0x1f,0x40,0x00
    %define __?ALIGN_16BIT_GROUP?__ 4

    %define __?ALIGN_32BIT_1B?__ 0x90
    %define __?ALIGN_32BIT_2B?__ 0x66,0x90
    %define __?ALIGN_32BIT_3B?__ 0x0f,0x1f,0x00
    %define __?ALIGN_32BIT_4B?__ 0x0f,0x1f,0x40,0x00
    %define __?ALIGN_32BIT_5B?__ 0x0f,0x1f,0x44,0x00,0x00
    %define __?ALIGN_32BIT_6B?__ 0x66,0x0f,0x1f,0x44,0x00,0x00
    %define __?ALIGN_32BIT_7B?__ 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_8B?__ 0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00
    %define __?ALIGN_32BIT_GROUP?__ 8

    %define __?ALIGN_64BIT_1B?__ 0x90
    %define __?ALIGN_64BIT_2B?__ 0x66,0x90
    %define __?ALIGN_64BIT_3B?__ 0x0f,0x1f,0x00
    %define __?ALIGN_64BIT_4B?__ 0x0f,0x1f,0x40,0x00
    %define __?ALIGN_64BIT_5B?__ 0x0f,0x1f,0x44,0x00,0x00
    %define __?ALIGN_64BIT_6B?__ 0x66,0x0f,0x1f,0x44,0x00,0x00
    %define __?ALIGN_64BIT_7B?__ 0x0f,0x1f,0x80,0x00,0x00,0x00,0x00
    %define __?ALIGN_64BIT_8B?__ 0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00
    %define __?ALIGN_64BIT_GROUP?__ 8
  %else
    %error unknown alignment mode: %1
  %endif
  %ifnempty %2
    %ifidni %2,nojmp
      %xdefine __?ALIGN_JMP_THRESHOLD?__ -1
    %else
      %xdefine __?ALIGN_JMP_THRESHOLD?__ %2
    %endif
  %endif
  %xdefine __?ALIGNMODE?__ %1,__?ALIGN_JMP_THRESHOLD?__
%endmacro

%defalias __ALIGNMODE__ __?ALIGNMODE?__

%unimacro align 1-2+.nolist
%imacro align 1-2+.nolist
  sectalign %1   ; align a segment as well
  %ifnempty %2
    times (((%1) - (($-$$) % (%1))) % (%1)) %2
  %elif __?PASS?__ == 0 || __?PASS?__ == 3
    times (((%1) - (($-$$) % (%1))) % (%1)) nop
  %else
    %push
    %assign %$pad (((%1) - (($-$$) % (%1))) % (%1))
    %if __?ALIGN_JMP_THRESHOLD?__ != -1 && %$pad > __?ALIGN_JMP_THRESHOLD?__
      jmp %$end
      ; We can't re-use %$pad here as $ will have changed!
      times (((%1) - (($-$$) % (%1))) % (%1)) nop
    %else
      times (%$pad / __?ALIGN_%[__?BITS?__]BIT_GROUP?__) \
        db __?ALIGN_%[__?BITS?__]BIT_%[__?ALIGN_%[__?BITS?__]BIT_GROUP?__]B?__
      %assign %$pad %$pad % __?ALIGN_%[__?BITS?__]BIT_GROUP?__
      %if %$pad > 0
        db __?ALIGN_%[__?BITS?__]BIT_%[%$pad]B?__
      %endif
    %endif
%$end:
    %pop
  %endif
%endmacro

	alignmode generic
