Skip to content

Commit 830f4e9

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 f0d3257 commit 830f4e9

File tree

5 files changed

+321
-8
lines changed

5 files changed

+321
-8
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(Constraint);
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: 118 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,8 +2141,7 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
21412141
void VisitBlockExpr(const BlockExpr *B);
21422142
void VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
21432143
void VisitCompoundStmt(const CompoundStmt *S);
2144-
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */
2145-
}
2144+
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { /* Do nothing. */ }
21462145
void VisitMSDependentExistsStmt(const MSDependentExistsStmt *S);
21472146
void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *E);
21482147
void VisitCXXNewExpr(const CXXNewExpr *E);
@@ -2252,8 +2251,8 @@ class EnqueueVisitor : public ConstStmtVisitor<EnqueueVisitor, void>,
22522251
void VisitOMPMaskedTaskLoopDirective(const OMPMaskedTaskLoopDirective *D);
22532252
void
22542253
VisitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective *D);
2255-
void VisitOMPMaskedTaskLoopSimdDirective(
2256-
const OMPMaskedTaskLoopSimdDirective *D);
2254+
void
2255+
VisitOMPMaskedTaskLoopSimdDirective(const OMPMaskedTaskLoopSimdDirective *D);
22572256
void VisitOMPParallelMasterTaskLoopDirective(
22582257
const OMPParallelMasterTaskLoopDirective *D);
22592258
void VisitOMPParallelMaskedTaskLoopDirective(
@@ -2811,8 +2810,7 @@ void OMPClauseEnqueue::VisitOMPXDynCGroupMemClause(
28112810
void OMPClauseEnqueue::VisitOMPDoacrossClause(const OMPDoacrossClause *C) {
28122811
VisitOMPClauseList(C);
28132812
}
2814-
void OMPClauseEnqueue::VisitOMPXAttributeClause(const OMPXAttributeClause *C) {
2815-
}
2813+
void OMPClauseEnqueue::VisitOMPXAttributeClause(const OMPXAttributeClause *C) {}
28162814
void OMPClauseEnqueue::VisitOMPXBareClause(const OMPXBareClause *C) {}
28172815

28182816
} // namespace
@@ -5290,7 +5288,7 @@ typedef struct _CXChildVisitResult {
52905288
int reserved;
52915289
enum CXChildVisitResult (*invoke)(struct _CXChildVisitResult *, CXCursor,
52925290
CXCursor);
5293-
} * CXCursorVisitorBlock;
5291+
} *CXCursorVisitorBlock;
52945292

52955293
static enum CXChildVisitResult visitWithBlock(CXCursor cursor, CXCursor parent,
52965294
CXClientData client_data) {
@@ -8648,6 +8646,119 @@ void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens,
86488646
}
86498647
}
86508648

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

0 commit comments

Comments
 (0)