[clang] [AArch64] Add support for the __{inc|add}x18{byte|word|dword|qword intrinsics (PR #117752)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Nov 26 09:31:05 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-backend-x86
Author: Daniel Paoliello (dpaoliello)
<details>
<summary>Changes</summary>
Adds support for the following MSVC intrinsics:
* `__addx18byte`
* `__addx18word`
* `__addx18dword`
* `__addx18qword`
* `__incx18byte`
* `__incx18word`
* `__incx18dword`
* `__incx18qword`
These are documented at: <https://learn.microsoft.com/en-us/cpp/intrinsics/arm64-intrinsics?view=msvc-170>
---
Full diff: https://github.com/llvm/llvm-project/pull/117752.diff
4 Files Affected:
- (modified) clang/include/clang/Basic/BuiltinsAArch64.def (+10)
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+67-17)
- (modified) clang/lib/Headers/intrin.h (+10)
- (modified) clang/test/CodeGen/arm64-microsoft-intrinsics.c (+148)
``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def
index 473b1d4698f04a..aeb9cdee38f40f 100644
--- a/clang/include/clang/Basic/BuiltinsAArch64.def
+++ b/clang/include/clang/Basic/BuiltinsAArch64.def
@@ -281,6 +281,16 @@ TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__addx18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+
+TARGET_HEADER_BUILTIN(__incx18byte, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18word, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18dword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+TARGET_HEADER_BUILTIN(__incx18qword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
+
TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 91b70b4fdf3d20..d6f5e71d989bbc 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -244,6 +244,19 @@ static Value *handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E) {
return CGF.Builder.CreateBitCast(BitVec, ResultType);
}
+/// Helper for the read/write/add/inc X18 builtins: read the X18 register and
+/// return it as an i8 pointer.
+Value *readX18AsPtr(CodeGenFunction &CGF) {
+ LLVMContext &Context = CGF.CGM.getLLVMContext();
+ llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
+ llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
+ llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
+ llvm::Function *F =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF.Int64Ty});
+ llvm::Value *X18 = CGF.Builder.CreateCall(F, Metadata);
+ return CGF.Builder.CreateIntToPtr(X18, CGF.Int8PtrTy);
+}
+
/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
@@ -11821,14 +11834,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
BuiltinID == AArch64::BI__writex18dword ||
BuiltinID == AArch64::BI__writex18qword) {
// Read x18 as i8*
- LLVMContext &Context = CGM.getLLVMContext();
- llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
- llvm::Function *F =
- CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
- llvm::Value *X18 = Builder.CreateCall(F, Metadata);
- X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
+ llvm::Value *X18 = readX18AsPtr(*this);
// Store val at x18 + offset
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
@@ -11842,23 +11848,67 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
BuiltinID == AArch64::BI__readx18word ||
BuiltinID == AArch64::BI__readx18dword ||
BuiltinID == AArch64::BI__readx18qword) {
+ // Read x18 as i8*
+ llvm::Value *X18 = readX18AsPtr(*this);
+
+ // Load x18 + offset
+ Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
+ Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
llvm::Type *IntTy = ConvertType(E->getType());
+ LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
+ return Load;
+ }
+
+ if (BuiltinID == AArch64::BI__addx18byte ||
+ BuiltinID == AArch64::BI__addx18word ||
+ BuiltinID == AArch64::BI__addx18dword ||
+ BuiltinID == AArch64::BI__addx18qword ||
+ BuiltinID == AArch64::BI__incx18byte ||
+ BuiltinID == AArch64::BI__incx18word ||
+ BuiltinID == AArch64::BI__incx18dword ||
+ BuiltinID == AArch64::BI__incx18qword) {
+ llvm::Type *IntTy;
+ bool isIncrement;
+ switch (BuiltinID) {
+ case AArch64::BI__incx18byte:
+ IntTy = Int8Ty;
+ isIncrement = true;
+ break;
+ case AArch64::BI__incx18word:
+ IntTy = Int16Ty;
+ isIncrement = true;
+ break;
+ case AArch64::BI__incx18dword:
+ IntTy = Int32Ty;
+ isIncrement = true;
+ break;
+ case AArch64::BI__incx18qword:
+ IntTy = Int64Ty;
+ isIncrement = true;
+ break;
+ default:
+ IntTy = ConvertType(E->getArg(1)->getType());
+ isIncrement = false;
+ break;
+ }
// Read x18 as i8*
- LLVMContext &Context = CGM.getLLVMContext();
- llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
- llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
- llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
- llvm::Function *F =
- CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
- llvm::Value *X18 = Builder.CreateCall(F, Metadata);
- X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
+ llvm::Value *X18 = readX18AsPtr(*this);
// Load x18 + offset
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
- return Load;
+
+ // Add values
+ Value *ValToAdd =
+ isIncrement ? ConstantInt::get(IntTy, 1) : EmitScalarExpr(E->getArg(1));
+ Value *AddResult = Builder.CreateAdd(Load, ValToAdd);
+
+ // Store val at x18 + offset
+ StoreInst *Store =
+ Builder.CreateAlignedStore(AddResult, Ptr, CharUnits::One());
+ return Store;
}
if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||
diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index 6308c865ca9136..9e89ae31187d14 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -396,6 +396,16 @@ unsigned short __readx18word(unsigned long offset);
unsigned long __readx18dword(unsigned long offset);
unsigned __int64 __readx18qword(unsigned long offset);
+void __addx18byte(unsigned long offset, unsigned char data);
+void __addx18word(unsigned long offset, unsigned short data);
+void __addx18dword(unsigned long offset, unsigned long data);
+void __addx18qword(unsigned long offset, unsigned __int64 data);
+
+void __incx18byte(unsigned long offset);
+void __incx18word(unsigned long offset);
+void __incx18dword(unsigned long offset);
+void __incx18qword(unsigned long offset);
+
double _CopyDoubleFromInt64(__int64);
float _CopyFloatFromInt32(__int32);
__int32 _CopyInt32FromFloat(float);
diff --git a/clang/test/CodeGen/arm64-microsoft-intrinsics.c b/clang/test/CodeGen/arm64-microsoft-intrinsics.c
index 7953618d2f9d13..fd104642664611 100644
--- a/clang/test/CodeGen/arm64-microsoft-intrinsics.c
+++ b/clang/test/CodeGen/arm64-microsoft-intrinsics.c
@@ -288,6 +288,154 @@ unsigned __int64 check__readx18qword(unsigned LONG offset) {
// CHECK-MSCOMPAT: %[[RETVAL:.*]] = load i64, ptr %[[PTR]], align 1
// CHECK-MSCOMPAT: ret i64 %[[RETVAL]]
+#ifdef __LP64__
+void check__addx18byte(unsigned char data, unsigned LONG offset) {
+#else
+void check__addx18byte(unsigned LONG offset, unsigned char data) {
+#endif
+ __addx18byte(offset, data);
+}
+
+// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i8, align 1
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i8 %data, ptr %[[DATA_ADDR]], align 1
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i8, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[DATA:.*]] = load i8, ptr %[[DATA_ADDR]], align 1
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i8 %[[ORIG_VAL]], %[[DATA]]
+// CHECK-MSCOMPAT: store i8 %[[SUM]], ptr %[[PTR]], align 1
+
+#ifdef __LP64__
+void check__addx18word(unsigned short data, unsigned LONG offset) {
+#else
+void check__addx18word(unsigned LONG offset, unsigned short data) {
+#endif
+ __addx18word(offset, data);
+}
+
+// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i16, align 2
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i16 %data, ptr %[[DATA_ADDR]], align 2
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i16, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[DATA:.*]] = load i16, ptr %[[DATA_ADDR]], align 2
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i16 %[[ORIG_VAL]], %[[DATA]]
+// CHECK-MSCOMPAT: store i16 %[[SUM]], ptr %[[PTR]], align 1
+
+#ifdef __LP64__
+void check__addx18dword(unsigned LONG data, unsigned LONG offset) {
+#else
+void check__addx18dword(unsigned LONG offset, unsigned LONG data) {
+#endif
+ __addx18dword(offset, data);
+}
+
+// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i32 %data, ptr %[[DATA_ADDR]], align 4
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i32, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[DATA:.*]] = load i32, ptr %[[DATA_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i32 %[[ORIG_VAL]], %[[DATA]]
+// CHECK-MSCOMPAT: store i32 %[[SUM]], ptr %[[PTR]], align 1
+
+#ifdef __LP64__
+void check__addx18qword(unsigned __int64 data, unsigned LONG offset) {
+#else
+void check__addx18qword(unsigned LONG offset, unsigned __int64 data) {
+#endif
+ __addx18qword(offset, data);
+}
+
+// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i64, align 8
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i64 %data, ptr %[[DATA_ADDR]], align 8
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i64, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[DATA:.*]] = load i64, ptr %[[DATA_ADDR]], align 8
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i64 %[[ORIG_VAL]], %[[DATA]]
+// CHECK-MSCOMPAT: store i64 %[[SUM]], ptr %[[PTR]], align 1
+
+void check__incx18byte(unsigned LONG offset) {
+ __incx18byte(offset);
+}
+
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i8, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i8 %[[ORIG_VAL]], 1
+// CHECK-MSCOMPAT: store i8 %[[SUM]], ptr %[[PTR]], align 1
+
+void check__incx18word(unsigned LONG offset) {
+ __incx18word(offset);
+}
+
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i16, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i16 %[[ORIG_VAL]], 1
+// CHECK-MSCOMPAT: store i16 %[[SUM]], ptr %[[PTR]], align 1
+
+void check__incx18dword(unsigned LONG offset) {
+ __incx18dword(offset);
+}
+
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i32, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i32 %[[ORIG_VAL]], 1
+// CHECK-MSCOMPAT: store i32 %[[SUM]], ptr %[[PTR]], align 1
+
+void check__incx18qword(unsigned LONG offset) {
+ __incx18qword(offset);
+}
+
+// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
+// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
+// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
+// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
+// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
+// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
+// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i64, ptr %[[PTR]], align 1
+// CHECK-MSCOMPAT: %[[SUM:.*]] = add i64 %[[ORIG_VAL]], 1
+// CHECK-MSCOMPAT: store i64 %[[SUM]], ptr %[[PTR]], align 1
+
double check__CopyDoubleFromInt64(__int64 arg1) {
return _CopyDoubleFromInt64(arg1);
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/117752
More information about the cfe-commits
mailing list