Skip to content

Commit bc10900

Browse files
committed
Add initial implementation for BMv2 headers and parsers
Signed-off-by: Pietro Ghiglio <[email protected]>
1 parent 81389a6 commit bc10900

File tree

17 files changed

+819
-10
lines changed

17 files changed

+819
-10
lines changed

include/p4mlir/Dialect/BMv2IR/BMv2IR_Attrs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99

1010
#include "llvm/ADT/APSInt.h"
1111
#include "mlir/IR/BuiltinAttributes.h"
12-
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Types.h"
1312

13+
// clang-format off
1414
#define GET_ATTRDEF_CLASSES
15+
#include "p4mlir/Dialect/BMv2IR/BMv2IR_EnumAttrs.h.inc"
1516
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Attrs.h.inc"
1617

1718
#endif // P4MLIR_DIALECT_BMv2IR_BMv2IR_ATTRS_H

include/p4mlir/Dialect/BMv2IR/BMv2IR_Attrs.td

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define P4MLIR_DIALECT_BMv2IR_BMv2IR_ATTRS_TD
33

44
include "mlir/IR/BuiltinAttributeInterfaces.td"
5+
include "mlir/IR/CommonAttrConstraints.td"
6+
include "mlir/IR/EnumAttr.td"
57

68
include "p4mlir/Dialect/BMv2IR/BMv2IR_Dialect.td"
79

@@ -10,4 +12,28 @@ class BMv2IR_Attr<string name, string attrMnemonic, list<Trait> traits = []>
1012
let mnemonic = attrMnemonic;
1113
}
1214

15+
def BMv2IR_ExtractKind : IntEnum<"ExtractKind",
16+
"BMv2 extract operation kind",
17+
[
18+
I32EnumAttrCase<"Regular", 0, "regular">,
19+
I32EnumAttrCase<"Stack", 1, "stack">,
20+
I32EnumAttrCase<"UnionStack", 2, "union_stack">
21+
], 32> {
22+
let cppNamespace = "P4::P4MLIR::BMv2IR";
23+
}
24+
25+
def BMv2IR_ExtractKindAttr : EnumAttr<BMv2IR_Dialect, BMv2IR_ExtractKind, "extract_kind">;
26+
27+
def BMv2IR_TransitionKind : IntEnum<"TransitionKind",
28+
"BMv2 extract operation kind",
29+
[
30+
I32EnumAttrCase<"Default", 0, "default">,
31+
I32EnumAttrCase<"Hexstr", 1, "hexstr">,
32+
I32EnumAttrCase<"Parse_vset", 2, "parse_vset">
33+
], 32> {
34+
let cppNamespace = "P4::P4MLIR::BMv2IR";
35+
}
36+
37+
def BMv2IR_TransitionKindAttr : EnumAttr<BMv2IR_Dialect, BMv2IR_TransitionKind, "transition_kind">;
38+
1339
#endif // P4MLIR_DIALECT_BMv2IR_BMv2IR_ATTRS_TD

include/p4mlir/Dialect/BMv2IR/BMv2IR_Dialect.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ def BMv2IR_Dialect : Dialect {
1818
}];
1919
let cppNamespace = "::P4::P4MLIR::BMv2IR";
2020

21+
let useDefaultTypePrinterParser = 1;
22+
let useDefaultAttributePrinterParser = 1;
23+
2124
let extraClassDeclaration = [{
2225
void registerAttributes();
2326
void registerTypes();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef P4MLIR_DIALECT_BMv2IR_BMv2IR_OPINTERFACES_H
2+
#define P4MLIR_DIALECT_BMv2IR_BMv2IR_OPINTERFACES_H
3+
4+
#include "mlir/IR/OpDefinition.h"
5+
#include "p4mlir/Dialect/BMv2IR/BMv2IR_OpInterfaces.h.inc"
6+
7+
#endif // P4MLIR_DIALECT_BMv2IR_BMv2IR_OPINTERFACES_H
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef BMv2IR_OP_INTERFACES_TD
2+
#define BMv2IR_OP_INTERFACES_TD
3+
4+
include "mlir/IR/OpBase.td"
5+
include "mlir/IR/Interfaces.td"
6+
7+
def AllowedTransitionKey : OpInterface<"AllowedTransitionKey"> {
8+
let description = [{
9+
Common interfaces for operations that could be used as transition keys
10+
}];
11+
let methods = [];
12+
13+
14+
let cppNamespace = "::P4::P4MLIR::BMv2IR";
15+
}
16+
17+
def AllowedParserOp : OpInterface<"AllowedParserOp"> {
18+
let description = [{
19+
Common interfaces for operations that could be used as parser ops
20+
}];
21+
let methods = [];
22+
23+
24+
let cppNamespace = "::P4::P4MLIR::BMv2IR";
25+
}
26+
27+
#endif

include/p4mlir/Dialect/BMv2IR/BMv2IR_Ops.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
#include "mlir/IR/BuiltinTypes.h"
1010
#include "mlir/IR/Dialect.h"
1111
#include "mlir/IR/OpDefinition.h"
12+
#include "mlir/IR/SymbolTable.h"
13+
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Attrs.h"
14+
#include "p4mlir/Dialect/BMv2IR/BMv2IR_OpInterfaces.h"
1215
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Types.h"
13-
1416
#define GET_OP_CLASSES
1517
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Ops.h.inc"
1618

include/p4mlir/Dialect/BMv2IR/BMv2IR_Ops.td

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
#define P4MLIR_DIALECT_BMv2IR_BMv2IR_OPS_TD
33

44
include "mlir/IR/OpBase.td"
5+
include "mlir/IR/SymbolInterfaces.td"
6+
57

68
include "p4mlir/Dialect/BMv2IR/BMv2IR_Dialect.td"
79
include "p4mlir/Dialect/BMv2IR/BMv2IR_Types.td"
10+
include "p4mlir/Dialect/BMv2IR/BMv2IR_Attrs.td"
11+
include "p4mlir/Dialect/BMv2IR/BMv2IR_OpInterfaces.td"
812

913
//===----------------------------------------------------------------------===//
1014
// Base BMv2IR operation definition.
@@ -13,4 +17,181 @@ include "p4mlir/Dialect/BMv2IR/BMv2IR_Types.td"
1317
class BMv2IR_Op<string mnemonic, list<Trait> traits = []> :
1418
Op<BMv2IR_Dialect, mnemonic, traits>;
1519

20+
def BMv2IR_ParserOp : BMv2IR_Op<"parser", [
21+
Symbol, SymbolTable,
22+
SingleBlock, NoTerminator
23+
]> {
24+
let summary = "P4 parser definition";
25+
let description = [{
26+
Represents a P4 parser with an initial state and a set of parse states.
27+
28+
Example:
29+
```mlir
30+
bmv2.parser @my_parser init_state @start {
31+
// parse states here
32+
}
33+
```
34+
}];
35+
36+
let arguments = (ins
37+
SymbolNameAttr:$sym_name,
38+
SymbolRefAttr:$init_state
39+
);
40+
41+
let regions = (region SizedRegion<1>:$body);
42+
43+
let assemblyFormat = [{
44+
$sym_name `init_state` $init_state $body attr-dict
45+
}];
46+
}
47+
48+
def BMv2IR_ParserStateOp : BMv2IR_Op<"state",
49+
[HasParent<"ParserOp">,
50+
Symbol, NoTerminator]> {
51+
let arguments = (ins
52+
SymbolNameAttr:$sym_name
53+
);
54+
let description = [{
55+
Represents a BMv2 parse state.
56+
The op has 3 regions, which match the JSON format for parse states:
57+
- parser_ops contains the operations performed by the state to parse the header
58+
- transition_keys contains the keys from select transitions
59+
- transitions contains the actual transitions
60+
}];
61+
62+
let regions = (region
63+
SizedRegion<1>:$parser_ops,
64+
SizedRegion<1>:$transitions,
65+
SizedRegion<1>:$transition_keys);
66+
67+
let assemblyFormat = [{
68+
$sym_name
69+
`\n``transition_key` $transition_keys
70+
`\n``transitions` $transitions
71+
`\n``parser_ops` $parser_ops attr-dict
72+
}];
73+
74+
let hasVerifier = 1;
75+
}
76+
77+
def BMv2IR_TransitionOp : BMv2IR_Op<"transition", [HasParent<"ParserStateOp">]> {
78+
let summary = "Parser transition";
79+
let description = [{
80+
Represents a single transition from a parse state.
81+
82+
Types:
83+
- default: default transition (no value/mask)
84+
- hexstr: value-based transition with hexstring
85+
- parse_vset: parse value-set based transition
86+
87+
The value and mask are hexstrings in the format described in the BMv2 JSON
88+
spec (concatenation of byte-padded fields). For example, if the transition
89+
key has a 12-bit field and a 2-bit field, values use 3 bytes (0x0aba03).
90+
91+
`next_state` can be null for the last state in the parser.
92+
`value` is the hexstr value or vset name (null if default)
93+
`mask` is the mask (if needed) for the hexstr
94+
}];
95+
96+
// TODO: refine value and mask fields
97+
let arguments = (ins
98+
BMv2IR_TransitionKindAttr:$type,
99+
OptionalAttr<SymbolRefAttr>:$next_state,
100+
OptionalAttr<AnyAttr>:$value,
101+
OptionalAttr<AnyAttr>:$mask
102+
);
103+
104+
let assemblyFormat = "`type`$type (`value` $value^)? (`mask` $mask^)? (`next_state` $next_state^)? attr-dict";
105+
}
106+
107+
108+
def BMv2_ExtractOp : BMv2IR_Op<"extract", [HasParent<"ParserStateOp">, AllowedParserOp]> {
109+
let summary = "Extract header operation";
110+
let description = [{
111+
Extracts the field of a header instance, header stack, or union stack element.
112+
113+
Types:
114+
- regular: extraction to a regular header instance
115+
- stack: extraction to the end of a header stack
116+
- union_stack: extraction to the end of a header union stack
117+
}];
118+
119+
let arguments = (ins
120+
BMv2IR_ExtractKindAttr:$extract_type,
121+
StrAttr:$value,
122+
OptionalAttr<StrAttr>:$union_member
123+
);
124+
125+
let assemblyFormat = [{
126+
$extract_type $value (`union_member` $union_member^)? attr-dict
127+
}];
128+
}
129+
130+
//===-------------------------------------------------------------------------------------------===//
131+
// BMv2 type-value fields
132+
// see https://github.com/p4lang/behavioral-model/blob/main/docs/JSON_format.md#the-type-value-object
133+
//===-------------------------------------------------------------------------------------------===//
134+
135+
def BMv2IR_FieldOp : BMv2IR_Op<"field", [AllowedTransitionKey]> {
136+
let summary = "BMv2 header field access";
137+
let description = [{
138+
Represents access to a field within a header instance.
139+
Contains a 2-tuple: (header_instance_name, field_member_name)
140+
}];
141+
142+
let arguments = (ins
143+
StrAttr:$headerInstance,
144+
StrAttr:$fieldMember
145+
);
146+
147+
let assemblyFormat = "`<` $headerInstance `,` $fieldMember `>` attr-dict";
148+
}
149+
150+
def BMv2_StackFieldOp : BMv2IR_Op<"stack_field", [AllowedTransitionKey]> {
151+
let summary = "BMv2 header stack field access";
152+
let description = [{
153+
Represents access to a field in the last valid header instance in a stack.
154+
Contains a 2-tuple: (header_stack_name, field_member_name)
155+
}];
156+
157+
let arguments = (ins
158+
StrAttr:$headerStack,
159+
StrAttr:$fieldMember
160+
);
161+
162+
let assemblyFormat = "`<` $headerStack `,` $fieldMember `>` attr-dict";
163+
}
164+
165+
166+
def BMv2IR_LookaheadOp : BMv2IR_Op<"lookahead", [AllowedTransitionKey]> {
167+
let summary = "BMv2 parser lookahead";
168+
let description = [{
169+
Represents a lookahead operation in a parser.
170+
Contains a 2-tuple: (bit_offset, bitwidth)
171+
}];
172+
173+
let arguments = (ins
174+
I32Attr:$bitOffset,
175+
I32Attr:$bitwidth
176+
);
177+
178+
let assemblyFormat = "`<` $bitOffset `,` $bitwidth `>` attr-dict";
179+
}
180+
181+
def BMv2_UnionStackFieldOp : BMv2IR_Op<"union_stack_field", [AllowedTransitionKey]> {
182+
let summary = "BMv2 header union stack field access";
183+
let description = [{
184+
Represents access to a field in the last valid union instance in a stack.
185+
Contains a 3-tuple: (header_union_stack_name, union_member_name, field_member_name)
186+
}];
187+
188+
let arguments = (ins
189+
StrAttr:$headerUnionStack,
190+
StrAttr:$unionMember,
191+
StrAttr:$fieldMember
192+
);
193+
194+
let assemblyFormat = "`<` $headerUnionStack `,` $unionMember `,` $fieldMember `>` attr-dict";
195+
}
196+
16197
#endif // P4MLIR_DIALECT_BMv2IR_BMv2IR_OPS_TD

include/p4mlir/Dialect/BMv2IR/BMv2IR_Types.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,35 @@
33

44
// We explicitly do not use push / pop for diagnostic in
55
// order to propagate pragma further on
6+
#include "llvm/ADT/APFloat.h"
7+
#include "llvm/Support/raw_ostream.h"
8+
#include "mlir/IR/BuiltinAttributes.h"
69
#pragma GCC diagnostic ignored "-Wunused-parameter"
710

811
#include "mlir/IR/BuiltinTypes.h"
912

13+
namespace P4::P4MLIR::BMv2IR {
14+
15+
// Struct that models a header field info.
16+
struct FieldInfo {
17+
mlir::StringAttr name;
18+
mlir::Type type;
19+
20+
FieldInfo(mlir::StringAttr name, mlir::Type type) : name(name), type(type) {}
21+
22+
bool operator==(const FieldInfo &other) const {
23+
return name == other.name && type == other.type;
24+
}
25+
26+
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const FieldInfo &f) {
27+
return os << f.name.data() << ":" << f.type;
28+
}
29+
30+
friend llvm::hash_code hash_value(P4::P4MLIR::BMv2IR::FieldInfo f);
31+
};
32+
33+
} // namespace P4::P4MLIR::BMv2IR
34+
1035
#define GET_TYPEDEF_CLASSES
1136
#include "p4mlir/Dialect/BMv2IR/BMv2IR_Types.h.inc"
1237

include/p4mlir/Dialect/BMv2IR/BMv2IR_Types.td

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,47 @@ class BMv2IR_Type<string name, string typeMnemonic, list<Trait> traits = []>
1515
let mnemonic = typeMnemonic;
1616
}
1717

