32 changes: 23 additions & 9 deletions clang/lib/AST/Interp/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,15 +942,29 @@ static bool interp__builtin_atomic_lock_free(InterpState &S, CodePtr OpPC,
if (Ptr.isZero())
return returnBool(true);

QualType PointeeType = Call->getArg(1)
->IgnoreImpCasts()
->getType()
->castAs<PointerType>()
->getPointeeType();
// OK, we will inline operations on this object.
if (!PointeeType->isIncompleteType() &&
S.getCtx().getTypeAlignInChars(PointeeType) >= Size)
return returnBool(true);
if (Ptr.isIntegralPointer()) {
uint64_t IntVal = Ptr.getIntegerRepresentation();
if (APSInt(APInt(64, IntVal, false), true).isAligned(Size.getAsAlign()))
return returnBool(true);
}

const Expr *PtrArg = Call->getArg(1);
// Otherwise, check if the type's alignment against Size.
if (const auto *ICE = dyn_cast<ImplicitCastExpr>(PtrArg)) {
// Drop the potential implicit-cast to 'const volatile void*', getting
// the underlying type.
if (ICE->getCastKind() == CK_BitCast)
PtrArg = ICE->getSubExpr();
}

if (auto PtrTy = PtrArg->getType()->getAs<PointerType>()) {
QualType PointeeType = PtrTy->getPointeeType();
if (!PointeeType->isIncompleteType() &&
S.getCtx().getTypeAlignInChars(PointeeType) >= Size) {
// OK, we will inline operations on this object.
return returnBool(true);
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,8 @@ def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}

def SizelessVectorElementSize : Opcode;

def Assume : Opcode;

def ArrayDecay : Opcode;
Expand Down
43 changes: 35 additions & 8 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Pointer::Pointer(Pointer &&P)
}

Pointer::~Pointer() {
if (isIntegralPointer())
if (!isBlockPointer())
return;

if (Block *Pointee = PointeeStorage.BS.Pointee) {
Expand Down Expand Up @@ -87,6 +87,8 @@ void Pointer::operator=(const Pointer &P) {
PointeeStorage.BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
} else {
assert(false && "Unhandled storage kind");
}
Expand Down Expand Up @@ -115,6 +117,8 @@ void Pointer::operator=(Pointer &&P) {
PointeeStorage.BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
PointeeStorage.Int = P.PointeeStorage.Int;
} else if (P.isFunctionPointer()) {
PointeeStorage.Fn = P.PointeeStorage.Fn;
} else {
assert(false && "Unhandled storage kind");
}
Expand All @@ -131,6 +135,8 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
if (isFunctionPointer())
return asFunctionPointer().toAPValue(ASTCtx);

// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
Expand All @@ -149,6 +155,10 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
CharUnits Offset = CharUnits::Zero();

auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
// This shouldn't happen, but if it does, don't crash inside
// getASTRecordLayout.
if (FD->getParent()->isInvalidDecl())
return CharUnits::Zero();
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
unsigned FieldIndex = FD->getFieldIndex();
return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
Expand Down Expand Up @@ -176,18 +186,30 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
// TODO: figure out if base is virtual
bool IsVirtual = false;

// Create a path entry for the field.
const Descriptor *Desc = Ptr.getFieldDesc();
if (const auto *BaseOrMember = Desc->asDecl()) {
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
Ptr = Ptr.getBase();

if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember))
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
Ptr = Ptr.getBase();
Offset += getFieldOffset(FD);
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
IsVirtual = Ptr.isVirtualBaseClass();
Ptr = Ptr.getBase();
const Record *BaseRecord = Ptr.getRecord();

const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
cast<CXXRecordDecl>(BaseRecord->getDecl()));
if (IsVirtual)
Offset += Layout.getVBaseClassOffset(RD);
else
Offset += Layout.getBaseClassOffset(RD);

} else {
Ptr = Ptr.getBase();
}
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
continue;
}
llvm_unreachable("Invalid field type");
Expand Down Expand Up @@ -247,7 +269,7 @@ std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
}

bool Pointer::isInitialized() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;

if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
Expand Down Expand Up @@ -283,7 +305,7 @@ bool Pointer::isInitialized() const {
}

void Pointer::initialize() const {
if (isIntegralPointer())
if (!isBlockPointer())
return;

assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
Expand Down Expand Up @@ -352,10 +374,15 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {

if (A.isIntegralPointer() && B.isIntegralPointer())
return true;
if (A.isFunctionPointer() && B.isFunctionPointer())
return true;

if (A.isIntegralPointer() || B.isIntegralPointer())
return A.getSource() == B.getSource();

if (A.StorageKind != B.StorageKind)
return false;

return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
}

Expand Down
45 changes: 36 additions & 9 deletions clang/lib/AST/Interp/Pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_INTERP_POINTER_H

#include "Descriptor.h"
#include "FunctionPointer.h"
#include "InterpBlock.h"
#include "clang/AST/ComparisonCategories.h"
#include "clang/AST/Decl.h"
Expand Down Expand Up @@ -45,7 +46,7 @@ struct IntPointer {
uint64_t Value;
};

enum class Storage { Block, Int };
enum class Storage { Block, Int, Fn };

/// A pointer to a memory block, live or dead.
///
Expand Down Expand Up @@ -96,6 +97,10 @@ class Pointer {
PointeeStorage.Int.Value = Address;
PointeeStorage.Int.Desc = Desc;
}
Pointer(const Function *F, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Fn) {
PointeeStorage.Fn = FunctionPointer(F);
}
~Pointer();

void operator=(const Pointer &P);
Expand Down Expand Up @@ -126,6 +131,8 @@ class Pointer {
uint64_t getIntegerRepresentation() const {
if (isIntegralPointer())
return asIntPointer().Value + (Offset * elemSize());
if (isFunctionPointer())
return asFunctionPointer().getIntegerRepresentation();
return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
}

Expand All @@ -137,6 +144,8 @@ class Pointer {
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
if (isFunctionPointer())
return Pointer(asFunctionPointer().getFunction(), Idx);

if (asBlockPointer().Base == RootPtrMark)
return Pointer(asBlockPointer().Pointee, RootPtrMark,
Expand Down Expand Up @@ -247,18 +256,20 @@ class Pointer {
bool isZero() const {
if (isBlockPointer())
return asBlockPointer().Pointee == nullptr;
if (isFunctionPointer())
return asFunctionPointer().isZero();
assert(isIntegralPointer());
return asIntPointer().Value == 0 && Offset == 0;
}
/// Checks if the pointer is live.
bool isLive() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;
return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
}
/// Checks if the item is a field in an object.
bool isField() const {
if (isIntegralPointer())
if (!isBlockPointer())
return false;

return !isRoot() && getFieldDesc()->asDecl();
Expand All @@ -268,6 +279,8 @@ class Pointer {
const Descriptor *getDeclDesc() const {
if (isIntegralPointer())
return asIntPointer().Desc;
if (isFunctionPointer())
return nullptr;

assert(isBlockPointer());
assert(asBlockPointer().Pointee);
Expand All @@ -279,7 +292,10 @@ class Pointer {
DeclTy getSource() const {
if (isBlockPointer())
return getDeclDesc()->getSource();

if (isFunctionPointer()) {
const Function *F = asFunctionPointer().getFunction();
return F ? F->getDecl() : DeclTy();
}
assert(isIntegralPointer());
return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
}
Expand Down Expand Up @@ -354,6 +370,7 @@ class Pointer {
/// Returns the offset into an array.
unsigned getOffset() const {
assert(Offset != PastEndMark && "invalid offset");
assert(isBlockPointer());
if (asBlockPointer().Base == RootPtrMark)
return Offset;

Expand Down Expand Up @@ -421,8 +438,14 @@ class Pointer {
assert(isIntegralPointer());
return PointeeStorage.Int;
}
[[nodiscard]] const FunctionPointer &asFunctionPointer() const {
assert(isFunctionPointer());
return PointeeStorage.Fn;
}

bool isBlockPointer() const { return StorageKind == Storage::Block; }
bool isIntegralPointer() const { return StorageKind == Storage::Int; }
bool isFunctionPointer() const { return StorageKind == Storage::Fn; }

/// Returns the record descriptor of a class.
const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
Expand All @@ -445,7 +468,7 @@ class Pointer {
}
/// Checks if the storage is static.
bool isStatic() const {
if (isIntegralPointer())
if (!isBlockPointer())
return true;
assert(asBlockPointer().Pointee);
return asBlockPointer().Pointee->isStatic();
Expand All @@ -469,7 +492,7 @@ class Pointer {
}

bool isWeak() const {
if (isIntegralPointer())
if (!isBlockPointer())
return false;

assert(isBlockPointer());
Expand All @@ -487,6 +510,9 @@ class Pointer {
}
/// Checks if a structure is a base class.
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
bool isVirtualBaseClass() const {
return isField() && getInlineDesc()->IsVirtualBase;
}
/// Checks if the pointer points to a dummy value.
bool isDummy() const {
if (!isBlockPointer())
Expand Down Expand Up @@ -525,8 +551,8 @@ class Pointer {

/// Returns the number of elements.
unsigned getNumElems() const {
if (isIntegralPointer())
return ~unsigned(0);
if (!isBlockPointer())
return ~0u;
return getSize() / elemSize();
}

Expand All @@ -552,7 +578,7 @@ class Pointer {

/// Checks if the index is one past end.
bool isOnePastEnd() const {
if (isIntegralPointer())
if (isIntegralPointer() || isFunctionPointer())
return false;

if (!asBlockPointer().Pointee)
Expand Down Expand Up @@ -689,6 +715,7 @@ class Pointer {
union {
BlockPointer BS;
IntPointer Int;
FunctionPointer Fn;
} PointeeStorage;
Storage StorageKind = Storage::Int;
};
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5179,6 +5179,14 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
Diags.Report(DiagID);
return;
}
case UETT_PtrAuthTypeDiscriminator: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(
DiagnosticsEngine::Error,
"cannot yet mangle __builtin_ptrauth_type_discriminator expression");
Diags.Report(E->getExprLoc(), DiagID);
return;
}
case UETT_VecStep: {
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
Expand Down
24 changes: 11 additions & 13 deletions clang/lib/AST/StmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,11 @@ OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
/*NumChildren=*/1);
}

OMPSimdDirective *OMPSimdDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, OpenMPDirectiveKind ParamPrevMappedDirective) {
OMPSimdDirective *
OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs) {
auto *Dir = createDirective<OMPSimdDirective>(
C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_simd),
StartLoc, EndLoc, CollapsedNum);
Expand All @@ -320,7 +321,6 @@ OMPSimdDirective *OMPSimdDirective::Create(
Dir->setDependentInits(Exprs.DependentInits);
Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand All @@ -336,8 +336,7 @@ OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C,
OMPForDirective *OMPForDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, Expr *TaskRedRef, bool HasCancel,
OpenMPDirectiveKind ParamPrevMappedDirective) {
const HelperExprs &Exprs, Expr *TaskRedRef, bool HasCancel) {
auto *Dir = createDirective<OMPForDirective>(
C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_for) + 1,
StartLoc, EndLoc, CollapsedNum);
Expand Down Expand Up @@ -367,7 +366,6 @@ OMPForDirective *OMPForDirective::Create(
Dir->setPreInits(Exprs.PreInits);
Dir->setTaskReductionRefExpr(TaskRedRef);
Dir->setHasCancel(HasCancel);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand Down Expand Up @@ -1569,10 +1567,11 @@ OMPParallelMaskedTaskLoopSimdDirective::CreateEmpty(const ASTContext &C,
CollapsedNum);
}

OMPDistributeDirective *OMPDistributeDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
const HelperExprs &Exprs, OpenMPDirectiveKind ParamPrevMappedDirective) {
OMPDistributeDirective *
OMPDistributeDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc, unsigned CollapsedNum,
ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs) {
auto *Dir = createDirective<OMPDistributeDirective>(
C, Clauses, AssociatedStmt,
numLoopChildren(CollapsedNum, OMPD_distribute), StartLoc, EndLoc,
Expand Down Expand Up @@ -1601,7 +1600,6 @@ OMPDistributeDirective *OMPDistributeDirective::Create(
Dir->setDependentInits(Exprs.DependentInits);
Dir->setFinalsConditions(Exprs.FinalsConditions);
Dir->setPreInits(Exprs.PreInits);
Dir->setMappedDirective(ParamPrevMappedDirective);
return Dir;
}

Expand Down
21 changes: 15 additions & 6 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,12 +524,21 @@ void Environment::initialize() {
assert(VarDecl != nullptr);
setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr));
} else if (Capture.capturesThis()) {
const auto *SurroundingMethodDecl =
cast<CXXMethodDecl>(InitialTargetFunc->getNonClosureAncestor());
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
if (auto *Ancestor = InitialTargetFunc->getNonClosureAncestor()) {
const auto *SurroundingMethodDecl = cast<CXXMethodDecl>(Ancestor);
QualType ThisPointeeType =
SurroundingMethodDecl->getFunctionObjectParameterType();
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(ThisPointeeType)));
} else if (auto *FieldBeingInitialized =
dyn_cast<FieldDecl>(Parent->getLambdaContextDecl())) {
// This is in a field initializer, rather than a method.
setThisPointeeStorageLocation(
cast<RecordStorageLocation>(createObject(QualType(
FieldBeingInitialized->getParent()->getTypeForDecl(), 0))));
} else {
assert(false && "Unexpected this-capturing lambda context.");
}
}
}
} else if (MethodDecl->isImplicitObjectMemberFunction()) {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Basic/IdentifierTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,8 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) {
if (LangOpts.IEEE128)
AddKeyword("__ieee128", tok::kw___float128, KEYALL, LangOpts, *this);

// Add the 'import' and 'module' contextual keyword.
// Add the 'import' contextual keyword.
get("import").setModulesImport(true);
get("module").setModulesDeclaration(true);
}

/// Checks if the specified token kind represents a keyword in the
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple,
StringRef AArch64TargetInfo::getABI() const { return ABI; }

bool AArch64TargetInfo::setABI(const std::string &Name) {
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs")
if (Name != "aapcs" && Name != "aapcs-soft" && Name != "darwinpcs" &&
Name != "pauthtest")
return false;

ABI = Name;
Expand All @@ -218,6 +219,12 @@ bool AArch64TargetInfo::validateTarget(DiagnosticsEngine &Diags) const {
Diags.Report(diag::err_target_unsupported_abi_with_fpu) << ABI;
return false;
}
if (getTriple().getEnvironment() == llvm::Triple::PAuthTest &&
getTriple().getOS() != llvm::Triple::Linux) {
Diags.Report(diag::err_target_unsupported_abi_for_triple)
<< getTriple().getEnvironmentName() << getTriple().getTriple();
return false;
}
return true;
}

Expand Down
23 changes: 22 additions & 1 deletion clang/lib/Basic/Targets/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,24 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,

// Define __loongarch_arch.
StringRef ArchName = getCPU();
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
if (ArchName == "loongarch64") {
if (HasFeatureLSX) {
// TODO: As more features of the V1.1 ISA are supported, a unified "v1.1"
// arch feature set will be used to include all sub-features belonging to
// the V1.1 ISA version.
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.1" + Twine('"'));
else
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.0" + Twine('"'));
} else {
Builder.defineMacro("__loongarch_arch",
Twine('"') + ArchName + Twine('"'));
}
} else {
Builder.defineMacro("__loongarch_arch", Twine('"') + ArchName + Twine('"'));
}

// Define __loongarch_tune.
StringRef TuneCPU = getTargetOpts().TuneCPU;
Expand All @@ -216,6 +233,8 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__loongarch_simd_width", "128");
Builder.defineMacro("__loongarch_sx", Twine(1));
}
if (HasFeatureFrecipe)
Builder.defineMacro("__loongarch_frecipe", Twine(1));

StringRef ABI = getABI();
if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
Expand Down Expand Up @@ -291,6 +310,8 @@ bool LoongArchTargetInfo::handleTargetFeatures(
HasFeatureLASX = true;
else if (Feature == "-ual")
HasUnalignedAccess = false;
else if (Feature == "+frecipe")
HasFeatureFrecipe = true;
}
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/LoongArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool HasFeatureF;
bool HasFeatureLSX;
bool HasFeatureLASX;
bool HasFeatureFrecipe;

public:
LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
Expand All @@ -37,6 +38,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
HasFeatureF = false;
HasFeatureLSX = false;
HasFeatureLASX = false;
HasFeatureFrecipe = false;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
Expand Down
39 changes: 26 additions & 13 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("_ARCH_PWR9");
if (ArchDefs & ArchDefinePwr10)
Builder.defineMacro("_ARCH_PWR10");
if (ArchDefs & ArchDefinePwr11)
Builder.defineMacro("_ARCH_PWR11");
if (ArchDefs & ArchDefineA2)
Builder.defineMacro("_ARCH_A2");
if (ArchDefs & ArchDefineE500)
Expand Down Expand Up @@ -622,10 +624,17 @@ bool PPCTargetInfo::initFeatureMap(
addP10SpecificFeatures(Features);
}

// Future CPU should include all of the features of Power 10 as well as any
// Power11 includes all the same features as Power10 plus any features
// specific to the Power11 core.
if (CPU == "pwr11" || CPU == "power11") {
initFeatureMap(Features, Diags, "pwr10", FeaturesVec);
addP11SpecificFeatures(Features);
}

// Future CPU should include all of the features of Power 11 as well as any
// additional features (yet to be determined) specific to it.
if (CPU == "future") {
initFeatureMap(Features, Diags, "pwr10", FeaturesVec);
initFeatureMap(Features, Diags, "pwr11", FeaturesVec);
addFutureSpecificFeatures(Features);
}

Expand Down Expand Up @@ -696,6 +705,10 @@ void PPCTargetInfo::addP10SpecificFeatures(
Features["isa-v31-instructions"] = true;
}

// Add any Power11 specific features.
void PPCTargetInfo::addP11SpecificFeatures(
llvm::StringMap<bool> &Features) const {}

// Add features specific to the "Future" CPU.
void PPCTargetInfo::addFutureSpecificFeatures(
llvm::StringMap<bool> &Features) const {}
Expand Down Expand Up @@ -870,17 +883,17 @@ ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const {
}

static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
{"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
{"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
{"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
{"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"},
{"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"},
{"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"},
{"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"},
{"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"},
{"powerpc"}, {"ppc"}, {"ppc32"}, {"powerpc64"}, {"ppc64"},
{"powerpc64le"}, {"ppc64le"}, {"future"}};
{"generic"}, {"440"}, {"450"}, {"601"}, {"602"},
{"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"},
{"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"},
{"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"},
{"g5"}, {"a2"}, {"e500"}, {"e500mc"}, {"e5500"},
{"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"},
{"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"},
{"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"},
{"pwr8"}, {"power9"}, {"pwr9"}, {"power10"}, {"pwr10"},
{"power11"}, {"pwr11"}, {"powerpc"}, {"ppc"}, {"ppc32"},
{"powerpc64"}, {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, {"future"}};

bool PPCTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::is_contained(ValidCPUNames, Name);
Expand Down
19 changes: 13 additions & 6 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
ArchDefinePwr8 = 1 << 12,
ArchDefinePwr9 = 1 << 13,
ArchDefinePwr10 = 1 << 14,
ArchDefineFuture = 1 << 15,
ArchDefineA2 = 1 << 16,
ArchDefinePwr11 = 1 << 15,
ArchDefineFuture = 1 << 16,
ArchDefineA2 = 1 << 17,
ArchDefineE500 = 1 << 18
} ArchDefineTypes;

Expand Down Expand Up @@ -166,11 +167,16 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x |
ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr |
ArchDefinePpcsq)
.Cases("power11", "pwr11",
ArchDefinePwr11 | ArchDefinePwr10 | ArchDefinePwr9 |
ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 |
ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
ArchDefinePpcgr | ArchDefinePpcsq)
.Case("future",
ArchDefineFuture | ArchDefinePwr10 | ArchDefinePwr9 |
ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 |
ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 |
ArchDefinePpcgr | ArchDefinePpcsq)
ArchDefineFuture | ArchDefinePwr11 | ArchDefinePwr10 |
ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 |
ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 |
ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq)
.Cases("8548", "e500", ArchDefineE500)
.Default(ArchDefineNone);
}
Expand All @@ -192,6 +198,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
const std::vector<std::string> &FeaturesVec) const override;

void addP10SpecificFeatures(llvm::StringMap<bool> &Features) const;
void addP11SpecificFeatures(llvm::StringMap<bool> &Features) const;
void addFutureSpecificFeatures(llvm::StringMap<bool> &Features) const;

bool handleTargetFeatures(std::vector<std::string> &Features,
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,9 @@ RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
return CCCR_OK;
}
}

bool RISCVTargetInfo::validateCpuSupports(StringRef Feature) const {
// Only allow extensions we have a known bit position for in the
// __riscv_feature_bits structure.
return -1 != llvm::RISCVISAInfo::getRISCVFeaturesBitPosition(Feature);
}
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ class RISCVTargetInfo : public TargetInfo {
std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
}

bool supportsCpuSupports() const override { return getTriple().isOSLinux(); }
bool supportsCpuInit() const override { return getTriple().isOSLinux(); }
bool validateCpuSupports(StringRef Feature) const override;
};
class LLVM_LIBRARY_VISIBILITY RISCV32TargetInfo : public RISCVTargetInfo {
public:
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,15 +513,6 @@ class LLVM_LIBRARY_VISIBILITY NetBSDI386TargetInfo
public:
NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts)
: NetBSDTargetInfo<X86_32TargetInfo>(Triple, Opts) {}

LangOptions::FPEvalMethodKind getFPEvalMethod() const override {
VersionTuple OsVersion = getTriple().getOSVersion();
// New NetBSD uses the default rounding mode.
if (OsVersion >= VersionTuple(6, 99, 26) || OsVersion.getMajor() == 0)
return X86_32TargetInfo::getFPEvalMethod();
// NetBSD before 6.99.26 defaults to "double" rounding.
return LangOptions::FPEvalMethodKind::FEM_Double;
}
};

