Skip to content

Commit f758d86

Browse files
committed
Merge branch 'main' into merge-functions
2 parents 8703263 + 79dab3f commit f758d86

File tree

122 files changed

+3662
-5795
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+3662
-5795
lines changed

clang/include/clang/Basic/AttrDocs.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3985,6 +3985,8 @@ The capturing entity ``X`` can be one of the following:
39853985
std::set<std::string_view> s;
39863986
};
39873987

3988+
Note: When applied to a constructor parameter, `[[clang::lifetime_capture_by(this)]]` is just an alias of `[[clang::lifetimebound]]`.
3989+
39883990
- `global`, `unknown`.
39893991

39903992
.. code-block:: c++

clang/include/clang/Basic/TargetBuiltins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ namespace clang {
336336
bool isTupleSet() const { return Flags & IsTupleSet; }
337337
bool isReadZA() const { return Flags & IsReadZA; }
338338
bool isWriteZA() const { return Flags & IsWriteZA; }
339+
bool setsFPMR() const { return Flags & SetsFPMR; }
339340
bool isReductionQV() const { return Flags & IsReductionQV; }
340341
uint64_t getBits() const { return Flags; }
341342
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }

clang/include/clang/Basic/arm_sve.td

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,14 +2422,16 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
24222422
def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>;
24232423
}
24242424

2425-
//
2426-
// Multi-vector scaling
2427-
//
2428-
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
2425+
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
2426+
// Multi-vector scaling
24292427
def FSCALE_SINGLE_X2 : Inst<"svscale[_single_{d}_x2]", "22x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x2", [IsStreaming],[]>;
24302428
def FSCALE_SINGLE_X4 : Inst<"svscale[_single_{d}_x4]", "44x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x4", [IsStreaming],[]>;
24312429
def FSCALE_X2 : Inst<"svscale[_{d}_x2]", "222.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x2", [IsStreaming],[]>;
24322430
def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x4", [IsStreaming],[]>;
2431+
2432+
// Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector
2433+
def SVF1CVTL : Inst<"svcvtl1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming, SetsFPMR], []>;
2434+
def SVF2CVTL : Inst<"svcvtl2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming, SetsFPMR], []>;
24332435
}
24342436

24352437
let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {

clang/include/clang/Basic/arm_sve_sme_incl.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ include "arm_immcheck_incl.td"
9494
// l: int64_t
9595
// m: uint32_t
9696
// n: uint64_t
97+
// >: fpm_t
9798

9899
// [: svuint8_t
99100
// t: svint32_t
@@ -103,6 +104,7 @@ include "arm_immcheck_incl.td"
103104
// M: svfloat32_t
104105
// N: svfloat64_t
105106
// $: svbfloat16_t
107+
// ~: svmfloat8_t
106108

107109
// J: Prefetch type (sv_prfop)
108110

@@ -235,6 +237,7 @@ def IsInOutZA : FlagType<0x200000000000>;
235237
def IsInZT0 : FlagType<0x400000000000>;
236238
def IsOutZT0 : FlagType<0x800000000000>;
237239
def IsInOutZT0 : FlagType<0x1000000000000>;
240+
def SetsFPMR : FlagType<0x2000000000000>;
238241

239242
defvar InvalidMode = "";
240243

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10859,6 +10859,10 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
1085910859
else if (TypeFlags.isUndef())
1086010860
return UndefValue::get(Ty);
1086110861
else if (Builtin->LLVMIntrinsic != 0) {
10862+
// Emit set FPMR for intrinsics that require it
10863+
if (TypeFlags.setsFPMR())
10864+
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_set_fpmr),
10865+
Ops.pop_back_val());
1086210866
if (TypeFlags.getMergeType() == SVETypeFlags::MergeZeroExp)
1086310867
InsertExplicitZeroOperand(Builder, Ty, Ops);
1086410868

clang/lib/Sema/CheckExprLifetime.cpp

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "CheckExprLifetime.h"
1010
#include "clang/AST/Decl.h"
1111
#include "clang/AST/Expr.h"
12+
#include "clang/AST/Type.h"
1213
#include "clang/Basic/DiagnosticSema.h"
1314
#include "clang/Sema/Initialization.h"
1415
#include "clang/Sema/Sema.h"
@@ -253,9 +254,17 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
253254
LocalVisitor Visit);
254255

255256
template <typename T> static bool isRecordWithAttr(QualType Type) {
256-
if (auto *RD = Type->getAsCXXRecordDecl())
257-
return RD->hasAttr<T>();
258-
return false;
257+
auto *RD = Type->getAsCXXRecordDecl();
258+
if (!RD)
259+
return false;
260+
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
261+
RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
262+
return RD->hasAttr<T>();
263+
}
264+
265+
bool isPointerLikeType(QualType QT) {
266+
return isRecordWithAttr<PointerAttr>(QT) || QT->isPointerType() ||
267+
QT->isNullPtrType();
259268
}
260269

261270
// Decl::isInStdNamespace will return false for iterators in some STL
@@ -276,11 +285,6 @@ static bool isInStlNamespace(const Decl *D) {
276285
return DC->isStdNamespace();
277286
}
278287

279-
static bool isPointerLikeType(QualType Type) {
280-
return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
281-
Type->isNullPtrType();
282-
}
283-
284288
// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
285289
// type, e.g. std::vector<string_view>, std::optional<string_view>.
286290
static bool isContainerOfPointer(const RecordDecl *Container) {
@@ -623,6 +627,26 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
623627
}
624628
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
625629
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
630+
else if (const auto *CaptureAttr =
631+
Callee->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>();
632+
CaptureAttr && isa<CXXConstructorDecl>(Callee) &&
633+
llvm::any_of(CaptureAttr->params(), [](int ArgIdx) {
634+
return ArgIdx == LifetimeCaptureByAttr::THIS;
635+
}))
636+
// `lifetime_capture_by(this)` in a class constructor has the same
637+
// semantics as `lifetimebound`:
638+
//
639+
// struct Foo {
640+
// const int& a;
641+
// // Equivalent to Foo(const int& t [[clang::lifetimebound]])
642+
// Foo(const int& t [[clang::lifetime_capture_by(this)]]) : a(t) {}
643+
// };
644+
//
645+
// In the implementation, `lifetime_capture_by` is treated as an alias for
646+
// `lifetimebound` and shares the same code path. This implies the emitted
647+
// diagnostics will be emitted under `-Wdangling`, not
648+
// `-Wdangling-capture`.
649+
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
626650
else if (EnableGSLAnalysis && I == 0) {
627651
// Perform GSL analysis for the first argument
628652
if (shouldTrackFirstArgument(Callee)) {

clang/lib/Sema/CheckExprLifetime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@
1818

1919
namespace clang::sema {
2020

21+
// Tells whether the type is annotated with [[gsl::Pointer]] or is a pointer
22+
// type.
23+
bool isPointerLikeType(QualType QT);
24+
2125
/// Describes an entity that is being assigned.
2226
struct AssignedEntity {
2327
// The left-hand side expression of the assignment.

clang/lib/Sema/SemaAttr.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,6 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
269269
}
270270
}
271271

272-
static bool isPointerLikeType(QualType QT) {
273-
QT = QT.getNonReferenceType();
274-
if (QT->isPointerType())
275-
return true;
276-
auto *RD = QT->getAsCXXRecordDecl();
277-
if (!RD)
278-
return false;
279-
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
280-
RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
281-
return RD->hasAttr<PointerAttr>();
282-
}
283-
284272
void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
285273
if (!FD)
286274
return;
@@ -299,7 +287,7 @@ void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
299287
if (PVD->hasAttr<LifetimeCaptureByAttr>())
300288
return;
301289
for (ParmVarDecl *PVD : MD->parameters()) {
302-
if (isPointerLikeType(PVD->getType())) {
290+
if (sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
303291
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
304292
PVD->addAttr(
305293
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));

clang/lib/Sema/SemaChecking.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3240,8 +3240,14 @@ void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
32403240
unsigned ArgIdx) {
32413241
if (!Attr)
32423242
return;
3243+
32433244
Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx));
32443245
for (int CapturingParamIdx : Attr->params()) {
3246+
// lifetime_capture_by(this) case is handled in the lifetimebound expr
3247+
// initialization codepath.
3248+
if (CapturingParamIdx == LifetimeCaptureByAttr::THIS &&
3249+
isa<CXXConstructorDecl>(FD))
3250+
continue;
32453251
Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx));
32463252
CapturingEntity CE{Capturing};
32473253
// Ensure that 'Captured' outlives the 'Capturing' entity.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
3+
// REQUIRES: aarch64-registered-target
4+
5+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s
6+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK
7+
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s
8+
// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK
9+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +fp8 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s
10+
11+
#include <arm_sve.h>
12+
13+
#ifdef SVE_OVERLOADED_FORMS
14+
#define SVE_ACLE_FUNC(A1,A2_UNUSED,A3) A1##A3
15+
#else
16+
#define SVE_ACLE_FUNC(A1,A2,A3) A1##A2##A3
17+
#endif
18+
19+
// CHECK-LABEL: @test_cvtl1_f16_x2(
20+
// CHECK-NEXT: entry:
21+
// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
22+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x half>, <vscale x 8 x half> } @llvm.aarch64.sve.fp8.cvtl1.x2.nxv8f16(<vscale x 16 x i8> [[ZN:%.*]])
23+
// CHECK-NEXT: ret { <vscale x 8 x half>, <vscale x 8 x half> } [[TMP0]]
24+
//
25+
// CPP-CHECK-LABEL: @_Z17test_cvtl1_f16_x2u13__SVMfloat8_tm(
26+
// CPP-CHECK-NEXT: entry:
27+
// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
28+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x half>, <vscale x 8 x half> } @llvm.aarch64.sve.fp8.cvtl1.x2.nxv8f16(<vscale x 16 x i8> [[ZN:%.*]])
29+
// CPP-CHECK-NEXT: ret { <vscale x 8 x half>, <vscale x 8 x half> } [[TMP0]]
30+
//
31+
svfloat16x2_t test_cvtl1_f16_x2(svmfloat8_t zn, fpm_t fpmr) __arm_streaming {
32+
return SVE_ACLE_FUNC(svcvtl1_f16,_mf8,_x2_fpm)(zn, fpmr);
33+
}
34+
35+
// CHECK-LABEL: @test_cvtl2_f16_x2(
36+
// CHECK-NEXT: entry:
37+
// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
38+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x half>, <vscale x 8 x half> } @llvm.aarch64.sve.fp8.cvtl2.x2.nxv8f16(<vscale x 16 x i8> [[ZN:%.*]])
39+
// CHECK-NEXT: ret { <vscale x 8 x half>, <vscale x 8 x half> } [[TMP0]]
40+
//
41+
// CPP-CHECK-LABEL: @_Z17test_cvtl2_f16_x2u13__SVMfloat8_tm(
42+
// CPP-CHECK-NEXT: entry:
43+
// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
44+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x half>, <vscale x 8 x half> } @llvm.aarch64.sve.fp8.cvtl2.x2.nxv8f16(<vscale x 16 x i8> [[ZN:%.*]])
45+
// CPP-CHECK-NEXT: ret { <vscale x 8 x half>, <vscale x 8 x half> } [[TMP0]]
46+
//
47+
svfloat16x2_t test_cvtl2_f16_x2(svmfloat8_t zn, fpm_t fpmr) __arm_streaming {
48+
return SVE_ACLE_FUNC(svcvtl2_f16,_mf8,_x2_fpm)(zn, fpmr);
49+
}
50+
51+
// CHECK-LABEL: @test_cvtl1_bf16_x2(
52+
// CHECK-NEXT: entry:
53+
// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
54+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } @llvm.aarch64.sve.fp8.cvtl1.x2.nxv8bf16(<vscale x 16 x i8> [[ZN:%.*]])
55+
// CHECK-NEXT: ret { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } [[TMP0]]
56+
//
57+
// CPP-CHECK-LABEL: @_Z18test_cvtl1_bf16_x2u13__SVMfloat8_tm(
58+
// CPP-CHECK-NEXT: entry:
59+
// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
60+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } @llvm.aarch64.sve.fp8.cvtl1.x2.nxv8bf16(<vscale x 16 x i8> [[ZN:%.*]])
61+
// CPP-CHECK-NEXT: ret { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } [[TMP0]]
62+
//
63+
svbfloat16x2_t test_cvtl1_bf16_x2(svmfloat8_t zn, fpm_t fpmr) __arm_streaming {
64+
return SVE_ACLE_FUNC(svcvtl1_bf16,_mf8,_x2_fpm)(zn, fpmr);
65+
}
66+
67+
// CHECK-LABEL: @test_cvtl2_bf16_x2(
68+
// CHECK-NEXT: entry:
69+
// CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
70+
// CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } @llvm.aarch64.sve.fp8.cvtl2.x2.nxv8bf16(<vscale x 16 x i8> [[ZN:%.*]])
71+
// CHECK-NEXT: ret { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } [[TMP0]]
72+
//
73+
// CPP-CHECK-LABEL: @_Z18test_cvtl2_bf16_x2u13__SVMfloat8_tm(
74+
// CPP-CHECK-NEXT: entry:
75+
// CPP-CHECK-NEXT: tail call void @llvm.aarch64.set.fpmr(i64 [[FPMR:%.*]])
76+
// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } @llvm.aarch64.sve.fp8.cvtl2.x2.nxv8bf16(<vscale x 16 x i8> [[ZN:%.*]])
77+
// CPP-CHECK-NEXT: ret { <vscale x 8 x bfloat>, <vscale x 8 x bfloat> } [[TMP0]]
78+
//
79+
svbfloat16x2_t test_cvtl2_bf16_x2(svmfloat8_t zn, fpm_t fpmr) __arm_streaming {
80+
return SVE_ACLE_FUNC(svcvtl2_bf16,_mf8,_x2_fpm)(zn, fpmr);
81+
}

0 commit comments

Comments
 (0)