[PATCH 34/57][Arm][GAS] Add support for MVE instructions: vshl and vqshl

gas/ChangeLog:
2019-05-16  Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* config/tc-arm.c (enum operand_parse_code): Add new operand.
	(parse_operands): Handle new operand.
	(do_neon_shl_imm): Accept MVE variants.
	(do_neon_shl): Likewise.
	(do_neon_qshl_imm): Likewise.
	(do_neon_qshl): Likewise.
	(do_neon_qshlu_imm): Likewise.
	(insns): Likewise.
	* testsuite/gas/arm/mve-vqshl-bad.d: New test.
	* testsuite/gas/arm/mve-vqshl-bad.l: New test.
	* testsuite/gas/arm/mve-vqshl-bad.s: New test.
	* testsuite/gas/arm/mve-vshl-bad.d: New test.
	* testsuite/gas/arm/mve-vshl-bad.l: New test.
	* testsuite/gas/arm/mve-vshl-bad.s: New test.
This commit is contained in:
Andre Vieira 2019-05-16 12:17:44 +01:00
parent 4401c2414d
commit 5150f0d83e
8 changed files with 363 additions and 42 deletions

View File

@ -1,3 +1,20 @@
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/tc-arm.c (enum operand_parse_code): Add new operand.
(parse_operands): Handle new operand.
(do_neon_shl_imm): Accept MVE variants.
(do_neon_shl): Likewise.
(do_neon_qshl_imm): Likewise.
(do_neon_qshl): Likewise.
(do_neon_qshlu_imm): Likewise.
(insns): Likewise.
* testsuite/gas/arm/mve-vqshl-bad.d: New test.
* testsuite/gas/arm/mve-vqshl-bad.l: New test.
* testsuite/gas/arm/mve-vqshl-bad.s: New test.
* testsuite/gas/arm/mve-vshl-bad.d: New test.
* testsuite/gas/arm/mve-vshl-bad.l: New test.
* testsuite/gas/arm/mve-vshl-bad.s: New test.
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
* config/tc-arm.c (do_neon_sli): Accept MVE variants.

View File

