Skip to content

Comments

Templatize _adEq2#21513

Merged
thewilsonator merged 19 commits intodlang:masterfrom
Albert24GG:template_adEq2
Jul 14, 2025
Merged

Templatize _adEq2#21513
thewilsonator merged 19 commits intodlang:masterfrom
Albert24GG:template_adEq2

Conversation

@Albert24GG
Copy link
Contributor

This PR replaces all uses of _adEq2 with the existing __equals templated hook, thus closing draft PR #13331.

There may be room for some cleanups or optimizations, so let me know your thoughts.

@Albert24GG Albert24GG requested a review from ibuclaw as a code owner July 7, 2025 10:51
@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @Albert24GG! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#21513"


bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs)
if (!__traits(isScalar, T1) || !__traits(isScalar, T2))
bool __equals(T1, T2)(scope T1[] lhs, scope T2[] rhs) @trusted
Copy link
Contributor

Choose a reason for hiding this comment

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

why remove the attributes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All checks are done before lowering.

// GC checks occur before the expression is lowered to `memcmp` in e2ir.d.
// Thus, we will consider the literal arrays as on-stack arrays to avoid issues
// during GC checks.
if (isArrayComparison)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@thewilsonator Because of the fact that now the result expression is the original one with a .lowering field that is set to null when memcmp is used (the lowering to memcmp happens in e2ir.d), the GC checks will be done on the original expression. This hack allows to preserve the current upstream behavior by avoiding flagging the array literals as @gc. Is there a better way of achieving the same goal, but without this type of hacks?

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.
@thewilsonator thewilsonator requested a review from teodutu July 11, 2025 07:44
$p:makedeps_exe.d$ \
$p:makedeps_a.d$ \
$p:makedeps-import.txt$ \
$p:makedeps-import-codemixin.txt$ \
Copy link
Contributor

Choose a reason for hiding this comment

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

silly question: what's this change for? ditto for the rest of these makedeps changes

Copy link
Contributor Author

@Albert24GG Albert24GG Jul 11, 2025

Choose a reason for hiding this comment

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

The previous refs expected the test output not to include the last line from the makedeps output. If you run -makedeps you will se that all line except the last have a '' at the end. I tried writing something more elegant using the existing regex capabilities, but I couldn't get it right because of the weird parser implementation in d_do_test.d.

Copy link
Member

@teodutu teodutu left a comment

Choose a reason for hiding this comment

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

Looks fine!

@thewilsonator thewilsonator merged commit ad35200 into dlang:master Jul 14, 2025
43 of 44 checks passed
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
# This is the 1st commit message:

refactoring

# This is the commit message #2:

refactoring

# This is the commit message #3:

refactoring

# This is the commit message #4:

refactoring

# This is the commit message #5:

refactoring

# This is the commit message #6:

refactoring

# This is the commit message #7:

refactoring

# This is the commit message #8:

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 14, 2025
refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

ref
gorsing added a commit to gorsing/dmd that referenced this pull request Jul 15, 2025
refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactor/irstate-attrs

refactoring

add pragma(inline, true)

change pragma(inline, true) -> pragma(inline, false)

introduce root.Array.only and test it out in expressionsem (dlang#21520)

[attrib.d] remove unused semantic import

[dstruct.d] remove unused import

[aggregate.d] move `searchCtor` to `expressionsem.d`

remove some now unused semantic symbols from the import list.

[cond.d] remove unused `typesem` import (dlang#21538)

[expression.d] restrict `typesem` import

fix dlang#19587 No debug line info for simple code blocks (dlang#21544)

set location info on return statement, not only on return expression

[dsymbol.d] remove dependance on glue layer (dlang#21532)

move `loadModuleFromLibrary` to `dsymbolsem.d` (dlang#21535)

remove `dmodule.d` dependance of a few more `dsymbolsem.d` symbols.

[func.d] remove dependance on glue layer (dlang#21534)

[aggregate.d] move `checkOverlappedFields` to `dsymbolsem.d` (dlang#21542)

and make private

Templatize `_adEq2` (dlang#21513)

* Mark array literals as `on-stack` to bypass `@nogc` analysis

* Update `fail_compilation` test output

After updating the memcmp-ability criteria, now dynamic array can also
be compared using `memcmp` if their element type is comparable bit by
bit.

refactor: use new array constructor throughout expressionsem

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

refactoring

ref

refactoring

refactoring

ref

refactoring
kinke added a commit to kinke/dmd that referenced this pull request Aug 4, 2025
As the new compiler logic introduced in dlang#21513 was more simplistic than
the previous (templated) implementation in druntime. It e.g. didn't
handle comparisons of multi-dimensional static arrays, e.g., `byte[3][3]`,
breaking an LDC-specific codegen test.
thewilsonator pushed a commit that referenced this pull request Aug 4, 2025
As the new compiler logic introduced in #21513 was more simplistic than
the previous (templated) implementation in druntime. It e.g. didn't
handle comparisons of multi-dimensional static arrays, e.g., `byte[3][3]`,
breaking an LDC-specific codegen test.
@dkorpel
Copy link
Contributor

dkorpel commented Oct 7, 2025

This introduced a regression: #21945

@schveiguy
Copy link
Member

If I'm reading this correctly, we removed memcmp as the mechanism to compare pod arrays? If so, we need to put this back. memcmp is an extremely optimized function.

I'm seeing slowdowns of at least 2x for string comparisons, and in some tests 3x slowdown.

@teodutu
Copy link
Member

teodutu commented Oct 15, 2025

This was because DMD lowered POD array comparisons to memcmp() by itself. @Albert24GG, can you please check that the arrays are memcmp()'d in the example in #21976?

@Albert24GG
Copy link
Contributor Author

Albert24GG commented Oct 15, 2025

Yes, I just checked. The logic is correct, but in the current implementation the equality is lowered to OPmemcmp [1], which dmd implements manually using REP* instructions [2]. Before this PR, that array comparison was being lowered to __equals which directly called memcmp@plt (the optimized libc function).

[1]

e = el_bin(OPmemcmp, TYint, e, esize);

[2]
REPE CMPSB ;compare string

@teodutu
Copy link
Member

teodutu commented Oct 15, 2025

@schveiguy do you have the possiblitiy to test your code with gdc or ldc (provided they integrated this PR)? I'm pretty sure they lower POD comparisons to memcmp().

@schveiguy
Copy link
Member

I happen to have built an ldc with all the recent updates, which I think includes this PR.

Testing issue #21976 with this results in 59-60ms runtime, so ldc is doing the right thing, and it does seem like the memcmp should be selected with the current code.

I would suggest if we never expect __equals to be called with something that should be using memcmp, you insert a static if branch that covers that case, which just static assert(0, "should have been handled by compiler!"); or something like that. This way we know the compiler isn't making mistakes. But probably not the cause of this regression.

@ibuclaw
Copy link
Member

ibuclaw commented Oct 16, 2025

I'd expect ldc to be aware of what memcmp is (or its LLVM IR) - gcc middle end certainly does - and emit an inline (optimised) comparison for small data or a libc call to memcmp when it sees str1 == str2

@Herringway
Copy link
Contributor

I'd expect ldc to be aware of what memcmp is (or its LLVM IR) - gcc middle end certainly does - and emit an inline (optimised) comparison for small data or a libc call to memcmp when it sees str1 == str2

I believe that is the case. I encountered that while trying to implement a memcmp at one point... that overflowed the stack real quick.

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.

8 participants