18+
// P4HeaderType represents a complete header type definition
19+
def BMv2_HeaderType : BMv2IR_Type<"Header", "header"> {
20+
let summary = "BMv2 header type";
21+
let description = [{
22+
Represents a P4 header according to the
23+
[BMv2 JSON spec](https://github.com/p4lang/behavioral-model/blob/main/docs/JSON_format.md#header_types)
24+
25+
The type encodes:
26+
- A unique name for the header type
27+
- An array of fields (name, bitwidth, optional signed flag)
28+
- Optional maximum length for variable-length headers
29+
30+
Variable-length fields are represented with bitwidth = -1.
31+
At most one field can be variable-length.
32+
}];
33+
34+
let parameters = (ins
35+
StringRefParameter<"struct name">:$name,
36+
ArrayRefParameter<"BMv2IR::FieldInfo", "struct fields">:$fields,
37+
OptionalParameter<"unsigned">:$max_length
38+
);
39+
40+
let assemblyFormat = [{
41+
`<` $name `,` `[` $fields `]`
42+
(`,` `max_length` `=` $max_length^)?
43+
`>`
44+
}];
45+
46+
let genVerifyDecl = 1;
47+
let skipDefaultBuilders = 1;
48+
let builders = [
49+
TypeBuilder<(ins "llvm::StringRef":$name, "llvm::ArrayRef<BMv2IR::FieldInfo>":$fields), [{
50+
return $_get($_ctxt, name, fields, computeMaxLength(fields));
51+
}]>,
52+
];
53+
54+
// Add verification for constraints
55+
let extraClassDeclaration = [{
56+
static unsigned computeMaxLength(llvm::ArrayRef<BMv2IR::FieldInfo>);
57+
static bool isAllowedFieldType(mlir::Type ty);
58+
}];
59+
}
60+
1861
#endif // P4MLIR_DIALECT_BMv2IR_BMv2IR_TYPES_TD

0 commit comments

Comments
 (0)