get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/76959/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 76959,
    "url": "http://patches.dpdk.org/api/patches/76959/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200908201830.74206-26-cristian.dumitrescu@intel.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20200908201830.74206-26-cristian.dumitrescu@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20200908201830.74206-26-cristian.dumitrescu@intel.com",
    "date": "2020-09-08T20:18:14",
    "name": "[v3,25/41] pipeline: introduce SWX jmp and return instructions",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": true,
    "hash": "d557d4b3ad525e553887154cc1b4e1aa656a53ad",
    "submitter": {
        "id": 19,
        "url": "http://patches.dpdk.org/api/people/19/?format=api",
        "name": "Cristian Dumitrescu",
        "email": "cristian.dumitrescu@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20200908201830.74206-26-cristian.dumitrescu@intel.com/mbox/",
    "series": [
        {
            "id": 12034,
            "url": "http://patches.dpdk.org/api/series/12034/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=12034",
            "date": "2020-09-08T20:17:52",
            "name": "Pipeline alignment with the P4 language",
            "version": 3,
            "mbox": "http://patches.dpdk.org/series/12034/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/76959/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/76959/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@inbox.dpdk.org",
        "Delivered-To": "patchwork@inbox.dpdk.org",
        "Received": [
            "from dpdk.org (dpdk.org [92.243.14.124])\n\tby inbox.dpdk.org (Postfix) with ESMTP id 8AF48A04B1;\n\tTue,  8 Sep 2020 22:23:17 +0200 (CEST)",
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 2ADCC1C221;\n\tTue,  8 Sep 2020 22:19:36 +0200 (CEST)",
            "from mga02.intel.com (mga02.intel.com [134.134.136.20])\n by dpdk.org (Postfix) with ESMTP id 5CEF71C119\n for <dev@dpdk.org>; Tue,  8 Sep 2020 22:19:03 +0200 (CEST)",
            "from fmsmga006.fm.intel.com ([10.253.24.20])\n by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 08 Sep 2020 13:18:56 -0700",
            "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com) ([10.237.223.107])\n by fmsmga006.fm.intel.com with ESMTP; 08 Sep 2020 13:18:55 -0700"
        ],
        "IronPort-SDR": [
            "\n a7GVrC/x8eqXdmk2SmEUJMDASm1COQwHSUgMRrN6HbBwxw/E8QMjv6oCEQ/QKt02SyafD25Qhr\n O+hyY7fM+K/g==",
            "\n CW1JJV9EbUE8EGoCGmrhknsq9lRJaXmQpoTM3UUGzAFaRkqgAvSrpzfAdiXPi4PnfUSdaqrzUv\n UjcLp54mByxQ=="
        ],
        "X-IronPort-AV": [
            "E=McAfee;i=\"6000,8403,9738\"; a=\"145939426\"",
            "E=Sophos;i=\"5.76,407,1592895600\"; d=\"scan'208\";a=\"145939426\"",
            "E=Sophos;i=\"5.76,406,1592895600\"; d=\"scan'208\";a=\"504493487\""
        ],
        "X-Amp-Result": "SKIPPED(no attachment in message)",
        "X-Amp-File-Uploaded": "False",
        "X-ExtLoop1": "1",
        "From": "Cristian Dumitrescu <cristian.dumitrescu@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Tue,  8 Sep 2020 21:18:14 +0100",
        "Message-Id": "<20200908201830.74206-26-cristian.dumitrescu@intel.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20200908201830.74206-1-cristian.dumitrescu@intel.com>",
        "References": "<20200907214032.95052-2-cristian.dumitrescu@intel.com>\n <20200908201830.74206-1-cristian.dumitrescu@intel.com>",
        "Subject": "[dpdk-dev] [PATCH v3 25/41] pipeline: introduce SWX jmp and return\n\tinstructions",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n <mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n <mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "The jump instructions are either unconditional (jmp) or conditional on\npositive/negative tests such as header validity (jmpv/jmpnv), table\nlookup hit/miss (jmph/jmpnh), executed action (jmpa/jmpna), equality\n(jmpeq/jmpneq), comparison result (jmplt/jmpgt). The return\ninstruction resumes the pipeline execution after action subroutine.\n\nSigned-off-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>\n---\n lib/librte_pipeline/rte_swx_pipeline.c | 1323 ++++++++++++++++++++++--\n 1 file changed, 1211 insertions(+), 112 deletions(-)",
    "diff": "diff --git a/lib/librte_pipeline/rte_swx_pipeline.c b/lib/librte_pipeline/rte_swx_pipeline.c\nindex aaf2aafa5..ef388fec1 100644\n--- a/lib/librte_pipeline/rte_swx_pipeline.c\n+++ b/lib/librte_pipeline/rte_swx_pipeline.c\n@@ -358,6 +358,84 @@ enum instruction_type {\n \n \t/* extern f.func */\n \tINSTR_EXTERN_FUNC,\n+\n+\t/* jmp LABEL\n+\t * Unconditional jump\n+\t */\n+\tINSTR_JMP,\n+\n+\t/* jmpv LABEL h.header\n+\t * Jump if header is valid\n+\t */\n+\tINSTR_JMP_VALID,\n+\n+\t/* jmpnv LABEL h.header\n+\t * Jump if header is invalid\n+\t */\n+\tINSTR_JMP_INVALID,\n+\n+\t/* jmph LABEL\n+\t * Jump if table lookup hit\n+\t */\n+\tINSTR_JMP_HIT,\n+\n+\t/* jmpnh LABEL\n+\t * Jump if table lookup miss\n+\t */\n+\tINSTR_JMP_MISS,\n+\n+\t/* jmpa LABEL ACTION\n+\t * Jump if action run\n+\t */\n+\tINSTR_JMP_ACTION_HIT,\n+\n+\t/* jmpna LABEL ACTION\n+\t * Jump if action not run\n+\t */\n+\tINSTR_JMP_ACTION_MISS,\n+\n+\t/* jmpeq LABEL a b\n+\t * Jump is a is equal to b\n+\t * a = HMEFT, b = HMEFTI\n+\t */\n+\tINSTR_JMP_EQ,   /* (a, b) = (MEFT, MEFT) or (a, b) = (H, H) */\n+\tINSTR_JMP_EQ_S, /* (a, b) = (MEFT, H) or (a, b) = (H, MEFT) */\n+\tINSTR_JMP_EQ_I, /* (a, b) = (MEFT, I) or (a, b) = (H, I) */\n+\n+\t/* jmpneq LABEL a b\n+\t * Jump is a is not equal to b\n+\t * a = HMEFT, b = HMEFTI\n+\t */\n+\tINSTR_JMP_NEQ,   /* (a, b) = (MEFT, MEFT) or (a, b) = (H, H) */\n+\tINSTR_JMP_NEQ_S, /* (a, b) = (MEFT, H) or (a, b) = (H, MEFT) */\n+\tINSTR_JMP_NEQ_I, /* (a, b) = (MEFT, I) or (a, b) = (H, I) */\n+\n+\t/* jmplt LABEL a b\n+\t * Jump if a is less than b\n+\t * a = HMEFT, b = HMEFTI\n+\t */\n+\tINSTR_JMP_LT,    /* a = MEF, b = MEF */\n+\tINSTR_JMP_LT_MH, /* a = MEF, b = H */\n+\tINSTR_JMP_LT_HM, /* a = H, b = MEF */\n+\tINSTR_JMP_LT_HH, /* a = H, b = H */\n+\tINSTR_JMP_LT_MI, /* a = MEF, b = I */\n+\tINSTR_JMP_LT_HI, /* a = H, b = I */\n+\n+\t/* jmpgt LABEL a b\n+\t * Jump if a is greater than b\n+\t * a = HMEFT, b = HMEFTI\n+\t */\n+\tINSTR_JMP_GT,    /* a = MEF, b = MEF */\n+\tINSTR_JMP_GT_MH, /* a = MEF, b = H */\n+\tINSTR_JMP_GT_HM, /* a = H, b = MEF */\n+\tINSTR_JMP_GT_HH, /* a = H, b = H */\n+\tINSTR_JMP_GT_MI, /* a = MEF, b = I */\n+\tINSTR_JMP_GT_HI, /* a = H, b = I */\n+\n+\t/* return\n+\t * Return from action\n+\t */\n+\tINSTR_RETURN,\n };\n \n struct instr_operand {\n@@ -419,6 +497,21 @@ struct instr_dma {\n \tuint16_t n_bytes[8];\n };\n \n+struct instr_jmp {\n+\tstruct instruction *ip;\n+\n+\tunion {\n+\t\tstruct instr_operand a;\n+\t\tuint8_t header_id;\n+\t\tuint8_t action_id;\n+\t};\n+\n+\tunion {\n+\t\tstruct instr_operand b;\n+\t\tuint32_t b_val;\n+\t};\n+};\n+\n struct instruction {\n \tenum instruction_type type;\n \tunion {\n@@ -430,6 +523,7 @@ struct instruction {\n \t\tstruct instr_table table;\n \t\tstruct instr_extern_obj ext_obj;\n \t\tstruct instr_extern_func ext_func;\n+\t\tstruct instr_jmp jmp;\n \t};\n };\n \n@@ -544,6 +638,9 @@ struct thread {\n #define MASK64_BIT_SET(mask, pos) ((mask) | (1LLU << (pos)))\n #define MASK64_BIT_CLR(mask, pos) ((mask) & ~(1LLU << (pos)))\n \n+#define HEADER_VALID(thread, header_id) \\\n+\tMASK64_BIT_GET((thread)->valid_headers, header_id)\n+\n #define ALU(thread, ip, operator)  \\\n {                                                                              \\\n \tuint8_t *dst_struct = (thread)->structs[(ip)->alu.dst.struct_id];      \\\n@@ -725,6 +822,118 @@ struct thread {\n \t*dst64_ptr = (dst64 & ~dst64_mask) | (src & dst64_mask);               \\\n }\n \n+#define JMP_CMP(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \\\n+\tuint64_t a = a64 & a64_mask;                                           \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \\\n+\tuint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \\\n+\tuint64_t b64 = *b64_ptr;                                               \\\n+\tuint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \\\n+\tuint64_t b = b64 & b64_mask;                                           \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define JMP_CMP_S(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \\\n+\tuint64_t a = a64 & a64_mask;                                           \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \\\n+\tuint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \\\n+\tuint64_t b64 = *b64_ptr;                                               \\\n+\tuint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#define JMP_CMP_MH JMP_CMP_S\n+\n+#define JMP_CMP_HM(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \\\n+\tuint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \\\n+\tuint64_t b64 = *b64_ptr;                                               \\\n+\tuint64_t b64_mask = UINT64_MAX >> (64 - (ip)->jmp.b.n_bits);           \\\n+\tuint64_t b = b64 & b64_mask;                                           \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#define JMP_CMP_HH(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint8_t *b_struct = (thread)->structs[(ip)->jmp.b.struct_id];          \\\n+\tuint64_t *b64_ptr = (uint64_t *)&b_struct[(ip)->jmp.b.offset];         \\\n+\tuint64_t b64 = *b64_ptr;                                               \\\n+\tuint64_t b = ntoh64(b64) >> (64 - (ip)->jmp.b.n_bits);                 \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#else\n+\n+#define JMP_CMP_S JMP_CMP\n+#define JMP_CMP_MH JMP_CMP\n+#define JMP_CMP_HM JMP_CMP\n+#define JMP_CMP_HH JMP_CMP\n+\n+#endif\n+\n+#define JMP_CMP_I(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a64_mask = UINT64_MAX >> (64 - (ip)->jmp.a.n_bits);           \\\n+\tuint64_t a = a64 & a64_mask;                                           \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint64_t b = (ip)->jmp.b_val;                                          \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#define JMP_CMP_MI JMP_CMP_I\n+\n+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN\n+\n+#define JMP_CMP_HI(thread, ip, operator)  \\\n+{                                                                              \\\n+\tuint8_t *a_struct = (thread)->structs[(ip)->jmp.a.struct_id];          \\\n+\tuint64_t *a64_ptr = (uint64_t *)&a_struct[(ip)->jmp.a.offset];         \\\n+\tuint64_t a64 = *a64_ptr;                                               \\\n+\tuint64_t a = ntoh64(a64) >> (64 - (ip)->jmp.a.n_bits);                 \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\tuint64_t b = (ip)->jmp.b_val;                                          \\\n+\t\t\t\t\t\t\t\t\t       \\\n+\t(thread)->ip = (a operator b) ? (ip)->jmp.ip : ((thread)->ip + 1);     \\\n+}\n+\n+#else\n+\n+#define JMP_CMP_HI JMP_CMP_I\n+\n+#endif\n+\n #define METADATA_READ(thread, offset, n_bits)                                  \\\n ({                                                                             \\\n \tuint64_t *m64_ptr = (uint64_t *)&(thread)->metadata[offset];           \\\n@@ -2048,6 +2257,42 @@ metadata_free(struct rte_swx_pipeline *p)\n /*\n  * Instruction.\n  */\n+static int\n+instruction_is_jmp(struct instruction *instr)\n+{\n+\tswitch (instr->type) {\n+\tcase INSTR_JMP:\n+\tcase INSTR_JMP_VALID:\n+\tcase INSTR_JMP_INVALID:\n+\tcase INSTR_JMP_HIT:\n+\tcase INSTR_JMP_MISS:\n+\tcase INSTR_JMP_ACTION_HIT:\n+\tcase INSTR_JMP_ACTION_MISS:\n+\tcase INSTR_JMP_EQ:\n+\tcase INSTR_JMP_EQ_S:\n+\tcase INSTR_JMP_EQ_I:\n+\tcase INSTR_JMP_NEQ:\n+\tcase INSTR_JMP_NEQ_S:\n+\tcase INSTR_JMP_NEQ_I:\n+\tcase INSTR_JMP_LT:\n+\tcase INSTR_JMP_LT_MH:\n+\tcase INSTR_JMP_LT_HM:\n+\tcase INSTR_JMP_LT_HH:\n+\tcase INSTR_JMP_LT_MI:\n+\tcase INSTR_JMP_LT_HI:\n+\tcase INSTR_JMP_GT:\n+\tcase INSTR_JMP_GT_MH:\n+\tcase INSTR_JMP_GT_HM:\n+\tcase INSTR_JMP_GT_HH:\n+\tcase INSTR_JMP_GT_MI:\n+\tcase INSTR_JMP_GT_HI:\n+\t\treturn 1;\n+\n+\tdefault:\n+\t\treturn 0;\n+\t}\n+}\n+\n static struct field *\n action_field_parse(struct action *action, const char *name);\n \n@@ -2136,6 +2381,12 @@ thread_ip_reset(struct rte_swx_pipeline *p, struct thread *t)\n \tt->ip = p->instructions;\n }\n \n+static inline void\n+thread_ip_set(struct thread *t, struct instruction *ip)\n+{\n+\tt->ip = ip;\n+}\n+\n static inline void\n thread_ip_action_call(struct rte_swx_pipeline *p,\n \t\t      struct thread *t,\n@@ -4351,141 +4602,819 @@ instr_alu_ckadd_struct_exec(struct rte_swx_pipeline *p)\n \tthread_ip_inc(p);\n }\n \n-#define RTE_SWX_INSTRUCTION_TOKENS_MAX 16\n+/*\n+ * jmp.\n+ */\n+static struct action *\n+action_find(struct rte_swx_pipeline *p, const char *name);\n \n static int\n-instr_translate(struct rte_swx_pipeline *p,\n-\t\tstruct action *action,\n-\t\tchar *string,\n-\t\tstruct instruction *instr,\n-\t\tstruct instruction_data *data)\n+instr_jmp_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t    struct action *action __rte_unused,\n+\t\t    char **tokens,\n+\t\t    int n_tokens,\n+\t\t    struct instruction *instr,\n+\t\t    struct instruction_data *data)\n {\n-\tchar *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX];\n-\tint n_tokens = 0, tpos = 0;\n+\tCHECK(n_tokens == 2, EINVAL);\n \n-\t/* Parse the instruction string into tokens. */\n-\tfor ( ; ; ) {\n-\t\tchar *token;\n+\tstrcpy(data->jmp_label, tokens[1]);\n \n-\t\ttoken = strtok_r(string, \" \\t\\v\", &string);\n-\t\tif (!token)\n-\t\t\tbreak;\n+\tinstr->type = INSTR_JMP;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n \n-\t\tCHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL);\n+static int\n+instr_jmp_valid_translate(struct rte_swx_pipeline *p,\n+\t\t\t  struct action *action __rte_unused,\n+\t\t\t  char **tokens,\n+\t\t\t  int n_tokens,\n+\t\t\t  struct instruction *instr,\n+\t\t\t  struct instruction_data *data)\n+{\n+\tstruct header *h;\n \n-\t\ttokens[n_tokens] = token;\n-\t\tn_tokens++;\n-\t}\n+\tCHECK(n_tokens == 3, EINVAL);\n \n-\tCHECK(n_tokens, EINVAL);\n+\tstrcpy(data->jmp_label, tokens[1]);\n \n-\t/* Handle the optional instruction label. */\n-\tif ((n_tokens >= 2) && !strcmp(tokens[1], \":\")) {\n-\t\tstrcpy(data->label, tokens[0]);\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n \n-\t\ttpos += 2;\n-\t\tCHECK(n_tokens - tpos, EINVAL);\n-\t}\n+\tinstr->type = INSTR_JMP_VALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n \n-\t/* Identify the instruction type. */\n-\tif (!strcmp(tokens[tpos], \"rx\"))\n-\t\treturn instr_rx_translate(p,\n-\t\t\t\t\t  action,\n-\t\t\t\t\t  &tokens[tpos],\n-\t\t\t\t\t  n_tokens - tpos,\n-\t\t\t\t\t  instr,\n-\t\t\t\t\t  data);\n+static int\n+instr_jmp_invalid_translate(struct rte_swx_pipeline *p,\n+\t\t\t    struct action *action __rte_unused,\n+\t\t\t    char **tokens,\n+\t\t\t    int n_tokens,\n+\t\t\t    struct instruction *instr,\n+\t\t\t    struct instruction_data *data)\n+{\n+\tstruct header *h;\n \n-\tif (!strcmp(tokens[tpos], \"tx\"))\n-\t\treturn instr_tx_translate(p,\n-\t\t\t\t\t  action,\n-\t\t\t\t\t  &tokens[tpos],\n-\t\t\t\t\t  n_tokens - tpos,\n-\t\t\t\t\t  instr,\n-\t\t\t\t\t  data);\n+\tCHECK(n_tokens == 2, EINVAL);\n \n-\tif (!strcmp(tokens[tpos], \"extract\"))\n-\t\treturn instr_hdr_extract_translate(p,\n-\t\t\t\t\t\t   action,\n-\t\t\t\t\t\t   &tokens[tpos],\n-\t\t\t\t\t\t   n_tokens - tpos,\n-\t\t\t\t\t\t   instr,\n-\t\t\t\t\t\t   data);\n+\tstrcpy(data->jmp_label, tokens[1]);\n \n-\tif (!strcmp(tokens[tpos], \"emit\"))\n-\t\treturn instr_hdr_emit_translate(p,\n-\t\t\t\t\t\taction,\n-\t\t\t\t\t\t&tokens[tpos],\n-\t\t\t\t\t\tn_tokens - tpos,\n-\t\t\t\t\t\tinstr,\n-\t\t\t\t\t\tdata);\n+\th = header_parse(p, tokens[2]);\n+\tCHECK(h, EINVAL);\n \n-\tif (!strcmp(tokens[tpos], \"validate\"))\n-\t\treturn instr_hdr_validate_translate(p,\n-\t\t\t\t\t\t    action,\n-\t\t\t\t\t\t    &tokens[tpos],\n-\t\t\t\t\t\t    n_tokens - tpos,\n-\t\t\t\t\t\t    instr,\n-\t\t\t\t\t\t    data);\n+\tinstr->type = INSTR_JMP_INVALID;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.header_id = h->id;\n+\treturn 0;\n+}\n \n-\tif (!strcmp(tokens[tpos], \"invalidate\"))\n-\t\treturn instr_hdr_invalidate_translate(p,\n-\t\t\t\t\t\t      action,\n-\t\t\t\t\t\t      &tokens[tpos],\n-\t\t\t\t\t\t      n_tokens - tpos,\n-\t\t\t\t\t\t      instr,\n-\t\t\t\t\t\t      data);\n+static int\n+instr_jmp_hit_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n \n-\tif (!strcmp(tokens[tpos], \"mov\"))\n-\t\treturn instr_mov_translate(p,\n-\t\t\t\t\t   action,\n-\t\t\t\t\t   &tokens[tpos],\n-\t\t\t\t\t   n_tokens - tpos,\n-\t\t\t\t\t   instr,\n-\t\t\t\t\t   data);\n+\tstrcpy(data->jmp_label, tokens[1]);\n \n-\tif (!strcmp(tokens[tpos], \"dma\"))\n-\t\treturn instr_dma_translate(p,\n-\t\t\t\t\t   action,\n-\t\t\t\t\t   &tokens[tpos],\n-\t\t\t\t\t   n_tokens - tpos,\n-\t\t\t\t\t   instr,\n-\t\t\t\t\t   data);\n+\tinstr->type = INSTR_JMP_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n \n-\tif (!strcmp(tokens[tpos], \"add\"))\n-\t\treturn instr_alu_add_translate(p,\n-\t\t\t\t\t       action,\n-\t\t\t\t\t       &tokens[tpos],\n-\t\t\t\t\t       n_tokens - tpos,\n-\t\t\t\t\t       instr,\n-\t\t\t\t\t       data);\n+static int\n+instr_jmp_miss_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t\t struct action *action,\n+\t\t\t char **tokens,\n+\t\t\t int n_tokens,\n+\t\t\t struct instruction *instr,\n+\t\t\t struct instruction_data *data)\n+{\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 2, EINVAL);\n \n-\tif (!strcmp(tokens[tpos], \"sub\"))\n-\t\treturn instr_alu_sub_translate(p,\n-\t\t\t\t\t       action,\n-\t\t\t\t\t       &tokens[tpos],\n-\t\t\t\t\t       n_tokens - tpos,\n-\t\t\t\t\t       instr,\n-\t\t\t\t\t       data);\n+\tstrcpy(data->jmp_label, tokens[1]);\n \n-\tif (!strcmp(tokens[tpos], \"ckadd\"))\n-\t\treturn instr_alu_ckadd_translate(p,\n-\t\t\t\t\t\t action,\n-\t\t\t\t\t\t &tokens[tpos],\n-\t\t\t\t\t\t n_tokens - tpos,\n-\t\t\t\t\t\t instr,\n-\t\t\t\t\t\t data);\n+\tinstr->type = INSTR_JMP_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\treturn 0;\n+}\n \n-\tif (!strcmp(tokens[tpos], \"cksub\"))\n-\t\treturn instr_alu_cksub_translate(p,\n-\t\t\t\t\t\t action,\n-\t\t\t\t\t\t &tokens[tpos],\n-\t\t\t\t\t\t n_tokens - tpos,\n-\t\t\t\t\t\t instr,\n-\t\t\t\t\t\t data);\n+static int\n+instr_jmp_action_hit_translate(struct rte_swx_pipeline *p,\n+\t\t\t       struct action *action,\n+\t\t\t       char **tokens,\n+\t\t\t       int n_tokens,\n+\t\t\t       struct instruction *instr,\n+\t\t\t       struct instruction_data *data)\n+{\n+\tstruct action *a;\n \n-\tif (!strcmp(tokens[tpos], \"and\"))\n-\t\treturn instr_alu_and_translate(p,\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_HIT;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_action_miss_translate(struct rte_swx_pipeline *p,\n+\t\t\t\tstruct action *action,\n+\t\t\t\tchar **tokens,\n+\t\t\t\tint n_tokens,\n+\t\t\t\tstruct instruction *instr,\n+\t\t\t\tstruct instruction_data *data)\n+{\n+\tstruct action *a;\n+\n+\tCHECK(!action, EINVAL);\n+\tCHECK(n_tokens == 3, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\ta = action_find(p, tokens[2]);\n+\tCHECK(a, EINVAL);\n+\n+\tinstr->type = INSTR_JMP_ACTION_MISS;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.action_id = a->id;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_eq_translate(struct rte_swx_pipeline *p,\n+\t\t       struct action *action,\n+\t\t       char **tokens,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint32_t a_struct_id, b_struct_id, b_val;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_EQ or JMP_EQ_S. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_EQ;\n+\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n+\t\t    (a[0] != 'h' && b[0] == 'h'))\n+\t\t\tinstr->type = INSTR_JMP_EQ_S;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_EQ_I. */\n+\tb_val = strtoul(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tif (a[0] == 'h')\n+\t\tb_val = htonl(b_val);\n+\n+\tinstr->type = INSTR_JMP_EQ_I;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = (uint32_t)b_val;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_neq_translate(struct rte_swx_pipeline *p,\n+\t\t\tstruct action *action,\n+\t\t\tchar **tokens,\n+\t\t\tint n_tokens,\n+\t\t\tstruct instruction *instr,\n+\t\t\tstruct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint32_t a_struct_id, b_struct_id, b_val;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_NEQ or JMP_NEQ_S. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_NEQ;\n+\t\tif ((a[0] == 'h' && b[0] != 'h') ||\n+\t\t    (a[0] != 'h' && b[0] == 'h'))\n+\t\t\tinstr->type = INSTR_JMP_NEQ_S;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_NEQ_I. */\n+\tb_val = strtoul(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tif (a[0] == 'h')\n+\t\tb_val = htonl(b_val);\n+\n+\tinstr->type = INSTR_JMP_NEQ_I;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = (uint32_t)b_val;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_lt_translate(struct rte_swx_pipeline *p,\n+\t\t       struct action *action,\n+\t\t       char **tokens,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint32_t a_struct_id, b_struct_id, b_val;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_LT, JMP_LT_MH, JMP_LT_HM, JMP_LT_HH. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_LT;\n+\t\tif (a[0] == 'h' && b[0] == 'm')\n+\t\t\tinstr->type = INSTR_JMP_LT_HM;\n+\t\tif (a[0] == 'm' && b[0] == 'h')\n+\t\t\tinstr->type = INSTR_JMP_LT_MH;\n+\t\tif (a[0] == 'h' && b[0] == 'h')\n+\t\t\tinstr->type = INSTR_JMP_LT_HH;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_LT_MI, JMP_LT_HI. */\n+\tb_val = strtoul(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tinstr->type = INSTR_JMP_LT_MI;\n+\tif (a[0] == 'h')\n+\t\tinstr->type = INSTR_JMP_LT_HI;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = (uint32_t)b_val;\n+\treturn 0;\n+}\n+\n+static int\n+instr_jmp_gt_translate(struct rte_swx_pipeline *p,\n+\t\t       struct action *action,\n+\t\t       char **tokens,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data)\n+{\n+\tchar *a = tokens[2], *b = tokens[3];\n+\tstruct field *fa, *fb;\n+\tuint32_t a_struct_id, b_struct_id, b_val;\n+\n+\tCHECK(n_tokens == 4, EINVAL);\n+\n+\tstrcpy(data->jmp_label, tokens[1]);\n+\n+\tfa = struct_field_parse(p, action, a, &a_struct_id);\n+\tCHECK(fa, EINVAL);\n+\n+\t/* JMP_GT, JMP_GT_MH, JMP_GT_HM, JMP_GT_HH. */\n+\tfb = struct_field_parse(p, action, b, &b_struct_id);\n+\tif (fb) {\n+\t\tinstr->type = INSTR_JMP_GT;\n+\t\tif (a[0] == 'h' && b[0] == 'm')\n+\t\t\tinstr->type = INSTR_JMP_GT_HM;\n+\t\tif (a[0] == 'm' && b[0] == 'h')\n+\t\t\tinstr->type = INSTR_JMP_GT_MH;\n+\t\tif (a[0] == 'h' && b[0] == 'h')\n+\t\t\tinstr->type = INSTR_JMP_GT_HH;\n+\t\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\t\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\t\tinstr->jmp.a.n_bits = fa->n_bits;\n+\t\tinstr->jmp.a.offset = fa->offset / 8;\n+\t\tinstr->jmp.b.struct_id = (uint8_t)b_struct_id;\n+\t\tinstr->jmp.b.n_bits = fb->n_bits;\n+\t\tinstr->jmp.b.offset = fb->offset / 8;\n+\t\treturn 0;\n+\t}\n+\n+\t/* JMP_GT_MI, JMP_GT_HI. */\n+\tb_val = strtoul(b, &b, 0);\n+\tCHECK(!b[0], EINVAL);\n+\n+\tinstr->type = INSTR_JMP_GT_MI;\n+\tif (a[0] == 'h')\n+\t\tinstr->type = INSTR_JMP_GT_HI;\n+\tinstr->jmp.ip = NULL; /* Resolved later. */\n+\n+\tinstr->jmp.a.struct_id = (uint8_t)a_struct_id;\n+\tinstr->jmp.a.n_bits = fa->n_bits;\n+\tinstr->jmp.a.offset = fa->offset / 8;\n+\tinstr->jmp.b_val = (uint32_t)b_val;\n+\treturn 0;\n+}\n+\n+static inline void\n+instr_jmp_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmp\\n\", p->thread_id);\n+\n+\tthread_ip_set(t, ip->jmp.ip);\n+}\n+\n+static inline void\n+instr_jmp_valid_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint32_t header_id = ip->jmp.header_id;\n+\n+\tTRACE(\"[Thread %2u] jmpv\\n\", p->thread_id);\n+\n+\tt->ip = HEADER_VALID(t, header_id) ? ip->jmp.ip : (t->ip + 1);\n+}\n+\n+static inline void\n+instr_jmp_invalid_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tuint32_t header_id = ip->jmp.header_id;\n+\n+\tTRACE(\"[Thread %2u] jmpnv\\n\", p->thread_id);\n+\n+\tt->ip = HEADER_VALID(t, header_id) ? (t->ip + 1) : ip->jmp.ip;\n+}\n+\n+static inline void\n+instr_jmp_hit_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tstruct instruction *ip_next[] = {t->ip + 1, ip->jmp.ip};\n+\n+\tTRACE(\"[Thread %2u] jmph\\n\", p->thread_id);\n+\n+\tt->ip = ip_next[t->hit];\n+}\n+\n+static inline void\n+instr_jmp_miss_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\tstruct instruction *ip_next[] = {ip->jmp.ip, t->ip + 1};\n+\n+\tTRACE(\"[Thread %2u] jmpnh\\n\", p->thread_id);\n+\n+\tt->ip = ip_next[t->hit];\n+}\n+\n+static inline void\n+instr_jmp_action_hit_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpa\\n\", p->thread_id);\n+\n+\tt->ip = (ip->jmp.action_id == t->action_id) ? ip->jmp.ip : (t->ip + 1);\n+}\n+\n+static inline void\n+instr_jmp_action_miss_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpna\\n\", p->thread_id);\n+\n+\tt->ip = (ip->jmp.action_id == t->action_id) ? (t->ip + 1) : ip->jmp.ip;\n+}\n+\n+static inline void\n+instr_jmp_eq_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpeq\\n\", p->thread_id);\n+\n+\tJMP_CMP(t, ip, ==);\n+}\n+\n+static inline void\n+instr_jmp_eq_s_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpeq (s)\\n\", p->thread_id);\n+\n+\tJMP_CMP_S(t, ip, ==);\n+}\n+\n+static inline void\n+instr_jmp_eq_i_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpeq (i)\\n\", p->thread_id);\n+\n+\tJMP_CMP_I(t, ip, ==);\n+}\n+\n+static inline void\n+instr_jmp_neq_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpneq\\n\", p->thread_id);\n+\n+\tJMP_CMP(t, ip, !=);\n+}\n+\n+static inline void\n+instr_jmp_neq_s_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpneq (s)\\n\", p->thread_id);\n+\n+\tJMP_CMP_S(t, ip, !=);\n+}\n+\n+static inline void\n+instr_jmp_neq_i_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpneq (i)\\n\", p->thread_id);\n+\n+\tJMP_CMP_I(t, ip, !=);\n+}\n+\n+static inline void\n+instr_jmp_lt_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt\\n\", p->thread_id);\n+\n+\tJMP_CMP(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_lt_mh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt (mh)\\n\", p->thread_id);\n+\n+\tJMP_CMP_MH(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_lt_hm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt (hm)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HM(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_lt_hh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt (hh)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HH(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_lt_mi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt (mi)\\n\", p->thread_id);\n+\n+\tJMP_CMP_MI(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_lt_hi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmplt (hi)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HI(t, ip, <);\n+}\n+\n+static inline void\n+instr_jmp_gt_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt\\n\", p->thread_id);\n+\n+\tJMP_CMP(t, ip, >);\n+}\n+\n+static inline void\n+instr_jmp_gt_mh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt (mh)\\n\", p->thread_id);\n+\n+\tJMP_CMP_MH(t, ip, >);\n+}\n+\n+static inline void\n+instr_jmp_gt_hm_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt (hm)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HM(t, ip, >);\n+}\n+\n+static inline void\n+instr_jmp_gt_hh_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt (hh)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HH(t, ip, >);\n+}\n+\n+static inline void\n+instr_jmp_gt_mi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt (mi)\\n\", p->thread_id);\n+\n+\tJMP_CMP_MI(t, ip, >);\n+}\n+\n+static inline void\n+instr_jmp_gt_hi_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\tstruct instruction *ip = t->ip;\n+\n+\tTRACE(\"[Thread %2u] jmpgt (hi)\\n\", p->thread_id);\n+\n+\tJMP_CMP_HI(t, ip, >);\n+}\n+\n+/*\n+ * return.\n+ */\n+static int\n+instr_return_translate(struct rte_swx_pipeline *p __rte_unused,\n+\t\t       struct action *action,\n+\t\t       char **tokens __rte_unused,\n+\t\t       int n_tokens,\n+\t\t       struct instruction *instr,\n+\t\t       struct instruction_data *data __rte_unused)\n+{\n+\tCHECK(action, EINVAL);\n+\tCHECK(n_tokens == 1, EINVAL);\n+\n+\tinstr->type = INSTR_RETURN;\n+\treturn 0;\n+}\n+\n+static inline void\n+instr_return_exec(struct rte_swx_pipeline *p)\n+{\n+\tstruct thread *t = &p->threads[p->thread_id];\n+\n+\tTRACE(\"[Thread %2u] return\\n\", p->thread_id);\n+\n+\tt->ip = t->ret;\n+}\n+\n+#define RTE_SWX_INSTRUCTION_TOKENS_MAX 16\n+\n+static int\n+instr_translate(struct rte_swx_pipeline *p,\n+\t\tstruct action *action,\n+\t\tchar *string,\n+\t\tstruct instruction *instr,\n+\t\tstruct instruction_data *data)\n+{\n+\tchar *tokens[RTE_SWX_INSTRUCTION_TOKENS_MAX];\n+\tint n_tokens = 0, tpos = 0;\n+\n+\t/* Parse the instruction string into tokens. */\n+\tfor ( ; ; ) {\n+\t\tchar *token;\n+\n+\t\ttoken = strtok_r(string, \" \\t\\v\", &string);\n+\t\tif (!token)\n+\t\t\tbreak;\n+\n+\t\tCHECK(n_tokens < RTE_SWX_INSTRUCTION_TOKENS_MAX, EINVAL);\n+\n+\t\ttokens[n_tokens] = token;\n+\t\tn_tokens++;\n+\t}\n+\n+\tCHECK(n_tokens, EINVAL);\n+\n+\t/* Handle the optional instruction label. */\n+\tif ((n_tokens >= 2) && !strcmp(tokens[1], \":\")) {\n+\t\tstrcpy(data->label, tokens[0]);\n+\n+\t\ttpos += 2;\n+\t\tCHECK(n_tokens - tpos, EINVAL);\n+\t}\n+\n+\t/* Identify the instruction type. */\n+\tif (!strcmp(tokens[tpos], \"rx\"))\n+\t\treturn instr_rx_translate(p,\n+\t\t\t\t\t  action,\n+\t\t\t\t\t  &tokens[tpos],\n+\t\t\t\t\t  n_tokens - tpos,\n+\t\t\t\t\t  instr,\n+\t\t\t\t\t  data);\n+\n+\tif (!strcmp(tokens[tpos], \"tx\"))\n+\t\treturn instr_tx_translate(p,\n+\t\t\t\t\t  action,\n+\t\t\t\t\t  &tokens[tpos],\n+\t\t\t\t\t  n_tokens - tpos,\n+\t\t\t\t\t  instr,\n+\t\t\t\t\t  data);\n+\n+\tif (!strcmp(tokens[tpos], \"extract\"))\n+\t\treturn instr_hdr_extract_translate(p,\n+\t\t\t\t\t\t   action,\n+\t\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t\t   instr,\n+\t\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"emit\"))\n+\t\treturn instr_hdr_emit_translate(p,\n+\t\t\t\t\t\taction,\n+\t\t\t\t\t\t&tokens[tpos],\n+\t\t\t\t\t\tn_tokens - tpos,\n+\t\t\t\t\t\tinstr,\n+\t\t\t\t\t\tdata);\n+\n+\tif (!strcmp(tokens[tpos], \"validate\"))\n+\t\treturn instr_hdr_validate_translate(p,\n+\t\t\t\t\t\t    action,\n+\t\t\t\t\t\t    &tokens[tpos],\n+\t\t\t\t\t\t    n_tokens - tpos,\n+\t\t\t\t\t\t    instr,\n+\t\t\t\t\t\t    data);\n+\n+\tif (!strcmp(tokens[tpos], \"invalidate\"))\n+\t\treturn instr_hdr_invalidate_translate(p,\n+\t\t\t\t\t\t      action,\n+\t\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t\t      instr,\n+\t\t\t\t\t\t      data);\n+\n+\tif (!strcmp(tokens[tpos], \"mov\"))\n+\t\treturn instr_mov_translate(p,\n+\t\t\t\t\t   action,\n+\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t   instr,\n+\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"dma\"))\n+\t\treturn instr_dma_translate(p,\n+\t\t\t\t\t   action,\n+\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t   instr,\n+\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"add\"))\n+\t\treturn instr_alu_add_translate(p,\n+\t\t\t\t\t       action,\n+\t\t\t\t\t       &tokens[tpos],\n+\t\t\t\t\t       n_tokens - tpos,\n+\t\t\t\t\t       instr,\n+\t\t\t\t\t       data);\n+\n+\tif (!strcmp(tokens[tpos], \"sub\"))\n+\t\treturn instr_alu_sub_translate(p,\n+\t\t\t\t\t       action,\n+\t\t\t\t\t       &tokens[tpos],\n+\t\t\t\t\t       n_tokens - tpos,\n+\t\t\t\t\t       instr,\n+\t\t\t\t\t       data);\n+\n+\tif (!strcmp(tokens[tpos], \"ckadd\"))\n+\t\treturn instr_alu_ckadd_translate(p,\n+\t\t\t\t\t\t action,\n+\t\t\t\t\t\t &tokens[tpos],\n+\t\t\t\t\t\t n_tokens - tpos,\n+\t\t\t\t\t\t instr,\n+\t\t\t\t\t\t data);\n+\n+\tif (!strcmp(tokens[tpos], \"cksub\"))\n+\t\treturn instr_alu_cksub_translate(p,\n+\t\t\t\t\t\t action,\n+\t\t\t\t\t\t &tokens[tpos],\n+\t\t\t\t\t\t n_tokens - tpos,\n+\t\t\t\t\t\t instr,\n+\t\t\t\t\t\t data);\n+\n+\tif (!strcmp(tokens[tpos], \"and\"))\n+\t\treturn instr_alu_and_translate(p,\n \t\t\t\t\t       action,\n \t\t\t\t\t       &tokens[tpos],\n \t\t\t\t\t       n_tokens - tpos,\n@@ -4540,9 +5469,117 @@ instr_translate(struct rte_swx_pipeline *p,\n \t\t\t\t\t      instr,\n \t\t\t\t\t      data);\n \n+\tif (!strcmp(tokens[tpos], \"jmp\"))\n+\t\treturn instr_jmp_translate(p,\n+\t\t\t\t\t   action,\n+\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t   instr,\n+\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpv\"))\n+\t\treturn instr_jmp_valid_translate(p,\n+\t\t\t\t\t\t action,\n+\t\t\t\t\t\t &tokens[tpos],\n+\t\t\t\t\t\t n_tokens - tpos,\n+\t\t\t\t\t\t instr,\n+\t\t\t\t\t\t data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpnv\"))\n+\t\treturn instr_jmp_invalid_translate(p,\n+\t\t\t\t\t\t   action,\n+\t\t\t\t\t\t   &tokens[tpos],\n+\t\t\t\t\t\t   n_tokens - tpos,\n+\t\t\t\t\t\t   instr,\n+\t\t\t\t\t\t   data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmph\"))\n+\t\treturn instr_jmp_hit_translate(p,\n+\t\t\t\t\t       action,\n+\t\t\t\t\t       &tokens[tpos],\n+\t\t\t\t\t       n_tokens - tpos,\n+\t\t\t\t\t       instr,\n+\t\t\t\t\t       data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpnh\"))\n+\t\treturn instr_jmp_miss_translate(p,\n+\t\t\t\t\t\taction,\n+\t\t\t\t\t\t&tokens[tpos],\n+\t\t\t\t\t\tn_tokens - tpos,\n+\t\t\t\t\t\tinstr,\n+\t\t\t\t\t\tdata);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpa\"))\n+\t\treturn instr_jmp_action_hit_translate(p,\n+\t\t\t\t\t\t      action,\n+\t\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t\t      instr,\n+\t\t\t\t\t\t      data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpna\"))\n+\t\treturn instr_jmp_action_miss_translate(p,\n+\t\t\t\t\t\t       action,\n+\t\t\t\t\t\t       &tokens[tpos],\n+\t\t\t\t\t\t       n_tokens - tpos,\n+\t\t\t\t\t\t       instr,\n+\t\t\t\t\t\t       data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpeq\"))\n+\t\treturn instr_jmp_eq_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpneq\"))\n+\t\treturn instr_jmp_neq_translate(p,\n+\t\t\t\t\t       action,\n+\t\t\t\t\t       &tokens[tpos],\n+\t\t\t\t\t       n_tokens - tpos,\n+\t\t\t\t\t       instr,\n+\t\t\t\t\t       data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmplt\"))\n+\t\treturn instr_jmp_lt_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n+\tif (!strcmp(tokens[tpos], \"jmpgt\"))\n+\t\treturn instr_jmp_gt_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n+\tif (!strcmp(tokens[tpos], \"return\"))\n+\t\treturn instr_return_translate(p,\n+\t\t\t\t\t      action,\n+\t\t\t\t\t      &tokens[tpos],\n+\t\t\t\t\t      n_tokens - tpos,\n+\t\t\t\t\t      instr,\n+\t\t\t\t\t      data);\n+\n \tCHECK(0, EINVAL);\n }\n \n+static struct instruction_data *\n+label_find(struct instruction_data *data, uint32_t n, const char *label)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < n; i++)\n+\t\tif (!strcmp(label, data[i].label))\n+\t\t\treturn &data[i];\n+\n+\treturn NULL;\n+}\n+\n static uint32_t\n label_is_used(struct instruction_data *data, uint32_t n, const char *label)\n {\n@@ -4590,6 +5627,32 @@ instr_label_check(struct instruction_data *instruction_data,\n \treturn 0;\n }\n \n+static int\n+instr_jmp_resolve(struct instruction *instructions,\n+\t\t  struct instruction_data *instruction_data,\n+\t\t  uint32_t n_instructions)\n+{\n+\tuint32_t i;\n+\n+\tfor (i = 0; i < n_instructions; i++) {\n+\t\tstruct instruction *instr = &instructions[i];\n+\t\tstruct instruction_data *data = &instruction_data[i];\n+\t\tstruct instruction_data *found;\n+\n+\t\tif (!instruction_is_jmp(instr))\n+\t\t\tcontinue;\n+\n+\t\tfound = label_find(instruction_data,\n+\t\t\t\t   n_instructions,\n+\t\t\t\t   data->jmp_label);\n+\t\tCHECK(found, EINVAL);\n+\n+\t\tinstr->jmp.ip = &instr[found - instruction_data];\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int\n instruction_config(struct rte_swx_pipeline *p,\n \t\t   struct action *a,\n@@ -4638,6 +5701,10 @@ instruction_config(struct rte_swx_pipeline *p,\n \tif (err)\n \t\tgoto error;\n \n+\terr = instr_jmp_resolve(instr, data, n_instructions);\n+\tif (err)\n+\t\tgoto error;\n+\n \tfree(data);\n \n \tif (a) {\n@@ -4746,6 +5813,38 @@ static instr_exec_t instruction_table[] = {\n \t[INSTR_TABLE] = instr_table_exec,\n \t[INSTR_EXTERN_OBJ] = instr_extern_obj_exec,\n \t[INSTR_EXTERN_FUNC] = instr_extern_func_exec,\n+\n+\t[INSTR_JMP] = instr_jmp_exec,\n+\t[INSTR_JMP_VALID] = instr_jmp_valid_exec,\n+\t[INSTR_JMP_INVALID] = instr_jmp_invalid_exec,\n+\t[INSTR_JMP_HIT] = instr_jmp_hit_exec,\n+\t[INSTR_JMP_MISS] = instr_jmp_miss_exec,\n+\t[INSTR_JMP_ACTION_HIT] = instr_jmp_action_hit_exec,\n+\t[INSTR_JMP_ACTION_MISS] = instr_jmp_action_miss_exec,\n+\n+\t[INSTR_JMP_EQ] = instr_jmp_eq_exec,\n+\t[INSTR_JMP_EQ_S] = instr_jmp_eq_s_exec,\n+\t[INSTR_JMP_EQ_I] = instr_jmp_eq_i_exec,\n+\n+\t[INSTR_JMP_NEQ] = instr_jmp_neq_exec,\n+\t[INSTR_JMP_NEQ_S] = instr_jmp_neq_s_exec,\n+\t[INSTR_JMP_NEQ_I] = instr_jmp_neq_i_exec,\n+\n+\t[INSTR_JMP_LT] = instr_jmp_lt_exec,\n+\t[INSTR_JMP_LT_MH] = instr_jmp_lt_mh_exec,\n+\t[INSTR_JMP_LT_HM] = instr_jmp_lt_hm_exec,\n+\t[INSTR_JMP_LT_HH] = instr_jmp_lt_hh_exec,\n+\t[INSTR_JMP_LT_MI] = instr_jmp_lt_mi_exec,\n+\t[INSTR_JMP_LT_HI] = instr_jmp_lt_hi_exec,\n+\n+\t[INSTR_JMP_GT] = instr_jmp_gt_exec,\n+\t[INSTR_JMP_GT_MH] = instr_jmp_gt_mh_exec,\n+\t[INSTR_JMP_GT_HM] = instr_jmp_gt_hm_exec,\n+\t[INSTR_JMP_GT_HH] = instr_jmp_gt_hh_exec,\n+\t[INSTR_JMP_GT_MI] = instr_jmp_gt_mi_exec,\n+\t[INSTR_JMP_GT_HI] = instr_jmp_gt_hi_exec,\n+\n+\t[INSTR_RETURN] = instr_return_exec,\n };\n \n static inline void\n",
    "prefixes": [
        "v3",
        "25/41"
    ]
}