Skip to content

[clang][CodeGen] Make UnqualPtrTy truly unqualified #94388

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

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

AlexVlx
Copy link
Contributor

@AlexVlx AlexVlx commented Jun 4, 2024

At the moment we alias UnqualPtrTy with the other default AS pointer types, which means that for certain targets using it doesn't actually yield an unqualified pointer. This patch changes that so that it does exactly what it says on the tin, under the assumption that if someone asks for an unqualified pointer they do so knowingly and expect to get exactly that.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jun 4, 2024
@AlexVlx AlexVlx removed the clang Clang issues not falling into any other category label Jun 4, 2024
@llvmbot
Copy link
Member

llvmbot commented Jun 4, 2024

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-clang

Author: Alex Voicu (AlexVlx)

Changes

At the moment we alias UnqualPtrTy with the other default AS pointer types, which means that for certain targets using it doesn't actually yield an unqualified pointer. This patch changes that so that it does exactly what it says on the tin, under the assumption that if someone asks for an unqualified pointer they do so knowingly and expect to get exactly that.


Full diff: https://github.com/llvm/llvm-project/pull/94388.diff

3 Files Affected:

  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+1)
  • (modified) clang/lib/CodeGen/CodeGenTypeCache.h (+3-1)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+3-3)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index be7bf0b72dc0c..b58ca03ce69da 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -368,6 +368,7 @@ CodeGenModule::CodeGenModule(ASTContext &C,
   IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
   IntPtrTy = llvm::IntegerType::get(LLVMContext,
     C.getTargetInfo().getMaxPointerWidth());
+  UnqualPtrTy = llvm::PointerType::getUnqual(LLVMContext);
   Int8PtrTy = llvm::PointerType::get(LLVMContext,
                                      C.getTargetAddressSpace(LangAS::Default));
   const llvm::DataLayout &DL = M.getDataLayout();
diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h
index e273ebe3b060f..3b659bc182aa4 100644
--- a/clang/lib/CodeGen/CodeGenTypeCache.h
+++ b/clang/lib/CodeGen/CodeGenTypeCache.h
@@ -51,9 +51,11 @@ struct CodeGenTypeCache {
     llvm::IntegerType *PtrDiffTy;
   };
 
+  /// unqualified void*
+  llvm::PointerType *UnqualPtrTy;
+
   /// void*, void** in the target's default address space (often 0)
   union {
-    llvm::PointerType *UnqualPtrTy;
     llvm::PointerType *VoidPtrTy;
     llvm::PointerType *Int8PtrTy;
     llvm::PointerType *VoidPtrPtrTy;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 8427286dee887..8952e7ca072da 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -4656,14 +4656,14 @@ static void InitCatchParam(CodeGenFunction &CGF,
   auto catchRD = CatchType->getAsCXXRecordDecl();
   CharUnits caughtExnAlignment = CGF.CGM.getClassPointerAlignment(catchRD);
 
-  llvm::Type *PtrTy = CGF.UnqualPtrTy; // addrspace 0 ok
+  llvm::Type *PtrTy = CGF.UnqualPtrTy; // unqualified is ok
 
   // Check for a copy expression.  If we don't have a copy expression,
   // that means a trivial copy is okay.
   const Expr *copyExpr = CatchParam.getInit();
   if (!copyExpr) {
     llvm::Value *rawAdjustedExn = CallBeginCatch(CGF, Exn, true);
-    Address adjustedExn(CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy),
+    Address adjustedExn(CGF.Builder.CreatePointerCast(rawAdjustedExn, PtrTy),
                         LLVMCatchTy, caughtExnAlignment);
     LValue Dest = CGF.MakeAddrLValue(ParamAddr, CatchType);
     LValue Src = CGF.MakeAddrLValue(adjustedExn, CatchType);
@@ -4677,7 +4677,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
     CGF.EmitNounwindRuntimeCall(getGetExceptionPtrFn(CGF.CGM), Exn);
 
   // Cast that to the appropriate type.
-  Address adjustedExn(CGF.Builder.CreateBitCast(rawAdjustedExn, PtrTy),
+  Address adjustedExn(CGF.Builder.CreatePointerCast(rawAdjustedExn, PtrTy),
                       LLVMCatchTy, caughtExnAlignment);
 
   // The copy expression is defined in terms of an OpaqueValueExpr.

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Jun 4, 2024
@jrtc27
Copy link
Collaborator

jrtc27 commented Jun 4, 2024

I don't think that assumption is currently true. I think it's also worth clarifying what this thing is, and possibly renaming it, because "unqualified" has C language level meaning that would contradict what it is here.

@efriedma-quic
Copy link
Collaborator

llvm::PointerType::getUnqual assumes pointers to addr-space 0 are "unqualified"... but the discussion on #88182 concluded that doesn't make sense: the "unqualified" address space is a target-specific choice, and address-space zero isn't required to have any meaning at all.

Given that, it seems like this is going in the opposite direction of what you want.

@jrtc27
Copy link
Collaborator

jrtc27 commented Jun 5, 2024

I think the point is there are two things going on here that people think of as unqualified:

  1. "Give me a pointer that's whatever void * is"
  2. "Give me a pointer in some address space just so I can put a global in some metadata"

The vast majority of the time we're talking about 1, which is what most people would think of unqualified as meaning. #93601 / #93914 are about the three special cases that are case 2 above. But those are a special case, and normally when people say unqualified they mean "default" address space / void *.

@AlexVlx
Copy link
Contributor Author

AlexVlx commented Jun 5, 2024

I think the point is there are two things going on here that people think of as unqualified:

  1. "Give me a pointer that's whatever void * is"
  2. "Give me a pointer in some address space just so I can put a global in some metadata"

The vast majority of the time we're talking about 1, which is what most people would think of unqualified as meaning. #93601 / #93914 are about the three special cases that are case 2 above. But those are a special case, and normally when people say unqualified they mean "default" address space / void *.

Building on the above, let me add a bit more colour I should have added from the get go:

  • More often than not, for case (1) above, folks probably want (knowingly or not) a void* that "works",
    with no actual concern for the address space (the "default");
  • As an example, for targets which model themselves / draw inspiration from e.g. OpenCL, this'd be a
    generic / flat pointer, but there's no way for the FE to query that from the target (today?), and that
    information isn't really observably encoded in something like the DataLayout; if we were to add
    something like that, then unqualified would / should correspond to this, IMHO (could well happen to be 0
    in practice);
  • We have targets that map LangAS::Defaultoddly / differently from the above expectation, and hence it
    appeared profitable to have UnqualPtrTy, which is a generally useful / everywhere usable pointer type,
    be different from Int8PtrTy / VoidPtrTy which are pointer types which correspond to the target's
    default (perhaps I am being overly cautious here though).

Having said that, this change is somewhat inert at the moment beyond carving out the name / making it shorthand for calling getUnqual(). In the future, we could either:

  • extend DL to expose a target's flat/generic AS
  • (more intrusive / might be infeasible) make unqualified ptrs be generic/everywhere usable in IR, without
    the target exposing a flat/generic AS, letting the target figure out the legality of e.g. this or that ascast.

Copy link
Contributor Author

@AlexVlx AlexVlx left a comment

Choose a reason for hiding this comment

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

I don't think that assumption is currently true. I think it's also worth clarifying what this thing is, and possibly renaming it, because "unqualified" has C language level meaning that would contradict what it is here.

It's probably optimistic, based on us also having Int8PtrTy / VoidPtrTy which seem less "scary" (for lack of a better word) and more familiar for someone coming from e.g. C. In what regards renaming, I don't have an immediate idea of what to rename it to, and it's tied to PointerType::getUnqual, so if we rename this we'd probably have to rename that as well, no?

@@ -4656,14 +4656,14 @@ static void InitCatchParam(CodeGenFunction &CGF,
auto catchRD = CatchType->getAsCXXRecordDecl();
CharUnits caughtExnAlignment = CGF.CGM.getClassPointerAlignment(catchRD);

llvm::Type *PtrTy = CGF.UnqualPtrTy; // addrspace 0 ok
Copy link
Member

Choose a reason for hiding this comment

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

I am not convinced this is actually correct, it's been a long time since I looked at C++ exception handling, but I would have assumed this to either be a stack variable or a global?

Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be a pointer to a heap-allocated object.

In any case, we shouldn't need to cast the return value of __cxa_begin_catch to a different address-space; we can just drop the bitcasts.

@@ -51,9 +51,11 @@ struct CodeGenTypeCache {
llvm::IntegerType *PtrDiffTy;
};

/// unqualified void*
llvm::PointerType *UnqualPtrTy;
Copy link
Member

Choose a reason for hiding this comment

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

I'd argue we should just remove this variable, and the few cases that actually want AS0 can call PointerType::get(0) directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not opposed to this in principle; might have some additional benefits in that it forces people to knowingly opt for something via PointerType::getUnqual / PointerType::get(some_as), rather than accidentally stumbling into it.

Copy link
Member

@arichardson arichardson left a comment

Choose a reason for hiding this comment

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

This looks fine to me now, but I'd suggest a TODO comment that UnqualPtrTy should be removed in the future.

@jrtc27
Copy link
Collaborator

jrtc27 commented Jun 8, 2024

There are still quite a few references to UnqualPtrTy that you're not changing yet are now wrong, no?

$ git grep --count '\<UnqualPtrTy\>' origin/main clang
origin/main:clang/lib/CodeGen/CGAtomic.cpp:1
origin/main:clang/lib/CodeGen/CGBlocks.cpp:1
origin/main:clang/lib/CodeGen/CGBuiltin.cpp:13
origin/main:clang/lib/CodeGen/CGCUDANV.cpp:1
origin/main:clang/lib/CodeGen/CGExpr.cpp:2
origin/main:clang/lib/CodeGen/CGObjCMac.cpp:1
origin/main:clang/lib/CodeGen/CodeGenTypeCache.h:1
origin/main:clang/lib/CodeGen/ItaniumCXXABI.cpp:10
origin/main:clang/lib/CodeGen/Targets/PPC.cpp:1
origin/main:clang/lib/CodeGen/Targets/Sparc.cpp:1

@jrtc27
Copy link
Collaborator

jrtc27 commented Jun 8, 2024

And I still strongly urge renaming what this is, given it is not the type for an unqualified C void *, as one would normally expect given it's in Clang. Perhaps DummyPtrTy?

Copy link
Member

@arichardson arichardson left a comment

Choose a reason for hiding this comment

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

Ah I did not realize there were so many uses remaining. I that case those probably need auditing/changing before this change can land.

@AlexVlx
Copy link
Contributor Author

AlexVlx commented Jun 8, 2024

And I still strongly urge renaming what this is, given it is not the type for an unqualified C void *, as one would normally expect given it's in Clang. Perhaps DummyPtrTy?

DummyPtrTy seems mnemonic / on point, but it might trigger antibodies from the LLVM side:) Perhaps NoAddrSpacePtrTy or something to that extent? What makes this unqualified is it being just a ptr and not a ptr addrspace(n). On the other hand, since today it's an unconditional alias for ptr addrspace(0), perhaps AS0PtrTy or somesuch thing could also work?

@AlexVlx
Copy link
Contributor Author

AlexVlx commented Jun 8, 2024

There are still quite a few references to UnqualPtrTy that you're not changing yet are now wrong, no?

$ git grep --count '\<UnqualPtrTy\>' origin/main clang
origin/main:clang/lib/CodeGen/CGAtomic.cpp:1
origin/main:clang/lib/CodeGen/CGBlocks.cpp:1
origin/main:clang/lib/CodeGen/CGBuiltin.cpp:13
origin/main:clang/lib/CodeGen/CGCUDANV.cpp:1
origin/main:clang/lib/CodeGen/CGExpr.cpp:2
origin/main:clang/lib/CodeGen/CGObjCMac.cpp:1
origin/main:clang/lib/CodeGen/CodeGenTypeCache.h:1
origin/main:clang/lib/CodeGen/ItaniumCXXABI.cpp:10
origin/main:clang/lib/CodeGen/Targets/PPC.cpp:1
origin/main:clang/lib/CodeGen/Targets/Sparc.cpp:1

Right, going through these at the moment, I got sidetracked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants