mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Allow hooks with arguments.
llvm-svn: 62685
This commit is contained in:
parent
8ff90a156b
commit
9153777db7
16
test/LLVMC/HookWithArguments.td
Normal file
16
test/LLVMC/HookWithArguments.td
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Check that hooks with arguments work.
|
||||||
|
// RUN: tblgen -I $srcroot/include --gen-llvmc %s -o %t
|
||||||
|
// RUN: grep {Hook(const char\\* Arg0, const char\\* Arg1, const char\\* Arg2);} %t | count 1
|
||||||
|
// RUN: grep "/path" %t | count 1
|
||||||
|
// RUN: grep "VARIABLE" %t | count 1
|
||||||
|
// RUN: grep "/2path" %t | count 1
|
||||||
|
|
||||||
|
include "llvm/CompilerDriver/Common.td"
|
||||||
|
|
||||||
|
def dummy_tool : Tool<[
|
||||||
|
(cmd_line "$CALL(Hook, 'Arg1', 'Arg2', 'Arg3 Arg3Cont')/path arg1 $ENV(VARIABLE)/2path arg2 $INFILE"),
|
||||||
|
(in_language "dummy"),
|
||||||
|
(out_language "dummy")
|
||||||
|
]>;
|
||||||
|
|
||||||
|
def DummyGraph : CompilationGraph<[SimpleEdge<"root", "dummy_tool">]>;
|
@ -560,16 +560,21 @@ Hooks and environment variables
|
|||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
Normally, LLVMC executes programs from the system ``PATH``. Sometimes,
|
Normally, LLVMC executes programs from the system ``PATH``. Sometimes,
|
||||||
this is not sufficient: for example, we may want to specify tool names
|
this is not sufficient: for example, we may want to specify tool paths
|
||||||
in the configuration file. This can be achieved via the mechanism of
|
or names in the configuration file. This can be easily achieved via
|
||||||
hooks - to write your own hooks, just add their definitions to the
|
the hooks mechanism. To write your own hooks, just add their
|
||||||
``PluginMain.cpp`` or drop a ``.cpp`` file into the
|
definitions to the ``PluginMain.cpp`` or drop a ``.cpp`` file into the
|
||||||
``$LLVMC_DIR/driver`` directory. Hooks should live in the ``hooks``
|
your plugin directory. Hooks should live in the ``hooks`` namespace
|
||||||
namespace and have the signature ``std::string hooks::MyHookName
|
and have the signature ``const char* hooks::MyHookName ([const char*
|
||||||
(void)``. They can be used from the ``cmd_line`` tool property::
|
Arg0 [ const char* Arg2 [, ...]]])``. They can be used from the
|
||||||
|
``cmd_line`` tool property::
|
||||||
|
|
||||||
(cmd_line "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)")
|
(cmd_line "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)")
|
||||||
|
|
||||||
|
To pass arguments to hooks, use the following syntax::
|
||||||
|
|
||||||
|
(cmd_line "$CALL(MyHook, 'Arg1', 'Arg2', 'Arg # 3')/path/to/file -o1 -o2")
|
||||||
|
|
||||||
It is also possible to use environment variables in the same manner::
|
It is also possible to use environment variables in the same manner::
|
||||||
|
|
||||||
(cmd_line "$ENV(VAR1)/path/to/file -o $ENV(VAR2)")
|
(cmd_line "$ENV(VAR1)/path/to/file -o $ENV(VAR2)")
|
||||||
|
@ -118,6 +118,15 @@ std::string EscapeVariableName(const std::string& Var) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// oneOf - Does the input string contain this character?
|
||||||
|
bool oneOf(const char* lst, char c) {
|
||||||
|
while (*lst) {
|
||||||
|
if (*lst++ == c)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
/// Back-end specific code
|
/// Back-end specific code
|
||||||
|
|
||||||
@ -1041,39 +1050,157 @@ void EmitCaseConstructHandler(const Init* Dag, const char* IndentLevel,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
|
||||||
|
/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
|
||||||
|
/// Helper function used by EmitCmdLineVecFill and.
|
||||||
|
void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
|
||||||
|
const char* Delimiters = " \t\n\v\f\r";
|
||||||
|
enum TokenizerState
|
||||||
|
{ Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
|
||||||
|
cur_st = Normal;
|
||||||
|
Out.push_back("");
|
||||||
|
|
||||||
|
std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
|
||||||
|
E = CmdLine.size();
|
||||||
|
if (B == std::string::npos)
|
||||||
|
throw "Empty command-line string!";
|
||||||
|
for (; B != E; ++B) {
|
||||||
|
char cur_ch = CmdLine[B];
|
||||||
|
|
||||||
|
switch (cur_st) {
|
||||||
|
case Normal:
|
||||||
|
if (cur_ch == '$') {
|
||||||
|
cur_st = SpecialCommand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (oneOf(Delimiters, cur_ch)) {
|
||||||
|
// Skip whitespace
|
||||||
|
B = CmdLine.find_first_not_of(Delimiters, B);
|
||||||
|
if (B == std::string::npos) {
|
||||||
|
B = E-1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
--B;
|
||||||
|
Out.push_back("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case SpecialCommand:
|
||||||
|
if (oneOf(Delimiters, cur_ch)) {
|
||||||
|
cur_st = Normal;
|
||||||
|
Out.push_back("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cur_ch == '(') {
|
||||||
|
Out.push_back("");
|
||||||
|
cur_st = InsideSpecialCommand;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InsideSpecialCommand:
|
||||||
|
if (oneOf(Delimiters, cur_ch)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cur_ch == '\'') {
|
||||||
|
cur_st = InsideQuotationMarks;
|
||||||
|
Out.push_back("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cur_ch == ')') {
|
||||||
|
cur_st = Normal;
|
||||||
|
Out.push_back("");
|
||||||
|
}
|
||||||
|
if (cur_ch == ',') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InsideQuotationMarks:
|
||||||
|
if (cur_ch == '\'') {
|
||||||
|
cur_st = InsideSpecialCommand;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Out.back().push_back(cur_ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class I, class S>
|
||||||
|
void checkedIncrement(I& P, I E, S ErrorString) {
|
||||||
|
++P;
|
||||||
|
if (P == E)
|
||||||
|
throw ErrorString;
|
||||||
|
}
|
||||||
|
|
||||||
/// SubstituteSpecialCommands - Perform string substitution for $CALL
|
/// SubstituteSpecialCommands - Perform string substitution for $CALL
|
||||||
/// and $ENV. Helper function used by EmitCmdLineVecFill().
|
/// and $ENV. Helper function used by EmitCmdLineVecFill().
|
||||||
std::string SubstituteSpecialCommands(const std::string& cmd) {
|
StrVector::const_iterator SubstituteSpecialCommands
|
||||||
size_t cparen = cmd.find(")");
|
(StrVector::const_iterator Pos, StrVector::const_iterator End, std::ostream& O)
|
||||||
std::string ret;
|
{
|
||||||
|
|
||||||
if (cmd.find("$CALL(") == 0) {
|
const std::string& cmd = *Pos;
|
||||||
if (cmd.size() == 6)
|
|
||||||
|
if (cmd == "$CALL") {
|
||||||
|
checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
|
||||||
|
const std::string& CmdName = *Pos;
|
||||||
|
|
||||||
|
if (CmdName == ")")
|
||||||
throw std::string("$CALL invocation: empty argument list!");
|
throw std::string("$CALL invocation: empty argument list!");
|
||||||
|
|
||||||
ret += "hooks::";
|
O << "hooks::";
|
||||||
ret += std::string(cmd.begin() + 6, cmd.begin() + cparen);
|
O << CmdName << "(";
|
||||||
ret += "()";
|
|
||||||
}
|
|
||||||
else if (cmd.find("$ENV(") == 0) {
|
|
||||||
if (cmd.size() == 5)
|
|
||||||
throw std::string("$ENV invocation: empty argument list!");
|
|
||||||
|
|
||||||
ret += "checkCString(std::getenv(\"";
|
|
||||||
ret += std::string(cmd.begin() + 5, cmd.begin() + cparen);
|
bool firstIteration = true;
|
||||||
ret += "\"))";
|
while (true) {
|
||||||
|
checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
|
||||||
|
const std::string& Arg = *Pos;
|
||||||
|
assert(Arg.size() != 0);
|
||||||
|
|
||||||
|
if (Arg[0] == ')')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (firstIteration)
|
||||||
|
firstIteration = false;
|
||||||
|
else
|
||||||
|
O << ", ";
|
||||||
|
|
||||||
|
O << '"' << Arg << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
O << ')';
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (cmd == "$ENV") {
|
||||||
|
checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
|
||||||
|
const std::string& EnvName = *Pos;
|
||||||
|
|
||||||
|
if (EnvName == ")")
|
||||||
|
throw "$ENV invocation: empty argument list!";
|
||||||
|
|
||||||
|
O << "checkCString(std::getenv(\"";
|
||||||
|
O << EnvName;
|
||||||
|
O << "\"))";
|
||||||
|
|
||||||
|
checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw "Unknown special command: " + cmd;
|
throw "Unknown special command: " + cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.begin() + cparen + 1 != cmd.end()) {
|
const std::string& Leftover = *Pos;
|
||||||
ret += " + std::string(\"";
|
assert(Leftover.at(0) == ')');
|
||||||
ret += (cmd.c_str() + cparen + 1);
|
if (Leftover.size() != 1)
|
||||||
ret += "\")";
|
O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
|
||||||
}
|
O << ')';
|
||||||
|
|
||||||
return ret;
|
return Pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EmitCmdLineVecFill - Emit code that fills in the command line
|
/// EmitCmdLineVecFill - Emit code that fills in the command line
|
||||||
@ -1082,14 +1209,28 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
|
|||||||
bool IsJoin, const char* IndentLevel,
|
bool IsJoin, const char* IndentLevel,
|
||||||
std::ostream& O) {
|
std::ostream& O) {
|
||||||
StrVector StrVec;
|
StrVector StrVec;
|
||||||
SplitString(InitPtrToString(CmdLine), StrVec);
|
TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
|
||||||
|
|
||||||
if (StrVec.empty())
|
if (StrVec.empty())
|
||||||
throw "Tool " + ToolName + " has empty command line!";
|
throw "Tool " + ToolName + " has empty command line!";
|
||||||
|
|
||||||
StrVector::const_iterator I = StrVec.begin();
|
StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
|
||||||
++I;
|
|
||||||
for (StrVector::const_iterator E = StrVec.end(); I != E; ++I) {
|
// If there is a hook invocation on the place of the first command, skip it.
|
||||||
|
if (StrVec[0][0] == '$') {
|
||||||
|
while (I != E && (*I)[0] != ')' )
|
||||||
|
++I;
|
||||||
|
|
||||||
|
// Skip the ')' symbol.
|
||||||
|
++I;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++I;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; I != E; ++I) {
|
||||||
const std::string& cmd = *I;
|
const std::string& cmd = *I;
|
||||||
|
// std::cerr << cmd;
|
||||||
O << IndentLevel;
|
O << IndentLevel;
|
||||||
if (cmd.at(0) == '$') {
|
if (cmd.at(0) == '$') {
|
||||||
if (cmd == "$INFILE") {
|
if (cmd == "$INFILE") {
|
||||||
@ -1105,7 +1246,8 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
|
|||||||
O << "vec.push_back(out_file);\n";
|
O << "vec.push_back(out_file);\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
O << "vec.push_back(" << SubstituteSpecialCommands(cmd);
|
O << "vec.push_back(";
|
||||||
|
I = SubstituteSpecialCommands(I, E, O);
|
||||||
O << ");\n";
|
O << ");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1113,10 +1255,13 @@ void EmitCmdLineVecFill(const Init* CmdLine, const std::string& ToolName,
|
|||||||
O << "vec.push_back(\"" << cmd << "\");\n";
|
O << "vec.push_back(\"" << cmd << "\");\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
O << IndentLevel << "cmd = "
|
O << IndentLevel << "cmd = ";
|
||||||
<< ((StrVec[0][0] == '$') ? SubstituteSpecialCommands(StrVec[0])
|
|
||||||
: "\"" + StrVec[0] + "\"")
|
if (StrVec[0][0] == '$')
|
||||||
<< ";\n";
|
SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
|
||||||
|
else
|
||||||
|
O << '"' << StrVec[0] << '"';
|
||||||
|
O << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// EmitCmdLineVecFillCallback - A function object wrapper around
|
/// EmitCmdLineVecFillCallback - A function object wrapper around
|
||||||
@ -1650,22 +1795,39 @@ void EmitPopulateCompilationGraph (const RecordVector& EdgeVector,
|
|||||||
/// $CALL(HookName) in the provided command line string. Helper
|
/// $CALL(HookName) in the provided command line string. Helper
|
||||||
/// function used by FillInHookNames().
|
/// function used by FillInHookNames().
|
||||||
class ExtractHookNames {
|
class ExtractHookNames {
|
||||||
llvm::StringSet<>& HookNames_;
|
llvm::StringMap<unsigned>& HookNames_;
|
||||||
public:
|
public:
|
||||||
ExtractHookNames(llvm::StringSet<>& HookNames)
|
ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
|
||||||
: HookNames_(HookNames_) {}
|
: HookNames_(HookNames) {}
|
||||||
|
|
||||||
void operator()(const Init* CmdLine) {
|
void operator()(const Init* CmdLine) {
|
||||||
StrVector cmds;
|
StrVector cmds;
|
||||||
llvm::SplitString(InitPtrToString(CmdLine), cmds);
|
TokenizeCmdline(InitPtrToString(CmdLine), cmds);
|
||||||
for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
|
for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
|
||||||
B != E; ++B) {
|
B != E; ++B) {
|
||||||
const std::string& cmd = *B;
|
const std::string& cmd = *B;
|
||||||
if (cmd.find("$CALL(") == 0) {
|
|
||||||
if (cmd.size() == 6)
|
if (cmd == "$CALL") {
|
||||||
throw std::string("$CALL invocation: empty argument list!");
|
unsigned NumArgs = 0;
|
||||||
HookNames_.insert(std::string(cmd.begin() + 6,
|
checkedIncrement(B, E, "Syntax error in $CALL invocation!");
|
||||||
cmd.begin() + cmd.find(")")));
|
const std::string& HookName = *B;
|
||||||
|
|
||||||
|
|
||||||
|
if (HookName.at(0) == ')')
|
||||||
|
throw "$CALL invoked with no arguments!";
|
||||||
|
|
||||||
|
while (++B != E && B->at(0) != ')') {
|
||||||
|
++NumArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
|
||||||
|
|
||||||
|
if (H != HookNames_.end() && H->second != NumArgs)
|
||||||
|
throw "Overloading of hooks is not allowed. Overloaded hook: "
|
||||||
|
+ HookName;
|
||||||
|
else
|
||||||
|
HookNames_[HookName] = NumArgs;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1674,7 +1836,7 @@ public:
|
|||||||
/// FillInHookNames - Actually extract the hook names from all command
|
/// FillInHookNames - Actually extract the hook names from all command
|
||||||
/// line strings. Helper function used by EmitHookDeclarations().
|
/// line strings. Helper function used by EmitHookDeclarations().
|
||||||
void FillInHookNames(const ToolDescriptions& ToolDescs,
|
void FillInHookNames(const ToolDescriptions& ToolDescs,
|
||||||
llvm::StringSet<>& HookNames)
|
llvm::StringMap<unsigned>& HookNames)
|
||||||
{
|
{
|
||||||
// For all command lines:
|
// For all command lines:
|
||||||
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
|
for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
|
||||||
@ -1695,16 +1857,23 @@ void FillInHookNames(const ToolDescriptions& ToolDescs,
|
|||||||
/// property records and emit hook function declaration for each
|
/// property records and emit hook function declaration for each
|
||||||
/// instance of $CALL(HookName).
|
/// instance of $CALL(HookName).
|
||||||
void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) {
|
void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) {
|
||||||
llvm::StringSet<> HookNames;
|
llvm::StringMap<unsigned> HookNames;
|
||||||
|
|
||||||
FillInHookNames(ToolDescs, HookNames);
|
FillInHookNames(ToolDescs, HookNames);
|
||||||
if (HookNames.empty())
|
if (HookNames.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
O << "namespace hooks {\n";
|
O << "namespace hooks {\n";
|
||||||
for (StringSet<>::const_iterator B = HookNames.begin(), E = HookNames.end();
|
for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
|
||||||
B != E; ++B)
|
E = HookNames.end(); B != E; ++B) {
|
||||||
O << Indent1 << "std::string " << B->first() << "();\n";
|
O << Indent1 << "const char* " << B->first() << "(";
|
||||||
|
|
||||||
|
for (unsigned i = 0, j = B->second; i < j; ++i) {
|
||||||
|
O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
O <<");\n";
|
||||||
|
}
|
||||||
O << "}\n\n";
|
O << "}\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user