Verification and isa problem

Hi folks,

I’m playing around with MLIR and hitting an issue with verification and Attribute::isa.

TL;DR:

mlir::IntegerAttr::get(i32, 42).isa<mlir::IntegerAttr>() yelds false and I’m not sure I understand what is going on.

Details:

The original issue is coming from a simple Dialect.td which prints verification errors like this:

loc("whatever":1:0): error: 'foobar.ui32' op attribute 'value' failed to satisfy constraint: 32-bit unsigned integer attribute

with the op in question being

%1 = "foobar.ui32"() {value = 42 : ui32} : () -> ui32

Upon investigation, I boiled the issue down to the following reproducer:

// main.cpp
#include <mlir/IR/BuiltinAttributes.h>
#include <mlir/IR/BuiltinTypes.h>
#include <mlir/IR/MLIRContext.h>

int main() {
  mlir::MLIRContext context;
  auto i32 = mlir::IntegerType::get(&context, 32);
  mlir::IntegerAttr intAttr = mlir::IntegerAttr::get(i32, 42);
  llvm::errs() << intAttr.isa<mlir::IntegerAttr>() << "\n";

  // For debugging only
  mlir::Attribute attr = intAttr;
  llvm::errs() << "IntegerAttr: " << intAttr.getTypeID().getAsOpaquePointer() << "\n";
  llvm::errs() << "Attribute: " << attr.getTypeID().getAsOpaquePointer() << "\n";

  return 0;
}
cmake_minimum_required(VERSION 3.22)
project(MLIRAttrTest)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(LLVM CONFIG REQUIRED)
find_package(MLIR CONFIG REQUIRED)

include_directories(${MLIR_INCLUDE_DIRS})

add_executable(MLIRAttrTest main.cpp)
target_compile_options(MLIRAttrTest PRIVATE -fno-rtti)
target_link_libraries(MLIRAttrTest LLVM MLIR)

I’m building the project on macOS with the following invocation (I’m using precompiled LLVM 13 from Homebrew):

> cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm/lib/cmake
> make MLIRAttrTest
> ./MLIRAttrTest
0
0x103830118
0x1068a5cb0

The first line outputs 0 meaning that effectively

mlir::IntegerAttr::get(i32, 42).isa<mlir::IntegerAttr>()

is false.


The isa call goes through

// mlir/IR/Attributes.h:102
template <typename U> bool Attribute::isa() const {
  assert(impl && "isa<> used on a null attribute.");
  return U::classof(*this);
}

and then through

// mlir/IR/StorageUniquerSupport.h:79
template <typename T> static bool classof(T val) {
  static_assert(std::is_convertible<ConcreteT, T>::value,
                "casting from a non-convertible type");
  return val.getTypeID() == getTypeID();
}

with the val.getTypeID() == getTypeID() yielding false.


I modified the classof method as follows:

template <typename T> static bool classof(T val) {
  static_assert(std::is_convertible<ConcreteT, T>::value,
                "casting from a non-convertible type");
  auto this_ = getTypeID();
  auto that = val.getTypeID();
  llvm::errs() << "this: " << this_.getAsOpaquePointer() << "\n";
  llvm::errs() << "that: " << that.getAsOpaquePointer() << "\n";
  return this_ == that;
}

And the program now outputs this:

this: 0x10a0980f8
that: 0x10d10dcb0
0
IntegerAttr: 0x10a0980f8
Attribute: 0x10d10dcb0

I believe I don’t do anything obviously wrong, so any hints on why this happens (and how to use/workaround it) would be highly appreciated!

Thanks,
Alex.

Interestingly enough, using the official precompiled binaries (from releases.llvm.org) does the job. The only difference so far, is that with Homebrew I linked against dylibs, while the precompiled binaries only ship static libraries.

There a known issues with mlir::TypeID and dynamic libraries, we did some very recent changes there to improve the situation though: It’d be interesting to see if we’re in a good spot now or if this kind of issues are still widespread.