Thread

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. jit: Add missing inline pass for LLVM >= 17.

  1. Add missing JIT inline pass for llvm>=17

    Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com> — 2026-01-14T08:02:16Z

    Hi,
    
    While reviewing the llvm-22 patches[0], I've tried to trigger JIT
    inlining using the provided check_jit_code.sh script. The script
    generates bc for both jit_inline_above_cost=0 and
    jit_inline_above_cost=100000 and compares the generated code.
    
    However, the generated bitcode were more or less the same, the only
    minor difference being the "inlining" version had additional strings.
    I've made sure to install through autoconf as meson doesn't generate
    and install bitcode files yet[1].
    
    Debugging showed the code correctly going through llvm_inline and
    correctly importing the functions in the module. However, I'm using
    llvm21 and only the "default<O0>,mem2reg" passes are used, without any
    inlining passes.
    
    With llvm<17, the passes were configured as follow:
    - No optimisation and no inlining: always-inline
    - No optimisation and inlining: inline
    - Optimisation: O3 (which includes inline)
    
    The attached patch adds the inline pass when jit inlining is triggered
    without optimisation, as was done with LLVM<17.
    
    I didn't add the always-inline pass as I don't think this can have any
    effect. From what I understand, the functions need to be imported
    through llvm_inline for LLVM to be able to inline them. I've tested by
    tagging int4mod as always inline, and the generated bc was still
    calling the function despite the always-inline pass.
    
    Regards,
    Anthonin Bonnefoy
    
    [0]: https://www.postgresql.org/message-id/flat/CA%2BhUKGJTumad75o8Zao-LFseEbt%3DenbUFCM7LZVV%3Dc8yg2i7dg%40mail.gmail.com
    [1]: https://www.postgresql.org/message-id/flat/206b001d-1884-4081-bd02-bed5c92f02ba%40eisentraut.org
    
  2. Re: Add missing JIT inline pass for llvm>=17

    Thomas Munro <thomas.munro@gmail.com> — 2026-01-15T02:33:13Z

    On Wed, Jan 14, 2026 at 9:02 PM Anthonin Bonnefoy
    <anthonin.bonnefoy@datadoghq.com> wrote:
    > The attached patch adds the inline pass when jit inlining is triggered
    > without optimisation, as was done with LLVM<17.
    
    Oof, right.  Commit message should mention that this was an oversight
    in 76200e5e.  I think we should back-patch this.
    
         if (context->base.flags & PGJIT_OPT3)
             passes = "default<O3>";
    +    else if (context->base.flags & PGJIT_INLINE
    +             && !(context->base.flags & PGJIT_OPT3))
    +        /* if doing inlining, but no expensive optimization, add inline pass */
    +        passes = "default<O0>,mem2reg,inline";
         else
             passes = "default<O0>,mem2reg";
    
    That expression after && is redundant with the "else".
    
    > I didn't add the always-inline pass as I don't think this can have any
    > effect. From what I understand, the functions need to be imported
    > through llvm_inline for LLVM to be able to inline them. I've tested by
    > tagging int4mod as always inline, and the generated bc was still
    > calling the function despite the always-inline pass.
    
    What about llvmjit_deform.c's use of l_callsite_alwaysinline()?
    
    
    
    
  3. Re: Add missing JIT inline pass for llvm>=17

    Andreas Karlsson <andreas@proxel.se> — 2026-01-15T03:20:45Z

    Great find! Sadly shows how little people actually use JIT.
    
    On 1/14/26 9:02 AM, Anthonin Bonnefoy wrote:
    > I didn't add the always-inline pass as I don't think this can have any
    > effect. From what I understand, the functions need to be imported
    > through llvm_inline for LLVM to be able to inline them. I've tested by
    > tagging int4mod as always inline, and the generated bc was still
    > calling the function despite the always-inline pass.
    
    If inline-always does not do anything it should be removed on older LLVM 
    versions too. I do not think we should be having pre- and post-LLVM 17 
    run different passes. But as Thomas pointed out inline-always is likely 
    used for tuple deforming.
    
    Andreas
    
    
    
    
    
  4. Re: Add missing JIT inline pass for llvm>=17

    Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com> — 2026-01-15T09:40:37Z

    On Thu, Jan 15, 2026 at 4:20 AM Andreas Karlsson <andreas@proxel.se> wrote:
    > If inline-always does not do anything it should be removed on older LLVM
    > versions too. I do not think we should be having pre- and post-LLVM 17
    > run different passes. But as Thomas pointed out inline-always is likely
    > used for tuple deforming.
    
    Right, I've missed the l_callsite_alwaysinline for varsize_any.
    Testing with the following query to trigger a call to varsize_any:
    
    create table test_always_inline(id integer, data text);
    select data, id FROM test_always_inline;
    
    The generated bc were identical (attached with the message), with and
    without always-inline with varsize_any not being inlined. I think this
    is the same issue as with external functions. varsize_any is defined
    in postgres/access/common/heaptuple.bc, and the function needs to be
    imported for LLVM to be able to inline it. Without going through
    llvm_inline and importing the functions, there's no inlining doable.
    
    Maybe the issue is that always-inline functions should be inlined,
    even with the non-optimized case (at least, that's what the configured
    passes seem to imply)? But that would require calling llvm_inline,
    which kind of defeats the purpose of having a dedicated PGJIT_INLINE
    flag and threshold.
    
    I've updated the patch with the simplified PGJIT_INLINE check and the
    commit message change. I've added a separate patch to remove the
    always-inline pass pre-LLVM 17 if we want to go that way.
    
  5. Re: Add missing JIT inline pass for llvm>=17

    Álvaro Herrera <alvherre@kurilemu.de> — 2026-01-15T11:26:23Z

    On 2026-Jan-15, Andreas Karlsson wrote:
    
    > Great find! Sadly shows how little people actually use JIT.
    
    I disagree.  Given that JIT is enabled by default, I think lots of
    people use it.  What they don't do, is realize that things are slower
    than they could be -- much less try to figure out why.
    
    But yes, this was a great find.
    
    -- 
    Álvaro Herrera         PostgreSQL Developer  —  https://www.EnterpriseDB.com/
    
    
    
    
  6. Re: Add missing JIT inline pass for llvm>=17

    Andres Freund <andres@anarazel.de> — 2026-01-15T13:51:52Z

    Hi,
    
    Good catch in noticing this.
    
    On 2026-01-15 10:40:37 +0100, Anthonin Bonnefoy wrote:
    > On Thu, Jan 15, 2026 at 4:20 AM Andreas Karlsson <andreas@proxel.se> wrote:
    > > If inline-always does not do anything it should be removed on older LLVM
    > > versions too. I do not think we should be having pre- and post-LLVM 17
    > > run different passes. But as Thomas pointed out inline-always is likely
    > > used for tuple deforming.
    > 
    > Right, I've missed the l_callsite_alwaysinline for varsize_any.
    > Testing with the following query to trigger a call to varsize_any:
    > 
    > create table test_always_inline(id integer, data text);
    > select data, id FROM test_always_inline;
    > 
    > The generated bc were identical (attached with the message), with and
    > without always-inline with varsize_any not being inlined. I think this
    > is the same issue as with external functions. varsize_any is defined
    > in postgres/access/common/heaptuple.bc, and the function needs to be
    > imported for LLVM to be able to inline it. Without going through
    > llvm_inline and importing the functions, there's no inlining doable.
    
    Right - but the heuristic inline pass might *still* not inline even after
    llvm_inline...
    
    
    > Maybe the issue is that always-inline functions should be inlined,
    > even with the non-optimized case (at least, that's what the configured
    > passes seem to imply)? But that would require calling llvm_inline,
    > which kind of defeats the purpose of having a dedicated PGJIT_INLINE
    > flag and threshold.
    
    No, it doesn't. E.g. the generated deform function should be inlined even if
    we don't do the more expansive inlining.
    
    
    > I've updated the patch with the simplified PGJIT_INLINE check and the
    > commit message change. I've added a separate patch to remove the
    > always-inline pass pre-LLVM 17 if we want to go that way.
    
    I'm strongly against removing the always inline pass, I see absolutely no
    reason for doing that. The whole point of always inline is that it happens
    unconditionally. It's not an expensive pass either.
    
    Greetings,
    
    Andres Freund
    
    
    
    
  7. Re: Add missing JIT inline pass for llvm>=17

    Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com> — 2026-01-16T09:10:07Z

    On Thu, Jan 15, 2026 at 2:51 PM Andres Freund <andres@anarazel.de> wrote:
    > I'm strongly against removing the always inline pass, I see absolutely no
    > reason for doing that. The whole point of always inline is that it happens
    > unconditionally. It's not an expensive pass either.
    
    I've looked into more details on what was provided by 'default<O0>',
    and it turns out it includes an always-inline pass[0]. This is also
    visible when using debug-pass-manager:
    
    llvm-as < /dev/null | opt -disable-output --passes='default<O0>'
    -debug-pass-manager
    Running analysis: InnerAnalysisManagerProxy<FunctionAnalysisManager,
    Module> on [module]
    Running pass: AlwaysInlinerPass on [module]
    Running analysis: ProfileSummaryAnalysis on [module]
    Running pass: CoroConditionalWrapper on [module]
    Running pass: VerifierPass on [module]
    Running analysis: VerifierAnalysis on [module]
    
    With the pre-LLVM17 legacy pass manager, that doesn't seem to be the
    case[1] (despite the confusing comment? Inliner is only set by
    LLVMPassManagerBuilderUseInlinerWithThreshold).
    
    So, with 'default<O0>,mem2reg', we replicate the same behaviour as
    pre-LLVM17 as it includes the always-inline pass.
    
    I've updated the patch to only add the inline pass when PGJIT_INLINE
    is on. I've also added a comment to mention that always-inline is
    included in O0.
    
    [0]: https://github.com/llvm/llvm-project/blob/701040d48f759369dce755f185a21aa6b92ba3ae/llvm/lib/Passes/PassBuilderPipelines.cpp#L2360-L2365
    [1]: https://github.com/llvm/llvm-project/blob/release/16.x/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp#L290-L313
    
  8. Re: Add missing JIT inline pass for llvm>=17

    Michael Banck <mbanck@gmx.net> — 2026-01-16T09:29:59Z

    Hi,
    
    On Thu, Jan 15, 2026 at 12:26:23PM +0100, Álvaro Herrera wrote:
    > On 2026-Jan-15, Andreas Karlsson wrote:
    > > Great find! Sadly shows how little people actually use JIT.
    > 
    > I disagree.  Given that JIT is enabled by default, I think lots of
    > people use it. 
    
    Well, not sure about that - all of the three major hyperscalers disable
    JIT in their managed Postgres offerings (or at least used to when I last
    checked), and those are a major chunk of usage these days. Also, both
    the RPM and (since recently) the Debian/Ubuntu community packages have
    factored out the LLVM/jit part into their own packages and AFAIK they do
    not get installed by default.
    
    So while the GUC is on by default, a lot of users might not use JIT
    these days and not know either way.
    
    > What they don't do, is realize that things are slower
    > than they could be -- much less try to figure out why.
    
    Right.
    
    
    Michael
    
    
    
    
  9. Re: Add missing JIT inline pass for llvm>=17

    Pierre Ducroquet <p.psql@pinaraf.info> — 2026-01-19T10:52:51Z

    On Friday, January 16, 2026 10:29:59 AM Central European Standard Time Michael 
    Banck wrote:
    > Hi,
    > 
    > On Thu, Jan 15, 2026 at 12:26:23PM +0100, Álvaro Herrera wrote:
    > > On 2026-Jan-15, Andreas Karlsson wrote:
    > > > Great find! Sadly shows how little people actually use JIT.
    > > 
    > > I disagree.  Given that JIT is enabled by default, I think lots of
    > > people use it.
    > 
    > Well, not sure about that - all of the three major hyperscalers disable
    > JIT in their managed Postgres offerings (or at least used to when I last
    > checked), and those are a major chunk of usage these days. Also, both
    > the RPM and (since recently) the Debian/Ubuntu community packages have
    > factored out the LLVM/jit part into their own packages and AFAIK they do
    > not get installed by default.
    > 
    > So while the GUC is on by default, a lot of users might not use JIT
    > these days and not know either way.
    > 
    > > What they don't do, is realize that things are slower
    > > than they could be -- much less try to figure out why.
    > 
    > Right.
    
    People have also seen blog articles saying «JIT is bad, switch it off» that are 
    right if you are in the wrong use cases for JIT. Which, to be fair, is not 
    easy to figure out.
    
    Re. the topic, good catch, I was looking at the JITted assembly code a few 
    days ago and was left with that in the back of my mind, patch reviewed and +1 
    
    
    
    
    
    
    
  10. Re: Add missing JIT inline pass for llvm>=17

    Andres Freund <andres@anarazel.de> — 2026-01-20T19:03:45Z

    Hi,
    
    On 2026-01-16 10:10:07 +0100, Anthonin Bonnefoy wrote:
    > On Thu, Jan 15, 2026 at 2:51 PM Andres Freund <andres@anarazel.de> wrote:
    > > I'm strongly against removing the always inline pass, I see absolutely no
    > > reason for doing that. The whole point of always inline is that it happens
    > > unconditionally. It's not an expensive pass either.
    > 
    > I've looked into more details on what was provided by 'default<O0>',
    > and it turns out it includes an always-inline pass[0]. This is also
    > visible when using debug-pass-manager:
    
    Ah, that's good to know!
    
    
    > So, with 'default<O0>,mem2reg', we replicate the same behaviour as
    > pre-LLVM17 as it includes the always-inline pass.
    > 
    > I've updated the patch to only add the inline pass when PGJIT_INLINE
    > is on. I've also added a comment to mention that always-inline is
    > included in O0.
    
    That looks good to me.
    
    Greetings,
    
    Andres Freund
    
    
    
    
  11. Re: Add missing JIT inline pass for llvm>=17

    Matheus Alcantara <matheusssilv97@gmail.com> — 2026-01-21T21:08:37Z

    Hi,
    
    Good catch, thanks for the patch.
    
    On 16/01/26 06:10, Anthonin Bonnefoy wrote:
    > On Thu, Jan 15, 2026 at 2:51 PM Andres Freund <andres@anarazel.de> wrote:
    >> I'm strongly against removing the always inline pass, I see absolutely no
    >> reason for doing that. The whole point of always inline is that it happens
    >> unconditionally. It's not an expensive pass either.
    > 
    > I've looked into more details on what was provided by 'default<O0>',
    > and it turns out it includes an always-inline pass[0]. This is also
    > visible when using debug-pass-manager:
    > 
    > llvm-as < /dev/null | opt -disable-output --passes='default<O0>'
    > -debug-pass-manager
    > Running analysis: InnerAnalysisManagerProxy<FunctionAnalysisManager,
    > Module> on [module]
    > Running pass: AlwaysInlinerPass on [module]
    > Running analysis: ProfileSummaryAnalysis on [module]
    > Running pass: CoroConditionalWrapper on [module]
    > Running pass: VerifierPass on [module]
    > Running analysis: VerifierAnalysis on [module]
    > 
    > With the pre-LLVM17 legacy pass manager, that doesn't seem to be the
    > case[1] (despite the confusing comment? Inliner is only set by
    > LLVMPassManagerBuilderUseInlinerWithThreshold).
    > 
    > So, with 'default<O0>,mem2reg', we replicate the same behaviour as
    > pre-LLVM17 as it includes the always-inline pass.
    > 
    > I've updated the patch to only add the inline pass when PGJIT_INLINE
    > is on. I've also added a comment to mention that always-inline is
    > included in O0.
    > 
    > [0]: https://github.com/llvm/llvm-project/blob/701040d48f759369dce755f185a21aa6b92ba3ae/llvm/lib/Passes/PassBuilderPipelines.cpp#L2360-L2365
    > [1]: https://github.com/llvm/llvm-project/blob/release/16.x/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp#L290-L313
    
    I've tested this patch with LLVM 22 using the patches from [1] and it
    seems to me that it's working as expected.
    
    On master with jit_inline_above_cost=0 and jit_inline_above_cost=10000 I
    see the same bc:
    
        op.0.fetch:                                       ; preds = %b.op.0.start
          call void @deform_0_1(ptr %v_scanslot)
          br label %b.op.1.start
    
    With v3 patch and with jit_inline_above_cost=0 it inline the deform
    function as expected:
    
        op.0.fetch:                                       ; preds = %b.op.0.start
          %29 = getelementptr inbounds nuw %struct.TupleTableSlot, ptr %v_scanslot, i32 0, i32 5
          %tts_values.i = load ptr, ptr %29, align 8
          %30 = getelementptr inbounds nuw %struct.TupleTableSlot, ptr %v_scanslot, i32 0, i32 6
          %tts_ISNULL.i = load ptr, ptr %30, align 8
          %31 = getelementptr inbounds nuw %struct.TupleTableSlot, ptr %v_scanslot, i32 0, i32 1
          ...
    
    
    [1] https://www.postgresql.org/message-id/flat/CA%2BhUKGJTumad75o8Zao-LFseEbt%3DenbUFCM7LZVV%3Dc8yg2i7dg%40mail.gmail.com
    
    --
    Matheus Alcantara
    EDB: https://www.enterprisedb.com
    
    
    
    
  12. Re: Add missing JIT inline pass for llvm>=17

    Thomas Munro <thomas.munro@gmail.com> — 2026-01-22T02:25:45Z

    Thanks all.  I'll go ahead and push this.