@ -6965,6 +6965,8 @@ enum operand_parse_code
/* Neon D, Q or MVE vector register, or big immediate for logic and VMVN. */
OP_RNDQMQ_Ibig,
OP_RNDQ_I63b, /* Neon D or Q reg, or immediate for shift. */
OP_RNDQMQ_I63b_RR, /* Neon D or Q reg, immediate for shift, MVE vector or
ARM register. */
OP_RIWR_I32z, /* iWMMXt wR register, or immediate 0 .. 32 for iWMMXt2. */
OP_VLDR, /* VLDR operand. */
@ -7421,6 +7423,13 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
}
break;
case OP_RNDQMQ_I63b_RR:
po_reg_or_goto (REG_TYPE_MQ, try_rndq_i63b_rr);
break;
try_rndq_i63b_rr:
po_reg_or_goto (REG_TYPE_RN, try_rndq_i63b);
break;
try_rndq_i63b:
case OP_RNDQ_I63b:
{
po_reg_or_goto (REG_TYPE_NDQ, try_shimm);
@ -16378,12 +16387,25 @@ neon_imm_shift (int write_ubit, int uval, int isquad, struct neon_type_el et,
}
static void
do_neon_shl_imm (void)
do_neon_shl (void)
{
if (check_simd_pred_availability (0, NEON_CHECK_ARCH | NEON_CHECK_CC))
return;
if (!inst.operands[2].isreg)
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
enum neon_shape rs;
struct neon_type_el et;
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_MVE);
}
else
{
rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_KEY | N_I_ALL);
}
int imm = inst.operands[2].imm;
constraint (imm < 0 || (unsigned)imm >= et.size,
@ -16393,33 +16415,77 @@ do_neon_shl_imm (void)
}
else
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
unsigned int tmp;
enum neon_shape rs;
struct neon_type_el et;
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQQ, NS_QQR, NS_NULL);
et = neon_check_type (3, rs, N_EQK, N_SU_MVE | N_KEY, N_EQK | N_EQK);
}
else
{
rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
et = neon_check_type (3, rs, N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
}
/* VSHL/VQSHL 3-register variants have syntax such as:
vshl.xx Dd, Dm, Dn
whereas other 3-register operations encoded by neon_three_same have
syntax like:
vadd.xx Dd, Dn, Dm
(i.e. with Dn & Dm reversed). Swap operands[1].reg and operands[2].reg
here. */
tmp = inst.operands[2].reg;
inst.operands[2].reg = inst.operands[1].reg;
inst.operands[1].reg = tmp;
NEON_ENCODE (INTEGER, inst);
neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
if (rs == NS_QQR)
{
constraint (inst.operands[0].reg != inst.operands[1].reg,
_("invalid instruction shape"));
if (inst.operands[2].reg == REG_SP)
as_tsktsk (MVE_BAD_SP);
else if (inst.operands[2].reg == REG_PC)
as_tsktsk (MVE_BAD_PC);
inst.instruction = 0xee311e60;
inst.instruction |= (et.type == NT_unsigned) << 28;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= neon_logbits (et.size) << 18;
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= inst.operands[2].reg;
inst.is_neon = 1;
}
else
{
unsigned int tmp;
/* VSHL/VQSHL 3-register variants have syntax such as:
vshl.xx Dd, Dm, Dn
whereas other 3-register operations encoded by neon_three_same have
syntax like:
vadd.xx Dd, Dn, Dm
(i.e. with Dn & Dm reversed). Swap operands[1].reg and
operands[2].reg here. */
tmp = inst.operands[2].reg;
inst.operands[2].reg = inst.operands[1].reg;
inst.operands[1].reg = tmp;
NEON_ENCODE (INTEGER, inst);
neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
}
}
}
static void
do_neon_qshl_imm (void)
do_neon_qshl (void)
{
if (check_simd_pred_availability (0, NEON_CHECK_ARCH | NEON_CHECK_CC))
return;
if (!inst.operands[2].isreg)
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
enum neon_shape rs;
struct neon_type_el et;
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_KEY | N_SU_MVE);
}
else
{
rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_SU_ALL | N_KEY);
}
int imm = inst.operands[2].imm;
constraint (imm < 0 || (unsigned)imm >= et.size,
@ -16429,17 +16495,48 @@ do_neon_qshl_imm (void)
}
else
{
enum neon_shape rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
struct neon_type_el et = neon_check_type (3, rs,
N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
unsigned int tmp;
enum neon_shape rs;
struct neon_type_el et;
/* See note in do_neon_shl_imm. */
tmp = inst.operands[2].reg;
inst.operands[2].reg = inst.operands[1].reg;
inst.operands[1].reg = tmp;
NEON_ENCODE (INTEGER, inst);
neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQQ, NS_QQR, NS_NULL);
et = neon_check_type (3, rs, N_EQK, N_SU_MVE | N_KEY, N_EQK | N_EQK);
}
else
{
rs = neon_select_shape (NS_DDD, NS_QQQ, NS_NULL);
et = neon_check_type (3, rs, N_EQK, N_SU_ALL | N_KEY, N_EQK | N_SGN);
}
if (rs == NS_QQR)
{
constraint (inst.operands[0].reg != inst.operands[1].reg,
_("invalid instruction shape"));
if (inst.operands[2].reg == REG_SP)
as_tsktsk (MVE_BAD_SP);
else if (inst.operands[2].reg == REG_PC)
as_tsktsk (MVE_BAD_PC);
inst.instruction = 0xee311ee0;
inst.instruction |= (et.type == NT_unsigned) << 28;
inst.instruction |= HI1 (inst.operands[0].reg) << 22;
inst.instruction |= neon_logbits (et.size) << 18;
inst.instruction |= LOW4 (inst.operands[0].reg) << 12;
inst.instruction |= inst.operands[2].reg;
inst.is_neon = 1;
}
else
{
unsigned int tmp;
/* See note in do_neon_shl. */
tmp = inst.operands[2].reg;
inst.operands[2].reg = inst.operands[1].reg;
inst.operands[1].reg = tmp;
NEON_ENCODE (INTEGER, inst);
neon_three_same (neon_quad (rs), et.type == NT_unsigned, et.size);
}
}
}
@ -17924,9 +18021,23 @@ do_neon_sri (void)
static void
do_neon_qshlu_imm (void)
{
enum neon_shape rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
struct neon_type_el et = neon_check_type (2, rs,
N_EQK | N_UNS, N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
if (check_simd_pred_availability (0, NEON_CHECK_ARCH | NEON_CHECK_CC))
return;
enum neon_shape rs;
struct neon_type_el et;
if (ARM_CPU_HAS_FEATURE (cpu_variant, mve_ext))
{
rs = neon_select_shape (NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK, N_S8 | N_S16 | N_S32 | N_KEY);
}
else
{
rs = neon_select_shape (NS_DDI, NS_QQI, NS_NULL);
et = neon_check_type (2, rs, N_EQK | N_UNS,
N_S8 | N_S16 | N_S32 | N_S64 | N_KEY);
}
int imm = inst.operands[2].imm;
constraint (imm < 0 || (unsigned)imm >= et.size,
_("immediate out of range for shift"));
@ -24301,12 +24412,10 @@ static const struct asm_opcode insns[] =
NUF(vrshlq, 0000500, 3, (RNQ, oRNQ, RNQ), neon_rshl),
NUF(vqrshlq, 0000510, 3, (RNQ, oRNQ, RNQ), neon_rshl),
/* If not immediate, fall back to neon_dyadic_i64_su.
shl_imm should accept I8 I16 I32 I64,
qshl_imm should accept S8 S16 S32 S64 U8 U16 U32 U64. */
nUF(vshl, _vshl, 3, (RNDQ, oRNDQ, RNDQ_I63b), neon_shl_imm),
nUF(vshlq, _vshl, 3, (RNQ, oRNQ, RNDQ_I63b), neon_shl_imm),
nUF(vqshl, _vqshl, 3, (RNDQ, oRNDQ, RNDQ_I63b), neon_qshl_imm),
nUF(vqshlq, _vqshl, 3, (RNQ, oRNQ, RNDQ_I63b), neon_qshl_imm),
shl should accept I8 I16 I32 I64,
qshl should accept S8 S16 S32 S64 U8 U16 U32 U64. */
nUF(vshlq, _vshl, 3, (RNQ, oRNQ, RNDQ_I63b), neon_shl),
nUF(vqshlq, _vqshl, 3, (RNQ, oRNQ, RNDQ_I63b), neon_qshl),
/* Logic ops, types optional & ignored. */
nUF(vandq, _vand, 3, (RNQ, oRNQ, RNDQ_Ibig), neon_logic),
nUF(vbicq, _vbic, 3, (RNQ, oRNQ, RNDQ_Ibig), neon_logic),
@ -24389,7 +24498,6 @@ static const struct asm_opcode insns[] =
NUF(vsliq, 1800510, 3, (RNQ, oRNQ, I63), neon_sli),
NUF(vsriq, 1800410, 3, (RNQ, oRNQ, I64), neon_sri),
/* QSHL{U} immediate accepts S8 S16 S32 S64 U8 U16 U32 U64. */
NUF(vqshlu, 1800610, 3, (RNDQ, oRNDQ, I63), neon_qshlu_imm),
NUF(vqshluq, 1800610, 3, (RNQ, oRNQ, I63), neon_qshlu_imm),
/* Right shift immediate, saturating & narrowing, with rounding variants.
Types accepted S16 S32 S64 U16 U32 U64. */
@ -25165,6 +25273,9 @@ static const struct asm_opcode insns[] =
MNUF(vrev64, 1b00000, 2, (RNDQMQ, RNDQMQ), neon_rev),
MNUF(vrev32, 1b00080, 2, (RNDQMQ, RNDQMQ), neon_rev),
MNUF(vrev16, 1b00100, 2, (RNDQMQ, RNDQMQ), neon_rev),
mnUF(vshl, _vshl, 3, (RNDQMQ, oRNDQMQ, RNDQMQ_I63b_RR), neon_shl),
mnUF(vqshl, _vqshl, 3, (RNDQMQ, oRNDQMQ, RNDQMQ_I63b_RR), neon_qshl),
MNUF(vqshlu, 1800610, 3, (RNDQMQ, oRNDQMQ, I63), neon_qshlu_imm),
#undef ARM_VARIANT
#define ARM_VARIANT & arm_ext_v8_3

View File

@ -0,0 +1,5 @@
#name: bad MVE VQSHL instructions
#as: -march=armv8.1-m.main+mve
#error_output: mve-vqshl-bad.l
.*: +file format .*arm.*

View File

@ -0,0 +1,45 @@
[^:]*: Assembler messages:
[^:]*:10: Error: bad type in SIMD instruction -- `vqshl.s64 q0,q0,#0'
[^:]*:11: Error: bad type in SIMD instruction -- `vqshl.i32 q0,q0,#0'
[^:]*:12: Error: immediate out of range for shift -- `vqshl.s8 q0,q1,#8'
[^:]*:13: Error: immediate out of range for shift -- `vqshl.u16 q0,q1,#16'
[^:]*:14: Error: immediate out of range for shift -- `vqshl.s32 q0,q1,#32'
[^:]*:15: Error: bad type in SIMD instruction -- `vqshl.s64 q0,r1'
[^:]*:16: Error: bad type in SIMD instruction -- `vqshl.i16 q0,r1'
[^:]*:17: Warning: instruction is UNPREDICTABLE with SP operand
[^:]*:18: Warning: instruction is UNPREDICTABLE with PC operand
[^:]*:19: Error: bad type in SIMD instruction -- `vqshl.s64 q0,q1,q2'
[^:]*:20: Error: bad type in SIMD instruction -- `vqshl.i32 q0,q1,q2'
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:23: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:25: Error: syntax error -- `vqshleq.s16 q0,q1,#0'
[^:]*:26: Error: syntax error -- `vqshleq.s16 q0,q1,#0'
[^:]*:28: Error: syntax error -- `vqshleq.s16 q0,q1,#0'
[^:]*:29: Error: vector predicated instruction should be in VPT/VPST block -- `vqshlt.s16 q0,q1,#0'
[^:]*:31: Error: instruction missing MVE vector predication code -- `vqshl.s16 q0,q1,#0'
[^:]*:33: Error: syntax error -- `vqshleq.s16 q0,r1'
[^:]*:34: Error: syntax error -- `vqshleq.s16 q0,r1'
[^:]*:36: Error: syntax error -- `vqshleq.s16 q0,r1'
[^:]*:37: Error: vector predicated instruction should be in VPT/VPST block -- `vqshlt.s16 q0,r1'
[^:]*:39: Error: instruction missing MVE vector predication code -- `vqshl.s16 q0,r1'
[^:]*:41: Error: syntax error -- `vqshleq.s16 q0,q1,q2'
[^:]*:42: Error: syntax error -- `vqshleq.s16 q0,q1,q2'
[^:]*:44: Error: syntax error -- `vqshleq.s16 q0,q1,q2'
[^:]*:45: Error: vector predicated instruction should be in VPT/VPST block -- `vqshlt.s16 q0,q1,q2'
[^:]*:47: Error: instruction missing MVE vector predication code -- `vqshl.s16 q0,q1,q2'

View File

@ -0,0 +1,48 @@
.macro cond type, lastreg
.irp cond, eq, ne, gt, ge, lt, le
it \cond
vqshl.\type q0, q0, \lastreg
.endr
.endm
.syntax unified
.thumb
vqshl.s64 q0, q0, #0
vqshl.i32 q0, q0, #0
vqshl.s8 q0, q1, #8
vqshl.u16 q0, q1, #16
vqshl.s32 q0, q1, #32
vqshl.s64 q0, r1
vqshl.i16 q0, r1
vqshl.u16 q0, sp
vqshl.s32 q0, pc
vqshl.s64 q0, q1, q2
vqshl.i32 q0, q1, q2
cond u32, #0
cond s8, r1
cond s16, q2
it eq
vqshleq.s16 q0, q1, #0
vqshleq.s16 q0, q1, #0
vpst
vqshleq.s16 q0, q1, #0
vqshlt.s16 q0, q1, #0
vpst
vqshl.s16 q0, q1, #0
it eq
vqshleq.s16 q0, r1
vqshleq.s16 q0, r1
vpst
vqshleq.s16 q0, r1
vqshlt.s16 q0, r1
vpst
vqshl.s16 q0, r1
it eq
vqshleq.s16 q0, q1, q2
vqshleq.s16 q0, q1, q2
vpst
vqshleq.s16 q0, q1, q2
vqshlt.s16 q0, q1, q2
vpst
vqshl.s16 q0, q1, q2

View File

@ -0,0 +1,5 @@
#name: bad MVE VSHL instructions
#as: -march=armv8.1-m.main+mve
#error_output: mve-vshl-bad.l
.*: +file format .*arm.*

View File

@ -0,0 +1,44 @@
[^:]*: Assembler messages:
[^:]*:10: Error: bad type in SIMD instruction -- `vshl.i64 q0,q0,#0'
[^:]*:11: Error: immediate out of range for shift -- `vshl.i8 q0,q1,#8'
[^:]*:12: Error: immediate out of range for shift -- `vshl.i16 q0,q1,#16'
[^:]*:13: Error: immediate out of range for shift -- `vshl.i32 q0,q1,#32'
[^:]*:14: Error: bad type in SIMD instruction -- `vshl.s64 q0,r1'
[^:]*:15: Error: bad type in SIMD instruction -- `vshl.i16 q0,r1'
[^:]*:16: Warning: instruction is UNPREDICTABLE with SP operand
[^:]*:17: Warning: instruction is UNPREDICTABLE with PC operand
[^:]*:18: Error: bad type in SIMD instruction -- `vshl.s64 q0,q1,q2'
[^:]*:19: Error: bad type in SIMD instruction -- `vshl.i32 q0,q1,q2'
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:20: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:21: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:22: Warning: instruction is UNPREDICTABLE in an IT block
[^:]*:24: Error: syntax error -- `vshleq.i16 q0,q1,#0'
[^:]*:25: Error: syntax error -- `vshleq.i16 q0,q1,#0'
[^:]*:27: Error: syntax error -- `vshleq.i16 q0,q1,#0'
[^:]*:28: Error: vector predicated instruction should be in VPT/VPST block -- `vshlt.i16 q0,q1,#0'
[^:]*:30: Error: instruction missing MVE vector predication code -- `vshl.i16 q0,q1,#0'
[^:]*:32: Error: syntax error -- `vshleq.s16 q0,r1'
[^:]*:33: Error: syntax error -- `vshleq.s16 q0,r1'
[^:]*:35: Error: syntax error -- `vshleq.s16 q0,r1'
[^:]*:36: Error: vector predicated instruction should be in VPT/VPST block -- `vshlt.s16 q0,r1'
[^:]*:38: Error: instruction missing MVE vector predication code -- `vshl.s16 q0,r1'
[^:]*:40: Error: syntax error -- `vshleq.s16 q0,q1,q2'
[^:]*:41: Error: syntax error -- `vshleq.s16 q0,q1,q2'
[^:]*:43: Error: syntax error -- `vshleq.s16 q0,q1,q2'
[^:]*:44: Error: vector predicated instruction should be in VPT/VPST block -- `vshlt.s16 q0,q1,q2'
[^:]*:46: Error: instruction missing MVE vector predication code -- `vshl.s16 q0,q1,q2'

View File

@ -0,0 +1,46 @@
.macro cond type, lastreg
.irp cond, eq, ne, gt, ge, lt, le
it \cond
vshl.\type q0, q0, \lastreg
.endr
.endm
.syntax unified
.thumb
vshl.i64 q0, q0, #0
vshl.i8 q0, q1, #8
vshl.i16 q0, q1, #16
vshl.i32 q0, q1, #32
vshl.s64 q0, r1
vshl.i16 q0, r1
vshl.u16 q0, sp
vshl.s32 q0, pc
vshl.s64 q0, q1, q2
vshl.i32 q0, q1, q2
cond i32, #0
cond s8, r1
cond s16, q2
it eq
vshleq.i16 q0, q1, #0
vshleq.i16 q0, q1, #0
vpst
vshleq.i16 q0, q1, #0
vshlt.i16 q0, q1, #0
vpst
vshl.i16 q0, q1, #0
it eq
vshleq.s16 q0, r1
vshleq.s16 q0, r1
vpst
vshleq.s16 q0, r1
vshlt.s16 q0, r1
vpst
vshl.s16 q0, r1
it eq
vshleq.s16 q0, q1, q2
vshleq.s16 q0, q1, q2
vpst
vshleq.s16 q0, q1, q2
vshlt.s16 q0, q1, q2
vpst
vshl.s16 q0, q1, q2