| /* addsub.s Test file for AArch64 add-subtract instructions. |
| |
| Copyright 2012 Free Software Foundation, Inc. |
| Contributed by ARM Ltd. |
| |
| This file is part of GAS. |
| |
| GAS is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the license, or |
| (at your option) any later version. |
| |
| GAS is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; see the file COPYING3. If not, |
| see <http://www.gnu.org/licenses/>. */ |
| |
| // TODO: also cover the addsub_imm instructions. |
| |
| /* |
| * Adjust Rm |
| */ |
| .macro adjust_rm op, rd, rn, rm_r, rm_n, extend, amount |
| // for 64-bit instruction, Rm is Xm when <extend> is explicitely |
| // or implicitly UXTX, SXTX or LSL; otherwise it Wm. |
| .ifc \rm_r, X |
| .ifnc \extend, UXTX |
| .ifnc \extend, SXTX |
| .ifnc \extend, LSL |
| .ifb \amount |
| \op \rd, \rn, W\()\rm_n, \extend |
| .else |
| \op \rd, \rn, W\()\rm_n, \extend #\amount |
| .endif |
| .exitm |
| .endif |
| .endif |
| .endif |
| .endif |
| |
| .ifb \amount |
| \op \rd, \rn, \rm_r\()\rm_n, \extend |
| .else |
| \op \rd, \rn, \rm_r\()\rm_n, \extend #\amount |
| .endif |
| .endm |
| |
| /* |
| * Emitting addsub_ext instruction |
| */ |
| .macro do_addsub_ext type, op, Rn, reg, extend, amount |
| .ifc \type, 0 |
| // normal add/adds/sub/subs |
| .ifb \extend |
| \op \reg\()16, \Rn, \reg\()1 |
| .else |
| .ifb \amount |
| adjust_rm \op, \reg\()16, \Rn, \reg, 1, \extend |
| .else |
| adjust_rm \op, \reg\()16, \Rn, \reg, 1, \extend, \amount |
| .endif |
| .endif |
| .else |
| .ifc \type, 1 |
| // adds/subs with ZR as Rd |
| .ifb \extend |
| \op \reg\()ZR, \Rn, \reg\()1 |
| .else |
| .ifb \amount |
| adjust_rm \op, \reg\()ZR, \Rn, \reg, 1, \extend |
| .else |
| adjust_rm \op, \reg\()ZR, \Rn, \reg, 1, \extend, \amount |
| .endif |
| .endif |
| .else |
| // cmn/cmp |
| .ifb \extend |
| \op \Rn, \reg\()1 |
| .else |
| .ifb \amount |
| \op \Rn, \reg\()1, \extend |
| .else |
| \op \Rn, \reg\()1, \extend #\amount |
| .endif |
| .endif |
| .endif |
| .endif |
| .endm |
| |
| /* |
| * Optional extension and optional shift amount |
| */ |
| .macro do_extend type, op, Rn, reg |
| // <extend> absent |
| // note that when SP is not used, the GAS will encode it as addsub_shift |
| do_addsub_ext \type, \op, \Rn, \reg |
| // optional absent <amount> |
| .irp extend, UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX |
| .irp amount, , 0, 1, 2, 3, 4 |
| do_addsub_ext \type, \op, \Rn, \reg, \extend, \amount |
| .endr |
| .endr |
| // when <extend> is LSL, <amount> cannot be absent |
| // note that when SP is not used, the GAS will encode it as addsub_shift |
| .irp amount, 0, 1, 2, 3, 4 |
| do_addsub_ext \type, \op, \Rn, \reg, LSL, \amount |
| .endr |
| .endm |
| |
| /* |
| * Leaf macro emitting addsub_shift instruction |
| */ |
| .macro do_addsub_shift type, op, R, reg, shift, amount |
| .ifc \type, 0 |
| // normal add/adds/sub/subs |
| .ifb \shift |
| \op \reg\()16, \R, \reg\()1 |
| .else |
| \op \reg\()16, \R, \reg\()1, \shift #\amount |
| .endif |
| .else |
| .ifc \type, 1 |
| // adds/subs with ZR as Rd |
| .ifb \shift |
| \op \reg\()ZR, \R, \reg\()1 |
| .else |
| \op \reg\()ZR, \R, \reg\()1, \shift #\amount |
| .endif |
| .else |
| .ifc \type, 2 |
| // cmn/cmp/neg/negs |
| .ifb \shift |
| \op \R, \reg\()1 |
| .else |
| \op \R, \reg\()1, \shift #\amount |
| .endif |
| .else |
| // sub/subs with ZR as Rn |
| .ifb \shift |
| \op \R, \reg\()ZR, \reg\()1 |
| .else |
| \op \R, \reg\()ZR, \reg\()1, \shift #\amount |
| .endif |
| .endif |
| .endif |
| .endif |
| .endm |
| |
| /* |
| * Optional shift and optional shift amount |
| */ |
| .macro do_shift type, op, R, reg |
| // <shift> absent |
| do_addsub_shift \type, \op, \R, \reg |
| // optional absent <amount> |
| .irp shift, LSL, LSR, ASR |
| .irp amount, 0, 1, 2, 3, 4, 5, 16, 31 |
| // amount cannot be absent when shift is present. |
| do_addsub_shift \type, \op, \R, \reg, \shift, \amount |
| .endr |
| .ifc \reg, X |
| do_addsub_shift \type, \op, \R, \reg, \shift, 63 |
| .endif |
| .endr |
| .endm |
| |
| func: |
| /* |
| * Add-subtract (extended register) |
| */ |
| |
| .irp op, ADD, ADDS, SUB, SUBS |
| do_extend 0, \op, W7, W |
| do_extend 0, \op, WSP, W |
| do_extend 0, \op, X7, X |
| do_extend 0, \op, SP, X |
| .endr |
| |
| .irp op, ADDS, SUBS |
| do_extend 1, \op, W7, W |
| do_extend 1, \op, WSP, W |
| do_extend 1, \op, X7, X |
| do_extend 1, \op, SP, X |
| .endr |
| |
| .irp op, CMN, CMP |
| do_extend 2, \op, W7, W |
| do_extend 2, \op, WSP, W |
| do_extend 2, \op, X7, X |
| do_extend 2, \op, SP, X |
| .endr |
| |
| /* |
| * Add-subtract (shift register) |
| */ |
| |
| .irp op, ADD, ADDS, SUB, SUBS |
| do_shift 0, \op, W7, W |
| do_shift 0, \op, X7, X |
| .endr |
| |
| .irp op, ADDS, SUBS |
| do_shift 1, \op, W7, W |
| do_shift 1, \op, X7, X |
| .endr |
| |
| .irp op, CMN, CMP |
| do_shift 2, \op, W7, W |
| do_shift 2, \op, X7, X |
| .endr |
| |
| .irp op, SUB, SUBS |
| do_shift 3, \op, W7, W |
| do_shift 3, \op, X7, X |
| .endr |
| |
| .irp op, NEG, NEGS |
| do_shift 2, \op, W7, W |
| do_shift 2, \op, X7, X |
| .endr |