Get rid of the gross operator,()/variadic macro hack

that made ccprintf and friends work, turn it into a
normal function (though it still has a slightly strange
implementation.)  All instances of variadic macros
are not yet removed, but I know how, and it will happen.

One side effect of this new implementation is that a
cprintf statement can now only have 16 parameters, though
it's easy enough to raise this number if needed.

--HG--
extra : convert_revision : 85cb3c17f8e2ecf9cd2f31ea80a760a28ea127a7
This commit is contained in:
Nathan Binkert 2007-02-07 22:11:30 -08:00
parent af698e8b05
commit 1f834b569c
8 changed files with 750 additions and 432 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2002-2006 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,232 +39,247 @@ using namespace std;
namespace cp { namespace cp {
ArgList::~ArgList() Print::Print(std::ostream &stream, const std::string &format)
: stream(stream), format(format.c_str()), ptr(format.c_str())
{
saved_flags = stream.flags();
saved_fill = stream.fill();
saved_precision = stream.precision();
}
Print::Print(std::ostream &stream, const char *format)
: stream(stream), format(format), ptr(format)
{
saved_flags = stream.flags();
saved_fill = stream.fill();
saved_precision = stream.precision();
}
Print::~Print()
{ {
while (!objects.empty()) {
delete objects.front();
objects.pop_front();
}
} }
void void
ArgList::dump(const string &format) Print::process(Format &fmt)
{ {
list_t::iterator iter = objects.begin(); size_t len;
list_t::iterator end = objects.end();
const char *p = format.c_str(); while (*ptr) {
switch (*ptr) {
case '%':
if (ptr[1] != '%')
goto processing;
stream->fill(' '); stream.put('%');
stream->flags((ios::fmtflags)0); ptr += 2;
while (*p) {
switch (*p) {
case '%': {
if (p[1] == '%') {
*stream << '%';
p += 2;
continue;
}
Format fmt;
bool done = false;
bool end_number = false;
bool have_precision = false;
int number = 0;
while (!done) {
++p;
if (*p >= '0' && *p <= '9') {
if (end_number)
continue;
} else if (number > 0)
end_number = true;
switch (*p) {
case 's':
fmt.format = Format::string;
done = true;
break;
case 'c':
fmt.format = Format::character;
done = true;
break;
case 'l':
continue;
case 'p':
fmt.format = Format::integer;
fmt.base = Format::hex;
fmt.alternate_form = true;
done = true;
break;
case 'X':
fmt.uppercase = true;
case 'x':
fmt.base = Format::hex;
fmt.format = Format::integer;
done = true;
break;
case 'o':
fmt.base = Format::oct;
fmt.format = Format::integer;
done = true;
break;
case 'd':
case 'i':
case 'u':
fmt.format = Format::integer;
done = true;
break;
case 'G':
fmt.uppercase = true;
case 'g':
fmt.format = Format::floating;
fmt.float_format = Format::best;
done = true;
break;
case 'E':
fmt.uppercase = true;
case 'e':
fmt.format = Format::floating;
fmt.float_format = Format::scientific;
done = true;
break;
case 'f':
fmt.format = Format::floating;
fmt.float_format = Format::fixed;
done = true;
break;
case 'n':
*stream << "we don't do %n!!!\n";
done = true;
break;
case '#':
fmt.alternate_form = true;
break;
case '-':
fmt.flush_left = true;
break;
case '+':
fmt.print_sign = true;
break;
case ' ':
fmt.blank_space = true;
break;
case '.':
fmt.width = number;
fmt.precision = 0;
have_precision = true;
number = 0;
end_number = false;
break;
case '0':
if (number == 0) {
fmt.fill_zero = true;
break;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number = number * 10 + (*p - '0');
break;
case '%':
assert("we shouldn't get here");
break;
default:
done = true;
break;
}
if (end_number) {
if (have_precision)
fmt.precision = number;
else
fmt.width = number;
end_number = false;
number = 0;
}
}
if (iter != end)
{
ios::fmtflags saved_flags = stream->flags();
char old_fill = stream->fill();
int old_precision = stream->precision();
(*iter)->process(*stream, fmt);
stream->flags(saved_flags);
stream->fill(old_fill);
stream->precision(old_precision);
++iter;
} else {
*stream << "<missing arg for format>";
}
++p;
}
break; break;
case '\n': case '\n':
*stream << endl; stream << endl;
++p; ++ptr;
break; break;
case '\r': case '\r':
++p; ++ptr;
if (*p != '\n') if (*ptr != '\n')
*stream << endl; stream << endl;
break; break;
default: { default:
size_t len = strcspn(p, "%\n\r\0"); len = strcspn(ptr, "%\n\r\0");
stream->write(p, len); stream.write(ptr, len);
p += len; ptr += len;
}
break; break;
} }
} }
while (iter != end) { return;
*stream << "<extra arg>";
++iter; processing:
bool done = false;
bool end_number = false;
bool have_precision = false;
int number = 0;
stream.fill(' ');
stream.flags((ios::fmtflags)0);
while (!done) {
++ptr;
if (*ptr >= '0' && *ptr <= '9') {
if (end_number)
continue;
} else if (number > 0)
end_number = true;
switch (*ptr) {
case 's':
fmt.format = Format::string;
done = true;
break;
case 'c':
fmt.format = Format::character;
done = true;
break;
case 'l':
continue;
case 'p':
fmt.format = Format::integer;
fmt.base = Format::hex;
fmt.alternate_form = true;
done = true;
break;
case 'X':
fmt.uppercase = true;
case 'x':
fmt.base = Format::hex;
fmt.format = Format::integer;
done = true;
break;
case 'o':
fmt.base = Format::oct;
fmt.format = Format::integer;
done = true;
break;
case 'd':
case 'i':
case 'u':
fmt.format = Format::integer;
done = true;
break;
case 'G':
fmt.uppercase = true;
case 'g':
fmt.format = Format::floating;
fmt.float_format = Format::best;
done = true;
break;
case 'E':
fmt.uppercase = true;
case 'e':
fmt.format = Format::floating;
fmt.float_format = Format::scientific;
done = true;
break;
case 'f':
fmt.format = Format::floating;
fmt.float_format = Format::fixed;
done = true;
break;
case 'n':
stream << "we don't do %n!!!\n";
done = true;
break;
case '#':
fmt.alternate_form = true;
break;
case '-':
fmt.flush_left = true;
break;
case '+':
fmt.print_sign = true;
break;
case ' ':
fmt.blank_space = true;
break;
case '.':
fmt.width = number;
fmt.precision = 0;
have_precision = true;
number = 0;
end_number = false;
break;
case '0':
if (number == 0) {
fmt.fill_zero = true;
break;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
number = number * 10 + (*ptr - '0');
break;
case '%':
assert("we shouldn't get here");
break;
default:
done = true;
break;
}
if (end_number) {
if (have_precision)
fmt.precision = number;
else
fmt.width = number;
end_number = false;
number = 0;
}
} }
++ptr;
} }
string void
ArgList::dumpToString(const string &format) Print::end_args()
{ {
stringstream ss; size_t len;
dump(ss, format); while (*ptr) {
switch (*ptr) {
case '%':
if (ptr[1] != '%')
stream << "<extra arg>";
return ss.str(); stream.put('%');
ptr += 2;
break;
case '\n':
stream << endl;
++ptr;
break;
case '\r':
++ptr;
if (*ptr != '\n')
stream << endl;
break;
default:
len = strcspn(ptr, "%\n\r\0");
stream.write(ptr, len);
ptr += len;
break;
}
}
stream.flags(saved_flags);
stream.fill(saved_fill);
stream.precision(saved_precision);
} }
} /* end namespace cp */ }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2005 The Regents of The University of Michigan * Copyright (c) 2002-2006 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -29,142 +29,135 @@
* Steve Reinhardt * Steve Reinhardt
*/ */
#ifndef __CPRINTF_HH__ #ifndef __BASE_CPRINTF_HH__
#define __CPRINTF_HH__ #define __BASE_CPRINTF_HH__
#include <ios>
#include <iostream> #include <iostream>
#include <list> #include <list>
#include <string> #include <string>
#include "base/varargs.hh"
#include "base/cprintf_formats.hh" #include "base/cprintf_formats.hh"
namespace cp { namespace cp {
class ArgList #define CPRINTF_DECLARATION VARARGS_DECLARATION(cp::Print)
#define CPRINTF_DEFINITION VARARGS_DEFINITION(cp::Print)
struct Print
{ {
private:
class Base
{
public:
virtual ~Base() {}
virtual void process(std::ostream &out, Format &fmt) = 0;
};
template <typename T>
class Node : public Base
{
public:
const T &data;
public:
Node(const T &d) : data(d) {}
virtual void process(std::ostream &out, Format &fmt) {
switch (fmt.format) {
case Format::character:
format_char(out, data, fmt);
break;
case Format::integer:
format_integer(out, data, fmt);
break;
case Format::floating:
format_float(out, data, fmt);
break;
case Format::string:
format_string(out, data, fmt);
break;
default:
out << "<bad format>";
break;
}
}
};
typedef std::list<Base *> list_t;
protected: protected:
list_t objects; std::ostream &stream;
std::ostream *stream; const char *format;
const char *ptr;
std::ios::fmtflags saved_flags;
char saved_fill;
int saved_precision;
void process(Format &fmt);
public: public:
ArgList() : stream(&std::cout) {} Print(std::ostream &stream, const std::string &format);
~ArgList(); Print(std::ostream &stream, const char *format);
~Print();
template<class T> template <typename T>
void append(const T &data) { void
Base *obj = new ArgList::Node<T>(data); add_arg(const T &data)
objects.push_back(obj); {
Format fmt;
process(fmt);
switch (fmt.format) {
case Format::character:
format_char(stream, data, fmt);
break;
case Format::integer:
format_integer(stream, data, fmt);
break;
case Format::floating:
format_float(stream, data, fmt);
break;
case Format::string:
format_string(stream, data, fmt);
break;
default:
stream << "<bad format>";
break;
}
} }
template<class T> void end_args();
void prepend(const T &data) {
Base *obj = new ArgList::Node<T>(data);
objects.push_front(obj);
}
void dump(const std::string &format);
void dump(std::ostream &strm, const std::string &fmt)
{ stream = &strm; dump(fmt); }
std::string dumpToString(const std::string &format);
friend ArgList &operator<<(std::ostream &str, ArgList &list);
}; };
template<class T> /* end namespace cp */ }
inline ArgList &
operator,(ArgList &alist, const T &data) typedef VarArgs::List<cp::Print> CPrintfArgsList;
inline void
ccprintf(std::ostream &stream, const char *format, const CPrintfArgsList &args)
{ {
alist.append(data); cp::Print print(stream, format);
return alist; args.add_args(print);
} }
class ArgListNull {
};
inline ArgList &
operator,(ArgList &alist, ArgListNull)
{ return alist; }
//
// cprintf(format, args, ...) prints to cout
// (analogous to printf())
//
inline void inline void
__cprintf(const std::string &format, ArgList &args) ccprintf(std::ostream &stream, const char *format, CPRINTF_DECLARATION)
{ args.dump(format); delete &args; } {
#define __cprintf__(format, ...) \ cp::Print print(stream, format);
cp::__cprintf(format, (*(new cp::ArgList), __VA_ARGS__)) VARARGS_ADDARGS(print);
#define cprintf(...) \ }
__cprintf__(__VA_ARGS__, cp::ArgListNull())
//
// ccprintf(stream, format, args, ...) prints to the specified stream
// (analogous to fprintf())
//
inline void inline void
__ccprintf(std::ostream &stream, const std::string &format, ArgList &args) cprintf(const char *format, CPRINTF_DECLARATION)
{ args.dump(stream, format); delete &args; } {
#define __ccprintf__(stream, format, ...) \ ccprintf(std::cout, format, VARARGS_ALLARGS);
cp::__ccprintf(stream, format, (*(new cp::ArgList), __VA_ARGS__)) }
#define ccprintf(stream, ...) \
__ccprintf__(stream, __VA_ARGS__, cp::ArgListNull())
//
// csprintf(format, args, ...) returns a string
// (roughly analogous to sprintf())
//
inline std::string inline std::string
__csprintf(const std::string &format, ArgList &args) csprintf(const char *format, CPRINTF_DECLARATION)
{ std::string s = args.dumpToString(format); delete &args; return s; } {
#define __csprintf__(format, ...) \ std::stringstream stream;
cp::__csprintf(format, (*(new cp::ArgList), __VA_ARGS__)) ccprintf(stream, format, VARARGS_ALLARGS);
#define csprintf(...) \ return stream.str();
__csprintf__(__VA_ARGS__, cp::ArgListNull()) }
/*
* functions again with std::string. We have both so we don't waste
* time converting const char * to std::string since we don't take
* advantage of it.
*/
inline void
ccprintf(std::ostream &stream, const std::string &format,
const CPrintfArgsList &args)
{
ccprintf(stream, format.c_str(), args);
}
inline void
ccprintf(std::ostream &stream, const std::string &format, CPRINTF_DECLARATION)
{
ccprintf(stream, format, VARARGS_ALLARGS);
}
inline void
cprintf(const std::string &format, CPRINTF_DECLARATION)
{
ccprintf(std::cout, format, VARARGS_ALLARGS);
}
inline std::string
csprintf(const std::string &format, CPRINTF_DECLARATION)
{
std::stringstream stream;
ccprintf(stream, format, VARARGS_ALLARGS);
return stream.str();
} }
#endif // __CPRINTF_HH__ #endif // __CPRINTF_HH__

View file

@ -28,8 +28,8 @@
* Authors: Nathan Binkert * Authors: Nathan Binkert
*/ */
#ifndef __CPRINTF_FORMATS_HH__ #ifndef __BASE_CPRINTF_FORMATS_HH__
#define __CPRINTF_FORMATS_HH__ #define __BASE_CPRINTF_FORMATS_HH__
#include <sstream> #include <sstream>
#include <ostream> #include <ostream>

View file

@ -36,91 +36,99 @@
#include "base/misc.hh" #include "base/misc.hh"
#include "base/output.hh" #include "base/output.hh"
#include "base/trace.hh" #include "base/trace.hh"
#include "base/varargs.hh"
#include "sim/host.hh" #include "sim/host.hh"
#include "sim/root.hh" #include "sim/root.hh"
using namespace std; using namespace std;
void void
__panic(const string &format, cp::ArgList &args, const char *func, __panic(const char *func, const char *file, int line, const char *fmt,
const char *file, int line) CPRINTF_DEFINITION)
{ {
string fmt = "panic: " + format; string format = "panic: ";
switch (fmt[fmt.size() - 1]) { format += fmt;
switch (format[format.size() - 1]) {
case '\n': case '\n':
case '\r': case '\r':
break; break;
default: default:
fmt += "\n"; format += "\n";
} }
fmt += " @ cycle %d\n[%s:%s, line %d]\n"; format += " @ cycle %d\n[%s:%s, line %d]\n";
args.append(curTick); CPrintfArgsList args(VARARGS_ALLARGS);
args.append(func);
args.append(file);
args.append(line);
args.dump(cerr, fmt);
delete &args; args.push_back(curTick);
args.push_back(func);
args.push_back(file);
args.push_back(line);
ccprintf(cerr, format.c_str(), args);
abort(); abort();
} }
void void
__fatal(const string &format, cp::ArgList &args, const char *func, __fatal(const char *func, const char *file, int line, const char *fmt,
const char *file, int line) CPRINTF_DEFINITION)
{ {
string fmt = "fatal: " + format; CPrintfArgsList args(VARARGS_ALLARGS);
string format = "fatal: ";
format += fmt;
switch (fmt[fmt.size() - 1]) { switch (format[format.size() - 1]) {
case '\n': case '\n':
case '\r': case '\r':
break; break;
default: default:
fmt += "\n"; format += "\n";
} }
fmt += " @ cycle %d\n[%s:%s, line %d]\n"; format += " @ cycle %d\n[%s:%s, line %d]\n";
fmt += "Memory Usage: %ld KBytes\n"; format += "Memory Usage: %ld KBytes\n";
args.append(curTick); args.push_back(curTick);
args.append(func); args.push_back(func);
args.append(file); args.push_back(file);
args.append(line); args.push_back(line);
args.append(memUsage()); args.push_back(memUsage());
args.dump(cerr, fmt);
delete &args; ccprintf(cerr, format.c_str(), args);
exit(1); exit(1);
} }
void void
__warn(const string &format, cp::ArgList &args, const char *func, __warn(const char *func, const char *file, int line, const char *fmt,
const char *file, int line) CPRINTF_DEFINITION)
{ {
string fmt = "warn: " + format; string format = "warn: ";
format += fmt;
switch (fmt[fmt.size() - 1]) { switch (format[format.size() - 1]) {
case '\n': case '\n':
case '\r': case '\r':
break; break;
default: default:
fmt += "\n"; format += "\n";
} }
#ifdef VERBOSE_WARN #ifdef VERBOSE_WARN
fmt += " @ cycle %d\n[%s:%s, line %d]\n"; format += " @ cycle %d\n[%s:%s, line %d]\n";
args.append(curTick);
args.append(func);
args.append(file);
args.append(line);
#endif #endif
args.dump(cerr, fmt); CPrintfArgsList args(VARARGS_ALLARGS);
if (simout.isFile(*outputStream))
args.dump(*outputStream, fmt);
delete &args; #ifdef VERBOSE_WARN
args.push_back(curTick);
args.push_back(func);
args.push_back(file);
args.push_back(line);
#endif
ccprintf(cerr, format.c_str(), args);
if (simout.isFile(*outputStream))
ccprintf(*outputStream, format.c_str(), args);
} }

View file

@ -32,9 +32,11 @@
#ifndef __MISC_HH__ #ifndef __MISC_HH__
#define __MISC_HH__ #define __MISC_HH__
#include <assert.h> #include <cassert>
#include "base/compiler.hh" #include "base/compiler.hh"
#include "base/cprintf.hh" #include "base/cprintf.hh"
#include "base/varargs.hh"
#if defined(__SUNPRO_CC) #if defined(__SUNPRO_CC)
#define __FUNCTION__ "how to fix me?" #define __FUNCTION__ "how to fix me?"
@ -47,14 +49,20 @@
// calls abort which can dump core or enter the debugger. // calls abort which can dump core or enter the debugger.
// //
// //
void __panic(const std::string&, cp::ArgList &, const char*, const char*, int) void __panic(const char *func, const char *file, int line, const char *format,
M5_ATTR_NORETURN; CPRINTF_DECLARATION) M5_ATTR_NORETURN;
#define __panic__(format, ...) \ void __panic(const char *func, const char *file, int line,
__panic(format, (*(new cp::ArgList), __VA_ARGS__), \ const std::string &format, CPRINTF_DECLARATION)
__FUNCTION__ , __FILE__, __LINE__) M5_ATTR_NORETURN;
#define panic(...) \
__panic__(__VA_ARGS__, cp::ArgListNull()) inline void
__panic(const char *func, const char *file, int line,
const std::string &format, CPRINTF_DEFINITION)
{
__panic(func, file, line, format.c_str(), VARARGS_ALLARGS);
}
M5_PRAGMA_NORETURN(__panic) M5_PRAGMA_NORETURN(__panic)
#define panic(...) __panic(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
// //
// This implements a cprintf based fatal() function. fatal() should // This implements a cprintf based fatal() function. fatal() should
@ -64,34 +72,43 @@ M5_PRAGMA_NORETURN(__panic)
// "normal" exit with an error code, as opposed to abort() like // "normal" exit with an error code, as opposed to abort() like
// panic() does. // panic() does.
// //
void __fatal(const std::string&, cp::ArgList &, const char*, const char*, int) void __fatal(const char *func, const char *file, int line, const char *format,
CPRINTF_DECLARATION) M5_ATTR_NORETURN;
void __fatal(const char *func, const char *file, int line,
const std::string &format, CPRINTF_DECLARATION)
M5_ATTR_NORETURN; M5_ATTR_NORETURN;
#define __fatal__(format, ...) \
__fatal(format, (*(new cp::ArgList), __VA_ARGS__), \ inline void
__FUNCTION__ , __FILE__, __LINE__) __fatal(const char *func, const char *file, int line,
#define fatal(...) \ const std::string &format, CPRINTF_DEFINITION)
__fatal__(__VA_ARGS__, cp::ArgListNull()) {
__fatal(func, file, line, format.c_str(), VARARGS_ALLARGS);
}
M5_PRAGMA_NORETURN(__fatal) M5_PRAGMA_NORETURN(__fatal)
#define fatal(...) __fatal(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
// //
// This implements a cprintf based warn // This implements a cprintf based warn
// //
void __warn(const std::string&, cp::ArgList &, const char*, const char*, int); void __warn(const char *func, const char *file, int line, const char *format,
#define __warn__(format, ...) \ CPRINTF_DECLARATION);
__warn(format, (*(new cp::ArgList), __VA_ARGS__), \ inline void
__FUNCTION__ , __FILE__, __LINE__) __warn(const char *func, const char *file, int line, const std::string &format,
#define warn(...) \ CPRINTF_DECLARATION)
__warn__(__VA_ARGS__, cp::ArgListNull()) {
__warn(func, file, line, format, VARARGS_ALLARGS);
}
#define warn(...) __warn(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
// Only print the warning message the first time it is seen. This // Only print the warning message the first time it is seen. This
// doesn't check the warning string itself, it just only lets one // doesn't check the warning string itself, it just only lets one
// warning come from the statement. So, even if the arguments change // warning come from the statement. So, even if the arguments change
// and that would have resulted in a different warning message, // and that would have resulted in a different warning message,
// subsequent messages would still be supressed. // subsequent messages would still be supressed.
#define warn_once(...) do { \ #define warn_once(...) do { \
static bool once = false; \ static bool once = false; \
if (!once) { \ if (!once) { \
__warn__(__VA_ARGS__, cp::ArgListNull()); \ warn(__VA_ARGS__); \
once = true; \ once = true; \
} \ } \
} while (0) } while (0)
@ -99,10 +116,10 @@ void __warn(const std::string&, cp::ArgList &, const char*, const char*, int);
// //
// assert() that prints out the current cycle // assert() that prints out the current cycle
// //
#define m5_assert(TEST) \ #define m5_assert(TEST) do { \
if (!(TEST)) { \ if (!(TEST)) \
std::cerr << "Assertion failure, curTick = " << curTick << std::endl; \ ccprintf(std::cerr, "Assertion failure, curTick = %d\n", curTick); \
} \ assert(TEST); \
assert(TEST); } while (0)
#endif // __MISC_HH__ #endif // __MISC_HH__

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2005 The Regents of The University of Michigan * Copyright (c) 2001-2006 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,6 +39,7 @@
#include "base/misc.hh" #include "base/misc.hh"
#include "base/trace.hh" #include "base/trace.hh"
#include "base/str.hh" #include "base/str.hh"
#include "base/varargs.hh"
using namespace std; using namespace std;
@ -153,9 +154,7 @@ Log::dump(ostream &os)
} }
PrintfRecord::~PrintfRecord() PrintfRecord::~PrintfRecord()
{ {}
delete &args;
}
void void
PrintfRecord::dump(ostream &os) PrintfRecord::dump(ostream &os)
@ -164,17 +163,17 @@ PrintfRecord::dump(ostream &os)
if (!name.empty()) { if (!name.empty()) {
fmt = "%s: " + fmt; fmt = "%s: " + fmt;
args.prepend(name); args.push_front(name);
} }
if (cycle != (Tick)-1) { if (cycle != (Tick)-1) {
fmt = "%7d: " + fmt; fmt = "%7d: " + fmt;
args.prepend(cycle); args.push_front(cycle);
} }
fmt += format; fmt += format;
args.dump(os, fmt); ccprintf(os, fmt.c_str(), args);
os.flush(); os.flush();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001-2005 The Regents of The University of Michigan * Copyright (c) 2001-2006 The Regents of The University of Michigan
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -81,14 +81,15 @@ namespace Trace {
class PrintfRecord : public Record class PrintfRecord : public Record
{ {
private: private:
const char *format;
const std::string &name; const std::string &name;
cp::ArgList &args; const char *format;
CPrintfArgsList args;
public: public:
PrintfRecord(const char *_format, cp::ArgList &_args, PrintfRecord(Tick cycle, const std::string &_name, const char *_format,
Tick cycle, const std::string &_name) CPRINTF_DECLARATION)
: Record(cycle), format(_format), name(_name), args(_args) : Record(cycle), name(_name), format(_format),
args(VARARGS_ALLARGS)
{ {
} }
@ -121,7 +122,6 @@ namespace Trace {
Record **wrapRecPtr; // &buffer[size], for quick wrap check Record **wrapRecPtr; // &buffer[size], for quick wrap check
public: public:
Log(); Log();
~Log(); ~Log();
@ -136,22 +136,28 @@ namespace Trace {
extern ObjectMatch ignore; extern ObjectMatch ignore;
inline void inline void
dprintf(const char *format, cp::ArgList &args, Tick cycle, dprintf(Tick when, const std::string &name, const char *format,
const std::string &name) CPRINTF_DECLARATION)
{ {
if (name.empty() || !ignore.match(name)) if (!name.empty() && ignore.match(name))
theLog.append(new Trace::PrintfRecord(format, args, cycle, name)); return;
theLog.append(new Trace::PrintfRecord(when, name, format,
VARARGS_ALLARGS));
} }
inline void inline void
dataDump(Tick cycle, const std::string &name, const void *data, int len) dataDump(Tick when, const std::string &name, const void *data, int len)
{ {
theLog.append(new Trace::DataRecord(cycle, name, data, len)); theLog.append(new Trace::DataRecord(when, name, data, len));
} }
extern const std::string DefaultName; extern const std::string DefaultName;
}; };
std::ostream &DebugOut();
// This silly little class allows us to wrap a string in a functor // This silly little class allows us to wrap a string in a functor
// object so that we can give a name() that DPRINTF will like // object so that we can give a name() that DPRINTF will like
struct StringWrap struct StringWrap
@ -162,7 +168,6 @@ struct StringWrap
}; };
inline const std::string &name() { return Trace::DefaultName; } inline const std::string &name() { return Trace::DefaultName; }
std::ostream &DebugOut();
// //
// DPRINTF is a debugging trace facility that allows one to // DPRINTF is a debugging trace facility that allows one to
@ -178,47 +183,36 @@ std::ostream &DebugOut();
#define DTRACE(x) (Trace::IsOn(Trace::x)) #define DTRACE(x) (Trace::IsOn(Trace::x))
#define DCOUT(x) if (Trace::IsOn(Trace::x)) DebugOut() #define DDUMP(x, data, count) do { \
if (DTRACE(x)) \
#define DDUMP(x, data, count) \ Trace::dataDump(curTick, name(), data, count); \
do { \
if (Trace::IsOn(Trace::x)) \
Trace::dataDump(curTick, name(), data, count); \
} while (0) } while (0)
#define __dprintf(cycle, name, format, ...) \ #define DPRINTF(x, args...) do { \
Trace::dprintf(format, (*(new cp::ArgList), __VA_ARGS__), cycle, name) if (DTRACE(x)) \
Trace::dprintf(curTick, name(), args); \
#define DPRINTF(x, ...) \
do { \
if (Trace::IsOn(Trace::x)) \
__dprintf(curTick, name(), __VA_ARGS__, cp::ArgListNull()); \
} while (0) } while (0)
#define DPRINTFR(x, ...) \ #define DPRINTFR(x, args...) do { \
do { \ if (DTRACE(x)) \
if (Trace::IsOn(Trace::x)) \ Trace::dprintf((Tick)-1, std::string(), args); \
__dprintf((Tick)-1, std::string(), __VA_ARGS__, cp::ArgListNull()); \
} while (0) } while (0)
#define DPRINTFN(...) \ #define DPRINTFN(args...) do { \
do { \ Trace::dprintf(curTick, name(), args); \
__dprintf(curTick, name(), __VA_ARGS__, cp::ArgListNull()); \
} while (0) } while (0)
#define DPRINTFNR(...) \ #define DPRINTFNR(args...) do { \
do { \ Trace::dprintf((Tick)-1, string(), args); \
__dprintf((Tick)-1, string(), __VA_ARGS__, cp::ArgListNull()); \
} while (0) } while (0)
#else // !TRACING_ON #else // !TRACING_ON
#define DTRACE(x) (false) #define DTRACE(x) (false)
#define DCOUT(x) if (0) DebugOut() #define DPRINTF(x, args...) do {} while (0)
#define DPRINTF(x, ...) do {} while (0) #define DPRINTFR(args...) do {} while (0)
#define DPRINTFR(...) do {} while (0) #define DPRINTFN(args...) do {} while (0)
#define DPRINTFN(...) do {} while (0) #define DPRINTFNR(args...) do {} while (0)
#define DPRINTFNR(...) do {} while (0)
#define DDUMP(x, data, count) do {} while (0) #define DDUMP(x, data, count) do {} while (0)
#endif // TRACING_ON #endif // TRACING_ON

