Skip to content

[clang-c] introduce queries on GCC-style inline assembly statements #143424

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 25, 2025

Conversation

dingxiangfei2009
Copy link
Contributor

Discourse link

We strive for exposing such information using existing stable ABIs. In doing so, queries are limited to what the original source holds or the LLVM IR asm block would expose in connection with attributes that the queries are concerned.

These APIs opens new opportunities for rust-bindgen to translate inline assemblies in reasonably cases into Rust inline assembly blocks, which would further aid better interoperability with other existing code.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:as-a-library libclang and C++ API labels Jun 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 9, 2025

@llvm/pr-subscribers-clang

Author: wieDasDing (dingxiangfei2009)

Changes

Discourse link

We strive for exposing such information using existing stable ABIs. In doing so, queries are limited to what the original source holds or the LLVM IR asm block would expose in connection with attributes that the queries are concerned.

These APIs opens new opportunities for rust-bindgen to translate inline assemblies in reasonably cases into Rust inline assembly blocks, which would further aid better interoperability with other existing code.


Full diff: https://github.com/llvm/llvm-project/pull/143424.diff

5 Files Affected:

  • (modified) clang/include/clang-c/Index.h (+92-1)
  • (added) clang/test/Index/inline-assembly.c (+48)
  • (modified) clang/tools/c-index-test/c-index-test.c (+52)
  • (modified) clang/tools/libclang/CIndex.cpp (+118-7)
  • (modified) clang/tools/libclang/libclang.map (+10)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index e4cb4327fbaac..340d050654a69 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -36,7 +36,7 @@
 #define CINDEX_VERSION_MAJOR 0
 #define CINDEX_VERSION_MINOR 64
 
-#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
+#define CINDEX_VERSION_ENCODE(major, minor) (((major) * 10000) + ((minor) * 1))
 
 #define CINDEX_VERSION                                                         \
   CINDEX_VERSION_ENCODE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR)
@@ -4495,6 +4495,97 @@ CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
  */
 CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor);
 
