[clang] 4ab76b7 - [AArch64][InlineAsm]Add Clang support for flag output constraints

Mingming Liu via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 27 09:39:38 PDT 2023


Author: Mingming Liu
Date: 2023-04-27T09:39:08-07:00
New Revision: 4ab76b77cee0e27510d5d5cb3072ee7e92d96eec

URL: https://github.com/llvm/llvm-project/commit/4ab76b77cee0e27510d5d5cb3072ee7e92d96eec
DIFF: https://github.com/llvm/llvm-project/commit/4ab76b77cee0e27510d5d5cb3072ee7e92d96eec.diff

LOG: [AArch64][InlineAsm]Add Clang support for flag output constraints

- Mention this change in Clang release notes

Before:
- Clang emits "invalid output constraint '=@cceq' in asm" https://gcc.godbolt.org/z/b9crfEo8h

After:
- For aarch64 targets (with __aarch64__ defined), Clang validates and parses flag output constraints to generate LLVM IR.

Differential Revision: https://reviews.llvm.org/D149123

Added: 
    clang/test/CodeGen/inline-asm-aarch64-flag-output.c
    clang/test/Preprocessor/aarch64_asm_flag_output.c

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Basic/Targets/AArch64.cpp
    clang/lib/Basic/Targets/AArch64.h
    clang/test/Preprocessor/init-aarch64.c
    clang/test/Preprocessor/predefined-win-macros.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 26fdffe920e95..aff9ce3782532 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -416,6 +416,15 @@ Arm and AArch64 Support
 - Clang builtin ``__arithmetic_fence`` and the command line option ``-fprotect-parens``
   are now enabled for AArch64.
 
+- Clang supports flag output operands by which conditions in the NZCV could be outputs
+  of inline assembly for AArch64. This change is more consistent with the behavior of
+  GCC.
+
+   .. code-block:: c
+
+     // int a = foo(); int* b = bar();
+     asm("ands %w[a], %w[a], #3" : [a] "+r"(a), "=@cceq"(*b));
+
 Windows Support
 ^^^^^^^^^^^^^^^
 

