P4 Compiler 系列 — Midend

1 月 9, 2019

上一篇講述了 P4 IR 以及 Visitor 是如何運作的,本篇將講述如何把 Midend compiler 加入到自訂的 Compiler 當中。

在這個範例裡面,我們會定義一個新的 Midend,主要是用來在每一個 Table 加入 FTTID 這一個 annontation,舉例來說如果原先的 table 長這樣:

table tableA {
    key = {
        hdr.eth.ether_type: exact;
    }
    actions = {
        set_egress_port();
    }
}

經過 Midend 之後則會變成這樣:

@FTTID(0)
table tableA {
    key = {
        hdr.eth.ether_type: exact;
    }
    actions = {
        set_egress_port();
    }
}

當然,Midend 能做到的不只這樣,p4c 專案中帶有許多預設常用的 Midend 實作,例如將 Table 名稱修改成 Control+Table 名稱,或是將 if/else 簡化等等的。

詳細的 Midend 範例以及實作可以在這邊找到。

接下來是要實作一個 Midend 的 Class 讓我們的 Compiler 去使用。

Midend 可以是套用各種 Modifier 或是 Transformer,或是其他 Midend,這邊我們的 Midend 繼承 PassManager 並實作一個名為 HandleFttTableId 的 Modifier。

class FttMidEnd : public PassManager {
public:
    P4::ReferenceMap    refMap;
    P4::TypeMap         typeMap;
    IR::ToplevelBlock   *toplevel = nullptr;

    explicit FttMidEnd(CompilerOptions& options);
    IR::ToplevelBlock* process(const IR::P4Program *&program) {
        program = program->apply(*this);
        return toplevel;
    }
};

在 Midend 的建構子中,我們透過呼叫 addPasses 並帶入我們想要的 Visitor 或是 Modifier 等等的 Pass。

addPasses({
    new HandleFttTableId(),
    // ... other passes
    new P4::MidEndLast()
});

HandleFttTableId 的實作則是看起來像這樣:

bool HandleFttTableId::preorder(IR::P4Table* table) {
    IR::Annotations *annot = table->annotations->clone();
    annot->annotations.push_back(new IR::Annotation("FTTID", nextTableId));
    table->annotations = annot;
    nextTableId++;
    return true;
}

這個 Modifier 僅實作了 preorder function,在透過 preorder 走訪個 P4Table 節點時,會去在該 Table 的 Annotations 中多新增一個 FTTID 的 Annotation。

實際的實作可以參考本篇的範例

下一篇會講述如何去走訪 IR 並將其轉換成自定義的 binary format。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料