+/**
+ * @}
+ */
+
+/**
+ * \defgroup CINDEX_MODULE Inline Assembly introspection
+ *
+ * The functions in this group provide access to information about GCC-style
+ * inline assembly statements.
+ *
+ * @{
+ */
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, return the assembly template string.
+ * As per LLVM IR Assembly Template language, template placeholders for
+ * inputs and outputs are either of the form $N where N is a decimal number
+ * as an index into the input-output specification,
+ * or ${N:M} where N is a decimal number also as an index into the
+ * input-output specification and M is the template argument modifier.
+ * The index N in both cases points into the the total inputs and outputs,
+ * or more specifically, into the list of outputs followed by the inputs,
+ * starting from index 0 as the first available template argument.
+ */
+
+CINDEX_LINKAGE CXString clang_Cursor_getGCCAssemblyTemplate(CXCursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, check if the assembly block has goto
+ * labels.
+ */
+
+CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblyHasGoto(CXCursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, count the number of outputs
+ */
+
+CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumOutputs(CXCursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, count the number of inputs
+ */
+
+CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumInputs(CXCursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
+ * to the Index-th input.
+ */
+
+CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyInput(CXCursor Cursor,
+                                                         unsigned Index,
+                                                         CXString *Constraint,
+                                                         CXCursor *Expr);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
+ * to the Index-th output.
+ */
+
+CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyOutput(CXCursor Cursor,
+                                                          unsigned Index,
+                                                          CXString *Constraint,
+                                                          CXCursor *Expr);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, count the clobbers in it.
+ */
+
+unsigned clang_Cursor_getGCCAssemblyNumClobbers(CXCursor Cursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, get the Index-th clobber of it.
+ */
+
+CXString clang_Cursor_getGCCAssemblyClobber(CXCursor Cursor, unsigned Index);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is simple.
+ */
+
+unsigned clang_Cursor_isGCCAssemblySimple(CXCursor Cursor);
+
+/**
+ * Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is
+ * `volatile`.
+ */
+
+unsigned clang_Cursor_isGCCAssemblyVolatile(CXCursor Cursor);
+
 /**
  * @}
  */
diff --git a/clang/test/Index/inline-assembly.c b/clang/test/Index/inline-assembly.c
new file mode 100644
index 0000000000000..1953d3d9033ff
--- /dev/null
+++ b/clang/test/Index/inline-assembly.c
@@ -0,0 +1,48 @@
+static void inline_assembly_template_regardless_of_target_machine() {
+    int tmp;
+    asm volatile (
+        "nop\n"
+        "a_value %w[v]\n"
+        "o_value %w[o]"
+        : [v] "=&r" (tmp)
+        : [o] "r" (tmp)
+        : "cc", "memory"
+    );
+}
+
+// RUN c-index-test -test-inline-assembly %s 2>&1 | FileCheck %s
+// CHECK: ===ASM TEMPLATE===
+// CHECK: nop
+// CHECK: a_value ${0:w}
+// CHECK: o_value ${1:w}
+// CHECK: ===ASM TEMPLATE END===
+// CHECK: volatile: true
+// CHECK: simple: false
+// CHECK: Output #0 Constraint (=&r): DeclRefExpr=tmp:2:9
+// CHECK: Input #0 Constraint (r): UnexposedExpr=tmp:2:9
+// CHECK: Clobber #0: cc
+// CHECK: Clobber #1: memory
+// CHECK: ===ASM END===
+
+static void inline_assembly_valid_x86_example() {
+    int tmp;
+    asm (
+        "nop\n"
+        "mov %w[o], %w[v]"
+        : [v] "=&r" (tmp)
+        : [o] "r" (tmp)
+        : "cc", "memory"
+    );
+}
+
+// CHECK: ===ASM TEMPLATE===
+// CHECK: nop
+// CHECK: mov ${1:w}, ${0:w}
+// CHECK: ===ASM TEMPLATE END===
+// CHECK: volatile: false
+// CHECK: simple: false
+// CHECK: Output #0 Constraint (=&r): DeclRefExpr=tmp:28:9
+// CHECK: Input #0 Constraint (r): UnexposedExpr=tmp:28:9
+// CHECK: Clobber #0: cc
+// CHECK: Clobber #1: memory
+// CHECK: ===ASM END===
\ No newline at end of file
diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c
index 4a887cd0c1e2e..0917439898f98 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -1988,6 +1988,53 @@ static enum CXChildVisitResult PrintDeclAttributes(CXCursor cursor, CXCursor p,
   return CXChildVisit_Continue;
 }
 
+/******************************************************************************/
+/* Inline assembly cursor testing                                             */
+/******************************************************************************/
+
+static enum CXChildVisitResult
+PrintGCCInlineAssembly(CXCursor cursor, CXCursor p, CXClientData d) {
+  CXString Constraint, Template, Clobber;
+  CXCursor Expr;
+  unsigned hasGoto, i, e;
+  if (clang_getCursorKind(cursor) != CXCursor_AsmStmt) {
+    return CXChildVisit_Recurse;
+  }
+  hasGoto = clang_Cursor_isGCCAssemblyHasGoto(cursor);
+  printf("===ASM TEMPLATE%s===\n", hasGoto ? " (WITH GOTO)" : "");
+  Template = clang_Cursor_getGCCAssemblyTemplate(cursor);
+  printf("%s", clang_getCString(Template));
+  clang_disposeString(Template);
+  printf("\n===ASM TEMPLATE END===\n");
+
+  printf("volatile: %s\n",
+         clang_Cursor_isGCCAssemblyVolatile(cursor) ? "true" : "false");
+  printf("simple: %s\n",
+         clang_Cursor_isGCCAssemblySimple(cursor) ? "true" : "false");
+
+  for (i = 0, e = clang_Cursor_getGCCAssemblyNumOutputs(cursor); i < e; ++i) {
+    clang_Cursor_getGCCAssemblyOutput(cursor, i, &Constraint, &Expr);
+    printf("Output #%d Constraint (%s): ", i, clang_getCString(Constraint));
+    PrintCursor(Expr, NULL);
+    printf("\n");
+    clang_disposeString(Constraint);
+  }
+  for (i = 0, e = clang_Cursor_getGCCAssemblyNumInputs(cursor); i < e; ++i) {
+    clang_Cursor_getGCCAssemblyInput(cursor, i, &Constraint, &Expr);
+    printf("Input #%d Constraint (%s): ", i, clang_getCString(Constraint));
+    PrintCursor(Expr, NULL);
+    printf("\n");
+    clang_disposeString(Constraint);
+  }
+  for (i = 0, e = clang_Cursor_getGCCAssemblyNumClobbers(cursor); i < e; ++i) {
+    Clobber = clang_Cursor_getGCCAssemblyClobber(cursor, i);
+    printf("Clobber #%d: %s\n", i, clang_getCString(Clobber));
+    clang_disposeString(Constraint);
+  }
+  printf("===ASM END===\n");
+  return CXChildVisit_Recurse;
+}
+
 /******************************************************************************/
 /* Target information testing.                                                */
 /******************************************************************************/
@@ -5010,6 +5057,7 @@ static void print_usage(void) {
     "       c-index-test -test-annotate-tokens=<range> {<args>}*\n"
     "       c-index-test -test-inclusion-stack-source {<args>}*\n"
     "       c-index-test -test-inclusion-stack-tu <AST file>\n");
+  fprintf(stderr, "       c-index-test -test-inline-assembly <AST file>\n");
   fprintf(stderr,
     "       c-index-test -test-print-linkage-source {<args>}*\n"
     "       c-index-test -test-print-visibility {<args>}*\n"
@@ -5167,6 +5215,10 @@ int cindextest_main(int argc, const char **argv) {
   else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-for=") == argv[1])
     return perform_test_single_symbol_sgf(argv[1], argc - 2, argv + 2);
 
+  if (argc > 2 && strstr(argv[1], "-test-inline-assembly") == argv[1])
+    return perform_test_load_source(argc - 2, argv + 2, "all",
+                                    PrintGCCInlineAssembly, NULL);
+
   print_usage();
   return 1;
 }
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 3068621d9c004..3d7aa19c10645 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -2141,8 +2141,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
   void VisitBlockExpr(const BlockExpr *B);
   void VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
   void VisitCompoundStmt(const CompoundStmt *S);
-  void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */
-  }
+  void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */ }
   void VisitMSDependentExistsStmt(const MSDependentExistsStmt *S);
   void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E);
   void VisitCXXNewExpr(const CXXNewExpr *E);
@@ -2252,8 +2251,8 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
   void VisitOMPMaskedTaskLoopDirective(const OMPMaskedTaskLoopDirective *D);
   void
   VisitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective *D);
-  void VisitOMPMaskedTaskLoopSimdDirective(
-      const OMPMaskedTaskLoopSimdDirective *D);
+  void
+  VisitOMPMaskedTaskLoopSimdDirective(const OMPMaskedTaskLoopSimdDirective *D);
   void VisitOMPParallelMasterTaskLoopDirective(
       const OMPParallelMasterTaskLoopDirective *D);
   void VisitOMPParallelMaskedTaskLoopDirective(
@@ -2811,8 +2810,7 @@ void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause(
 void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) {
   VisitOMPClauseList(C);
 }
-void OMPClauseEnqueue::VisitOMPXAttributeClause(const OMPXAttributeClause *C) {
-}
+void OMPClauseEnqueue::VisitOMPXAttributeClause(const OMPXAttributeClause *C) {}
 void OMPClauseEnqueue::VisitOMPXBareClause(const OMPXBareClause *C) {}
 
 } // namespace
@@ -5290,7 +5288,7 @@ typedef struct _CXChildVisitResult {
   int reserved;
   enum CXChildVisitResult (*invoke)(struct _CXChildVisitResult *, CXCursor,
                                     CXCursor);
-} * CXCursorVisitorBlock;
+} *CXCursorVisitorBlock;
 
 static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent,
                                               CXClientData client_data) {
@@ -8648,6 +8646,119 @@ void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens,
   }
 }
 
