mirror of https://github.com/YosysHQ/abc.git
366 lines
10 KiB
C++
366 lines
10 KiB
C++
#include "global.h"
|
|
|
|
#include "internal.hpp"
|
|
|
|
ABC_NAMESPACE_IMPL_START
|
|
|
|
namespace CaDiCaL {
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// By default, e.g., for library usage, the 'opts.report' value is zero
|
|
// ('false') but can be set to '1' by the stand alone solver. Using here
|
|
// a static default value avoids that the stand alone solver reports that
|
|
// '--report=1' is different from the default in 'print ()' below.
|
|
//
|
|
int Options::reportdefault;
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// The order of initializations of static objects is undefined and thus we
|
|
// can not assume that this table is already initialized if a solver and
|
|
// thus the constructor of 'Options' is called. Therefore we just have to
|
|
// reinitialize this table in every call to 'Options::Options'. This does
|
|
// not produce a data race even for parallel initialization since the
|
|
// same values are written by all threads under the assumption that the
|
|
// 'reportdefault' is set before any solver is initialized. We do have to
|
|
// perform this static initialization though, since 'has' is static and does
|
|
// not require that the 'Options' constructor was called.
|
|
|
|
Option Options::table[] = {
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
{#N, (int) V, (int) L, (int) H, (int) O, (bool) P, D},
|
|
OPTIONS
|
|
#undef OPTION
|
|
};
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
// Binary search in 'table', which requires option names to be sorted, which
|
|
// in turned is checked at start-up in 'Options::Options'.
|
|
|
|
Option *Options::has (const char *name) {
|
|
size_t l = 0, r = number_of_options;
|
|
while (l < r) {
|
|
size_t m = l + (r - l) / 2;
|
|
Option *res = &table[m];
|
|
int tmp = strcmp (name, res->name);
|
|
if (!tmp)
|
|
return res;
|
|
if (tmp < 0)
|
|
r = m;
|
|
if (tmp > 0)
|
|
l = m + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
bool Options::parse_long_option (const char *arg, string &name, int &val) {
|
|
if (arg[0] != '-' || arg[1] != '-')
|
|
return false;
|
|
const bool has_no_prefix =
|
|
(arg[2] == 'n' && arg[3] == 'o' && arg[4] == '-');
|
|
const size_t offset = has_no_prefix ? 5 : 2;
|
|
name = arg + offset;
|
|
const size_t pos = name.find_first_of ('=');
|
|
if (pos != string::npos)
|
|
name[pos] = 0;
|
|
if (!Options::has (name.c_str ()))
|
|
return false;
|
|
if (pos == string::npos)
|
|
val = !has_no_prefix;
|
|
else {
|
|
const char *val_str = name.c_str () + pos + 1;
|
|
if (!parse_int_str (val_str, val))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::initialize_from_environment (int &val, const char *name,
|
|
const int L, const int H) {
|
|
char key[80], *q;
|
|
const char *p;
|
|
CADICAL_assert (strlen (name) + strlen ("CADICAL_") + 1 < sizeof (key));
|
|
for (p = "CADICAL_", q = key; *p; p++)
|
|
*q++ = *p;
|
|
for (p = name; *p; p++)
|
|
*q++ = toupper (*p);
|
|
CADICAL_assert (q < key + sizeof (key));
|
|
*q = 0;
|
|
const char *val_str = getenv (key);
|
|
if (!val_str)
|
|
return;
|
|
if (!parse_int_str (val_str, val))
|
|
return;
|
|
if (val < L)
|
|
val = L;
|
|
if (val > H)
|
|
val = H;
|
|
}
|
|
|
|
// Initialize all the options to their default value 'V'.
|
|
|
|
Options::Options (Internal *s) : internal (s) {
|
|
CADICAL_assert (number_of_options == sizeof Options::table / sizeof (Option));
|
|
|
|
// First initialize them according to defaults in 'options.hpp'.
|
|
//
|
|
const char *prev = "";
|
|
size_t i = 0;
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
do { \
|
|
if ((L) > (V)) \
|
|
FATAL ("'" #N "' default '" #V "' " \
|
|
"lower minimum '" #L "' in 'options.hpp'"); \
|
|
if ((H) < (V)) \
|
|
FATAL ("'" #N "' default '" #V "' " \
|
|
"larger maximum '" #H "' in 'options.hpp'"); \
|
|
if (strcmp (prev, #N) > 0) \
|
|
FATAL ("'%s' ordered before '" #N "' in 'options.hpp'", prev); \
|
|
N = (int) (V); \
|
|
CADICAL_assert (&val (i) == &N); \
|
|
/* The order of initializing static data is undefined and thus */ \
|
|
/* it might be the case that the 'table' is not initialized yet. */ \
|
|
/* Thus this construction just reinitializes the table too even */ \
|
|
/* though it might not be necessary. */ \
|
|
CADICAL_assert (!table[i].name || !strcmp (table[i].name, #N)); \
|
|
table[i] = {#N, (int) (V), (int) (L), (int) (H), \
|
|
(int) (O), (bool) (P), D}; \
|
|
prev = #N; \
|
|
i++; \
|
|
} while (0);
|
|
OPTIONS
|
|
#undef OPTION
|
|
|
|
// Check consistency in debugging mode.
|
|
//
|
|
#ifndef CADICAL_NDEBUG
|
|
CADICAL_assert (i == number_of_options);
|
|
CADICAL_assert (!has ("aaaaa"));
|
|
CADICAL_assert (!has ("non-existing-option"));
|
|
CADICAL_assert (!has ("zzzzz"));
|
|
#endif
|
|
|
|
// Now overwrite default options with environment values.
|
|
//
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
initialize_from_environment (N, #N, L, H);
|
|
OPTIONS
|
|
#undef OPTION
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::set (Option *o, int new_val) {
|
|
CADICAL_assert (o);
|
|
int &val = o->val (this), old_val = val;
|
|
if (old_val == new_val) {
|
|
LOG ("keeping value '%d' of option '%s'", old_val, o->name);
|
|
return;
|
|
}
|
|
if (new_val < o->lo) {
|
|
LOG ("bounding '%d' to lower limit '%d' for option '%s'", new_val,
|
|
o->lo, o->name);
|
|
new_val = o->lo;
|
|
}
|
|
if (new_val > o->hi) {
|
|
LOG ("bounding '%d' to upper limit '%d' for option '%s'", new_val,
|
|
o->hi, o->name);
|
|
new_val = o->hi;
|
|
}
|
|
val = new_val;
|
|
LOG ("set option 'set (\"%s\", %d)' from '%d'", o->name, new_val,
|
|
old_val);
|
|
}
|
|
|
|
// Explicit option value setting.
|
|
|
|
bool Options::set (const char *name, int val) {
|
|
Option *o = has (name);
|
|
if (!o)
|
|
return false;
|
|
set (o, val);
|
|
return true;
|
|
}
|
|
|
|
int Options::get (const char *name) {
|
|
Option *o = has (name);
|
|
return o ? o->val (this) : 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::print () {
|
|
unsigned different = 0;
|
|
#ifdef CADICAL_QUIET
|
|
const bool verbose = false;
|
|
#endif
|
|
char buffer[256];
|
|
// We prefer the macro iteration here since '[VLH]' might be '1e9' etc.
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
if (N != (V)) \
|
|
different++; \
|
|
if (verbose || N != (V)) { \
|
|
if ((L) == 0 && (H) == 1) { \
|
|
snprintf (buffer, sizeof buffer, "--" #N "=%s", \
|
|
(N ? "true" : "false")); \
|
|
MSG (" %s%-30s%s (%s default %s'%s'%s)", \
|
|
((N == (V)) ? "" : tout.bright_yellow_code ()), buffer, \
|
|
((N == (V)) ? "" : tout.normal_code ()), \
|
|
((N == (V)) ? "same as" : "different from"), \
|
|
((N == (V)) ? tout.green_code () : tout.yellow_code ()), \
|
|
(bool) (V) ? "true" : "false", tout.normal_code ()); \
|
|
} else { \
|
|
snprintf (buffer, sizeof buffer, "--" #N "=%d", N); \
|
|
MSG (" %s%-30s%s (%s default %s'" #V "'%s)", \
|
|
((N == (V)) ? "" : tout.bright_yellow_code ()), buffer, \
|
|
((N == (V)) ? "" : tout.normal_code ()), \
|
|
((N == (V)) ? "same as" : "different from"), \
|
|
((N == (V)) ? tout.green_code () : tout.yellow_code ()), \
|
|
tout.normal_code ()); \
|
|
} \
|
|
}
|
|
OPTIONS
|
|
#undef OPTION
|
|
if (!different)
|
|
MSG ("all options are set to their default value");
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::usage () {
|
|
// We prefer the macro iteration here since '[VLH]' might be '1e9' etc.
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
if ((L) == 0 && (H) == 1) \
|
|
printf (" %-26s " D " [%s]\n", "--" #N "=bool", \
|
|
(bool) (V) ? "true" : "false"); \
|
|
else \
|
|
printf (" %-26s " D " [" #V "]\n", "--" #N "=" #L ".." #H);
|
|
OPTIONS
|
|
#undef OPTION
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::optimize (int val) {
|
|
|
|
if (val < 0) {
|
|
LOG ("ignoring negative optimization mode '%d'", val);
|
|
return;
|
|
}
|
|
|
|
const int max_val = 31;
|
|
if (val > max_val) {
|
|
LOG ("optimization argument '%d' reduced to '%d'", val, max_val);
|
|
val = max_val;
|
|
}
|
|
|
|
int64_t factor2 = 1;
|
|
for (int i = 0; i < val && factor2 <= INT_MAX; i++)
|
|
factor2 *= 2;
|
|
|
|
int64_t factor10 = 1;
|
|
for (int i = 0; i < val && factor10 <= INT_MAX; i++)
|
|
factor10 *= 10;
|
|
|
|
unsigned increased = 0;
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
do { \
|
|
if (!(O)) \
|
|
break; \
|
|
const int64_t factor1 = ((O) == 1 ? factor2 : factor10); \
|
|
int64_t new_val = factor1 * (int64_t) (V); \
|
|
if (new_val > (H)) \
|
|
new_val = (H); \
|
|
if (new_val == (int) (V)) \
|
|
break; \
|
|
LOG ("optimization mode '%d' for '%s' " \
|
|
"gives '%" PRId64 "' instead of '%d", \
|
|
val, #N, new_val, (int) (V)); \
|
|
CADICAL_assert (new_val <= INT_MAX); \
|
|
N = (int) new_val; \
|
|
increased++; \
|
|
} while (0);
|
|
OPTIONS
|
|
#undef OPTION
|
|
if (increased)
|
|
MSG ("optimization mode '-O%d' increased %u limits", val, increased);
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::disable_preprocessing () {
|
|
size_t count = 0;
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
do { \
|
|
if (!(P)) \
|
|
break; \
|
|
if (!(N)) \
|
|
break; \
|
|
LOG ("plain mode disables '%s'", #N); \
|
|
CADICAL_assert ((L) == 0); \
|
|
CADICAL_assert ((H) == 1); \
|
|
count++; \
|
|
N = 0; \
|
|
} while (0);
|
|
OPTIONS
|
|
#undef OPTION
|
|
LOG ("forced plain mode disabled %zd preprocessing options", count);
|
|
#ifndef LOGGING
|
|
(void) count;
|
|
#endif
|
|
}
|
|
|
|
bool Options::is_preprocessing_option (const char *name) {
|
|
Option *o = has (name);
|
|
return o ? o->preprocessing : false;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::reset_default_values () {
|
|
size_t count = 0;
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
do { \
|
|
if (!(R)) \
|
|
break; \
|
|
if (N == (V)) \
|
|
break; \
|
|
LOG ("resetting option '%s' to default %s", #N, #V); \
|
|
count++; \
|
|
N = (int) (V); \
|
|
} while (0);
|
|
OPTIONS
|
|
#undef OPTION
|
|
LOG ("reset %zd options to their default values", count);
|
|
#ifndef LOGGING
|
|
(void) count;
|
|
#endif
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
void Options::copy (Options &other) const {
|
|
#ifdef LOGGING
|
|
Internal *internal = other.internal;
|
|
#endif
|
|
#define OPTION(N, V, L, H, O, P, R, D) \
|
|
if ((N) == (int) (V)) \
|
|
LOG ("keeping non default option '--%s=%s'", #N, #V); \
|
|
else if ((N) != (int) (V)) { \
|
|
LOG ("overwriting default option by '--%s=%d'", #N, N); \
|
|
other.N = N; \
|
|
}
|
|
OPTIONS
|
|
#undef OPTION
|
|
}
|
|
|
|
} // namespace CaDiCaL
|
|
|
|
ABC_NAMESPACE_IMPL_END
|