diff  --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 67ba5f6b35145..3840139d27434 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -333,6 +333,8 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
                                          MacroBuilder &Builder) const {
   // Target identification.
   Builder.defineMacro("__aarch64__");
+  // Inline assembly supports AArch64 flag outputs.
+  Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__");
   // For bare-metal.
   if (getTriple().getOS() == llvm::Triple::UnknownOS &&
       getTriple().isOSBinFormatELF())
@@ -1210,6 +1212,52 @@ ArrayRef<TargetInfo::GCCRegAlias> AArch64TargetInfo::getGCCRegAliases() const {
   return llvm::ArrayRef(GCCRegAliases);
 }
 
+// Returns the length of cc constraint.
+static unsigned matchAsmCCConstraint(const char *Name) {
+  constexpr unsigned len = 5;
+  auto RV = llvm::StringSwitch<unsigned>(Name)
+                .Case("@cceq", len)
+                .Case("@ccne", len)
+                .Case("@cchs", len)
+                .Case("@cccs", len)
+                .Case("@cccc", len)
+                .Case("@cclo", len)
+                .Case("@ccmi", len)
+                .Case("@ccpl", len)
+                .Case("@ccvs", len)
+                .Case("@ccvc", len)
+                .Case("@cchi", len)
+                .Case("@ccls", len)
+                .Case("@ccge", len)
+                .Case("@cclt", len)
+                .Case("@ccgt", len)
+                .Case("@ccle", len)
+                .Default(0);
+  return RV;
+}
+
+std::string
+AArch64TargetInfo::convertConstraint(const char *&Constraint) const {
+  std::string R;
+  switch (*Constraint) {
+  case 'U': // Three-character constraint; add "@3" hint for later parsing.
+    R = std::string("@3") + std::string(Constraint, 3);
+    Constraint += 2;
+    break;
+  case '@':
+    if (const unsigned Len = matchAsmCCConstraint(Constraint)) {
+      std::string Converted = "{" + std::string(Constraint, Len) + "}";
+      Constraint += Len - 1;
+      return Converted;
+    }
+    return std::string(1, *Constraint);
+  default:
+    R = TargetInfo::convertConstraint(Constraint);
+    break;
+  }
+  return R;
+}
+
 bool AArch64TargetInfo::validateAsmConstraint(
     const char *&Name, TargetInfo::ConstraintInfo &Info) const {
   switch (*Name) {
@@ -1257,6 +1305,13 @@ bool AArch64TargetInfo::validateAsmConstraint(
   case 'y': // SVE registers (V0-V7)
     Info.setAllowsRegister();
     return true;
+  case '@':
+    // CC condition
+    if (const unsigned Len = matchAsmCCConstraint(Name)) {
+      Name += Len - 1;
+      Info.setAllowsRegister();
+      return true;
+    }
   }
   return false;
 }

diff  --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index 967a888f6b6f8..cce80e10f2bb1 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -173,19 +173,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
   ArrayRef<const char *> getGCCRegNames() const override;
   ArrayRef<TargetInfo::GCCRegAlias> getGCCRegAliases() const override;
 
-  std::string convertConstraint(const char *&Constraint) const override {
-    std::string R;
-    switch (*Constraint) {
-    case 'U': // Three-character constraint; add "@3" hint for later parsing.
-      R = std::string("@3") + std::string(Constraint, 3);
-      Constraint += 2;
-      break;
-    default:
-      R = TargetInfo::convertConstraint(Constraint);
-      break;
-    }
-    return R;
-  }
+  std::string convertConstraint(const char *&Constraint) const override;
 
   bool validateAsmConstraint(const char *&Name,
                              TargetInfo::ConstraintInfo &Info) const override;

diff  --git a/clang/test/CodeGen/inline-asm-aarch64-flag-output.c b/clang/test/CodeGen/inline-asm-aarch64-flag-output.c
new file mode 100644
index 0000000000000..b1ef6e3883754
--- /dev/null
+++ b/clang/test/CodeGen/inline-asm-aarch64-flag-output.c
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -O2 -emit-llvm %s -o - -triple aarch64 | FileCheck %s
+
+int test_cceq(int a, int* b) {
+// CHECK-LABEL: @test_cceq
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cceq},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cceq"(*b));
+  return a;
+}
+
+int test_ccne(int a, int* b) {
+// CHECK-LABEL: @test_ccne
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccne},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccne"(*b));
+  return a;
+}
+
+int test_cccs(int a, int* b) {
+// CHECK-LABEL: @test_cccs
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cccs},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cccs"(*b));
+  return a;
+}
+
+int test_cchs(int a, int* b) {
+// CHECK-LABEL: @test_cchs
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cchs},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cchs"(*b));
+  return a;
+}
+
+int test_cccc(int a, int* b) {
+// CHECK-LABEL: @test_cccc
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cccc},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cccc"(*b));
+  return a;
+}
+
+int test_cclo(int a, int* b) {
+// CHECK-LABEL: @test_cclo
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cclo},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cclo"(*b));
+  return a;
+}
+
+int test_ccmi(int a, int* b) {
+// CHECK-LABEL: @test_ccmi
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccmi},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccmi"(*b));
+  return a;
+}
+
+int test_ccpl(int a, int* b) {
+// CHECK-LABEL: @test_ccpl
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccpl},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccpl"(*b));
+  return a;
+}
+
+int test_ccvs(int a, int* b) {
+// CHECK-LABEL: @test_ccvs
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccvs},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccvs"(*b));
+  return a;
+}
+
+int test_ccvc(int a, int* b) {
+// CHECK-LABEL: @test_ccvc
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccvc},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccvc"(*b));
+  return a;
+}
+
+int test_cchi(int a, int* b) {
+// CHECK-LABEL: @test_cchi
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cchi},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cchi"(*b));
+  return a;
+}
+
+int test_ccls(int a, int* b) {
+// CHECK-LABEL: @test_ccls
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccls},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccls"(*b));
+  return a;
+}
+
+
+int test_ccge(int a, int* b) {
+// CHECK-LABEL: @test_ccge
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccge},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccge"(*b));
+  return a;
+}
+
+int test_cclt(int a, int* b) {
+// CHECK-LABEL: @test_cclt
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@cclt},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@cclt"(*b));
+  return a;
+}
+
+int test_ccgt(int a, int* b) {
+// CHECK-LABEL: @test_ccgt
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccgt},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccgt"(*b));
+  return a;
+}
+
+int test_ccle(int a, int* b) {
+// CHECK-LABEL: @test_ccle
+// CHECK: = tail call { i32, i32 } asm "ands ${0:w}, ${0:w}, #3", "=r,={@ccle},0"(i32 %a)
+  asm("ands %w[a], %w[a], #3"
+      : [a] "+r"(a), "=@ccle"(*b));
+  return a;
+}

diff  --git a/clang/test/Preprocessor/aarch64_asm_flag_output.c b/clang/test/Preprocessor/aarch64_asm_flag_output.c
new file mode 100644
index 0000000000000..28b5282132099
--- /dev/null
+++ b/clang/test/Preprocessor/aarch64_asm_flag_output.c
@@ -0,0 +1,3 @@
+// RUN: %clang -target aarch64-unknown-unknown -x c -E -dM -o - %s | FileCheck -match-full-lines %s
+
+// CHECK: #define __GCC_ASM_FLAG_OUTPUTS__ 1

diff  --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c
index 869d7ca8a0636..4ef62f0e2aa8d 100644
--- a/clang/test/Preprocessor/init-aarch64.c
+++ b/clang/test/Preprocessor/init-aarch64.c
@@ -106,6 +106,7 @@
 // AARCH64-NEXT: #define __FLT_RADIX__ 2
 // AARCH64-NEXT: #define __FP_FAST_FMA 1
 // AARCH64-NEXT: #define __FP_FAST_FMAF 1
+// AARCH64-NEXT: #define __GCC_ASM_FLAG_OUTPUTS__ 1
 // AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 1
 // AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 1
 // AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1

diff  --git a/clang/test/Preprocessor/predefined-win-macros.c b/clang/test/Preprocessor/predefined-win-macros.c
index f402ce91838d6..4497d14c6a5ef 100644
--- a/clang/test/Preprocessor/predefined-win-macros.c
+++ b/clang/test/Preprocessor/predefined-win-macros.c
@@ -129,4 +129,5 @@
 // CHECK-ARM64-MINGW: #define WINNT 1
 // CHECK-ARM64-MINGW: #define _WIN32 1
 // CHECK-ARM64-MINGW: #define _WIN64 1
+// CHECK-ARM64-MINGW: #define __GCC_ASM_FLAG_OUTPUTS__ 1
 // CHECK-ARM64-MINGW: #define __aarch64__ 1


        


More information about the cfe-commits mailing list