-
Notifications
You must be signed in to change notification settings - Fork 14.2k
[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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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,98 @@ 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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What kind of things does the function return via its return value? |
||
*/ | ||
|
||
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, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same question here. |
||
unsigned Index, | ||
CXString *Constraint, | ||
CXCursor *Expr); | ||
|
||
/** | ||
* Given a CXCursor_GCCAsmStmt cursor, count the clobbers in it. | ||
*/ | ||
|
||
CINDEX_LINKAGE unsigned clang_Cursor_getGCCAssemblyNumClobbers(CXCursor Cursor); | ||
|
||
/** | ||
* Given a CXCursor_GCCAsmStmt cursor, get the Index-th clobber of it. | ||
*/ | ||
|
||
CINDEX_LINKAGE CXString clang_Cursor_getGCCAssemblyClobber(CXCursor Cursor, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this return on error? An empty string? Something else? |
||
unsigned Index); | ||
|
||
/** | ||
* Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is simple. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does it mean for assembly to be "simple"? |
||
*/ | ||
|
||
CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblySimple(CXCursor Cursor); | ||
|
||
/** | ||
* Given a CXCursor_GCCAsmStmt cursor, check if the inline assembly is | ||
* `volatile`. | ||
*/ | ||
|
||
CINDEX_LINKAGE unsigned clang_Cursor_isGCCAssemblyVolatile(CXCursor Cursor); | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | 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=== |
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -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))) { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||
auto const &C = getCursorContext(Cursor); | ||||||||||||
auto AsmTemplate = Stmt->generateAsmString(C); | ||||||||||||
Comment on lines
+8657
to
+8658
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't use |
||||||||||||
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(); | ||||||||||||
} | ||||||||||||
Comment on lines
+8667
to
+8669
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
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(); | ||||||||||||
} | ||||||||||||
Comment on lines
+8676
to
+8678
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
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(); | ||||||||||||
} | ||||||||||||
Comment on lines
+8685
to
+8687
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
return 0; | ||||||||||||
} | ||||||||||||
|
||||||||||||
unsigned clang_Cursor_getGCCAssemblyInput(CXCursor Cursor, unsigned Index, | ||||||||||||
CXString *Constraint, | ||||||||||||
CXCursor *Expr) { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||
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); | ||||||||||||
Comment on lines
+8698
to
+8699
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here about |
||||||||||||
*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) { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here as above. |
||||||||||||
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); | ||||||||||||
Comment on lines
+8715
to
+8716
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here as above. |
||||||||||||
*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(); | ||||||||||||
} | ||||||||||||
Comment on lines
+8728
to
+8730
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I'll stop commenting on this -- basically, single-line substatements don't get curly braces per our (odd) coding convention. |
||||||||||||
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. | ||||||||||||
//===----------------------------------------------------------------------===// | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this return on error?