Author: 吴腾 Date: 2026-07-01T21:05:17-07:00 New Revision: 39f1fb931f81d78c3ea9e9fb2ae0deefbdcb4922
URL: https://github.com/llvm/llvm-project/commit/39f1fb931f81d78c3ea9e9fb2ae0deefbdcb4922 DIFF: https://github.com/llvm/llvm-project/commit/39f1fb931f81d78c3ea9e9fb2ae0deefbdcb4922.diff LOG: [InlineAsm] Diagnose oversized non-scalar tied asm outputs (#206230) 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. Fixes #204775 Added: clang/test/SemaCXX/inline-asm-aggregate-output.cpp Modified: clang/lib/Sema/SemaStmtAsm.cpp clang/test/Sema/asm.c Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 96d372c89d2b1..6bf12d9cd98da 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -735,10 +735,13 @@ 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; } diff --git a/clang/test/Sema/asm.c b/clang/test/Sema/asm.c index a666b45b3150c..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; @@ -352,7 +359,12 @@ void test19(long long x) st_size16 c; st_size32 d; st_size128 e; - asm ("" : "=rm" (a): "0" (1)); // no-error + char f[16]; + 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. @@ -360,10 +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'}} + // 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
