Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/76020/?format=api
http://patches.dpdk.org/api/patches/76020/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/patch/20200826151445.51500-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": "<20200826151445.51500-26-cristian.dumitrescu@intel.com>", "list_archive_url": "https://inbox.dpdk.org/dev/20200826151445.51500-26-cristian.dumitrescu@intel.com", "date": "2020-08-26T15:14:30", "name": "[25/40] pipeline: introduce 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/20200826151445.51500-26-cristian.dumitrescu@intel.com/mbox/", "series": [ { "id": 11806, "url": "http://patches.dpdk.org/api/series/11806/?format=api", "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=11806", "date": "2020-08-26T15:14:05", "name": "Pipeline alignment with the P4 language", "version": 1, "mbox": "http://patches.dpdk.org/series/11806/mbox/" } ], "comments": "http://patches.dpdk.org/api/patches/76020/comments/", "check": "success", "checks": "http://patches.dpdk.org/api/patches/76020/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 20246A04B1;\n\tWed, 26 Aug 2020 17:20:47 +0200 (CEST)", "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 9A3241C1F2;\n\tWed, 26 Aug 2020 17:15:41 +0200 (CEST)", "from mga11.intel.com (mga11.intel.com [192.55.52.93])\n by dpdk.org (Postfix) with ESMTP id A23F41C0B4\n for <dev@dpdk.org>; Wed, 26 Aug 2020 17:15:13 +0200 (CEST)", "from orsmga004.jf.intel.com ([10.7.209.38])\n by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384;\n 26 Aug 2020 08:15:13 -0700", "from silpixa00400573.ir.intel.com (HELO\n silpixa00400573.ger.corp.intel.com) ([10.237.223.107])\n by orsmga004.jf.intel.com with ESMTP; 26 Aug 2020 08:15:11 -0700" ], "IronPort-SDR": [ "\n RToGsDJkAGbg+gUMhJNkTb7zkZ+89xpVR1s08eSJ9nENEielgcY5ABcVulEzBLyB/fezY3ZXEJ\n QzZrIT/Lh8zQ==", "\n p2A+uMhr5cjySuQvyhfUHl1v8q/g2kBClj9TqGhw3NmMQOD00o0S0hSYOEQn2lOyr0zKr04bWH\n ZTgj+OZGR4CA==" ], "X-IronPort-AV": [ "E=McAfee;i=\"6000,8403,9725\"; a=\"153879579\"", "E=Sophos;i=\"5.76,356,1592895600\"; d=\"scan'208\";a=\"153879579\"", "E=Sophos;i=\"5.76,356,1592895600\"; d=\"scan'208\";a=\"444081410\"" ], "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": "Wed, 26 Aug 2020 16:14:30 +0100", "Message-Id": "<20200826151445.51500-26-cristian.dumitrescu@intel.com>", "X-Mailer": "git-send-email 2.17.1", "In-Reply-To": "<20200826151445.51500-1-cristian.dumitrescu@intel.com>", "References": "<20200826151445.51500-1-cristian.dumitrescu@intel.com>", "Subject": "[dpdk-dev] [PATCH 25/40] pipeline: introduce 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 1fb3a24af..4eb1f4228 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": [ "25/40" ] }{ "id": 76020, "url": "