class LLVM_LIBRARY_VISIBILITY OpenBSDI386TargetInfo
Expand Down
61 changes: 57 additions & 4 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/TargetParser/AArch64TargetParser.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
#include "llvm/TargetParser/X86TargetParser.h"
#include <optional>
#include <sstream>
Expand Down Expand Up @@ -14308,6 +14309,16 @@ Value *CodeGenFunction::EmitAArch64CpuInit() {
return Builder.CreateCall(Func);
}

Value *CodeGenFunction::EmitRISCVCpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
llvm::FunctionCallee Func =
CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
CalleeGV->setDSOLocal(true);
CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
return Builder.CreateCall(Func);
}

Value *CodeGenFunction::EmitX86CpuInit() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy,
/*Variadic*/ false);
Expand Down Expand Up @@ -14360,6 +14371,42 @@ CodeGenFunction::EmitAArch64CpuSupports(ArrayRef<StringRef> FeaturesStrs) {
return Result;
}

Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {

const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
return Builder.getFalse();

// Note: We are making an unchecked assumption that the size of the
// feature array is >= 1. This holds for any version of compiler-rt
// which defines this interface.
llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1);
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
llvm::Constant *RISCVFeaturesBits =
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
GV->setDSOLocal(true);

auto LoadFeatureBit = [&](unsigned Index) {
// Create GEP then load.
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
IndexVal};
Value *Ptr =
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
Value *FeaturesBit =
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
return FeaturesBit;
};

int BitPos = RISCVISAInfo::getRISCVFeaturesBitPosition(FeatureStr);
assert(BitPos != -1 && "validation should have rejected this feature");
Value *MaskV = Builder.getInt64(1ULL << BitPos);
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(0), MaskV);
return Builder.CreateICmpEQ(Bitset, MaskV);
}

Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (BuiltinID == Builtin::BI__builtin_cpu_is)
Expand Down Expand Up @@ -18424,10 +18471,10 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
if (!E->getArg(0)->getType()->hasFloatingRepresentation())
llvm_unreachable("frac operand must have a float representation");
return Builder.CreateIntrinsic(
/*ReturnType=*/Op0->getType(), Intrinsic::dx_frac,
ArrayRef<Value *>{Op0}, nullptr, "dx.frac");
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
/*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(),
ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac");
}
case Builtin::BI__builtin_hlsl_elementwise_isinf: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
llvm::Type *Xty = Op0->getType();
llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
Expand Down Expand Up @@ -21854,6 +21901,12 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
const CallExpr *E,
ReturnValueSlot ReturnValue) {

if (BuiltinID == Builtin::BI__builtin_cpu_supports)
return EmitRISCVCpuSupports(E);
if (BuiltinID == Builtin::BI__builtin_cpu_init)
return EmitRISCVCpuInit();

SmallVector<Value *, 4> Ops;
llvm::Type *ResultType = ConvertType(E->getType());

Expand Down
216 changes: 118 additions & 98 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2025,6 +2025,9 @@ static void getTrivialDefaultFunctionAttributes(
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
}

if (CodeGenOpts.SaveRegParams && !AttrOnCallSite)
FuncAttrs.addAttribute("save-reg-params");

for (StringRef Attr : CodeGenOpts.DefaultFunctionAttrs) {
StringRef Var, Value;
std::tie(Var, Value) = Attr.split('=');
Expand Down Expand Up @@ -5034,7 +5037,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
ReturnValueSlot ReturnValue,
const CallArgList &CallArgs,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc) {
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk) {
// FIXME: We no longer need the types from CallArgs; lift up and simplify.

assert(Callee.isOrdinary() || Callee.isVirtual());
Expand Down Expand Up @@ -5098,7 +5102,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
RawAddress SRetAlloca = RawAddress::invalid();
llvm::Value *UnusedReturnSizePtr = nullptr;
if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
if (!ReturnValue.isNull()) {
if (IsVirtualFunctionPointerThunk && RetAI.isIndirect()) {
SRetPtr = makeNaturalAddressForPointer(CurFn->arg_begin() +
IRFunctionArgs.getSRetArgNo(),
RetTy, CharUnits::fromQuantity(1));
} else if (!ReturnValue.isNull()) {
SRetPtr = ReturnValue.getAddress();
} else {
SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca);
Expand Down Expand Up @@ -5877,119 +5885,131 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
CallArgs.freeArgumentMemory(*this);

// Extract the return value.
RValue Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);
RValue Ret;

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
// If the current function is a virtual function pointer thunk, avoid copying
// the return value of the musttail call to a temporary.
if (IsVirtualFunctionPointerThunk) {
Ret = RValue::get(CI);
} else {
Ret = [&] {
switch (RetAI.getKind()) {
case ABIArgInfo::CoerceAndExpand: {
auto coercionType = RetAI.getCoerceAndExpandType();

Address addr = SRetPtr.withElementType(coercionType);

assert(CI->getType() == RetAI.getUnpaddedCoerceAndExpandType());
bool requiresExtract = isa<llvm::StructType>(CI->getType());

unsigned unpaddedIndex = 0;
for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
llvm::Type *eltType = coercionType->getElementType(i);
if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
continue;
Address eltAddr = Builder.CreateStructGEP(addr, i);
llvm::Value *elt = CI;
if (requiresExtract)
elt = Builder.CreateExtractValue(elt, unpaddedIndex++);
else
assert(unpaddedIndex == 0);
Builder.CreateStore(elt, eltAddr);
}
[[fallthrough]];
}
[[fallthrough]];
}

case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);
case ABIArgInfo::InAlloca:
case ABIArgInfo::Indirect: {
RValue ret = convertTempToRValue(SRetPtr, RetTy, SourceLocation());
if (UnusedReturnSizePtr)
PopCleanupBlock();
return ret;
}

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy && RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();
case ABIArgInfo::Ignore:
// If we are ignoring an argument that had a result, make sure to
// construct the appropriate return value for our caller.
return GetUndefRValue(RetTy);

case ABIArgInfo::Extend:
case ABIArgInfo::Direct: {
llvm::Type *RetIRTy = ConvertType(RetTy);
if (RetAI.getCoerceToType() == RetIRTy &&
RetAI.getDirectOffset() == 0) {
switch (getEvaluationKind(RetTy)) {
case TEK_Complex: {
llvm::Value *Real = Builder.CreateExtractValue(CI, 0);
llvm::Value *Imag = Builder.CreateExtractValue(CI, 1);
return RValue::getComplex(std::make_pair(Real, Imag));
}
case TEK_Aggregate: {
Address DestPtr = ReturnValue.getAddress();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "agg.tmp");
DestIsVolatile = false;
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it.
// This can happen due to trivial type mismatches.
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
}
EmitAggregateStore(CI, DestPtr, DestIsVolatile);
return RValue::getAggregate(DestPtr);
llvm_unreachable("bad evaluation kind");
}
case TEK_Scalar: {
// If the argument doesn't match, perform a bitcast to coerce it. This
// can happen due to trivial type mismatches.

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (V->getType() != RetIRTy)
V = Builder.CreateBitCast(V, RetIRTy);
return RValue::get(V);
}
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() ==
ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero,
"cast.fixed");
return RValue::get(V);
}
}
}
llvm_unreachable("bad evaluation kind");
}

// If coercing a fixed vector from a scalable vector for ABI
// compatibility, and the types match, use the llvm.vector.extract
// intrinsic to perform the conversion.
if (auto *FixedDstTy = dyn_cast<llvm::FixedVectorType>(RetIRTy)) {
llvm::Value *V = CI;
if (auto *ScalableSrcTy =
dyn_cast<llvm::ScalableVectorType>(V->getType())) {
if (FixedDstTy->getElementType() == ScalableSrcTy->getElementType()) {
llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty);
V = Builder.CreateExtractVector(FixedDstTy, V, Zero, "cast.fixed");
return RValue::get(V);
}
Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
}
}

Address DestPtr = ReturnValue.getValue();
bool DestIsVolatile = ReturnValue.isVolatile();
// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
}

if (!DestPtr.isValid()) {
DestPtr = CreateMemTemp(RetTy, "coerce");
DestIsVolatile = false;
return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

// An empty record can overlap other data (if declared with
// no_unique_address); omit the store for such types - as there is no
// actual data to store.
if (!isEmptyRecord(getContext(), RetTy, true)) {
// If the value is offset in memory, apply the offset now.
Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

return convertTempToRValue(DestPtr, RetTy, SourceLocation());
}

case ABIArgInfo::Expand:
case ABIArgInfo::IndirectAliased:
llvm_unreachable("Invalid ABI kind for return argument");
}

llvm_unreachable("Unhandled ABIArgInfo::Kind");
} ();
llvm_unreachable("Unhandled ABIArgInfo::Kind");
}();
}

// Emit the assume_aligned check on the return value.
if (Ret.isScalar() && TargetDecl) {
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,11 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
const CGRecordLayout &Layout = CGF.CGM.getTypes().getCGRecordLayout(RD);
int64_t FieldNo = -1;
for (const FieldDecl *FD : RD->fields()) {
if (!Layout.containsFieldDecl(FD))
// This could happen if the field has a struct type that's empty. I don't
// know why either.
continue;

FieldNo = Layout.getLLVMFieldNo(FD);
if (FD == Field) {
Indices.emplace_back(std::make_pair(RD, CGF.Builder.getInt32(FieldNo)));
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CodeGen/CGExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -814,8 +814,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD,
llvm::Constant *VTableAddressPoint =
CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset),
VTableClass);
if (auto Authentication =
CGM.getVTablePointerAuthentication(VTableClass)) {
if (auto Authentication = CGM.getVTablePointerAuthentication(CD)) {
VTableAddressPoint = Emitter.tryEmitConstantSignedPointer(
VTableAddressPoint, *Authentication);
if (!VTableAddressPoint)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class CGHLSLRuntime {

GENERATE_HLSL_INTRINSIC_FUNCTION(All, all)
GENERATE_HLSL_INTRINSIC_FUNCTION(Any, any)
GENERATE_HLSL_INTRINSIC_FUNCTION(Frac, frac)
GENERATE_HLSL_INTRINSIC_FUNCTION(Lerp, lerp)
GENERATE_HLSL_INTRINSIC_FUNCTION(Rsqrt, rsqrt)
GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1695,7 +1695,8 @@ void CGOpenMPRuntimeGPU::emitReduction(
CGF.AllocaInsertPt->getIterator());
InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(),
CGF.Builder.GetInsertPoint());
llvm::OpenMPIRBuilder::LocationDescription OmpLoc(CodeGenIP);
llvm::OpenMPIRBuilder::LocationDescription OmpLoc(
CodeGenIP, CGF.SourceLocToDebugLoc(Loc));
llvm::SmallVector<llvm::OpenMPIRBuilder::ReductionInfo> ReductionInfos;

CodeGenFunction::OMPPrivateScope Scope(CGF);
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/CodeGen/CGPointerAuth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,40 @@ llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
}

CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (!Schema)
return CGPointerAuthInfo();

assert(!Schema.isAddressDiscriminated() &&
"function pointers cannot use address-specific discrimination");

llvm::ConstantInt *Discriminator =
getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);
return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
/* IsIsaPointer */ false,
/* AuthenticatesNullValues */ false, Discriminator);
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT) {
if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
return getConstantSignedPointer(
Pointer, PointerAuth.getKey(), nullptr,
cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));

return Pointer;
}

llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty) {
QualType FT = FD->getType();
FT = getContext().getMemberPointerType(
FT, cast<CXXMethodDecl>(FD)->getParent()->getTypeForDecl());
return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);
}

std::optional<PointerAuthQualifier>
CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGRecordLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ class CGRecordLayout {
return IsZeroInitializableAsBase;
}

bool containsFieldDecl(const FieldDecl *FD) const {
return FieldInfo.count(FD) != 0;
}

/// Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
Expand Down
392 changes: 239 additions & 153 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ add_clang_library(clangCodeGen
MacroPPCallbacks.cpp
MicrosoftCXXABI.cpp
ModuleBuilder.cpp
ObjectFilePCHContainerOperations.cpp
ObjectFilePCHContainerWriter.cpp
PatternInit.cpp
SanitizerMetadata.cpp
SwiftCallingConv.cpp
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
if (CodeGenOpts.PointerAuth.FunctionPointers)
Fn->addFnAttr("ptrauth-calls");
if (CodeGenOpts.PointerAuth.IndirectGotos)
Fn->addFnAttr("ptrauth-indirect-gotos");

// Apply xray attributes to the function (as a string, for now)
bool AlwaysXRayAttr = false;
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4374,7 +4374,8 @@ class CodeGenFunction : public CodeGenTypeCache {
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke, bool IsMustTail,
SourceLocation Loc);
SourceLocation Loc,
bool IsVirtualFunctionPointerThunk = false);
RValue EmitCall(const CGFunctionInfo &CallInfo, const CGCallee &Callee,
ReturnValueSlot ReturnValue, const CallArgList &Args,
llvm::CallBase **callOrInvoke = nullptr,
Expand Down Expand Up @@ -4696,6 +4697,9 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue);

llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
llvm::Value *EmitRISCVCpuInit();

void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,
const CallExpr *E);
void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
return createWindowsAArch64TargetCodeGenInfo(CGM, AArch64ABIKind::Win64);
else if (Target.getABI() == "aapcs-soft")
Kind = AArch64ABIKind::AAPCSSoft;
else if (Target.getABI() == "pauthtest")
Kind = AArch64ABIKind::PAuthTest;

return createAArch64TargetCodeGenInfo(CGM, Kind);
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -973,8 +973,16 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
QualType FunctionType);

llvm::Constant *getMemberFunctionPointer(const FunctionDecl *FD,
llvm::Type *Ty = nullptr);

llvm::Constant *getMemberFunctionPointer(llvm::Constant *Pointer,
QualType FT);

CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);

CGPointerAuthInfo getMemberFunctionPointerAuthInfo(QualType FT);

CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type);

CGPointerAuthInfo getPointerAuthInfoForType(QualType type);
Expand Down
254 changes: 242 additions & 12 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {

bool NeedsVTTParameter(GlobalDecl GD) override;

llvm::Constant *
getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD);

/**************************** RTTI Uniqueness ******************************/

protected:
Expand Down Expand Up @@ -426,6 +429,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
const CXXRecordDecl *RD) override;

private:
llvm::Constant *
getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD);

bool hasAnyUnusedVirtualInlineFunction(const CXXRecordDecl *RD) const {
const auto &VtableLayout =
CGM.getItaniumVTableContext().getVTableLayout(RD);
Expand Down Expand Up @@ -835,7 +841,25 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
CalleePtr->addIncoming(VirtualFn, FnVirtual);
CalleePtr->addIncoming(NonVirtualFn, FnNonVirtual);

CGCallee Callee(FPT, CalleePtr);
CGPointerAuthInfo PointerAuth;

if (const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers) {
llvm::PHINode *DiscriminatorPHI = Builder.CreatePHI(CGF.IntPtrTy, 2);
DiscriminatorPHI->addIncoming(llvm::ConstantInt::get(CGF.IntPtrTy, 0),
FnVirtual);
const auto &AuthInfo =
CGM.getMemberFunctionPointerAuthInfo(QualType(MPT, 0));
assert(Schema.getKey() == AuthInfo.getKey() &&
"Keys for virtual and non-virtual member functions must match");
auto *NonVirtualDiscriminator = AuthInfo.getDiscriminator();
DiscriminatorPHI->addIncoming(NonVirtualDiscriminator, FnNonVirtual);
PointerAuth = CGPointerAuthInfo(
Schema.getKey(), Schema.getAuthenticationMode(), Schema.isIsaPointer(),
Schema.authenticatesNullValues(), DiscriminatorPHI);
}

CGCallee Callee(FPT, CalleePtr, PointerAuth);
return Callee;
}

Expand All @@ -853,6 +877,25 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
"memptr.offset");
}

// See if it's possible to return a constant signed pointer.
static llvm::Constant *pointerAuthResignConstant(
llvm::Value *Ptr, const CGPointerAuthInfo &CurAuthInfo,
const CGPointerAuthInfo &NewAuthInfo, CodeGenModule &CGM) {
const auto *CPA = dyn_cast<llvm::ConstantPtrAuth>(Ptr);

if (!CPA)
return nullptr;

assert(CPA->getKey()->getZExtValue() == CurAuthInfo.getKey() &&
CPA->getAddrDiscriminator()->isZeroValue() &&
CPA->getDiscriminator() == CurAuthInfo.getDiscriminator() &&
"unexpected key or discriminators");

return CGM.getConstantSignedPointer(
CPA->getPointer(), NewAuthInfo.getKey(), nullptr,
cast<llvm::ConstantInt>(NewAuthInfo.getDiscriminator()));
}

/// Perform a bitcast, derived-to-base, or base-to-derived member pointer
/// conversion.
///
Expand Down Expand Up @@ -880,21 +923,63 @@ llvm::Value *
ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
llvm::Value *src) {
// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

CGBuilderTy &Builder = CGF.Builder;
QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType()) {
if (const auto &NewAuthInfo =
CGM.getMemberFunctionPointerAuthInfo(DstType)) {
QualType SrcType = E->getSubExpr()->getType();
assert(SrcType->isMemberFunctionPointerType());
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
llvm::Type *OrigTy = MemFnPtr->getType();

llvm::BasicBlock *StartBB = Builder.GetInsertBlock();
llvm::BasicBlock *ResignBB = CGF.createBasicBlock("resign");
llvm::BasicBlock *MergeBB = CGF.createBasicBlock("merge");

// Check whether we have a virtual offset or a pointer to a function.
assert(UseARMMethodPtrABI && "ARM ABI expected");
llvm::Value *Adj = Builder.CreateExtractValue(src, 1, "memptr.adj");
llvm::Constant *Ptrdiff_1 = llvm::ConstantInt::get(CGM.PtrDiffTy, 1);
llvm::Value *AndVal = Builder.CreateAnd(Adj, Ptrdiff_1);
llvm::Value *IsVirtualOffset =
Builder.CreateIsNotNull(AndVal, "is.virtual.offset");
Builder.CreateCondBr(IsVirtualOffset, MergeBB, ResignBB);

CGF.EmitBlock(ResignBB);
llvm::Type *PtrTy = llvm::PointerType::getUnqual(CGM.Int8Ty);
MemFnPtr = Builder.CreateIntToPtr(MemFnPtr, PtrTy);
MemFnPtr =
CGF.emitPointerAuthResign(MemFnPtr, SrcType, CurAuthInfo, NewAuthInfo,
isa<llvm::Constant>(src));
MemFnPtr = Builder.CreatePtrToInt(MemFnPtr, OrigTy);
llvm::Value *ResignedVal = Builder.CreateInsertValue(src, MemFnPtr, 0);
ResignBB = Builder.GetInsertBlock();

CGF.EmitBlock(MergeBB);
llvm::PHINode *NewSrc = Builder.CreatePHI(src->getType(), 2);
NewSrc->addIncoming(src, StartBB);
NewSrc->addIncoming(ResignedVal, ResignBB);
src = NewSrc;
}
}

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

// Use constant emission if we can.
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));

llvm::Constant *adj = getMemberPointerAdjustment(E);
if (!adj) return src;

CGBuilderTy &Builder = CGF.Builder;
bool isDerivedToBase = (E->getCastKind() == CK_DerivedToBaseMemberPointer);

const MemberPointerType *destTy =
Expand Down Expand Up @@ -932,13 +1017,47 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
return Builder.CreateInsertValue(src, dstAdj, 1);
}

static llvm::Constant *
pointerAuthResignMemberFunctionPointer(llvm::Constant *Src, QualType DestType,
QualType SrcType, CodeGenModule &CGM) {
assert(DestType->isMemberFunctionPointerType() &&
SrcType->isMemberFunctionPointerType() &&
"member function pointers expected");
if (DestType == SrcType)
return Src;

const auto &NewAuthInfo = CGM.getMemberFunctionPointerAuthInfo(DestType);
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);

if (!NewAuthInfo && !CurAuthInfo)
return Src;

llvm::Constant *MemFnPtr = Src->getAggregateElement(0u);
if (MemFnPtr->getNumOperands() == 0) {
// src must be a pair of null pointers.
assert(isa<llvm::ConstantInt>(MemFnPtr) && "constant int expected");
return Src;
}

llvm::Constant *ConstPtr = pointerAuthResignConstant(
cast<llvm::User>(MemFnPtr)->getOperand(0), CurAuthInfo, NewAuthInfo, CGM);
ConstPtr = llvm::ConstantExpr::getPtrToInt(ConstPtr, MemFnPtr->getType());
return ConstantFoldInsertValueInstruction(Src, ConstPtr, 0);
}

llvm::Constant *
ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *src) {
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
E->getCastKind() == CK_ReinterpretMemberPointer);

QualType DstType = E->getType();

if (DstType->isMemberFunctionPointerType())
src = pointerAuthResignMemberFunctionPointer(
src, DstType, E->getSubExpr()->getType(), CGM);

// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;

Expand Down Expand Up @@ -1036,9 +1155,32 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// least significant bit of adj then makes exactly the same
// discrimination as the least significant bit of ptr does for
// Itanium.
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
2 * ThisAdjustment.getQuantity() + 1);

// We cannot use the Itanium ABI's representation for virtual member
// function pointers under pointer authentication because it would
// require us to store both the virtual offset and the constant
// discriminator in the pointer, which would be immediately vulnerable
// to attack. Instead we introduce a thunk that does the virtual dispatch
// and store it as if it were a non-virtual member function. This means
// that virtual function pointers may not compare equal anymore, but
// fortunately they aren't required to by the standard, and we do make
// a best-effort attempt to re-use the thunk.
//
// To support interoperation with code in which pointer authentication
// is disabled, derefencing a member function pointer must still handle
// the virtual case, but it can use a discriminator which should never
// be valid.
const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
if (Schema)
MemPtr[0] = llvm::ConstantExpr::getPtrToInt(
getSignedVirtualMemberFunctionPointer(MD), CGM.PtrDiffTy);
else
MemPtr[0] = llvm::ConstantInt::get(CGM.PtrDiffTy, VTableOffset);
// Don't set the LSB of adj to 1 if pointer authentication for member
// function pointers is enabled.
MemPtr[1] = llvm::ConstantInt::get(
CGM.PtrDiffTy, 2 * ThisAdjustment.getQuantity() + !Schema);
} else {
// Itanium C++ ABI 2.3:
// For a virtual function, [the pointer field] is 1 plus the
Expand All @@ -1060,7 +1202,7 @@ llvm::Constant *ItaniumCXXABI::BuildMemberPointer(const CXXMethodDecl *MD,
// function type is incomplete.
Ty = CGM.PtrDiffTy;
}
llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty);
llvm::Constant *addr = CGM.getMemberFunctionPointer(MD, Ty);

MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, CGM.PtrDiffTy);
MemPtr[1] = llvm::ConstantInt::get(CGM.PtrDiffTy,
Expand All @@ -1080,8 +1222,12 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const APValue &MP,

CharUnits ThisAdjustment = getContext().getMemberPointerPathAdjustment(MP);

if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD))
return BuildMemberPointer(MD, ThisAdjustment);
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) {
llvm::Constant *Src = BuildMemberPointer(MD, ThisAdjustment);
QualType SrcType = getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return pointerAuthResignMemberFunctionPointer(Src, MPType, SrcType, CGM);
}

CharUnits FieldOffset =
getContext().toCharUnitsFromBits(getContext().getFieldOffset(MPD));
Expand Down Expand Up @@ -3185,6 +3331,78 @@ bool ItaniumCXXABI::NeedsVTTParameter(GlobalDecl GD) {
return false;
}

llvm::Constant *
ItaniumCXXABI::getOrCreateVirtualFunctionPointerThunk(const CXXMethodDecl *MD) {
SmallString<256> MethodName;
llvm::raw_svector_ostream Out(MethodName);
getMangleContext().mangleCXXName(MD, Out);
MethodName += "_vfpthunk_";
StringRef ThunkName = MethodName.str();
llvm::Function *ThunkFn;
if ((ThunkFn = cast_or_null<llvm::Function>(
CGM.getModule().getNamedValue(ThunkName))))
return ThunkFn;

const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeCXXMethodDeclaration(MD);
llvm::FunctionType *ThunkTy = CGM.getTypes().GetFunctionType(FnInfo);
llvm::GlobalValue::LinkageTypes Linkage =
MD->isExternallyVisible() ? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
ThunkFn =
llvm::Function::Create(ThunkTy, Linkage, ThunkName, &CGM.getModule());
if (Linkage == llvm::GlobalValue::LinkOnceODRLinkage)
ThunkFn->setVisibility(llvm::GlobalValue::HiddenVisibility);
assert(ThunkFn->getName() == ThunkName && "name was uniqued!");

CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn, /*IsThunk=*/true);
CGM.SetLLVMFunctionAttributesForDefinition(MD, ThunkFn);

// Stack protection sometimes gets inserted after the musttail call.
ThunkFn->removeFnAttr(llvm::Attribute::StackProtect);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectStrong);
ThunkFn->removeFnAttr(llvm::Attribute::StackProtectReq);

// Start codegen.
CodeGenFunction CGF(CGM);
CGF.CurGD = GlobalDecl(MD);
CGF.CurFuncIsThunk = true;

// Build FunctionArgs.
FunctionArgList FunctionArgs;
CGF.BuildFunctionArgList(CGF.CurGD, FunctionArgs);

CGF.StartFunction(GlobalDecl(), FnInfo.getReturnType(), ThunkFn, FnInfo,
FunctionArgs, MD->getLocation(), SourceLocation());
llvm::Value *ThisVal = loadIncomingCXXThis(CGF);
setCXXABIThisValue(CGF, ThisVal);

CallArgList CallArgs;
for (const VarDecl *VD : FunctionArgs)
CGF.EmitDelegateCallArg(CallArgs, VD, SourceLocation());

const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, /*this*/ 1);
const CGFunctionInfo &CallInfo =
CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT, Required, 0);
CGCallee Callee = CGCallee::forVirtual(nullptr, GlobalDecl(MD),
getThisAddress(CGF), ThunkTy);
llvm::CallBase *CallOrInvoke;
CGF.EmitCall(CallInfo, Callee, ReturnValueSlot(), CallArgs, &CallOrInvoke,
/*IsMustTail=*/true, SourceLocation(), true);
auto *Call = cast<llvm::CallInst>(CallOrInvoke);
Call->setTailCallKind(llvm::CallInst::TCK_MustTail);
if (Call->getType()->isVoidTy())
CGF.Builder.CreateRetVoid();
else
CGF.Builder.CreateRet(Call);

// Finish the function to maintain CodeGenFunction invariants.
// FIXME: Don't emit unreachable code.
CGF.EmitBlock(CGF.createBasicBlock());
CGF.FinishFunction();
return ThunkFn;
}

namespace {
class ItaniumRTTIBuilder {
CodeGenModule &CGM; // Per-module state.
Expand Down Expand Up @@ -4875,6 +5093,18 @@ ItaniumCXXABI::LoadVTablePtr(CodeGenFunction &CGF, Address This,
return {CGF.GetVTablePtr(This, CGM.Int8PtrTy, RD), RD};
}

llvm::Constant *
ItaniumCXXABI::getSignedVirtualMemberFunctionPointer(const CXXMethodDecl *MD) {
const CXXMethodDecl *origMD =
cast<CXXMethodDecl>(CGM.getItaniumVTableContext()
.findOriginalMethod(MD->getCanonicalDecl())
.getDecl());
llvm::Constant *thunk = getOrCreateVirtualFunctionPointerThunk(origMD);
QualType funcType = CGM.getContext().getMemberPointerType(
MD->getType(), MD->getParent()->getTypeForDecl());
return CGM.getMemberFunctionPointer(thunk, funcType);
}

void WebAssemblyCXXABI::emitBeginCatch(CodeGenFunction &CGF,
const CXXCatchStmt *C) {
if (CGF.getTarget().hasFeature("exception-handling"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//===--- ObjectFilePCHContainerOperations.cpp -----------------------------===//
//===--- ObjectFilePCHContainerWriter.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 "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/CodeGen/ObjectFilePCHContainerWriter.h"
#include "CGDebugInfo.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
Expand Down Expand Up @@ -351,46 +351,3 @@ ObjectFilePCHContainerWriter::CreatePCHContainerGenerator(
return std::make_unique<PCHContainerGenerator>(
CI, MainFileName, OutputFileName, std::move(OS), Buffer);
}

ArrayRef<StringRef> ObjectFilePCHContainerReader::getFormats() const {
static StringRef Formats[] = {"obj", "raw"};
return Formats;
}

StringRef
ObjectFilePCHContainerReader::ExtractPCH(llvm::MemoryBufferRef Buffer) const {
StringRef PCH;
auto OFOrErr = llvm::object::ObjectFile::createObjectFile(Buffer);
if (OFOrErr) {
auto &OF = OFOrErr.get();
bool IsCOFF = isa<llvm::object::COFFObjectFile>(*OF);
// Find the clang AST section in the container.
for (auto &Section : OF->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Section.getName())
Name = *NameOrErr;
else
consumeError(NameOrErr.takeError());

if ((!IsCOFF && Name == "__clangast") || (IsCOFF && Name == "clangast")) {
if (Expected<StringRef> E = Section.getContents())
return *E;
else {
handleAllErrors(E.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
EIB.log(llvm::errs());
});
return "";
}
}
}
}
handleAllErrors(OFOrErr.takeError(), [&](const llvm::ErrorInfoBase &EIB) {
if (EIB.convertToErrorCode() ==
llvm::object::object_error::invalid_file_type)
// As a fallback, treat the buffer as a raw AST.
PCH = Buffer.getBuffer();
else
EIB.log(llvm::errs());
});
return PCH;
}
1 change: 1 addition & 0 deletions clang/lib/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ enum class AArch64ABIKind {
DarwinPCS,
Win64,
AAPCSSoft,
PAuthTest,
};

std::unique_ptr<TargetCodeGenInfo>
Expand Down
17 changes: 2 additions & 15 deletions clang/lib/CodeGen/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,9 @@ bool IsX86_MMXType(llvm::Type *IRType) {
IRType->getScalarSizeInBits() != 64;
}

static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
static llvm::Type *X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF,
StringRef Constraint,
llvm::Type* Ty) {
bool IsMMXCons = llvm::StringSwitch<bool>(Constraint)
.Cases("y", "&y", "^Ym", true)
.Default(false);
if (IsMMXCons && Ty->isVectorTy()) {
if (cast<llvm::VectorType>(Ty)->getPrimitiveSizeInBits().getFixedValue() !=
64) {
// Invalid MMX constraint
return nullptr;
}

return llvm::Type::getX86_MMXTy(CGF.getLLVMContext());
}

llvm::Type *Ty) {
if (Constraint == "k") {
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(CGF.getLLVMContext());
return llvm::FixedVectorType::get(Int1Ty, Ty->getScalarSizeInBits());
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,11 +1031,12 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
}
case llvm::Triple::aarch64: {
llvm::Triple Triple = getTriple();
tools::aarch64::setPAuthABIInTriple(getDriver(), Args, Triple);
if (!Triple.isOSBinFormatMachO())
return getTripleString();
return Triple.getTriple();

if (Triple.isArm64e())
return getTripleString();
return Triple.getTriple();

// FIXME: older versions of ld64 expect the "arm64" component in the actual
// triple string and query it to determine whether an LTO file can be
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Driver/ToolChains/AIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,9 @@ void AIX::addClangTargetOptions(
options::OPT_mtocdata))
addTocDataOptions(Args, CC1Args, getDriver());

if (Args.hasArg(options::OPT_msave_reg_params))
CC1Args.push_back("-msave-reg-params");

if (Args.hasFlag(options::OPT_fxl_pragma_pack,
options::OPT_fno_xl_pragma_pack, true))
CC1Args.push_back("-fxl-pragma-pack");
Expand All @@ -557,6 +560,12 @@ void AIX::addClangTargetOptions(
if (!Args.getLastArgNoClaim(options::OPT_fsized_deallocation,
options::OPT_fno_sized_deallocation))
CC1Args.push_back("-fno-sized-deallocation");

if (Args.hasFlag(options::OPT_ferr_pragma_mc_func_aix,
options::OPT_fno_err_pragma_mc_func_aix, false))
CC1Args.push_back("-ferr-pragma-mc-func-aix");
else
CC1Args.push_back("-fno-err-pragma-mc-func-aix");
}

void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,9 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
else if (Args.hasArg(options::OPT_mcpu_EQ))
CmdArgs.push_back(Args.MakeArgString(
"-plugin-opt=mcpu=" + Args.getLastArgValue(options::OPT_mcpu_EQ)));

addGPULibraries(getToolChain(), Args, CmdArgs);

CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,24 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
if (Args.getLastArg(options::OPT_mno_bti_at_return_twice))
Features.push_back("+no-bti-at-return-twice");
}

void aarch64::setPAuthABIInTriple(const Driver &D, const ArgList &Args,
llvm::Triple &Triple) {
Arg *ABIArg = Args.getLastArg(options::OPT_mabi_EQ);
bool HasPAuthABI =
ABIArg ? (StringRef(ABIArg->getValue()) == "pauthtest") : false;

switch (Triple.getEnvironment()) {
case llvm::Triple::UnknownEnvironment:
if (HasPAuthABI)
Triple.setEnvironment(llvm::Triple::PAuthTest);
break;
case llvm::Triple::PAuthTest:
break;
default:
if (HasPAuthABI)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< ABIArg->getAsString(Args) << Triple.getTriple();
break;
}
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, llvm::opt::Arg *&A);

void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args,
llvm::Triple &triple);

} // end namespace aarch64
} // end namespace target
} // end namespace driver
Expand Down
86 changes: 53 additions & 33 deletions clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
// Enable the `lsx` feature on 64-bit LoongArch by default.
if (Triple.isLoongArch64() &&
(!Args.hasArgNoClaim(clang::driver::options::OPT_march_EQ)))
Features.push_back("+lsx");

std::string ArchName;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
ArchName = A->getValue();
Expand All @@ -145,9 +150,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (A->getOption().matches(options::OPT_msingle_float)) {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else /*Soft-float*/ {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
}
} else if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ)) {
StringRef FPU = A->getValue();
Expand All @@ -157,9 +164,11 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else if (FPU == "32") {
Features.push_back("+f");
Features.push_back("-d");
Features.push_back("-lsx");
} else if (FPU == "0" || FPU == "none") {
Features.push_back("-f");
Features.push_back("-d");
Features.push_back("-lsx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_mfpu_EQ) << FPU;
}
Expand All @@ -174,6 +183,42 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_mfpu_EQ))
A->ignoreTargetSpecific();
if (Arg *A = Args.getLastArgNoClaim(options::OPT_msimd_EQ))
A->ignoreTargetSpecific();

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= precedes -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -msimd=lsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
else
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float, -mfpu=none/0/32 and -mno-lsx conflict with -msimd=lasx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);

// The command options do not contain -mno-lasx.
if (!Args.getLastArg(options::OPT_mno_lasx)) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD == "none") {
if (llvm::find(Features, "+lsx") != Features.end())
Features.push_back("-lsx");
if (llvm::find(Features, "+lasx") != Features.end())
Features.push_back("-lasx");
} else {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}

