https://github.com/tengwu updated 
https://github.com/llvm/llvm-project/pull/206230

From 57cfb356fd0eccdda85dd5c504308891e0ac7445 Mon Sep 17 00:00:00 2001
From: wt <[email protected]>
Date: Sat, 27 Jun 2026 07:59:18 +0000
Subject: [PATCH 1/2] [InlineAsm] Diagnose pointer input tied to larger
 aggregate output

GCC supports tying an aggregate register output to a pointer input in cases such
as an array operand after array-to-pointer decay. Clang currently accepts this,
but codegen crashes when lowering the mismatched tied operands.

Add a Sema check for pointer inputs tied to larger aggregate register outputs
when the aggregate can be scalarized to an integer register value. This turns 
the
crash into an unsupported inline asm diagnostic.

Fixes #204775
---
 clang/lib/Sema/SemaStmtAsm.cpp | 12 ++++++++++++
 clang/test/Sema/asm.c          |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 96d372c89d2b1..8b53697bd01f7 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -743,6 +743,18 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, 
bool IsSimple,
         return NS;
       }
 
+      // FIXME: GCC supports this, but codegen currently crashes when lowering
+      // a pointer input tied to a larger aggregate register output.
+      if (OutputDomain == AD_Other && InTy->isPointerType() &&
+          OutSize > InSize &&
+          !Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull()) {
+        targetDiag(InputExpr->getBeginLoc(),
+                   diag::err_asm_tying_incompatible_types)
+            << InTy << OutTy << OutputExpr->getSourceRange()
+            << InputExpr->getSourceRange();
+        return NS;
+      }
+
       continue;
     }
 
diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c
index a666b45b3150c..6d638be77dc9d 100644
--- a/clang/test/Sema/asm.c
+++ b/clang/test/Sema/asm.c
@@ -352,6 +352,7 @@ void test19(long long x)
   st_size16 c;
   st_size32 d;
   st_size128 e;
+  char f[16];
   asm ("" : "=rm" (a): "0" (1)); // no-error
   asm ("" : "=rm" (d): "0" (1)); // no-error
   asm ("" : "=rm" (c): "0" (x)); // no-error
@@ -364,6 +365,8 @@ void test19(long long x)
   asm ("" : "=rm" (e): "0" (1)); // no-error
   // FIXME: This case should be supported by codegen, but it fails now.
   asm ("" : "=rm" (x): "0" (e)); // expected-error {{unsupported inline asm: 
input with type 'st_size128' (aka 'struct _st_size128') matching output with 
type 'long long'}}
+  // FIXME: This case should be supported by codegen, but it fails now.
+  asm ("" : "=r" (f): "0" (f)); // expected-error {{unsupported inline asm: 
input with type 'char *' matching output with type 'char[16]'}}
 }
 
 typedef int int2 __attribute__((ext_vector_type(2)));

From 180152b24a930793e97ecd55d9818858c8d778d9 Mon Sep 17 00:00:00 2001
From: wt <[email protected]>
Date: Wed, 1 Jul 2026 07:31:38 +0000
Subject: [PATCH 2/2] [InlineAsm] Diagnose oversized non-scalar tied asm
 outputs

The 'r' asm constraint binds an operand to a general-purpose register.
For tied inline asm operands, Clang may promote a smaller integer input
to match a larger non-scalar register output. Only allow that path when
the output size can be represented by an integer type that fits in a
general-purpose register.

Otherwise, diagnose with err_store_value_to_reg before CodeGen attempts
to lower the asm and crashes.

This keeps GPR-sized aggregate/class outputs accepted while rejecting
larger array, struct, union, complex, vector, and class outputs. Add
Sema coverage for the affected C and C++ cases.
---
 clang/lib/Sema/SemaStmtAsm.cpp                | 23 ++++------
 clang/test/Sema/asm.c                         | 25 ++++++++---
 .../SemaCXX/inline-asm-aggregate-output.cpp   | 42 +++++++++++++++++++
 3 files changed, 69 insertions(+), 21 deletions(-)
 create mode 100644 clang/test/SemaCXX/inline-asm-aggregate-output.cpp

diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 8b53697bd01f7..6bf12d9cd98da 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -735,26 +735,17 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, 
bool IsSimple,
     if (!SmallerValueMentioned && !FPTiedToInt && InputDomain != AD_Other &&
         OutputConstraintInfos[TiedTo].allowsRegister()) {
 
-      // FIXME: GCC supports the OutSize to be 128 at maximum. Currently 
codegen
-      // crash when the size larger than the register size. So we limit it 
here.
-      if (OutTy->isStructureType() &&
-          Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull()) {
+      // FIXME: GCC supports some non-scalar register outputs. Currently
+      // codegen crashes when the size cannot be represented by an integer type
+      // that fits in a general-purpose register.
+      bool FitsInGeneralPurposeRegister =
+          OutSize <= Context.getTargetInfo().getRegisterWidth() &&
+          !Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull();
+      if (OutputDomain == AD_Other && !FitsInGeneralPurposeRegister) {
         targetDiag(OutputExpr->getExprLoc(), diag::err_store_value_to_reg);
         return NS;
       }
 
-      // FIXME: GCC supports this, but codegen currently crashes when lowering
-      // a pointer input tied to a larger aggregate register output.
-      if (OutputDomain == AD_Other && InTy->isPointerType() &&
-          OutSize > InSize &&
-          !Context.getIntTypeForBitwidth(OutSize, /*Signed*/ false).isNull()) {
-        targetDiag(InputExpr->getBeginLoc(),
-                   diag::err_asm_tying_incompatible_types)
-            << InTy << OutTy << OutputExpr->getSourceRange()
-            << InputExpr->getSourceRange();
-        return NS;
-      }
-
       continue;
     }
 
diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c
index 6d638be77dc9d..cc9acac1e169d 100644
--- a/clang/test/Sema/asm.c
+++ b/clang/test/Sema/asm.c
@@ -345,6 +345,13 @@ typedef struct _st_size128 {
   int d;
 } st_size128;
 
+typedef union _un_size96 {
+  int a[3];
+  char b[12];
+} un_size96;
+
+typedef int int4 __attribute__((ext_vector_type(4)));
+
 void test19(long long x)
 {
   st_size64 a;
@@ -353,7 +360,11 @@ void test19(long long x)
   st_size32 d;
   st_size128 e;
   char f[16];
-  asm ("" : "=rm" (a): "0" (1)); // no-error
+  char g[8];
+  un_size96 h;
+  _Complex float i;
+  int4 j;
+  asm ("" : "=rm" (a): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
   asm ("" : "=rm" (d): "0" (1)); // no-error
   asm ("" : "=rm" (c): "0" (x)); // no-error
   // FIXME: This case is actually supported by codegen.
@@ -361,12 +372,16 @@ void test19(long long x)
   // FIXME: This case is actually supported by codegen.
   asm ("" : "=rm" (a): "0" (d)); // expected-error {{unsupported inline asm: 
input with type 'st_size32' (aka 'struct _st_size32') matching output with type 
'st_size64' (aka 'struct _st_size64')}}
   asm ("" : "=rm" (b): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
-  // FIXME: This case should be supported by codegen, but it fails now.
-  asm ("" : "=rm" (e): "0" (1)); // no-error
+  // No general-purpose register can hold a 128-bit aggregate output.
+  asm ("" : "=rm" (e): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
   // FIXME: This case should be supported by codegen, but it fails now.
   asm ("" : "=rm" (x): "0" (e)); // expected-error {{unsupported inline asm: 
input with type 'st_size128' (aka 'struct _st_size128') matching output with 
type 'long long'}}
-  // FIXME: This case should be supported by codegen, but it fails now.
-  asm ("" : "=r" (f): "0" (f)); // expected-error {{unsupported inline asm: 
input with type 'char *' matching output with type 'char[16]'}}
+  // Likewise for larger array, union, complex, and vector outputs.
+  asm ("" : "=r" (f): "0" (f)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+  asm ("" : "=rm" (g): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+  asm ("" : "=rm" (h): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+  asm ("" : "=rm" (i): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+  asm ("" : "=rm" (j): "0" (1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
 }
 
 typedef int int2 __attribute__((ext_vector_type(2)));
diff --git a/clang/test/SemaCXX/inline-asm-aggregate-output.cpp 
b/clang/test/SemaCXX/inline-asm-aggregate-output.cpp
new file mode 100644
index 0000000000000..e7b16519c78c9
--- /dev/null
+++ b/clang/test/SemaCXX/inline-asm-aggregate-output.cpp
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 %s -triple x86_64-pc-linux-gnu -fsyntax-only -verify
+
+namespace TiedAggregateOutput {
+class C8 {
+  long long a;
+
+public:
+  C8();
+};
+
+class C12 {
+  int a;
+  int b;
+  int c;
+
+public:
+  C12();
+};
+
+class C16 {
+  long long a;
+  long long b;
+
+public:
+  C16();
+};
+
+void int_tied_to_gpr_sized_class_output() {
+  C8 c;
+  asm("" : "=rm"(c) : "0"(1)); // no-error
+}
+
+void int_tied_to_class_output_too_large() {
+  C12 c;
+  asm("" : "=rm"(c) : "0"(1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+}
+
+void int_tied_to_class_output() {
+  C16 c;
+  asm("" : "=r"(c) : "0"(1)); // expected-error {{impossible constraint in 
asm: cannot store value into a register}}
+}
+} // namespace TiedAggregateOutput

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to