Skip to content

Translate ^^ operator to druntime hook#22831

Merged
dkorpel merged 1 commit intodlang:masterfrom
dkorpel:pow-hook
Mar 28, 2026
Merged

Translate ^^ operator to druntime hook#22831
dkorpel merged 1 commit intodlang:masterfrom
dkorpel:pow-hook

Conversation

@dkorpel
Copy link
Copy Markdown
Contributor

@dkorpel dkorpel commented Mar 28, 2026

First step to fixing #22670

It doesn't move the implementation like #14297 does, but it moves the hard-coded std import to one that can be overridden in custom druntime.

@dlang-bot
Copy link
Copy Markdown
Contributor

Thanks for your pull request and interest in making D better, @dkorpel! 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#22831"

@rikkimax
Copy link
Copy Markdown
Contributor

I had to double check what ldc with optimizations would do with ^^ 0.5:

float abc(float a) {
 	return a ^^ 0.5;   
}
float onlineapp.abc(float):
	.cfi_startproc
	sqrtss	%xmm0, %xmm0
	retq

It will optimize it, doing it in the frontend is far too early.

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

@rikkimax You got that backwards

@rikkimax
Copy link
Copy Markdown
Contributor

@rikkimax You got that backwards

Which part?

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

ldc shares dmd's frontend, which does the transformation. LDC's backend is not allowed to rewrite pow(x, 0.5) to sqrt(x) because that's not strictly equivalent.

@rikkimax
Copy link
Copy Markdown
Contributor

Okay, yes llvm isn't doing the rewrite, IR with optimizations turned off is already sqrt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ibuclaw
Copy link
Copy Markdown
Member

ibuclaw commented Mar 28, 2026

@dkorpel are you offering to write an ibm-real implementation of ^^ then? Thanks! :-)

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

What is that and why would it be needed?

@ibuclaw
Copy link
Copy Markdown
Member

ibuclaw commented Mar 28, 2026

What is that and why would it be needed?

alias real = double[2];

https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format#Double-double_arithmetic

Without support, building druntime would regress on POWER targets.

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

The goal here is to move code from one package to another. Why would that break existing support or require new support? Looks like a separate thing to me.

@ibuclaw
Copy link
Copy Markdown
Member

ibuclaw commented Mar 28, 2026

These power targets can't build std.math, moving that out of phobos means they won't be able to build druntime - ergo can't bootstrap the compiler.

// TODO: move implementation to druntime instead of Phobos.
auto _d_sqrt(T)(T x)
{
import std.math : sqrt;
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.

This is an intrinsic, use core.math.sqrt instead.

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.

The goal of this PR is to keep behavior equivalent to what it was before, just moving the logic to druntime so at least users of custom druntime can already swap in their own implementation. I plan on breaking the Phobos connection in subsequent PRs.

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.

// TODO: move implementation to druntime instead of Phobos.
auto _d_pow(Base, Exp)(Base base, Exp exp)
{
import std.math : pow;
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.

Could test the import in case this is a port that doesn't have phobos included?

static if (__traits(compiles, { import std.math : pow; }))

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.

No need, because the import is inside a template

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.

Then why go to all the trouble of putting in a friendly error in the compiler then.

The current runtime does not support the ^^ operator, or the runtime is corrupt.

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.

That's the standard verifyHookExist procedure.

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.

Which succeeds because _d_pow exists, then it later fails as std.math doesn't.

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.

Test.

[Environment64]
#DFLAGS=-I%@P%/../../../../druntime/import -I%@P%/../../../../../phobos -L-L%@P%/../../../../../phobos/generated/linux/release/64 -L--export-dynamic -fPIC
DFLAGS=-I%@P%/../../../../druntime/import -L-L%@P%/../../../../../phobos/generated/linux/release/64 -L--export-dynamic -fPIC

Before:

pow.d(3): Error: `a ^^ b` requires `std.math` for `^^` operators
    auto c = a ^^ b;
             ^

After:

./generated/linux/release/64/../../../../druntime/import/object.d(4761): Error: unable to read module `math`
    import std.math : pow;
           ^
./generated/linux/release/64/../../../../druntime/import/object.d(4761):        Expected 'std/math.d' or 'std/math/package.d' in one of the following import paths:
    import std.math : pow;
           ^
import path[0] = ./generated/linux/release/64/../../../../druntime/import

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, that's to be expected

Copy link
Copy Markdown
Member

@ibuclaw ibuclaw Mar 28, 2026

Choose a reason for hiding this comment

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

Then why shy away from friendly error messages then? :-)

static assert(__traits(compiles, { import std.math : pow; }),
              "The current runtime does not support the ^^ operator");
return imported!"std.math".pow(base, exp);

->

./generated/linux/release/64/../../../../druntime/import/object.d(4761): Error: static assert:  "The current runtime does not support the ^^ operator"
    static assert(__traits(compiles, { import std.math : pow; }),
    ^
pow.d(3):        instantiated from here: `_d_pow!(double, double)`
    auto c = a ^^ b;
             ^

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.

Multiple reasons

  • __traits(compiles) is a hack
  • It's better to improve compiler error messages in general than trying to 'catch' them and replacing them manually
  • The error message is not part of normal usage, but advanced usage in unsupported environments
  • The static assert removes information from the compiler's error message (import paths)
  • The whole std import is to be removed any way

The unnormalized path is pretty long and pushes the message to the right, I think that would make a good improvement to start with in general.

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

These power targets can't build std.math, moving that out of phobos means they won't be able to build druntime - ergo can't bootstrap the compiler.

If they couldn't build std.math, then they couldn't use ^^ either, so if the implementation in druntime gets versioned out for those targets it will work like before

@dkorpel dkorpel merged commit 18013b9 into dlang:master Mar 28, 2026
42 checks passed
@dkorpel dkorpel deleted the pow-hook branch March 28, 2026 17:01
@ibuclaw
Copy link
Copy Markdown
Member

ibuclaw commented Mar 28, 2026

These power targets can't build std.math, moving that out of phobos means they won't be able to build druntime - ergo can't bootstrap the compiler.

If they couldn't build std.math, then they couldn't use ^^ either, so if the implementation in druntime gets versioned out for those targets it will work like before

Except it won't as someone's going to add static assert(0) and I'll get all the bug reports from my downstreams that D broke.

@dkorpel
Copy link
Copy Markdown
Contributor Author

dkorpel commented Mar 28, 2026

Do downstreams just pull changes from upstream without testing?

@xoxorwr
Copy link
Copy Markdown
Contributor

xoxorwr commented Mar 28, 2026

This needs change log entry, this will affect custom runtimes.

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.

6 participants