LLVM Discussion Forums

Initialize global struct during lowering to LLVM

Hi there.

I’m encountering a problem when lowering a declaration op of my own dialect into the LLVM dialect.

I want my custom dialect type to be transformed into a global struct in LLVM.

So RewritePattern is used here and the matchAndRewrite function is showed below:


  matchAndRewrite(Operation *op, ArrayRef<Value> operands,

                  ConversionPatternRewriter &rewriter) const override {

    auto loc = op->getLoc();

    auto myOp = cast<myDialect::StructDeclOp>(op);

    auto *llvmDialect =


    assert(llvmDialect && "expected llvm dialect to be registered");

    // Convert my dialect struct to an LLVM Dialect struct, using our

    // custom type converter.

    // strcutPtr is an anonymous struct pointer like !llvm<"{ i64, i32}*">

    auto structPtr = typeConverter->convertType(myOp.getResult().getType());


    // Define a global struct for our struct type

    // Insert the global op into module

    ModuleOp parentModule = op->getParentOfType<ModuleOp>();

    PatternRewriter::InsertPoint ip = rewriter.saveInsertionPoint();


    // Use globalOp to initialize the global struct we need

    // A LLVM struct with type defined and value inserted is expected

    auto attrValue = myOp.value().dyn_cast<ArrayAttr>();

    LLVM::GlobalOp global = rewriter.create<LLVM::GlobalOp>(

        loc, structPtr.cast<LLVM::LLVMType>().getPointerElementTy(), /*isConstant=*/false, 

        LLVM::Linkage::Internal, "structName", attrValue, /*addrSpace=*/0);


    // restore insert point


    // Get the pointer to the struct type.

    LLVM::AddressOfOp globalPtr = rewriter.create<LLVM::AddressOfOp>(loc, global);


    // Make sure to replace all uses of the declOp with the appropriate

    // LLVM dialect op.


    // Notify the rewriter that this operation has been removed.


    return success();


In short, my own declOp is expected to be repalced by a globalOp and an addressOfOp.

I am confused how to pass and initialize the values stored in my custom dialect type (via ::mlir::Attribute) into the LLVM global struct

I’ve tried the type ArrayAttr. But obviously, it’s inappropriate in initializing a struct type.

Could anybody tell me how to initialize a global struct here in the rewriting func?


1 Like

I don’t think there is support for struct-typed constants, but you are very welcome to add it. The places to look at are ModuleTranslation::convertGlobals and ModuleTranslation::getLLVMConstant. I think having a nested ArrayAttr is appropriate: unlike C arrays, ArrayAttr may indeed contain attributes of different types, and array-typed constants use ElementsAttr to store data.

Incidentally, you must not use replaceAllUsesWith in patterns, use rewriter.replaceOp instead. Any direct mutation of the IR, except that of the pattern root guarded by appropriate calls on the rewriter, is illegal and will lead to subtle crashes.

I have to solve a similar problemin npcomp, you can see the code here. Basically, I have to lower a global module descriptor op (npcomprt.module_metadata) and a global tensor op (npcomprt.global)

llvm.mlir.global supports a feature where you use a region to initialize the value (which then gets turned into an LLVM constant expression). Example when lowering module descriptors. That is, create a region that creates an UndefOp of the desired LLVM struct type, does a bunch of InsertValueOp’s into the LLVM struct, then returns it. (.mlir test files 1, 2)

This is definitely verbose to do and native support in core for having an Attribute that gets mapped to an LLVM type directly and cleanly would be useful. In particular, it would be great if it would make testing easier somehow (I’m really unsatisfied with how I had to write the tests I linked above)