Skip to content

Commit 0e992a5

Browse files
committed
Implement BMv2IR parser to JSON translation
Signed-off-by: devalgupta404 <devalgupta4@gmail.com>
1 parent 0fb8d01 commit 0e992a5

File tree

2 files changed

+81
-82
lines changed

2 files changed

+81
-82
lines changed

lib/Targets/BMv2/Target.cpp

Lines changed: 62 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,22 @@ using namespace P4::P4MLIR;
1515

1616
namespace {
1717

18+
/// Convert an MLIR attribute to its JSON string representation
19+
static std::string attrToJsonString(mlir::Attribute attr) {
20+
std::string result;
21+
llvm::raw_string_ostream os(result);
22+
attr.print(os);
23+
return os.str();
24+
}
25+
26+
/// Serialize parser operation to BMv2 JSON (extract: regular, stack, union_stack).
1827
static llvm::json::Object serializeParserOp(Operation *op) {
1928
llvm::json::Object opJson;
20-
29+
2130
if (auto extractOp = dyn_cast<BMv2IR::ExtractOp>(op)) {
2231
opJson["op"] = "extract";
23-
llvm::json::Array parameters;
2432
llvm::json::Object param;
25-
33+
2634
auto extractKind = extractOp.getExtractType();
2735
if (extractKind == BMv2IR::ExtractKind::Regular) {
2836
param["type"] = "regular";
@@ -38,17 +46,19 @@ static llvm::json::Object serializeParserOp(Operation *op) {
3846
unionValue.push_back(extractOp.getUnionMember()->str());
3947
param["value"] = std::move(unionValue);
4048
}
41-
49+
50+
llvm::json::Array parameters;
4251
parameters.push_back(std::move(param));
4352
opJson["parameters"] = std::move(parameters);
4453
}
45-
54+
4655
return opJson;
4756
}
4857

58+
/// Serialize transition key to BMv2 JSON (field, lookahead, stack_field, union_stack_field).
4959
static llvm::json::Object serializeTransitionKey(Operation *op) {
5060
llvm::json::Object keyJson;
51-
61+
5262
if (auto fieldOp = dyn_cast<BMv2IR::FieldOp>(op)) {
5363
keyJson["type"] = "field";
5464
llvm::json::Array value;
@@ -75,124 +85,113 @@ static llvm::json::Object serializeTransitionKey(Operation *op) {
7585
value.push_back(unionStackFieldOp.getFieldMember().str());
7686
keyJson["value"] = std::move(value);
7787
}
78-
88+
7989
return keyJson;
8090
}
8191

92+
/// Serialize parser state transition to BMv2 JSON (default, hexstr, parse_vset).
8293
static llvm::json::Object serializeTransition(BMv2IR::TransitionOp transitionOp) {
8394
llvm::json::Object transJson;
84-
95+
8596
auto kind = transitionOp.getType();
8697
if (kind == BMv2IR::TransitionKind::Default) {
8798
transJson["type"] = "default";
8899
transJson["value"] = nullptr;
89100
transJson["mask"] = nullptr;
90101
} else if (kind == BMv2IR::TransitionKind::Hexstr) {
91102
transJson["type"] = "hexstr";
92-
if (transitionOp.getValue()) {
93-
std::string valueStr;
94-
llvm::raw_string_ostream os(valueStr);
95-
transitionOp.getValue()->print(os);
96-
transJson["value"] = os.str();
97-
} else {
98-
transJson["value"] = nullptr;
99-
}
100-
if (transitionOp.getMask()) {
101-
std::string maskStr;
102-
llvm::raw_string_ostream os(maskStr);
103-
transitionOp.getMask()->print(os);
104-
transJson["mask"] = os.str();
105-
} else {
106-
transJson["mask"] = nullptr;
107-
}
103+
transJson["value"] = transitionOp.getValue()
104+
? llvm::json::Value(attrToJsonString(*transitionOp.getValue()))
105+
: llvm::json::Value(nullptr);
106+
transJson["mask"] = transitionOp.getMask()
107+
? llvm::json::Value(attrToJsonString(*transitionOp.getMask()))
108+
: llvm::json::Value(nullptr);
108109
} else if (kind == BMv2IR::TransitionKind::Parse_vset) {
109110
transJson["type"] = "parse_vset";
110-
if (transitionOp.getValue()) {
111-
std::string valueStr;
112-
llvm::raw_string_ostream os(valueStr);
113-
transitionOp.getValue()->print(os);
114-
transJson["value"] = os.str();
115-
} else {
116-
transJson["value"] = nullptr;
117-
}
111+
transJson["value"] = transitionOp.getValue()
112+
? llvm::json::Value(attrToJsonString(*transitionOp.getValue()))
113+
: llvm::json::Value(nullptr);
118114
transJson["mask"] = nullptr;
119115
}
120-
121-
if (transitionOp.getNextState()) {
122-
auto nextState = transitionOp.getNextState()->getLeafReference().str();
123-
transJson["next_state"] = nextState;
124-
} else {
125-
transJson["next_state"] = nullptr;
126-
}
127-
116+
117+
// Set next_state: use state name or null for end of parsing
118+
transJson["next_state"] = transitionOp.getNextState()
119+
? llvm::json::Value(transitionOp.getNextState()->getLeafReference().str())
120+
: llvm::json::Value(nullptr);
121+
128122
return transJson;
129123
}
130124

125+
/// Serialize parser state to BMv2 JSON with operations, transition keys, and transitions.
131126
static llvm::json::Object serializeParserState(BMv2IR::ParserStateOp stateOp, int stateId) {
132127
llvm::json::Object stateJson;
133128
stateJson["name"] = stateOp.getSymName().str();
134129
stateJson["id"] = stateId;
135130

131+
// Serialize parser operations (e.g., extract header fields)
136132
llvm::json::Array parserOps;
137133
for (auto &op : stateOp.getParserOps().front()) {
138-
if (!isa<BMv2IR::ExtractOp>(&op)) continue;
139-
parserOps.push_back(serializeParserOp(&op));
134+
if (isa<BMv2IR::ExtractOp>(&op))
135+
parserOps.push_back(serializeParserOp(&op));
140136
}
141137
stateJson["parser_ops"] = std::move(parserOps);
142138

139+
// Serialize transition keys (fields used to determine next state)
143140
llvm::json::Array transitionKeys;
144141
for (auto &op : stateOp.getTransitionKeys().front()) {
145-
if (isa<BMv2IR::FieldOp, BMv2IR::LookaheadOp,
146-
BMv2IR::StackFieldOp, BMv2IR::UnionStackFieldOp>(&op)) {
142+
if (isa<BMv2IR::FieldOp, BMv2IR::LookaheadOp,
143+
BMv2IR::StackFieldOp, BMv2IR::UnionStackFieldOp>(&op))
147144
transitionKeys.push_back(serializeTransitionKey(&op));
148-
}
149145
}
150146
stateJson["transition_key"] = std::move(transitionKeys);
151-
147+
148+
// Serialize state transitions
152149
llvm::json::Array transitions;
153150
for (auto &op : stateOp.getTransitions().front()) {
154-
if (auto transOp = dyn_cast<BMv2IR::TransitionOp>(&op)) {
151+
if (auto transOp = dyn_cast<BMv2IR::TransitionOp>(&op))
155152
transitions.push_back(serializeTransition(transOp));
156-
}
157153
}
158154
stateJson["transitions"] = std::move(transitions);
159-
155+
160156
return stateJson;
161157
}
162158

159+
/// Serialize complete parser to BMv2 JSON with initial state and parse states.
163160
static llvm::json::Object serializeParser(BMv2IR::ParserOp parserOp, int parserId) {
164-
llvm::json::Object parserJson;
165-
parserJson["name"] = parserOp.getSymName().str();
166-
parserJson["id"] = parserId;
167-
parserJson["init_state"] = parserOp.getInitState().getLeafReference().str();
168-
161+
// Collect all parse states
169162
llvm::json::Array parseStates;
170163
int stateId = 0;
171164
for (auto &op : parserOp.getBody().front()) {
172-
if (auto stateOp = dyn_cast<BMv2IR::ParserStateOp>(&op)) {
165+
if (auto stateOp = dyn_cast<BMv2IR::ParserStateOp>(&op))
173166
parseStates.push_back(serializeParserState(stateOp, stateId++));
174-
}
175167
}
168+
169+
// Build parser JSON object
170+
llvm::json::Object parserJson;
171+
parserJson["name"] = parserOp.getSymName().str();
172+
parserJson["id"] = parserId;
173+
parserJson["init_state"] = parserOp.getInitState().getLeafReference().str();
176174
parserJson["parse_states"] = std::move(parseStates);
177-
175+
178176
return parserJson;
179177
}
180178

181-
}
179+
} // namespace
182180

181+
/// Convert BMv2IR module to BMv2 JSON. Currently supports parsers only.
183182
mlir::FailureOr<llvm::json::Value> P4::P4MLIR::bmv2irToJson(ModuleOp moduleOp) {
184-
llvm::json::Object rootJson;
185183
llvm::json::Array parsers;
186184

185+
// Collect all parsers from the module
187186
int parserId = 0;
188187
for (auto &op : moduleOp.getBody()->getOperations()) {
189-
if (auto parserOp = dyn_cast<BMv2IR::ParserOp>(&op)) {
188+
if (auto parserOp = dyn_cast<BMv2IR::ParserOp>(&op))
190189
parsers.push_back(serializeParser(parserOp, parserId++));
191-
}
192190
}
193-
191+
192+
llvm::json::Object rootJson;
194193
rootJson["parsers"] = std::move(parsers);
195-
194+
196195
return llvm::json::Value(std::move(rootJson));
197196
}
198197

test/Targets/BMv2/parser_json.mlir

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,41 @@
11
// RUN: p4mlir-to-json --p4hir-to-bmv2-json %s | FileCheck %s
22

33
module {
4-
// CHECK: "parsers"
5-
// CHECK: "name": "test_parser"
6-
// CHECK: "id": 0
7-
// CHECK: "init_state": "test_parser::@start"
8-
// CHECK: "parse_states"
9-
4+
// CHECK: "parsers":[{
5+
// CHECK: "id":0
6+
// CHECK: "init_state":"start"
7+
// CHECK: "name":"test_parser"
8+
// CHECK: "parse_states":[
9+
1010
bmv2ir.parser @test_parser init_state @start {
11-
// CHECK: "name": "start"
12-
// CHECK: "id": 0
13-
// CHECK: "parser_ops"
14-
// CHECK: "op": "extract"
15-
// CHECK: "type": "regular"
16-
// CHECK: "value": "hdr"
11+
// CHECK: "id":0
12+
// CHECK: "name":"start"
13+
// CHECK: "parser_ops":[
14+
// CHECK: "op":"extract"
15+
// CHECK: "type":"regular"
16+
// CHECK: "value":"hdr"
1717
bmv2ir.state @start
1818
transition_key {
1919
^bb0:
2020
}
2121
transitions {
22-
// CHECK: "type": "default"
23-
// CHECK: "next_state": "accept"
22+
// CHECK: "next_state":"accept"
23+
// CHECK: "type":"default"
2424
bmv2ir.transition type default next_state @accept
2525
}
2626
parser_ops {
2727
bmv2ir.extract regular "hdr"
2828
}
29-
30-
// CHECK: "name": "accept"
31-
// CHECK: "id": 1
29+
30+
// CHECK: "id":1
31+
// CHECK: "name":"accept"
3232
bmv2ir.state @accept
3333
transition_key {
3434
^bb0:
3535
}
3636
transitions {
37-
// CHECK: "type": "default"
38-
// CHECK: "next_state": null
37+
// CHECK: "next_state":null
38+
// CHECK: "type":"default"
3939
bmv2ir.transition type default
4040
}
4141
parser_ops {

0 commit comments

Comments
 (0)