[PATCH v4] PowerPC: Support for Elliptic Curve Cryptography Instructions (RFC02669)
Surya Kumari Jangala
jskumari@linux.ibm.com
Mon Jan 12 10:01:15 GMT 2026
One other thing I missed mentioning is that the order of the opcodes
in powerpc_opcodes[] is incorrect. But this seems to be fixed in v5.
On 12/01/26 12:57 pm, Abhay Kandpal wrote:
>
> On 10/01/26 17:09, Surya Kumari Jangala wrote:
>> Hi,
>>
>> On 07/01/26 2:46 pm, Abhay Kandpal wrote:
>>> opcodes/
>>> * ppc-opc.c: (insert_s3, extract_s3):New functions.
>> Incorrect indentation. The tab should be 8 chars in length.
>>
>>> (XX3MUL_MASK, XX3SUM_MASK, XX3MADD_MASK, XX4EXT, P_XX4EXT_MASK
>>> SFUNC, S0EXP, S1EXP, S2EXP, PSSUM, PSSUMEXT): New defines.
>>> (PS, PSD): Update for new macros.
>>> (powerpc_opcodes): Add xxmulmul, xxmulmulhiadd, xxmulmulloadd,
>>> xxssumudm, xxssumudmc, xsmerge2t3uqm, xsaddadduqm, xsaddaddsuqm,
>>> xsaddsubuqm, xsmerge3t1uqm, xsrebase2t1uqm, xsrebase2t2uqm,
>>> xsrebase3t3uqm, xsrebase2t3uqm, xsrebase2t4uqm, xsaddsubsuqm,
>>> xsmerge2t1uqm, xsmerge2t2uqm, xsrebase3t1uqm, xsrebase3t2uqm,
>>> xxssumudmcext.
>>>
>>> gas/
>>> * testsuite/gas/ppc/future.s: New test.
>> Ditto.
>>
>>> * testsuite/gas/ppc/future.d: Likewise.
>>> ---
>>> This patch is reg tested.
>>> Changes from v3->v4
>>> <Created new functions to verify S value>
>>> <Used regex [[:space:]]* in test case to avoid whitespace warning>
>>>
>>> gas/testsuite/gas/ppc/future.d | 22 ++++++++
>>> gas/testsuite/gas/ppc/future.s | 21 ++++++++
>>> opcodes/ppc-opc.c | 94 +++++++++++++++++++++++++++++++++-
>>> 3 files changed, 135 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/gas/testsuite/gas/ppc/future.d b/gas/testsuite/gas/ppc/future.d
>>> index efb3ee8428d..5cd15578c93 100644
>>> --- a/gas/testsuite/gas/ppc/future.d
>>> +++ b/gas/testsuite/gas/ppc/future.d
>>> @@ -109,4 +109,26 @@ Disassembly of section \.text:
>>> .*: (4c 06 00 7c|7c 00 06 4c) ccmclean
>>> .*: (cc 06 00 7c|7c 00 06 cc) ccmrl
>>> .*: (26 22 40 7c|7c 40 22 26) mtlpl r4,r2
>>> +.*: (0f 36 44 ec|ec 44 36 0f) xxmulmul vs34,vs36,vs38,6
>>> +.*: (4d 4d a7 ec|ec a7 4d 4d) xxmulmulhiadd vs37,vs39,vs9,1,0,1
>>> +.*: (8f 69 4c ed|ed 4c 69 8f) xxmulmulloadd vs42,vs44,vs45,0,1
>>> +.*: (c8 34 85 ec|ec 85 34 c8) xxssumudm vs4,vs5,vs6,1
>>> +.*: (c8 39 64 ec|ec 64 39 c8) xxssumudmc vs3,vs4,vs7,0
>>> +.*: (07 ab 74 ee|ee 74 ab 07) xsaddadduqm vs51,vs52,vs53
>>> +.*: (40 13 01 ec|ec 01 13 40) xsaddaddsuqm vs0,vs1,vs2
>>> +.*: (87 fb be ef|ef be fb 87) xsaddsubuqm vs61,vs62,vs63
>>> +.*: (00 2f 64 ec|ec 64 2f 00) xsaddsubsuqm vs3,vs4,vs5
>>> +.*: (40 57 c8 ec|ec c8 57 40) xsmerge2t1uqm vs6,vs8,vs10
>>> +.*: (80 87 8e ed|ed 8e 87 80) xsmerge2t2uqm vs12,vs14,vs16
>>> +.*: (c8 a2 53 ee|ee 53 a2 c8) xsmerge2t3uqm vs18,vs19,vs20
>>> +.*: (c8 cb b7 ee|ee b7 cb c8) xsmerge3t1uqm vs21,vs23,vs25
>>> +.*: (88 f4 7d ef|ef 7d f4 88) xsrebase2t1uqm vs27,vs29,vs30
>>> +.*: (8e 0d e0 ef|ef e0 0d 8e) xsrebase2t2uqm vs31,vs32,vs33
>>> +.*: (8f 26 43 ec|ec 43 26 8f) xsrebase2t3uqm vs34,vs35,vs36
>>> +.*: (cf 2e 64 ec|ec 64 2e cf) xsrebase2t4uqm vs35,vs36,vs37
>>> +.*: (8f 47 c7 ec|ec c7 47 8f) xsrebase3t1uqm vs38,vs39,vs40
>>> +.*: (cf 5f 2a ed|ed 2a 5f cf) xsrebase3t2uqm vs41,vs42,vs43
>>> +.*: (1f 76 8d ed|ed 8d 76 1f) xsrebase3t3uqm vs44,vs45,vs46
>>> +.*: (00 00 00 05|05 00 00 00) xxssumudmcext vs35,vs9,vs11,vs13,1
>>> +.*: (71 5b 69 88|88 69 5b 71)[[:space:]]*
>>> #pass
>>> diff --git a/gas/testsuite/gas/ppc/future.s b/gas/testsuite/gas/ppc/future.s
>>> index e66465a7418..0bb0e5f0eb1 100644
>>> --- a/gas/testsuite/gas/ppc/future.s
>>> +++ b/gas/testsuite/gas/ppc/future.s
>>> @@ -83,4 +83,25 @@ _start:
>>> ccmclean
>>> ccmrl
>>> mtlpl 4, 2
>>> + xxmulmul 34, 36, 38, 6
>>> + xxmulmulhiadd 37, 39, 9, 1, 0, 1
>>> + xxmulmulloadd 42, 44, 45, 0, 1
>>> + xxssumudm 4, 5, 6, 1
>>> + xxssumudmc 3, 4, 7, 0
>>> + xsaddadduqm 51, 52, 53
>>> + xsaddaddsuqm 0, 1, 2
>>> + xsaddsubuqm 61, 62, 63
>>> + xsaddsubsuqm 3, 4, 5
>>> + xsmerge2t1uqm 6, 8, 10
>>> + xsmerge2t2uqm 12, 14, 16
>>> + xsmerge2t3uqm 18, 19, 20
>>> + xsmerge3t1uqm 21, 23, 25
>>> + xsrebase2t1uqm 27, 29, 30
>>> + xsrebase2t2uqm 31, 32, 33
>>> + xsrebase2t3uqm 34, 35, 36
>>> + xsrebase2t4uqm 35, 36, 37
>>> + xsrebase3t1uqm 38, 39, 40
>>> + xsrebase3t2uqm 41, 42, 43
>>> + xsrebase3t3uqm 44, 45, 46
>>> + xxssumudmcext 35, 9, 11, 13, 1
>>> diff --git a/opcodes/ppc-opc.c b/opcodes/ppc-opc.c
>>> index ddf0a8ca69c..297f9470a12 100644
>>> --- a/opcodes/ppc-opc.c
>>> +++ b/opcodes/ppc-opc.c
>>> @@ -2359,6 +2359,34 @@ extract_xab6 (uint64_t insn,
>>> return xa6;
>>> }
>>> +/* The S field in XX3 form bit (21-23) as arithmetic function */
>>> +
>>> +static uint64_t
>>> +insert_s3 (uint64_t insn,
>>> + int64_t value,
>>> + ppc_cpu_t dialect ATTRIBUTE_UNUSED,
>>> + const char **errmsg)
>>> +{
>>> + if (value == 7)
>>> + {
>>> + *errmsg = _("invalid S value (must be 0 - 6)");
>>> + return insn;
>> This line is incorrect and should be removed.
>
> Thanks for the clarification, I will drop the early return and follow the existing insert_*
>
> behaviour of returning the modified instruction even on error.
>
>>
>>> + }
>>> + return (insn | ((value & 0x7) << 8));
>>> +}
>>> +
>>> +static int64_t
>>> +extract_s3 (uint64_t insn,
>>> + ppc_cpu_t dialect ATTRIBUTE_UNUSED,
>>> + int *invalid)
>>> +{
>>> + int64_t value = (insn >> 8) & 0x7;
>>> +
>>> + if (value == 7)
>>> + *invalid = 1;
>>> + return value;
>>> +}
>>> +
>>> /* The XC field in an XX4 form instruction. This is split. */
>>> static uint64_t
>>> @@ -3729,8 +3757,14 @@ const struct powerpc_operand powerpc_operands[] =
>>> #define MMMM SIX
>>> { 0xf, 11, NULL, NULL, 0 },
>>> + /* The P bit in Prefix XX4-form instruction. */
>>> +#define PSSUMEXT MMMM + 1
>>> + { 0x1, 4, NULL, NULL, 0 },
>>> +
>>> + /* The S1 bit an exponent in XX3 form bit (22) */
>>> +#define S1EXP PSSUMEXT + 1
>>> /* The PS field in a VX form instruction. */
>>> -#define PS SIX + 1
>>> +#define PS PSSUMEXT + 1
>>> { 0x1, 9, NULL, NULL, 0 },
>>> /* The SH field in a vector shift double by bit immediate instruction. */
>>> @@ -3778,6 +3812,10 @@ const struct powerpc_operand powerpc_operands[] =
>>> /* PowerPC paired singles extensions. */
>>> /* W bit in the pair singles instructions for x type instructions. */
>>> #define PSWM WS + 1
>>> + /* The P bit in scaled multiply-sum XX3 form instructions (bit 21) */
>>> +#define PSSUM PSWM
>>> + /* The S0 bit an exponent in XX3 form bit (21) */
>>> +#define S0EXP PSWM
>>> /* The BO16 field in a BD8 form instruction. */
>>> #define BO16 PSWM
>>> /* The pst field in a SVRM form instruction. */
>>> @@ -3794,8 +3832,12 @@ const struct powerpc_operand powerpc_operands[] =
>>> #define PSQM PSQ + 1
>>> { 0x7, 7, 0, 0, PPC_OPERAND_GQR },
>>> + /* The S field in XX3 form bit (21-23) as arithmetic function */
>>> +#define SFUNC PSQM + 1
>>> + { 0x7, 8, insert_s3, extract_s3, 0 },
>> The shift amount (the second field) should be PPC_OPSHIFT_INV, not 8.
>
> My reasoning for using a normal shift (8) instead of|PPC_OPSHIFT_INV| is that the S field is a contiguous 3-bit field at a fixed position (bits 21–23),
>
> and the placement itself is fully representable by the generic shift+mask encoding.
>
> The custom|insert_s3| /|extract_s3| helpers are used only to enforce architectural validity (rejecting S>6),
>
> not because the field is split or requires non-generic placement.
>
> This pattern is already used in several existing operands where insert/extract are present alongside a normal shift (e.g.|CRWn|,|ERWn|,|DMEX|,|PL|),
>
> and functional testing confirms that validation is correctly applied (invalid values are rejected).
>
> Please let me know your view point.
Doesn't seem to make sense to use a shift when insert/extract routines are present.
However, to keep in line with existing code, you can use 8.
>
>>
>>> +
>>> /* Smaller D field for quantization in the pair singles instructions. */
>>> -#define PSD PSQM + 1
>>> +#define PSD SFUNC + 1
>>> { 0xfff, 0, 0, 0, PPC_OPERAND_PARENS | PPC_OPERAND_SIGNED },
>>> /* The L field in an mtmsrd or A form instruction or R or W in an
>>> @@ -4026,6 +4068,8 @@ const struct powerpc_operand powerpc_operands[] =
>>> #define ms vs + 1
>>> #define yx ms
>>> + /* The S2 bit an exponent in XX3 form bit (23) */
>>> +#define S2EXP yx
>> This should be #define S2EXP ms
>
> Understood, I should update operand index instead of alias name. I will update it.
>
>>
>>> /* The P field in Galois Field XX3 form instruction. */
>>> #define PGF1 yx
>>> { 0x1, 8, NULL, NULL, 0 },
>>> @@ -4105,6 +4149,7 @@ const unsigned int num_powerpc_operands = ARRAY_SIZE (powerpc_operands);
>>> #define P_XX4_MASK (PREFIX_MASK | XX4_MASK)
>>> #define P_UXX4_MASK (P_XX4_MASK & ~(7ULL << 32))
>>> #define P_U8XX4_MASK (P_XX4_MASK & ~(0xffULL << 32))
>>> +#define P_XX4EXT_MASK (PREFIX_MASK | XX4EXT (0x3f, 0x1))
>>> /* MMIRR:XX3-form 8-byte outer product instructions. */
>>> #define P_GER_MASK ((-1ULL << 40) | XX3ACC_MASK)
>>> @@ -4597,6 +4642,9 @@ const unsigned int num_powerpc_operands = ARRAY_SIZE (powerpc_operands);
>>> /* An XX4 form instruction. */
>>> #define XX4(op, xop) (OP (op) | ((((uint64_t)(xop)) & 0x3) << 4))
>>> +/* An XX4 form instruction with 1 bit carry extended. */
>>> +#define XX4EXT(op, xop) (OP (op) | ((((uint64_t)(xop)) & 0x1) << 5))
>>> +
>>> /* A Z form instruction. */
>>> #define Z(op, xop) (OP (op) | ((((uint64_t)(xop)) & 0x1ff) << 1))
>>> @@ -4675,6 +4723,7 @@ const unsigned int num_powerpc_operands = ARRAY_SIZE (powerpc_operands);
>>> specified. */
Modify the comment. Or add a new one for XX3MADD_MASK.
>>> #define XX3DM_MASK (XX3 (0x3f, 0x1f) | (1 << 10))
>>> #define XX3SHW_MASK XX3DM_MASK
>>> +#define XX3MADD_MASK XX3DM_MASK
>>> /* The masks for X* form instructions with an ACC/DMR register. */
>>> #define XX2ACC_MASK (XX2 (0x3f, 0x1ff) | (3 << 21) | 1)
>>> @@ -4694,6 +4743,12 @@ const unsigned int num_powerpc_operands = ARRAY_SIZE (powerpc_operands);
>>> /* The masks for XX3 GF instructions with P bit. */
>>> #define XX3GF_MASK (XX3 (0x3f, 0xff) & ~(1 << 8))
>>> +/* The masks for VSX multiply XX3 instructions with scale bits. */
>>> +#define XX3MUL_MASK (XX3 (0x3f, 0x1f))
>>> +
>>> +/* The masks for VSX multiplty-sum XX3 instructions with p bits. */
>>> +#define XX3SUM_MASK (XX3 (0x3f, 0x7f))
>>> +
>>> /* The mask for an XX4 form instruction. */
>>> #define XX4_MASK XX4 (0x3f, 0x3)
>>> @@ -9161,6 +9216,8 @@ const struct powerpc_opcode powerpc_opcodes[] = {
>>> {"ldu", DSO(58,1), DS_MASK, PPC64, PPCVLE, {RT, DS, RAL}},
>>> {"lwa", DSO(58,2), DS_MASK, PPC64, PPCVLE, {RT, DS, RA0}},
>>> +{"xxmulmul", XX3(59,1), XX3MUL_MASK, FUTURE, PPCVLE, {XT6, XA6, XB6, SFUNC}},
>>> +
>>> {"dadd", XRC(59,2,0), X_MASK, POWER6, PPCVLE, {FRT, FRA, FRB}},
>>> {"dadd.", XRC(59,2,1), X_MASK, POWER6, PPCVLE, {FRT, FRA, FRB}},
>>> @@ -9172,6 +9229,9 @@ const struct powerpc_opcode powerpc_opcodes[] = {
>>> {"dmxvi8ger4", XX3(59,3), XX3ACC_MASK, POWER10, PPCVLE, {ACC, XA6a, XB6a}},
>>> {"xvi8ger4", XX3(59,3), XX3ACC_MASK, POWER10, PPCVLE, {ACC, XA6a, XB6a}},
>>> +{"xxmulmulhiadd",XX3(59,9), XX3MUL_MASK, FUTURE, PPCVLE, {XT6, XA6, XB6, S0EXP, S1EXP, S2EXP}},
>>> +{"xxmulmulloadd",XX3(59,17), XX3MADD_MASK, FUTURE, PPCVLE, {XT6, XA6, XB6, S1EXP, S2EXP}},
>> The 21st bit is 0. This is not being handled here.
>
> I think 21st bit is handled by below macro
>
> #define XX3DM_MASK (XX3 (0x3f, 0x1f) | (1 << 10))
> #define XX3MADD_MASK XX3DM_MAS
this is fine.
-Surya
More information about the Binutils
mailing list