292
src/base/varargs.hh Normal file
View file

@ -0,0 +1,292 @@
/*
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
*/
#ifndef __BASE_VARARGS_HH__
#define __BASE_VARARGS_HH__
#include "base/refcnt.hh"
#define VARARGS_DECLARATION(receiver) \
VarArgs::Argument<receiver> a01 = VarArgs::Null(), \
VarArgs::Argument<receiver> a02 = VarArgs::Null(), \
VarArgs::Argument<receiver> a03 = VarArgs::Null(), \
VarArgs::Argument<receiver> a04 = VarArgs::Null(), \
VarArgs::Argument<receiver> a05 = VarArgs::Null(), \
VarArgs::Argument<receiver> a06 = VarArgs::Null(), \
VarArgs::Argument<receiver> a07 = VarArgs::Null(), \
VarArgs::Argument<receiver> a08 = VarArgs::Null(), \
VarArgs::Argument<receiver> a09 = VarArgs::Null(), \
VarArgs::Argument<receiver> a10 = VarArgs::Null(), \
VarArgs::Argument<receiver> a11 = VarArgs::Null(), \
VarArgs::Argument<receiver> a12 = VarArgs::Null(), \
VarArgs::Argument<receiver> a13 = VarArgs::Null(), \
VarArgs::Argument<receiver> a14 = VarArgs::Null(), \
VarArgs::Argument<receiver> a15 = VarArgs::Null(), \
VarArgs::Argument<receiver> a16 = VarArgs::Null()
#define VARARGS_DEFINITION(receiver) \
VarArgs::Argument<receiver> a01, \
VarArgs::Argument<receiver> a02, \
VarArgs::Argument<receiver> a03, \
VarArgs::Argument<receiver> a04, \
VarArgs::Argument<receiver> a05, \
VarArgs::Argument<receiver> a06, \
VarArgs::Argument<receiver> a07, \
VarArgs::Argument<receiver> a08, \
VarArgs::Argument<receiver> a09, \
VarArgs::Argument<receiver> a10, \
VarArgs::Argument<receiver> a11, \
VarArgs::Argument<receiver> a12, \
VarArgs::Argument<receiver> a13, \
VarArgs::Argument<receiver> a14, \
VarArgs::Argument<receiver> a15, \
VarArgs::Argument<receiver> a16
#define VARARGS_ALLARGS \
a01, a02, a03, a04, a05, a06, a07, a08, \
a09, a10, a11, a12, a13, a14, a15, a16
#define VARARGS_ADDARGS(receiver) do { \
do { \
if (!a01) break; \
a01.add_arg(receiver); \
if (!a02) break; \
a02.add_arg(receiver); \
if (!a03) break; \
a03.add_arg(receiver); \
if (!a04) break; \
a04.add_arg(receiver); \
if (!a05) break; \
a05.add_arg(receiver); \
if (!a06) break; \
a06.add_arg(receiver); \
if (!a07) break; \
a07.add_arg(receiver); \
if (!a08) break; \
a08.add_arg(receiver); \
if (!a09) break; \
a09.add_arg(receiver); \
if (!a10) break; \
a10.add_arg(receiver); \
if (!a11) break; \
a11.add_arg(receiver); \
if (!a12) break; \
a12.add_arg(receiver); \
if (!a13) break; \
a13.add_arg(receiver); \
if (!a14) break; \
a14.add_arg(receiver); \
if (!a15) break; \
a15.add_arg(receiver); \
if (!a16) break; \
a16.add_arg(receiver); \
} while (0); \
receiver.end_args(); \
} while (0)
namespace VarArgs {
struct Null {};
template <typename T>
struct Traits
{
enum { enabled = true };
};
template <>
struct Traits<Null>
{
enum { enabled = false };
};
template <class RECV>
struct Base : public RefCounted
{
virtual void add_arg(RECV &receiver) const = 0;
};
template <typename T, class RECV>
struct Any : public Base<RECV>
{
const T &argument;
Any(const T &arg) : argument(arg) {}
virtual void
add_arg(RECV &receiver) const
{
receiver.add_arg(argument);
}
};
template <class RECV>
struct Argument : public RefCountingPtr<Base<RECV> >
{
typedef RefCountingPtr<Base<RECV> > Base;
Argument() { }
Argument(const Null &null) { }
template <typename T>
Argument(const T& arg) : Base(new Any<T, RECV>(arg)) { }
void
add_arg(RECV &receiver) const
{
if (this->data)
this->data->add_arg(receiver);
}
};
template<class RECV>
class List
{
public:
typedef Argument<RECV> Argument;
typedef std::list<Argument> list;
typedef typename list::iterator iterator;
typedef typename list::const_iterator const_iterator;
typedef typename list::size_type size_type;
protected:
list l;
public:
List() {}
List(Argument a01, Argument a02, Argument a03, Argument a04,
Argument a05, Argument a06, Argument a07, Argument a08,
Argument a09, Argument a10, Argument a11, Argument a12,
Argument a13, Argument a14, Argument a15, Argument a16)
{
if (!a01) return;
l.push_back(a01);
if (!a02) return;
l.push_back(a02);
if (!a03) return;
l.push_back(a03);
if (!a04) return;
l.push_back(a04);
if (!a05) return;
l.push_back(a05);
if (!a06) return;
l.push_back(a06);
if (!a07) return;
l.push_back(a07);
if (!a08) return;
l.push_back(a08);
if (!a09) return;
l.push_back(a09);
if (!a10) return;
l.push_back(a10);
if (!a11) return;
l.push_back(a11);
if (!a12) return;
l.push_back(a12);
if (!a13) return;
l.push_back(a13);
if (!a14) return;
l.push_back(a14);
if (!a15) return;
l.push_back(a15);
if (!a16) return;
l.push_back(a16);
}
size_type size() const { return l.size(); }
bool empty() const { return l.empty(); }
iterator begin() { return l.begin(); }
const_iterator begin() const { return l.begin(); }
iterator end() { return l.end(); }
const_iterator end() const { return l.end(); }
void
push_back(const Argument &arg)
{
if (arg)
l.push_back(arg);
}
void
push_front(const Argument &arg)
{
if (arg)
l.push_front(arg);
}
template <typename T>
void
push_back(const T &arg)
{
if (Traits<T>::enabled)
l.push_back(arg);
}
template <typename T>
void
push_front(const T &arg)
{
if (Traits<T>::enabled)
l.push_front(arg);
}
Argument& front() { return l.front(); }
const Argument& front() const { return l.front(); }
Argument& back() { return l.back(); }
const Argument& back() const { return l.back(); }
void erase(iterator position) { return l.erase(position); }
void erase(iterator first, iterator last) { return l.erase(first, last); }
void clear() { return l.clear(); }
void pop_front() { return l.pop_front(); }
void pop_back() { return l.pop_back(); }
void reverse() { l.reverse(); }
/*
* Functions specific to variable arguments
*/
void
add_args(RECV &recv) const
{
const_iterator i = l.begin();
const_iterator end = l.end();
while (i != end) {
i->add_arg(recv);
++i;
}
recv.end_args();
}
};
/* end namespace VarArgs */ }
#endif /* __BASE_VARARGS_HH__ */