11 #include "kconfig/lkc.h"
12 #include "lcp_utils.h"
37 printf("Usage: kconfig2sat [options/actions]\n"
40 " -b, --baseconf <.config> Linux .config file with base configuration\n"
41 " --env <.conf.mk> Set env. variables such as ARCH from .conf.mk\n"
42 " -k, --kconfig <Kconfig> Kconfig file (with path)\n"
43 " --varfile <file> File listing variable options (one option per line)\n"
46 " --dump Dump internal data (for debugging)\n"
47 " --cnf <file> Generate CNF representation to <file>\n"
51 char *expr_to_string(struct expr *e);
53 char *sym_to_string(struct symbol *sym)
58 asprintf(&ret, sym->name);
60 asprintf(&ret, "NONAME%d", sym->lcp.id);
64 char *expr_binop_to_string(struct expr *e, const char *op_str)
66 char *l = expr_to_string(e->left.expr);
67 char *r = expr_to_string(e->right.expr);
70 asprintf(&ret, "(%s %s %s)", l, op_str, r);
76 char *expr_comp_to_string(struct expr *e, const char *op_str)
78 char *l = sym_to_string(e->left.sym);
79 char *r = sym_to_string(e->right.sym);
82 asprintf(&ret, "(%s %s %s)", l, op_str, r);
88 char *expr_to_string(struct expr *e)
98 asprintf(&ret, "()%" PRIdPTR, (intptr_t)(e->right.expr));
101 return expr_binop_to_string(e, "||");
103 return expr_binop_to_string(e, "&&");
105 tmp = expr_to_string(e->left.expr);
106 asprintf(&ret, "!%s", tmp);
110 return expr_comp_to_string(e, "==");
112 return expr_comp_to_string(e, "!=");
114 return expr_comp_to_string(e, "<");
116 return expr_comp_to_string(e, "<=");
118 return expr_comp_to_string(e, ">");
120 return expr_comp_to_string(e, ">=");
122 fprintf(stderr, "LIST not implemented\n");
126 return sym_to_string(e->left.sym);
128 fprintf(stderr, "RANGE not implemented\n");
138 void dump_symbol(struct symbol *sym)
140 struct property *prop;
141 const char *name = sym_to_string(sym);
142 const char *type = sym_type_name(sym->type);
143 const char *prompt = NULL;
145 char flags[256] = "fl(";
148 if (sym->type == S_BOOLEAN || sym->type == S_TRISTATE) {
149 switch (sym->curr.tri) {
150 case no: val = 'n'; break;
151 case mod: val = 'm'; break;
152 case yes: val = 'y'; break;
156 #define FLAG(f) do { if (sym->flags & (SYMBOL_##f)) strcat(flags, #f " "); } while (0)
173 flags[strlen(flags)-1] = ')'; /* Replace trailing space */
176 for_all_properties(sym, prop, P_PROMPT) {
180 printf("%-40s %c %-8s %-50s %s\n", name, val, type, flags, prompt);
183 if (sym->dir_dep.expr) {
184 tmp = expr_to_string(sym->dir_dep.expr);
185 printf(" depends %s\n", tmp);
189 for_all_properties(sym, prop, P_SELECT) {
190 assert(prop->expr->type == E_SYMBOL);
191 tmp = expr_to_string(prop->visible.expr);
192 printf(" selects %s if %s\n", prop->expr->left.sym->name, tmp);
203 for_all_symbols(i, sym) {
208 void read_varfile(const char *varfile)
210 FILE *f = fopen(varfile, "r");
219 while (fgets(line, sizeof(line), f)) {
223 if (strncmp(line, CONFIG_, strlen(CONFIG_)) == 0)
224 p += strlen(CONFIG_);
226 const char *sym_name = strtok(p, " =\n");
227 struct symbol *sym = sym_find(sym_name);
229 fprintf(stderr, "%s:%d: Invalid symbol: %s\n", varfile, lineno, sym_name);
232 if (!(sym->flags & SYMBOL_WRITE)) {
233 fprintf(stderr, "%s:%d: Symbol %s not visible\n", varfile, lineno, sym_name);
236 if (sym->flags & (SYMBOL_CHOICEVAL | SYMBOL_CHOICE)) {
237 fprintf(stderr, "%s:%d: Choice values not yet supported: %s", varfile, lineno, sym_name);
240 struct property *prop;
241 const char *prompt = NULL;
242 for_all_properties(sym, prop, P_PROMPT) {
246 fprintf(stderr, "%s:%d: Warning: Symbol %s is internal (has no prompt)\n", varfile, lineno, sym_name);
248 sym->lcp.variable = 1;
257 SatLiteral(struct symbol *s) : sym(s), expr(nullptr) {}
258 SatLiteral(struct expr *e) : sym(nullptr), expr(e) {}
259 bool has_fixed_value() const { return sym && !sym->lcp.variable; }
260 sat_id id() const { return sym ? sym->lcp.id : expr->lcp.id; }
261 bool value() const { assert(sym); return sym->curr.tri == yes; }
264 typedef vector<sat_id> SatClause;
270 SatExpr(int l, enum expr_type o, int r)
271 : left(l), right(r), op(o) {}
272 bool operator<(const SatExpr &o) const { return tie(left, right, op) < tie(o.left, o.right, o.op); }
275 class SatLiterals : public vector<struct SatLiteral>
279 SatLiterals() { push_back(SatLiteral((struct symbol*)nullptr)); reserve(20000); }
280 int count() const { return size() - 1; }
286 * bool FOO!=y => !FOO
287 * bool FOO==n => !FOO
290 struct expr *expr_eliminate_eq_yn(struct expr *e)
298 e->left.expr = expr_eliminate_eq_yn(e->left.expr);
299 e->right.expr = expr_eliminate_eq_yn(e->right.expr);
302 // UNKNOWN symbols sometimes occur in dependency -
303 // e.g. ACPI_VIDEO on arm (the symbol is only defined
304 // for ACPI platforms (x86) but some drivers refer to
306 if (e->left.sym->type == S_TRISTATE || e->left.sym->type == S_BOOLEAN || e->left.sym->type == S_UNKNOWN) {
307 if (e->right.sym == &symbol_no) {
311 } else if (e->right.sym == &symbol_yes) {
315 e = expr_alloc_one(E_NOT, e);
320 if (e->left.sym->type == S_TRISTATE || e->left.sym->type == S_BOOLEAN || e->left.sym->type == S_UNKNOWN) {
321 if (e->right.sym == &symbol_yes) {
325 } else if (e->right.sym == &symbol_no) {
329 e = expr_alloc_one(E_NOT, e);
341 SatLiterals literals = {};
342 vector<SatClause> clauses = {};
343 map<SatExpr, sat_id> expressions = {};
349 expressions2literals();
351 expressions2clauses();
354 void add_symbol_literal(struct symbol *sym) {
355 literals.push_back(SatLiteral(sym));
356 sym->lcp.id = literals.count();
359 void symbols2literals() {
363 symbol_yes.type = S_TRISTATE;
364 symbol_no.type = S_TRISTATE;
365 symbol_mod.type = S_TRISTATE;
367 add_symbol_literal(&symbol_yes);
368 add_symbol_literal(&symbol_no);
369 add_symbol_literal(&symbol_mod);
371 for_all_symbols(i, sym) {
372 if (sym->type == S_BOOLEAN || sym->type == S_TRISTATE || sym->type == S_UNKNOWN) {
373 add_symbol_literal(sym);
378 void expr2literal(struct expr *e) {
384 e->lcp.id = e->left.sym->lcp.id;
387 fprintf(stderr, "NONE not implemented\n");
391 expr2literal(e->left.expr);
393 SatExpr se(e->left.expr->lcp.id, e->type, 0);
394 auto it = expressions.find(se);
395 if (it == expressions.end()) {
396 literals.push_back(SatLiteral(e));
397 expressions.insert(pair<SatExpr, sat_id>(se, literals.count()));
398 e->lcp.id = literals.count();
400 e->lcp.id = it->second;
405 expr2literal(e->left.expr);
406 expr2literal(e->right.expr);
408 SatExpr se(e->left.expr->lcp.id, e->type, e->right.expr->lcp.id);
409 auto it = expressions.find(se);
410 if (it == expressions.end()) {
411 literals.push_back(SatLiteral(e));
412 expressions.insert(pair<SatExpr, sat_id>(se, literals.count()));
413 e->lcp.id = literals.count();
415 e->lcp.id = it->second;
424 SatExpr se(e->left.sym->lcp.id, e->type, e->right.sym->lcp.id);
425 auto it = expressions.find(se);
426 if (it == expressions.end()) {
427 literals.push_back(SatLiteral(e));
428 expressions.insert(pair<SatExpr, sat_id>(se, literals.count()));
429 e->lcp.id = literals.count();
431 e->lcp.id = it->second;
435 fprintf(stderr, "LIST not implemented\n");
439 fprintf(stderr, "RANGE not implemented\n");
445 void expressions2literals() {
448 struct property *prop;
450 for_all_symbols(i, sym) {
451 if (sym->type == S_BOOLEAN || sym->type == S_TRISTATE) {
453 if (sym->flags & SYMBOL_VALID && !sym->lcp.variable)
454 clauses.push_back(SatClause{ sym->curr.tri == yes ? sym->lcp.id : -sym->lcp.id });
456 sym->dir_dep.expr = expr_eliminate_eq_yn(sym->dir_dep.expr);
457 expr2literal(sym->dir_dep.expr);
459 for_all_properties(sym, prop, P_SELECT) {
460 assert(prop->expr->type == E_SYMBOL);
461 prop->visible.expr = expr_eliminate_eq_yn(prop->visible.expr);
462 expr2literal(prop->visible.expr);
468 void symbols2clauses() {
469 for (auto lit: literals)
470 if (lit.sym && lit.has_fixed_value())
471 clauses.push_back(SatClause{ lit.value() ? lit.id() : -lit.id() });
474 void expressions2clauses() {
475 // Tseitin Transformation - see https://en.wikipedia.org/wiki/Tseitin_transformation
476 // or http://fmv.jku.at/biere/talks/Biere-TPTPA11.pdf, slide 27.
477 for (auto expr: expressions) {
478 SatExpr e = expr.first;
479 sat_id e_id = expr.second;
481 if (e.left == 0 || (e.right == 0 && e.op != E_NOT)) {
482 unique_ptr<char> tmp(expr_to_string(literals[e_id].expr));
483 printf("Unexpected sat_id == 0 in %s\n", tmp.get());
492 clauses.push_back(SatClause{ e_id, e.left });
493 clauses.push_back(SatClause{ -e_id, -e.left });
496 clauses.push_back(SatClause{ -e.left, e_id });
497 clauses.push_back(SatClause{ -e.right, e_id });
498 clauses.push_back(SatClause{ -e_id, e.left, e.right });
501 clauses.push_back(SatClause{ -e_id, e.left });
502 clauses.push_back(SatClause{ -e_id, e.right });
503 clauses.push_back(SatClause{ -e.left, -e.right, e_id });
506 clauses.push_back(SatClause{ -e_id, -e.left, e.right });
507 clauses.push_back(SatClause{ -e_id, -e.right, e.left });
508 clauses.push_back(SatClause{ -e.left, -e.right, e_id });
509 clauses.push_back(SatClause{ e.left, e.right, e_id });
512 clauses.push_back(SatClause{ -e_id, -e.left, -e.right });
513 clauses.push_back(SatClause{ -e_id, e.right, e.left });
514 clauses.push_back(SatClause{ -e.left, e.right, e_id });
515 clauses.push_back(SatClause{ e.left, -e.right, e_id });
521 struct expr *e = literals[e_id].expr;
522 unique_ptr<char> tmp(expr_to_string(e));
523 tristate val = expr_calc_value(e);
524 //fprintf(stderr, "Comparison operators not implemented %s = %d\n", tmp.get(), val);
525 //exit(EXIT_FAILURE);
526 clauses.push_back(SatClause{ val == yes ? e_id : -e_id });
530 fprintf(stderr, "LIST not implemented\n");
534 fprintf(stderr, "RANGE not implemented\n");
542 void write_dimacs_cnf(const char *cnf) {
543 FILE *f = fopen(cnf, "w");
550 fprintf(f, "p cnf %d %lu\n", literals.count(), clauses.size() + literals.fixed);
552 for (auto l: literals) {
554 char val = l.has_fixed_value() ? (l.value() ? 'y' : 'n') : '?';
555 fprintf(f, "c SYM %d %s = %c\n", l.sym->lcp.id, l.sym->name, val);
558 char *tmp = expr_to_string(l.expr);
559 fprintf(f, "c EXPR %d %s\n", l.expr->lcp.id, tmp);
563 for (auto clause: clauses) {
564 for (sat_id id: clause) {
566 fprintf(f, "%d ", id);
574 int main(int argc, char **argv)
578 char *baseconf = NULL;
580 char *kconfig = NULL;
581 char *varfile = NULL;
585 int option_index = 0;
586 static struct option long_options[] = {
587 {"baseconf", required_argument, 0, OPT_BASECONFIG },
588 {"cnf", required_argument, 0, OPT_CNF },
589 {"env", required_argument, 0, OPT_ENV },
590 {"dump", no_argument, &dump, true },
591 {"help", no_argument, 0, OPT_HELP },
592 {"kconfig", required_argument, 0, OPT_KCONFIG },
593 {"varfile", required_argument, 0, OPT_VARFILE },
594 // {"varopt", required_argument, 0, OPT_VAROPTION },
595 {"verbose", no_argument, 0, OPT_VERBOSE },
599 c = getopt_long(argc, argv, "b:hk:v",
600 long_options, &option_index);
605 case 0: /* long option with flag != NULL */
615 set_missing_env(optarg);
636 printf("?? getopt returned character code 0%o ??\n", c);
641 fprintf(stderr, "Unexpected option '%s'\n", argv[optind]);
647 if (kconfig == NULL) {
648 fprintf(stderr, "--kconfig option missing\n");
652 setlocale(LC_ALL, "");
653 bindtextdomain(PACKAGE, LOCALEDIR);
656 conf_parse_path(kconfig);
663 read_varfile(varfile);
669 sat_data.write_dimacs_cnf(cnf);