// Select lsx feature determined by -m[no-]lsx.
if (const Arg *A = Args.getLastArg(options::OPT_mlsx, options::OPT_mno_lsx)) {
Expand All @@ -197,44 +242,13 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
if (A->getOption().matches(options::OPT_mlasx)) {
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
else { /*-mlasx*/
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else /*-mno-lasx*/
Features.push_back("-lasx");
}

// Select lsx/lasx feature determined by -msimd=.
// Option -msimd= has lower priority than -m[no-]lsx and -m[no-]lasx.
if (const Arg *A = Args.getLastArg(options::OPT_msimd_EQ)) {
StringRef MSIMD = A->getValue();
if (MSIMD == "lsx") {
// Option -msimd=lsx depends on 64-bit FPU.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LSX*/ 0;
// The previous option does not contain feature -lsx.
else if (llvm::find(Features, "-lsx") == Features.end())
Features.push_back("+lsx");
} else if (MSIMD == "lasx") {
// Option -msimd=lasx depends on 64-bit FPU and LSX.
// -m*-float and -mfpu=none/0/32 conflict with -mlsx.
if (llvm::find(Features, "-d") != Features.end())
D.Diag(diag::err_drv_loongarch_wrong_fpu_width) << /*LASX*/ 1;
else if (llvm::find(Features, "-lsx") != Features.end())
D.Diag(diag::err_drv_loongarch_invalid_simd_option_combination);
// The previous option does not contain feature -lasx.
else if (llvm::find(Features, "-lasx") == Features.end()) {
Features.push_back("+lsx");
Features.push_back("+lasx");
}
} else if (MSIMD != "none") {
D.Diag(diag::err_drv_loongarch_invalid_msimd_EQ) << MSIMD;
}
}
}

std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
Expand All @@ -253,8 +267,14 @@ std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
std::string loongarch::getLoongArchTargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple) {
std::string CPU;
std::string Arch;
// If we have -march, use that.
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
CPU = A->getValue();
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
Arch = A->getValue();
if (Arch == "la64v1.0" || Arch == "la64v1.1")
CPU = llvm::LoongArch::getDefaultArch(Triple.isLoongArch64());
else
CPU = Arch;
}
return postProcessTargetCPUString(CPU, Triple);
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static std::string normalizeCPUName(StringRef CPUName, const llvm::Triple &T) {
.Case("power8", "pwr8")
.Case("power9", "pwr9")
.Case("power10", "pwr10")
.Case("power11", "pwr11")
.Case("future", "future")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
Expand Down Expand Up @@ -103,6 +104,8 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
.Case("power9", "-mpower9")
.Case("pwr10", "-mpower10")
.Case("power10", "-mpower10")
.Case("pwr11", "-mpower11")
.Case("power11", "-mpower11")
.Default("-many");
}

Expand Down
87 changes: 74 additions & 13 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,10 +794,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
Args.hasArg(options::OPT_coverage))
FProfileDir = Args.getLastArg(options::OPT_fprofile_dir);

// TODO: Don't claim -c/-S to warn about -fsyntax-only -c/-S, -E -c/-S,
// like we warn about -fsyntax-only -E.
(void)(Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S));

// Put the .gcno and .gcda files (if needed) next to the primary output file,
// or fall back to a file in the current directory for `clang -c --coverage
// d/a.c` in the absence of -o.
Expand Down Expand Up @@ -1486,6 +1482,41 @@ void AddUnalignedAccessWarning(ArgStringList &CmdArgs) {
}
}

// Each combination of options here forms a signing schema, and in most cases
// each signing schema is its own incompatible ABI. The default values of the
// options represent the default signing schema.
static void handlePAuthABI(const ArgList &DriverArgs, ArgStringList &CC1Args) {
if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics,
options::OPT_fno_ptrauth_intrinsics))
CC1Args.push_back("-fptrauth-intrinsics");

if (!DriverArgs.hasArg(options::OPT_fptrauth_calls,
options::OPT_fno_ptrauth_calls))
CC1Args.push_back("-fptrauth-calls");

if (!DriverArgs.hasArg(options::OPT_fptrauth_returns,
options::OPT_fno_ptrauth_returns))
CC1Args.push_back("-fptrauth-returns");

if (!DriverArgs.hasArg(options::OPT_fptrauth_auth_traps,
options::OPT_fno_ptrauth_auth_traps))
CC1Args.push_back("-fptrauth-auth-traps");

if (!DriverArgs.hasArg(
options::OPT_fptrauth_vtable_pointer_address_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination))
CC1Args.push_back("-fptrauth-vtable-pointer-address-discrimination");

if (!DriverArgs.hasArg(
options::OPT_fptrauth_vtable_pointer_type_discrimination,
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination))
CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");

if (!DriverArgs.hasArg(options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini))
CC1Args.push_back("-fptrauth-init-fini");
}

static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool isAArch64) {
const Arg *A = isAArch64
Expand Down Expand Up @@ -1548,16 +1579,30 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,

CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address=") + Scope));
if (Scope != "none")
if (Scope != "none") {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
if (BranchProtectionPAuthLR)
}
if (BranchProtectionPAuthLR) {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back(
Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
}
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
if (GuardedControlStack)
// GCS is currently untested with PAuthABI, but enabling this could be allowed
// in future after testing with a suitable system.
if (GuardedControlStack) {
if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << Triple.getTriple();
CmdArgs.push_back("-mguarded-control-stack");
}
}

void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args,
Expand Down Expand Up @@ -1701,6 +1746,8 @@ void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args,
ABIName = A->getValue();
else if (Triple.isOSDarwin())
ABIName = "darwinpcs";
else if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
ABIName = "pauthtest";
else
ABIName = "aapcs";

Expand Down Expand Up @@ -1737,6 +1784,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
// Enable/disable return address signing and indirect branch targets.
CollectARMPACBTIOptions(getToolChain(), Args, CmdArgs, true /*isAArch64*/);

if (Triple.getEnvironment() == llvm::Triple::PAuthTest)
handlePAuthABI(Args, CmdArgs);

// Handle -msve_vector_bits=<bits>
if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) {
StringRef Val = A->getValue();
Expand Down Expand Up @@ -1794,6 +1844,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
options::OPT_fno_ptrauth_function_pointer_type_discrimination);

Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos);
}

void Clang::AddLoongArchTargetArgs(const ArgList &Args,
Expand Down Expand Up @@ -3903,6 +3956,9 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
options::OPT_fno_modules_strict_decluse, false))
CmdArgs.push_back("-fmodules-strict-decluse");

Args.addOptOutFlag(CmdArgs, options::OPT_fmodulemap_allow_subdirectory_search,
options::OPT_fno_modulemap_allow_subdirectory_search);

// -fno-implicit-modules turns off implicitly compiling modules on demand.
bool ImplicitModules = false;
if (!Args.hasFlag(options::OPT_fimplicit_modules,
Expand Down Expand Up @@ -4661,11 +4717,8 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,

// -gdwarf-aranges turns on the emission of the aranges section in the
// backend.
// Always enabled for SCE tuning.
bool NeedAranges = DebuggerTuning == llvm::DebuggerKind::SCE;
if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges))
NeedAranges = checkDebugInfoOption(A, Args, D, TC) || NeedAranges;
if (NeedAranges) {
if (const Arg *A = Args.getLastArg(options::OPT_gdwarf_aranges);
A && checkDebugInfoOption(A, Args, D, TC)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-generate-arange-section");
}
Expand Down Expand Up @@ -6666,7 +6719,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
StringRef S0 = A->getValue(), S = S0;
unsigned Size, Offset = 0;
if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() &&
!Triple.isX86())
!Triple.isX86() &&
!(!Triple.isOSAIX() && (Triple.getArch() == llvm::Triple::ppc ||
Triple.getArch() == llvm::Triple::ppc64)))
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
else if (S.consumeInteger(10, Size) ||
Expand Down Expand Up @@ -6759,6 +6814,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (const char *Name = C.getTimeTraceFile(&JA)) {
CmdArgs.push_back(Args.MakeArgString("-ftime-trace=" + Twine(Name)));
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ);
Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_verbose);
}

if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) {
Expand Down Expand Up @@ -9048,6 +9104,11 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
A->claim();
}

// If we disable the GPU C library support it needs to be forwarded to the
// link job.
if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, true))
CmdArgs.push_back("--device-linker=-nolibc");

// Add the linker arguments to be forwarded by the wrapper.
CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") +
LinkCommand->getExecutable()));
Expand Down
56 changes: 17 additions & 39 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,22 @@ void tools::addLinkerCompressDebugSectionsOption(
}
}

void tools::addGPULibraries(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
if (Args.hasArg(options::OPT_nostdlib, options::OPT_r,
options::OPT_nodefaultlibs, options::OPT_nolibc,
options::OPT_nogpulibc))
return;

// If the user's toolchain has the 'include/<triple>/` path, we assume it
// supports the standard C libraries for the GPU and include them.
bool HasLibC = TC.getStdlibIncludePath().has_value();
if (HasLibC) {
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lm");
}
}

void tools::AddTargetFeature(const ArgList &Args,
std::vector<StringRef> &Features,
OptSpecifier OnOpt, OptSpecifier OffOpt,
Expand Down Expand Up @@ -1145,42 +1161,6 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args,
}
}

/// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the
/// LLVM C library for GPUs.
static void addOpenMPDeviceLibC(const Compilation &C, const ArgList &Args,
ArgStringList &CmdArgs) {
if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc))
return;

// Check the resource directory for the LLVM libc GPU declarations. If it's
// found we can assume that LLVM was built with support for the GPU libc.
SmallString<256> LibCDecls(C.getDriver().ResourceDir);
llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers",
"llvm-libc-decls");
bool HasLibC = llvm::sys::fs::exists(LibCDecls) &&
llvm::sys::fs::is_directory(LibCDecls);
if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC))
return;

SmallVector<const ToolChain *> ToolChains;
auto TCRange = C.getOffloadToolChains(Action::OFK_OpenMP);
for (auto TI = TCRange.first, TE = TCRange.second; TI != TE; ++TI)
ToolChains.push_back(TI->second);

if (llvm::any_of(ToolChains, [](const ToolChain *TC) {
return TC->getTriple().isAMDGPU();
})) {
CmdArgs.push_back("-lcgpu-amdgpu");
CmdArgs.push_back("-lmgpu-amdgpu");
}
if (llvm::any_of(ToolChains, [](const ToolChain *TC) {
return TC->getTriple().isNVPTX();
})) {
CmdArgs.push_back("-lcgpu-nvptx");
CmdArgs.push_back("-lmgpu-nvptx");
}
}

void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC,
const ArgList &Args,
ArgStringList &CmdArgs) {
Expand Down Expand Up @@ -1253,10 +1233,8 @@ bool tools::addOpenMPRuntime(const Compilation &C, ArgStringList &CmdArgs,
if (IsOffloadingHost && !Args.hasArg(options::OPT_nogpulib))
CmdArgs.push_back("-lomptarget.devicertl");

if (IsOffloadingHost)
addOpenMPDeviceLibC(C, Args, CmdArgs);

addArchSpecificRPath(TC, Args, CmdArgs);

addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs);

return true;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ void addLinkerCompressDebugSectionsOption(const ToolChain &TC,
const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);

void addGPULibraries(const ToolChain &TC, const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);

void claimNoWarnArgs(const llvm::opt::ArgList &Args);

bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args,
Expand Down
71 changes: 18 additions & 53 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,6 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--output-file");
std::string OutputFileName = TC.getInputFilename(Output);

// If we are invoking `nvlink` internally we need to output a `.cubin` file.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (!C.getInputArgs().getLastArg(options::OPT_c)) {
SmallString<256> Filename(Output.getFilename());
llvm::sys::path::replace_extension(Filename, "cubin");
OutputFileName = Filename.str();
}
if (Output.isFilename() && OutputFileName != Output.getFilename())
C.addTempFile(Args.MakeArgString(OutputFileName));

Expand Down Expand Up @@ -612,64 +605,40 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-arch");
CmdArgs.push_back(Args.MakeArgString(GPUArch));

if (Args.hasArg(options::OPT_ptxas_path_EQ))
CmdArgs.push_back(Args.MakeArgString(
"--pxtas-path=" + Args.getLastArgValue(options::OPT_ptxas_path_EQ)));

if (Args.hasArg(options::OPT_cuda_path_EQ))
CmdArgs.push_back(Args.MakeArgString(
"--cuda-path=" + Args.getLastArgValue(options::OPT_cuda_path_EQ)));

// Add paths specified in LIBRARY_PATH environment variable as -L options.
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

// Add standard library search paths passed on the command line.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);

if (C.getDriver().isUsingLTO())
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
C.getDriver().getLTOMode() == LTOK_Thin);

addGPULibraries(getToolChain(), Args, CmdArgs);

// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
llvm::sys::path::append(DefaultLibPath, CLANG_INSTALL_LIBDIR_BASENAME);
CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));

for (const auto &II : Inputs) {
if (II.getType() == types::TY_LLVM_IR || II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LTO_BC || II.getType() == types::TY_LLVM_BC) {
C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
continue;
}

// The 'nvlink' application performs RDC-mode linking when given a '.o'
// file and device linking when given a '.cubin' file. We always want to
// perform device linking, so just rename any '.o' files.
// FIXME: This should hopefully be removed if NVIDIA updates their tooling.
if (II.isFilename()) {
auto InputFile = getToolChain().getInputFilename(II);
if (llvm::sys::path::extension(InputFile) != ".cubin") {
// If there are no actions above this one then this is direct input and
// we can copy it. Otherwise the input is internal so a `.cubin` file
// should exist.
if (II.getAction() && II.getAction()->getInputs().size() == 0) {
const char *CubinF =
Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath(
llvm::sys::path::stem(InputFile), "cubin"));
if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF)))
continue;

CmdArgs.push_back(CubinF);
} else {
SmallString<256> Filename(InputFile);
llvm::sys::path::replace_extension(Filename, "cubin");
CmdArgs.push_back(Args.MakeArgString(Filename));
}
} else {
CmdArgs.push_back(Args.MakeArgString(InputFile));
}
} else if (!II.isNothing()) {
II.getInputArg().renderAsInput(Args, CmdArgs);
}
}

C.addCommand(std::make_unique<Command>(
JA, *this,
ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8,
"--options-file"},
Args.MakeArgString(getToolChain().GetProgramPath("nvlink")), CmdArgs,
Inputs, Output));
Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")),
CmdArgs, Inputs, Output));
}

void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Expand Down Expand Up @@ -949,11 +918,7 @@ std::string CudaToolChain::getInputFilename(const InputInfo &Input) const {
if (Input.getType() != types::TY_Object || getDriver().offloadDeviceOnly())
return ToolChain::getInputFilename(Input);

// Replace extension for object files with cubin because nvlink relies on
// these particular file names.
SmallString<256> Filename(ToolChain::getInputFilename(Input));
llvm::sys::path::replace_extension(Filename, "cubin");
return std::string(Filename);
return ToolChain::getInputFilename(Input);
}

llvm::opt::DerivedArgList *
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ class LLVM_LIBRARY_VISIBILITY NVPTXToolChain : public ToolChain {
bool isPIEDefault(const llvm::opt::ArgList &Args) const override {
return false;
}
bool HasNativeLLVMSupport() const override { return true; }
bool isPICDefaultForced() const override { return false; }
bool SupportsProfiling() const override { return false; }

Expand Down Expand Up @@ -192,6 +193,8 @@ class LLVM_LIBRARY_VISIBILITY CudaToolChain : public NVPTXToolChain {
return &HostTC.getTriple();
}

bool HasNativeLLVMSupport() const override { return false; }

std::string getInputFilename(const InputInfo &Input) const override;

llvm::opt::DerivedArgList *
Expand Down
29 changes: 29 additions & 0 deletions clang/lib/Driver/ToolChains/Darwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3036,6 +3036,35 @@ void Darwin::addClangTargetOptions(
if (!DriverArgs.hasArgNoClaim(options::OPT_fdefine_target_os_macros,
options::OPT_fno_define_target_os_macros))
CC1Args.push_back("-fdefine-target-os-macros");

// Disable subdirectory modulemap search on sufficiently recent SDKs.
if (SDKInfo &&
!DriverArgs.hasFlag(options::OPT_fmodulemap_allow_subdirectory_search,
options::OPT_fno_modulemap_allow_subdirectory_search,
false)) {
bool RequiresSubdirectorySearch;
VersionTuple SDKVersion = SDKInfo->getVersion();
switch (TargetPlatform) {
default:
RequiresSubdirectorySearch = true;
break;
case MacOS:
RequiresSubdirectorySearch = SDKVersion < VersionTuple(15, 0);
break;
case IPhoneOS:
case TvOS:
RequiresSubdirectorySearch = SDKVersion < VersionTuple(18, 0);
break;
case WatchOS:
RequiresSubdirectorySearch = SDKVersion < VersionTuple(11, 0);
break;
case XROS:
RequiresSubdirectorySearch = SDKVersion < VersionTuple(2, 0);
break;
}
if (!RequiresSubdirectorySearch)
CC1Args.push_back("-fno-modulemap-allow-subdirectory-search");
}
}

void Darwin::addClangCC1ASTargetOptions(
Expand Down
29 changes: 0 additions & 29 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,41 +672,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}

// Facebook T92898286
if (Args.hasArg(options::OPT_post_link_optimize))
CmdArgs.push_back("-q");
// End Facebook T92898286

Args.AddAllArgs(CmdArgs, options::OPT_T);

const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
// Facebook T92898286
if (!Args.hasArg(options::OPT_post_link_optimize) || !Output.isFilename())
return;

const char *MvExec = Args.MakeArgString(ToolChain.GetProgramPath("mv"));
ArgStringList MoveCmdArgs;
MoveCmdArgs.push_back(Output.getFilename());
const char *PreBoltBin =
Args.MakeArgString(Twine(Output.getFilename()) + ".pre-bolt");
MoveCmdArgs.push_back(PreBoltBin);
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
MvExec, MoveCmdArgs, std::nullopt));

ArgStringList BoltCmdArgs;
const char *BoltExec =
Args.MakeArgString(ToolChain.GetProgramPath("llvm-bolt"));
BoltCmdArgs.push_back(PreBoltBin);
BoltCmdArgs.push_back("-reorder-blocks=reverse");
BoltCmdArgs.push_back("-update-debug-sections");
BoltCmdArgs.push_back("-o");
BoltCmdArgs.push_back(Output.getFilename());
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
BoltExec, BoltCmdArgs, std::nullopt));
// End Facebook T92898286
}

void tools::gnutools::Assembler::ConstructJob(Compilation &C,
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ std::string Linux::getMultiarchTriple(const Driver &D,
case llvm::Triple::aarch64:
if (IsAndroid)
return "aarch64-linux-android";
if (hasEffectiveTriple() &&
getEffectiveTriple().getEnvironment() == llvm::Triple::PAuthTest)
return "aarch64-linux-pauthtest";
return "aarch64-linux-gnu";
case llvm::Triple::aarch64_be:
return "aarch64_be-linux-gnu";
Expand Down
8 changes: 0 additions & 8 deletions clang/lib/Driver/ToolChains/PS4CPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,6 @@ void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
};

if (UseLTO) {
// We default to creating the arange section, but LTO does not. Enable it
// here.
AddCodeGenFlag("-generate-arange-section");

// This tells LTO to perform JustMyCode instrumentation.
if (UseJMC)
AddCodeGenFlag("-enable-jmc-instrument");
Expand Down Expand Up @@ -272,10 +268,6 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,
};

if (UseLTO) {
// We default to creating the arange section, but LTO does not. Enable it
// here.
AddCodeGenFlag("-generate-arange-section");

// This tells LTO to perform JustMyCode instrumentation.
if (UseJMC)
AddCodeGenFlag("-enable-jmc-instrument");
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/PS4CPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ class LLVM_LIBRARY_VISIBILITY PS5CPU : public PS4PS5Base {
llvm::opt::ArgStringList &CmdArgs, const char *Prefix,
const char *Suffix) const override;
const char *getProfileRTLibName() const override {
return "libclang_rt.profile-x86_64_nosubmission.a";
return "libclang_rt.profile_nosubmission.a";
}

protected:
Expand Down
Loading