+//===----------------------------------------------------------------------===//
+// Operations for querying information of a GCC inline assembly block under a
+// cursor.
+//===----------------------------------------------------------------------===//
+CXString clang_Cursor_getGCCAssemblyTemplate(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return cxstring::createEmpty();
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    auto const &C = getCursorContext(Cursor);
+    auto AsmTemplate = Stmt->generateAsmString(C);
+    return cxstring::createDup(AsmTemplate);
+  }
+  return cxstring::createEmpty();
+}
+
+unsigned clang_Cursor_isGCCAssemblyHasGoto(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->isAsmGoto();
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_getGCCAssemblyNumOutputs(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->getNumOutputs();
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_getGCCAssemblyNumInputs(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->getNumInputs();
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_getGCCAssemblyInput(CXCursor Cursor, unsigned Index,
+                                          CXString *Constraint,
+                                          CXCursor *Expr) {
+  if (!clang_isStatement(Cursor.kind) || !Constraint || !Expr)
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
+      Stmt && Index < Stmt->getNumInputs()) {
+    auto Constraint_ = Stmt->getInputConstraint(Index);
+    auto const *Expr_ = Stmt->getInputExpr(Index);
+    *Constraint = cxstring::createDup(Constraint_);
+    *Expr = MakeCXCursor(Expr_, getCursorDecl(Cursor),
+                         cxcursor::getCursorTU(Cursor));
+    return 1;
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_getGCCAssemblyOutput(CXCursor Cursor, unsigned Index,
+                                           CXString *Constraint,
+                                           CXCursor *Expr) {
+  if (!clang_isStatement(Cursor.kind) || !Constraint || !Expr)
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
+      Stmt && Index < Stmt->getNumOutputs()) {
+    auto Constraint_ = Stmt->getOutputConstraint(Index);
+    auto const *Expr_ = Stmt->getOutputExpr(Index);
+    *Constraint = cxstring::createDup(Constraint_);
+    *Expr = MakeCXCursor(Expr_, getCursorDecl(Cursor),
+                         cxcursor::getCursorTU(Cursor));
+    return 1;
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_getGCCAssemblyNumClobbers(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->getNumClobbers();
+  }
+  return 0;
+}
+
+CXString clang_Cursor_getGCCAssemblyClobber(CXCursor Cursor, unsigned Index) {
+  if (!clang_isStatement(Cursor.kind))
+    return cxstring::createEmpty();
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
+      Stmt && Stmt->getNumClobbers()) {
+    return cxstring::createDup(Stmt->getClobber(Index));
+  }
+  return cxstring::createEmpty();
+}
+
+unsigned clang_Cursor_isGCCAssemblySimple(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->isSimple();
+  }
+  return 0;
+}
+
+unsigned clang_Cursor_isGCCAssemblyVolatile(CXCursor Cursor) {
+  if (!clang_isStatement(Cursor.kind))
+    return 0;
+  if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
+    return Stmt->isVolatile();
+  }
+  return 0;
+}
+
 //===----------------------------------------------------------------------===//
 // Operations for querying linkage of a cursor.
 //===----------------------------------------------------------------------===//
diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map
index f08d13c3da9e1..b3a12e9e9834b 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -441,6 +441,16 @@ LLVM_20 {
 LLVM_21 {
   global:
     clang_getFullyQualifiedName;
+    clang_Cursor_getGCCAssemblyTemplate;
+    clang_Cursor_isGCCAssemblyHasGoto;
+    clang_Cursor_getGCCAssemblyNumOutputs;
+    clang_Cursor_getGCCAssemblyNumInputs;
+    clang_Cursor_getGCCAssemblyInput;
+    clang_Cursor_getGCCAssemblyOutput;
+    clang_Cursor_getGCCAssemblyNumClobbers;
+    clang_Cursor_getGCCAssemblyClobber;
+    clang_Cursor_isGCCAssemblySimple;
+    clang_Cursor_isGCCAssemblyVolatile;
 };
 
 # Example of how to add a new symbol version entry.  If you do add a new symbol

@dingxiangfei2009 dingxiangfei2009 force-pushed the inline-assembly branch 4 times, most recently from 78ee7fe to 510960f Compare June 10, 2025 11:45
@nikic nikic requested a review from AaronBallman June 13, 2025 08:50
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! Mostly just nits, the implementation itself looks pretty reasonable so far.

Please be sure to add a release note to clang/docs/ReleaseNotes.rst so users know about the new functionality.

@dingxiangfei2009 dingxiangfei2009 force-pushed the inline-assembly branch 2 times, most recently from 199ddbd to fd302d3 Compare June 20, 2025 22:07
@dingxiangfei2009
Copy link
Contributor Author

Thank you for the review!

I had to make a little rebase as there were merge conflicts that I have to resolve.

@AaronBallman
Copy link
Collaborator

Precommit CI found a relevant failure on Windows (it looks like we're crashing, IIRC that's STATUS_HEAP_CORRUPTION as a failure code):

 FAIL: Clang :: Index/inline-assembly.c (13090 of 21590)
******************** TEST 'Clang :: Index/inline-assembly.c' FAILED ********************
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 13
c:\_work\llvm-project\llvm-project\build\bin\c-index-test.exe -test-inline-assembly C:\_work\llvm-project\llvm-project\clang\test\Index\inline-assembly.c 2>&1 | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\clang\test\Index\inline-assembly.c
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\c-index-test.exe' -test-inline-assembly 'C:\_work\llvm-project\llvm-project\clang\test\Index\inline-assembly.c'
# note: command had no output on stdout or stderr
# error: command failed with exit status: 0xc0000374
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 'C:\_work\llvm-project\llvm-project\clang\test\Index\inline-assembly.c'
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe C:\_work\llvm-project\llvm-project\clang\test\Index\inline-assembly.c
# `-----------------------------
# error: command failed with exit status: 2

--

********************

We strive for exposing such information using existing stable ABIs.
In doing so, queries are limited to what the original source holds
or the LLVM IR `asm` block would expose in connection with attributes
that the queries are concerned.

Signed-off-by: Xiangfei Ding <[email protected]>
@dingxiangfei2009
Copy link
Contributor Author

Thank you @AaronBallman. That was a genuine error. A typo led to a double-free in the c-index-test. 😓

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly just nits with documentation, but the functionality is looking good to me.

Comment on lines 330 to 332
- `libclang` receives a family of new bindings to query basic facts about
GCC-style inline assembly blocks, including whether the block is `volatile`
and its template string following the LLVM IR `asm` format. (#GH143424)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `libclang` receives a family of new bindings to query basic facts about
GCC-style inline assembly blocks, including whether the block is `volatile`
and its template string following the LLVM IR `asm` format. (#GH143424)
- ``libclang`` receives a family of new bindings to query basic facts about
GCC-style inline assembly blocks, including whether the block is ``volatile``
and its template string following the LLVM IR ``asm`` format. (#GH143424)

Adding some more backticks because RST is funny sometimes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pointer!

/**
* Given a CXCursor_GCCAsmStmt cursor, check if the assembly block has goto
* labels.
* This function also returns FALSE if the cursor does not point at a GCC inline
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This function also returns FALSE if the cursor does not point at a GCC inline
* This function also returns 0 if the cursor does not point at a GCC inline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in one commit

* This function returns TRUE when the cursor points at a GCC inline assembly
* statement, `Index` is within bounds and both the `Constraint` and `Expr` are
* not NULL.
* Otherwise, this function returns FALSE but leaves `Constraint` and `Expr`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Otherwise, this function returns FALSE but leaves `Constraint` and `Expr`
* Otherwise, this function returns 0 but leaves `Constraint` and `Expr`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in one commit

* This function returns TRUE when the cursor points at a GCC inline assembly
* statement, `Index` is within bounds and both the `Constraint` and `Expr` are
* not NULL.
* Otherwise, this function returns FALSE but leaves `Constraint` and `Expr`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Otherwise, this function returns FALSE but leaves `Constraint` and `Expr`
* Otherwise, this function returns 0 but leaves `Constraint` and `Expr`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in one commit

/**
* Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is
* `volatile`.
* This function returns FALSE if the cursor does not point at a GCC inline
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This function returns FALSE if the cursor does not point at a GCC inline
* This function returns 0 if the cursor does not point at a GCC inline

/**
* Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
* to the Index-th output.
* This function returns TRUE when the cursor points at a GCC inline assembly
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This function returns TRUE when the cursor points at a GCC inline assembly
* This function returns 1 when the cursor points at a GCC inline assembly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in one commit

/**
* Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
* to the Index-th input.
* This function returns TRUE when the cursor points at a GCC inline assembly
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This function returns TRUE when the cursor points at a GCC inline assembly
* This function returns 1 when the cursor points at a GCC inline assembly

We should also tell the user they're responsible for releasing the output parameters in this case? (Same suggestion below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in one commit.

Also I have commented on other places where users are responsible for managing the deallocation. Thank you for pointing it out!

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! The precommit CI failures appear to be unrelated.

Let me know if you need me to merge the changes on your behalf.

@dingxiangfei2009
Copy link
Contributor Author

@AaronBallman Yes, please. I don't have the merge right, so I would like to ask for your assistance. Many thanks!

@AaronBallman AaronBallman merged commit d76fdf7 into llvm:main Jun 25, 2025
9 of 10 checks passed
@dingxiangfei2009 dingxiangfei2009 deleted the inline-assembly branch June 25, 2025 15:04
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
…lvm#143424)

[Discourse
link](https://discourse.llvm.org/t/a-small-proposal-for-extraction-of-inline-assembly-block-information/86658)

We strive for exposing such information using existing stable ABIs. In
doing so, queries are limited to what the original source holds or the
LLVM IR `asm` block would expose in connection with attributes that the
queries are concerned.

These APIs opens new opportunities for `rust-bindgen` to translate
inline assemblies in reasonably cases into Rust inline assembly blocks,
which would further aid better interoperability with other existing
code.

---------

Signed-off-by: Xiangfei Ding <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:as-a-library libclang and C++ API clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants