<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【從零開(kāi)始學(xué)深度學(xué)習(xí)編譯器】十八,MLIR中的Interfaces

          共 6819字,需瀏覽 14分鐘

           ·

          2022-01-11 00:51

          0x0. 前言

          這篇文章用來(lái)了解一下MLIR中的Interfaces(接口)。MLIR是一個(gè)通用可擴(kuò)展的框架,由不同層次的具有 特定屬性,Operation以及Type的Dialects構(gòu)成。正是由于Dialects的分層設(shè)計(jì), 使得MLIR可以表達(dá)多種語(yǔ)意和抽象級(jí)別的Operation。但這個(gè)分級(jí)設(shè)計(jì)也存在一個(gè)缺點(diǎn),那就是在不同的Dialect層次進(jìn)行Operation轉(zhuǎn)換或者做變換(Pass)的時(shí)候我們需要明確每個(gè)Dialect下的每個(gè)Operation的具體語(yǔ)意,否則就可能會(huì)轉(zhuǎn)換或變換失敗。其實(shí)基于MLIR開(kāi)發(fā)過(guò)的讀者應(yīng)該碰到過(guò)組合一些MLIR Pass對(duì)一個(gè)MLIR文件進(jìn)行Lower的時(shí)候,有可能出現(xiàn)Op轉(zhuǎn)換失敗的情況。為了緩解這種情況,MLIR提出了Interfaces。實(shí)際上在【從零開(kāi)始學(xué)深度學(xué)習(xí)編譯器】十三,如何在MLIR里面寫(xiě)Pass? 這里我們已經(jīng)利用過(guò)Interfaces來(lái)實(shí)現(xiàn)內(nèi)聯(lián)以及形狀推導(dǎo)Pass了。這一節(jié)就更深入的了解一下MLIR中的Interfaces,最后還結(jié)合了OneFlow IR中的UserOpCompatibleInterface例子來(lái)進(jìn)一步加深了解。

          ?

          本文提到的Operation和操作是一個(gè)東西,都是MLIR Dialect下的操作。

          ?

          0x1. 動(dòng)機(jī)

          Interfaces可以翻譯成接口,MLIR的Interfaces提供了和IR交互的通用方式。Interfaces的設(shè)計(jì)目標(biāo)是可以不用侵入到具體某個(gè)Dialect下的特定Operation和Dialect的特定知識(shí)就達(dá)到可以轉(zhuǎn)換和分析MLIR表達(dá)式。這樣就可以將轉(zhuǎn)換,分析和新增一個(gè)Dialect和對(duì)應(yīng)的Operation 進(jìn)行解耦,大大增強(qiáng)MLIR的可擴(kuò)展性。

          0x2. Dialect Interfaces定義(細(xì)看)

          Dialect Interfaces一般用在想對(duì)一組屬性,Operation,類型進(jìn)行通用的轉(zhuǎn)換(Pass)或者分析,這些屬性,Operation,類型可以是由不同的Dialect定義的。這些Interfaces一般會(huì)廣泛覆蓋各個(gè)級(jí)別的Dialects,僅用于少數(shù)分析和變換。因此,我們要明確Interface并不是Operation的核心,而是一些通用變換的核心。在【從零開(kāi)始學(xué)深度學(xué)習(xí)編譯器】十三,如何在MLIR里面寫(xiě)Pass? 這里有一個(gè)使用內(nèi)聯(lián)Interface實(shí)現(xiàn)內(nèi)聯(lián)Pass的例子。內(nèi)聯(lián)通常查詢的是有關(guān)Dialect中Operation的高級(jí)信息,例如cost modeling和合法性,而這些信息通常不特定于某個(gè)Dialect下的某個(gè)Operation單獨(dú)存在。

          Dialect Interface可以通過(guò)繼承一個(gè)CRTP基類DialectInterfaceBase::Base<>來(lái)進(jìn)行定義。CRTP的介紹可以參考:https://zh.wikipedia.org/wiki/奇異遞歸模板模式,我理解靜態(tài)多態(tài)(CRTP)是因?yàn)镸LIR里面會(huì)存在很多Dialect Interface要從這個(gè)DialectInterfaceBase::Base<>基類派生出來(lái),為了性能考慮用CRTP比較合適。這個(gè)基類提供了Dialect Interface注冊(cè)必須的一些接口,方便將來(lái)引用它們。當(dāng)Interface被定義之后,Dialects就可以使用Dialect特定信息去重寫(xiě)它。被一個(gè)Dialect定義的Interfaces通過(guò)addInterfaces<>進(jìn)行注冊(cè),和屬性,Operation,Type的注冊(cè)機(jī)制類似。下面舉一個(gè)栗子:

          //?定義一個(gè)基礎(chǔ)的內(nèi)聯(lián)Interface類以允許Dialect選擇加入內(nèi)聯(lián)。?
          class?DialectInlinerInterface?:
          ????public?DialectInterface::Base?{
          public:
          ??///?如果給定的區(qū)域?'src'?可以內(nèi)聯(lián)到該區(qū)域中,則返回 true。
          ??///?'dest'?附加到注冊(cè)到當(dāng)前Dialect的Operation上。?
          ??///?'valueMapping'?包含來(lái)自?'src'?區(qū)域內(nèi)的任何重新映射的值。?
          ??///?例如,這可用于檢查哪些值將替換“src”區(qū)域中的條目參數(shù)。?
          ??virtual?bool?isLegalToInline(Region?*dest,?Region?*src,
          ???????????????????????????????BlockAndValueMapping?&valueMapping)
          ?const?
          {
          ????return?false;
          ??}
          };

          ///?覆蓋內(nèi)聯(lián)接口以添加對(duì) AffineDialect 的支持以啟用內(nèi)聯(lián)Affine Dialect的Operation。?
          struct?AffineInlinerInterface?:?public?DialectInlinerInterface?{
          ??/// Affine結(jié)構(gòu)具有特定的內(nèi)聯(lián)約束。?
          ??bool?isLegalToInline(Region?*dest,?Region?*src,
          ???????????????????????BlockAndValueMapping?&valueMapping)
          ?const?final?
          {
          ????...
          ??}
          };

          ///?在Dialect下注冊(cè)內(nèi)聯(lián)Interfaces
          AffineDialect::AffineDialect(MLIRContext?*context)?...?{
          ??addInterfaces();
          }

          這些Interfaces被注冊(cè)之后,在執(zhí)行MLIR的變換和分析時(shí)就可以從Dialect中查到,并不需要確定特定的Dialect子類(如具體到某個(gè)Operation)。例如:

          Dialect?*dialect?=?...;
          if?(DialectInlinerInterface?*interface
          ??????=?dialect->getRegisteredInterface())?{
          ??//?Dialect提供了這個(gè)Interface的實(shí)現(xiàn)
          ??...
          }

          例如,在llvm/mlir/lib/IR/Dialect.cpp這個(gè)文件中的registerDelayedInterfaces函數(shù)就展示了上面這種用法,這個(gè)函數(shù)用于注冊(cè)加載進(jìn)來(lái)的Dialect的Interfaces:

          void?DialectRegistry::registerDelayedInterfaces(Dialect?*dialect)?const?{
          ??auto?it?=?interfaces.find(dialect->getTypeID());
          ??if?(it?==?interfaces.end())
          ????return;

          ??//?Add?an?interface?if?it?is?not?already?present.
          ??for?(const?auto?&kvp?:?it->getSecond().dialectInterfaces)?{
          ????if?(dialect->getRegisteredInterface(kvp.first))
          ??????continue;
          ????dialect->addInterface(kvp.second(dialect));
          ??}

          ??//?Add?attribute,?operation?and?type?interfaces.
          ??for?(const?auto?&info?:?it->getSecond().objectInterfaces)
          ????std::get<2>(info)(dialect->getContext());
          }

          0x3. DialectInterfaceCollection(選看,我還沒(méi)用過(guò))

          DialectInterfaceCollection提供了一個(gè)額外的實(shí)用程序。這個(gè)類允許收集已在 MLIRContext 實(shí)例中注冊(cè)給定Interface的所有Dialect。這對(duì)于隱藏和優(yōu)化已注冊(cè)Dialect Interface的查找很有用。

          class?InlinerInterface?:?public
          ????DialectInterfaceCollection?{
          ??//?此類的鉤子是DialectInlinerInterface的鉤子鏡像,默認(rèn)實(shí)現(xiàn)為調(diào)用給定Dialect上Interface上的鉤子。?
          ??virtual?bool?isLegalToInline(Region?*dest,?Region?*src,
          ???????????????????????????????BlockAndValueMapping?&valueMapping)
          ?const?
          {
          ????auto?*handler?=?getInterfaceFor(dest->getContainingOp());
          ????return?handler???handler->isLegalToInline(dest,?src,?valueMapping)?:?false;
          ??}
          };

          MLIRContext?*ctx?=?...;
          InlinerInterface?interface(ctx);
          if(!interface.isLegalToInline(...))
          ???...

          0x4. 屬性,操作,類型 Interfaces(選看)

          顧名思義,屬性/操作/類型Interface是在特定屬性/操作/類型級(jí)別注冊(cè)的那些。這些Interface 「通過(guò)提供」必須實(shí)現(xiàn)的虛接口來(lái)提供對(duì)派生對(duì)象的訪問(wèn)。例如,許多分析和轉(zhuǎn)換想要知道Operation的副作用以提高性能和正確性。Operation的副作用通常與特定Operation的語(yǔ)義相關(guān),例如 affine.load Operation具有讀取效果(顧名思義)。

          這些Interface是通過(guò)覆蓋特定 IR 實(shí)體的 CRTP 類來(lái)定義的;分別是 AttrInterface、OpInterfaceTypeInterface。這些類將定義ConceptModel類的 Traits 類作為模板參數(shù)。這些類提供了基于概念的多態(tài)性的實(shí)現(xiàn),其中Concept定義了一組虛方法,這些方法被在具體實(shí)體類型上模板化的Model覆蓋。需要注意的是,這些類應(yīng)該是純的,不應(yīng)包含非靜態(tài)數(shù)據(jù)成員或其他可變數(shù)據(jù)。為了將Interface附加到對(duì)象,基類提供了一個(gè)可以附加到該對(duì)象的特征列表的 Trait 類(跳過(guò)下面的示例代碼就可以看到解釋)。

          struct?ExampleOpInterfaceTraits?{
          ??///?定義一個(gè)基礎(chǔ)Concept類,指定要實(shí)現(xiàn)的虛擬接口。?
          ??struct?Concept?{
          ????virtual?~Concept();

          ????///?這是對(duì)Operation的非靜態(tài)鉤子的示例?
          ????virtual?unsigned?exampleInterfaceHook(Operation?*op)?const?=?0;

          ????///?這是Operation的靜態(tài)鉤子示例。?靜態(tài)鉤子不需要Operation的具體實(shí)例。?實(shí)現(xiàn)是一個(gè)虛擬的鉤子,和非靜態(tài)的情況一樣,因?yàn)殂^??子本身的實(shí)現(xiàn)還是需要間接實(shí)現(xiàn)的。?
          ????virtual?unsigned?exampleStaticInterfaceHook()?const?=?0;
          ??};

          ??///?為給定Operation類型的concept定義一個(gè)model類?
          ??template?<typename?ConcreteOp>
          ??struct?Model?:?public?Concept?{
          ????///?覆蓋要在具體Operation上分發(fā)的方法?
          ????unsigned?exampleInterfaceHook(Operation?*op)?const?final?{
          ??????return?llvm::cast(op).exampleInterfaceHook();
          ????}

          ????///?覆蓋要在具體Operation上分發(fā)的方法
          ????unsigned?exampleStaticInterfaceHook()?const?final?{
          ??????return?ConcreteOp::exampleStaticInterfaceHook();
          ????}
          ??};
          };

          ///?定義分析和轉(zhuǎn)換將與之交互的主Interface類。?
          class?ExampleOpInterface?:?public?OpInterface??????????????????????????????????????????????ExampleOpInterfaceTraits>?{
          public:
          ??///?繼承基類構(gòu)造函數(shù)以支持 LLVM 樣式的轉(zhuǎn)換。?
          ??using?OpInterface::OpInterface;

          ??/// Interface分發(fā)到`getImpl()`,這是一個(gè)由基本的`OpInterface`類提供的方法,它返回concept的一個(gè)實(shí)例。?
          ??unsigned?exampleInterfaceHook()?const?{
          ????return?getImpl()->exampleInterfaceHook(getOperation());
          ??}
          ??unsigned?exampleStaticInterfaceHook()?const?{
          ????return?getImpl()->exampleStaticInterfaceHook(getOperation()->getName());
          ??}
          };

          一旦定義了Interface,就可以通過(guò)添加提供的特征 ExampleOpInterface::Trait 將其注冊(cè)到操作中,如前所述。使用此接口就像使用任何其他派生操作類型,即強(qiáng)制轉(zhuǎn)換:


          ///?定義Operation時(shí),Interface通過(guò)`OpInterface<>`基類提供的嵌套`Trait`類進(jìn)行注冊(cè)。
          class?MyOp?:?public?Op?{
          public:
          ??///?The?definition?of?the?interface?method?on?the?derived?operation.
          ??unsigned?exampleInterfaceHook()?{?return?...;?}
          ??static?unsigned?exampleStaticInterfaceHook()?{?return?...;?}
          };

          ///?稍后,我們可以查詢特定Operation(如“MyOp”)是否覆蓋給定Interface。?
          Operation?*op?=?...;
          if?(ExampleOpInterface?example?=?dyn_cast(op))
          ??llvm::errs()?<"hook?returned?=?"?<"\n";

          如果你讀到這里并且看過(guò)之前在【從零開(kāi)始學(xué)深度學(xué)習(xí)編譯器】十三,如何在MLIR里面寫(xiě)Pass? 使用內(nèi)聯(lián)Interface的例子,相信可以更加理解在Toy Dialect下注冊(cè)內(nèi)聯(lián)Pass的幾個(gè)步驟。

          0x5. 屬性、操作和類型Interfaces的外部Model(選看)

          這可能需要為 IR 對(duì)象提供Interface實(shí)現(xiàn)而不修改所述對(duì)象的定義。值得注意的是,這允許在定義它們的Dialect之外實(shí)現(xiàn)屬性、操作和類型的Interface,例如,為built-in類型提供InterFace。這是通過(guò)使用兩個(gè)基于concept的多態(tài)性Model從 Concept 派生的擴(kuò)展類來(lái)實(shí)現(xiàn)的,如下所示(注意注釋):

          struct?ExampleTypeInterfaceTraits?{
          ??struct?Concept?{
          ????virtual?unsigned?exampleInterfaceHook(Type?type)?const?=?0;
          ????virtual?unsigned?exampleStaticInterfaceHook()?const?=?0;
          ??};

          ??template?<typename?ConcreteType>
          ??struct?Model?:?public?Concept?{?/*...*/?};

          ??///?與?Model?不同,F(xiàn)allbackModel?將類型對(duì)象傳遞給
          ??///?鉤子,使其在方法體中可訪問(wèn),即使該方法未在類本身中定義,
          ??///?因此沒(méi)有“this”訪問(wèn)權(quán)限。ODS 自動(dòng)為所有Interfaces生成此類。?
          ??template?<typename?ConcreteType>
          ??struct?FallbackModel?:?public?Concept?{
          ????unsigned?exampleInterfaceHook(Type?type)?const?override?{
          ??????getImpl()->exampleInterfaceHook(type);
          ????}
          ????unsigned?exampleStaticInterfaceHook()?const?override?{
          ??????ConcreteType::exampleStaticInterfaceHook();
          ????}
          ??};

          ??///?`ExternalModel`?通過(guò)顯式地分離實(shí)現(xiàn)Interface的模型類和實(shí)現(xiàn)Interface的類型類,為Interface方法的默認(rèn)實(shí)現(xiàn)提供了一個(gè)位置。?然后可以使用?`cast`?定義默認(rèn)實(shí)現(xiàn)。?如果`ConcreteType`?沒(méi)有提供默認(rèn)實(shí)現(xiàn)所需的API,自定義實(shí)現(xiàn)可以直接使用`FallbackModel`?來(lái)覆蓋默認(rèn)實(shí)現(xiàn)。位于類模板中,它永遠(yuǎn)不會(huì)被實(shí)例化,也不會(huì)導(dǎo)致編譯錯(cuò)誤。ODS 自動(dòng)生成此類并將默認(rèn)方法實(shí)現(xiàn)放入其中。?
          ??template?<typename?ConcreteModel,?typename?ConcreteType>
          ??struct?ExternalModel?:?public?FallbackModel?{
          ????unsigned?exampleInterfaceHook(Type?type)?const?override?{
          ??????//?Default?implementation?can?be?provided?here.
          ??????return?type.cast().callSomeTypeSpecificMethod();
          ????}
          ??};
          };

          通過(guò)派生 FallbackModeExternalModel 并通過(guò)在給定context中向相關(guān)類注冊(cè)Model類,可以為屬性、操作和類型接口提供外部Models。除非注冊(cè),否則其它c(diǎn)ontext將看不到該Interface。例如:

          ///?具體類的外部Interface實(shí)現(xiàn)。?這不需要修改類型類本身的定義。?
          struct?ExternalModelExample
          ????:
          ?public?ExampleTypeInterface::ExternalModel?????????????????????????????????????????????????IntegerType>?{
          ??static?unsigned?exampleStaticInterfaceHook()?{
          ????//?實(shí)現(xiàn)被提供在這里
          ????return?IntegerType::someStaticMethod();
          ??}
          ??//?無(wú)需定義在“ExternalModel”中具有默認(rèn)實(shí)現(xiàn)的“exampleInterfaceHook”。?但如果需要,它可以被覆蓋。?
          }

          int?main()?{
          ??MLIRContext?context;
          ??/*?...?*/;

          ??//?在使用之前,將interface model附加到給定context中的類型。?預(yù)計(jì)此時(shí)已加載包含該類型的Dialect。?
          ??IntegerType::attachInterface(context);
          }

          文檔最后還提出了一個(gè)建議,即當(dāng)我們“擁有”外部應(yīng)用的Interface時(shí)才使用此機(jī)制。這可以防止包含對(duì)象的Dialect的所有者和interface的所有者都不知道Interface實(shí)現(xiàn)的情況,這可能導(dǎo)致重復(fù)或發(fā)散的實(shí)現(xiàn)。還沒(méi)有碰到過(guò)需要使用這種機(jī)制的情況,這里不繼續(xù)深入了。

          0x6. OpInterface的Dialect Fallback(選看)

          一些Dialects有一個(gè)開(kāi)放的生態(tài)系統(tǒng),并沒(méi)有注冊(cè)所有可能的Operation。在這種情況下,仍然可以為實(shí)現(xiàn)這些操作的 OpInterface 提供支持。當(dāng)操作未注冊(cè)或未提供Interface實(shí)現(xiàn)時(shí),查詢將fallback到Dialect本身。

          第二種Model用于此類情況,并在ODS使用名為 FallbackModel(見(jiàn)下文)時(shí)自動(dòng)生成??梢詾樘囟ǚ窖詫?shí)現(xiàn)此Model:

          //?This?is?the?implementation?of?a?dialect?fallback?for?`ExampleOpInterface`.
          struct?FallbackExampleOpInterface
          ????:
          ?public?ExampleOpInterface::FallbackModel<
          ??????????FallbackExampleOpInterface>?{
          ??static?bool?classof(Operation?*op)?{?return?true;?}

          ??unsigned?exampleInterfaceHook(Operation?*op)?const;
          ??unsigned?exampleStaticInterfaceHook()?const;
          };

          然后,Dialect可以實(shí)例化此實(shí)現(xiàn),并通過(guò)覆蓋 getRegisteredInterfaceForOp 方法在特定Operation上返回它:

          void?*TestDialect::getRegisteredInterfaceForOp(TypeID?typeID,
          ???????????????????????????????????????????????StringAttr?opName)
          ?
          {
          ??if?(typeID?==?TypeID::get())?{
          ????if?(isSupported(opName))
          ??????return?fallbackExampleOpInterface;
          ????return?nullptr;
          ??}
          ??return?nullptr;
          }

          這一節(jié)也不是很懂,先記錄著吧。通過(guò)上面對(duì)Interfaces的介紹,我們能留下一些基礎(chǔ)的印象我覺(jué)得應(yīng)該就夠了,接下來(lái)要講的是如何基于ODS去定義Interfaces,這才是我們這篇文章的重點(diǎn)。

          0x7. 利用ODS框架定義Interface(重要)

          如上所述,Interface允許屬性、Operation和Type 暴露調(diào)用方法,而無(wú)需調(diào)用者知道特定的派生類型。這種基礎(chǔ)設(shè)施的缺點(diǎn)是它需要一些樣板才能將所有部分連接在一起。MLIR 提供了一種機(jī)制,用于在 ODS 中以聲明方式定義接口,并自動(dòng)生成 C++ 定義。舉個(gè)栗子:

          def?ExampleOpInterface?:?OpInterface<"ExampleOpInterface">?{
          ??let?description?=?[{
          ????This?is?an?example?interface?definition.
          ??}];

          ??let?methods?=?[
          ????InterfaceMethod<
          ??????"This?is?an?example?of?a?non-static?hook?to?an?operation.",
          ??????"unsigned",?"exampleInterfaceHook"
          ????>,
          ????StaticInterfaceMethod<
          ??????"This?is?an?example?of?a?static?hook?to?an?operation.",
          ??????"unsigned",?"exampleStaticInterfaceHook"
          ????>,
          ??];
          }

          提供 AttrInterfaceOpInterfaceTypeInterface 類的定義將自動(dòng)生成接口的 C++ 類。接口由以下組件組成:

          • C++ 類名(通過(guò)模板參數(shù)提供) 。
          • 描述。(description)。
          • C++ Namespace。(cppNamespace)。即Interface類應(yīng)該產(chǎn)生在哪個(gè)C++名稱空間下。
          • Methods(methods)。由 IR 對(duì)象定義的Interfaces鉤子方法列表。
          • Extra Class Declarations。可選的:extraClassDeclaration。在Interface類的聲明中生成的附加 C++ 代碼。這允許在面向用戶的Interface類上定義方法等,不需要鉤到 IR 實(shí)體。這些聲明在接口方法的默認(rèn)實(shí)現(xiàn)中不是隱式可見(jiàn)的,但可以使用全名限定訪問(wèn)靜態(tài)聲明。

          OpInterface類可能還額外包含Verifier(verify)。它是一個(gè)包含附加驗(yàn)證的 C++ 代碼塊應(yīng)用于Interface所附加的Operation。此代碼塊的結(jié)構(gòu)與 Trait::verifyTrait 方法的結(jié)構(gòu) 1-1 對(duì)應(yīng)。

          有兩種類型的方法可以與Interface一起使用,InterfaceMethodStaticInterfaceMethod。它們都由相同的核心組件組成,區(qū)別在于 StaticInterfaceMethod 為派生的 IR 對(duì)象上的靜態(tài)方法建模。Interface 方法有以下組件:

          • Description:方法的描述信息,一個(gè)字符串。
          • ReturnType:與方法的 C++ 返回類型對(duì)應(yīng)的字符串。
          • MethodName:與方法的 C++ 名稱對(duì)應(yīng)的字符串。
          • Arguments (Optional):分別對(duì)應(yīng)于 C++ 類型和變量名稱的字符串。
          • MethodBody (Optional)和DefaultImplementation。暫沒(méi)有用到,以后有需要再查。

          如果Operation使用 DeclareOpInterfaceMethods 指定Interface,則 ODS 還允許為Operation的 InterfaceMethods 生成聲明(請(qǐng)參見(jiàn)下面的示例)。

          ef?MyInterface?:?OpInterface<"MyInterface">?{
          ??let?description?=?[{
          ????This?is?the?description?of?the?interface.?It?provides?concrete?information
          ????on?the?semantics?of?the?interface,?and?how?it?may?be?used?by?the?compiler.
          ??}];

          ??let?methods?=?[
          ????InterfaceMethod<[{
          ??????This?method?represents?a?simple?non-static?interface?method?with?no
          ??????inputs,?and?a?void?return?type.?This?method?is?required?to?be?implemented
          ??????by?all?operations?implementing?this?interface.?This?method?roughly
          ??????correlates?to?the?following?on?an?operation?implementing?this?interface:

          ??????```c++
          ??????class?ConcreteOp?...?{
          ??????public:
          ????????void?nonStaticMethod();
          ??????};
          ??????```
          ????}],?"void",?"nonStaticMethod"
          ????>,

          ????InterfaceMethod<[{
          ??????This?method?represents?a?non-static?interface?method?with?a?non-void
          ??????return?value,?as?well?as?an?`unsigned`?input?named?`i`.?This?method?is
          ??????required?to?be?implemented?by?all?operations?implementing?this?interface.
          ??????This?method?roughly?correlates?to?the?following?on?an?operation
          ??????implementing?this?interface:

          ??????```c++
          ??????class?ConcreteOp?...?{
          ??????public:
          ????????Value?nonStaticMethod(unsigned?i);
          ??????};
          ??????```
          ????}],?"Value",?"nonStaticMethodWithParams",?(ins?"unsigned":$i)
          ????>,

          ????StaticInterfaceMethod<[{
          ??????This?method?represents?a?static?interface?method?with?no?inputs,?and?a
          ??????void?return?type.?This?method?is?required?to?be?implemented?by?all
          ??????operations?implementing?this?interface.?This?method?roughly?correlates
          ??????to?the?following?on?an?operation?implementing?this?interface:

          ??????```c++
          ??????class?ConcreteOp?...?{
          ??????public:
          ????????static?void?staticMethod();
          ??????};
          ??????```
          ????}],?"void",?"staticMethod"
          ????>,

          ????StaticInterfaceMethod<[{
          ??????This?method?corresponds?to?a?static?interface?method?that?has?an?explicit
          ??????implementation?of?the?method?body.?Given?that?the?method?body?has?been
          ??????explicitly?implemented,?this?method?should?not?be?defined?by?the?operation
          ??????implementing?this?method.?This?method?merely?takes?advantage?of?properties
          ??????already?available?on?the?operation,?in?this?case?its?`build`?methods.?This
          ??????method?roughly?correlates?to?the?following?on?the?interface?`Model`?class:

          ??????```c++
          ??????struct?InterfaceTraits?{
          ????????///?...?The?`Concept`?class?is?elided?here?...

          ????????template?<typename?ConcreteOp>
          ????????struct?Model?:?public?Concept?{
          ??????????Operation?*create(OpBuilder?&builder,?Location?loc)?const?override?{
          ????????????return?builder.create(loc);
          ??????????}
          ????????}
          ??????};
          ??????```

          ??????Note?above?how?no?modification?is?required?for?operations?implementing?an
          ??????interface?with?this?method.
          ????}],
          ??????"Operation?*",?"create",?(ins?"OpBuilder?&":$builder,?"Location":$loc),
          ??????/*methodBody=*/[{
          ????????return?builder.create(loc);
          ????}]>,

          ????InterfaceMethod<[{
          ??????This?method?represents?a?non-static?method?that?has?an?explicit
          ??????implementation?of?the?method?body.?Given?that?the?method?body?has?been
          ??????explicitly?implemented,?this?method?should?not?be?defined?by?the?operation
          ??????implementing?this?method.?This?method?merely?takes?advantage?of?properties
          ??????already?available?on?the?operation,?in?this?case?its?`build`?methods.?This
          ??????method?roughly?correlates?to?the?following?on?the?interface?`Model`?class:

          ??????```c++
          ??????struct?InterfaceTraits?{
          ????????///?...?The?`Concept`?class?is?elided?here?...

          ????????template?<typename?ConcreteOp>
          ????????struct?Model?:?public?Concept?{
          ??????????Operation?*create(Operation?*opaqueOp,?OpBuilder?&builder,
          ????????????????????????????Location?loc)
          ?const?override?
          {
          ????????????ConcreteOp?op?=?cast(opaqueOp);
          ????????????return?op.getNumInputs()?+?op.getNumOutputs();
          ??????????}
          ????????}
          ??????};
          ??????```

          ??????Note?above?how?no?modification?is?required?for?operations?implementing?an
          ??????interface?with?this?method.
          ????}],
          ??????"unsigned",?"getNumInputsAndOutputs",?(ins),?/*methodBody=*/[{
          ????????return?$_op.getNumInputs()?+?$_op.getNumOutputs();
          ????}]>,

          ????InterfaceMethod<[{
          ??????This?method?represents?a?non-static?method?that?has?a?default
          ??????implementation?of?the?method?body.?This?means?that?the?implementation
          ??????defined?here?will?be?placed?in?the?trait?class?that?is?attached?to?every
          ??????operation?that?implements?this?interface.?This?has?no?effect?on?the
          ??????generated?`Concept`?and?`Model`?class.?This?method?roughly?correlates?to
          ??????the?following?on?the?interface?`Trait`?class:


          ??????```c++
          ??????template?<typename?ConcreteOp>
          ??????class?MyTrait?:?public?OpTrait::TraitBase?{
          ??????public:
          ????????bool?isSafeToTransform()?{
          ??????????ConcreteOp?op?=?cast(this->getOperation());
          ??????????return?op.getNumInputs()?+?op.getNumOutputs();
          ????????}
          ??????};
          ??????```

          ??????As?detailed?in?[Traits](Traits.md),?given?that?each?operation?implementing
          ??????this?interface?will?also?add?the?interface?trait,?the?methods?on?this
          ??????interface?are?inherited?by?the?derived?operation.?This?allows?for
          ??????injecting?a?default?implementation?of?this?method?into?each?operation?that
          ??????implements?this?interface,?without?changing?the?interface?class?itself.?If
          ??????an?operation?wants?to?override?this?default?implementation,?it?merely
          ??????needs?to?implement?the?method?and?the?derived?implementation?will?be
          ??????picked?up?transparently?by?the?interface?class.

          ??????```c++
          ??????class?ConcreteOp?...?{

          ??????public:
          ????????bool?isSafeToTransform()?{
          ??????????//?Here?we?can?override?the?default?implementation?of?the?hook
          ??????????//?provided?by?the?trait.
          ????????}
          ??????};
          ??????```
          ????}],
          ??????"bool",?"isSafeToTransform",?(ins),?/*methodBody=*/[{}],
          ??????/*defaultImplementation=*/[{
          ????}]>,
          ??];
          }

          //?Operation?interfaces?can?optionally?be?wrapped?inside
          //?DeclareOpInterfaceMethods.?This?would?result?in?autogenerating?declarations
          //?for?members?`foo`,?`bar`?and?`fooStatic`.?Methods?with?bodies?are?not
          //?declared?inside?the?op?declaration?but?instead?handled?by?the?op?interface
          //?trait?directly.
          def?OpWithInferTypeInterfaceOp?:?Op<...
          ????[DeclareOpInterfaceMethods]>?{?...?}

          //?Methods?that?have?a?default?implementation?do?not?have?declarations
          //?generated.?If?an?operation?wishes?to?override?the?default?behavior,?it?can
          //?explicitly?specify?the?method?that?it?wishes?to?override.?This?will?force
          //?the?generation?of?a?declaration?for?those?methods.
          def?OpWithOverrideInferTypeInterfaceOp?:?Op<...
          ????[DeclareOpInterfaceMethods"getNumWithDefault"]>]>?{?...?}

          注意:在 ODS 框架中可以通過(guò) OpInterfaceTrait 類訪問(wèn) C++ 中定義的現(xiàn)有Operation接口。

          0x8. Operation Interface列表

          MLIR包括提供可能在許多不同Operation中通用的功能的標(biāo)準(zhǔn)Interface。下面是一些可以被任何方言直接使用的關(guān)鍵Interface的列表。每個(gè)Interface部分的標(biāo)題格式如下:

          • Interface class name
            • (C++ classODS class(if applicable))

          標(biāo)準(zhǔn)Interface截圖如下:

          MLIR的標(biāo)準(zhǔn)Interface類型

          0x9. OneFlow的Interface

          接下來(lái)我們以O(shè)neFlow IR為例,來(lái)看一下OneFlow Dialect中定義了哪些Interface。代碼在:oneflow/ir/include/OneFlow/OneFlowInterfaces.td 這里。OneFlow基于ODS定義了UserOpCompatibleInterface,ControlEdgeCompatibleInterfaceNoGrad 等Interface類型。我們以UserOpCompatibleInterface為例來(lái)看一下它的實(shí)現(xiàn):

          def?UserOpCompatibleInterface?:?OpInterface<"UserOpCompatible">?{
          ??let?description?=?[{
          ????Interface?to?getting?the?hard-coded?bn
          ??}];

          ??let?methods?=?[
          ????StaticInterfaceMethod<"",
          ????????"const?std::vector*",?"inputKeys",?(ins),?[{
          ????????static?std::vector<std::string>?val(mlir::oneflow::support::GetInputKeys(ConcreteOp::getOperationName().split('.').second.str()));
          ????????return?&val;
          ????}]>,
          ????StaticInterfaceMethod<"",
          ????????"const?std::vector*",?"outputKeys",?(ins),?[{
          ????????static?std::vector<std::string>?val(mlir::oneflow::support::GetOutputKeys(ConcreteOp::getOperationName().split('.').second.str()));
          ????????return?&val;
          ????}]>,
          ????InterfaceMethod<"",
          ????????"std::pair",?"getODSOperandIndexAndLength",?(ins?"unsigned":$index),?[{
          ????????return?$_op.getODSOperandIndexAndLength(index);
          ????}]>,
          ????InterfaceMethod<"",
          ????????"std::pair",?"getODSResultIndexAndLength",?(ins?"unsigned":$index),?[{
          ????????return?$_op.getODSResultIndexAndLength(index);
          ????}]>
          ??];
          }

          可以看到UserOpCompatibleInterface使用第7節(jié)Interface ODS規(guī)范中的StaticInterfaceMethod和InterfaceMethod為這個(gè)Interface指定了獲取Operation輸入操作數(shù)名字,輸出操作數(shù)名字,操作數(shù)以及長(zhǎng)度,結(jié)果以及長(zhǎng)度等方法。然后在OneFlow的oneflow/ir/include/OneFlow/OneFlowUserOps.td中使用DeclareOpInterfaceMethods來(lái)為各種Operation指定Interface,在生成的Operation代碼中就會(huì)帶上這個(gè)Interface聲明。

          那么這樣做有什么好處嗎?第一點(diǎn)就是由于OneFlow的UserOp都帶上了UserOpCompatibleInterface,只要我們?yōu)镺neFlow的UserOp實(shí)現(xiàn)一個(gè)通用的GetInputKeys函數(shù),那么所有UserOp派生出來(lái)的Operation都擁有了這個(gè)函數(shù)的功能,因?yàn)樗鼈兌紟狭薝serOpCompatibleInterface這個(gè)接口。

          更加通用的例子是基于InterFace來(lái)開(kāi)發(fā)一些通用Pass,比如內(nèi)聯(lián)和形狀推導(dǎo)Pass。見(jiàn)【從零開(kāi)始學(xué)深度學(xué)習(xí)編譯器】十三,如何在MLIR里面寫(xiě)Pass?

          0x10. 總結(jié)

          這篇文章主要介紹了一下MLIR的Interface,在MLIR文檔的基礎(chǔ)上添加了一些自己的理解和描述,以及展示了OneFlow的一個(gè)例子,以此來(lái)說(shuō)明Interface的好處以及如何使用ODS來(lái)寫(xiě)Interface。


          瀏覽 75
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜操穴 | 国产成年人黄色大香蕉 | 亚洲黄色小视频 | 在线观看免费无码 | 欧美大屌操B |