Skip to content

Adds support for special magic LDC_inline_mlir pragma support - #5307

Open
asindarov wants to merge 7 commits into
ldc-developers:masterfrom
asindarov:inline-mlir-pragma
Open

asindarov wants to merge 7 commits into
ldc-developers:masterfrom
asindarov:inline-mlir-pragma

Conversation

@asindarov

Copy link
Copy Markdown
Contributor

This is the follow-up to #5300. It adds LDC_inline_mlir, a pragma similar to LDC_inline_ir, which lets us write a function body in MLIR in D code. It's used through the new __mlir! template in ldc.llvmasm:

import ldc.llvmasm;

int add(int a, int b)
{
    return __mlir!(`
        %res = arith.addi %arg0, %arg1 : i32
        return %res : i32`, int, int, int)(a, b);
}

How it works:

  1. LDC wraps the code in a func.func with the D parameter and return types translated to MLIR types. For void functions it adds the return itself.
  2. The module is parsed and verified. A parse or verify error gives a normal compile error.
  3. It is lowered to the LLVM dialect (scf → cf, arith, cf and func → llvm), translated to LLVM IR and linked into the current module.
  4. The generated function is marked with alwaysinline, gets the function attributes of the calling function (like LDC_inline_ir does), and is called with the runtime arguments.

Supported dialects for now: func, arith, cf, scf and llvm.
In a build without MLIR support, using __mlir! errors with message "Inline MLIR is not supported by this LDC build".

This replaces my earlier draft #5295, which I rebased onto master after #5300 was merged and cleaned up.

@asindarov

Copy link
Copy Markdown
Contributor Author

Hello @kinke, @thewilsonator, the Ubuntu 24.04, LLVM 20, bootstrap LDC CI job was failing because of the way we link MLIR libs. Turns out this job uses the gold linker, which, like GNU ld, cares about the order of the libraries being linked, so I had to use the -Wl,--start-group and -Wl,--end-group linker options to resolve this. They have some (unmeasured) performance cost but took care of the problem. I restricted them to non-Apple, non-MSVC toolchains. The other approach to resolve it would be to manually specify the libraries we use in the dependency order, which is a bit cumbersome, and I don't think it's the way we should go with, as we need to support multiple LLVM versions.
Can you please give a review when you have a chance?

@asindarov

Copy link
Copy Markdown
Contributor Author

Hello @kinke @thewilsonator, just a gentle ping on this when you have a moment. Thanks!

@kinke

kinke commented Oct 22, 2026

Copy link
Copy Markdown
Member

so I had to use the -Wl,--start-group and -Wl,--end-group linker options to resolve this

That's absolutely fine; I was expecting this problem earlier, but looks like we had to actually drag in a bit more MLIR stuff to show up.

What I'm lacking is a rationale for this feature - do we expect this to be necessary for users, to implement certain stuff that they couldn't otherwise?

The size of the FreeBSD artifact grows significantly - used to 18.9 MB IIRC, then 19.3 MB after your first PR, and now it's 25.5 MB. I haven't checked the ldc2 executable size, but it must have grown quite a lot. We might want to disable the MLIR integration for that CI job; an inline-MLIR feature alone doesn't justify that size increase IMO.

Comment thread gen/functions.cpp Outdated
Comment thread gen/functions.cpp Outdated
Comment thread gen/inlinemlir.cpp Outdated
Comment thread gen/inlinemlir.cpp Outdated
return {str.ptr, str.length};
}
} // anonymous namespace
#endif // LDC_MLIR_ENABLED

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, AFAICT, these are 1:1 copies of the helpers in gen/inlineir.cpp. The DtoCheck…Pragma() and DtoInlineMLIR() look quite similar to the normal-LLVM-IR functions, so there's probably room to refactor this (probably after moving this to the existing .cpp modue), avoiding all duplication.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are from gen/inlineir.cpp. I'll refactor it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have refactored it and moved llvm ir/mlir parsing logic into the same file gen/inlineir.cpp. Please let me know if I should make more adjustments.

@asindarov

Copy link
Copy Markdown
Contributor Author

so I had to use the -Wl,--start-group and -Wl,--end-group linker options to resolve this

That's absolutely fine; I was expecting this problem earlier, but looks like we had to actually drag in a bit more MLIR stuff to show up.

What I'm lacking is a rationale for this feature - do we expect this to be necessary for users, to implement certain stuff that they couldn't otherwise?

The size of the FreeBSD artifact grows significantly - used to 18.9 MB IIRC, then 19.3 MB after your first PR, and now it's 25.5 MB. I haven't checked the ldc2 executable size, but it must have grown quite a lot. We might want to disable the MLIR integration for that CI job; an inline-MLIR feature alone doesn't justify that size increase IMO.

On its own, inlineMLIR is a small feature, but it's the first user-visible step of my SAOC project (mentored by Nicholas, plan here). The goal is an MLIR code generation path for the BetterC subset of D to start with, and after that lowering DCompute kernels through MLIR's GPU and transformation infrastructure. I intend to keep working on it after SAOC program. The pragma was the smallest thing that used the whole chain end to end, and I've started on the next milestone, an MLIR-emitting AST visitor.

For the size, I think I know the cause: I used registerAllToLLVMIRTranslations, which references the LLVM IR translations of every dialect, so the linker kept all of them even though we don't need them. I now register only the builtin and llvm dialect translations, the FreeBSD artifact is 22.5 MB, down from 25.5 MB, against the pre-MLIR 18.9 MB. The remaining ~3.6 MB is the dialects and conversion passes the pragma actually uses plus MLIR core, which I can't trim further. If that's still too much for the release packages, we can disable MLIR for those and keep it only in the vanilla-LLVM jobs for testing.

@asindarov
asindarov requested a review from kinke October 25, 2026 17:11
@asindarov

Copy link
Copy Markdown
Contributor Author

Hello @kinke @thewilsonator , just a gentle ping on this when you have a chance. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants