Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cast global variables to default address space #135026

Merged
merged 2 commits into from
Jan 31, 2025

Conversation

Flakebi
Copy link
Contributor

@Flakebi Flakebi commented Jan 2, 2025

Pointers for variables all need to be in the same address space for correct compilation. Therefore ensure that even if a global variable is created in a different address space, it is casted to the default address space before its value is used.

This is necessary for the amdgpu target and others where the default address space for global variables is not 0.

For example core does not compile in debug mode when not casting the address space to the default one because it tries to emit the following (simplified) LLVM IR, containing a type mismatch:

@alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
@alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspace(1) @alloc_0 }>, align 8
; ^ here a struct containing a `ptr` is needed, but it is created using a `ptr addrspace(1)`

For this to compile, we need to insert a constant addrspacecast before we use a global variable:

@alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
@alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspacecast (ptr addrspace(1) @alloc_0 to ptr) }>, align 8

As vtables are global variables as well, they are also created with an addrspacecast. In the SSA backend, after a vtable global is created, metadata is added to it. To add metadata, we need the non-casted global variable. Therefore we strip away an addrspacecast if there is one, to get the underlying global.

Tracking issue: #135024

Pointers for variables all need to be in the same address space for
correct compilation. Therefore ensure that even if a global variable is
created in a different address space, it is casted to the default
address space before its value is used.

This is necessary for the amdgpu target and others where the default
address space for global variables is not 0.

For example `core` does not compile in debug mode when not casting the
address space to the default one because it tries to emit the following
(simplified) LLVM IR, containing a type mismatch:

```llvm
@alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
@alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspace(1) @alloc_0 }>, align 8
; ^ here a struct containing a `ptr` is needed, but it is created using a `ptr addrspace(1)`
```

For this to compile, we need to insert a constant `addrspacecast` before
we use a global variable:

```llvm
@alloc_0 = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
@alloc_1 = addrspace(1) constant <{ ptr }> <{ ptr addrspacecast (ptr addrspace(1) @alloc_0 to ptr) }>, align 8
```

As vtables are global variables as well, they are also created with an
`addrspacecast`. In the SSA backend, after a vtable global is created,
metadata is added to it. To add metadata, we need the non-casted global
variable. Therefore we strip away an addrspacecast if there is one, to
get the underlying global.
@rustbot
Copy link
Collaborator

rustbot commented Jan 2, 2025

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @fmease (or someone else) some time within the next two weeks.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 2, 2025
@Flakebi Flakebi mentioned this pull request Jan 2, 2025
16 tasks
@fmease
Copy link
Member

fmease commented Jan 22, 2025

r? codegen

@rustbot rustbot assigned saethlin and unassigned fmease Jan 22, 2025
Comment on lines -288 to +289
_ => self.static_addr_of(init, alloc.align, None),
_ => self.static_addr_of_impl(init, alloc.align, None),
Copy link
Member

Choose a reason for hiding this comment

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

Why does this function call the _impl version? I would think that _impl would be a private helper method or something like that. Unless this means that it's the address of an implementation? The naming here is not doing any favors and there are also no comments on the methods to explain what they are for so I'm really struggling to follow. Can you clarify in the code what the intended difference between static_addr_of and static_addr_of_impl is, and comment why we need the _impl version 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.

Thanks for taking a look!
I added comments to the functions, let me know if that makes it clearer or if you think something is unclear or missing.

To the point you mentioned here, static_addr_of_impl always returns a llvm::GlobalVariable. But that may not be a ptr (in LLVM IR; this is implicitly an addrspace(0) ptr, 0 is the default and is omitted), but a addrspace(1) ptr.
When we use a global in Rust (or in the ssa codegen), we need it to be just a ptr (so, addrspace(0)). Therefore, static_addr_of must return a ptr and it does that by inserting an addrspacecast on the result of static_addr_of_impl.

So, depending on what we need either function is called. If we need a llvm::GlobalVariable, we need to call static_addr_of_impl, if a ptr is needed, we call static_addr_of.

Copy link
Member

Choose a reason for hiding this comment

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

That all makes sense, but why in these call sites specifically, is it okay to have addrspace(1) ptr?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here, we want to have the llvm::GlobalValue and edit some of its properties like with llvm::set_value_name below.
We cast it to an (addrspace(0)) ptr with the const_pointercast at the end of this Scalar::Ptr match arm.

@saethlin saethlin added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 23, 2025
@Flakebi
Copy link
Contributor Author

Flakebi commented Jan 24, 2025

@nikic, as you reviewed #135025, you may want to take a look at this one as well.

@saethlin
Copy link
Member

I think I'm convinced of the implementation here, but this is a rather fiddly change with no tests. Can you add a codegen test that covers the scenarios the implementation is addressing?

@Flakebi
Copy link
Contributor Author

Flakebi commented Jan 28, 2025

I think I'm convinced of the implementation here, but this is a rather fiddly change with no tests. Can you add a codegen test that covers the scenarios the implementation is addressing?

Yeah, definitely makes sense. I can do that once the amdgpu target is merged. (Before that, I can't create globals in a different address space.)

@saethlin
Copy link
Member

I see. Oof.

@bors r=saethlin

@bors
Copy link
Contributor

bors commented Jan 30, 2025

📌 Commit b06e840 has been approved by saethlin

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 30, 2025
bors added a commit to rust-lang-ci/rust that referenced this pull request Jan 30, 2025
…iaskrgr

Rollup of 9 pull requests

Successful merges:

 - rust-lang#135026 (Cast global variables to default address space)
 - rust-lang#135475 (uefi: Implement path)
 - rust-lang#135852 (Add `AsyncFn*` to `core` prelude)
 - rust-lang#136004 (tests: Skip const OOM tests on aarch64-unknown-linux-gnu)
 - rust-lang#136157 (override build profile for bootstrap tests)
 - rust-lang#136180 (Introduce a wrapper for "typed valtrees" and properly check the type before extracting the value)
 - rust-lang#136256 (Add release notes for 1.84.1)
 - rust-lang#136271 (Remove minor future footgun in `impl Debug for MaybeUninit`)
 - rust-lang#136288 (Improve documentation for file locking)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 89f8abe into rust-lang:master Jan 31, 2025
6 checks passed
@rustbot rustbot added this to the 1.86.0 milestone Jan 31, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this pull request Jan 31, 2025
Rollup merge of rust-lang#135026 - Flakebi:global-addrspace, r=saethlin

Cast global variables to default address space

Pointers for variables all need to be in the same address space for correct compilation. Therefore ensure that even if a global variable is created in a different address space, it is casted to the default address space before its value is used.

This is necessary for the amdgpu target and others where the default address space for global variables is not 0.

For example `core` does not compile in debug mode when not casting the address space to the default one because it tries to emit the following (simplified) LLVM IR, containing a type mismatch:

```llvm
`@alloc_0` = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
`@alloc_1` = addrspace(1) constant <{ ptr }> <{ ptr addrspace(1) `@alloc_0` }>, align 8
; ^ here a struct containing a `ptr` is needed, but it is created using a `ptr addrspace(1)`
```

For this to compile, we need to insert a constant `addrspacecast` before we use a global variable:

```llvm
`@alloc_0` = addrspace(1) constant <{ [6 x i8] }> <{ [6 x i8] c"bit.rs" }>, align 1
`@alloc_1` = addrspace(1) constant <{ ptr }> <{ ptr addrspacecast (ptr addrspace(1) `@alloc_0` to ptr) }>, align 8
```

As vtables are global variables as well, they are also created with an `addrspacecast`. In the SSA backend, after a vtable global is created, metadata is added to it. To add metadata, we need the non-casted global variable. Therefore we strip away an addrspacecast if there is one, to get the underlying global.

Tracking issue: rust-lang#135024
@Flakebi Flakebi deleted the global-addrspace branch January 31, 2025 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants