MLIR에서 데이터 레이아웃 정보를 모델링하고 질의하는 방법을 설명한다. 스코프, 호환성, 질의 흐름, 확장 가능한 인터페이스(DLTI, 명세/항목/연산/타입/타깃)와 기본 구현(내장 모듈/타입, 바이트 크기, DLTI 방언)을 다룬다.
데이터 레이아웃 정보는 특정 타입의 값이 메모리에 어떻게 저장되는지와 관련된 질문(예: 값의 크기나 주소 정렬 요구사항)에 답할 수 있게 한다. 이를 통해 추상 타입 컨테이너에 대한 다양한 선형 메모리 주소 지정 방식 생성, 벡터에 대한 더 깊은 추론 등을 가능하게 한다.
데이터 레이아웃 서브시스템은 MLIR의 개방형 타입/연산 시스템으로 확장 가능하도록 설계되었다. 최상위 수준에서 다음으로 구성된다.
내장 타입은 전체 질의 비용을 줄이기 위해 특별 취급된다. 마찬가지로, 내장 ModuleOp은 인터페이스를 거치지 않고도 데이터 레이아웃을 지원한다.
MLIR의 중첩 구조를 따르며, 데이터 레이아웃 속성은 DataLayoutOpInterface를 구현하는 연산 또는 ModuleOp 연산에 속한 리전에 스코프(scope)된다. 이러한 스코핑 연산은 데이터 레이아웃 속성을 부분적으로 제어하며, 일반적으로 데이터 레이아웃 명세에 정리된 속성에 영향을 주는 애트리뷰트를 가질 수 있다.
타입은 서로 다른 스코프에서 서로 다른 데이터 레이아웃을 가질 수 있으며, 다른 모듈에 포함된 모듈처럼 스코프가 중첩될 수도 있다. 동시에, 주어진 스코프(중첩 스코프 제외) 내에서 특정 타입은 고정된 데이터 레이아웃 속성을 가진다. 또한 타입은 어떤 연산도 해당 타입에 대한 데이터 레이아웃 스코프를 제공하지 않는 경우에도 사용될 수 있도록 기본적이고 “자연스러운” 데이터 레이아웃을 가져야 한다. 이는 데이터 레이아웃 질의가 항상 유효한 결과를 갖도록 보장한다.
레이아웃 속성 계산에 필요한 정보는 중첩 스코프에서 결합될 수 있다. 예를 들어, 외부 스코프는 타입 부분집합에 대한 레이아웃 속성을 정의하고 내부 스코프는 그와 서로소인 부분집합에 대해 정의할 수 있으며, 혹은 스코프가 진행됨에 따라 특정 타입의 정렬 요구사항을 점진적으로 완화할 수도 있다. 이 메커니즘은 데이터 레이아웃의 “호환성” 개념으로 지원된다. 즉, 중첩 스코프에서 정의된 레이아웃은 외부 스코프의 레이아웃과 호환되어야 한다. MLIR은 특정 op나 타입에 대해 호환성이 무엇을 의미하는지 규정하지 않으며, 타깃 및 타입별 체크를 제공할 수 있는 훅을 제공한다. 예를 들어, 중첩 모듈에서 정렬 제약의 완화(즉, 더 작은 정렬)만 허용하게 하거나, 반대로 중첩 모듈이 외부 스코프의 모든 제약을 완전히 재정의하도록 요구할 수도 있다.
데이터 레이아웃 호환성은 IR 변환 중에도 중요하다. 데이터 레이아웃 스코핑 연산에 영향을 미치는 모든 변환은 데이터 레이아웃 호환성을 유지해야 한다. 실제로 그렇게 되는지 보장하는 책임은 해당 변환에 있다.
데이터 레이아웃 속성 질의는 특정 객체인 DataLayout에서 수행할 수 있으며, 이는 주어진 스코핑 연산에 대해 생성될 수 있다. 이 객체는 데이터 레이아웃 인프라와 상호작용하고 해당 객체의 스코프에서 특정 타입의 속성을 질의할 수 있게 한다. DataLayout 클래스의 시그니처는 다음과 같다.
class DataLayout {
public:
explicit DataLayout(DataLayoutOpInterface scope);
llvm::TypeSize getTypeSize(Type type) const;
llvm::TypeSize getTypeSizeInBits(Type type) const;
uint64_t getTypeABIAlignment(Type type) const;
uint64_t getTypePreferredAlignment(Type type) const;
std::optional<uint64_t> getTypeIndexBitwidth(Type type) const;
};
사용자는 관심 있는 스코프에 대해 DataLayout 객체를 구성할 수 있다. 데이터 레이아웃 속성은 스코프 내에서 고정되므로, 최초 요청 시 한 번만 계산되고 이후 사용을 위해 캐시된다. 따라서 DataLayout(op.getParentOfType<DataLayoutOpInterface>()).getTypeSize(type)처럼 사용 후 캐시를 버리는 방식은 안티패턴으로 간주된다. 캐싱 덕분에, DataLayout 객체는 상위 스코프의 데이터 레이아웃 속성이 동일하게 유지되는 한(즉, 조상 연산 중 데이터 레이아웃에 영향을 주는 방식으로 수정되지 않는 한) 유효한 결과를 반환한다. 그러한 수정 이후에는 사용자가 새로운 DataLayout 객체를 생성해야 한다. 이를 돕기 위해, MLIR을 애서션을 활성화하여 컴파일한 경우 DataLayout은 스코프가 동일하게 유지되는지 단언(assert)한다.
데이터 레이아웃 모델링의 확장성은 일련의 MLIR Interfaces를 통해 제공된다.
데이터 레이아웃 명세는 개념적으로 데이터 레이아웃 명세 “항목(entry)”이라 불리는 키-값 쌍의 모음인 애트리뷰트다. 데이터 레이아웃 명세 애트리뷰트는 아래에 설명된 DataLayoutSpecInterface를 구현한다. 각 항목은 자체적으로 DataLayoutEntryInterface를 구현하는 애트리뷰트다. 항목은 타입(Type) 또는 StringAttr 중 하나인 키와 값을 가진다. 키는 항목을 특정 타입이나 방언과 연관시키는 데 사용된다. 데이터 레이아웃 속성 요청을 처리할 때, 타입이나 방언은 자신과 관련된 명세 항목만 볼 수 있으며 재귀적 질의가 필요한 경우 반드시 제공된 DataLayout 객체를 통해 수행해야 한다. 이는 타입들이 다른 타입의 레이아웃 세부사항을 이해할 수 없고(또는 이해해서도 안 되므로) 더 나은 합성 가능성을 지원하고 강제한다. 항목 값은 임의의 애트리뷰트이며, 타입별로 구체적이다.
예를 들어, 데이터 레이아웃 명세는 다음과 같은 간단한 사용자 정의 문법을 가진 실제 쌍의 리스트일 수 있다.
#my_dialect.layout_spec<
#my_dialect.layout_entry<!my_dialect.type, size=42>,
#my_dialect.layout_entry<"my_dialect.endianness", "little">,
#my_dialect.layout_entry<!my_dialect.vector, prefer_large_alignment>>
명세와 항목 애트리뷰트의 구체적인 세부사항 및 문법은 구현에 달려 있다.
데이터 레이아웃 서브시스템 전반에서 “타입 클래스(type class)” 개념을 사용한다. 이는 주어진 타입의 C++ 클래스에 해당한다(예: 내장 정수의 경우 IntegerType). MLIR은 IR에서 타입 클래스를 표현하는 메커니즘을 제공하지 않는다. 대신, 데이터 레이아웃 항목은 예를 들어 IntegerType{signedness=signless, bitwidth=8}(IR에서는 i8) 또는 IntegerType{signedness=unsigned, bitwidth=32}(IR에서는 ui32)와 같이 특정 타입 클래스의 “인스턴스”를 포함한다. 데이터 레이아웃 속성 질의를 처리할 때, 타입 클래스는 이 타입 클래스에 속하는 키를 가진 “모든” 항목을 전달받는다. 예를 들어, IntegerType은 i8, si16, ui32에 대한 항목은 보지만 f32나 memref<?xi32>에 대한 항목은 보지 않는다(마찬가지로 MemRefType은 i32에 대한 항목을 보지 않는다). 이를 통해 타입 클래스는 다른 인스턴스의 속성을 바탕으로 임의의 특정 타입 인스턴스의 데이터 레이아웃 속성을 계산하는 타입별 “보간(interpolation)” 동작을 제공할 수 있다. 다시 정수 타입을 예로 들면, 정렬은 2의 거듭제곱 비트폭을 가진 그보다 크거나 같은 가장 가까운 정수 타입의 정렬을 취해 계산할 수 있다.
DLTIQueryInterface)¶키-값 연관을 위한 질의 메커니즘을 노출하는 애트리뷰트 인터페이스.
DLTI 애트리뷰트의 핵심 기능은 키에 대한 값 조회를 허용하는 것이다. 이 인터페이스는 그 핵심 기능을 표현하며, 대부분의 DLTI 애트리뷰트는 이 인터페이스를 구현해야 한다.
query 메서드는 애트리뷰트를 반환하므로, 반환된 애트리뷰트가 이 인터페이스를 구현한다면 재귀적으로 질의할 수 있다는 점에 유의한다.
query¶::mlir::FailureOr<::mlir::Attribute> query(::mlir::DataLayoutEntryKey key);
키에 연관된 애트리뷰트를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
DataLayoutEntryInterface)¶데이터 레이아웃 명세의 항목을 기술하는 애트리뷰트 인터페이스.
데이터 레이아웃 명세 항목은 키-값 쌍이다. 키는 항목이 타입 또는 타입 클래스와 관련될 때는 타입이고, 그렇지 않을 때는 식별자다. DataLayoutEntryKey는 두 종류의 키를 모두 사용할 수 있게 하는 별칭이다. 값은 임의의 애트리뷰트이며, 타입 키의 경우 해당 타입이, 식별자 키의 경우 해당 식별자를 포함하는 방언이 이를 해석한다. 이 인터페이스는 특정 구현이 특정 키에 대한 애트리뷰트의 적합성 검증을 관련 타입이나 방언으로 위임할 수 있도록 하는 훅을 제공한다.
getKey¶::mlir::DataLayoutEntryKey getKey();
이 레이아웃 항목의 키를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getValue¶::mlir::Attribute getValue();
이 레이아웃 항목의 값을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
verifyEntry¶::llvm::LogicalResult verifyEntry(::mlir::Location loc);
항목의 구성이 올바른지 확인하고, 제공된 위치에서 오류를 보고한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
DataLayoutSpecInterface)¶데이터 레이아웃 명세를 기술하는 애트리뷰트 인터페이스.
데이터 레이아웃 명세는 항목들의 시퀀스로 간주되며, 각 항목은 데이터 레이아웃 항목 인터페이스를 구현하는 애트리뷰트다. 항목에 대해 연속적인 내부 저장을 가정한다. 이 인터페이스는 구현체가 명세의 정합성을 검증할 수 있는 훅을 제공하며, 기본 구현은 중복 키가 없는지, 각 개별 항목이 올바르게 구성되어 있는지, 그리고 해당 항목이 연관된 타입 또는 방언에 대한 디스패치 전 검증을 수행한다.
데이터 레이아웃 명세는 레이아웃 대상인 중첩 연산에 나타나거나 레이아웃 수정의 유효성을 보장하기 위해 결합되어야 할 수 있다. 구체적인 명세 애트리뷰트는 해당 훅을 구현해야 한다.
combineWith¶::mlir::DataLayoutSpecInterface combineWith(::llvm::ArrayRef<::mlir::DataLayoutSpecInterface> specs);
현재 레이아웃을 주어진 레이아웃 리스트와 결합한다. 리스트는 가장 바깥쪽(오래된)에서 가장 안쪽(최신) 순으로 제공된다. 실패 시 null을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getEntries¶::mlir::DataLayoutEntryListRef getEntries();
레이아웃 항목의 리스트를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getEndiannessIdentifier¶::mlir::StringAttr getEndiannessIdentifier(::mlir::MLIRContext *context);
엔디언성 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getDefaultMemorySpaceIdentifier¶::mlir::StringAttr getDefaultMemorySpaceIdentifier(::mlir::MLIRContext *context);
기본 메모리 공간 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getAllocaMemorySpaceIdentifier¶::mlir::StringAttr getAllocaMemorySpaceIdentifier(::mlir::MLIRContext *context);
alloca 메모리 공간 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getProgramMemorySpaceIdentifier¶::mlir::StringAttr getProgramMemorySpaceIdentifier(::mlir::MLIRContext *context);
프로그램 메모리 공간 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getGlobalMemorySpaceIdentifier¶::mlir::StringAttr getGlobalMemorySpaceIdentifier(::mlir::MLIRContext *context);
글로벌 메모리 공간 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getManglingModeIdentifier¶::mlir::StringAttr getManglingModeIdentifier(::mlir::MLIRContext *context);
맹글링 모드 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getStackAlignmentIdentifier¶::mlir::StringAttr getStackAlignmentIdentifier(::mlir::MLIRContext *context);
스택 정렬 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getFunctionPointerAlignmentIdentifier¶::mlir::StringAttr getFunctionPointerAlignmentIdentifier(::mlir::MLIRContext *context);
함수 포인터 정렬 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getLegalIntWidthsIdentifier¶::mlir::StringAttr getLegalIntWidthsIdentifier(::mlir::MLIRContext *context);
허용 정수 폭 식별자를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getSpecForType¶::mlir::DataLayoutEntryList getSpecForType(::mlir::TypeID type);
타입 매개변수와 무관하게 특정 타입 클래스와 관련된 항목의 복사본을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getSpecForIdentifier¶::mlir::DataLayoutEntryInterface getSpecForIdentifier(::mlir::StringAttr identifier);
주어진 식별자와 관련된 항목이 존재하면 이를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
verifySpec¶::llvm::LogicalResult verifySpec(::mlir::Location loc);
명세의 유효성을 검증하고, 주어진 위치에서 모든 오류를 보고한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
TargetDeviceSpecInterface)¶타깃 장치 설명 명세를 기술하는 애트리뷰트 인터페이스.
타깃 장치 설명 명세는 특정 장치에 대해 장치 속성(키)과 그 값의 리스트다. 장치는 “device_id”(키 및 ui32 값)와 문자열 값을 가져야 하는 “device_type” 키로 식별된다. “device_id”와 “device_type”은 필수 키다. 예를 들어, L1 캐시 크기가 장치 속성이 될 수 있고, 그 값은 장치별 크기다.
타깃 장치 설명 명세는 모듈 수준 애트리뷰트로 모듈에 부착된다.
getEntries¶::mlir::DataLayoutEntryListRef getEntries();
레이아웃 항목의 리스트를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getSpecForIdentifier¶::mlir::DataLayoutEntryInterface getSpecForIdentifier(::mlir::StringAttr identifier);
주어진 식별자와 관련된 항목이 존재하면 이를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
verifyEntry¶::llvm::LogicalResult verifyEntry(::mlir::Location loc);
항목의 구성이 올바른지 확인하고, 제공된 위치에서 오류를 보고한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
TargetSystemSpecInterface)¶타깃 시스템 설명 명세를 기술하는 애트리뷰트 인터페이스.
타깃 시스템 설명 명세는 시스템 내 각 장치에 대해 하나의 장치 명세를 가지는 타깃 장치 명세의 리스트다. 따라서 이 명세를 사용하면 CPU, GPU 등 서로 다른 종류의 장치로 구성된 이기종 시스템을 기술할 수 있다.
유효한 타깃 시스템 설명 명세에 대한 유일한 요구사항은 각 타깃 장치 설명 명세의 “device_id”가 고유해야 한다는 것이다. 궁극적으로 이 “device_id”는 사용자가 장치 속성 값을 질의할 때 사용되기 때문이다.
getEntries¶::llvm::ArrayRef<DataLayoutEntryInterface> getEntries();
레이아웃 항목의 리스트를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getDeviceSpecForDeviceID¶std::optional<::mlir::TargetDeviceSpecInterface> getDeviceSpecForDeviceID(StringAttr deviceID);
주어진 장치 ID에 대한 장치 설명 명세를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
verifySpec¶::llvm::LogicalResult verifySpec(::mlir::Location loc);
명세의 유효성을 검증하고, 주어진 위치에서 모든 오류를 보고한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
데이터 레이아웃 질의의 스코프를 정의하고 DataLayout 객체를 만드는 데 사용할 수 있는 연산은 DataLayoutOpInterface를 구현해야 한다. 이러한 op는 최소한 데이터 레이아웃 명세를 얻는 방법을 제공해야 한다. 명세는 반드시 연산에 애트리뷰트로 부착될 필요는 없으며, 필요 시 즉시(on-the-fly) 구성될 수 있다. 이는 DataLayout 객체마다 한 번만 가져오며 캐시된다. 이러한 op는 또한 특정 타입으로 질의를 전달하지 않고 결과를 제공하거나, 타입이 반환한 결과를 타깃/스코프 특화 방식으로 후처리하는 데이터 레이아웃 질의에 대한 사용자 정의 핸들러를 제공할 수 있다. 이러한 사용자 정의 핸들러를 통해 스코핑 연산은 다른 방언에서 정의된 타입을 포함해 타입 자체를 수정하지 않고도 타입에 대한 데이터 레이아웃 속성을 (재)정의할 수 있다.
DataLayoutOpInterface)¶데이터 레이아웃 명세를 부착할 수 있는 연산을 위한 인터페이스.
데이터 레이아웃 질의에 사용할 수 있는 DataLayout 객체는 이러한 연산에 대해 구성될 수 있다. 데이터 레이아웃 명세가 없는 경우에도 실패 없이 처리되어야 한다.
구체 연산은 데이터 레이아웃 명세를 반환하는 훅을 구현해야 한다. 선택적으로 데이터 레이아웃 질의에 사용되는 메서드를 재정의할 수 있으며, 기본 구현은 내장 타입에 대한 미리 정의된 답을 제공하고 그 외 모든 타입에 대해 타입 인터페이스로 디스패치한다. 이들 메서드는 멱등적이어야 하며, 동일한 파라미터로 반복 질의 시 동일한 결과를 반환해야 한다. 이들은 정적(static)으로 선언되어 연산이나 그 애트리뷰트에 접근할 수 없다. 대신, 요청과 관련된 데이터 레이아웃 항목 리스트를 받는다. 항목들은 명세 및 항목 검증기를 통과한 것으로 보장된다.
getDataLayoutSpec¶::mlir::DataLayoutSpecInterface getDataLayoutSpec();
이 op에 대한 데이터 레이아웃 명세를 반환하거나, 존재하지 않으면 null을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTargetSystemSpec¶::mlir::TargetSystemSpecInterface getTargetSystemSpec();
이 op에 대한 타깃 시스템 설명 명세를 반환하거나, 존재하지 않으면 null을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTypeSize¶static ::llvm::TypeSize getTypeSize(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
관련 항목을 사용해 주어진 타입의 크기를 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTypeSizeInBits¶static ::llvm::TypeSize getTypeSizeInBits(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
관련 항목을 사용해 주어진 타입의 크기(비트)를 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTypeABIAlignment¶static uint64_t getTypeABIAlignment(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
관련 항목을 사용해 주어진 타입에 대해 ABI가 요구하는 정렬을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTypePreferredAlignment¶static uint64_t getTypePreferredAlignment(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
관련 항목을 사용해 주어진 타입이 선호하는 정렬을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getIndexBitwidth¶static std::optional<uint64_t> getIndexBitwidth(::mlir::Type type, const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
관련 항목을 사용해 주어진 타입의 인덱스 연산에 사용할 비트폭을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getEndianness¶static ::mlir::Attribute getEndianness(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 ABI에 의해 사용되는 엔디언성을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getDefaultMemorySpace¶static ::mlir::Attribute getDefaultMemorySpace(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 ABI에 의해 사용되는 메모리 공간을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getAllocaMemorySpace¶static ::mlir::Attribute getAllocaMemorySpace(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 ABI에 의해 사용되는 메모리 공간을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getManglingMode¶static ::mlir::Attribute getManglingMode(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 맹글링 모드를 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getProgramMemorySpace¶static ::mlir::Attribute getProgramMemorySpace(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 ABI에 의해 사용되는 메모리 공간을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getGlobalMemorySpace¶static ::mlir::Attribute getGlobalMemorySpace(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 ABI에 의해 사용되는 메모리 공간을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getStackAlignment¶static uint64_t getStackAlignment(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 자연 스택 정렬(비트)을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getFunctionPointerAlignment¶static Attribute getFunctionPointerAlignment(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 함수 포인터 정렬(비트)을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getLegalIntWidths¶static Attribute getLegalIntWidths(::mlir::DataLayoutEntryInterface entry);
관련 항목을 사용해 허용 정수 폭(각 폭은 비트)을 반환한다. 재귀적 질의에는 데이터 레이아웃 객체를 사용할 수 있다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getDevicePropertyValue¶static std::optional<Attribute> getDevicePropertyValue(::mlir::DataLayoutEntryInterface entry);
해당 속성이 정의되어 있으면 그 값을 반환한다. 그렇지 않으면 std::nullopt을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
데이터 레이아웃 질의를 직접 처리하려는 타입 클래스는 DataLayoutTypeInterface를 구현해야 한다. 이 인터페이스는 각 데이터 레이아웃 질의에 대해 재정의 가능한 훅을 제공한다. 각 훅에는 타입 인스턴스, 재귀적 질의에 적합한 DataLayout 객체, 그리고 해당 타입 클래스와 관련된 데이터 레이아웃 항목 리스트가 제공된다. 리스트가 비어 있어도 유효한 결과를 제공해야 한다. 이들 훅은 질의가 처리되는 스코프의 연산에 접근할 수 없으며, 대신 제공된 항목을 사용해야 한다.
DataLayoutTypeInterface)¶데이터 레이아웃 대상이 되는 타입을 위한 인터페이스.
데이터 레이아웃 서브시스템의 지원을 받고자 하는 타입은 자신의 크기, 요구/선호 정렬을 질의하는 함수 구현을 제공함으로써 이 인터페이스를 구현해야 한다. 각 함수는 동일 스코프 내에서 재귀적 질의를 수행하는 데 사용할 수 있는 데이터 레이아웃 객체와 이 타입과 관련된 데이터 레이아웃 항목 리스트를 인자로 받는다. 구체적으로, 항목들은 현재 타입과 동일한 타입 클래스의 “어떤 인스턴스”를 키로 가진 항목들이다. 예를 들어, IntegerType이 이 인터페이스를 구현한다면 이 타입의 비트폭과 무관하게 키가 i1, i2, i8 등인 항목들을 전달받게 된다. 이 메커니즘을 통해 타입은 명세에 가능한 모든 타입을 나열하지 않고도 타입별 방식으로 결과를 “보간”할 수 있다.
항목 리스트는 비어 있을 수 있으며, 이 경우 타입은 합리적인 기본값을 제공해야 한다. 리스트의 항목들은 명세 및 항목 검증기와, 제공된 경우 타입별 검증기를 통과한 것으로 보장된다.
중첩 레이아웃 명세나 명세 변경의 경우, 타입은 외부(이전) 명세와 내부(새로운) 명세가 호환되는지 여부를 나타내는 훅을 재정의할 수 있다.
getTypeSize¶::llvm::TypeSize getTypeSize(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
이 타입의 크기(바이트)를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getTypeSizeInBits¶::llvm::TypeSize getTypeSizeInBits(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
이 타입의 크기(비트)를 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getABIAlignment¶uint64_t getABIAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
이 타입에 대해 ABI가 요구하는 정렬(바이트)을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getPreferredAlignment¶uint64_t getPreferredAlignment(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
이 타입이 선호하는 정렬(바이트)을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
getIndexBitwidth¶std::optional<uint64_t> getIndexBitwidth(const ::mlir::DataLayout &dataLayout, ::mlir::DataLayoutEntryListRef params);
주어진 포인터 유사(pointer-like) 타입에 대해 인덱스 계산 시 사용해야 하는 비트폭을 반환한다. 타입이 포인터 유사 타입이 아니면 std::nullopt을 반환한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
areCompatible¶bool areCompatible(::mlir::DataLayoutEntryListRef oldLayout, ::mlir::DataLayoutEntryListRef newLayout, ::mlir::DataLayoutSpecInterface newSpec, const ::mlir::DataLayoutIdentifiedEntryMap&identified);
두 항목 리스트가 호환되는지, 즉 newLayout 명세 항목이 oldLayout 명세 항목을 가진 op 내부에 중첩될 수 있는지를 반환한다. newSpec과 identified는 결합된 명세에서 추가 데이터를 질의(예: 기본 주소 공간)하기 위해 제공된다. TODO: https://github.com/llvm/llvm-project/issues/130321 해결 후 이 메서드를 재검토한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
verifyEntries¶::llvm::LogicalResult verifyEntries(::mlir::DataLayoutEntryListRef entries, ::mlir::Location loc);
주어진 항목 리스트가 이 타입에 대해 유효한지 검증한다.
참고: 이 메서드는 사용자에 의해 반드시 구현되어야 한다.
특정 타입 클래스와 관련되지 않은 데이터 레이아웃 항목의 키는 어떤 방언에 속하는 식별자(Identifier)다. 이 경우 해당 방언은 DataLayoutDialectInterface를 구현해야 한다. 이 방언은 항목 값 애트리뷰트의 유효성 검증과 중첩 항목의 호환성 검증을 위한 훅을 제공한다.
크기에 대한 훅은 비트 단위와 바이트 단위의 두 버전이 제공된다. 바이트 버전의 기본 구현은 비트 단위 크기를 8로 나눈 값을 올림하여 바이트 크기를 도출한다. 다른 가정을 갖는 아키텍처만을 대상으로 하는 타입은 이를 재정의할 수 있다. 연산은 모든 타입에 대해 이를 재정의하여, 내장 타입을 포함해 타입을 수정하지 않고도 바이트 크기가 8이 아닌 경우를 스코프 단위로 처리할 수 있다.
데이터 레이아웃 속성 질의의 전체 흐름은 다음과 같다.
DataLayout을 생성한다. 생성자는 데이터 레이아웃 명세를 가져와 둘러싼 스코프의 명세와 결합한다(레이아웃은 호환되어야 한다).DataLayout::query(Type ty)를 호출한다.DataLayout에 캐시된 응답이 있으면 즉시 반환한다.DataLayout에 의해 가장 가까운 레이아웃 스코핑 연산으로 전달된다. 해당 연산이 DataLayoutOpInterface를 구현한다면, 질의는 DataLayoutOpInterface::query(ty, *this, relevantEntries)로 전달되며, 관련 항목은 위에서 설명한 대로 계산된다. 이를 구현하지 않는 경우 반드시 ModuleOp이어야 하며, 질의는 ty를 타입 인터페이스로 캐스팅한 후 DataLayoutTypeInterface::query(dataLayout, relevantEntries)로 전달된다.query 훅이 재구현되지 않았다면, 질의는 ty를 타입 인터페이스로 캐스팅한 후 DataLayoutTypeInterface::query(dataLayout, relevantEntries)로 더 아래로 처리된다. 타입이 인터페이스를 구현하지 않으면 복구 불가능한 치명적 오류가 발생한다.DataLayout에 의해 캐시된다.데이터 레이아웃 인터페이스의 기본 구현은 내장 타입의 부분 집합에 대해 질의를 직접 처리한다.
내장 ModuleOp은 DataLayoutSpecInterface를 구현하는 애트리뷰트를 최대 하나까지만 허용한다. 효율성과 계층화(layering)상의 이유로 전체 인터페이스를 구현하지는 않는다. 대신, DataLayout은 ModuleOp에 대해 구성될 수 있으며 인터페이스를 구현하는 다른 연산과 함께 모듈을 투명하게 처리한다.
다음은 내장 타입의 기본 속성을 설명한다.
내장 정수와 부동소수점의 바이트 단위 크기는 ceildiv(bitwidth, 8)로 계산된다. 비트폭이 64 미만인 정수 타입과 부동소수점 타입의 ABI 정렬은 바이트 단위로 위쪽에서 가장 가까운 2의 거듭제곱이다. 비트폭이 64 이상인 정수 타입의 ABI 정렬은 4바이트(32비트)다.
내장 벡터의 크기는 먼저 “가장 안쪽” 차원의 원소 수를 위쪽에서 가장 가까운 2의 거듭제곱으로 반올림하고, 총 원소 수를 구한 뒤, 이를 원소 크기와 곱해서 계산한다. 예를 들어, vector<3xi32>와 vector<4xi32>는 같은 크기를 갖는다. vector<2x3xf32>와 vector<2x4xf32>도 마찬가지지만, vector<3x4xf32>와 vector<4x4xf32>는 서로 다른 크기를 갖는다. 벡터 타입의 ABI/선호 정렬은 벡터의 가장 안쪽 차원을 취해 이를 가장 가까운 2의 거듭제곱으로 올림하고, 그것과 원소 바이트 크기의 곱을 취해, 다시 가장 가까운 2의 거듭제곱으로 올림하여 계산한다.
참고: 이 값들은 LLVM의 기본 데이터 레이아웃과의 일관성을 위해 선택되었으며, 이는 제대로 된 데이터 레이아웃 모델링이 도입되기 전까지 MLIR이 가정하던 것이고, n차원 벡터 모델링과도 일관성을 가진다. 향후 변경될 수 있다.
index 타입¶Index 타입은 예를 들어 memref 연산에서 타깃 특화 크기 정보에 사용되는 정수 타입이다. 그 데이터 레이아웃은 비트폭을 지정하는 단일 정수 데이터 레이아웃 항목으로 매개변수화된다. 예를 들어,
module attributes { dlti.dl_spec = #dlti.dl_spec<
#dlti.dl_entry<index, 32>
>} {}
이는 index가 32비트이며 인덱스 연산도 32비트 정밀도로 수행되어야 함을 지정한다. index의 다른 모든 레이아웃 속성은 위에서 정의한 동일 비트폭의 정수 타입과 동일하다.
해당 항목이 없는 경우, index는 64비트 정수로 가정된다.
complex 타입¶기본적으로 complex 타입은 주어진 원소 타입의 2-원소 구조체처럼 취급된다. 즉, 각 원소는 자신의 선호 정렬에 맞춰 정렬되며, 전체 complex 타입 역시 이 선호 정렬로 정렬되고, complex 타입의 크기에는 정렬을 강제하기 위한 원소 간 패딩이 포함된다.
기본 데이터 레이아웃은 8비트 바이트를 가정한다.
DLTI 방언은 DataLayoutSpecInterface와 DataLayoutEntryInterface를 구현하는 애트리뷰트와, 명세를 특정 연산에 부착하는 데 사용할 수 있는 방언 애트리뷰트를 제공한다. 이 애트리뷰트의 검증기는 명세의 검증기를 트리거하고, 중첩 명세의 호환성을 확인한다.