diff --git a/include/p4mlir/Dialect/P4HIR/P4HIR_Ops.td b/include/p4mlir/Dialect/P4HIR/P4HIR_Ops.td
index c7c24f8..bfe1cf5 100644
--- a/include/p4mlir/Dialect/P4HIR/P4HIR_Ops.td
+++ b/include/p4mlir/Dialect/P4HIR/P4HIR_Ops.td
@@ -132,7 +132,7 @@ def LoadOp : P4HIR_Op<"load", [
let arguments = (ins Arg:$ref);
// FIXME: Constraint result type
- let results = (outs AnyP4Type:$result);
+ let results = (outs LoadableP4Type:$result);
let assemblyFormat = [{
$ref `:` qualified(type($ref)) `,` type($result) attr-dict
@@ -160,7 +160,7 @@ def StoreOp : P4HIR_Op<"store", [
```
}];
- let arguments = (ins AnyP4Type:$value,
+ let arguments = (ins LoadableP4Type:$value,
Arg:$ref);
diff --git a/include/p4mlir/Dialect/P4HIR/P4HIR_Types.td b/include/p4mlir/Dialect/P4HIR/P4HIR_Types.td
index 206581e..1cca5de 100644
--- a/include/p4mlir/Dialect/P4HIR/P4HIR_Types.td
+++ b/include/p4mlir/Dialect/P4HIR/P4HIR_Types.td
@@ -135,5 +135,6 @@ def ReferenceType : P4HIR_Type<"Reference", "ref"> {
def AnyP4Type : AnyTypeOf<[BitsType, BooleanType, InfIntType,
DontcareType, ErrorType, UnknownType]> {}
+def LoadableP4Type : AnyTypeOf<[BitsType, BooleanType, InfIntType]> {}
#endif // P4MLIR_DIALECT_P4HIR_P4HIR_TYPES_TD
diff --git a/test/Translate/Ops/variables.p4 b/test/Translate/Ops/variables.p4
new file mode 100644
index 0000000..15c37b6
--- /dev/null
+++ b/test/Translate/Ops/variables.p4
@@ -0,0 +1,46 @@
+// RUN: p4mlir-translate --typeinference-only %s | FileCheck %s
+
+// NOTE: Assertions have been autogenerated by utils/generate-test-checks.py
+
+// Adopted from spec-ex04.p4
+
+action foo() {
+ bit<32> b0 = 32w0xFF; // a 32-bit bit-string with value 00FF
+ int<32> b2 = 32s0xFF; // a 32-bit signed number with value 255
+ int<32> b3 = -32s0xFF; // a 32-bit signed number with value -255
+ bit<8> b4 = 8w0b10101010; // an 8-bit bit-string with value AA
+ bit<8> b5 = 8w0b_1010_1010; // same value as above
+ bit<8> b6 = 8w170; // same value as above
+ bit<8> b7 = 8w0b1010_1010; // an 8-bit unsigned number with value 170
+ // FIXME: Implement casts and path resolution
+ // int<8> b8 = (int<8>)b7;
+ int<42> b9;
+ bit<8> b10 = b7;
+}
+
+// CHECK-LABEL: module
+// CHECK-NEXT: %[[VAL_0:.*]] = p4hir.const #p4hir.int<255> : !p4hir.bit<32>
+// CHECK: %[[VAL_1:.*]] = p4hir.alloca !p4hir.bit<32> ["b0", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_0]], %[[VAL_1]] : !p4hir.bit<32>, !p4hir.ref>
+// CHECK: %[[VAL_2:.*]] = p4hir.const #p4hir.int<255> : !p4hir.int<32>
+// CHECK: %[[VAL_3:.*]] = p4hir.alloca !p4hir.int<32> ["b2", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_2]], %[[VAL_3]] : !p4hir.int<32>, !p4hir.ref>
+// CHECK: %[[VAL_4:.*]] = p4hir.const #p4hir.int<-255> : !p4hir.int<32>
+// CHECK: %[[VAL_5:.*]] = p4hir.alloca !p4hir.int<32> ["b3", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_4]], %[[VAL_5]] : !p4hir.int<32>, !p4hir.ref>
+// CHECK: %[[VAL_6:.*]] = p4hir.const #p4hir.int<170> : !p4hir.bit<8>
+// CHECK: %[[VAL_7:.*]] = p4hir.alloca !p4hir.bit<8> ["b4", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_6]], %[[VAL_7]] : !p4hir.bit<8>, !p4hir.ref>
+// CHECK: %[[VAL_8:.*]] = p4hir.const #p4hir.int<170> : !p4hir.bit<8>
+// CHECK: %[[VAL_9:.*]] = p4hir.alloca !p4hir.bit<8> ["b5", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_8]], %[[VAL_9]] : !p4hir.bit<8>, !p4hir.ref>
+// CHECK: %[[VAL_10:.*]] = p4hir.const #p4hir.int<170> : !p4hir.bit<8>
+// CHECK: %[[VAL_11:.*]] = p4hir.alloca !p4hir.bit<8> ["b6", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_10]], %[[VAL_11]] : !p4hir.bit<8>, !p4hir.ref>
+// CHECK: %[[VAL_12:.*]] = p4hir.const #p4hir.int<170> : !p4hir.bit<8>
+// CHECK: %[[VAL_13:.*]] = p4hir.alloca !p4hir.bit<8> ["b7", init] : !p4hir.ref>
+// CHECK: p4hir.store %[[VAL_12]], %[[VAL_13]] : !p4hir.bit<8>, !p4hir.ref>
+// CHECK: %[[VAL_14:.*]] = p4hir.alloca !p4hir.int<42> ["b9"] : !p4hir.ref>
+// CHECK: %[[VAL_15:.*]] = p4hir.alloca !p4hir.bit<8> ["b10", init] : !p4hir.ref>
+// CHECK: %[[VAL_16:.*]] = p4hir.load %[[VAL_13]] : !p4hir.ref>, !p4hir.bit<8>
+// CHECK: p4hir.store %[[VAL_16]], %[[VAL_15]] : !p4hir.bit<8>, !p4hir.ref>
diff --git a/tools/p4mlir-translate/translate.cpp b/tools/p4mlir-translate/translate.cpp
index 357b7e8..08837f9 100644
--- a/tools/p4mlir-translate/translate.cpp
+++ b/tools/p4mlir-translate/translate.cpp
@@ -108,9 +108,16 @@ class P4HIRConverter : public P4::Inspector, public P4::ResolutionContext {
const P4::TypeMap *typeMap = nullptr;
llvm::DenseMap p4Types;
+ // TODO: Implement unified constant map
+ // using CTVOrExpr = std::variant;
+ // llvm::DenseMap p4Constants;
llvm::DenseMap p4Constants;
llvm::DenseMap p4Values;
+ mlir::TypedAttr resolveConstant(const P4::IR::CompileTimeValue *ctv);
+ mlir::TypedAttr resolveConstantExpr(const P4::IR::Expression *expr);
+
public:
P4HIRConverter(mlir::OpBuilder &builder, const P4::TypeMap *typeMap)
: builder(builder), typeMap(typeMap) {
@@ -134,28 +141,80 @@ class P4HIRConverter : public P4::Inspector, public P4::ResolutionContext {
return getOrCreateType(expr->type);
}
- mlir::TypedAttr resolveConstant(const P4::IR::Expression *expr);
+ mlir::Type getOrCreateType(const P4::IR::Declaration_Variable *decl) {
+ auto declType = getOrCreateType(decl->type);
+ return P4HIR::ReferenceType::get(builder.getContext(), declType);
+ }
+
+ mlir::Value materializeConstantExpr(const P4::IR::Expression *expr);
- mlir::TypedAttr setConstant(const P4::IR::Expression *expr, mlir::TypedAttr attr) {
+ // TODO: Implement proper CompileTimeValue support
+ /*
+ mlir::TypedAttr setConstant(const P4::IR::CompileTimeValue *ctv, mlir::TypedAttr attr) {
+ auto [it, inserted] = p4Constants.try_emplace(ctv, attr);
+ BUG_CHECK(inserted, "duplicate conversion of %1%", ctv);
+ return it->second;
+ }
+ */
+
+ mlir::TypedAttr setConstantExpr(const P4::IR::Expression *expr, mlir::TypedAttr attr) {
auto [it, inserted] = p4Constants.try_emplace(expr, attr);
BUG_CHECK(inserted, "duplicate conversion of %1%", expr);
return it->second;
}
- mlir::TypedAttr getOrCreateConstant(const P4::IR::Expression *expr) {
+ // TODO: Implement proper CompileTimeValue support
+ /*
+ mlir::TypedAttr getOrCreateConstant(const P4::IR::CompileTimeValue *ctv) {
+ BUG_CHECK(!ctv->is(), "use getOrCreateConstantExpr() instead");
+ auto cst = p4Constants.lookup(ctv);
+ if (cst) return cst;
+
+ cst = resolveConstant(ctv);
+
+ BUG_CHECK(cst, "expected %1% to be converted as constant", ctv);
+ return cst;
+ }
+ */
+
+ mlir::TypedAttr getOrCreateConstantExpr(const P4::IR::Expression *expr) {
auto cst = p4Constants.lookup(expr);
if (cst) return cst;
- cst = resolveConstant(expr);
+ cst = resolveConstantExpr(expr);
BUG_CHECK(cst, "expected %1% to be converted as constant", expr);
return cst;
}
+ mlir::Value getValue(const P4::IR::Node *node) {
+ // If this is a PathExpression, resolve it
+ if (const auto *pe = node->to()) {
+ node = resolvePath(pe->path, false)->checkedTo();
+ }
+
+ if (const auto *decl = node->to()) {
+ // Getting value out of variable involves involves a load.
+ auto alloca = p4Values.lookup(decl);
+ BUG_CHECK(alloca, "expected %1% (aka %2%) to be converted", node, dbp(node));
+ return builder.create(getLoc(builder, node), alloca);
+ }
+
+ if (auto val = p4Values.lookup(node)) return val;
+
+ BUG("expected %1% (aka %2%) to be converted", node, dbp(node));
+ }
+
+ mlir::Value setValue(const P4::IR::Node *node, mlir::Value value) {
+ auto [it, inserted] = p4Values.try_emplace(node, value);
+ BUG_CHECK(inserted, "duplicate conversion of %1%", node);
+ return it->second;
+ }
+
mlir::MLIRContext *context() const { return builder.getContext(); }
bool preorder(const P4::IR::Node *node) override {
- ::P4::error("%1%: P4 construct not yet supported.", node);
+ ::P4::error("P4 construct not yet supported: %1% (aka %2%)", node, dbp(node));
return false;
}
@@ -167,28 +226,44 @@ class P4HIRConverter : public P4::Inspector, public P4::ResolutionContext {
}
bool preorder(const P4::IR::P4Program *) override { return true; }
- bool preorder(const P4::IR::Constant *c) override { return !p4Constants.contains(c); }
- bool preorder(const P4::IR::BoolLiteral *b) override { return !p4Constants.contains(b); }
+ bool preorder(const P4::IR::P4Action *a) override {
+ // TODO: For now simply visit every node of the body
+ visit(a->body);
+ return false;
+ }
+ bool preorder(const P4::IR::BlockStatement *block) override {
+ // TODO: For now simply visit every node of the block, create scope afterwards
+ visit(block->components);
+ return false;
+ }
+
+ bool preorder(const P4::IR::Constant *c) override {
+ materializeConstantExpr(c);
+ return false;
+ }
+ bool preorder(const P4::IR::BoolLiteral *b) override {
+ materializeConstantExpr(b);
+ return false;
+ }
+ bool preorder(const P4::IR::PathExpression *e) override {
+ // Should be resolved eslewhere
+ return false;
+ }
+
bool preorder(const P4::IR::Cast *cast) override {
// Cast could be used in constant initializers or as a separate
// operation. In former case resolve it to the constant
if (typeMap->isCompileTimeConstant(cast)) {
- resolveConstant(cast);
+ resolveConstantExpr(cast);
return false;
}
return true;
}
- bool preorder(const P4::IR::Declaration_Constant *decl) override {
- // We only should visit it once
- BUG_CHECK(!p4Values.contains(decl), "duplicate decl conversion %1%", decl);
- return true;
- }
- void postorder(const P4::IR::Constant *cst) override { resolveConstant(cst); }
+ bool preorder(const P4::IR::Declaration_Constant *decl) override;
- void postorder(const P4::IR::BoolLiteral *b) override { resolveConstant(b); }
-
- void postorder(const P4::IR::Declaration_Constant *decl) override;
+ bool preorder(const P4::IR::Declaration_Variable *) override { return true; }
+ void postorder(const P4::IR::Declaration_Variable *decl) override;
};
bool P4TypeConverter::preorder(const P4::IR::Type_Bits *type) {
@@ -237,8 +312,13 @@ bool P4TypeConverter::setType(const P4::IR::Type *type, mlir::Type mlirType) {
return false;
}
-mlir::TypedAttr P4HIRConverter::resolveConstant(const P4::IR::Expression *expr) {
- LOG4("Resolving " << dbp(expr) << " as constant");
+mlir::TypedAttr P4HIRConverter::resolveConstant(const P4::IR::CompileTimeValue *ctv) {
+ BUG("cannot resolve this constant yet %1%", ctv);
+}
+
+mlir::TypedAttr P4HIRConverter::resolveConstantExpr(const P4::IR::Expression *expr) {
+ LOG4("Resolving " << dbp(expr) << " as constant expression");
+
if (const auto *cst = expr->to()) {
auto type = getOrCreateType(cst->type);
mlir::APInt value;
@@ -248,45 +328,78 @@ mlir::TypedAttr P4HIRConverter::resolveConstant(const P4::IR::Expression *expr)
value = toAPInt(cst->value);
}
- return setConstant(cst, P4HIR::IntAttr::get(context(), type, value));
+ return setConstantExpr(expr, P4HIR::IntAttr::get(context(), type, value));
}
if (const auto *b = expr->to()) {
// FIXME: For some reason type inference uses `Type_Unknown` for BoolLiteral (sic!)
// auto type = mlir::cast(getOrCreateType(b->type));
auto type = P4HIR::BoolType::get(context());
- return setConstant(b, P4HIR::BoolAttr::get(context(), type, b->value));
+ return setConstantExpr(b, P4HIR::BoolAttr::get(context(), type, b->value));
}
if (const auto *cast = expr->to()) {
mlir::Type destType = getOrCreateType(cast);
mlir::Type srcType = getOrCreateType(cast->expr);
// Fold equal-type casts (e.g. due to typedefs)
- if (destType == srcType) return setConstant(expr, getOrCreateConstant(cast->expr));
+ if (destType == srcType) return setConstantExpr(expr, getOrCreateConstantExpr(cast->expr));
// Fold sign conversions
if (auto destBitsType = mlir::dyn_cast(destType)) {
if (auto srcBitsType = mlir::dyn_cast(srcType)) {
assert(destBitsType.getWidth() == srcBitsType.getWidth() &&
"expected signess conversion only");
- auto castee = mlir::cast(getOrCreateConstant(cast->expr));
- return setConstant(expr,
- P4HIR::IntAttr::get(context(), destBitsType, castee.getValue()));
+ auto castee = mlir::cast(getOrCreateConstantExpr(cast->expr));
+ return setConstantExpr(
+ expr, P4HIR::IntAttr::get(context(), destBitsType, castee.getValue()));
}
}
}
- BUG("cannot resolve this constant yet %1%", expr);
+ BUG("cannot resolve this constant expression yet %1%", expr);
}
-void P4HIRConverter::postorder(const P4::IR::Declaration_Constant *decl) {
+mlir::Value P4HIRConverter::materializeConstantExpr(const P4::IR::Expression *expr) {
+ LOG4("Materializing constant expression " << dbp(expr));
+ auto type = getOrCreateType(expr->type);
+ auto init = getOrCreateConstantExpr(expr);
+ auto loc = getLoc(builder, expr);
+
+ auto val = builder.create(loc, type, init);
+ return setValue(expr, val);
+}
+
+bool P4HIRConverter::preorder(const P4::IR::Declaration_Constant *decl) {
LOG4("Converting " << dbp(decl));
auto type = getOrCreateType(decl->type);
- auto init = getOrCreateConstant(decl->initializer);
+ auto init = getOrCreateConstantExpr(decl->initializer);
auto loc = getLoc(builder, decl);
auto val = builder.create(loc, type, init);
- auto [it, inserted] = p4Values.try_emplace(decl, val);
- BUG_CHECK(inserted, "duplicate conversion of %1%", decl);
+ setValue(decl, val);
+
+ return false;
+}
+
+void P4HIRConverter::postorder(const P4::IR::Declaration_Variable *decl) {
+ LOG4("Converting " << dbp(decl));
+ const auto *init = decl->initializer;
+ mlir::Type objectType;
+ if (init) objectType = getOrCreateType(init);
+ if (!objectType || mlir::isa(objectType))
+ objectType = getOrCreateType(decl->type);
+
+ auto type = getOrCreateType(decl);
+
+ // TODO: Choose better insertion point for alloca (entry BB or so)
+ auto alloca = builder.create(getLoc(builder, decl), type, objectType,
+ decl->name.string_view());
+
+ if (init) {
+ alloca.setInit(true);
+ builder.create(getLoc(builder, init), getValue(decl->initializer), alloca);
+ }
+
+ setValue(decl, alloca);
}
} // namespace