2023-05-09 18:55:59 +03:00
|
|
|
//===- ABIInfoImpl.cpp ----------------------------------------------------===//
|
|
|
|
|
//
|
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "ABIInfoImpl.h"
|
|
|
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
|
using namespace clang::CodeGen;
|
|
|
|
|
|
|
|
|
|
// Pin the vtable to this file.
|
|
|
|
|
DefaultABIInfo::~DefaultABIInfo() = default;
|
|
|
|
|
|
|
|
|
|
ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const {
|
|
|
|
|
Ty = useFirstFieldIfTransparentUnion(Ty);
|
|
|
|
|
|
|
|
|
|
if (isAggregateTypeForABI(Ty)) {
|
|
|
|
|
// Records with non-trivial destructors/copy-constructors should not be
|
|
|
|
|
// passed by value.
|
|
|
|
|
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI()))
|
[clang][CodeGen] `sret` args should always point to the `alloca` AS, so use that (#114062)
`sret` arguments are always going to reside in the stack/`alloca`
address space, which makes the current formulation where their AS is
derived from the pointee somewhat quaint. This patch ensures that `sret`
ends up pointing to the `alloca` AS in IR function signatures, and also
guards agains trying to pass a casted `alloca`d pointer to a `sret` arg,
which can happen for most languages, when compiled for targets that have
a non-zero `alloca` AS (e.g. AMDGCN) / map `LangAS::default` to a
non-zero value (SPIR-V). A target could still choose to do something
different here, by e.g. overriding `classifyReturnType` behaviour.
In a broader sense, this patch extends non-aliased indirect args to also
carry an AS, which leads to changing the `getIndirect()` interface. At
the moment we're only using this for (indirect) returns, but it allows
for future handling of indirect args themselves. We default to using the
AllocaAS as that matches what Clang is currently doing, however if, in
the future, a target would opt for e.g. placing indirect returns in some
other storage, with another AS, this will require revisiting.
---------
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
Co-authored-by: Matt Arsenault <Matthew.Arsenault@amd.com>
2025-02-14 11:20:45 +00:00
|
|
|
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
|
|
|
|
|
RAA == CGCXXABI::RAA_DirectInMemory);
|
2023-05-09 18:55:59 +03:00
|
|
|
|
[clang][CodeGen] `sret` args should always point to the `alloca` AS, so use that (#114062)
`sret` arguments are always going to reside in the stack/`alloca`
address space, which makes the current formulation where their AS is
derived from the pointee somewhat quaint. This patch ensures that `sret`
ends up pointing to the `alloca` AS in IR function signatures, and also
guards agains trying to pass a casted `alloca`d pointer to a `sret` arg,
which can happen for most languages, when compiled for targets that have
a non-zero `alloca` AS (e.g. AMDGCN) / map `LangAS::default` to a
non-zero value (SPIR-V). A target could still choose to do something
different here, by e.g. overriding `classifyReturnType` behaviour.
In a broader sense, this patch extends non-aliased indirect args to also
carry an AS, which leads to changing the `getIndirect()` interface. At
the moment we're only using this for (indirect) returns, but it allows
for future handling of indirect args themselves. We default to using the
AllocaAS as that matches what Clang is currently doing, however if, in
the future, a target would opt for e.g. placing indirect returns in some
other storage, with another AS, this will require revisiting.
---------
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
Co-authored-by: Matt Arsenault <Matthew.Arsenault@amd.com>
2025-02-14 11:20:45 +00:00
|
|
|
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Treat an enum type as its underlying type.
|
2025-08-26 16:05:59 -03:00
|
|
|
if (const auto *ED = Ty->getAsEnumDecl())
|
|
|
|
|
Ty = ED->getIntegerType();
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
ASTContext &Context = getContext();
|
|
|
|
|
if (const auto *EIT = Ty->getAs<BitIntType>())
|
|
|
|
|
if (EIT->getNumBits() >
|
|
|
|
|
Context.getTypeSize(Context.getTargetInfo().hasInt128Type()
|
|
|
|
|
? Context.Int128Ty
|
|
|
|
|
: Context.LongLongTy))
|
[clang][CodeGen] `sret` args should always point to the `alloca` AS, so use that (#114062)
`sret` arguments are always going to reside in the stack/`alloca`
address space, which makes the current formulation where their AS is
derived from the pointee somewhat quaint. This patch ensures that `sret`
ends up pointing to the `alloca` AS in IR function signatures, and also
guards agains trying to pass a casted `alloca`d pointer to a `sret` arg,
which can happen for most languages, when compiled for targets that have
a non-zero `alloca` AS (e.g. AMDGCN) / map `LangAS::default` to a
non-zero value (SPIR-V). A target could still choose to do something
different here, by e.g. overriding `classifyReturnType` behaviour.
In a broader sense, this patch extends non-aliased indirect args to also
carry an AS, which leads to changing the `getIndirect()` interface. At
the moment we're only using this for (indirect) returns, but it allows
for future handling of indirect args themselves. We default to using the
AllocaAS as that matches what Clang is currently doing, however if, in
the future, a target would opt for e.g. placing indirect returns in some
other storage, with another AS, this will require revisiting.
---------
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
Co-authored-by: Matt Arsenault <Matthew.Arsenault@amd.com>
2025-02-14 11:20:45 +00:00
|
|
|
return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace());
|
2023-05-09 18:55:59 +03:00
|
|
|
|
2024-08-19 12:17:44 -04:00
|
|
|
return (isPromotableIntegerTypeForABI(Ty)
|
|
|
|
|
? ABIArgInfo::getExtend(Ty, CGT.ConvertType(Ty))
|
|
|
|
|
: ABIArgInfo::getDirect());
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const {
|
|
|
|
|
if (RetTy->isVoidType())
|
|
|
|
|
return ABIArgInfo::getIgnore();
|
|
|
|
|
|
|
|
|
|
if (isAggregateTypeForABI(RetTy))
|
[clang][CodeGen] `sret` args should always point to the `alloca` AS, so use that (#114062)
`sret` arguments are always going to reside in the stack/`alloca`
address space, which makes the current formulation where their AS is
derived from the pointee somewhat quaint. This patch ensures that `sret`
ends up pointing to the `alloca` AS in IR function signatures, and also
guards agains trying to pass a casted `alloca`d pointer to a `sret` arg,
which can happen for most languages, when compiled for targets that have
a non-zero `alloca` AS (e.g. AMDGCN) / map `LangAS::default` to a
non-zero value (SPIR-V). A target could still choose to do something
different here, by e.g. overriding `classifyReturnType` behaviour.
In a broader sense, this patch extends non-aliased indirect args to also
carry an AS, which leads to changing the `getIndirect()` interface. At
the moment we're only using this for (indirect) returns, but it allows
for future handling of indirect args themselves. We default to using the
AllocaAS as that matches what Clang is currently doing, however if, in
the future, a target would opt for e.g. placing indirect returns in some
other storage, with another AS, this will require revisiting.
---------
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
Co-authored-by: Matt Arsenault <Matthew.Arsenault@amd.com>
2025-02-14 11:20:45 +00:00
|
|
|
return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace());
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
// Treat an enum type as its underlying type.
|
2025-08-26 16:05:59 -03:00
|
|
|
if (const auto *ED = RetTy->getAsEnumDecl())
|
|
|
|
|
RetTy = ED->getIntegerType();
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
if (const auto *EIT = RetTy->getAs<BitIntType>())
|
|
|
|
|
if (EIT->getNumBits() >
|
|
|
|
|
getContext().getTypeSize(getContext().getTargetInfo().hasInt128Type()
|
|
|
|
|
? getContext().Int128Ty
|
|
|
|
|
: getContext().LongLongTy))
|
[clang][CodeGen] `sret` args should always point to the `alloca` AS, so use that (#114062)
`sret` arguments are always going to reside in the stack/`alloca`
address space, which makes the current formulation where their AS is
derived from the pointee somewhat quaint. This patch ensures that `sret`
ends up pointing to the `alloca` AS in IR function signatures, and also
guards agains trying to pass a casted `alloca`d pointer to a `sret` arg,
which can happen for most languages, when compiled for targets that have
a non-zero `alloca` AS (e.g. AMDGCN) / map `LangAS::default` to a
non-zero value (SPIR-V). A target could still choose to do something
different here, by e.g. overriding `classifyReturnType` behaviour.
In a broader sense, this patch extends non-aliased indirect args to also
carry an AS, which leads to changing the `getIndirect()` interface. At
the moment we're only using this for (indirect) returns, but it allows
for future handling of indirect args themselves. We default to using the
AllocaAS as that matches what Clang is currently doing, however if, in
the future, a target would opt for e.g. placing indirect returns in some
other storage, with another AS, this will require revisiting.
---------
Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
Co-authored-by: Matt Arsenault <Matthew.Arsenault@amd.com>
2025-02-14 11:20:45 +00:00
|
|
|
return getNaturalAlignIndirect(RetTy,
|
|
|
|
|
getDataLayout().getAllocaAddrSpace());
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
return (isPromotableIntegerTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy)
|
|
|
|
|
: ABIArgInfo::getDirect());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
|
|
|
|
if (!getCXXABI().classifyReturnType(FI))
|
|
|
|
|
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
|
|
|
|
|
for (auto &I : FI.arguments())
|
|
|
|
|
I.info = classifyArgumentType(I.type);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-17 14:29:20 +03:00
|
|
|
RValue DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
|
|
|
QualType Ty, AggValueSlot Slot) const {
|
|
|
|
|
return CGF.EmitLoadOfAnyValue(
|
|
|
|
|
CGF.MakeAddrLValue(
|
|
|
|
|
EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)), Ty),
|
|
|
|
|
Slot);
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CodeGen::AssignToArrayRange(CodeGen::CGBuilderTy &Builder,
|
|
|
|
|
llvm::Value *Array, llvm::Value *Value,
|
|
|
|
|
unsigned FirstIndex, unsigned LastIndex) {
|
|
|
|
|
// Alternatively, we could emit this as a loop in the source.
|
|
|
|
|
for (unsigned I = FirstIndex; I <= LastIndex; ++I) {
|
|
|
|
|
llvm::Value *Cell =
|
|
|
|
|
Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I);
|
|
|
|
|
Builder.CreateAlignedStore(Value, Cell, CharUnits::One());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::isAggregateTypeForABI(QualType T) {
|
|
|
|
|
return !CodeGenFunction::hasScalarEvaluationKind(T) ||
|
|
|
|
|
T->isMemberFunctionPointerType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) {
|
|
|
|
|
return CGF.ConvertTypeForMem(
|
|
|
|
|
CGF.getContext().getBuiltinVaListType()->getPointeeType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT,
|
|
|
|
|
CGCXXABI &CXXABI) {
|
[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in
the AST.
* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.
This patch offers a great performance benefit.
It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.
This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.
The rest and bulk of the changes are mostly consequences of the changes
in API.
PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.
Fixes #136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-09 05:06:53 -03:00
|
|
|
const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
|
|
|
|
|
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
|
|
|
|
|
return CXXABI.getRecordArgABI(CXXRD);
|
|
|
|
|
if (!RD->canPassInRegisters())
|
|
|
|
|
return CGCXXABI::RAA_Indirect;
|
|
|
|
|
return CGCXXABI::RAA_Default;
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) {
|
2025-08-27 06:20:14 -03:00
|
|
|
const RecordType *RT = T->getAsCanonical<RecordType>();
|
2023-05-09 18:55:59 +03:00
|
|
|
if (!RT)
|
|
|
|
|
return CGCXXABI::RAA_Default;
|
|
|
|
|
return getRecordArgABI(RT, CXXABI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI,
|
|
|
|
|
const ABIInfo &Info) {
|
|
|
|
|
QualType Ty = FI.getReturnType();
|
|
|
|
|
|
2025-08-25 20:18:56 -03:00
|
|
|
if (const auto *RD = Ty->getAsRecordDecl();
|
|
|
|
|
RD && !isa<CXXRecordDecl>(RD) && !RD->canPassInRegisters()) {
|
|
|
|
|
FI.getReturnInfo() = Info.getNaturalAlignIndirect(
|
|
|
|
|
Ty, Info.getDataLayout().getAllocaAddrSpace());
|
|
|
|
|
return true;
|
[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in
the AST.
* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.
This patch offers a great performance benefit.
It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.
This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.
The rest and bulk of the changes are mostly consequences of the changes
in API.
PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.
Fixes #136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-09 05:06:53 -03:00
|
|
|
}
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
return CXXABI.classifyReturnType(FI);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) {
|
|
|
|
|
if (const RecordType *UT = Ty->getAsUnionType()) {
|
[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in
the AST.
* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.
This patch offers a great performance benefit.
It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.
This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.
The rest and bulk of the changes are mostly consequences of the changes
in API.
PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.
Fixes #136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-09 05:06:53 -03:00
|
|
|
const RecordDecl *UD = UT->getOriginalDecl()->getDefinitionOrSelf();
|
2023-05-09 18:55:59 +03:00
|
|
|
if (UD->hasAttr<TransparentUnionAttr>()) {
|
|
|
|
|
assert(!UD->field_empty() && "sema created an empty transparent union");
|
|
|
|
|
return UD->field_begin()->getType();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::Value *CodeGen::emitRoundPointerUpToAlignment(CodeGenFunction &CGF,
|
|
|
|
|
llvm::Value *Ptr,
|
|
|
|
|
CharUnits Align) {
|
|
|
|
|
// OverflowArgArea = (OverflowArgArea + Align - 1) & -Align;
|
|
|
|
|
llvm::Value *RoundUp = CGF.Builder.CreateConstInBoundsGEP1_32(
|
|
|
|
|
CGF.Builder.getInt8Ty(), Ptr, Align.getQuantity() - 1);
|
|
|
|
|
return CGF.Builder.CreateIntrinsic(
|
2024-04-18 22:36:01 +01:00
|
|
|
llvm::Intrinsic::ptrmask, {Ptr->getType(), CGF.IntPtrTy},
|
2023-05-09 18:55:59 +03:00
|
|
|
{RoundUp, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())},
|
|
|
|
|
nullptr, Ptr->getName() + ".aligned");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Address
|
|
|
|
|
CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
|
|
|
llvm::Type *DirectTy, CharUnits DirectSize,
|
|
|
|
|
CharUnits DirectAlign, CharUnits SlotSize,
|
|
|
|
|
bool AllowHigherAlign, bool ForceRightAdjust) {
|
|
|
|
|
// Cast the element type to i8* if necessary. Some platforms define
|
|
|
|
|
// va_list as a struct containing an i8* instead of just an i8*.
|
|
|
|
|
if (VAListAddr.getElementType() != CGF.Int8PtrTy)
|
2023-06-30 17:33:28 -04:00
|
|
|
VAListAddr = VAListAddr.withElementType(CGF.Int8PtrTy);
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur");
|
|
|
|
|
|
|
|
|
|
// If the CC aligns values higher than the slot size, do so if needed.
|
|
|
|
|
Address Addr = Address::invalid();
|
|
|
|
|
if (AllowHigherAlign && DirectAlign > SlotSize) {
|
|
|
|
|
Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign),
|
|
|
|
|
CGF.Int8Ty, DirectAlign);
|
|
|
|
|
} else {
|
|
|
|
|
Addr = Address(Ptr, CGF.Int8Ty, SlotSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advance the pointer past the argument, then store that back.
|
|
|
|
|
CharUnits FullDirectSize = DirectSize.alignTo(SlotSize);
|
|
|
|
|
Address NextPtr =
|
|
|
|
|
CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next");
|
[CodeGen][arm64e] Add methods and data members to Address, which are needed to authenticate signed pointers (#86923)
To authenticate pointers, CodeGen needs access to the key and
discriminators that were used to sign the pointer. That information is
sometimes known from the context, but not always, which is why `Address`
needs to hold that information.
This patch adds methods and data members to `Address`, which will be
needed in subsequent patches to authenticate signed pointers, and uses
the newly added methods throughout CodeGen. Although this patch isn't
strictly NFC as it causes CodeGen to use different code paths in some
cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any
changes in functionality as it doesn't add any information needed for
authentication.
In addition to the changes mentioned above, this patch introduces class
`RawAddress`, which contains a pointer that we know is unsigned, and
adds several new functions for creating `Address` and `LValue` objects.
This reapplies d9a685a9dd589486e882b722e513ee7b8c84870c, which was
reverted because it broke ubsan bots. There seems to be a bug in
coroutine code-gen, which is causing EmitTypeCheck to use the wrong
alignment. For now, pass alignment zero to EmitTypeCheck so that it can
compute the correct alignment based on the passed type (see function
EmitCXXMemberOrOperatorMemberCallExpr).
2024-03-28 06:54:36 -07:00
|
|
|
CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr);
|
2023-05-09 18:55:59 +03:00
|
|
|
|
|
|
|
|
// If the argument is smaller than a slot, and this is a big-endian
|
|
|
|
|
// target, the argument will be right-adjusted in its slot.
|
|
|
|
|
if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() &&
|
|
|
|
|
(!DirectTy->isStructTy() || ForceRightAdjust)) {
|
|
|
|
|
Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize);
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-30 17:33:28 -04:00
|
|
|
return Addr.withElementType(DirectTy);
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
2024-06-17 14:29:20 +03:00
|
|
|
RValue CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
|
|
|
QualType ValueTy, bool IsIndirect,
|
|
|
|
|
TypeInfoChars ValueInfo,
|
|
|
|
|
CharUnits SlotSizeAndAlign,
|
|
|
|
|
bool AllowHigherAlign, AggValueSlot Slot,
|
|
|
|
|
bool ForceRightAdjust) {
|
2023-05-09 18:55:59 +03:00
|
|
|
// The size and alignment of the value that was passed directly.
|
|
|
|
|
CharUnits DirectSize, DirectAlign;
|
|
|
|
|
if (IsIndirect) {
|
|
|
|
|
DirectSize = CGF.getPointerSize();
|
|
|
|
|
DirectAlign = CGF.getPointerAlign();
|
|
|
|
|
} else {
|
|
|
|
|
DirectSize = ValueInfo.Width;
|
|
|
|
|
DirectAlign = ValueInfo.Align;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cast the address we've calculated to the right type.
|
|
|
|
|
llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy), *ElementTy = DirectTy;
|
|
|
|
|
if (IsIndirect) {
|
|
|
|
|
unsigned AllocaAS = CGF.CGM.getDataLayout().getAllocaAddrSpace();
|
|
|
|
|
DirectTy = llvm::PointerType::get(CGF.getLLVMContext(), AllocaAS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize,
|
|
|
|
|
DirectAlign, SlotSizeAndAlign,
|
|
|
|
|
AllowHigherAlign, ForceRightAdjust);
|
|
|
|
|
|
|
|
|
|
if (IsIndirect) {
|
|
|
|
|
Addr = Address(CGF.Builder.CreateLoad(Addr), ElementTy, ValueInfo.Align);
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-17 14:29:20 +03:00
|
|
|
return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Addr, ValueTy), Slot);
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1,
|
|
|
|
|
llvm::BasicBlock *Block1, Address Addr2,
|
|
|
|
|
llvm::BasicBlock *Block2,
|
|
|
|
|
const llvm::Twine &Name) {
|
|
|
|
|
assert(Addr1.getType() == Addr2.getType());
|
|
|
|
|
llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name);
|
[CodeGen][arm64e] Add methods and data members to Address, which are needed to authenticate signed pointers (#86923)
To authenticate pointers, CodeGen needs access to the key and
discriminators that were used to sign the pointer. That information is
sometimes known from the context, but not always, which is why `Address`
needs to hold that information.
This patch adds methods and data members to `Address`, which will be
needed in subsequent patches to authenticate signed pointers, and uses
the newly added methods throughout CodeGen. Although this patch isn't
strictly NFC as it causes CodeGen to use different code paths in some
cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any
changes in functionality as it doesn't add any information needed for
authentication.
In addition to the changes mentioned above, this patch introduces class
`RawAddress`, which contains a pointer that we know is unsigned, and
adds several new functions for creating `Address` and `LValue` objects.
This reapplies d9a685a9dd589486e882b722e513ee7b8c84870c, which was
reverted because it broke ubsan bots. There seems to be a bug in
coroutine code-gen, which is causing EmitTypeCheck to use the wrong
alignment. For now, pass alignment zero to EmitTypeCheck so that it can
compute the correct alignment based on the passed type (see function
EmitCXXMemberOrOperatorMemberCallExpr).
2024-03-28 06:54:36 -07:00
|
|
|
PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1);
|
|
|
|
|
PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2);
|
2023-05-09 18:55:59 +03:00
|
|
|
CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment());
|
|
|
|
|
return Address(PHI, Addr1.getElementType(), Align);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD,
|
2023-08-07 10:42:45 +01:00
|
|
|
bool AllowArrays, bool AsIfNoUniqueAddr) {
|
2024-04-18 07:39:29 +02:00
|
|
|
if (FD->isUnnamedBitField())
|
2023-05-09 18:55:59 +03:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
QualType FT = FD->getType();
|
|
|
|
|
|
|
|
|
|
// Constant arrays of empty records count as empty, strip them off.
|
|
|
|
|
// Constant arrays of zero length always count as empty.
|
|
|
|
|
bool WasArray = false;
|
|
|
|
|
if (AllowArrays)
|
|
|
|
|
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
|
2024-03-26 14:15:56 -05:00
|
|
|
if (AT->isZeroSize())
|
2023-05-09 18:55:59 +03:00
|
|
|
return true;
|
|
|
|
|
FT = AT->getElementType();
|
|
|
|
|
// The [[no_unique_address]] special case below does not apply to
|
|
|
|
|
// arrays of C++ empty records, so we need to remember this fact.
|
|
|
|
|
WasArray = true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 06:20:14 -03:00
|
|
|
const RecordType *RT = FT->getAsCanonical<RecordType>();
|
2023-05-09 18:55:59 +03:00
|
|
|
if (!RT)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// C++ record fields are never empty, at least in the Itanium ABI.
|
|
|
|
|
//
|
|
|
|
|
// FIXME: We should use a predicate for whether this behavior is true in the
|
|
|
|
|
// current ABI.
|
|
|
|
|
//
|
|
|
|
|
// The exception to the above rule are fields marked with the
|
|
|
|
|
// [[no_unique_address]] attribute (since C++20). Those do count as empty
|
|
|
|
|
// according to the Itanium ABI. The exception applies only to records,
|
|
|
|
|
// not arrays of records, so we must also check whether we stripped off an
|
|
|
|
|
// array type above.
|
[clang] Improve nested name specifier AST representation (#147835)
This is a major change on how we represent nested name qualifications in
the AST.
* The nested name specifier itself and how it's stored is changed. The
prefixes for types are handled within the type hierarchy, which makes
canonicalization for them super cheap, no memory allocation required.
Also translating a type into nested name specifier form becomes a no-op.
An identifier is stored as a DependentNameType. The nested name
specifier gains a lightweight handle class, to be used instead of
passing around pointers, which is similar to what is implemented for
TemplateName. There is still one free bit available, and this handle can
be used within a PointerUnion and PointerIntPair, which should keep
bit-packing aficionados happy.
* The ElaboratedType node is removed, all type nodes in which it could
previously apply to can now store the elaborated keyword and name
qualifier, tail allocating when present.
* TagTypes can now point to the exact declaration found when producing
these, as opposed to the previous situation of there only existing one
TagType per entity. This increases the amount of type sugar retained,
and can have several applications, for example in tracking module
ownership, and other tools which care about source file origins, such as
IWYU. These TagTypes are lazily allocated, in order to limit the
increase in AST size.
This patch offers a great performance benefit.
It greatly improves compilation time for
[stdexec](https://github.com/NVIDIA/stdexec). For one datapoint, for
`test_on2.cpp` in that project, which is the slowest compiling test,
this patch improves `-c` compilation time by about 7.2%, with the
`-fsyntax-only` improvement being at ~12%.
This has great results on compile-time-tracker as well:

This patch also further enables other optimziations in the future, and
will reduce the performance impact of template specialization resugaring
when that lands.
It has some other miscelaneous drive-by fixes.
About the review: Yes the patch is huge, sorry about that. Part of the
reason is that I started by the nested name specifier part, before the
ElaboratedType part, but that had a huge performance downside, as
ElaboratedType is a big performance hog. I didn't have the steam to go
back and change the patch after the fact.
There is also a lot of internal API changes, and it made sense to remove
ElaboratedType in one go, versus removing it from one type at a time, as
that would present much more churn to the users. Also, the nested name
specifier having a different API avoids missing changes related to how
prefixes work now, which could make existing code compile but not work.
How to review: The important changes are all in
`clang/include/clang/AST` and `clang/lib/AST`, with also important
changes in `clang/lib/Sema/TreeTransform.h`.
The rest and bulk of the changes are mostly consequences of the changes
in API.
PS: TagType::getDecl is renamed to `getOriginalDecl` in this patch, just
for easier to rebasing. I plan to rename it back after this lands.
Fixes #136624
Fixes https://github.com/llvm/llvm-project/issues/43179
Fixes https://github.com/llvm/llvm-project/issues/68670
Fixes https://github.com/llvm/llvm-project/issues/92757
2025-08-09 05:06:53 -03:00
|
|
|
if (isa<CXXRecordDecl>(RT->getOriginalDecl()) &&
|
2023-08-07 10:42:45 +01:00
|
|
|
(WasArray || (!AsIfNoUniqueAddr && !FD->hasAttr<NoUniqueAddressAttr>())))
|
2023-05-09 18:55:59 +03:00
|
|
|
return false;
|
|
|
|
|
|
2023-08-07 10:42:45 +01:00
|
|
|
return isEmptyRecord(Context, FT, AllowArrays, AsIfNoUniqueAddr);
|
2023-05-09 18:55:59 +03:00
|
|
|
}
|
|
|
|
|
|
2023-08-07 10:42:45 +01:00
|
|
|
bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays,
|
|
|
|
|
bool AsIfNoUniqueAddr) {
|
2025-08-25 20:18:56 -03:00
|
|
|
const auto *RD = T->getAsRecordDecl();
|
|
|
|
|
if (!RD)
|
2023-05-09 18:55:59 +03:00
|
|
|
return false;
|
|
|
|
|
if (RD->hasFlexibleArrayMember())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// If this is a C++ record, check the bases first.
|
|
|
|
|
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
|
|
|
|
|
for (const auto &I : CXXRD->bases())
|
2023-08-07 10:42:45 +01:00
|
|
|
if (!isEmptyRecord(Context, I.getType(), true, AsIfNoUniqueAddr))
|
2023-05-09 18:55:59 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (const auto *I : RD->fields())
|
2023-08-07 10:42:45 +01:00
|
|
|
if (!isEmptyField(Context, I, AllowArrays, AsIfNoUniqueAddr))
|
2023-05-09 18:55:59 +03:00
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-16 04:59:51 +01:00
|
|
|
bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context,
|
|
|
|
|
const FieldDecl *FD) {
|
2025-01-11 07:12:37 +01:00
|
|
|
if (FD->isZeroLengthBitField())
|
2024-07-16 04:59:51 +01:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (FD->isUnnamedBitField())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return isEmptyRecordForLayout(Context, FD->getType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) {
|
2025-08-25 20:18:56 -03:00
|
|
|
const auto *RD = T->getAsRecordDecl();
|
|
|
|
|
if (!RD)
|
2024-07-16 04:59:51 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// If this is a C++ record, check the bases first.
|
|
|
|
|
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
|
|
|
|
if (CXXRD->isDynamicClass())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (const auto &I : CXXRD->bases())
|
|
|
|
|
if (!isEmptyRecordForLayout(Context, I.getType()))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto *I : RD->fields())
|
|
|
|
|
if (!isEmptyFieldForLayout(Context, I))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-09 18:55:59 +03:00
|
|
|
const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) {
|
2025-08-25 20:18:56 -03:00
|
|
|
const auto *RD = T->getAsRecordDecl();
|
|
|
|
|
if (!RD)
|
2023-05-09 18:55:59 +03:00
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
if (RD->hasFlexibleArrayMember())
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
const Type *Found = nullptr;
|
|
|
|
|
|
|
|
|
|
// If this is a C++ record, check the bases first.
|
|
|
|
|
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
|
|
|
|
for (const auto &I : CXXRD->bases()) {
|
|
|
|
|
// Ignore empty records.
|
|
|
|
|
if (isEmptyRecord(Context, I.getType(), true))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// If we already found an element then this isn't a single-element struct.
|
|
|
|
|
if (Found)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
// If this is non-empty and not a single element struct, the composite
|
|
|
|
|
// cannot be a single element struct.
|
|
|
|
|
Found = isSingleElementStruct(I.getType(), Context);
|
|
|
|
|
if (!Found)
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for single element.
|
|
|
|
|
for (const auto *FD : RD->fields()) {
|
|
|
|
|
QualType FT = FD->getType();
|
|
|
|
|
|
|
|
|
|
// Ignore empty fields.
|
|
|
|
|
if (isEmptyField(Context, FD, true))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// If we already found an element then this isn't a single-element
|
|
|
|
|
// struct.
|
|
|
|
|
if (Found)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
// Treat single element arrays as the element.
|
|
|
|
|
while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
|
2024-03-26 14:15:56 -05:00
|
|
|
if (AT->getZExtSize() != 1)
|
2023-05-09 18:55:59 +03:00
|
|
|
break;
|
|
|
|
|
FT = AT->getElementType();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isAggregateTypeForABI(FT)) {
|
|
|
|
|
Found = FT.getTypePtr();
|
|
|
|
|
} else {
|
|
|
|
|
Found = isSingleElementStruct(FT, Context);
|
|
|
|
|
if (!Found)
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't consider a struct a single-element struct if it has
|
|
|
|
|
// padding beyond the element type.
|
|
|
|
|
if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T))
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
return Found;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr,
|
|
|
|
|
QualType Ty, const ABIArgInfo &AI) {
|
|
|
|
|
// This default implementation defers to the llvm backend's va_arg
|
|
|
|
|
// instruction. It can handle only passing arguments directly
|
|
|
|
|
// (typically only handled in the backend for primitive types), or
|
|
|
|
|
// aggregates passed indirectly by pointer (NOTE: if the "byval"
|
|
|
|
|
// flag has ABI impact in the callee, this implementation cannot
|
|
|
|
|
// work.)
|
|
|
|
|
|
|
|
|
|
// Only a few cases are covered here at the moment -- those needed
|
|
|
|
|
// by the default abi.
|
|
|
|
|
llvm::Value *Val;
|
|
|
|
|
|
|
|
|
|
if (AI.isIndirect()) {
|
|
|
|
|
assert(!AI.getPaddingType() &&
|
|
|
|
|
"Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
assert(
|
|
|
|
|
!AI.getIndirectRealign() &&
|
|
|
|
|
"Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
|
|
|
|
|
auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty);
|
|
|
|
|
CharUnits TyAlignForABI = TyInfo.Align;
|
|
|
|
|
|
|
|
|
|
llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty);
|
2025-03-03 23:00:32 +01:00
|
|
|
llvm::Type *BaseTy = llvm::PointerType::getUnqual(CGF.getLLVMContext());
|
2023-05-09 18:55:59 +03:00
|
|
|
llvm::Value *Addr =
|
[CodeGen][arm64e] Add methods and data members to Address, which are needed to authenticate signed pointers (#86923)
To authenticate pointers, CodeGen needs access to the key and
discriminators that were used to sign the pointer. That information is
sometimes known from the context, but not always, which is why `Address`
needs to hold that information.
This patch adds methods and data members to `Address`, which will be
needed in subsequent patches to authenticate signed pointers, and uses
the newly added methods throughout CodeGen. Although this patch isn't
strictly NFC as it causes CodeGen to use different code paths in some
cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any
changes in functionality as it doesn't add any information needed for
authentication.
In addition to the changes mentioned above, this patch introduces class
`RawAddress`, which contains a pointer that we know is unsigned, and
adds several new functions for creating `Address` and `LValue` objects.
This reapplies d9a685a9dd589486e882b722e513ee7b8c84870c, which was
reverted because it broke ubsan bots. There seems to be a bug in
coroutine code-gen, which is causing EmitTypeCheck to use the wrong
alignment. For now, pass alignment zero to EmitTypeCheck so that it can
compute the correct alignment based on the passed type (see function
EmitCXXMemberOrOperatorMemberCallExpr).
2024-03-28 06:54:36 -07:00
|
|
|
CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy);
|
2023-05-09 18:55:59 +03:00
|
|
|
return Address(Addr, ElementTy, TyAlignForABI);
|
|
|
|
|
} else {
|
|
|
|
|
assert((AI.isDirect() || AI.isExtend()) &&
|
|
|
|
|
"Unexpected ArgInfo Kind in generic VAArg emitter!");
|
|
|
|
|
|
|
|
|
|
assert(!AI.getInReg() &&
|
|
|
|
|
"Unexpected InReg seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
assert(!AI.getPaddingType() &&
|
|
|
|
|
"Unexpected PaddingType seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
assert(!AI.getDirectOffset() &&
|
|
|
|
|
"Unexpected DirectOffset seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
assert(!AI.getCoerceToType() &&
|
|
|
|
|
"Unexpected CoerceToType seen in arginfo in generic VAArg emitter!");
|
|
|
|
|
|
|
|
|
|
Address Temp = CGF.CreateMemTemp(Ty, "varet");
|
[CodeGen][arm64e] Add methods and data members to Address, which are needed to authenticate signed pointers (#86923)
To authenticate pointers, CodeGen needs access to the key and
discriminators that were used to sign the pointer. That information is
sometimes known from the context, but not always, which is why `Address`
needs to hold that information.
This patch adds methods and data members to `Address`, which will be
needed in subsequent patches to authenticate signed pointers, and uses
the newly added methods throughout CodeGen. Although this patch isn't
strictly NFC as it causes CodeGen to use different code paths in some
cases (e.g., `mergeAddressesInConditionalExpr`), it doesn't cause any
changes in functionality as it doesn't add any information needed for
authentication.
In addition to the changes mentioned above, this patch introduces class
`RawAddress`, which contains a pointer that we know is unsigned, and
adds several new functions for creating `Address` and `LValue` objects.
This reapplies d9a685a9dd589486e882b722e513ee7b8c84870c, which was
reverted because it broke ubsan bots. There seems to be a bug in
coroutine code-gen, which is causing EmitTypeCheck to use the wrong
alignment. For now, pass alignment zero to EmitTypeCheck so that it can
compute the correct alignment based on the passed type (see function
EmitCXXMemberOrOperatorMemberCallExpr).
2024-03-28 06:54:36 -07:00
|
|
|
Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF),
|
2023-05-09 18:55:59 +03:00
|
|
|
CGF.ConvertTypeForMem(Ty));
|
|
|
|
|
CGF.Builder.CreateStore(Val, Temp);
|
|
|
|
|
return Temp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::isSIMDVectorType(ASTContext &Context, QualType Ty) {
|
|
|
|
|
return Ty->getAs<VectorType>() && Context.getTypeSize(Ty) == 128;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CodeGen::isRecordWithSIMDVectorType(ASTContext &Context, QualType Ty) {
|
2025-08-25 20:18:56 -03:00
|
|
|
const auto *RD = Ty->getAsRecordDecl();
|
|
|
|
|
if (!RD)
|
2023-05-09 18:55:59 +03:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// If this is a C++ record, check the bases first.
|
|
|
|
|
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
|
|
|
|
|
for (const auto &I : CXXRD->bases())
|
|
|
|
|
if (!isRecordWithSIMDVectorType(Context, I.getType()))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (const auto *i : RD->fields()) {
|
|
|
|
|
QualType FT = i->getType();
|
|
|
|
|
|
|
|
|
|
if (isSIMDVectorType(Context, FT))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (isRecordWithSIMDVectorType(Context, FT))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|