efriedma updated this revision to Diff 458290.
efriedma added a comment.
Herald added subscribers: llvm-commits, arichardson.
Herald added a project: LLVM.
Update to handle va_arg
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D125419/new/
https://reviews.llvm.org/D125419
Files:
clang/lib/CodeGen/TargetInfo.cpp
clang/test/CodeGen/arm64ec.c
clang/test/CodeGenCXX/arm64ec.cpp
llvm/utils/UpdateTestChecks/common.py
Index: llvm/utils/UpdateTestChecks/common.py
===================================================================
--- llvm/utils/UpdateTestChecks/common.py
+++ llvm/utils/UpdateTestChecks/common.py
@@ -327,7 +327,7 @@
UNUSED_NOTE = 'NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:'
OPT_FUNCTION_RE = re.compile(
- r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.$-]+?)\s*'
+ r'^(\s*;\s*Function\sAttrs:\s(?P<attrs>[\w\s]+?))?\s*define\s+(?:internal\s+)?[^@]*@(?P<func>[\w.$-]+?|".+?")\s*'
r'(?P<args_and_sig>\((\)|(.*?[\w.-]+?)\))[^{]*\{)\n(?P<body>.*?)^\}$',
flags=(re.M | re.S))
Index: clang/test/CodeGenCXX/arm64ec.cpp
===================================================================
--- clang/test/CodeGenCXX/arm64ec.cpp
+++ clang/test/CodeGenCXX/arm64ec.cpp
@@ -2,6 +2,8 @@
// CHECK: @"?g@@YAXUA@@UB@@@Z" = alias void ([2 x float], [4 x float]), void ([2 x float], [4 x float])* @"?g@@$$hYAXUA@@UB@@@Z"
// CHECK: define dso_local void @"?g@@$$hYAXUA@@UB@@@Z"
+// CHECK: call void (i64, ...) @"?f@@YAXUA@@ZZ"(i64 %{{.*}}, %struct.B* noundef %{{.*}})
typedef struct { float x[2]; } A;
typedef struct { float x[4]; } B;
-void g(A a, B b) { }
+void f(A a, ...);
+void g(A a, B b) { f(a, b); }
Index: clang/test/CodeGen/arm64ec.c
===================================================================
--- clang/test/CodeGen/arm64ec.c
+++ clang/test/CodeGen/arm64ec.c
@@ -1,7 +1,62 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple arm64ec-windows-msvc -emit-llvm -o - %s | FileCheck %s
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs --global-value-regex "f"
+// RUN: %clang_cc1 -opaque-pointers -triple arm64ec-windows-msvc -emit-llvm -o - %s | FileCheck %s
-// CHECK: @g = alias void ([2 x float], [4 x float]), void ([2 x float], [4 x float])* @"#g"
-// CHECK: define dso_local void @"#g"
typedef struct { float x[2]; } A;
typedef struct { float x[4]; } B;
-void g(A a, B b) { }
+void f(A a, ...) {
+ __builtin_va_list b;
+ __builtin_va_start(b, a);
+ float x = __builtin_va_arg(b, A).x[0];
+ float y = __builtin_va_arg(b, B).x[0];
+}
+void g(A a, B b) { f(a, b); }
+
+//.
+// CHECK: @g = alias void ([2 x float], [4 x float]), ptr @"#g"
+//.
+// CHECK-LABEL: @"#f"(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 4
+// CHECK-NEXT: [[B:%.*]] = alloca ptr, align 8
+// CHECK-NEXT: [[X:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_A]], align 4
+// CHECK-NEXT: [[Y:%.*]] = alloca float, align 4
+// CHECK-NEXT: [[TMP2:%.*]] = alloca [[STRUCT_B:%.*]], align 4
+// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: store i64 [[A_COERCE:%.*]], ptr [[COERCE_DIVE]], align 4
+// CHECK-NEXT: call void @llvm.va_start(ptr [[B]])
+// CHECK-NEXT: [[ARGP_CUR:%.*]] = load ptr, ptr [[B]], align 8
+// CHECK-NEXT: [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i64 8
+// CHECK-NEXT: store ptr [[ARGP_NEXT]], ptr [[B]], align 8
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP]], ptr align 8 [[ARGP_CUR]], i64 8, i1 false)
+// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[TMP]], i32 0, i32 0
+// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x float], ptr [[X1]], i64 0, i64 0
+// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT: store float [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT: [[ARGP_CUR3:%.*]] = load ptr, ptr [[B]], align 8
+// CHECK-NEXT: [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i64 8
+// CHECK-NEXT: store ptr [[ARGP_NEXT4]], ptr [[B]], align 8
+// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR3]], align 8
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP2]], ptr align 4 [[TMP1]], i64 16, i1 false)
+// CHECK-NEXT: [[X5:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[TMP2]], i32 0, i32 0
+// CHECK-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x float], ptr [[X5]], i64 0, i64 0
+// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[ARRAYIDX6]], align 4
+// CHECK-NEXT: store float [[TMP2]], ptr [[Y]], align 4
+// CHECK-NEXT: ret void
+//
+//
+// CHECK-LABEL: @"#g"(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 4
+// CHECK-NEXT: [[B:%.*]] = alloca [[STRUCT_B:%.*]], align 4
+// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_B]], align 4
+// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: store [2 x float] [[A_COERCE:%.*]], ptr [[COERCE_DIVE]], align 4
+// CHECK-NEXT: [[COERCE_DIVE1:%.*]] = getelementptr inbounds [[STRUCT_B]], ptr [[B]], i32 0, i32 0
+// CHECK-NEXT: store [4 x float] [[B_COERCE:%.*]], ptr [[COERCE_DIVE1]], align 4
+// CHECK-NEXT: [[COERCE_DIVE2:%.*]] = getelementptr inbounds [[STRUCT_A]], ptr [[A]], i32 0, i32 0
+// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[COERCE_DIVE2]], align 4
+// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[BYVAL_TEMP]], ptr align 4 [[B]], i64 16, i1 false)
+// CHECK-NEXT: call void (i64, ...) @f(i64 [[TMP0]], ptr noundef [[BYVAL_TEMP]])
+// CHECK-NEXT: ret void
+//
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -2450,6 +2450,12 @@
return isX86VectorCallAggregateSmallEnough(NumMembers);
}
+ ABIArgInfo classifyArgForArm64ECVarArg(QualType Ty) {
+ unsigned FreeSSERegs = 0;
+ return classify(Ty, FreeSSERegs, /*IsReturnType=*/false,
+ /*IsVectorCall=*/false, /*IsRegCall=*/false);
+ }
+
private:
ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType,
bool IsVectorCall, bool IsRegCall) const;
@@ -5735,6 +5741,13 @@
unsigned CallingConvention) const {
Ty = useFirstFieldIfTransparentUnion(Ty);
+ if (IsVariadic && getTarget().getTriple().isWindowsArm64EC()) {
+ // Arm64EC varargs functions use the x86_64 classification rules,
+ // not the AArch64 ABI rules.
+ WinX86_64ABIInfo Win64ABIInfo(CGT, X86AVXABILevel::None);
+ return Win64ABIInfo.classifyArgForArm64ECVarArg(Ty);
+ }
+
// Handle illegal vector types here.
if (isIllegalVectorType(Ty))
return coerceIllegalVector(Ty);
@@ -6258,9 +6271,16 @@
QualType Ty) const {
bool IsIndirect = false;
- // Composites larger than 16 bytes are passed by reference.
- if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) > 128)
- IsIndirect = true;
+ if (getTarget().getTriple().isWindowsArm64EC()) {
+ // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is
+ // not 1, 2, 4, or 8 bytes, must be passed by reference."
+ uint64_t Width = getContext().getTypeSize(Ty);
+ IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width);
+ } else {
+ // Composites larger than 16 bytes are passed by reference.
+ if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) > 128)
+ IsIndirect = true;
+ }
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect,
CGF.getContext().getTypeInfoInChars(Ty),
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits