Skip to content

Commit fc49424

Browse files
[clang-c] introduce queries on GCC-style inline assembly statements
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]>
1 parent 329ae86 commit fc49424

File tree

5 files changed

+315
-1
lines changed

5 files changed

+315
-1
lines changed

clang/include/clang-c/Index.h

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#define CINDEX_VERSION_MAJOR 0
3737
#define CINDEX_VERSION_MINOR 64
3838

39-
#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
39+
#define CINDEX_VERSION_ENCODE(major, minor) (((major) * 10000) + ((minor) * 1))
4040

4141
#define CINDEX_VERSION \
4242
CINDEX_VERSION_ENCODE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR)
@@ -4495,6 +4495,98 @@ CINDEX_LINKAGE CXStringSet *clang_Cursor_getCXXManglings(CXCursor);
44954495
*/
44964496
CINDEX_LINKAGE CXStringSet *clang_Cursor_getObjCManglings(CXCursor);
44974497

4498+
/**
4499+
* @}
4500+
*/
4501+
4502+
/**
4503+
* \defgroup CINDEX_MODULE Inline Assembly introspection
4504+
*
4505+
* The functions in this group provide access to information about GCC-style
4506+
* inline assembly statements.
4507+
*
4508+
* @{
4509+
*/
4510+
4511+
/**
4512+
* Given a CXCursor_GCCAsmStmt cursor, return the assembly template string.
4513+
* As per LLVM IR Assembly Template language, template placeholders for
4514+
* inputs and outputs are either of the form $N where N is a decimal number
4515+
* as an index into the input-output specification,
4516+
* or ${N:M} where N is a decimal number also as an index into the
4517+
* input-output specification and M is the template argument modifier.
4518+
* The index N in both cases points into the the total inputs and outputs,
4519+
* or more specifically, into the list of outputs followed by the inputs,
4520+
* starting from index 0 as the first available template argument.
4521+
*/
4522+
4523+
CINDEX_LINKAGE CXString clang_Cursor_getGCCAssemblyTemplate(CXCursor);
4524+
4525+
/**
4526+
* Given a CXCursor_GCCAsmStmt cursor, check if the assembly block has goto
4527+
* labels.
4528+
*/
4529+
4530+
CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblyHasGoto(CXCursor);
4531+
4532+
/**
4533+
* Given a CXCursor_GCCAsmStmt cursor, count the number of outputs
4534+
*/
4535+
4536+
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumOutputs(CXCursor);
4537+
4538+
/**
4539+
* Given a CXCursor_GCCAsmStmt cursor, count the number of inputs
4540+
*/
4541+
4542+
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumInputs(CXCursor);
4543+
4544+
/**
4545+
* Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
4546+
* to the Index-th input.
4547+
*/
4548+
4549+
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyInput(CXCursor Cursor,
4550+
unsigned Index,
4551+
CXString *Constraint,
4552+
CXCursor *Expr);
4553+
4554+
/**
4555+
* Given a CXCursor_GCCAsmStmt cursor, get the constraint and expression cursor
4556+
* to the Index-th output.
4557+
*/
4558+
4559+
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyOutput(CXCursor Cursor,
4560+
unsigned Index,
4561+
CXString *Constraint,
4562+
CXCursor *Expr);
4563+
4564+
/**
4565+
* Given a CXCursor_GCCAsmStmt cursor, count the clobbers in it.
4566+
*/
4567+
4568+
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumClobbers(CXCursor Cursor);
4569+
4570+
/**
4571+
* Given a CXCursor_GCCAsmStmt cursor, get the Index-th clobber of it.
4572+
*/
4573+
4574+
CINDEX_LINKAGE CXString clang_Cursor_getGCCAssemblyClobber(CXCursor Cursor,
4575+
unsigned Index);
4576+
4577+
/**
4578+
* Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is simple.
4579+
*/
4580+
4581+
CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblySimple(CXCursor Cursor);
4582+
4583+
/**
4584+
* Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is
4585+
* `volatile`.
4586+
*/
4587+
4588+
CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblyVolatile(CXCursor Cursor);
4589+
44984590
/**
44994591
* @}
45004592
*/

clang/test/Index/inline-assembly.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
static void inline_assembly_template_regardless_of_target_machine() {
2+
int tmp;
3+
asm volatile (
4+
"nop\n"
5+
"a_value %w[v]\n"
6+
"o_value %w[o]"
7+
: [v] "=&r" (tmp)
8+
: [o] "r" (tmp)
9+
: "cc", "memory"
10+
);
11+
}
12+
13+
// RUN: c-index-test -test-inline-assembly %s 2>&1 | FileCheck %s
14+
// CHECK: ===ASM TEMPLATE===
15+
// CHECK: nop
16+
// CHECK: a_value ${0:w}
17+
// CHECK: o_value ${1:w}
18+
// CHECK: ===ASM TEMPLATE END===
19+
// CHECK: volatile: true
20+
// CHECK: simple: false
21+
// CHECK: Output #0 Constraint (=&r): DeclRefExpr=tmp:2:9
22+
// CHECK: Input #0 Constraint (r): UnexposedExpr=tmp:2:9
23+
// CHECK: Clobber #0: cc
24+
// CHECK: Clobber #1: memory
25+
// CHECK: ===ASM END===
26+
27+
static void inline_assembly_valid_x86_example() {
28+
int tmp;
29+
asm (
30+
"nop\n"
31+
"mov %w[o], %w[v]"
32+
: [v] "=&r" (tmp)
33+
: [o] "r" (tmp)
34+
: "cc", "memory"
35+
);
36+
}
37+
38+
// CHECK: ===ASM TEMPLATE===
39+
// CHECK: nop
40+
// CHECK: mov ${1:w}, ${0:w}
41+
// CHECK: ===ASM TEMPLATE END===
42+
// CHECK: volatile: false
43+
// CHECK: simple: false
44+
// CHECK: Output #0 Constraint (=&r): DeclRefExpr=tmp:28:9
45+
// CHECK: Input #0 Constraint (r): UnexposedExpr=tmp:28:9
46+
// CHECK: Clobber #0: cc
47+
// CHECK: Clobber #1: memory
48+
// CHECK: ===ASM END===

clang/tools/c-index-test/c-index-test.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,6 +1988,53 @@ static enum CXChildVisitResult PrintDeclAttributes(CXCursor cursor, CXCursor p,
19881988
return CXChildVisit_Continue;
19891989
}
19901990

1991+
/******************************************************************************/
1992+
/* Inline assembly cursor testing */
1993+
/******************************************************************************/
1994+
1995+
static enum CXChildVisitResult
1996+
PrintGCCInlineAssembly(CXCursor cursor, CXCursor p, CXClientData d) {
1997+
CXString Constraint, Template, Clobber;
1998+
CXCursor Expr;
1999+
unsigned hasGoto, i, e;
2000+
if (clang_getCursorKind(cursor) != CXCursor_AsmStmt) {
2001+
return CXChildVisit_Recurse;
2002+
}
2003+
hasGoto = clang_Cursor_isGCCAssemblyHasGoto(cursor);
2004+
printf("===ASM TEMPLATE%s===\n", hasGoto ? " (WITH GOTO)" : "");
2005+
Template = clang_Cursor_getGCCAssemblyTemplate(cursor);
2006+
printf("%s", clang_getCString(Template));
2007+
clang_disposeString(Template);
2008+
printf("\n===ASM TEMPLATE END===\n");
2009+
2010+
printf("volatile: %s\n",
2011+
clang_Cursor_isGCCAssemblyVolatile(cursor) ? "true" : "false");
2012+
printf("simple: %s\n",
2013+
clang_Cursor_isGCCAssemblySimple(cursor) ? "true" : "false");
2014+
2015+
for (i = 0, e = clang_Cursor_getGCCAssemblyNumOutputs(cursor); i < e; ++i) {
2016+
clang_Cursor_getGCCAssemblyOutput(cursor, i, &Constraint, &Expr);
2017+
printf("Output #%d Constraint (%s): ", i, clang_getCString(Constraint));
2018+
PrintCursor(Expr, NULL);
2019+
printf("\n");
2020+
clang_disposeString(Constraint);
2021+
}
2022+
for (i = 0, e = clang_Cursor_getGCCAssemblyNumInputs(cursor); i < e; ++i) {
2023+
clang_Cursor_getGCCAssemblyInput(cursor, i, &Constraint, &Expr);
2024+
printf("Input #%d Constraint (%s): ", i, clang_getCString(Constraint));
2025+
PrintCursor(Expr, NULL);
2026+
printf("\n");
2027+
clang_disposeString(Constraint);
2028+
}
2029+
for (i = 0, e = clang_Cursor_getGCCAssemblyNumClobbers(cursor); i < e; ++i) {
2030+
Clobber = clang_Cursor_getGCCAssemblyClobber(cursor, i);
2031+
printf("Clobber #%d: %s\n", i, clang_getCString(Clobber));
2032+
clang_disposeString(Clobber);
2033+
}
2034+
printf("===ASM END===\n");
2035+
return CXChildVisit_Recurse;
2036+
}
2037+
19912038
/******************************************************************************/
19922039
/* Target information testing. */
19932040
/******************************************************************************/
@@ -5010,6 +5057,7 @@ static void print_usage(void) {
50105057
" c-index-test -test-annotate-tokens=<range> {<args>}*\n"
50115058
" c-index-test -test-inclusion-stack-source {<args>}*\n"
50125059
" c-index-test -test-inclusion-stack-tu <AST file>\n");
5060+
fprintf(stderr, " c-index-test -test-inline-assembly <AST file>\n");
50135061
fprintf(stderr,
50145062
" c-index-test -test-print-linkage-source {<args>}*\n"
50155063
" c-index-test -test-print-visibility {<args>}*\n"
@@ -5167,6 +5215,10 @@ int cindextest_main(int argc, const char **argv) {
51675215
else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-for=") == argv[1])
51685216
return perform_test_single_symbol_sgf(argv[1], argc - 2, argv + 2);
51695217

5218+
if (argc > 2 && strstr(argv[1], "-test-inline-assembly") == argv[1])
5219+
return perform_test_load_source(argc - 2, argv + 2, "all",
5220+
PrintGCCInlineAssembly, NULL);
5221+
51705222
print_usage();
51715223
return 1;
51725224
}

clang/tools/libclang/CIndex.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8648,6 +8648,118 @@ void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens,
86488648
}
86498649
}
86508650

8651+
//===----------------------------------------------------------------------===//
8652+
// Operations for querying information of a GCC inline assembly block under a
8653+
// cursor.
8654+
//===----------------------------------------------------------------------===//
8655+
CXString clang_Cursor_getGCCAssemblyTemplate(CXCursor Cursor) {
8656+
if (!clang_isStatement(Cursor.kind))
8657+
return cxstring::createEmpty();
8658+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8659+
auto const &C = getCursorContext(Cursor);
8660+
auto AsmTemplate = Stmt->generateAsmString(C);
8661+
return cxstring::createDup(AsmTemplate);
8662+
}
8663+
return cxstring::createEmpty();
8664+
}
8665+
8666+
unsigned clang_Cursor_isGCCAssemblyHasGoto(CXCursor Cursor) {
8667+
if (!clang_isStatement(Cursor.kind))
8668+
return 0;
8669+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8670+
return Stmt->isAsmGoto();
8671+
}
8672+
return 0;
8673+
}
8674+
8675+
unsigned clang_Cursor_getGCCAssemblyNumOutputs(CXCursor Cursor) {
8676+
if (!clang_isStatement(Cursor.kind))
8677+
return 0;
8678+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8679+
return Stmt->getNumOutputs();
8680+
}
8681+
return 0;
8682+
}
8683+
8684+
unsigned clang_Cursor_getGCCAssemblyNumInputs(CXCursor Cursor) {
8685+
if (!clang_isStatement(Cursor.kind))
8686+
return 0;
8687+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8688+
return Stmt->getNumInputs();
8689+
}
8690+
return 0;
8691+
}
8692+
8693+
unsigned clang_Cursor_getGCCAssemblyInput(CXCursor Cursor, unsigned Index,
8694+
CXString *Constraint,
8695+
CXCursor *Expr) {
8696+
if (!clang_isStatement(Cursor.kind) || !Constraint || !Expr)
8697+
return 0;
8698+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
8699+
Stmt && Index < Stmt->getNumInputs()) {
8700+
auto Constraint_ = Stmt->getInputConstraint(Index);
8701+
auto const *Expr_ = Stmt->getInputExpr(Index);
8702+
*Constraint = cxstring::createDup(Constraint_);
8703+
*Expr = MakeCXCursor(Expr_, getCursorDecl(Cursor),
8704+
cxcursor::getCursorTU(Cursor));
8705+
return 1;
8706+
}
8707+
return 0;
8708+
}
8709+
8710+
unsigned clang_Cursor_getGCCAssemblyOutput(CXCursor Cursor, unsigned Index,
8711+
CXString *Constraint,
8712+
CXCursor *Expr) {
8713+
if (!clang_isStatement(Cursor.kind) || !Constraint || !Expr)
8714+
return 0;
8715+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
8716+
Stmt && Index < Stmt->getNumOutputs()) {
8717+
auto Constraint_ = Stmt->getOutputConstraint(Index);
8718+
auto const *Expr_ = Stmt->getOutputExpr(Index);
8719+
*Constraint = cxstring::createDup(Constraint_);
8720+
*Expr = MakeCXCursor(Expr_, getCursorDecl(Cursor),
8721+
cxcursor::getCursorTU(Cursor));
8722+
return 1;
8723+
}
8724+
return 0;
8725+
}
8726+
8727+
unsigned clang_Cursor_getGCCAssemblyNumClobbers(CXCursor Cursor) {
8728+
if (!clang_isStatement(Cursor.kind))
8729+
return 0;
8730+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8731+
return Stmt->getNumClobbers();
8732+
}
8733+
return 0;
8734+
}
8735+
8736+
CXString clang_Cursor_getGCCAssemblyClobber(CXCursor Cursor, unsigned Index) {
8737+
if (!clang_isStatement(Cursor.kind))
8738+
return cxstring::createEmpty();
8739+
if (auto const *S = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor));
8740+
S && Index < S->getNumClobbers())
8741+
return cxstring::createDup(S->getClobber(Index));
8742+
return cxstring::createEmpty();
8743+
}
8744+
8745+
unsigned clang_Cursor_isGCCAssemblySimple(CXCursor Cursor) {
8746+
if (!clang_isStatement(Cursor.kind))
8747+
return 0;
8748+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8749+
return Stmt->isSimple();
8750+
}
8751+
return 0;
8752+
}
8753+
8754+
unsigned clang_Cursor_isGCCAssemblyVolatile(CXCursor Cursor) {
8755+
if (!clang_isStatement(Cursor.kind))
8756+
return 0;
8757+
if (auto const *Stmt = dyn_cast_or_null<GCCAsmStmt>(getCursorStmt(Cursor))) {
8758+
return Stmt->isVolatile();
8759+
}
8760+
return 0;
8761+
}
8762+
86518763
//===----------------------------------------------------------------------===//
86528764
// Operations for querying linkage of a cursor.
86538765
//===----------------------------------------------------------------------===//

clang/tools/libclang/libclang.map

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,16 @@ LLVM_20 {
441441
LLVM_21 {
442442
global:
443443
clang_getFullyQualifiedName;
444+
clang_Cursor_getGCCAssemblyTemplate;
445+
clang_Cursor_isGCCAssemblyHasGoto;
446+
clang_Cursor_getGCCAssemblyNumOutputs;
447+
clang_Cursor_getGCCAssemblyNumInputs;
448+
clang_Cursor_getGCCAssemblyInput;
449+
clang_Cursor_getGCCAssemblyOutput;
450+
clang_Cursor_getGCCAssemblyNumClobbers;
451+
clang_Cursor_getGCCAssemblyClobber;
452+
clang_Cursor_isGCCAssemblySimple;
453+
clang_Cursor_isGCCAssemblyVolatile;
444454
};
445455

446456
# Example of how to add a new symbol version entry. If you do add a new symbol

0 commit comments

Comments
 (0)