diff --git a/backends/ebpf/ebpfProgram.cpp b/backends/ebpf/ebpfProgram.cpp index 681b937e121..8f9eb6b6b81 100644 --- a/backends/ebpf/ebpfProgram.cpp +++ b/backends/ebpf/ebpfProgram.cpp @@ -196,6 +196,22 @@ void EBPFProgram::emitTypes(CodeBuilder *builder) { type->emit(builder); builder->newline(); } + if (const auto *method = d->to()) { + if (method->srcInfo.isValid()) { + continue; + } + // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already + // defined. + // TODO: Is there a more portable way to do this? Currently we check for a specific + // filename as the source of a method. + auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); + if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + continue; + } + EBPFMethodDeclaration methodInstance(method); + methodInstance.emit(builder); + builder->newline(); + } } } diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 10c12961eec..0dd0432a877 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -39,8 +39,10 @@ EBPFType *EBPFTypeFactory::create(const IR::Type *type) { auto canon = typeMap->getTypeType(type, true); result = create(canon); result = new EBPFTypeName(tn, result); - } else if (auto te = type->to()) { + } else if (const auto *te = type->to()) { result = new EBPFEnumType(te); + } else if (auto te = type->to()) { + result = new EBPFErrorType(te); } else if (auto ts = type->to()) { auto et = create(ts->elementType); if (et == nullptr) return nullptr; @@ -325,4 +327,54 @@ void EBPFEnumType::emit(EBPF::CodeBuilder *builder) { builder->blockEnd(true); } +//////////////////////////////////////////////////////////////// + +void EBPFErrorType::declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) { + builder->append("enum "); + builder->append(getType()->name); + if (asPointer) builder->append("*"); + builder->append(" "); + builder->append(id); +} + +void EBPFErrorType::declareInit(CodeBuilder *builder, cstring id, bool asPointer) { + declare(builder, id, asPointer); +} + +void EBPFErrorType::emit(EBPF::CodeBuilder *builder) { + builder->append("enum "); + auto et = getType(); + builder->append(et->name); + builder->blockStart(); + for (auto m : et->members) { + builder->append(m->name); + builder->appendLine(","); + } + builder->blockEnd(true); +} + +//////////////////////////////////////////////////////////////// + +EBPFMethodDeclaration::EBPFMethodDeclaration(const IR::Method *method) : method_(method) {} + +void EBPFMethodDeclaration::emit(CodeBuilder *builder) { + auto *returnType = EBPFTypeFactory::instance->create(method_->type->returnType); + returnType->emit(builder); + builder->append(" "); + builder->append(method_->name); + builder->append("("); + for (const auto *parameter : method_->getParameters()->parameters) { + if (parameter->direction == IR::Direction::None || + parameter->direction == IR::Direction::In) { + builder->append("const "); + } + auto *type = EBPFTypeFactory::instance->create(parameter->type); + type->declare(builder, parameter->name, false); + if (parameter != method_->getParameters()->parameters.back()) { + builder->append(", "); + } + } + builder->append(");"); +} + } // namespace EBPF diff --git a/backends/ebpf/ebpfType.h b/backends/ebpf/ebpfType.h index 6af9a9cdbc5..703738b59ad 100644 --- a/backends/ebpf/ebpfType.h +++ b/backends/ebpf/ebpfType.h @@ -194,6 +194,35 @@ class EBPFEnumType : public EBPFType, public EBPF::IHasWidth { DECLARE_TYPEINFO(EBPFEnumType, EBPFType, IHasWidth); }; +class EBPFErrorType : public EBPFType, public EBPF::IHasWidth { + public: + explicit EBPFErrorType(const IR::Type_Error *type) : EBPFType(type) {} + void emit(CodeBuilder *builder) override; + void declare(CodeBuilder *builder, cstring id, bool asPointer) override; + void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; + void emitInitializer(CodeBuilder *builder) override { builder->append("0"); } + unsigned widthInBits() const override { return 32; } + unsigned implementationWidthInBits() const override { return 32; } + const IR::Type_Error *getType() const { return type->to(); } + + DECLARE_TYPEINFO(EBPFErrorType, EBPFType, IHasWidth); +}; + +/// Methods are function signatures. +class EBPFMethodDeclaration : public EBPFObject { + private: + /// The underlying P4 method of this declaration. + const IR::Method *method_; + + public: + explicit EBPFMethodDeclaration(const IR::Method *method); + + /// Emit the signature declaration of this method in C-style form. + void emit(CodeBuilder *builder); + + DECLARE_TYPEINFO(EBPFMethodDeclaration, EBPFObject); +}; + } // namespace EBPF #endif /* BACKENDS_EBPF_EBPFTYPE_H_ */ diff --git a/backends/ubpf/ubpfProgram.cpp b/backends/ubpf/ubpfProgram.cpp index 2c365485947..a40d97c987e 100644 --- a/backends/ubpf/ubpfProgram.cpp +++ b/backends/ubpf/ubpfProgram.cpp @@ -169,6 +169,22 @@ void UBPFProgram::emitTypes(EBPF::CodeBuilder *builder) { type->emit(builder); builder->newline(); } + if (const auto *method = d->to()) { + if (!method->srcInfo.isValid()) { + continue; + } + // Ignore methods originating from core.p4 and ubpf_model.p4 because they are already + // defined. + // TODO: Is there a more portable way to do this? Currently we check for a specific + // filename as the source of a method. + auto sourceName = std::filesystem::path(method->srcInfo.getSourceFile().c_str()); + if (sourceName.filename() == "core.p4" || sourceName.filename() == "ubpf_model.p4") { + continue; + } + EBPF::EBPFMethodDeclaration methodInstance(method); + methodInstance.emit(builder); + builder->newline(); + } } } diff --git a/backends/ubpf/ubpfType.cpp b/backends/ubpf/ubpfType.cpp index 3049fac6e1d..b5641d8ba3f 100644 --- a/backends/ubpf/ubpfType.cpp +++ b/backends/ubpf/ubpfType.cpp @@ -41,6 +41,8 @@ EBPF::EBPFType *UBPFTypeFactory::create(const IR::Type *type) { result = new EBPF::EBPFTypeName(tn, result); } else if (auto te = type->to()) { result = new UBPFEnumType(te); + } else if (auto te = type->to()) { + result = new UBPFErrorType(te); } else if (auto ts = type->to()) { auto et = create(ts->elementType); if (et == nullptr) return nullptr; @@ -155,6 +157,7 @@ void UBPFStructType::declare(EBPF::CodeBuilder *builder, cstring id, bool asPoin void UBPFStructType::declareInit(EBPF::CodeBuilder *builder, cstring id, bool asPointer) { declare(builder, id, asPointer); } + ////////////////////////////////////////////////////////// void UBPFEnumType::emit(EBPF::CodeBuilder *builder) { @@ -172,6 +175,21 @@ void UBPFEnumType::emit(EBPF::CodeBuilder *builder) { ////////////////////////////////////////////////////////// +void UBPFErrorType::emit(EBPF::CodeBuilder *builder) { + builder->append("enum "); + auto et = getType(); + builder->append(et->name); + builder->blockStart(); + for (auto m : et->members) { + builder->append(m->name); + builder->appendLine(","); + } + builder->blockEnd(false); + builder->endOfStatement(true); +} + +////////////////////////////////////////////////////////// + UBPFListType::UBPFListType(const IR::Type_List *lst) : EBPFType(lst) { kind = "struct"; width = 0; diff --git a/backends/ubpf/ubpfType.h b/backends/ubpf/ubpfType.h index 9e0ae406d83..aada218a8eb 100644 --- a/backends/ubpf/ubpfType.h +++ b/backends/ubpf/ubpfType.h @@ -58,6 +58,20 @@ class UBPFScalarType : public EBPF::EBPFScalarType { DECLARE_TYPEINFO(UBPFScalarType, EBPF::EBPFScalarType); }; +class UBPFExternType : public EBPF::EBPFScalarType { + public: + explicit UBPFExternType(const IR::Type_Bits *bits) : EBPF::EBPFScalarType(bits) {} + + void emit(EBPF::CodeBuilder *builder) override; + + cstring getAsString(); + + void declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override; + void declareInit(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override; + + DECLARE_TYPEINFO(UBPFExternType, EBPF::EBPFScalarType); +}; + class UBPFStructType : public EBPF::EBPFStructType { public: explicit UBPFStructType(const IR::Type_StructLike *strct) : EBPF::EBPFStructType(strct) {} @@ -77,6 +91,15 @@ class UBPFEnumType : public EBPF::EBPFEnumType { DECLARE_TYPEINFO(UBPFEnumType, EBPF::EBPFEnumType); }; +class UBPFErrorType : public EBPF::EBPFErrorType { + public: + explicit UBPFErrorType(const IR::Type_Error *strct) : EBPF::EBPFErrorType(strct) {} + + void emit(EBPF::CodeBuilder *builder) override; + + DECLARE_TYPEINFO(UBPFErrorType, EBPF::EBPFErrorType); +}; + class UBPFListType : public EBPF::EBPFType, public EBPF::IHasWidth { class UBPFListElement : public ICastable { public: