mstorsjo updated this revision to Diff 106489.
mstorsjo retitled this revision from "[RFC] [AArch64] Add support for 
__builtin_ms_va_list on aarch64" to "[AArch64] Add support for 
__builtin_ms_va_list on aarch64".
mstorsjo edited the summary of this revision.
mstorsjo added a comment.

Added test cases, a minor tweak to semantic error handling, removed the RFC 
tag, removed the reference to the clang prerequisite that now is committed.


https://reviews.llvm.org/D34475

Files:
  include/clang-c/Index.h
  include/clang/Basic/BuiltinsAArch64.def
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Basic/Specifiers.h
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/AST/Type.cpp
  lib/AST/TypePrinter.cpp
  lib/Basic/Targets.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGCall.cpp
  lib/CodeGen/CGDebugInfo.cpp
  lib/Sema/SemaChecking.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/CodeGen/ms_abi_aarch64.c
  test/Sema/varargs-aarch64.c
  tools/libclang/CXType.cpp

Index: tools/libclang/CXType.cpp
===================================================================
--- tools/libclang/CXType.cpp
+++ tools/libclang/CXType.cpp
@@ -619,6 +619,7 @@
       TCALLINGCONV(Swift);
       TCALLINGCONV(PreserveMost);
       TCALLINGCONV(PreserveAll);
+      TCALLINGCONV(AArch64Win64);
     case CC_SpirFunction: return CXCallingConv_Unexposed;
     case CC_OpenCLKernel: return CXCallingConv_Unexposed;
       break;
Index: test/Sema/varargs-aarch64.c
===================================================================
--- /dev/null
+++ test/Sema/varargs-aarch64.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple aarch64-linux-gnu
+
+void f1(int a, ...) {
+  __builtin_ms_va_list ap;
+  __builtin_ms_va_start(ap, a); // expected-error {{'__builtin_ms_va_start' used in AAPCS ABI function}}
+}
+
+void __attribute__((ms_abi)) f2(int a, ...) {
+  __builtin_va_list ap;
+  __builtin_va_start(ap, a); // expected-error {{'va_start' used in Win64 ABI function}}
+}
Index: test/CodeGen/ms_abi_aarch64.c
===================================================================
--- /dev/null
+++ test/CodeGen/ms_abi_aarch64.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm < %s | FileCheck -check-prefix=LINUX %s
+// RUN: %clang_cc1 -triple aarch64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s
+
+void __attribute__((ms_abi)) f1(void);
+void f2(void);
+void f3(void) {
+  // LINUX-LABEL: define void @f3()
+  // WIN64-LABEL: define void @f3()
+  f1();
+  // LINUX: call aarch64_win64cc void @f1()
+  // WIN64: call void @f1()
+  f2();
+  // LINUX: call void @f2()
+  // WIN64: call void @f2()
+}
+// LINUX: declare aarch64_win64cc void @f1()
+// LINUX: declare void @f2()
+// WIN64: declare void @f1()
+// WIN64: declare void @f2()
+
+// Win64 ABI varargs
+void __attribute__((ms_abi)) f4(int a, ...) {
+  // LINUX-LABEL: define aarch64_win64cc void @f4
+  // WIN64-LABEL: define void @f4
+  __builtin_ms_va_list ap;
+  __builtin_ms_va_start(ap, a);
+  // LINUX: %[[AP:.*]] = alloca i8*
+  // LINUX: call void @llvm.va_start
+  // WIN64: %[[AP:.*]] = alloca i8*
+  // WIN64: call void @llvm.va_start
+  int b = __builtin_va_arg(ap, int);
+  // LINUX: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+  // LINUX-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+  // LINUX-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+  // LINUX-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+  // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+  // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+  // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+  // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+  __builtin_ms_va_list ap2;
+  __builtin_ms_va_copy(ap2, ap);
+  // LINUX: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
+  // LINUX-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
+  // WIN64: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
+  // WIN64-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]]
+  __builtin_ms_va_end(ap);
+  // LINUX: call void @llvm.va_end
+  // WIN64: call void @llvm.va_end
+}
+
+// Let's verify that normal va_lists work right on Win64, too.
+void f5(int a, ...) {
+  // WIN64-LABEL: define void @f5
+  __builtin_va_list ap;
+  __builtin_va_start(ap, a);
+  // WIN64: %[[AP:.*]] = alloca i8*
+  // WIN64: call void @llvm.va_start
+  int b = __builtin_va_arg(ap, int);
+  // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+  // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
+  // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+  // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+  __builtin_va_list ap2;
+  __builtin_va_copy(ap2, ap);
+  // WIN64: call void @llvm.va_copy
+  __builtin_va_end(ap);
+  // WIN64: call void @llvm.va_end
+}
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4279,8 +4279,13 @@
   case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break;
   case AttributeList::AT_RegCall: CC = CC_X86RegCall; break;
   case AttributeList::AT_MSABI:
-    CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
-                                                             CC_X86_64Win64;
+
+    CC = Context.getTargetInfo().getTriple().isOSWindows()
+             ? CC_C
+             : Context.getTargetInfo().getTriple().getArch() ==
+                       llvm::Triple::aarch64
+                   ? CC_AArch64Win64
+                   : CC_X86_64Win64;
     break;
   case AttributeList::AT_SysVABI:
     CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -1440,6 +1440,9 @@
 
 bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
                                          CallExpr *TheCall) {
+  if (BuiltinID == AArch64::BI__builtin_ms_va_start)
+    return SemaBuiltinVAStart(BuiltinID, TheCall);
+
   if (BuiltinID == AArch64::BI__builtin_arm_ldrex ||
       BuiltinID == AArch64::BI__builtin_arm_ldaex ||
       BuiltinID == AArch64::BI__builtin_arm_strex ||
@@ -3622,12 +3625,15 @@
 static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
   const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
   bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
+  bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64;
   bool IsWindows = TT.isOSWindows();
-  bool IsMSVAStart = BuiltinID == X86::BI__builtin_ms_va_start;
+  bool IsMSVAStart = BuiltinID == X86::BI__builtin_ms_va_start ||
+                     BuiltinID == AArch64::BI__builtin_ms_va_start;
+  clang::CallingConv CC = CC_C;
+  if (const FunctionDecl *FD = S.getCurFunctionDecl())
+    CC = FD->getType()->getAs<FunctionType>()->getCallConv();
+
   if (IsX64) {
-    clang::CallingConv CC = CC_C;
-    if (const FunctionDecl *FD = S.getCurFunctionDecl())
-      CC = FD->getType()->getAs<FunctionType>()->getCallConv();
     if (IsMSVAStart) {
       // Don't allow this in System V ABI functions.
       if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_X86_64Win64))
@@ -3647,6 +3653,22 @@
     return false;
   }
 
+  if (IsAArch64) {
+    if (IsMSVAStart) {
+      // Don't allow this in AAPCS functions.
+      if (!IsWindows && CC != CC_AArch64Win64)
+        return S.Diag(Fn->getLocStart(),
+                      diag::err_ms_va_start_used_in_aapcs_function);
+    } else {
+      // On aarch64 Unix, don't allow this in Win64 ABI functions.
+      if (!IsWindows && CC == CC_AArch64Win64)
+        return S.Diag(Fn->getLocStart(),
+                      diag::err_va_start_used_in_wrong_abi_function)
+               << !IsWindows;
+    }
+    return false;
+  }
+
   if (IsMSVAStart)
     return S.Diag(Fn->getLocStart(), diag::err_x86_builtin_64_only);
   return false;
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -967,6 +967,7 @@
   case CC_PreserveMost:
   case CC_PreserveAll:
   case CC_X86RegCall:
+  case CC_AArch64Win64:
     return 0;
   }
   return 0;
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -64,6 +64,7 @@
   case CC_PreserveMost: return llvm::CallingConv::PreserveMost;
   case CC_PreserveAll: return llvm::CallingConv::PreserveAll;
   case CC_Swift: return llvm::CallingConv::Swift;
+  case CC_AArch64Win64: return llvm::CallingConv::AArch64_Win64;
   }
 }
 
@@ -191,7 +192,8 @@
                                    FTP, FD);
 }
 
-static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
+static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows,
+                                               llvm::Triple::ArchType Arch) {
   // Set the appropriate calling convention for the Function.
   if (D->hasAttr<StdCallAttr>())
     return CC_X86StdCall;
@@ -218,7 +220,8 @@
     return CC_IntelOclBicc;
 
   if (D->hasAttr<MSABIAttr>())
-    return IsWindows ? CC_C : CC_X86_64Win64;
+    return IsWindows ? CC_C : Arch == llvm::Triple::aarch64 ? CC_AArch64Win64
+                                                            : CC_X86_64Win64;
 
   if (D->hasAttr<SysVABIAttr>())
     return IsWindows ? CC_X86_64SysV : CC_C;
@@ -463,8 +466,11 @@
   }
 
   FunctionType::ExtInfo einfo;
-  bool IsWindows = getContext().getTargetInfo().getTriple().isOSWindows();
-  einfo = einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows));
+  const llvm::Triple &TT = getContext().getTargetInfo().getTriple();
+  bool IsWindows = TT.isOSWindows();
+  llvm::Triple::ArchType Arch = TT.getArch();
+  einfo =
+      einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows, Arch));
 
   if (getContext().getLangOpts().ObjCAutoRefCount &&
       MD->hasAttr<NSReturnsRetainedAttr>())
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -5273,6 +5273,31 @@
 
 Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
                                                const CallExpr *E) {
+  if (BuiltinID == AArch64::BI__builtin_ms_va_start ||
+      BuiltinID == AArch64::BI__builtin_ms_va_end)
+    return EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(),
+                          BuiltinID == AArch64::BI__builtin_ms_va_start);
+  if (BuiltinID == AArch64::BI__builtin_ms_va_copy) {
+    // Lower this manually. We can't reliably determine whether or not any
+    // given va_copy() is for a Win64 va_list from the calling convention
+    // alone, because it's legal to do this from an AAPCS ABI function.
+    // With opaque pointer types, we won't have enough information in LLVM
+    // IR to determine this from the argument types, either. Best to do it
+    // now, while we have enough information.
+    Address DestAddr = EmitMSVAListRef(E->getArg(0));
+    Address SrcAddr = EmitMSVAListRef(E->getArg(1));
+
+    llvm::Type *BPP = Int8PtrPtrTy;
+
+    DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"),
+                       DestAddr.getAlignment());
+    SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"),
+                      SrcAddr.getAlignment());
+
+    Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val");
+    return Builder.CreateStore(ArgPtr, DestAddr);
+  }
+
   unsigned HintID = static_cast<unsigned>(-1);
   switch (BuiltinID) {
   default: break;
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -6291,6 +6291,9 @@
     LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
     LongDoubleFormat = &llvm::APFloat::IEEEquad();
 
+    // Make __builtin_ms_va_list available.
+    HasBuiltinMSVaList = true;
+
     // {} in inline assembly are neon specifiers, not assembly variant
     // specifiers.
     NoAsmVariants = true;
@@ -6474,6 +6477,7 @@
     case CC_PreserveMost:
     case CC_PreserveAll:
     case CC_OpenCLKernel:
+    case CC_AArch64Win64:
       return CCCR_OK;
     default:
       return CCCR_Warning;
Index: lib/AST/TypePrinter.cpp
===================================================================
--- lib/AST/TypePrinter.cpp
+++ lib/AST/TypePrinter.cpp
@@ -742,6 +742,9 @@
     case CC_PreserveAll:
       OS << " __attribute__((preserve_all))";
       break;
+    case CC_AArch64Win64:
+      OS << " __attribute__((ms_abi))";
+      break;
     }
   }
 
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp
+++ lib/AST/Type.cpp
@@ -2641,6 +2641,7 @@
   case CC_Swift: return "swiftcall";
   case CC_PreserveMost: return "preserve_most";
   case CC_PreserveAll: return "preserve_all";
+  case CC_AArch64Win64: return "ms_abi";
   }
 
   llvm_unreachable("Invalid calling convention.");
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2124,6 +2124,7 @@
       llvm_unreachable("Unsupported CC for mangling");
     case CC_X86_64Win64:
     case CC_X86_64SysV:
+    case CC_AArch64Win64:
     case CC_C: Out << 'A'; break;
     case CC_X86Pascal: Out << 'C'; break;
     case CC_X86ThisCall: Out << 'E'; break;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -2539,6 +2539,7 @@
   case CC_OpenCLKernel:
   case CC_PreserveMost:
   case CC_PreserveAll:
+  case CC_AArch64Win64:
     // FIXME: we should be mangling all of the above.
     return "";
 
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h
+++ include/clang/Basic/Specifiers.h
@@ -247,6 +247,7 @@
     CC_Swift,        // __attribute__((swiftcall))
     CC_PreserveMost, // __attribute__((preserve_most))
     CC_PreserveAll,  // __attribute__((preserve_all))
+    CC_AArch64Win64, // __attribute__((ms_abi))
   };
 
   /// \brief Checks whether the given calling convention supports variadic
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7993,6 +7993,8 @@
   "'va_start' used in %select{System V|Win64}0 ABI function">;
 def err_ms_va_start_used_in_sysv_function : Error<
   "'__builtin_ms_va_start' used in System V ABI function">;
+def err_ms_va_start_used_in_aapcs_function : Error<
+  "'__builtin_ms_va_start' used in AAPCS ABI function">;
 def warn_second_arg_of_va_start_not_last_named_param : Warning<
   "second argument to 'va_start' is not the last named parameter">,
   InGroup<Varargs>;
Index: include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- include/clang/Basic/BuiltinsAArch64.def
+++ include/clang/Basic/BuiltinsAArch64.def
@@ -61,4 +61,9 @@
 BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc")
 BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
 
+// Win64-compatible va_list functions
+BUILTIN(__builtin_ms_va_start, "vc*&.", "nt")
+BUILTIN(__builtin_ms_va_end, "vc*&", "n")
+BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n")
+
 #undef BUILTIN
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -3211,6 +3211,7 @@
   CXCallingConv_Swift = 13,
   CXCallingConv_PreserveMost = 14,
   CXCallingConv_PreserveAll = 15,
+  CXCallingConv_AArch64Win64 = 16,
 
   CXCallingConv_Invalid = 100,
   CXCallingConv_Unexposed = 200
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to