ir/ir \
ir/lower \
ir/libcore \
+ ir/lpp \
ir/opt \
ir/st \
ir/stat \
* @remark This macro may change arr, so update all references!
*/
#define ARR_EXTO(type, arr, n) \
- ((n) >= ARR_LEN((arr)) ? ARR_RESIZE(type, (arr), (n)+1) : (arr))
+ do { \
+ if ((n) >= ARR_LEN(arr)) { ARR_RESIZE(type, arr, (n)+1); } \
+ } while(0)
/**
* Append one element to a flexible array.
/** Backend settings for if-conversion. */
arch_allow_ifconv_func allow_ifconv;
+ /** size of machine words. This is usually the size of the general purpose
+ * integer registers. */
+ unsigned machine_size;
+
/**
* some backends like x87 can only do arithmetic in a specific float
- * mode (but convert to/from other float modes).
+ * mode (load/store are still done in the "normal" float/double modes).
*/
ir_mode *mode_float_arithmetic;
+ /** size of a long double floating mode in bits (or 0 if not supported) */
+ unsigned long_double_size;
+
/** Size of the trampoline code. */
unsigned trampoline_size;
#define hook_exec(what, args) do { \
hook_entry_t *_p; \
for (_p = hooks[what]; _p; _p = _p->next){ \
- void *ctx = _p->context; \
+ void *hook_ctx_ = _p->context; \
_p->hook._##what args; \
} \
} while (0)
-#define hook_new_ir_op(op) hook_exec(hook_new_ir_op, (ctx, op))
-#define hook_free_ir_op(op) hook_exec(hook_free_ir_op, (ctx, op))
-#define hook_new_node(graph, node) hook_exec(hook_new_node, (ctx, graph, node))
+#define hook_new_ir_op(op) hook_exec(hook_new_ir_op, (hook_ctx_, op))
+#define hook_free_ir_op(op) hook_exec(hook_free_ir_op, (hook_ctx_, op))
+#define hook_new_node(graph, node) hook_exec(hook_new_node, (hook_ctx_, graph, node))
#define hook_set_irn_n(src, pos, tgt, old_tgt) \
- hook_exec(hook_set_irn_n, (ctx, src, pos, tgt, old_tgt))
-#define hook_replace(old, nw) hook_exec(hook_replace, (ctx, old, nw))
-#define hook_turn_into_id(node) hook_exec(hook_turn_into_id, (ctx, node))
-#define hook_normalize(node) hook_exec(hook_normalize, (ctx, node))
-#define hook_new_graph(irg, ent) hook_exec(hook_new_graph, (ctx, irg, ent))
-#define hook_free_graph(irg) hook_exec(hook_free_graph, (ctx, irg))
-#define hook_irg_walk(irg, pre, post) hook_exec(hook_irg_walk, (ctx, irg, pre, post))
+ hook_exec(hook_set_irn_n, (hook_ctx_, src, pos, tgt, old_tgt))
+#define hook_replace(old, nw) hook_exec(hook_replace, (hook_ctx_, old, nw))
+#define hook_turn_into_id(node) hook_exec(hook_turn_into_id, (hook_ctx_, node))
+#define hook_normalize(node) hook_exec(hook_normalize, (hook_ctx_, node))
+#define hook_new_graph(irg, ent) hook_exec(hook_new_graph, (hook_ctx_, irg, ent))
+#define hook_free_graph(irg) hook_exec(hook_free_graph, (hook_ctx_, irg))
+#define hook_irg_walk(irg, pre, post) hook_exec(hook_irg_walk, (hook_ctx_, irg, pre, post))
#define hook_irg_walk_blkwise(irg, pre, post) \
- hook_exec(hook_irg_walk_blkwise, (ctx, irg, pre, post))
+ hook_exec(hook_irg_walk_blkwise, (hook_ctx_, irg, pre, post))
#define hook_irg_block_walk(irg, node, pre, post) \
- hook_exec(hook_irg_block_walk, (ctx, irg, node, pre, post))
+ hook_exec(hook_irg_block_walk, (hook_ctx_, irg, node, pre, post))
#define hook_merge_nodes(new_node_array, new_num_entries, old_node_array, old_num_entries, opt) \
- hook_exec(hook_merge_nodes, (ctx, new_node_array, new_num_entries, old_node_array, old_num_entries, opt))
-#define hook_reassociate(start) hook_exec(hook_reassociate, (ctx, start))
-#define hook_lower(node) hook_exec(hook_lower, (ctx, node))
-#define hook_inline(call, irg) hook_exec(hook_inline, (ctx, call, irg))
-#define hook_tail_rec(irg, n_calls) hook_exec(hook_tail_rec, (ctx, irg, n_calls))
+ hook_exec(hook_merge_nodes, (hook_ctx_, new_node_array, new_num_entries, old_node_array, old_num_entries, opt))
+#define hook_reassociate(start) hook_exec(hook_reassociate, (hook_ctx_, start))
+#define hook_lower(node) hook_exec(hook_lower, (hook_ctx_, node))
+#define hook_inline(call, irg) hook_exec(hook_inline, (hook_ctx_, call, irg))
+#define hook_tail_rec(irg, n_calls) hook_exec(hook_tail_rec, (hook_ctx_, irg, n_calls))
#define hook_strength_red(irg, node) \
- hook_exec(hook_strength_red, (ctx, irg, node))
-#define hook_dead_node_elim(irg, start) hook_exec(hook_dead_node_elim, (ctx, irg, start))
+ hook_exec(hook_strength_red, (hook_ctx_, irg, node))
+#define hook_dead_node_elim(irg, start) hook_exec(hook_dead_node_elim, (hook_ctx_, irg, start))
#define hook_dead_node_elim_subst(irg, old, nw) \
- hook_exec(hook_dead_node_elim_subst, (ctx, irg, old, nw))
+ hook_exec(hook_dead_node_elim_subst, (hook_ctx_, irg, old, nw))
#define hook_if_conversion(irg, phi, pos, mux, reason) \
- hook_exec(hook_if_conversion, (ctx, irg, phi, pos, mux, reason))
+ hook_exec(hook_if_conversion, (hook_ctx_, irg, phi, pos, mux, reason))
#define hook_func_call(irg, call) \
- hook_exec(hook_func_call, (ctx, irg, call))
+ hook_exec(hook_func_call, (hook_ctx_, irg, call))
#define hook_arch_dep_replace_mul_with_shifts(irn) \
- hook_exec(hook_arch_dep_replace_mul_with_shifts, (ctx, irn))
+ hook_exec(hook_arch_dep_replace_mul_with_shifts, (hook_ctx_, irn))
#define hook_arch_dep_replace_division_by_const(irn) \
- hook_exec(hook_arch_dep_replace_division_by_const, (ctx, irn))
-#define hook_new_mode(tmpl, mode) hook_exec(hook_new_mode, (ctx, tmpl, mode))
-#define hook_new_entity(ent) hook_exec(hook_new_entity, (ctx, ent))
-#define hook_new_type(tp) hook_exec(hook_new_type, (ctx, tp))
-#define hook_node_info(F, node) hook_exec(hook_node_info, (ctx, F, node))
+ hook_exec(hook_arch_dep_replace_division_by_const, (hook_ctx_, irn))
+#define hook_new_mode(tmpl, mode) hook_exec(hook_new_mode, (hook_ctx_, tmpl, mode))
+#define hook_new_entity(ent) hook_exec(hook_new_entity, (hook_ctx_, ent))
+#define hook_new_type(tp) hook_exec(hook_new_type, (hook_ctx_, tp))
+#define hook_node_info(F, node) hook_exec(hook_node_info, (hook_ctx_, F, node))
#include "end.h"
/* ------------------------------------------------------------------- */
/** Returns non-zero if the predecessor pos is a backedge. */
-FIRM_API int is_backedge(ir_node *n, int pos);
+FIRM_API int is_backedge(const ir_node *n, int pos);
/** Marks edge pos as a backedge. */
FIRM_API void set_backedge(ir_node *n, int pos);
/** Marks edge pos as a non-backedge. */
FIRM_API void set_not_backedge(ir_node *n, int pos);
/** Returns non-zero if n has backedges. */
-FIRM_API int has_backedges(ir_node *n);
+FIRM_API int has_backedges(const ir_node *n);
/** Clears all backedge information. */
FIRM_API void clear_backedges(ir_node *n);
* They will either remain the same or be converted into if-cascades.
*
* @param irg The ir graph to be lowered.
+ * @param small_switch If switch has <= cases then change it to an if-cascade.
* @param spare_size Allowed spare size for table switches in machine words.
* (Default in edgfe: 128)
* @param allow_out_of_bounds backend can handle out-of-bounds values
* (values bigger than minimum and maximum proj
* number)
*/
-FIRM_API void lower_switch(ir_graph *irg, unsigned spare_size,
- int allow_out_of_bounds);
+FIRM_API void lower_switch(ir_graph *irg, unsigned small_switch,
+ unsigned spare_size, int allow_out_of_bounds);
/**
* Replaces SymConsts by a real constant if possible.
/**
* implementation of create_set_func which produces a Mux node with 0/1 input
*/
-ir_node *ir_create_mux_set(ir_node *cond, ir_mode *dest_mode);
+FIRM_API ir_node *ir_create_mux_set(ir_node *cond, ir_mode *dest_mode);
/**
* implementation of create_set_func which produces a cond with control
* flow
*/
-ir_node *ir_create_cond_set(ir_node *cond, ir_mode *dest_mode);
+FIRM_API ir_node *ir_create_cond_set(ir_node *cond, ir_mode *dest_mode);
typedef struct lower_mode_b_config_t {
/* mode that is used to transport 0/1 values */
}
} else if (is_Sel(ptr) && get_irp_callee_info_state() == irg_callee_info_consistent) {
/* is be a polymorphic call but callee information is available */
- int i, n_params = get_Call_n_params(succ);
+ int n_params = get_Call_n_params(succ);
+ int c;
/* simply look into ALL possible callees */
- for (i = get_Call_n_callees(succ) - 1; i >= 0; --i) {
- meth_ent = get_Call_callee(succ, i);
+ for (c = get_Call_n_callees(succ) - 1; c >= 0; --c) {
+ meth_ent = get_Call_callee(succ, c);
/* unknown_entity is used to signal that we don't know what is called */
if (meth_ent == unknown_entity) {
*/
static void free_mark(ir_node *node, eset * set)
{
- size_t i, n;
-
if (get_irn_link(node) == MARK)
return; /* already visited */
case iro_Sel: {
ir_entity *ent = get_Sel_entity(node);
if (is_method_entity(ent)) {
+ size_t i, n;
for (i = 0, n = get_Sel_n_methods(node); i < n; ++i) {
eset_insert(set, get_Sel_method(node, i));
}
static void free_ana_walker(ir_node *node, void *env)
{
eset *set = (eset*) env;
- int i;
if (get_irn_link(node) == MARK) {
/* already visited */
}
break;
}
- default:
+ default: {
+ int i;
/* other nodes: Alle anderen Knoten nehmen wir als Verr�ter an, bis
* jemand das Gegenteil implementiert. */
set_irn_link(node, MARK);
}
break;
}
+ }
}
/**
/* let's check if it's the address of a function */
if (is_Global(irn)) {
- ir_entity *ent = get_Global_entity(irn);
+ ir_entity *ent2 = get_Global_entity(irn);
- if (is_Method_type(get_entity_type(ent)))
- eset_insert(set, ent);
+ if (is_Method_type(get_entity_type(ent2)))
+ eset_insert(set, ent2);
}
}
}
}
for (i = 0; i < n; ++i) {
- dfs_node_t *node = nodes[i];
+ node = nodes[i];
ir_fprintf(file, "\tn%d [label=\"%d\"]\n", node->pre_num, get_Block_dom_tree_pre_num((ir_node*) node->node));
#if 0
ir_fprintf(file, "\tn%d [shape=box,label=\"%+F\\l%d %d/%d %d\"];\n",
for (idx = dfs_get_n_nodes(dfs) - 1; idx >= 0; --idx) {
ir_node *bb = (ir_node *) dfs_get_post_num_node(dfs, size - idx - 1);
- freq_t *freq;
int i;
freq = set_insert_freq(freqs, bb);
ef->max = 0.0;
set_foreach(freqs, freq_t*, freq) {
- int idx = freq->idx;
+ idx = freq->idx;
/* take abs because it sometimes can be -0 in case of endless loops */
freq->freq = fabs(x[idx]) * norm;
* Does not assert whether the backarray is correct -- use
* very careful!
*/
-static bitset_t *mere_get_backarray(ir_node *n)
+static bitset_t *mere_get_backarray(const ir_node *n)
{
switch (get_irn_opcode(n)) {
case iro_Block:
* Returns backarray if the node can have backedges, else returns
* NULL.
*/
-static bitset_t *get_backarray(ir_node *n)
+static bitset_t *get_backarray(const ir_node *n)
{
bitset_t *ba = mere_get_backarray(n);
* Returns non-zero if node has no backarray, or
* if size of backarray == size of in array.
*/
-static int legal_backarray(ir_node *n)
+static int legal_backarray(const ir_node *n)
{
bitset_t *ba = mere_get_backarray(n);
if (ba && (bitset_size(ba) != (unsigned) get_irn_arity(n)))
}
/* Returns non-zero if the predecessor pos is a backedge. */
-int is_backedge(ir_node *n, int pos)
+int is_backedge(const ir_node *n, int pos)
{
bitset_t *ba = get_backarray(n);
if (ba)
}
/* Returns non-zero if n has backedges. */
-int has_backedges(ir_node *n)
+int has_backedges(const ir_node *n)
{
bitset_t *ba = get_backarray(n);
if (ba != NULL) {
* left == Const and we found a movable user of left in a
* dominator of the Cond block
*/
- const ir_edge_t *edge, *next;
- for (edge = get_irn_out_edge_first(user); edge; edge = next) {
- ir_node *usr_of_usr = get_edge_src_irn(edge);
- int npos = get_edge_src_pos(edge);
- ir_node *blk = get_effective_use_block(usr_of_usr, npos);
-
- next = get_irn_out_edge_next(user, edge);
- if (block_dominates(block, blk)) {
+ const ir_edge_t *user_edge;
+ const ir_edge_t *user_next;
+ foreach_out_edge_safe(user, user_edge, user_next) {
+ ir_node *usr_of_usr = get_edge_src_irn(user_edge);
+ int npos = get_edge_src_pos(user_edge);
+ ir_node *user_blk = get_effective_use_block(usr_of_usr, npos);
+
+ if (block_dominates(block, user_blk)) {
/*
* The user of the user is dominated by our true/false
* block. So, create a copy of user WITH the constant
class1 = get_base_sc(mod1);
class2 = get_base_sc(mod2);
+ /* struct-access cannot alias with variables */
+ if (ent1 == NULL && ent2 != NULL && is_compound_type(get_entity_owner(ent2))
+ && (class1 == ir_sc_globalvar || class1 == ir_sc_localvar || class1 == ir_sc_tls || class1 == ir_sc_globaladdr)) {
+ return ir_no_alias;
+ }
+ if (ent2 == NULL && ent1 != NULL && is_compound_type(get_entity_owner(ent1))
+ && (class2 == ir_sc_globalvar || class2 == ir_sc_localvar || class2 == ir_sc_tls || class2 == ir_sc_globaladdr)) {
+ return ir_no_alias;
+ }
+
if (class1 == ir_sc_pointer || class2 == ir_sc_pointer) {
/* swap pointer class to class1 */
if (class2 == ir_sc_pointer) {
res |= determine_entity_usage(succ, entity);
break;
case iro_Sel: {
- ir_entity *entity = get_Sel_entity(succ);
+ ir_entity *sel_entity = get_Sel_entity(succ);
/* this analysis can't handle unions correctly */
- if (is_Union_type(get_entity_owner(entity))) {
+ if (is_Union_type(get_entity_owner(sel_entity))) {
res |= ir_usage_unknown;
break;
}
/* Check the successor of irn. */
- res |= determine_entity_usage(succ, entity);
+ res |= determine_entity_usage(succ, sel_entity);
break;
}
/* let's check if it's an address */
if (is_Global(irn)) {
- ir_entity *ent = get_Global_entity(irn);
- set_entity_usage(ent, ir_usage_unknown);
+ ir_entity *symconst_ent = get_Global_entity(irn);
+ set_entity_usage(symconst_ent, ir_usage_unknown);
}
}
}
reg->succ[0] = exit;
DEBUG_ONLY({
- size_t i;
DB((dbg, LEVEL_2, " Created %s(%u)\n", reg->type == ir_rk_Switch ? "Switch" : "Case", reg->nr));
for (i = 1; i < ARR_LEN(reg->parts); ++i) {
DB((dbg, LEVEL_2, " Case(%lu)\n", reg->parts[i].region->nr));
/* check for Switch, case */
if (k > 0) {
ir_region *rexit = NULL;
- size_t i, p = 0;
+ size_t i, pos = 0;
nset = NULL; nset_len = 0;
for (i = k; i > 0;) {
n = get_region_succ(node, i--);
if (get_region_n_succs(n) != 1) {
/* must be the exit */
rexit = n;
- ++p;
- if (p > 1)
+ ++pos;
+ if (pos > 1)
break;
}
}
- if (p <= 1) {
+ if (pos <= 1) {
ir_region_kind kind = ir_rk_Case;
ir_region *pos_exit_1 = NULL;
ir_region *pos_exit_2 = NULL;
#
# register types:
# 0 - no special type
-# 1 - caller save (register must be saved by the caller of a function)
-# 2 - callee save (register must be saved by the called function)
-# 4 - ignore (do not assign this register)
+# 1 - ignore (do not assign this register)
+# 2 - emitter can choose an arbitrary register of this class
+# 4 - the register is a virtual one
+# 8 - register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
- { name => "r0", type => 1 },
- { name => "r1", type => 1 },
- { name => "r2", type => 1 },
- { name => "r3", type => 1 },
- { name => "r4", type => 1 },
- { name => "r5", type => 1 },
- { name => "r6", type => 1 },
- { name => "r7", type => 2 },
- { name => "r8", type => 2 },
- { name => "r9", type => 2 },
- { name => "r10", type => 2 },
- { name => "r11", type => 2 },
- { name => "r12", type => 2 },
- { name => "r13", type => 2 },
- { name => "sp", realname => "r14", type => 4 }, # stackpointer
- { name => "bp", realname => "r15", type => 4 }, # basepointer
+ { name => "r0" },
+ { name => "r1" },
+ { name => "r2" },
+ { name => "r3" },
+ { name => "r4" },
+ { name => "r5" },
+ { name => "r6" },
+ { name => "r7" },
+ { name => "r8" },
+ { name => "r9" },
+ { name => "r10" },
+ { name => "r11" },
+ { name => "r12" },
+ { name => "r13" },
+ { name => "sp", realname => "r14", type => 1 }, # stackpointer
+ { name => "bp", realname => "r15", type => 1 }, # basepointer
{ mode => $mode_gp }
],
fp => [
- { name => "f0", type => 1 },
- { name => "f1", type => 1 },
- { name => "f2", type => 1 },
- { name => "f3", type => 1 },
- { name => "f4", type => 1 },
- { name => "f5", type => 1 },
- { name => "f6", type => 1 },
- { name => "f7", type => 1 },
- { name => "f8", type => 1 },
- { name => "f9", type => 1 },
- { name => "f10", type => 1 },
- { name => "f11", type => 1 },
- { name => "f12", type => 1 },
- { name => "f13", type => 1 },
- { name => "f14", type => 1 },
- { name => "f15", type => 1 },
+ { name => "f0" },
+ { name => "f1" },
+ { name => "f2" },
+ { name => "f3" },
+ { name => "f4" },
+ { name => "f5" },
+ { name => "f6" },
+ { name => "f7" },
+ { name => "f8" },
+ { name => "f9" },
+ { name => "f10" },
+ { name => "f11" },
+ { name => "f12" },
+ { name => "f13" },
+ { name => "f14" },
+ { name => "f15" },
{ mode => $mode_fp }
]
);
0, /* 0: little-endian, 1: big-endian */
NULL, /* architecture dependent settings, will be set later */
TEMPLATE_is_mux_allowed, /* parameter for if conversion */
+ 32, /* machine size - a 32bit CPU */
NULL, /* float arithmetic mode */
+ 0, /* size of long double */
0, /* no trampoline support: size 0 */
0, /* no trampoline support: align 0 */
NULL, /* no trampoline support: no trampoline builder */
return 0;
}
+/**
+ * Check if the given register is callee or caller save.
+ */
+static int TEMPLATE_register_saved_by(const arch_register_t *reg, int callee)
+{
+ if (callee) {
+ /* check for callee saved */
+ if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
+ switch (reg->index) {
+ case REG_GP_R7:
+ case REG_GP_R8:
+ case REG_GP_R9:
+ case REG_GP_R10:
+ case REG_GP_R11:
+ case REG_GP_R12:
+ case REG_GP_R13:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+ } else {
+ /* check for caller saved */
+ if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_gp]) {
+ switch (reg->index) {
+ case REG_GP_R0:
+ case REG_GP_R1:
+ case REG_GP_R2:
+ case REG_GP_R3:
+ case REG_GP_R4:
+ case REG_GP_R5:
+ case REG_GP_R6:
+ return 1;
+ default:
+ return 0;
+ }
+ } else if (reg->reg_class == &TEMPLATE_reg_classes[CLASS_TEMPLATE_fp]) {
+ /* all FP registers are caller save */
+ return 1;
+ }
+ }
+ return 0;
+}
+
const arch_isa_if_t TEMPLATE_isa_if = {
TEMPLATE_init,
TEMPLATE_lower_for_target,
TEMPLATE_after_ra,
TEMPLATE_finish_irg,
TEMPLATE_emit_routine,
+ TEMPLATE_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_TEMPLATE)
#
# register types:
$normal = 0; # no special type
-$caller_save = 1; # caller save (register must be saved by the caller of a function)
-$callee_save = 2; # callee save (register must be saved by the called function)
-$ignore = 4; # ignore (do not assign this register)
-$arbitrary = 8; # emitter can choose an arbitrary register of this class
-$virtual = 16; # the register is a virtual one
-$state = 32; # register represents a state
+$ignore = 1; # ignore (do not assign this register)
+$arbitrary = 2; # emitter can choose an arbitrary register of this class
+$virtual = 4; # the register is a virtual one
+$state = 8; # register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
- { name => "rax", type => $caller_save },
- { name => "rcx", type => $caller_save },
- { name => "rdx", type => $caller_save },
- { name => "rsi", type => $caller_save },
- { name => "rdi", type => $caller_save },
- { name => "rbx", type => $callee_save },
- { name => "rbp", type => $callee_save },
- { name => "rsp", type => 4 }, # stackpointer?
- { name => "r8", type => $caller_save },
- { name => "r9", type => $caller_save },
- { name => "r10", type => $caller_save },
- { name => "r11", type => $caller_save },
- { name => "r12", type => $callee_save },
- { name => "r13", type => $callee_save },
- { name => "r14", type => $callee_save },
- { name => "r15", type => $callee_save },
+ { name => "rax" },
+ { name => "rcx" },
+ { name => "rdx" },
+ { name => "rsi" },
+ { name => "rdi" },
+ { name => "rbx" },
+ { name => "rbp" },
+ { name => "rsp", type => $ignore }, # stackpointer?
+ { name => "r8" },
+ { name => "r9" },
+ { name => "r10" },
+ { name => "r11" },
+ { name => "r12" },
+ { name => "r13" },
+ { name => "r14" },
+ { name => "r15" },
# { name => "gp_NOREG", type => $ignore }, # we need a dummy register for NoReg nodes
{ mode => "mode_Lu" }
],
# fp => [
-# { name => "xmm0", type => $caller_save },
-# { name => "xmm1", type => $caller_save },
-# { name => "xmm2", type => $caller_save },
-# { name => "xmm3", type => $caller_save },
-# { name => "xmm4", type => $caller_save },
-# { name => "xmm5", type => $caller_save },
-# { name => "xmm6", type => $caller_save },
-# { name => "xmm7", type => $caller_save },
-# { name => "xmm8", type => $caller_save },
-# { name => "xmm9", type => $caller_save },
-# { name => "xmm10", type => $caller_save },
-# { name => "xmm11", type => $caller_save },
-# { name => "xmm12", type => $caller_save },
-# { name => "xmm13", type => $caller_save },
-# { name => "xmm14", type => $caller_save },
-# { name => "xmm15", type => $caller_save },
+# { name => "xmm0" },
+# { name => "xmm1" },
+# { name => "xmm2" },
+# { name => "xmm3" },
+# { name => "xmm4" },
+# { name => "xmm5" },
+# { name => "xmm6" },
+# { name => "xmm7" },
+# { name => "xmm8" },
+# { name => "xmm9" },
+# { name => "xmm10" },
+# { name => "xmm11" },
+# { name => "xmm12" },
+# { name => "xmm13" },
+# { name => "xmm14" },
+# { name => "xmm15" },
# { mode => "mode_D" }
# ]
flags => [
- { name => "eflags", type => 0 },
+ { name => "eflags" },
{ mode => "mode_Iu", flags => "manual_ra" }
],
);
/* FIXME: No floating point yet */
/* be_abi_call_res_reg(abi, 0,
- mode_is_float(mode) ? &amd64_fp_regs[REG_F0] : &amd64_registers[REG_R0], ABI_CONTEXT_BOTH) */;
+ mode_is_float(mode) ? &amd64_fp_regs[REG_F0] : &amd64_registers[REG_R0], ABI_CONTEXT_BOTH); */
be_abi_call_res_reg(abi, 0,
&amd64_registers[REG_RAX], ABI_CONTEXT_BOTH);
0, /* little endian */
NULL, /* will be set later */
amd64_is_mux_allowed, /* parameter for if conversion */
+ 64, /* machine size */
NULL, /* float arithmetic mode */
+ 0, /* size of long double */
0, /* no trampoline support: size 0 */
0, /* no trampoline support: align 0 */
NULL, /* no trampoline support: no trampoline builder */
return 0;
}
+static int amd64_register_saved_by(const arch_register_t *reg, int callee)
+{
+ if (callee) {
+ /* check for callee saved */
+ if (reg->reg_class == &amd64_reg_classes[CLASS_amd64_gp]) {
+ switch (reg->index) {
+ case REG_GP_RBX:
+ case REG_GP_RBP:
+ case REG_GP_R12:
+ case REG_GP_R13:
+ case REG_GP_R14:
+ case REG_GP_R15:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+ } else {
+ /* check for caller saved */
+ if (reg->reg_class == &amd64_reg_classes[CLASS_amd64_gp]) {
+ switch (reg->index) {
+ case REG_GP_RAX:
+ case REG_GP_RCX:
+ case REG_GP_RDX:
+ case REG_GP_RSI:
+ case REG_GP_RDI:
+ case REG_GP_R8:
+ case REG_GP_R9:
+ case REG_GP_R10:
+ case REG_GP_R11:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
const arch_isa_if_t amd64_isa_if = {
amd64_init,
amd64_lower_for_target,
amd64_after_ra,
amd64_finish_irg,
amd64_gen_routine,
+ amd64_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_amd64)
REG_FL,
};
-/* determine how function parameters and return values are passed. */
+static const arch_register_t* const param_regs[] = {
+ &arm_registers[REG_R0],
+ &arm_registers[REG_R1],
+ &arm_registers[REG_R2],
+ &arm_registers[REG_R3]
+};
+
+static const arch_register_t* const result_regs[] = {
+ &arm_registers[REG_R0],
+ &arm_registers[REG_R1],
+ &arm_registers[REG_R2],
+ &arm_registers[REG_R3]
+};
+
+static const arch_register_t* const float_result_regs[] = {
+ &arm_registers[REG_F0],
+ &arm_registers[REG_F1]
+};
+
calling_convention_t *arm_decide_calling_convention(const ir_graph *irg,
ir_type *function_type)
{
- int stack_offset = 0;
+ unsigned stack_offset = 0;
+ unsigned n_param_regs_used = 0;
reg_or_stackslot_t *params;
reg_or_stackslot_t *results;
int n_param_regs
const arch_register_t *reg = param_regs[regnum++];
param->reg1 = reg;
} else {
- ir_mode *mode = param_regs[0]->reg_class->mode;
- ir_type *type = get_type_for_mode(mode);
- param->type = type;
- param->offset = stack_offset;
- assert(get_mode_size_bits(mode) == 32);
+ ir_mode *pmode = param_regs[0]->reg_class->mode;
+ ir_type *type = get_type_for_mode(pmode);
+ param->type = type;
+ param->offset = stack_offset;
+ assert(get_mode_size_bits(pmode) == 32);
stack_offset += 4;
}
}
}
+ n_param_regs_used = regnum;
n_results = get_method_n_ress(function_type);
regnum = 0;
cconv = XMALLOCZ(calling_convention_t);
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
+ cconv->n_reg_params = n_param_regs_used;
cconv->results = results;
/* setup allocatable registers */
#include "../be_types.h"
#include "gen_arm_regalloc_if.h"
-static const arch_register_t *const callee_saves[] = {
- &arm_registers[REG_R4],
- &arm_registers[REG_R5],
- &arm_registers[REG_R6],
- &arm_registers[REG_R7],
- &arm_registers[REG_R8],
- &arm_registers[REG_R9],
- &arm_registers[REG_R10],
- &arm_registers[REG_R11],
- &arm_registers[REG_LR],
-};
-
-static const arch_register_t *const caller_saves[] = {
- &arm_registers[REG_R0],
- &arm_registers[REG_R1],
- &arm_registers[REG_R2],
- &arm_registers[REG_R3],
- &arm_registers[REG_LR],
-
- &arm_registers[REG_F0],
- &arm_registers[REG_F1],
- &arm_registers[REG_F2],
- &arm_registers[REG_F3],
- &arm_registers[REG_F4],
- &arm_registers[REG_F5],
- &arm_registers[REG_F6],
- &arm_registers[REG_F7],
-};
-
-static const arch_register_t* const param_regs[] = {
- &arm_registers[REG_R0],
- &arm_registers[REG_R1],
- &arm_registers[REG_R2],
- &arm_registers[REG_R3]
-};
-
-static const arch_register_t* const result_regs[] = {
- &arm_registers[REG_R0],
- &arm_registers[REG_R1],
- &arm_registers[REG_R2],
- &arm_registers[REG_R3]
-};
-
-static const arch_register_t* const float_result_regs[] = {
- &arm_registers[REG_F0],
- &arm_registers[REG_F1]
-};
-
/** information about a single parameter or result */
typedef struct reg_or_stackslot_t
{
const arch_register_t *reg1; /**< if != NULL, the second register used. */
ir_type *type; /**< indicates that an entity of the specific
type is needed */
- int offset; /**< if transmitted via stack, the offset for this parameter. */
+ unsigned offset; /**< if transmitted via stack, the offset for this parameter. */
ir_entity *entity; /**< entity in frame type */
} reg_or_stackslot_t;
typedef struct calling_convention_t
{
reg_or_stackslot_t *parameters; /**< parameter info. */
- int param_stack_size; /**< needed stack size for parameters */
+ unsigned param_stack_size; /**< needed stack size for parameters */
+ unsigned n_reg_params;
reg_or_stackslot_t *results; /**< result info. */
} calling_convention_t;
be_emit_write_line();
} else {
ir_tarval *tv = entry->u.tv;
- int i, size = get_mode_size_bytes(get_tarval_mode(tv));
- unsigned v;
+ int vi;
+ int size = get_mode_size_bytes(get_tarval_mode(tv));
/* beware: ARM fpa uses big endian format */
- for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
+ for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
/* get 32 bits */
- v = get_tarval_sub_bits(tv, i+3);
- v = (v << 8) | get_tarval_sub_bits(tv, i+2);
- v = (v << 8) | get_tarval_sub_bits(tv, i+1);
- v = (v << 8) | get_tarval_sub_bits(tv, i+0);
+ unsigned v;
+ v = get_tarval_sub_bits(tv, vi+3);
+ v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
+ v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
+ v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
be_emit_irprintf("\t.word\t%u\n", v);
be_emit_write_line();
}
first = node;
block = get_nodes_block(node);
for (cnt = 1; cnt < v.ops; ++cnt) {
- int value = sign * arm_ror(v.values[cnt], v.rors[cnt]);
- ir_node *next = be_new_IncSP(&arm_registers[REG_SP], block, node,
+ int value = sign * arm_ror(v.values[cnt], v.rors[cnt]);
+ ir_node *incsp = be_new_IncSP(&arm_registers[REG_SP], block, node,
value, 1);
- sched_add_after(node, next);
- node = next;
+ sched_add_after(node, incsp);
+ node = incsp;
}
/* reattach IncSP users */
static pmap *node_to_stack;
+static const arch_register_t *const callee_saves[] = {
+ &arm_registers[REG_R4],
+ &arm_registers[REG_R5],
+ &arm_registers[REG_R6],
+ &arm_registers[REG_R7],
+ &arm_registers[REG_R8],
+ &arm_registers[REG_R9],
+ &arm_registers[REG_R10],
+ &arm_registers[REG_R11],
+ &arm_registers[REG_LR],
+};
+
+static const arch_register_t *const caller_saves[] = {
+ &arm_registers[REG_R0],
+ &arm_registers[REG_R1],
+ &arm_registers[REG_R2],
+ &arm_registers[REG_R3],
+ &arm_registers[REG_LR],
+
+ &arm_registers[REG_F0],
+ &arm_registers[REG_F1],
+ &arm_registers[REG_F2],
+ &arm_registers[REG_F3],
+ &arm_registers[REG_F4],
+ &arm_registers[REG_F5],
+ &arm_registers[REG_F6],
+ &arm_registers[REG_F7],
+};
+
static bool mode_needs_gp_reg(ir_mode *mode)
{
return mode_is_int(mode) || mode_is_reference(mode);
}
if (try_encode_as_immediate(op2, &imm)) {
- ir_node *new_op1 = be_transform_node(op1);
+ new_op1 = be_transform_node(op1);
return factory->new_binop_imm(dbgi, block, new_op1, imm.imm_8, imm.rot);
}
new_op2 = be_transform_node(op2);
/* just produce a 0 */
ir_mode *mode = get_irn_mode(node);
if (mode_is_float(mode)) {
- ir_tarval *tv = get_mode_null(mode);
- ir_node *node = new_bd_arm_fConst(dbgi, new_block, tv);
- return node;
+ ir_tarval *tv = get_mode_null(mode);
+ ir_node *fconst = new_bd_arm_fConst(dbgi, new_block, tv);
+ return fconst;
} else if (mode_needs_gp_reg(mode)) {
return create_const_graph_value(dbgi, new_block, 0);
}
ir_type *type = get_Call_type(node);
calling_convention_t *cconv = arm_decide_calling_convention(NULL, type);
size_t n_params = get_Call_n_params(node);
- size_t n_param_regs = sizeof(param_regs)/sizeof(param_regs[0]);
+ size_t n_param_regs = cconv->n_reg_params;
/* max inputs: memory, callee, register arguments */
int max_inputs = 2 + n_param_regs;
ir_node **in = ALLOCAN(ir_node*, max_inputs);
const arm_attr_t *attr = get_arm_attr_const(irn);
if (is_arm_FrameAddr(irn)) {
- const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
- return attr->entity;
+ const arm_SymConst_attr_t *frame_attr = get_arm_SymConst_attr_const(irn);
+ return frame_attr->entity;
}
if (attr->is_load_store) {
const arm_load_store_attr_t *load_store_attr
for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i);
- lower_switch(irg, 256, true);
+ lower_switch(irg, 4, 256, true);
}
}
1, /* big endian */
&ad, /* will be set later */
arm_is_mux_allowed, /* allow_ifconv function */
+ 32, /* machine size */
NULL, /* float arithmetic mode (TODO) */
+ 0, /* size of long double */
0, /* no trampoline support: size 0 */
0, /* no trampoline support: align 0 */
NULL, /* no trampoline support: no trampoline builder */
arm_after_ra,
arm_finish_irg,
arm_gen_routine,
+ NULL, /* register_saved_by */
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_arm)
* checking */
continue;
}
- if (destroy_all_regs || (reg->type & arch_register_type_caller_save)) {
+ if (destroy_all_regs || arch_register_is_caller_save(arch_env, reg)) {
if (!(reg->type & arch_register_type_ignore)) {
ARR_APP1(const arch_register_t*, destroyed_regs, reg);
}
/* Add uses of the callee save registers. */
foreach_pmap(env->regs, ent) {
const arch_register_t *reg = (const arch_register_t*)ent->key;
- if (reg->type & (arch_register_type_callee_save | arch_register_type_ignore))
+ if ((reg->type & arch_register_type_ignore) || arch_register_is_callee_save(arch_env, reg))
pmap_insert(reg_map, ent->key, ent->value);
}
const arch_register_class_t *cls = &arch_env->register_classes[i];
for (j = 0; j < cls->n_regs; ++j) {
const arch_register_t *reg = &cls->regs[j];
- if (reg->type & (arch_register_type_callee_save | arch_register_type_state)) {
+ if ((reg->type & arch_register_type_state) || arch_register_is_callee_save(arch_env, reg)) {
pmap_insert(env->regs, (void *) reg, NULL);
}
}
typedef enum arch_register_type_t {
arch_register_type_none = 0,
- /** The register must be saved by the caller upon a function call. It thus
- * can be overwritten in the called function. */
- arch_register_type_caller_save = 1U << 0,
- /** The register must be saved by the caller upon a function call. It thus
- * can be overwritten in the called function. */
- arch_register_type_callee_save = 1U << 1,
/** Do not consider this register when allocating. */
- arch_register_type_ignore = 1U << 2,
+ arch_register_type_ignore = 1U << 0,
/** The emitter can choose an arbitrary register. The register fulfills any
* register constraints as long as the register class matches */
- arch_register_type_joker = 1U << 3,
+ arch_register_type_joker = 1U << 1,
/** This is just a virtual register. Virtual registers fulfill any register
* constraints as long as the register class matches. It is a allowed to
* have multiple definitions for the same virtual register at a point */
- arch_register_type_virtual = 1U << 4,
+ arch_register_type_virtual = 1U << 2,
/** The register represents a state that should be handled by bestate
* code */
- arch_register_type_state = 1U << 5,
+ arch_register_type_state = 1U << 3,
} arch_register_type_t;
ENUM_BITSET(arch_register_type_t)
* The code generator must also be de-allocated here.
*/
void (*emit)(ir_graph *irg);
+
+ /**
+ * Checks if the given register is callee/caller saved.
+ */
+ int (*register_saved_by)(const arch_register_t *reg, int callee);
};
#define arch_env_done(env) ((env)->impl->done(env))
return info->in_reqs;
}
+/**
+ * Check if the given register is callee save, ie. will be save by the callee.
+ */
+static inline bool arch_register_is_callee_save(
+ const arch_env_t *arch_env,
+ const arch_register_t *reg)
+{
+ if (arch_env->impl->register_saved_by)
+ return arch_env->impl->register_saved_by(reg, /*callee=*/1);
+ return false;
+}
+
+/**
+ * Check if the given register is caller save, ie. must be save by the caller.
+ */
+static inline bool arch_register_is_caller_save(
+ const arch_env_t *arch_env,
+ const arch_register_t *reg)
+{
+ if (arch_env->impl->register_saved_by)
+ return arch_env->impl->register_saved_by(reg, /*callee=*/0);
+ return false;
+}
+
/**
* Iterate over all values defined by an instruction.
* Only looks at values in a certain register class where the requirements
#include "lc_opts.h"
#include "lc_opts_enum.h"
-#ifdef WITH_ILP
-#include <lpp/lpp.h>
-#include <lpp/lpp_net.h>
-#endif /* WITH_ILP */
+#include "lpp.h"
+#include "lpp_net.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
static const lc_opt_enum_int_items_t blockschedalgo_items[] = {
{ "naiv", BLOCKSCHED_NAIV },
{ "greedy", BLOCKSCHED_GREEDY },
-#ifdef WITH_ILP
{ "ilp", BLOCKSCHED_ILP },
-#endif /* WITH_ILP */
{ NULL, 0 }
};
break;
}
succ_entry = succ_entry->prev;
- };
+ }
if (irn_visited(succ_entry->block))
continue;
*
*/
-#ifdef WITH_ILP
typedef struct ilp_edge_t {
ir_node *block; /**< source block */
int pos; /**< number of cfg predecessor (target) */
return block_list;
}
-#endif /* WITH_ILP */
/*
* __ __ _
case BLOCKSCHED_GREEDY:
case BLOCKSCHED_NAIV:
return create_block_schedule_greedy(irg, execfreqs);
-#ifdef WITH_ILP
case BLOCKSCHED_ILP:
return create_block_schedule_ilp(irg, execfreqs);
-#endif /* WITH_ILP */
}
panic("unknown blocksched algo");
fclose(self->f);
}
-const plotter_if_t ps_plotter_vtab = {
+static const plotter_if_t ps_plotter_vtab = {
ps_begin,
ps_setcolor,
get_color,
{ NULL, 0 }
};
-static const lc_opt_enum_int_items_t lower_perm_stat_items[] = {
- { NULL, 0 }
-};
-
static const lc_opt_enum_int_items_t dump_items[] = {
{ "none", BE_CH_DUMP_NONE },
{ "spill", BE_CH_DUMP_SPILL },
be_assure_liveness(irg);
be_liveness_assure_chk(be_get_irg_liveness(irg));
- stat_ev_do(pse->pre_spill_cost = be_estimate_irg_costs(irg, exec_freq));
+ if (stat_ev_enabled) {
+ pse->pre_spill_cost = be_estimate_irg_costs(irg, exec_freq);
+ }
/* put all ignore registers into the ignore register set. */
be_put_allocatable_regs(irg, pse->cls, chordal_env->allocatable_regs);
chordal_env->ifg = be_create_ifg(chordal_env);
be_timer_pop(T_RA_IFG);
- stat_ev_if {
+ if (stat_ev_enabled) {
be_ifg_stat_t stat;
be_node_stats_t node_stats;
be_timer_pop(T_RA_PROLOG);
- stat_ev_if {
+ if (stat_ev_enabled) {
be_collect_node_stats(&last_node_stats, irg);
}
stat_ev_ctx_push_str("bechordal_cls", cls->name);
- stat_ev_if {
+ if (stat_ev_enabled) {
be_do_stat_reg_pressure(irg, cls);
}
post_spill(&pse, 0);
- stat_ev_if {
+ if (stat_ev_enabled) {
be_node_stats_t node_stats;
be_collect_node_stats(&node_stats, irg);
#include "bemodule.h"
#include "error.h"
+#include "lpp.h"
+
#include "lc_opts.h"
#include "lc_opts_enum.h"
-#ifdef WITH_ILP
-
#define DUMP_ILP 1
#define DUMP_SOL 2
LC_OPT_LAST
};
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copyilp);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copyilp)
void be_init_copyilp(void)
{
lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be");
if (solve_log)
lpp_set_log(ienv->lp, stdout);
- lpp_solve_net(ienv->lp, options->ilp_server, options->ilp_solver);
+ lpp_solve(ienv->lp, options->ilp_server, options->ilp_solver);
//be_stat_ev_dbl("co_ilp_objval", ienv->lp->objval);
//be_stat_ev_dbl("co_ilp_best_bound", ienv->lp->best_bound);
free_lpp(ienv->lp);
free(ienv);
}
-
-#else /* WITH_ILP */
-
-static inline void only_that_you_can_compile_without_WITH_ILP_defined(void)
-{
-}
-
-#endif /* WITH_ILP */
*/
#include "config.h"
-#ifdef WITH_ILP
-
#include "bitset.h"
#include "raw_bitset.h"
#include "pdeq.h"
cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_equal, 1.0);
bitset_foreach(colors, col) {
- int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, col), lpp_binary, 0.0);
+ int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, (int)col), lpp_binary, 0.0);
lpp_set_start_value(ienv->lp, var_idx, (col == (unsigned) curr_node_color) ? 1.0 : 0.0);
lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1);
/* add register constraint constraints */
bitset_foreach_clear(colors, col) {
int cst_idx = lpp_add_cst(ienv->lp, NULL, lpp_equal, 0.0);
- int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, col), lpp_binary, 0.0);
+ int var_idx = lpp_add_var(ienv->lp, name_cdd(buf, 'x', node_nr, (int)col), lpp_binary, 0.0);
lpp_set_start_value(ienv->lp, var_idx, 0.0);
lpp_set_factor_fast(ienv->lp, cst_idx, var_idx, 1);
int growed;
/* get 2 starting nodes to form a clique */
- for (e=set_first(edges); !e->n1; e=set_next(edges))
- /*nothing*/ ;
+ for (e=set_first(edges); !e->n1; e=set_next(edges)) {
+ }
/* we could be stepped out of the loop before the set iterated to the end */
set_break(edges);
lpp_sol_state_t state = lpp_get_solution(ienv->lp, sol, lenv->first_x_var, lenv->last_x_var);
if (state != lpp_optimal) {
- printf("WARNING %s: Solution state is not 'optimal': %d\n", ienv->co->name, state);
+ printf("WARNING %s: Solution state is not 'optimal': %d\n", ienv->co->name, (int)state);
assert(state >= lpp_feasible && "The solution should at least be feasible!");
}
#endif
}
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copyilp2);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copyilp2)
void be_init_copyilp2(void)
{
static co_algo_info copyheur = {
return sol_state == lpp_optimal;
}
-
-#else /* WITH_ILP */
-
-static inline void only_that_you_can_compile_without_WITH_ILP_defined(void)
-{
-}
-
-#endif /* WITH_ILP */
*****************************************************************************/
-#ifdef WITH_ILP
-#include <lpp/lpp.h>
-#include <lpp/lpp_net.h>
+#include "lpp.h"
+#include "lpp_net.h"
#define EPSILON 0.00001
name_cdd(buf, char1, MIN(int1, int2), MAX(int1, int2))
#endif
-
-#endif
/**
* Holds current values. Values are added till next copystat_reset
*/
-int curr_vals[ASIZE];
+static int curr_vals[ASIZE];
static ir_nodeset_t *all_phi_nodes;
static ir_nodeset_t *all_copy_nodes;
curr_vals[I_HEUR_TIME] += time;
}
-#ifdef WITH_ILP
-
void copystat_add_ilp_5_sec_costs(int costs)
{
curr_vals[I_COPIES_5SEC] += costs;
curr_vals[I_ILP_ITER] += iters;
}
-#endif /* WITH_ILP */
-
/**
* Opens a file named base.ext with the mode mode.
*/
void copystat_dump(ir_graph *irg);
void copystat_dump_pretty(ir_graph *irg);
-#ifdef WITH_ILP
-
void copystat_add_ilp_5_sec_costs(int costs);
void copystat_add_ilp_30_sec_costs(int costs);
void copystat_add_ilp_time(int time);
void copystat_add_ilp_csts(int csts);
void copystat_add_ilp_iter(int iters);
-#endif /* WITH_ILP */
-
#endif
size_t i2;
fputs("\t.byte ", file);
for (i2 = i; i2 < i + 30 && i2 < len; ++i2) {
- fprintf(file, "0x%02X", buffer[i2]);
+ fprintf(file, "0x%02X", (unsigned)buffer[i2]);
}
i = i2;
fputs("\n", file);
be_emit_write_line();
}
}
+
+void emit_jump_table(const ir_node *node, long default_pn, ir_entity *entity,
+ get_cfop_target_func get_cfop_target)
+{
+ long switch_max = LONG_MIN;
+ ir_node *default_block = NULL;
+ unsigned long length;
+ const ir_edge_t *edge;
+ unsigned i;
+ ir_node **table;
+
+ /* go over all proj's and collect them */
+ foreach_out_edge(node, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ long pn = get_Proj_proj(proj);
+
+ /* check for default proj */
+ if (pn == default_pn) {
+ assert(default_block == NULL); /* more than 1 default_pn? */
+ default_block = get_cfop_target(proj);
+ } else {
+ switch_max = pn > switch_max ? pn : switch_max;
+ }
+ }
+ assert(switch_max > LONG_MIN);
+
+ length = (unsigned long) switch_max + 1;
+ /* the 16000 isn't a real limit of the architecture. But should protect us
+ * from seamingly endless compiler runs */
+ if (length > 16000) {
+ /* switch lowerer should have broken this monster to pieces... */
+ panic("too large switch encountered");
+ }
+
+ table = XMALLOCNZ(ir_node*, length);
+ foreach_out_edge(node, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+ long pn = get_Proj_proj(proj);
+ if (pn == default_pn)
+ continue;
+
+ table[pn] = get_cfop_target(proj);
+ }
+
+ /* emit table */
+ be_gas_emit_switch_section(GAS_SECTION_RODATA);
+ be_emit_cstring("\t.align 4\n");
+ be_gas_emit_entity(entity);
+ be_emit_cstring(":\n");
+ for (i = 0; i < length; ++i) {
+ ir_node *block = table[i];
+ if (block == NULL)
+ block = default_block;
+ be_emit_cstring("\t.long ");
+ be_gas_emit_block_name(block);
+ be_emit_char('\n');
+ be_emit_write_line();
+ }
+ be_gas_emit_switch_section(GAS_SECTION_TEXT);
+
+ xfree(table);
+}
*/
const char *be_gas_insn_label_prefix(void);
+typedef ir_node* (*get_cfop_target_func)(const ir_node *cfop);
+
+/**
+ * Emits a jump table for switch operations
+ */
+void emit_jump_table(const ir_node *node, long default_pn, ir_entity *table,
+ get_cfop_target_func get_cfop_target);
+
#endif
/* We define a generic dummy unit */
be_execution_unit_t be_machine_execution_units_DUMMY[1];
-be_execution_unit_type_t be_machine_execution_unit_types[] = {
+static be_execution_unit_type_t be_machine_execution_unit_types[] = {
{ 1, 1, "DUMMY", be_machine_execution_units_DUMMY },
};
0, /* try to omit frame pointer */
0, /* create PIC code */
BE_VERIFY_WARN, /* verification level: warn */
- "i44pc52.info.uni-karlsruhe.de", /* ilp server */
+ "", /* ilp server */
"cplex", /* ilp solver */
0, /* enable statistic event dumping */
"", /* print stat events */
LC_OPT_ENT_BOOL ("statev", "dump statistic events", &be_options.statev),
LC_OPT_ENT_STR ("filtev", "filter for stat events (regex if support is active", &be_options.filtev, sizeof(be_options.filtev)),
-#ifdef WITH_ILP
- LC_OPT_ENT_STR ("ilp.server", "the ilp server name", be_options.ilp_server, sizeof(be_options.ilp_server)),
- LC_OPT_ENT_STR ("ilp.solver", "the ilp solver name", be_options.ilp_solver, sizeof(be_options.ilp_solver)),
-#endif /* WITH_ILP */
+ LC_OPT_ENT_STR ("ilp.server", "the ilp server name", &be_options.ilp_server, sizeof(be_options.ilp_server)),
+ LC_OPT_ENT_STR ("ilp.solver", "the ilp solver name", &be_options.ilp_solver, sizeof(be_options.ilp_solver)),
LC_OPT_LAST
};
/* set the current graph (this is important for several firm functions) */
current_ir_graph = irg;
- stat_ev_if {
+ if (stat_ev_enabled) {
stat_ev_ctx_push_fobj("bemain_irg", irg);
be_stat_ev("bemain_insns_start", be_count_insns(irg));
be_stat_ev("bemain_blocks_start", be_count_blocks(irg));
dump(DUMP_ABI, irg, "abi");
}
- /* we have to do cfopt+remove_critical_edges as we can't have Bad-blocks
- * or critical edges in the backend */
- optimize_cf(irg);
+ /* We can't have Bad-blocks or critical edges in the backend.
+ * Before removing Bads, we remove unreachable code. */
+ optimize_graph_df(irg);
remove_critical_cf_edges(irg);
+ remove_bads(irg);
/* We often have dead code reachable through out-edges here. So for
* now we rebuild edges (as we need correct user count for code
be_sched_verify(irg, be_options.verify_option);
be_timer_pop(T_VERIFY);
- stat_ev_if {
+ if (stat_ev_enabled) {
stat_ev_dbl("bemain_costs_before_ra",
be_estimate_irg_costs(irg, birg->exec_freq));
be_stat_ev("bemain_insns_before_ra", be_count_insns(irg));
dump(DUMP_FINAL, irg, "finish");
- stat_ev_if {
+ if (stat_ev_enabled) {
be_stat_ev("bemain_insns_finish", be_count_insns(irg));
be_stat_ev("bemain_blocks_finish", be_count_blocks(irg));
}
if (be_options.timing == BE_TIME_ON) {
ir_timer_stop(t);
ir_timer_leave_high_priority();
- stat_ev_if {
+ if (stat_ev_enabled) {
stat_ev_dbl("bemain_backend_time", ir_timer_elapsed_msec(t));
} else {
double val = ir_timer_elapsed_usec(t) / 1000.0;
be_init_copyheur4();
be_init_copyheur();
be_init_copyheur2();
-#ifdef WITH_ILP
be_init_copyilp2();
-#endif
be_init_pbqp_coloring();
be_init_copynone();
be_init_copystat();
be_init_arch_amd64();
be_init_arch_TEMPLATE();
-#ifdef WITH_ILP
be_init_copyilp();
-#endif /* WITH_ILP */
#if PLUGIN_IR_BE_STA
be_init_arch_sta();
(void) len;
for (module = *(moddata->list_head); module != NULL; module = module->next) {
- size_t len = strlen(module->name);
+ size_t name_len = strlen(module->name);
if (module != *(moddata->list_head)) {
p = strncat(p, ", ", buflen - 1);
p = strncat(p, module->name, buflen - 1);
- if (len >= buflen)
+ if (name_len >= buflen)
break;
- buflen -= len;
+ buflen -= name_len;
}
return strlen(buf);
if (additional_types == 0) {
req = reg->single_req;
} else {
- ir_graph *irg = get_irn_irg(node);
struct obstack *obst = be_get_be_obst(irg);
req = be_create_reg_req(obst, reg, additional_types);
}
* First we count how many destinations a single value has. At the same time
* we can be sure that each destination register has at most 1 source register
* (it can have 0 which means we don't care what value is in it).
- * We ignore all fullfilled permuations (like 7->7)
+ * We ignore all fulfilled permuations (like 7->7)
* In a first pass we create as much copy instructions as possible as they
* are generally cheaper than exchanges. We do this by counting into how many
* destinations a register has to be copied (in the example it's 2 for register
* We can then create a copy into every destination register when the usecount
* of that register is 0 (= noone else needs the value in the register).
*
- * After this step we should have cycles left. We implement a cyclic permutation
- * of n registers with n-1 transpositions.
+ * After this step we should only have cycles left. We implement a cyclic
+ * permutation of n registers with n-1 transpositions.
*
* @param live_nodes the set of live nodes, updated due to live range split
* @param before the node before we add the permutation
if (fc == NULL) {
irn_cost_pair* costs;
- int i;
ir_node* block = get_nodes_block(irn);
fc = OALLOCF(&inst->obst, flag_and_cost, costs, arity);
for (i = 0; i < arity; ++i) {
ir_node* pred = get_irn_n(irn, i);
- int cost;
if (is_Phi(irn) || get_irn_mode(pred) == mode_M || is_Block(pred)) {
cost = 0;
DEBUG_ONLY(
memset(spilllist, 0, spillcount * sizeof(spilllist[0]));
- );
+ )
i = 0;
foreach_set(env->spills, spill_t*, spill) {
/**
* Re-materialize a node.
*
- * @param senv the spill environment
+ * @param env the spill environment
* @param spilled the node that was spilled
* @param reloader a irn that requires a reload
*/
ins[i] = arg;
} else {
ins[i] = do_remat(env, arg, reloader);
- /* don't count the recursive call as remat */
- env->remat_count--;
+ /* don't count the argument rematerialization as an extra remat */
+ --env->remat_count;
}
}
/* insert in schedule */
sched_reset(res);
sched_add_before(reloader, res);
- env->remat_count++;
+ ++env->remat_count;
}
return res;
return;
} /* if */
- if (0 && get_mode_size_bits(mode) & 7) {
+#if 0
+ if (get_mode_size_bits(mode) & 7) {
/* this is a bitfield type, ignore it */
return;
} /* if */
+#endif
type_num = get_type_number(h, tp);
ofs = get_entity_offset(ent);
if (is_Struct_type(mtp) && get_type_mode(mtp) != NULL) {
/* this structure is a bitfield, skip */
- int i, n;
+ int m;
+ int n_members = get_struct_n_members(mtp);
- for (i = 0, n = get_struct_n_members(mtp); i < n; ++i) {
- ir_entity *ent = get_struct_member(mtp, i);
- ir_type *tp = get_entity_type(ent);
+ for (m = 0; m < n_members; ++m) {
+ ir_entity *member = get_struct_member(mtp, m);
+ ir_type *member_tp = get_entity_type(member);
int bofs;
- type_num = get_type_number(h, tp);
- size = get_type_size_bytes(tp) * 8;
- bofs = (ofs + get_entity_offset(ent)) * 8 + get_entity_offset_bits_remainder(ent);
+ type_num = get_type_number(h, member_tp);
+ size = get_type_size_bytes(member_tp) * 8;
+ bofs = (ofs + get_entity_offset(member)) * 8 + get_entity_offset_bits_remainder(member);
/* name:type, bit offset from the start of the struct', number of bits in the element. */
- be_emit_irprintf("%s:%u,%d,%u;", get_entity_name(ent), type_num, bofs, size);
+ be_emit_irprintf("%s:%u,%d,%u;", get_entity_name(member), type_num, bofs, size);
}
} else {
/* no bitfield */
for (i = 0, n = get_method_n_params(mtp); i < n; ++i) {
ir_type *ptp = get_method_param_type(mtp, i);
const char *name = NULL;
- unsigned type_num = get_type_number(h, ptp);
char buf[16];
int ofs = 0;
ir_entity *stack_ent;
/* create entries for automatic variables on the stack */
frame_size = get_type_size_bytes(layout->frame_type);
for (i = 0, n = get_compound_n_members(layout->frame_type); i < n; ++i) {
- ir_entity *ent = get_compound_member(layout->frame_type, i);
+ ir_entity *member = get_compound_member(layout->frame_type, i);
ir_type *tp;
int ofs;
unsigned type_num;
/* ignore spill slots and other helper objects */
- if (is_entity_compiler_generated(ent))
+ if (is_entity_compiler_generated(member))
continue;
- tp = get_entity_type(ent);
+ tp = get_entity_type(member);
/* should not happen in backend but ... */
if (is_Method_type(tp))
continue;
type_num = get_type_number(h, tp);
- ofs = -frame_size + get_entity_offset(ent);
+ ofs = -frame_size + get_entity_offset(member);
be_emit_irprintf("\t.stabs\t\"%s:%u\",%d,0,0,%d\n",
- get_entity_name(ent), type_num, N_LSYM, ofs);
+ get_entity_name(member), type_num, N_LSYM, ofs);
be_emit_write_line();
}
/* we need a lexical block here */
ir_graph *irg = get_irn_irg(phi);
ir_node *block = get_nodes_block(phi);
int arity = get_irn_arity(phi);
- ir_node **in = ALLOCAN(ir_node*, arity);
+ ir_node **phi_in = ALLOCAN(ir_node*, arity);
ir_node *dummy = new_r_Dummy(irg, mode_M);
ir_node *spill_to_kill = NULL;
spill_info_t *spill_info;
/* create a new phi-M with bad preds */
for (i = 0; i < arity; ++i) {
- in[i] = dummy;
+ phi_in[i] = dummy;
}
DBG((dbg, LEVEL_2, "\tcreate Phi-M for %+F\n", phi));
/* create a Phi-M */
- spill_info->spill = be_new_Phi(block, arity, in, mode_M, NULL);
+ spill_info->spill = be_new_Phi(block, arity, phi_in, mode_M, NULL);
sched_add_after(block, spill_info->spill);
if (spill_to_kill != NULL) {
{
unsigned step;
ir_node *block = get_nodes_block(from);
- ir_node *next_use;
+ ir_node *next_use_node;
ir_node *node;
unsigned timestep;
unsigned next_use_step;
from = sched_next(from);
}
- next_use = NULL;
+ next_use_node = NULL;
next_use_step = INT_MAX;
timestep = get_step(from);
foreach_out_edge(def, edge) {
- ir_node *node = get_edge_src_irn(edge);
- unsigned node_step;
+ node = get_edge_src_irn(edge);
+ unsigned node_step;
if (is_Anchor(node))
continue;
if (node_step < timestep)
continue;
if (node_step < next_use_step) {
- next_use = node;
+ next_use_node = node;
next_use_step = node_step;
}
}
- if (next_use != NULL) {
+ if (next_use_node != NULL) {
be_next_use_t result;
result.time = next_use_step - timestep + skip_from_uses;
result.outermost_loop = get_loop_depth(get_irn_loop(block));
- result.before = next_use;
+ result.before = next_use_node;
return result;
}
* (except mode_X projs)
*/
sched_foreach(block, node) {
- int i, arity;
int timestep;
/* this node is scheduled */
/* Check that all uses come before their definitions */
if (!is_Phi(node)) {
+ int i;
+ int arity;
sched_timestep_t nodetime = sched_get_time_step(node);
for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
ir_node *arg = get_irn_n(node, i);
prev = sched_prev(prev);
while (true) {
+ int i;
for (i = 0; i < arity; ++i) {
ir_node *in = get_irn_n(node, i);
in = skip_Proj(in);
/* phis should be NOPs at this point, which means all input regs
* must be the same as the output reg */
if (is_Phi(node)) {
- int i, arity;
-
reg = arch_get_irn_register(node);
arity = get_irn_arity(node);
registers = ALLOCANZ(ir_node*, n_regs);
be_lv_foreach(lv, block, be_lv_state_end, idx) {
- ir_node *node = be_lv_get_irn(lv, block, idx);
- value_used(block, node);
+ ir_node *lv_node = be_lv_get_irn(lv, block, idx);
+ value_used(block, lv_node);
}
sched_foreach_reverse(block, node) {
}
be_lv_foreach(lv, block, be_lv_state_in, idx) {
- ir_node *node = be_lv_get_irn(lv, block, idx);
- value_def(node);
+ ir_node *lv_node = be_lv_get_irn(lv, block, idx);
+ value_def(lv_node);
}
/* set must be empty now */
transformer_t be_transformer = TRANSFORMER_DEFAULT;
#endif
-DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
-
-ir_mode *ia32_mode_fpcw = NULL;
+ir_mode *ia32_mode_fpcw = NULL;
/** The current omit-fp state */
static ir_type *omit_fp_between_type = NULL;
};
-typedef ir_node *(*create_const_node_func) (dbg_info *dbg, ir_node *block);
+typedef ir_node *(*create_const_node_func) (dbg_info *dbgi, ir_node *block);
/**
* Used to create per-graph unique pseudo nodes.
ir_mode *mode;
ir_mode *irn_mode;
ir_node *block, *noreg, *nomem;
- dbg_info *dbg;
+ dbg_info *dbgi;
/* we cannot invert non-ia32 irns */
if (! is_ia32_irn(irn))
irn_mode = get_irn_mode(irn);
noreg = get_irn_n(irn, 0);
nomem = get_irg_no_mem(irg);
- dbg = get_irn_dbg_info(irn);
+ dbgi = get_irn_dbg_info(irn);
/* initialize structure */
inverse->nodes = obstack_alloc(obst, 2 * sizeof(inverse->nodes[0]));
if (get_ia32_immop_type(irn) == ia32_ImmConst) {
/* we have an add with a const here */
/* invers == add with negated const */
- inverse->nodes[0] = new_bd_ia32_Add(dbg, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
+ inverse->nodes[0] = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
inverse->costs += 1;
copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
set_ia32_Immop_tarval(inverse->nodes[0], tarval_neg(get_ia32_Immop_tarval(irn)));
else if (get_ia32_immop_type(irn) == ia32_ImmSymConst) {
/* we have an add with a symconst here */
/* invers == sub with const */
- inverse->nodes[0] = new_bd_ia32_Sub(dbg, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
+ inverse->nodes[0] = new_bd_ia32_Sub(dbgi, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
inverse->costs += 2;
copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
}
else {
/* normal add: inverse == sub */
- inverse->nodes[0] = new_bd_ia32_Sub(dbg, block, noreg, noreg, nomem, (ir_node*) irn, get_irn_n(irn, i ^ 1));
+ inverse->nodes[0] = new_bd_ia32_Sub(dbgi, block, noreg, noreg, nomem, (ir_node*) irn, get_irn_n(irn, i ^ 1));
inverse->costs += 2;
}
break;
if (get_ia32_immop_type(irn) != ia32_ImmNone) {
/* we have a sub with a const/symconst here */
/* invers == add with this const */
- inverse->nodes[0] = new_bd_ia32_Add(dbg, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
+ inverse->nodes[0] = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
inverse->costs += (get_ia32_immop_type(irn) == ia32_ImmSymConst) ? 5 : 1;
copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
}
else {
/* normal sub */
if (i == n_ia32_binary_left) {
- inverse->nodes[0] = new_bd_ia32_Add(dbg, block, noreg, noreg, nomem, (ir_node*) irn, get_irn_n(irn, 3));
+ inverse->nodes[0] = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, (ir_node*) irn, get_irn_n(irn, 3));
}
else {
- inverse->nodes[0] = new_bd_ia32_Sub(dbg, block, noreg, noreg, nomem, get_irn_n(irn, n_ia32_binary_left), (ir_node*) irn);
+ inverse->nodes[0] = new_bd_ia32_Sub(dbgi, block, noreg, noreg, nomem, get_irn_n(irn, n_ia32_binary_left), (ir_node*) irn);
}
inverse->costs += 1;
}
case iro_ia32_Xor:
if (get_ia32_immop_type(irn) != ia32_ImmNone) {
/* xor with const: inverse = xor */
- inverse->nodes[0] = new_bd_ia32_Xor(dbg, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
+ inverse->nodes[0] = new_bd_ia32_Xor(dbgi, block, noreg, noreg, nomem, get_irn_n(irn, i), noreg);
inverse->costs += (get_ia32_immop_type(irn) == ia32_ImmSymConst) ? 5 : 1;
copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
}
else {
/* normal xor */
- inverse->nodes[0] = new_bd_ia32_Xor(dbg, block, noreg, noreg, nomem, (ir_node *) irn, get_irn_n(irn, i));
+ inverse->nodes[0] = new_bd_ia32_Xor(dbgi, block, noreg, noreg, nomem, (ir_node *) irn, get_irn_n(irn, i));
inverse->costs += 1;
}
break;
case iro_ia32_Not: {
- inverse->nodes[0] = new_bd_ia32_Not(dbg, block, (ir_node*) irn);
+ inverse->nodes[0] = new_bd_ia32_Not(dbgi, block, (ir_node*) irn);
inverse->costs += 1;
break;
}
case iro_ia32_Neg: {
- inverse->nodes[0] = new_bd_ia32_Neg(dbg, block, (ir_node*) irn);
+ inverse->nodes[0] = new_bd_ia32_Neg(dbgi, block, (ir_node*) irn);
inverse->costs += 1;
break;
}
ir_graph *irg = get_irn_irg(node);
ir_node *block = get_nodes_block(node);
ir_node *base = get_irn_n(node, n_ia32_base);
- ir_node *index = get_irn_n(node, n_ia32_index);
+ ir_node *idx = get_irn_n(node, n_ia32_index);
ir_node *mem = get_irn_n(node, n_ia32_mem);
ir_node *noreg;
- ir_node *load = new_bd_ia32_Load(dbgi, block, base, index, mem);
+ ir_node *load = new_bd_ia32_Load(dbgi, block, base, idx, mem);
ir_node *load_res = new_rd_Proj(dbgi, load, mode_Iu, pn_ia32_Load_res);
ia32_copy_am_attrs(load, node);
case ia32_AddrModeD:
/* TODO implement this later... */
panic("found DestAM with flag user %+F this should not happen", node);
- break;
default: assert(type == ia32_Normal); break;
}
static void transform_to_Load(ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
- dbg_info *dbg = get_irn_dbg_info(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
ir_entity *ent = be_get_frame_entity(node);
ir_mode *mode = get_irn_mode(node);
if (mode_is_float(spillmode)) {
if (ia32_cg_config.use_sse2)
- new_op = new_bd_ia32_xLoad(dbg, block, ptr, noreg, mem, spillmode);
+ new_op = new_bd_ia32_xLoad(dbgi, block, ptr, noreg, mem, spillmode);
else
- new_op = new_bd_ia32_vfld(dbg, block, ptr, noreg, mem, spillmode);
+ new_op = new_bd_ia32_vfld(dbgi, block, ptr, noreg, mem, spillmode);
}
else if (get_mode_size_bits(spillmode) == 128) {
/* Reload 128 bit SSE registers */
- new_op = new_bd_ia32_xxLoad(dbg, block, ptr, noreg, mem);
+ new_op = new_bd_ia32_xxLoad(dbgi, block, ptr, noreg, mem);
}
else
- new_op = new_bd_ia32_Load(dbg, block, ptr, noreg, mem);
+ new_op = new_bd_ia32_Load(dbgi, block, ptr, noreg, mem);
set_ia32_op_type(new_op, ia32_AddrModeS);
set_ia32_ls_mode(new_op, spillmode);
DBG_OPT_RELOAD2LD(node, new_op);
- proj = new_rd_Proj(dbg, new_op, mode, pn_ia32_Load_res);
+ proj = new_rd_Proj(dbgi, new_op, mode, pn_ia32_Load_res);
if (sched_point) {
sched_add_after(sched_point, new_op);
static void transform_to_Store(ir_node *node)
{
ir_graph *irg = get_irn_irg(node);
- dbg_info *dbg = get_irn_dbg_info(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
ir_entity *ent = be_get_frame_entity(node);
const ir_node *spillval = get_irn_n(node, n_be_Spill_val);
if (mode_is_float(mode)) {
if (ia32_cg_config.use_sse2) {
- store = new_bd_ia32_xStore(dbg, block, ptr, noreg, nomem, val);
+ store = new_bd_ia32_xStore(dbgi, block, ptr, noreg, nomem, val);
res = new_r_Proj(store, mode_M, pn_ia32_xStore_M);
} else {
- store = new_bd_ia32_vfst(dbg, block, ptr, noreg, nomem, val, mode);
+ store = new_bd_ia32_vfst(dbgi, block, ptr, noreg, nomem, val, mode);
res = new_r_Proj(store, mode_M, pn_ia32_vfst_M);
}
} else if (get_mode_size_bits(mode) == 128) {
/* Spill 128 bit SSE registers */
- store = new_bd_ia32_xxStore(dbg, block, ptr, noreg, nomem, val);
+ store = new_bd_ia32_xxStore(dbgi, block, ptr, noreg, nomem, val);
res = new_r_Proj(store, mode_M, pn_ia32_xxStore_M);
} else if (get_mode_size_bits(mode) == 8) {
- store = new_bd_ia32_Store8Bit(dbg, block, ptr, noreg, nomem, val);
+ store = new_bd_ia32_Store8Bit(dbgi, block, ptr, noreg, nomem, val);
res = new_r_Proj(store, mode_M, pn_ia32_Store8Bit_M);
} else {
- store = new_bd_ia32_Store(dbg, block, ptr, noreg, nomem, val);
+ store = new_bd_ia32_Store(dbgi, block, ptr, noreg, nomem, val);
res = new_r_Proj(store, mode_M, pn_ia32_Store_M);
}
static ir_node *create_push(ir_node *node, ir_node *schedpoint, ir_node *sp, ir_node *mem, ir_entity *ent)
{
- dbg_info *dbg = get_irn_dbg_info(node);
- ir_node *block = get_nodes_block(node);
- ir_graph *irg = get_irn_irg(node);
- ir_node *noreg = ia32_new_NoReg_gp(irg);
- ir_node *frame = get_irg_frame(irg);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_graph *irg = get_irn_irg(node);
+ ir_node *noreg = ia32_new_NoReg_gp(irg);
+ ir_node *frame = get_irg_frame(irg);
- ir_node *push = new_bd_ia32_Push(dbg, block, frame, noreg, mem, noreg, sp);
+ ir_node *push = new_bd_ia32_Push(dbgi, block, frame, noreg, mem, noreg, sp);
set_ia32_frame_ent(push, ent);
set_ia32_use_frame(push);
static ir_node *create_pop(ir_node *node, ir_node *schedpoint, ir_node *sp, ir_entity *ent)
{
- dbg_info *dbg = get_irn_dbg_info(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
ir_graph *irg = get_irn_irg(node);
ir_node *noreg = ia32_new_NoReg_gp(irg);
ir_node *frame = get_irg_frame(irg);
- ir_node *pop = new_bd_ia32_PopMem(dbg, block, frame, noreg,
+ ir_node *pop = new_bd_ia32_PopMem(dbgi, block, frame, noreg,
get_irg_no_mem(irg), sp);
set_ia32_frame_ent(pop, ent);
static ir_node* create_spproj(ir_node *node, ir_node *pred, int pos)
{
- dbg_info *dbg = get_irn_dbg_info(node);
- ir_mode *spmode = mode_Iu;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_mode *spmode = mode_Iu;
const arch_register_t *spreg = &ia32_registers[REG_ESP];
ir_node *sp;
- sp = new_rd_Proj(dbg, pred, spmode, pos);
+ sp = new_rd_Proj(dbgi, pred, spmode, pos);
arch_set_irn_register(sp, spreg);
return sp;
static void ia32_get_call_abi(const void *self, ir_type *method_type,
be_abi_call_t *abi)
{
- ir_type *tp;
- ir_mode *mode;
unsigned cc;
int n, i, regnum;
int pop_amount = 0;
n = get_method_n_params(method_type);
for (i = regnum = 0; i < n; i++) {
- ir_mode *mode;
- const arch_register_t *reg = NULL;
+ const arch_register_t *reg = NULL;
+ ir_type *tp = get_method_param_type(method_type, i);
+ ir_mode *mode = get_type_mode(tp);
- tp = get_method_param_type(method_type, i);
- mode = get_type_mode(tp);
if (mode != NULL) {
reg = ia32_get_RegParam_reg(cc, regnum, mode);
}
/* In case of 64bit returns, we will have two 32bit values */
if (n == 2) {
- tp = get_method_res_type(method_type, 0);
- mode = get_type_mode(tp);
+ ir_type *tp = get_method_res_type(method_type, 0);
+ ir_mode *mode = get_type_mode(tp);
assert(!mode_is_float(mode) && "two FP results not supported");
be_abi_call_res_reg(abi, 1, &ia32_registers[REG_EDX], ABI_CONTEXT_BOTH);
}
else if (n == 1) {
+ ir_type *tp = get_method_res_type(method_type, 0);
+ ir_mode *mode = get_type_mode(tp);
const arch_register_t *reg;
-
- tp = get_method_res_type(method_type, 0);
assert(is_atomic_type(tp));
- mode = get_type_mode(tp);
reg = mode_is_float(mode) ? &ia32_registers[REG_VF0] : &ia32_registers[REG_EAX];
/* lower for mode_b stuff */
ir_lower_mode_b(irg, &lower_mode_b_config);
/* break up switches with wide ranges */
- lower_switch(irg, 256, true);
+ lower_switch(irg, 4, 256, false);
}
}
0, /* little endian */
NULL, /* will be set later */
ia32_is_mux_allowed,
+ 32, /* machine_size */
NULL, /* float arithmetic mode, will be set below */
+ 0, /* size of long double */
12, /* size of trampoline code */
4, /* alignment of trampoline code */
ia32_create_trampoline_fkt,
init_asm_constraints();
p.dep_param = &ad;
- if (! ia32_cg_config.use_sse2)
+ if (! ia32_cg_config.use_sse2) {
p.mode_float_arithmetic = mode_E;
+ p.long_double_size = 96;
+ } else {
+ p.mode_float_arithmetic = NULL;
+ p.long_double_size = 64;
+ }
return &p;
}
+/**
+ * Check if the given register is callee or caller save.
+ */
+static int ia32_register_saved_by(const arch_register_t *reg, int callee)
+{
+ if (callee) {
+ /* check for callee saved */
+ if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_gp]) {
+ switch (reg->index) {
+ case REG_GP_EBX:
+ case REG_GP_ESI:
+ case REG_GP_EDI:
+ case REG_GP_EBP:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+ } else {
+ /* check for caller saved */
+ if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_gp]) {
+ switch (reg->index) {
+ case REG_GP_EDX:
+ case REG_GP_ECX:
+ case REG_GP_EAX:
+ return 1;
+ default:
+ return 0;
+ }
+ } else if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_xmm]) {
+ /* all XMM registers are caller save */
+ return reg->index != REG_XMM_NOREG;
+ } else if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]) {
+ /* all VFP registers are caller save */
+ return reg->index != REG_VFP_NOREG;
+ }
+ }
+ return 0;
+}
+
static const lc_opt_enum_int_items_t gas_items[] = {
{ "elf", OBJECT_FILE_FORMAT_ELF },
{ "mingw", OBJECT_FILE_FORMAT_COFF },
ia32_after_ra, /* after register allocation hook */
ia32_finish, /* called before codegen */
ia32_emit, /* emit && done */
+ ia32_register_saved_by,
};
BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_ia32)
lc_opt_add_table(ia32_grp, ia32_options);
be_register_isa_if("ia32", &ia32_isa_if);
- FIRM_DBG_REGISTER(dbg, "firm.be.ia32.cg");
-
ia32_init_emitter();
ia32_init_finish();
ia32_init_optimize();
case 'e': /* not available in 32 bit mode */
panic("unsupported asm constraint '%c' found in (%+F)",
*c, current_ir_graph);
- break;
default:
panic("unknown asm constraint '%c' found in (%+F)", *c,
current_ir_graph);
- break;
}
++c;
}
}
if (input == NULL) {
- ir_node *pred = get_irn_n(node, i);
input = get_new_node(pred);
if (parsed_constraint.cls == NULL
/* count inputs which are real values (and not memory) */
value_arity = 0;
for (i = 0; i < arity; ++i) {
- ir_node *in = get_irn_n(node, i);
- if (get_irn_mode(in) == mode_M)
+ ir_node *node_in = get_irn_n(node, i);
+ if (get_irn_mode(node_in) == mode_M)
continue;
++value_arity;
}
int o;
bitset_t *used_ins = bitset_alloca(arity);
for (o = 0; o < out_arity; ++o) {
- int i;
const arch_register_req_t *outreq = out_reg_reqs[o];
if (outreq->cls == NULL) {
++arity;
}
} else {
- int i;
bitset_t *used_outs = bitset_alloca(out_arity);
int orig_out_arity = out_arity;
for (i = 0; i < arity; ++i) {
int offs = get_ia32_am_offs_int(node);
ir_node *base = get_irn_n(node, n_ia32_base);
int has_base = !is_ia32_NoReg_GP(base);
- ir_node *index = get_irn_n(node, n_ia32_index);
- int has_index = !is_ia32_NoReg_GP(index);
+ ir_node *idx = get_irn_n(node, n_ia32_index);
+ int has_index = !is_ia32_NoReg_GP(idx);
/* just to be sure... */
assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL);
end_of_mods:
switch (*fmt++) {
+ arch_register_t const *reg;
+ ir_node const *imm;
+
case '%':
be_emit_char('%');
break;
ia32_emit_am(node);
break;
- case 'R': {
- const arch_register_t *reg = va_arg(ap, const arch_register_t*);
+ case 'R':
+ reg = va_arg(ap, const arch_register_t*);
if (get_ia32_op_type(node) == ia32_AddrModeS) {
goto emit_AM;
} else {
- if (mod & EMIT_ALTERNATE_AM)
- be_emit_char('*');
- emit_register(reg, NULL);
+ goto emit_R;
}
- break;
- }
case 'S':
if (get_ia32_op_type(node) == ia32_AddrModeS) {
assert(get_ia32_op_type(node) == ia32_Normal);
goto emit_S;
}
- break;
default: goto unknown;
}
break;
}
- case 'D': {
- unsigned pos;
- const arch_register_t *reg;
-
+ case 'D':
if (*fmt < '0' || '9' <= *fmt)
goto unknown;
-
- pos = *fmt++ - '0';
- reg = get_out_reg(node, pos);
- emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
- break;
- }
+ reg = get_out_reg(node, *fmt++ - '0');
+ goto emit_R;
case 'I':
+ imm = node;
+emit_I:
if (!(mod & EMIT_ALTERNATE_AM))
be_emit_char('$');
- emit_ia32_Immediate_no_prefix(node);
+ emit_ia32_Immediate_no_prefix(imm);
break;
case 'L':
ia32_emit_cfop_target(node);
break;
- case 'M': {
+ case 'M':
ia32_emit_mode_suffix_mode(get_ia32_ls_mode(node));
break;
- }
case 'P': {
ia32_condition_code_t cc = va_arg(ap, ia32_condition_code_t);
break;
}
- case 'R': {
- const arch_register_t *reg = va_arg(ap, const arch_register_t*);
+ case 'R':
+ reg = va_arg(ap, const arch_register_t*);
+emit_R:
+ if (mod & EMIT_ALTERNATE_AM)
+ be_emit_char('*');
if (mod & EMIT_HIGH_REG) {
emit_8bit_register_high(reg);
} else if (mod & EMIT_LOW_REG) {
emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
}
break;
- }
emit_S:
case 'S': {
- unsigned pos;
- const ir_node *in;
+ unsigned pos;
if (*fmt < '0' || '9' <= *fmt)
goto unknown;
pos = *fmt++ - '0';
- in = get_irn_n(node, pos);
- if (is_ia32_Immediate(in)) {
- if (!(mod & EMIT_ALTERNATE_AM))
- be_emit_char('$');
- emit_ia32_Immediate_no_prefix(in);
+ imm = get_irn_n(node, pos);
+ if (is_ia32_Immediate(imm)) {
+ goto emit_I;
} else {
- const arch_register_t *reg;
-
- if (mod & EMIT_ALTERNATE_AM)
- be_emit_char('*');
reg = get_in_reg(node, pos);
- emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL);
+ goto emit_R;
}
- break;
}
case 's': {
ia32_emitf(node, "\tcmov%P %#AR, %#R\n", cc, in_true, out);
}
-
-/* jump table entry (target and corresponding number) */
-typedef struct branch_t {
- ir_node *target;
- int value;
-} branch_t;
-
-/* jump table for switch generation */
-typedef struct jmp_tbl_t {
- ir_node *defProj; /**< default target */
- long min_value; /**< smallest switch case */
- long max_value; /**< largest switch case */
- long num_branches; /**< number of jumps */
- char label[SNPRINTF_BUF_LEN]; /**< label of the jump table */
- branch_t *branches; /**< jump array */
-} jmp_tbl_t;
-
/**
- * Compare two variables of type branch_t. Used to sort all switch cases
- */
-static int ia32_cmp_branch_t(const void *a, const void *b)
-{
- branch_t *b1 = (branch_t *)a;
- branch_t *b2 = (branch_t *)b;
-
- if (b1->value <= b2->value)
- return -1;
- else
- return 1;
-}
-
-static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node)
-{
- int i;
- long default_pn = get_ia32_default_pn(node);
- ir_node *proj;
- const ir_edge_t *edge;
-
- /* fill the table structure */
- get_unique_label(tbl->label, SNPRINTF_BUF_LEN, "TBL_");
- tbl->defProj = NULL;
- tbl->num_branches = get_irn_n_edges(node) - 1;
- tbl->branches = XMALLOCNZ(branch_t, tbl->num_branches);
- tbl->min_value = LONG_MAX;
- tbl->max_value = LONG_MIN;
-
- i = 0;
- /* go over all proj's and collect them */
- foreach_out_edge(node, edge) {
- long pn;
- proj = get_edge_src_irn(edge);
- assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
-
- pn = get_Proj_proj(proj);
-
- /* check for default proj */
- if (pn == default_pn) {
- assert(tbl->defProj == NULL && "found two default Projs at SwitchJmp");
- tbl->defProj = proj;
- } else {
- tbl->min_value = pn < tbl->min_value ? pn : tbl->min_value;
- tbl->max_value = pn > tbl->max_value ? pn : tbl->max_value;
-
- /* create branch entry */
- tbl->branches[i].target = proj;
- tbl->branches[i].value = pn;
- ++i;
- }
-
- }
- assert(i == tbl->num_branches);
-
- /* sort the branches by their number */
- qsort(tbl->branches, tbl->num_branches, sizeof(tbl->branches[0]), ia32_cmp_branch_t);
-}
-
-/**
- * Emits code for a SwitchJmp (creates a jump table if
- * possible otherwise a cmp-jmp cascade). Port from
- * cggg ia32 backend
+ * Emits code for a SwitchJmp
*/
static void emit_ia32_SwitchJmp(const ir_node *node)
{
- unsigned long interval;
- int last_value, i;
- jmp_tbl_t tbl;
-
- /* fill the table structure */
- generate_jump_table(&tbl, node);
-
- /* two-complement's magic make this work without overflow */
- interval = tbl.max_value - tbl.min_value;
-
- /* emit the table */
- ia32_emitf(node, "\tcmpl $%u, %S0\n", interval);
- ia32_emitf(tbl.defProj, "\tja %L\n");
+ ir_entity *jump_table = get_ia32_am_sc(node);
+ long default_pn = get_ia32_default_pn(node);
- if (tbl.num_branches > 1) {
- /* create table */
- ia32_emitf(node, "\tjmp *%s(,%S0,4)\n", tbl.label);
-
- be_gas_emit_switch_section(GAS_SECTION_RODATA);
- ia32_emitf(NULL, "\t.align 4\n");
- ia32_emitf(NULL, "%s:\n", tbl.label);
-
- last_value = tbl.branches[0].value;
- for (i = 0; i != tbl.num_branches; ++i) {
- while (last_value != tbl.branches[i].value) {
- ia32_emitf(tbl.defProj, ".long %L\n");
- ++last_value;
- }
- ia32_emitf(tbl.branches[i].target, ".long %L\n");
- ++last_value;
- }
- be_gas_emit_switch_section(GAS_SECTION_TEXT);
- } else {
- /* one jump is enough */
- ia32_emitf(tbl.branches[0].target, "\tjmp %L\n");
- }
-
- free(tbl.branches);
+ ia32_emitf(node, "\tjmp %*AM\n");
+ emit_jump_table(node, default_pn, jump_table, get_cfop_target_block);
}
/**
*/
static void emit_ia32_Conv_I2I(const ir_node *node)
{
- ir_mode *smaller_mode = get_ia32_ls_mode(node);
- int signed_mode = mode_is_signed(smaller_mode);
+ ir_mode *smaller_mode = get_ia32_ls_mode(node);
+ int signed_mode = mode_is_signed(smaller_mode);
const char *sign_suffix;
assert(!mode_is_float(smaller_mode));
*/
static void ia32_emit_block_header(ir_node *block)
{
- ir_graph *irg = current_ir_graph;
+ ir_graph *irg = current_ir_graph;
int need_label = block_needs_label(block);
- int i, arity;
- ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg);
+ ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg);
+ int arity;
if (block == get_irg_end_block(irg))
return;
if (arity <= 0) {
be_emit_cstring(" none");
} else {
+ int i;
for (i = 0; i < arity; ++i) {
ir_node *predblock = get_Block_cfgpred_block(block, i);
be_emit_irprintf(" %d", get_irn_node_nr(predblock));
Those are ascending with ascending addresses. */
qsort(exc_list, ARR_LEN(exc_list), sizeof(exc_list[0]), cmp_exc_entry);
{
- size_t i;
+ size_t e;
- for (i = 0; i < ARR_LEN(exc_list); ++i) {
+ for (e = 0; e < ARR_LEN(exc_list); ++e) {
be_emit_cstring("\t.long ");
- ia32_emit_exc_label(exc_list[i].exc_instr);
+ ia32_emit_exc_label(exc_list[e].exc_instr);
be_emit_char('\n');
be_emit_cstring("\t.long ");
- be_gas_emit_block_name(exc_list[i].block);
+ be_gas_emit_block_name(exc_list[e].block);
be_emit_char('\n');
}
}
int offs = get_ia32_am_offs_int(node);
ir_node *base = get_irn_n(node, n_ia32_base);
int has_base = !is_ia32_NoReg_GP(base);
- ir_node *index = get_irn_n(node, n_ia32_index);
- int has_index = !is_ia32_NoReg_GP(index);
+ ir_node *idx = get_irn_n(node, n_ia32_index);
+ int has_index = !is_ia32_NoReg_GP(idx);
unsigned modrm = 0;
unsigned sib = 0;
unsigned emitoffs = 0;
/* Determine if we need a SIB byte. */
if (has_index) {
- const arch_register_t *reg_index = arch_get_irn_register(index);
+ const arch_register_t *reg_index = arch_get_irn_register(idx);
int scale = get_ia32_am_scale(node);
assert(scale < 4);
/* R/M set to ESP means SIB in 32bit mode. */
if (out->index == REG_GP_EAX) {
ir_node *base = get_irn_n(node, n_ia32_base);
int has_base = !is_ia32_NoReg_GP(base);
- ir_node *index = get_irn_n(node, n_ia32_index);
- int has_index = !is_ia32_NoReg_GP(index);
+ ir_node *idx = get_irn_n(node, n_ia32_index);
+ int has_index = !is_ia32_NoReg_GP(idx);
if (!has_base && !has_index) {
ir_entity *ent = get_ia32_am_sc(node);
int offs = get_ia32_am_offs_int(node);
if (in->index == REG_GP_EAX) {
ir_node *base = get_irn_n(node, n_ia32_base);
int has_base = !is_ia32_NoReg_GP(base);
- ir_node *index = get_irn_n(node, n_ia32_index);
- int has_index = !is_ia32_NoReg_GP(index);
+ ir_node *idx = get_irn_n(node, n_ia32_index);
+ int has_index = !is_ia32_NoReg_GP(idx);
if (!has_base && !has_index) {
ir_entity *ent = get_ia32_am_sc(node);
int offs = get_ia32_am_offs_int(node);
static void bemit_switchjmp(const ir_node *node)
{
- unsigned long interval;
- int last_value;
- int i;
- jmp_tbl_t tbl;
- const arch_register_t *in;
-
- /* fill the table structure */
- generate_jump_table(&tbl, node);
-
- /* two-complement's magic make this work without overflow */
- interval = tbl.max_value - tbl.min_value;
-
- in = get_in_reg(node, 0);
- /* emit the table */
- if (get_signed_imm_size(interval) == 1) {
- bemit8(0x83); // cmpl $imm8, %in
- bemit_modru(in, 7);
- bemit8(interval);
- } else {
- bemit8(0x81); // cmpl $imm32, %in
- bemit_modru(in, 7);
- bemit32(interval);
- }
- bemit8(0x0F); // ja tbl.defProj
- bemit8(0x87);
- ia32_emitf(tbl.defProj, ".long %L - . - 4\n");
-
- if (tbl.num_branches > 1) {
- /* create table */
- bemit8(0xFF); // jmp *tbl.label(,%in,4)
- bemit8(MOD_IND | ENC_REG(4) | ENC_RM(0x04));
- bemit8(ENC_SIB(2, reg_gp_map[in->index], 0x05));
- be_emit_irprintf("\t.long %s\n", tbl.label);
-
- be_gas_emit_switch_section(GAS_SECTION_RODATA);
- be_emit_cstring(".align 4\n");
- be_emit_irprintf("%s:\n", tbl.label);
-
- last_value = tbl.branches[0].value;
- for (i = 0; i != tbl.num_branches; ++i) {
- while (last_value != tbl.branches[i].value) {
- ia32_emitf(tbl.defProj, ".long %L\n");
- ++last_value;
- }
- ia32_emitf(tbl.branches[i].target, ".long %L\n");
- ++last_value;
- }
- be_gas_emit_switch_section(GAS_SECTION_TEXT);
- } else {
- /* one jump is enough */
- panic("switch only has one case");
- //ia32_emitf(tbl.branches[0].target, "\tjmp %L\n");
- }
+ ir_entity *jump_table = get_ia32_am_sc(node);
+ long default_pn = get_ia32_default_pn(node);
- be_emit_write_line();
+ bemit8(0xFF); // jmp *tbl.label(,%in,4)
+ bemit_mod_am(0x05, node);
- free(tbl.branches);
+ emit_jump_table(node, default_pn, jump_table, get_cfop_target_block);
}
/**
ir_graph *irg;
ir_node *in1, *in2, *noreg, *nomem, *res;
ir_node *noreg_fp, *block;
- dbg_info *dbg;
+ dbg_info *dbgi;
const arch_register_t *in1_reg, *in2_reg, *out_reg;
/* fix_am will solve this for AddressMode variants */
return;
block = get_nodes_block(irn);
- dbg = get_irn_dbg_info(irn);
+ dbgi = get_irn_dbg_info(irn);
/* generate the neg src2 */
if (is_ia32_xSub(irn)) {
assert(get_irn_mode(irn) != mode_T);
- res = new_bd_ia32_xXor(dbg, block, noreg, noreg, nomem, in2, noreg_fp);
+ res = new_bd_ia32_xXor(dbgi, block, noreg, noreg, nomem, in2, noreg_fp);
size = get_mode_size_bits(op_mode);
entity = ia32_gen_fp_known_const(size == 32 ? ia32_SSIGN : ia32_DSIGN);
set_ia32_am_sc(res, entity);
sched_add_before(irn, res);
/* generate the add */
- res = new_bd_ia32_xAdd(dbg, block, noreg, noreg, nomem, res, in1);
+ res = new_bd_ia32_xAdd(dbgi, block, noreg, noreg, nomem, res, in1);
set_ia32_ls_mode(res, get_ia32_ls_mode(irn));
/* exchange the add and the sub */
}
if (flags_proj == NULL) {
- res = new_bd_ia32_Neg(dbg, block, in2);
+ res = new_bd_ia32_Neg(dbgi, block, in2);
arch_set_irn_register(res, in2_reg);
/* add to schedule */
sched_add_before(irn, res);
/* generate the add */
- res = new_bd_ia32_Add(dbg, block, noreg, noreg, nomem, res, in1);
+ res = new_bd_ia32_Add(dbgi, block, noreg, noreg, nomem, res, in1);
arch_set_irn_register(res, out_reg);
set_ia32_commutative(res);
*
* a + -b = a + (~b + 1) would set the carry flag IF a == b ...
*/
- nnot = new_bd_ia32_Not(dbg, block, in2);
+ nnot = new_bd_ia32_Not(dbgi, block, in2);
arch_set_irn_register(nnot, in2_reg);
sched_add_before(irn, nnot);
- stc = new_bd_ia32_Stc(dbg, block);
+ stc = new_bd_ia32_Stc(dbgi, block);
arch_set_irn_register(stc, &ia32_registers[REG_EFLAGS]);
sched_add_before(irn, stc);
- adc = new_bd_ia32_Adc(dbg, block, noreg, noreg, nomem, nnot, in1, stc);
+ adc = new_bd_ia32_Adc(dbgi, block, noreg, noreg, nomem, nnot, in1, stc);
arch_set_irn_register(adc, out_reg);
sched_add_before(irn, adc);
adc_flags = new_r_Proj(adc, mode_Iu, pn_ia32_Adc_flags);
arch_set_irn_register(adc_flags, &ia32_registers[REG_EFLAGS]);
- cmc = new_bd_ia32_Cmc(dbg, block, adc_flags);
+ cmc = new_bd_ia32_Cmc(dbgi, block, adc_flags);
arch_set_irn_register(cmc, &ia32_registers[REG_EFLAGS]);
sched_add_before(irn, cmc);
uses_out_reg_pos = -1;
for (i2 = 0; i2 < arity; ++i2) {
ir_node *in = get_irn_n(node, i2);
- const arch_register_t *in_reg;
+ const arch_register_t *other_in_reg;
if (!mode_is_data(get_irn_mode(in)))
continue;
- in_reg = arch_get_irn_register(in);
+ other_in_reg = arch_get_irn_register(in);
- if (in_reg != out_reg)
+ if (other_in_reg != out_reg)
continue;
if (uses_out_reg != NULL && in != uses_out_reg) {
static ir_node *create_fpu_mode_spill(void *env, ir_node *state, int force,
ir_node *after)
{
- ir_node *spill = NULL;
(void) env;
/* we don't spill the fpcw in unsafe mode */
ir_node *noreg = ia32_new_NoReg_gp(irg);
ir_node *nomem = get_irg_no_mem(irg);
ir_node *frame = get_irg_frame(irg);
-
- spill = new_bd_ia32_FnstCW(NULL, block, frame, noreg, nomem, state);
+ ir_node *spill
+ = new_bd_ia32_FnstCW(NULL, block, frame, noreg, nomem, state);
set_ia32_op_type(spill, ia32_AddrModeD);
/* use mode_Iu, as movl has a shorter opcode than movw */
set_ia32_ls_mode(spill, mode_Iu);
set_ia32_use_frame(spill);
sched_add_after(skip_Proj(after), spill);
+ return spill;
}
- return spill;
+ return NULL;
}
static ir_node *create_fldcw_ent(ir_node *block, ir_entity *entity)
/**
* Reroute edges from the pn_Call_T_result proj of a call.
*
- * @param proj the pn_Call_T_result Proj
- * @param l_res the lower 32 bit result
- * @param h_res the upper 32 bit result or NULL
+ * @param resproj the pn_Call_T_result Proj
+ * @param l_res the lower 32 bit result
+ * @param h_res the upper 32 bit result or NULL
*/
-static void reroute_result(ir_node *proj, ir_node *l_res, ir_node *h_res)
+static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
{
const ir_edge_t *edge, *next;
- foreach_out_edge_safe(proj, edge, next) {
+ foreach_out_edge_safe(resproj, edge, next) {
ir_node *proj = get_edge_src_irn(edge);
long pn = get_Proj_proj(proj);
struct ia32_switch_attr_t {
ia32_attr_t attr; /**< generic attribute */
long default_pn;
+ ir_entity *jump_table;
};
/**
if ((offset & 0xFFFFFF00) == 0) {
/* attr->am_offs += 0; */
} else if ((offset & 0xFFFF00FF) == 0) {
- ir_node *imm = ia32_create_Immediate(NULL, 0, offset >> 8);
- set_irn_n(node, n_ia32_Test_right, imm);
+ ir_node *imm_node = ia32_create_Immediate(NULL, 0, offset>>8);
+ set_irn_n(node, n_ia32_Test_right, imm_node);
attr->am_offs += 1;
} else if ((offset & 0xFF00FFFF) == 0) {
- ir_node *imm = ia32_create_Immediate(NULL, 0, offset >> 16);
- set_irn_n(node, n_ia32_Test_right, imm);
+ ir_node *imm_node = ia32_create_Immediate(NULL, 0, offset>>16);
+ set_irn_n(node, n_ia32_Test_right, imm_node);
attr->am_offs += 2;
} else if ((offset & 0x00FFFFFF) == 0) {
- ir_node *imm = ia32_create_Immediate(NULL, 0, offset >> 24);
- set_irn_n(node, n_ia32_Test_right, imm);
+ ir_node *imm_node = ia32_create_Immediate(NULL, 0, offset>>24);
+ set_irn_n(node, n_ia32_Test_right, imm_node);
attr->am_offs += 3;
} else {
return;
ir_node *val, *mem, *mem_proj;
ir_node *store = stores[i];
ir_node *noreg = ia32_new_NoReg_gp(irg);
- const ir_edge_t *edge;
- const ir_edge_t *next;
val = get_irn_n(store, n_ia32_unary_op);
mem = get_irn_n(store, n_ia32_mem);
# register types:
$normal = 0; # no special type
-$caller_save = 1; # caller save (register must be saved by the caller of a function)
-$callee_save = 2; # callee save (register must be saved by the called function)
-$ignore = 4; # ignore (do not assign this register)
-$arbitrary = 8; # emitter can choose an arbitrary register of this class
-$virtual = 16; # the register is a virtual one
-$state = 32; # register represents a state
+$ignore = 1; # ignore (do not assign this register)
+$arbitrary = 2; # emitter can choose an arbitrary register of this class
+$virtual = 4; # the register is a virtual one
+$state = 8; # register represents a state
# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
%reg_classes = (
gp => [
- { name => "edx", type => $caller_save },
- { name => "ecx", type => $caller_save },
- { name => "eax", type => $caller_save },
- { name => "ebx", type => $callee_save },
- { name => "esi", type => $callee_save },
- { name => "edi", type => $callee_save },
- { name => "ebp", type => $callee_save },
+ { name => "edx" },
+ { name => "ecx" },
+ { name => "eax" },
+ { name => "ebx" },
+ { name => "esi" },
+ { name => "edi" },
+ { name => "ebp" },
{ name => "esp", type => $ignore },
{ name => "gp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_Iu" }
{ mode => "mode_E", flags => "manual_ra" }
],
xmm => [
- { name => "xmm0", type => $caller_save },
- { name => "xmm1", type => $caller_save },
- { name => "xmm2", type => $caller_save },
- { name => "xmm3", type => $caller_save },
- { name => "xmm4", type => $caller_save },
- { name => "xmm5", type => $caller_save },
- { name => "xmm6", type => $caller_save },
- { name => "xmm7", type => $caller_save },
+ { name => "xmm0" },
+ { name => "xmm1" },
+ { name => "xmm2" },
+ { name => "xmm3" },
+ { name => "xmm4" },
+ { name => "xmm5" },
+ { name => "xmm6" },
+ { name => "xmm7" },
{ name => "xmm_NOREG", type => $ignore | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_E" }
],
vfp => [
- { name => "vf0", type => $caller_save },
- { name => "vf1", type => $caller_save },
- { name => "vf2", type => $caller_save },
- { name => "vf3", type => $caller_save },
- { name => "vf4", type => $caller_save },
- { name => "vf5", type => $caller_save },
- { name => "vf6", type => $caller_save },
- { name => "vf7", type => $caller_save },
+ { name => "vf0" },
+ { name => "vf1" },
+ { name => "vf2" },
+ { name => "vf3" },
+ { name => "vf4" },
+ { name => "vf5" },
+ { name => "vf6" },
+ { name => "vf7" },
{ name => "vfp_NOREG", type => $ignore | $arbitrary | $virtual }, # we need a dummy register for NoReg nodes
{ mode => "mode_E" }
],
SwitchJmp => {
state => "pinned",
op_flags => [ "labeled", "cfopcode", "forking" ],
- reg_req => { in => [ "gp" ] },
+ reg_req => { in => [ "gp", "gp" ] },
+ ins => [ "base", "index" ],
mode => "mode_T",
attr_type => "ia32_switch_attr_t",
attr => "long default_pn",
- latency => 3,
+ latency => 2,
units => [ "BRANCH" ],
- modified_flags => $status_flags,
init_attr => "info->out_infos = NULL;", # XXX ugly hack for out requirements
},
if (mode_is_float(mode)) {
ir_node *res = NULL;
ir_node *load;
- ir_node *base;
ir_entity *floatent;
if (ia32_cg_config.use_sse2) {
set_ia32_ls_mode(load, mode);
res = load;
} else {
+ ir_node *base;
#ifdef CONSTRUCT_SSE_CONST
if (mode == mode_D) {
unsigned val = get_tarval_sub_bits(tv, 0) |
}
am->op_type = ia32_AddrModeS;
} else {
- ir_mode *mode;
am->op_type = ia32_Normal;
if (flags & match_try_am) {
static ir_node *create_lea_from_address(dbg_info *dbgi, ir_node *block,
ia32_address_t *addr)
{
- ir_node *base, *index, *res;
+ ir_node *base;
+ ir_node *idx;
+ ir_node *res;
base = addr->base;
if (base == NULL) {
base = be_transform_node(base);
}
- index = addr->index;
- if (index == NULL) {
- index = noreg_GP;
+ idx = addr->index;
+ if (idx == NULL) {
+ idx = noreg_GP;
} else {
- index = be_transform_node(index);
+ idx = be_transform_node(idx);
}
/* segment overrides are ineffective for Leas :-( so we have to patch
addr->tls_segment = false;
}
- res = new_bd_ia32_Lea(dbgi, block, base, index);
+ res = new_bd_ia32_Lea(dbgi, block, base, idx);
set_address(res, addr);
return res;
return gen_unop(node, op, new_bd_ia32_Not, match_mode_neutral);
}
-static ir_node *create_abs(dbg_info *dbgi, ir_node *block, ir_node *op,
- bool negate, ir_node *node)
+static ir_node *create_float_abs(dbg_info *dbgi, ir_node *block, ir_node *op,
+ bool negate, ir_node *node)
{
ir_node *new_block = be_transform_node(block);
ir_mode *mode = get_irn_mode(op);
- ir_node *new_op;
+ ir_node *new_op = be_transform_node(op);
ir_node *new_node;
int size;
ir_entity *ent;
- if (mode_is_float(mode)) {
- new_op = be_transform_node(op);
+ assert(mode_is_float(mode));
- if (ia32_cg_config.use_sse2) {
- ir_node *noreg_fp = ia32_new_NoReg_xmm(current_ir_graph);
- new_node = new_bd_ia32_xAnd(dbgi, new_block, get_symconst_base(),
- noreg_GP, nomem, new_op, noreg_fp);
+ if (ia32_cg_config.use_sse2) {
+ ir_node *noreg_fp = ia32_new_NoReg_xmm(current_ir_graph);
+ new_node = new_bd_ia32_xAnd(dbgi, new_block, get_symconst_base(),
+ noreg_GP, nomem, new_op, noreg_fp);
- size = get_mode_size_bits(mode);
- ent = ia32_gen_fp_known_const(size == 32 ? ia32_SABS : ia32_DABS);
+ size = get_mode_size_bits(mode);
+ ent = ia32_gen_fp_known_const(size == 32 ? ia32_SABS : ia32_DABS);
- set_ia32_am_sc(new_node, ent);
+ set_ia32_am_sc(new_node, ent);
- SET_IA32_ORIG_NODE(new_node, node);
+ SET_IA32_ORIG_NODE(new_node, node);
- set_ia32_op_type(new_node, ia32_AddrModeS);
- set_ia32_ls_mode(new_node, mode);
+ set_ia32_op_type(new_node, ia32_AddrModeS);
+ set_ia32_ls_mode(new_node, mode);
- /* TODO, implement -Abs case */
- assert(!negate);
- } else {
- new_node = new_bd_ia32_vfabs(dbgi, new_block, new_op);
+ /* TODO, implement -Abs case */
+ assert(!negate);
+ } else {
+ new_node = new_bd_ia32_vfabs(dbgi, new_block, new_op);
+ SET_IA32_ORIG_NODE(new_node, node);
+ if (negate) {
+ new_node = new_bd_ia32_vfchs(dbgi, new_block, new_node);
SET_IA32_ORIG_NODE(new_node, node);
- if (negate) {
- new_node = new_bd_ia32_vfchs(dbgi, new_block, new_node);
- SET_IA32_ORIG_NODE(new_node, node);
- }
}
}
ir_mode *mode = get_Load_mode(node);
int throws_exception = ir_throws_exception(node);
ir_node *base;
- ir_node *index;
+ ir_node *idx;
ir_node *new_node;
ia32_address_t addr;
/* construct load address */
memset(&addr, 0, sizeof(addr));
ia32_create_address_mode(&addr, ptr, ia32_create_am_normal);
- base = addr.base;
- index = addr.index;
+ base = addr.base;
+ idx = addr.index;
if (base == NULL) {
base = noreg_GP;
base = be_transform_node(base);
}
- if (index == NULL) {
- index = noreg_GP;
+ if (idx == NULL) {
+ idx = noreg_GP;
} else {
- index = be_transform_node(index);
+ idx = be_transform_node(idx);
}
if (mode_is_float(mode)) {
if (ia32_cg_config.use_sse2) {
- new_node = new_bd_ia32_xLoad(dbgi, block, base, index, new_mem,
+ new_node = new_bd_ia32_xLoad(dbgi, block, base, idx, new_mem,
mode);
} else {
- new_node = new_bd_ia32_vfld(dbgi, block, base, index, new_mem,
+ new_node = new_bd_ia32_vfld(dbgi, block, base, idx, new_mem,
mode);
}
} else {
/* create a conv node with address mode for smaller modes */
if (get_mode_size_bits(mode) < 32) {
- new_node = new_bd_ia32_Conv_I2I(dbgi, block, base, index,
+ new_node = new_bd_ia32_Conv_I2I(dbgi, block, base, idx,
new_mem, noreg_GP, mode);
} else {
- new_node = new_bd_ia32_Load(dbgi, block, base, index, new_mem);
+ new_node = new_bd_ia32_Load(dbgi, block, base, idx, new_mem);
}
}
ir_set_throws_exception(new_node, throws_exception);
ir_node *new_node = new_bd_ia32_Store(dbgi, new_block, addr.base,
addr.index, addr.mem, imm);
- ir_node *mem = new_r_Proj(new_node, mode_M, pn_ia32_Store_M);
+ ir_node *new_mem = new_r_Proj(new_node, mode_M, pn_ia32_Store_M);
ir_set_throws_exception(new_node, throws_exception);
set_irn_pinned(new_node, get_irn_pinned(node));
SET_IA32_ORIG_NODE(new_node, node);
assert(i < 4);
- ins[i++] = mem;
+ ins[i++] = new_mem;
size -= 4;
ofs += 4;
*/
static ir_node *create_Switch(ir_node *node)
{
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *sel = get_Cond_selector(node);
- ir_node *new_sel = be_transform_node(sel);
- long switch_min = LONG_MAX;
- long switch_max = LONG_MIN;
- long default_pn = get_Cond_default_proj(node);
- ir_node *new_node;
- const ir_edge_t *edge;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *sel = get_Cond_selector(node);
+ ir_node *new_sel = be_transform_node(sel);
+ long default_pn = get_Cond_default_proj(node);
+ ir_node *new_node;
+ ir_entity *entity;
assert(get_mode_size_bits(get_irn_mode(sel)) == 32);
- /* determine the smallest switch case value */
- foreach_out_edge(node, edge) {
- ir_node *proj = get_edge_src_irn(edge);
- long pn = get_Proj_proj(proj);
- if (pn == default_pn)
- continue;
-
- if (pn < switch_min)
- switch_min = pn;
- if (pn > switch_max)
- switch_max = pn;
- }
+ entity = new_entity(NULL, id_unique("TBL%u"), get_unknown_type());
+ set_entity_visibility(entity, ir_visibility_private);
+ add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
- if ((unsigned long) (switch_max - switch_min) > 128000) {
- panic("Size of switch %+F bigger than 128000", node);
- }
-
- if (switch_min != 0) {
- /* if smallest switch case is not 0 we need an additional sub */
- new_sel = new_bd_ia32_Lea(dbgi, block, new_sel, noreg_GP);
- add_ia32_am_offs_int(new_sel, -switch_min);
- set_ia32_op_type(new_sel, ia32_AddrModeS);
-
- SET_IA32_ORIG_NODE(new_sel, node);
- }
-
- new_node = new_bd_ia32_SwitchJmp(dbgi, block, new_sel, default_pn);
+ /* TODO: we could perform some more matching here to also use the base
+ * register of the address mode */
+ new_node
+ = new_bd_ia32_SwitchJmp(dbgi, block, noreg_GP, new_sel, default_pn);
+ set_ia32_am_scale(new_node, 2);
+ set_ia32_am_sc(new_node, entity);
+ set_ia32_op_type(new_node, ia32_AddrModeS);
+ set_ia32_ls_mode(new_node, mode_Iu);
SET_IA32_ORIG_NODE(new_node, node);
+ // FIXME This seems wrong. GCC uses PIC for switch on OS X.
+ get_ia32_attr(new_node)->data.am_sc_no_pic_adjust = true;
return new_node;
}
++step;
res->steps[step].transform = SETCC_TR_NEG;
} else {
- int v = get_tarval_lowest_bit(t);
- assert(v >= 0);
+ int val = get_tarval_lowest_bit(t);
+ assert(val >= 0);
res->steps[step].transform = SETCC_TR_SHL;
- res->steps[step].scale = v;
+ res->steps[step].scale = val;
}
}
++step;
node);
} else {
ir_node *op = ir_get_abs_op(sel, mux_true, mux_false);
- return create_abs(dbgi, block, op, is_abs < 0, node);
+ return create_float_abs(dbgi, block, op, is_abs < 0, node);
}
}
static ir_node *gen_prefetch(ir_node *node)
{
dbg_info *dbgi;
- ir_node *ptr, *block, *mem, *base, *index;
+ ir_node *ptr, *block, *mem, *base, *idx;
ir_node *param, *new_node;
long rw, locality;
ir_tarval *tv;
memset(&addr, 0, sizeof(addr));
ptr = get_Builtin_param(node, 0);
ia32_create_address_mode(&addr, ptr, ia32_create_am_normal);
- base = addr.base;
- index = addr.index;
+ base = addr.base;
+ idx = addr.index;
if (base == NULL) {
base = noreg_GP;
base = be_transform_node(base);
}
- if (index == NULL) {
- index = noreg_GP;
+ if (idx == NULL) {
+ idx = noreg_GP;
} else {
- index = be_transform_node(index);
+ idx = be_transform_node(idx);
}
dbgi = get_irn_dbg_info(node);
if (rw == 1 && ia32_cg_config.use_3dnow_prefetch) {
/* we have 3DNow!, this was already checked above */
- new_node = new_bd_ia32_PrefetchW(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_PrefetchW(dbgi, block, base, idx, mem);
} else if (ia32_cg_config.use_sse_prefetch) {
/* note: rw == 1 is IGNORED in that case */
param = get_Builtin_param(node, 2);
/* SSE style prefetch */
switch (locality) {
case 0:
- new_node = new_bd_ia32_PrefetchNTA(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_PrefetchNTA(dbgi, block, base, idx, mem);
break;
case 1:
- new_node = new_bd_ia32_Prefetch2(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_Prefetch2(dbgi, block, base, idx, mem);
break;
case 2:
- new_node = new_bd_ia32_Prefetch1(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_Prefetch1(dbgi, block, base, idx, mem);
break;
default:
- new_node = new_bd_ia32_Prefetch0(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_Prefetch0(dbgi, block, base, idx, mem);
break;
}
} else {
assert(ia32_cg_config.use_3dnow_prefetch);
/* 3DNow! style prefetch */
- new_node = new_bd_ia32_Prefetch(dbgi, block, base, index, mem);
+ new_node = new_bd_ia32_Prefetch(dbgi, block, base, idx, mem);
}
set_irn_pinned(new_node, get_irn_pinned(node));
ir_type *res_tp = get_method_res_type(mtp, j);
ir_node *res, *new_res;
const ir_edge_t *edge, *next;
- ir_mode *mode;
+ ir_mode *res_mode;
if (! is_atomic_type(res_tp)) {
/* no floating point return */
continue;
}
- mode = get_type_mode(res_tp);
- if (! mode_is_float(mode)) {
+ res_mode = get_type_mode(res_tp);
+ if (! mode_is_float(res_mode)) {
/* no floating point return */
continue;
}
dbg_info *db = get_irn_dbg_info(succ);
ir_node *block = get_nodes_block(succ);
ir_node *base = get_irn_n(succ, n_ia32_xStore_base);
- ir_node *index = get_irn_n(succ, n_ia32_xStore_index);
+ ir_node *idx = get_irn_n(succ, n_ia32_xStore_index);
ir_node *mem = get_irn_n(succ, n_ia32_xStore_mem);
ir_node *value = get_irn_n(succ, n_ia32_xStore_val);
ir_mode *mode = get_ia32_ls_mode(succ);
- ir_node *st = new_bd_ia32_vfst(db, block, base, index, mem, value, mode);
+ ir_node *st = new_bd_ia32_vfst(db, block, base, idx, mem, value, mode);
//ir_node *mem = new_r_Proj(st, mode_M, pn_ia32_vfst_M);
set_ia32_am_offs_int(st, get_ia32_am_offs_int(succ));
if (is_ia32_use_frame(succ))
/* store st(0) on stack */
vfst = new_bd_ia32_vfst(db, block, frame, noreg_GP, call_mem,
- res, mode);
+ res, res_mode);
set_ia32_op_type(vfst, ia32_AddrModeD);
set_ia32_use_frame(vfst);
/* load into SSE register */
xld = new_bd_ia32_xLoad(db, block, frame, noreg_GP, vfst_mem,
- mode);
+ res_mode);
set_ia32_op_type(xld, ia32_AddrModeS);
set_ia32_use_frame(xld);
- new_res = new_r_Proj(xld, mode, pn_ia32_xLoad_res);
+ new_res = new_r_Proj(xld, res_mode, pn_ia32_xLoad_res);
new_mem = new_r_Proj(xld, mode_M, pn_ia32_xLoad_M);
if (old_mem != NULL) {
op1_idx = x87_on_stack(state, arch_register_get_index(op1));
if (is_vfp_live(arch_register_get_index(op1), live)) {
- ir_node *pred = get_irn_n(n, 0);
-
/* Operand is still live, a real copy. We need here an fpush that can
hold a a register, so use the fpushCopy or recreate constants */
node = create_Copy(state, n);
push(@obst_unit_tp_defs, "\t$tp_name,\n");
push(@obst_init, "\n\t\t/* init of execution unit type $tp_name */\n");
push(@obst_init, "\t\tcur_unit_tp = &$arch\_execution_unit_types[$tp_name];\n");
- push(@obst_init, "\t\t(void) cur_unit_tp; /* avoid warning */\n");
push(@obst_unit_defs, "/* enum for execution units of type $unit_type */\n");
push(@obst_unit_defs, "enum $arch\_execunit_tp_$unit_type\_vals {\n");
if ($num_unit_types > 0) {
print OUT<<EOF;
-be_execution_unit_type_t $arch\_execution_unit_types[] = {
+static be_execution_unit_type_t $arch\_execution_unit_types[] = {
EOF
}
}
print OUT<<EOF;
-be_machine_t $arch\_cpu = {
+static be_machine_t $arch\_cpu = {
$bundle_size,
$bundles_per_cycle,
$num_unit_types,
static int initialized = 0;
if (! initialized) {
- be_execution_unit_type_t *cur_unit_tp;
+ be_execution_unit_type_t *cur_unit_tp = NULL;
(void) cur_unit_tp; /* avoid warning */
be_machine_init_dummy_unit();
my @types;
if ($t & 1) {
- push(@types, "arch_register_type_caller_save");
- }
-
- if ($t & 2) {
- push(@types, "arch_register_type_callee_save");
- }
-
- if ($t & 4) {
push(@types, "arch_register_type_ignore");
}
- if ($t & 8) {
+ if ($t & 2) {
push(@types, "arch_register_type_joker");
}
- if ($t & 16) {
+ if ($t & 4) {
push(@types, "arch_register_type_virtual");
}
- if ($t & 32) {
+ if ($t & 8) {
push(@types, "arch_register_type_state");
}
for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i);
ir_lower_mode_b(irg, &lower_mode_b_config);
- lower_switch(irg, 256, false);
+ lower_switch(irg, 4, 256, false);
}
}
1, /* big endian */
&arch_dep, /* will be set later */
sparc_is_mux_allowed, /* parameter for if conversion */
+ 32, /* machine size */
NULL, /* float arithmetic mode */
+ 128, /* size of long double */
0, /* no trampoline support: size 0 */
0, /* no trampoline support: align 0 */
NULL, /* no trampoline support: no trampoline builder */
sparc_after_ra,
sparc_finish,
sparc_emit_routine,
+ NULL, /* register_saved_by */
};
-BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_sparc);
+BE_REGISTER_MODULE_CONSTRUCTOR(be_init_arch_sparc)
void be_init_arch_sparc(void)
{
be_register_isa_if("sparc", &sparc_isa_if);
REG_Y,
};
+static const arch_register_t* const param_regs[] = {
+ &sparc_registers[REG_I0],
+ &sparc_registers[REG_I1],
+ &sparc_registers[REG_I2],
+ &sparc_registers[REG_I3],
+ &sparc_registers[REG_I4],
+ &sparc_registers[REG_I5],
+};
+
+static const arch_register_t* const float_result_regs[] = {
+ &sparc_registers[REG_F0],
+ &sparc_registers[REG_F1],
+ &sparc_registers[REG_F2],
+ &sparc_registers[REG_F3],
+};
+
/**
* Maps an input register representing the i'th register input
* to the i'th register output.
calling_convention_t *sparc_decide_calling_convention(ir_type *function_type,
ir_graph *irg)
{
- int stack_offset = 0;
+ unsigned stack_offset = 0;
+ unsigned n_param_regs_used = 0;
int n_param_regs = ARRAY_SIZE(param_regs);
int n_float_result_regs = ARRAY_SIZE(float_result_regs);
bool omit_fp = false;
reg = map_i_to_o_reg(reg);
param->reg1 = reg;
} else {
- ir_mode *mode = param_regs[0]->reg_class->mode;
- ir_type *type = get_type_for_mode(mode);
- param->type = type;
- param->offset = stack_offset;
- assert(get_mode_size_bits(mode) == 32);
+ ir_mode *regmode = param_regs[0]->reg_class->mode;
+ ir_type *type = get_type_for_mode(regmode);
+ param->type = type;
+ param->offset = stack_offset;
+ assert(get_mode_size_bits(regmode) == 32);
stack_offset += 4;
}
}
}
+ n_param_regs_used = regnum;
/* determine how results are passed */
n_results = get_method_n_ress(function_type);
cconv = XMALLOCZ(calling_convention_t);
cconv->parameters = params;
cconv->param_stack_size = stack_offset;
+ cconv->n_param_regs = n_param_regs_used;
cconv->results = results;
cconv->omit_fp = omit_fp;
#include "../be_types.h"
#include "gen_sparc_regalloc_if.h"
-static const arch_register_t *const caller_saves[] = {
- &sparc_registers[REG_G1],
- &sparc_registers[REG_G2],
- &sparc_registers[REG_G3],
- &sparc_registers[REG_G4],
- &sparc_registers[REG_O0],
- &sparc_registers[REG_O1],
- &sparc_registers[REG_O2],
- &sparc_registers[REG_O3],
- &sparc_registers[REG_O4],
- &sparc_registers[REG_O5],
-
- &sparc_registers[REG_F0],
- &sparc_registers[REG_F1],
- &sparc_registers[REG_F2],
- &sparc_registers[REG_F3],
- &sparc_registers[REG_F4],
- &sparc_registers[REG_F5],
- &sparc_registers[REG_F6],
- &sparc_registers[REG_F7],
- &sparc_registers[REG_F8],
- &sparc_registers[REG_F9],
- &sparc_registers[REG_F10],
- &sparc_registers[REG_F11],
- &sparc_registers[REG_F12],
- &sparc_registers[REG_F13],
- &sparc_registers[REG_F14],
- &sparc_registers[REG_F15],
- &sparc_registers[REG_F16],
- &sparc_registers[REG_F17],
- &sparc_registers[REG_F18],
- &sparc_registers[REG_F19],
- &sparc_registers[REG_F20],
- &sparc_registers[REG_F21],
- &sparc_registers[REG_F22],
- &sparc_registers[REG_F23],
- &sparc_registers[REG_F24],
- &sparc_registers[REG_F25],
- &sparc_registers[REG_F26],
- &sparc_registers[REG_F27],
- &sparc_registers[REG_F28],
- &sparc_registers[REG_F29],
- &sparc_registers[REG_F30],
- &sparc_registers[REG_F31],
-};
-
-static const arch_register_t *const omit_fp_callee_saves[] = {
- &sparc_registers[REG_L0],
- &sparc_registers[REG_L1],
- &sparc_registers[REG_L2],
- &sparc_registers[REG_L3],
- &sparc_registers[REG_L4],
- &sparc_registers[REG_L5],
- &sparc_registers[REG_L6],
- &sparc_registers[REG_L7],
- &sparc_registers[REG_I0],
- &sparc_registers[REG_I1],
- &sparc_registers[REG_I2],
- &sparc_registers[REG_I3],
- &sparc_registers[REG_I4],
- &sparc_registers[REG_I5],
-};
-
-static const arch_register_t* const param_regs[] = {
- &sparc_registers[REG_I0],
- &sparc_registers[REG_I1],
- &sparc_registers[REG_I2],
- &sparc_registers[REG_I3],
- &sparc_registers[REG_I4],
- &sparc_registers[REG_I5],
-};
-
-static const arch_register_t* const float_result_regs[] = {
- &sparc_registers[REG_F0],
- &sparc_registers[REG_F1],
- &sparc_registers[REG_F2],
- &sparc_registers[REG_F3],
-};
-
/** information about a single parameter or result */
typedef struct reg_or_stackslot_t
{
const arch_register_t *reg1; /**< if != NULL, the second register used. */
ir_type *type; /**< indicates that an entity of the specific
type is needed */
- int offset; /**< if transmitted via stack, the offset for
+ unsigned offset; /**< if transmitted via stack, the offset for
this parameter. */
ir_entity *entity; /**< entity in frame type */
} reg_or_stackslot_t;
bool omit_fp; /**< do not use frame pointer (and no
save/restore) */
reg_or_stackslot_t *parameters; /**< parameter info. */
- int param_stack_size; /**< stack size for parameters */
+ unsigned param_stack_size; /**< stack size for parameters */
+ unsigned n_param_regs; /**< number of values passed in a
+ register */
reg_or_stackslot_t *results; /**< result info. */
} calling_convention_t;
be_emit_finish_line_gas(node);
}
-static void emit_jump_table(const ir_node *node)
+static void emit_sparc_SwitchJmp(const ir_node *node)
{
const sparc_switch_jmp_attr_t *attr = get_sparc_switch_jmp_attr_const(node);
- long switch_max = LONG_MIN;
- long default_pn = attr->default_proj_num;
- ir_entity *entity = attr->jump_table;
- ir_node *default_block = NULL;
- unsigned long length;
- const ir_edge_t *edge;
- unsigned i;
- ir_node **table;
-
- /* go over all proj's and collect them */
- foreach_out_edge(node, edge) {
- ir_node *proj = get_edge_src_irn(edge);
- long pn = get_Proj_proj(proj);
-
- /* check for default proj */
- if (pn == default_pn) {
- assert(default_block == NULL); /* more than 1 default_pn? */
- default_block = get_jump_target(proj);
- } else {
- switch_max = pn > switch_max ? pn : switch_max;
- }
- }
- assert(switch_max > LONG_MIN);
-
- length = (unsigned long) switch_max + 1;
- /* the 16000 isn't a real limit of the architecture. But should protect us
- * from seamingly endless compiler runs */
- if (length > 16000) {
- /* switch lowerer should have broken this monster to pieces... */
- panic("too large switch encountered");
- }
-
- table = XMALLOCNZ(ir_node*, length);
- foreach_out_edge(node, edge) {
- ir_node *proj = get_edge_src_irn(edge);
- long pn = get_Proj_proj(proj);
- if (pn == default_pn)
- continue;
-
- table[pn] = get_jump_target(proj);
- }
-
- /* emit table */
- be_gas_emit_switch_section(GAS_SECTION_RODATA);
- be_emit_cstring("\t.align 4\n");
- be_gas_emit_entity(entity);
- be_emit_cstring(":\n");
- for (i = 0; i < length; ++i) {
- ir_node *block = table[i];
- if (block == NULL)
- block = default_block;
- be_emit_cstring("\t.long ");
- be_gas_emit_block_name(block);
- be_emit_char('\n');
- be_emit_write_line();
- }
- be_gas_emit_switch_section(GAS_SECTION_TEXT);
-
- xfree(table);
-}
-static void emit_sparc_SwitchJmp(const ir_node *node)
-{
be_emit_cstring("\tjmp ");
sparc_emit_source_register(node, 0);
be_emit_finish_line_gas(node);
fill_delay_slot();
- emit_jump_table(node);
+ emit_jump_table(node, attr->default_proj_num, attr->jump_table,
+ get_jump_target);
}
static void emit_fmov(const ir_node *node, const arch_register_t *src_reg,
static const arch_register_t *get_next_fp_reg(const arch_register_t *reg)
{
- unsigned index = reg->global_index;
- assert(reg == &sparc_registers[index]);
- index++;
- assert(index - REG_F0 < N_sparc_fp_REGS);
- return &sparc_registers[index];
+ unsigned idx = reg->global_index;
+ assert(reg == &sparc_registers[idx]);
+ idx++;
+ assert(idx - REG_F0 < N_sparc_fp_REGS);
+ return &sparc_registers[idx];
}
static void emit_be_Copy(const ir_node *node)
*/
static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
{
- const sparc_attr_t *attr;
+ const sparc_attr_t *sparc_attr;
switch (reason) {
case dump_node_opcode_txt:
break;
arch_dump_reqs_and_registers(F, n);
- attr = get_sparc_attr_const(n);
- if (attr->immediate_value_entity) {
+ sparc_attr = get_sparc_attr_const(n);
+ if (sparc_attr->immediate_value_entity) {
ir_fprintf(F, "entity: %+F (offset %d)\n",
- attr->immediate_value_entity, attr->immediate_value);
+ sparc_attr->immediate_value_entity,
+ sparc_attr->immediate_value);
} else {
- ir_fprintf(F, "immediate value: %d\n", attr->immediate_value);
+ ir_fprintf(F, "immediate value: %d\n", sparc_attr->immediate_value);
}
if (sparc_has_load_store_attr(n)) {
const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(n);
return 1;
return attr_a->src_mode != attr_b->src_mode
- || attr_a->dest_mode != attr_b->dest_mode;;
+ || attr_a->dest_mode != attr_b->dest_mode;
}
/* Include the generated constructor functions */
static beabi_helper_env_t *abihelper;
static const arch_register_t *sp_reg = &sparc_registers[REG_SP];
static const arch_register_t *fp_reg = &sparc_registers[REG_FRAME_POINTER];
-static calling_convention_t *cconv = NULL;
+static calling_convention_t *current_cconv = NULL;
static ir_mode *mode_gp;
static ir_mode *mode_flags;
static ir_mode *mode_fp;
//static ir_mode *mode_fp4;
static pmap *node_to_stack;
+static const arch_register_t *const caller_saves[] = {
+ &sparc_registers[REG_G1],
+ &sparc_registers[REG_G2],
+ &sparc_registers[REG_G3],
+ &sparc_registers[REG_G4],
+ &sparc_registers[REG_O0],
+ &sparc_registers[REG_O1],
+ &sparc_registers[REG_O2],
+ &sparc_registers[REG_O3],
+ &sparc_registers[REG_O4],
+ &sparc_registers[REG_O5],
+
+ &sparc_registers[REG_F0],
+ &sparc_registers[REG_F1],
+ &sparc_registers[REG_F2],
+ &sparc_registers[REG_F3],
+ &sparc_registers[REG_F4],
+ &sparc_registers[REG_F5],
+ &sparc_registers[REG_F6],
+ &sparc_registers[REG_F7],
+ &sparc_registers[REG_F8],
+ &sparc_registers[REG_F9],
+ &sparc_registers[REG_F10],
+ &sparc_registers[REG_F11],
+ &sparc_registers[REG_F12],
+ &sparc_registers[REG_F13],
+ &sparc_registers[REG_F14],
+ &sparc_registers[REG_F15],
+ &sparc_registers[REG_F16],
+ &sparc_registers[REG_F17],
+ &sparc_registers[REG_F18],
+ &sparc_registers[REG_F19],
+ &sparc_registers[REG_F20],
+ &sparc_registers[REG_F21],
+ &sparc_registers[REG_F22],
+ &sparc_registers[REG_F23],
+ &sparc_registers[REG_F24],
+ &sparc_registers[REG_F25],
+ &sparc_registers[REG_F26],
+ &sparc_registers[REG_F27],
+ &sparc_registers[REG_F28],
+ &sparc_registers[REG_F29],
+ &sparc_registers[REG_F30],
+ &sparc_registers[REG_F31],
+};
+
+static const arch_register_t *const omit_fp_callee_saves[] = {
+ &sparc_registers[REG_L0],
+ &sparc_registers[REG_L1],
+ &sparc_registers[REG_L2],
+ &sparc_registers[REG_L3],
+ &sparc_registers[REG_L4],
+ &sparc_registers[REG_L5],
+ &sparc_registers[REG_L6],
+ &sparc_registers[REG_L7],
+ &sparc_registers[REG_I0],
+ &sparc_registers[REG_I1],
+ &sparc_registers[REG_I2],
+ &sparc_registers[REG_I3],
+ &sparc_registers[REG_I4],
+ &sparc_registers[REG_I5],
+};
+
static inline bool mode_needs_gp_reg(ir_mode *mode)
{
if (mode_is_int(mode) || mode_is_reference(mode)) {
assert(get_mode_size_bits(mode2) <= 32);
if (is_imm_encodeable(op2)) {
- ir_node *new_op1 = be_transform_node(op1);
int32_t immediate = get_tarval_long(get_Const_tarval(op2));
+ new_op1 = be_transform_node(op1);
if (! (flags & MATCH_MODE_NEUTRAL) && needs_extension(mode1)) {
new_op1 = gen_extension(dbgi, block, new_op1, mode1);
}
assert(match_flags & MATCH_MODE_NEUTRAL);
if (is_imm_encodeable(op2)) {
- ir_node *new_op1 = be_transform_node(op1);
int32_t immediate = get_tarval_long(get_Const_tarval(op2));
+ new_op1 = be_transform_node(op1);
return new_binopx_imm(dbgi, block, new_op1, new_flags, NULL, immediate);
}
new_op2 = be_transform_node(op2);
long default_pn = get_Cond_default_proj(node);
ir_entity *entity;
ir_node *table_address;
- ir_node *index;
+ ir_node *idx;
ir_node *load;
ir_node *address;
set_entity_visibility(entity, ir_visibility_private);
add_entity_linkage(entity, IR_LINKAGE_CONSTANT);
- /* TODO: this code does not construct code to check for access
- * out-of bounds of the jumptable yet. I think we should put this stuff
- * into the switch_lowering phase to get some additional optimisations
- * done. */
-
/* construct base address */
table_address = make_address(dbgi, block, entity, 0);
/* scale index */
- index = new_bd_sparc_Sll_imm(dbgi, block, new_selector, NULL, 2);
+ idx = new_bd_sparc_Sll_imm(dbgi, block, new_selector, NULL, 2);
/* load from jumptable */
- load = new_bd_sparc_Ld_reg(dbgi, block, table_address, index,
+ load = new_bd_sparc_Ld_reg(dbgi, block, table_address, idx,
get_irg_no_mem(current_ir_graph),
mode_gp);
address = new_r_Proj(load, mode_gp, pn_sparc_Ld_res);
ir_node *op = get_Conv_op(node);
ir_mode *src_mode = get_irn_mode(op);
ir_mode *dst_mode = get_irn_mode(node);
- dbg_info *dbg = get_irn_dbg_info(node);
+ dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *new_op;
int src_bits = get_mode_size_bits(src_mode);
if (mode_is_float(src_mode)) {
if (mode_is_float(dst_mode)) {
/* float -> float conv */
- return create_fftof(dbg, block, new_op, src_mode, dst_mode);
+ return create_fftof(dbgi, block, new_op, src_mode, dst_mode);
} else {
/* float -> int conv */
if (!mode_is_signed(dst_mode))
panic("float to unsigned not implemented yet");
- return create_ftoi(dbg, block, new_op, src_mode);
+ return create_ftoi(dbgi, block, new_op, src_mode);
}
} else {
/* int -> float conv */
if (src_bits < 32) {
- new_op = gen_extension(dbg, block, new_op, src_mode);
+ new_op = gen_extension(dbgi, block, new_op, src_mode);
} else if (src_bits == 32 && !mode_is_signed(src_mode)) {
panic("unsigned to float not lowered!");
}
- return create_itof(dbg, block, new_op, dst_mode);
+ return create_itof(dbgi, block, new_op, dst_mode);
}
} else if (src_mode == mode_b) {
panic("ConvB not lowered %+F", node);
}
if (mode_is_signed(min_mode)) {
- return gen_sign_extension(dbg, block, new_op, min_bits);
+ return gen_sign_extension(dbgi, block, new_op, min_bits);
} else {
- return gen_zero_extension(dbg, block, new_op, min_bits);
+ return gen_zero_extension(dbgi, block, new_op, min_bits);
}
}
}
static ir_type *between_type = NULL;
static ir_type *between_type0 = NULL;
- if (cconv->omit_fp) {
+ if (current_cconv->omit_fp) {
if (between_type0 == NULL) {
between_type0
= new_type_class(new_id_from_str("sparc_between_type"));
int n_params;
/* calling conventions must be decided by now */
- assert(cconv != NULL);
+ assert(current_cconv != NULL);
/* construct argument type */
arg_type = new_type_struct(id_mangle_u(get_entity_ident(entity), new_id_from_chars("arg_type", 8)));
n_params = get_method_n_params(function_type);
for (p = 0; p < n_params; ++p) {
- reg_or_stackslot_t *param = &cconv->parameters[p];
+ reg_or_stackslot_t *param = ¤t_cconv->parameters[p];
char buf[128];
ident *id;
layout->arg_type = arg_type;
layout->initial_offset = 0;
layout->initial_bias = 0;
- layout->sp_relative = cconv->omit_fp;
+ layout->sp_relative = current_cconv->omit_fp;
assert(N_FRAME_TYPES == 3);
layout->order[0] = layout->frame_type;
arch_register_req_type_ignore);
/* function parameters in registers */
for (i = 0; i < get_method_n_params(function_type); ++i) {
- const reg_or_stackslot_t *param = &cconv->parameters[i];
+ const reg_or_stackslot_t *param = ¤t_cconv->parameters[i];
if (param->reg0 != NULL) {
be_prolog_add_reg(abihelper, param->reg0,
arch_register_req_type_none);
}
/* we need the values of the callee saves (Note: non omit-fp mode has no
* callee saves) */
- if (cconv->omit_fp) {
+ if (current_cconv->omit_fp) {
size_t n_callee_saves = ARRAY_SIZE(omit_fp_callee_saves);
size_t c;
for (c = 0; c < n_callee_saves; ++c) {
for (i = 0; i < n_res; ++i) {
ir_node *res_value = get_Return_res(node, i);
ir_node *new_res_value = be_transform_node(res_value);
- const reg_or_stackslot_t *slot = &cconv->results[i];
+ const reg_or_stackslot_t *slot = ¤t_cconv->results[i];
const arch_register_t *reg = slot->reg0;
assert(slot->reg1 == NULL);
be_epilog_add_reg(abihelper, reg, arch_register_req_type_none,
new_res_value);
}
/* callee saves */
- if (cconv->omit_fp) {
+ if (current_cconv->omit_fp) {
size_t n_callee_saves = ARRAY_SIZE(omit_fp_callee_saves);
- size_t i;
for (i = 0; i < n_callee_saves; ++i) {
const arch_register_t *reg = omit_fp_callee_saves[i];
ir_node *value
dbg_info *dbgi = get_irn_dbg_info(node);
ir_type *type = get_Call_type(node);
size_t n_params = get_Call_n_params(node);
- size_t n_param_regs = sizeof(param_regs)/sizeof(param_regs[0]);
/* max inputs: memory, callee, register arguments */
- int max_inputs = 2 + n_param_regs;
- ir_node **in = ALLOCAN(ir_node*, max_inputs);
ir_node **sync_ins = ALLOCAN(ir_node*, n_params);
struct obstack *obst = be_get_be_obst(irg);
- const arch_register_req_t **in_req
- = OALLOCNZ(obst, const arch_register_req_t*, max_inputs);
calling_convention_t *cconv
= sparc_decide_calling_convention(type, NULL);
+ size_t n_param_regs = cconv->n_param_regs;
+ unsigned max_inputs = 2 + n_param_regs;
+ ir_node **in = ALLOCAN(ir_node*, max_inputs);
+ const arch_register_req_t **in_req
+ = OALLOCNZ(obst, const arch_register_req_t*, max_inputs);
int in_arity = 0;
int sync_arity = 0;
int n_caller_saves
set_irn_pinned(str, op_pin_state_floats);
sync_ins[sync_arity++] = str;
}
- assert(in_arity <= max_inputs);
+ assert(in_arity <= (int)max_inputs);
/* construct memory input */
if (sync_arity == 0) {
static ir_node *get_frame_base(void)
{
- const arch_register_t *reg = cconv->omit_fp ? sp_reg : fp_reg;
+ const arch_register_t *reg = current_cconv->omit_fp ? sp_reg : fp_reg;
return be_prolog_get_reg_value(abihelper, reg);
}
/* Proj->Proj->Start must be a method argument */
assert(get_Proj_proj(get_Proj_pred(node)) == pn_Start_T_args);
- param = &cconv->parameters[pn];
+ param = ¤t_cconv->parameters[pn];
if (param->reg0 != NULL) {
/* argument transmitted in register */
abihelper = be_abihelper_prepare(irg);
be_collect_stacknodes(abihelper);
- cconv = sparc_decide_calling_convention(get_entity_type(entity), irg);
+ current_cconv
+ = sparc_decide_calling_convention(get_entity_type(entity), irg);
create_stacklayout(irg);
be_transform_graph(irg, NULL);
be_abihelper_finish(abihelper);
- sparc_free_calling_convention(cconv);
+ sparc_free_calling_convention(current_cconv);
frame_type = get_irg_frame_type(irg);
if (get_type_state(frame_type) == layout_undefined)
#include <stddef.h>
-static inline void _time_get(ir_timer_val_t *val);
static inline void _time_reset(ir_timer_val_t *val);
-static inline unsigned long _time_to_msec(const ir_timer_val_t *val);
-static inline ir_timer_val_t *_time_add(ir_timer_val_t *res,
- const ir_timer_val_t *lhs, const ir_timer_val_t *rhs);
-static inline ir_timer_val_t *_time_sub(ir_timer_val_t *res,
- const ir_timer_val_t *lhs, const ir_timer_val_t *rhs);
/**
* A timer.
ir_node *block = get_irn_n(div, -1);
ir_mode *mode = get_irn_mode(n);
int bits = get_mode_size_bits(mode);
- ir_node *q, *t, *c;
+ ir_node *q;
/* Beware: do not transform bad code */
if (is_Bad(n) || is_Bad(block))
struct ms mag = magic(tv);
/* generate the Mulh instruction */
- c = new_r_Const(irg, mag.M);
+ ir_node *c = new_r_Const(irg, mag.M);
+ ir_node *t;
q = new_rd_Mulh(dbg, block, n, c, mode);
/* do we need an Add or Sub */
q = new_rd_Add(dbg, block, q, t, mode);
} else {
struct mu mag = magicu(tv);
- ir_node *c;
ir_graph *irg = get_irn_irg(div);
/* generate the Mulh instruction */
- c = new_r_Const(irg, mag.M);
+ ir_node *c = new_r_Const(irg, mag.M);
q = new_rd_Mulh(dbg, block, n, c, mode);
if (mag.need_add) {
if (mag.s > 0) {
/* use the GM scheme */
- t = new_rd_Sub(dbg, block, n, q, mode);
+ ir_node *t = new_rd_Sub(dbg, block, n, q, mode);
c = new_r_Const(irg, get_mode_one(mode_Iu));
t = new_rd_Shr(dbg, block, t, c, mode);
res = new_rd_Shrs(dbg, block, curr, k_node, mode);
if (n_flag) { /* negate the result */
- ir_node *k_node;
-
k_node = new_r_Const(irg, get_mode_null(mode));
res = new_rd_Sub(dbg, block, k_node, res, mode);
}
memcpy(res->attr.assem.output_constraints, outputs, sizeof(outputs[0]) * n_outs);
memcpy(res->attr.assem.clobbers, clobber, sizeof(clobber[0]) * n_clobber);
- res = optimize_node(res);
irn_verify_irg(res, irg);
+ res = optimize_node(res);
return res;
}
res->attr.symc.kind = symkind;
res->attr.symc.sym = value;
- res = optimize_node(res);
irn_verify_irg(res, irg);
+ res = optimize_node(res);
return res;
}
int arity = get_irn_arity(block);
/* no predecessors: use unknown value */
if (arity == 0 && block == get_irg_start_block(get_irn_irg(block))) {
- ir_graph *irg = get_irn_irg(block);
if (default_initialize_local_variable != NULL) {
ir_node *rem = get_r_cur_block(irg);
set_r_cur_block(irg, block);
nodes refer to the unoptimized node.
We can call optimize_in_place_2(), as global cse has no effect on blocks.
*/
- block = optimize_in_place_2(block);
irn_verify_irg(block, irg);
+ block = optimize_in_place_2(block);
}
ir_node *new_d_Const_long(dbg_info *db, ir_mode *mode, long value)
res = new_ir_node(dbgi, irg, block, op_Conv, mode, 1, in);
res->attr.conv.strict = 1;
- res = optimize_node(res);
irn_verify_irg(res, irg);
+ res = optimize_node(res);
return res;
}
res->attr.div.resmode = resmode;
res->attr.div.no_remainder = 1;
res->attr.div.exc.pin_state = pin_state;
- res = optimize_node(res);
irn_verify_irg(res, irg);
+ res = optimize_node(res);
return res;
}
break;
default:
- ;
+ break;
} /* end switch */
}
* from irg.
*/
for (i = get_irp_n_irgs(); i > 0;) {
- ir_graph *irg = get_irp_irg(--i);
- ir_node **arr = (ir_node**)ird_get_irg_link(irg);
+ ir_graph *other_irg = get_irp_irg(--i);
+ ir_node **arr = (ir_node**)ird_get_irg_link(other_irg);
if (arr == NULL)
continue;
- dump_graph_from_list(out, irg);
+ dump_graph_from_list(out, other_irg);
DEL_ARR_F(arr);
}
}
print_dbg_info(F, get_entity_dbg_info(ent));
for (i = get_irp_n_irgs(); i > 0;) {
- ir_graph *irg = get_irp_irg(--i);
- list_tuple *lists = (list_tuple*)ird_get_irg_link(irg);
+ ir_graph *other_irg = get_irp_irg(--i);
+ list_tuple *lists = (list_tuple*)ird_get_irg_link(other_irg);
if (lists) {
/* dump the extended blocks first */
if (ARR_LEN(lists->extbb_list)) {
- ird_set_irg_link(irg, lists->extbb_list);
- dump_extblock_graph(F, irg);
+ ird_set_irg_link(other_irg, lists->extbb_list);
+ dump_extblock_graph(F, other_irg);
}
/* we may have blocks without extended blocks, bad for instance */
if (ARR_LEN(lists->blk_list)) {
- ird_set_irg_link(irg, lists->blk_list);
- dump_block_graph(F, irg);
+ ird_set_irg_link(other_irg, lists->blk_list);
+ dump_block_graph(F, other_irg);
}
DEL_ARR_F(lists->extbb_list);
{
FILE *F = (FILE*)env;
int i;
- ir_node *pred;
if (is_Bad(block) && get_irn_mode(block) == mode_X) {
dump_node(F, block);
/* Dump dominator/postdominator edge */
if (ir_get_dump_flags() & ir_dump_flag_dominance) {
if (get_irg_dom_state(current_ir_graph) == dom_consistent && get_Block_idom(block)) {
- pred = get_Block_idom(block);
+ ir_node *pred = get_Block_idom(block);
fprintf(F, "edge: { sourcename: \"");
PRINT_NODEID(block);
fprintf(F, "\" targetname: \"");
fprintf(F, "\" " DOMINATOR_EDGE_ATTR "}\n");
}
if (get_irg_postdom_state(current_ir_graph) == dom_consistent && get_Block_ipostdom(block)) {
- pred = get_Block_ipostdom(block);
+ ir_node *pred = get_Block_ipostdom(block);
fprintf(F, "edge: { sourcename: \"");
PRINT_NODEID(block);
fprintf(F, "\" targetname: \"");
/* Write the irnode and all its attributes to the file passed. */
void dump_irnode_to_file(FILE *F, ir_node *n)
{
- int i;
char comma;
ir_graph *irg;
vrp_attr *vrp_info;
if (ir_get_dump_flags() & ir_dump_flag_analysed_types)
fprintf (F, " addr: %p\n", (void *)n);
fprintf (F, " mode: %s\n", get_mode_name(get_irn_mode(n)));
- fprintf (F, " visited: %ld\n", get_irn_visited(n));
+ fprintf (F, " visited: %lu\n", get_irn_visited(n));
irg = get_irn_irg(n);
if (irg != get_const_code_irg())
fprintf (F, " irg: %s\n", get_ent_dump_name(get_irg_entity(irg)));
dump_node_opcode(F, get_irn_n(n, -1));
fprintf(F, " %ld\n", get_irn_node_nr(get_irn_n(n, -1)));
}
- for ( i = 0; i < get_irn_arity(n); ++i) {
- fprintf(F, " %d: %s ", i, is_backedge(n, i) ? "be" : " ");
- dump_node_opcode(F, get_irn_n(n, i));
- fprintf(F, " %ld\n", get_irn_node_nr(get_irn_n(n, i)));
+
+ {
+ int i;
+ for (i = 0; i < get_irn_arity(n); ++i) {
+ fprintf(F, " %d: %s ", i, is_backedge(n, i) ? "be" : " ");
+ dump_node_opcode(F, get_irn_n(n, i));
+ fprintf(F, " %ld\n", get_irn_node_nr(get_irn_n(n, i)));
+ }
}
fprintf(F, " Private Attributes:\n");
}
/* This is not nice, output it as a marker in the predecessor list. */
- if (is_Block(n) ||
- get_irn_op(n) == op_Phi) {
+ if (is_Block(n) || get_irn_op(n) == op_Phi) {
+ int i;
fprintf(F, " backedges:");
comma = ' ';
for (i = 0; i < get_irn_arity(n); i++)
case iro_Block: {
if (has_Block_entity(n))
fprintf(F, " Label: %lu\n", get_entity_label(get_Block_entity(n)));
- fprintf(F, " block visited: %ld\n", get_Block_block_visited(n));
+ fprintf(F, " block visited: %lu\n", get_Block_block_visited(n));
fprintf(F, " block marked: %u\n", get_Block_mark(n));
if (get_irg_dom_state(get_irn_irg(n)) == dom_consistent) {
fprintf(F, " dom depth %d\n", get_Block_dom_depth(n));
- fprintf(F, " domtree pre num %d\n", get_Block_dom_tree_pre_num(n));
- fprintf(F, " max subtree pre num %d\n", get_Block_dom_max_subtree_pre_num(n));
+ fprintf(F, " domtree pre num %u\n", get_Block_dom_tree_pre_num(n));
+ fprintf(F, " max subtree pre num %u\n", get_Block_dom_max_subtree_pre_num(n));
}
if (get_irg_postdom_state(get_irn_irg(n)) == dom_consistent) {
fprintf(F, " pdom depth %d\n", get_Block_postdom_depth(n));
- fprintf(F, " pdomtree pre num %d\n", get_Block_pdom_tree_pre_num(n));
- fprintf(F, " max pdomsubtree pre num %d\n", get_Block_pdom_max_subtree_pre_num(n));
+ fprintf(F, " pdomtree pre num %u\n", get_Block_pdom_tree_pre_num(n));
+ fprintf(F, " max pdomsubtree pre num %u\n", get_Block_pdom_max_subtree_pre_num(n));
}
fprintf(F, " Execution frequency statistics:\n");
fprintf(F, " assembler text: %s", get_id_str(get_ASM_text(n)));
l = get_ASM_n_input_constraints(n);
if (l > 0) {
+ int i;
fprintf(F, "\n inputs: ");
cons = get_ASM_input_constraints(n);
for (i = 0; i < l; ++i)
}
l = get_ASM_n_output_constraints(n);
if (l > 0) {
+ int i;
fprintf(F, "\n outputs: ");
cons = get_ASM_output_constraints(n);
for (i = 0; i < l; ++i)
}
l = get_ASM_n_clobbers(n);
if (l > 0) {
+ int i;
fprintf(F, "\n clobber: ");
clobber = get_ASM_clobbers(n);
for (i = 0; i < l; ++i)
size_t j;
compound_graph_path *path = get_compound_ent_value_path(ent, i);
ir_entity *ent0 = get_compound_graph_path_node(path, 0);
- fprintf(F, "\n%s %3d:%u ", prefix, get_entity_offset(ent0), get_entity_offset_bits_remainder(ent0));
+ fprintf(F, "\n%s %3d:%d ", prefix, get_entity_offset(ent0), get_entity_offset_bits_remainder(ent0));
if (get_type_state(type) == layout_fixed)
fprintf(F, "(%3u:%u) ", get_compound_ent_value_offset_bytes(ent, i), get_compound_ent_value_offset_bit_remainder(ent, i));
fprintf(F, "%s", get_entity_name(ent));
case tpo_array:
if (verbosity & dump_verbosity_typeattrs) {
- size_t i, n_dim;
+ size_t n_dim;
ir_type *elem_tp = get_array_element_type(tp);
fprintf(F, "\n array ");
irg_edge_info_t *info;
ir_edgeset_t *edges;
ir_edge_t templ;
- ir_edge_t *edge;
assert(edges_activated_kind(irg, kind));
*/
if (tgt == NULL) {
/* search the edge in the set. */
- edge = ir_edgeset_find(edges, &templ);
+ ir_edge_t *edge = ir_edgeset_find(edges, &templ);
/* mark the edge invalid if it was found */
if (edge) {
/* If the old target is not null, the edge is moved. */
if (old_tgt) {
- edge = ir_edgeset_find(edges, &templ);
+ ir_edge_t *edge = ir_edgeset_find(edges, &templ);
assert(edge && "edge to redirect not found!");
assert(! edge->invalid && "Invalid edge encountered");
const ir_edge_t *next;
foreach_out_edge_kind_safe(old_tgt, edge, next, EDGE_KIND_BLOCK) {
ir_node *succ = get_edge_src_irn(edge);
- int pos = get_edge_src_pos(edge);
- ir_node *block_pred = get_Block_cfgpred(succ, pos);
+ int succ_pos = get_edge_src_pos(edge);
+ ir_node *block_pred = get_Block_cfgpred(succ, succ_pos);
if (block_pred != src)
continue;
- edges_notify_edge_kind(succ, pos, tgt, old_tgt,
+ edges_notify_edge_kind(succ, succ_pos, tgt, old_tgt,
EDGE_KIND_BLOCK, irg);
}
}
return;
}
- for (p = hooks[hook]; p && p->next != entry; p = p->next);
+ for (p = hooks[hook]; p && p->next != entry; p = p->next) {
+ }
if (p) {
p->next = entry->next;
default:
panic("export_type_or_ent_post: Unknown type or entity.");
- break;
}
}
default:
parse_error(env, "Unknown escape sequence '\\%c'\n", env->c);
exit(1);
- break;
}
} else {
obstack_1grow(&env->obst, env->c);
type = new_type_method(nparams, nresults);
for (i = 0; i < nparams; i++) {
- long typenr = read_long(env);
- ir_type *paramtype = get_type(env, typenr);
+ long ptypenr = read_long(env);
+ ir_type *paramtype = get_type(env, ptypenr);
set_method_param_type(type, i, paramtype);
}
for (i = 0; i < nresults; i++) {
- long typenr = read_long(env);
- ir_type *restype = get_type(env, typenr);
+ long ptypenr = read_long(env);
+ ir_type *restype = get_type(env, ptypenr);
set_method_res_type(type, i, restype);
}
skip_ws(env);
while (!isdigit(env->c)) {
- char *str = read_word(env);
+ char *vstr = read_word(env);
unsigned v;
skip_ws(env);
- v = symbol(str, tt_visibility);
+ v = symbol(vstr, tt_visibility);
if (v != SYMERROR) {
visibility = (ir_visibility)v;
continue;
}
- v = symbol(str, tt_linkage);
+ v = symbol(vstr, tt_linkage);
if (v != SYMERROR) {
linkage |= (ir_linkage)v;
continue;
}
printf("Parser error, expected visibility or linkage, got '%s'\n",
- str);
+ vstr);
break;
}
}
return sm_bits <= lm_bits;
}
- break;
case irms_float_number:
/* int to float works if the float is large enough */
} /* computed_value_Not */
/**
- * Tests wether a shift shifts more bits than available in the mode
+ * Tests whether a shift shifts more bits than available in the mode
*/
static bool is_oversize_shift(const ir_node *n)
{
/**
- * Optimize an "self-inverse unary op", ie op(op(n)) = n.
+ * Optimize an "self-inverse unary op", i.e. op(op(n)) = n.
*
* @todo
* -(-a) == a, but might overflow two times.
b_vrp = vrp_get_info(b);
if (a_vrp && b_vrp) {
- ir_tarval *c = tarval_and(a_vrp->bits_not_set, b_vrp->bits_not_set);
+ ir_tarval *vrp_val = tarval_and(a_vrp->bits_not_set, b_vrp->bits_not_set);
- if (tarval_is_null(c)) {
+ if (tarval_is_null(vrp_val)) {
dbg_info *dbgi = get_irn_dbg_info(n);
return new_rd_Or(dbgi, get_nodes_block(n), a, b, mode);
}
new_shift = new_rd_Shl(dbg_shift, block, new_bitop, shift_right, mode);
} else if (is_Shr(left)) {
new_shift = new_rd_Shr(dbg_shift, block, new_bitop, shift_right, mode);
- } else if (is_Rotl(left)) {
+ } else {
assert(is_Rotl(left));
new_shift = new_rd_Rotl(dbg_shift, block, new_bitop, shift_right, mode);
}
* then we can use that to minimize the value of Add(x, const) or
* Sub(Const, x). In particular this often avoids 1 instruction in some
* backends for the Shift(x, Sub(Const, y)) case because it can be replaced
- * by Shift(x, Minus(y)) which doesnt't need an explicit Const constructed.
+ * by Shift(x, Minus(y)) which does not need an explicit Const constructed.
*/
static ir_node *transform_node_shift_modulo(ir_node *n,
new_shift_func new_shift)
/* no need to keep Bad */
if (is_Bad(ka))
continue;
- /* dont keep unreachable code */
+ /* do not keep unreachable code */
block = is_Block(ka) ? ka : get_nodes_block(ka);
if (is_block_unreachable(block))
continue;
CASE_PROJ_EX(Load);
CASE_PROJ_EX(Mod);
default:
- /* leave NULL */;
+ break;
}
return ops;
/* for pinned nodes, the block inputs must be equal */
if (get_irn_n(a, -1) != get_irn_n(b, -1))
return 1;
- } else if (! get_opt_global_cse()) {
- /* for block-local CSE both nodes must be in the same Block */
- if (get_nodes_block(a) != get_nodes_block(b))
- return 1;
+ } else {
+ ir_node *block_a = get_nodes_block(a);
+ ir_node *block_b = get_nodes_block(b);
+ if (! get_opt_global_cse()) {
+ /* for block-local CSE both nodes must be in the same Block */
+ if (block_a != block_b)
+ return 1;
+ } else {
+ /* The optimistic approach would be to do nothing here.
+ * However doing GCSE optimistically produces a lot of partially dead code which appears
+ * to be worse in practice than the missed opportunities.
+ * So we use a very conservative variant here and only CSE if 1 value dominates the
+ * other. */
+ if (!block_dominates(block_a, block_b)
+ && !block_dominates(block_b, block_a))
+ return 1;
+ }
}
/* compare a->in[0..ins] with b->in[0..ins] */
ASSERT_AND_RET_DBG(
/* Sel: BB x M x ref x int^n --> ref */
(op1mode == mode_M && op2mode == mymode && mode_is_reference(mymode)),
- "Sel node", 0, show_node_failure(n)
+ "Sel node", 0, show_node_failure(n);
);
for (i = get_Sel_n_indexs(n) - 1; i >= 0; --i) {
- ASSERT_AND_RET_DBG(mode_is_int(get_irn_mode(get_Sel_index(n, i))), "Sel node", 0, show_node_failure(n));
+ ASSERT_AND_RET_DBG(mode_is_int(get_irn_mode(get_Sel_index(n, i))), "Sel node", 0, show_node_failure(n););
}
ent = get_Sel_entity(n);
- ASSERT_AND_RET_DBG(ent, "Sel node with empty entity", 0, show_node_failure(n));
+ ASSERT_AND_RET_DBG(ent, "Sel node with empty entity", 0, show_node_failure(n););
return 1;
}
/* Sync: BB x M^n --> M */
for (i = get_Sync_n_preds(n) - 1; i >= 0; --i) {
ASSERT_AND_RET( get_irn_mode(get_Sync_pred(n, i)) == mode_M, "Sync node", 0 );
- };
+ }
ASSERT_AND_RET( mymode == mode_M, "Sync node", 0 );
return 1;
}
unsigned idx = get_irn_idx(n);
ir_node *node_from_map = get_idx_irn(irg, idx);
ASSERT_AND_RET_DBG(node_from_map == n, "Node index and index map entry differ", 0,
- ir_printf("node %+F node in map %+F(%p)\n", n, node_from_map, node_from_map));
+ ir_printf("node %+F node in map %+F(%p)\n", n, node_from_map, node_from_map);
+ );
}
op = get_irn_op(n);
state == op_pin_state_floats ||
state == op_pin_state_pinned,
"invalid pin state", 0,
- ir_printf("node %+F", n));
+ ir_printf("node %+F", n);
+ );
} else if (!is_Block(n) && is_irn_pinned_in_irg(n)
&& !is_irg_state(irg, IR_GRAPH_STATE_BAD_BLOCK)) {
ASSERT_AND_RET_DBG(is_Block(get_nodes_block(n)) || is_Anchor(n),
"block input is not a block", 0,
- ir_printf("node %+F", n));
+ ir_printf("node %+F", n);
+ );
}
if (op->ops.verify_node)
ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->reachable_blocks, block),
"Block is not reachable by blockwalker (endless loop with no kept block?)", 0,
- ir_printf("block %+F\n", block));
+ ir_printf("block %+F\n", block);
+ );
n_cfgpreds = get_Block_n_cfgpreds(block);
branch_nodes = env->branch_nodes;
former_dest = pmap_get(branch_nodes, branch);
ASSERT_AND_RET_DBG(former_dest==NULL || is_unknown_jump(skip_Proj(branch)),
"Multiple users on mode_X node", 0,
- ir_printf("node %+F\n", branch));
+ ir_printf("node %+F\n", branch);
+ );
pmap_insert(branch_nodes, branch, (void*)block);
/* check that there's only 1 branching instruction in each block */
ASSERT_AND_RET_DBG(former_branch == NULL || former_branch == branch,
"Multiple branching nodes in a block", 0,
ir_printf("nodes %+F,%+F in block %+F\n",
- branch, former_branch, branch_block));
+ branch, former_branch, branch_block);
+ );
pmap_insert(branch_nodes, branch_block, branch);
if (is_Cond(branch)) {
if (pn == pn_Cond_false)
ir_nodeset_insert(&env->false_projs, branch);
} else {
- int default_pn = get_Cond_default_proj(branch);
+ long default_pn = get_Cond_default_proj(branch);
if (pn == default_pn)
ir_nodeset_insert(&env->true_projs, branch);
}
|| ir_nodeset_contains(&env->kept_nodes, block)
|| block == get_irg_end_block(get_irn_irg(block)),
"block contains no cfop", 0,
- ir_printf("block %+F\n", block));
+ ir_printf("block %+F\n", block);
+ );
return 1;
}
if (get_irn_mode(get_Cond_selector(cond)) == mode_b) {
ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, cond),
"Cond node lacks true proj", 0,
- ir_printf("Cond %+F\n", cond));
+ ir_printf("Cond %+F\n", cond);
+ );
ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->false_projs, cond),
"Cond node lacks false proj", 0,
- ir_printf("Cond %+F\n", cond));
+ ir_printf("Cond %+F\n", cond);
+ );
} else {
ASSERT_AND_RET_DBG(ir_nodeset_contains(&env->true_projs, cond),
"Cond node lacks default Proj", 0,
- ir_printf("Cond %+F\n", cond));
+ ir_printf("Cond %+F\n", cond);
+ );
}
return 1;
}
CASE(CopyB);
CASE(Bound);
default:
- /* leave NULL */;
+ break;
}
#undef CASE
CASE(CopyB);
CASE(Bound);
default:
- /* leave NULL */;
+ break;
}
#undef CASE
}
do { \
if (!(expr)) { \
firm_verify_failure_msg = #expr " && " string; \
- if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
+ if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk } \
if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
fprintf(stderr, #expr " : " string "\n"); \
else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
break;
default:
panic("Only nodes with degree one or two should be in this bucket");
- break;
}
}
}
#include "timing.h"
pbqp_edge_t **edge_bucket;
-pbqp_edge_t **rm_bucket;
+static pbqp_edge_t **rm_bucket;
pbqp_node_t **node_buckets[4];
pbqp_node_t **reduced_bucket = NULL;
pbqp_node_t *merged_node = NULL;
unsigned *mapping;
unsigned src_len;
unsigned tgt_len;
- unsigned src_index;
unsigned tgt_index;
unsigned edge_index;
unsigned edge_len;
/* Check that each column has at most one zero entry. */
for (tgt_index = 0; tgt_index < tgt_len; ++tgt_index) {
unsigned onlyOneZero = 0;
+ unsigned src_index;
if (tgt_vec->entries[tgt_index].data == INF_COSTS)
continue;
vector_t *other_vec;
unsigned other_len;
unsigned other_index;
- unsigned tgt_index;
assert(old_edge);
if (old_edge == edge)
unsigned src_len;
unsigned tgt_len;
unsigned src_index;
- unsigned tgt_index;
unsigned edge_index;
unsigned edge_len;
/* Check that each row has at most one zero entry. */
for (src_index = 0; src_index < src_len; ++src_index) {
unsigned onlyOneZero = 0;
+ unsigned tgt_index;
if (src_vec->entries[src_index].data == INF_COSTS)
continue;
vector_t *other_vec;
unsigned other_len;
unsigned other_index;
- unsigned src_index;
assert(old_edge);
break;
default:
panic("Only nodes with degree one or two should be in this bucket");
- break;
}
}
}
#if KAPS_USE_UNSIGNED
typedef unsigned num;
- static const num INF_COSTS = UINT_MAX;
+ #define INF_COSTS UINT_MAX
#else
typedef intmax_t num;
- static const num INF_COSTS = INTMAX_MAX;
+ #define INF_COSTS INTMAX_MAX
#endif
#include "matrix_t.h"
#include <stdio.h>
#include <string.h>
-#include "lc_common_t.h"
#include "lc_defines.h"
#include "lc_printf.h"
app->init(env);
}
-static void default_init(UNUSED(lc_appendable_t *env))
+static void default_init(lc_appendable_t *env)
{
+ (void) env;
}
-static void default_finish(UNUSED(lc_appendable_t *env))
+static void default_finish(lc_appendable_t *env)
{
+ (void) env;
}
/*
+++ /dev/null
-/*
- libcore: library for basic data structures and algorithms.
- Copyright (C) 2005 IPD Goos, Universit"at Karlsruhe, Germany
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
-
-#ifndef _COMMON_T_H
-#define _COMMON_T_H
-
-#include <obstack.h>
-#include <stdarg.h>
-#include <stdio.h>
-
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
-
-#define bcopy(src,dest,n) memcpy(dest,src,n)
-
-#include "lc_config.h"
-
-#define FUNCNAME LC_FUNCNAME
-#define UNUSED(x) LC_UNUSED(x)
-#define LONGLONG long /* LC_LONGLONG */
-#define LONGDOUBLE double /* LC_LONGDOUBLE */
-
-#ifdef _WIN32
-/* Windows names for non-POSIX calls */
-#define snprintf _snprintf
-#define vsnprintf _vsnprintf
-#endif /* WIN32 */
-
-#endif /* _COMMON_T_H */
#define inline __inline__
#define LC_FUNCNAME __FUNCTION__
-#define LC_UNUSED(x) x __attribute__((__unused__))
#define LC_PRINTF(m) __attribute__((format(printf,m,(m)+1)))
#ifdef __STRICT_ANSI__
#elif defined(_MSC_VER)
#define LC_FUNCNAME "<unknown>"
-#define LC_UNUSED(x) x
#define LC_PRINTF(m)
#define LC_LONGLONG __int64
#define inline
#define LC_FUNCNAME "<unknown>"
-#define LC_UNUSED(x)
#define LC_LONGLONG long
#define LC_LONGDOUBLE double
#define LC_PRINTF(m)
#include <string.h>
#include <ctype.h>
-#ifdef _WIN32
-#include <malloc.h>
-#endif
-
-/* Includes to determine user's home directory */
-#ifdef _WIN32
-#include <shlobj.h>
-#else
-#include <sys/types.h>
-#include <unistd.h>
-#include <pwd.h>
-#endif
-
-/* maximum length of a path. */
-#ifndef MAX_PATH
-#define MAX_PATH 2048
-#endif
-
-
-#include "lc_common_t.h"
#include "lc_opts_t.h"
#include "lc_opts_enum.h"
#include "hashptr.h"
#include "lc_printf.h"
#include "xmalloc.h"
+#include "obst.h"
#define ERR_STRING "In argument \"%s\": "
return buf;
}
-int lc_opt_std_cb(UNUSED(const char *name), lc_opt_type_t type, void *data, size_t length, ...)
+int lc_opt_std_cb(const char *name, lc_opt_type_t type, void *data, size_t length, ...)
{
va_list args;
int res = 0;
int integer;
+ (void) name;
va_start(args, length);
return res;
}
-int lc_opt_std_dump(char *buf, size_t n, UNUSED(const char *name), lc_opt_type_t type, void *data, UNUSED(size_t length))
+int lc_opt_std_dump(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t length)
{
int res;
+ (void) name;
+ (void) length;
if (data) {
switch (type) {
return res;
}
-int lc_opt_bool_dump_vals(char *buf, size_t n, UNUSED(const char *name), UNUSED(lc_opt_type_t type), UNUSED(void *data), UNUSED(size_t length))
+int lc_opt_bool_dump_vals(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t length)
{
+ (void) name;
+ (void) type;
+ (void) data;
+ (void) length;
strncpy(buf, "true, false", n);
return n;
}
return options_set;
}
-static int opt_arg_type(UNUSED(const lc_arg_occ_t *occ))
+static int opt_arg_type(const lc_arg_occ_t *occ)
{
+ (void) occ;
return lc_arg_type_ptr;
}
#include <stdio.h>
#include <string.h>
-#ifdef _WIN32
-#include <malloc.h>
-#endif
-
#include "lc_opts_t.h"
#include "lc_opts_enum.h"
+#include "xmalloc.h"
static const char *delim = " \t|,";
#define DECL_CB(N, op) \
-int lc_opt_enum_ ## N ## _cb(LC_UNUSED(const char *name), LC_UNUSED(lc_opt_type_t type), void *data, size_t len, ...) \
+int lc_opt_enum_ ## N ## _cb(const char *name, lc_opt_type_t type, void *data, size_t len, ...) \
{ \
lc_opt_enum_ ## N ## _var_t *var = (lc_opt_enum_ ## N ## _var_t*)data; \
const lc_opt_enum_ ## N ## _items_t *items = var->items; \
const char *arg; \
int res = 0; \
\
+ (void) name; \
+ (void) type; \
va_start(args, len); \
arg = va_arg(args, const char *); \
va_end(args); \
DECL_CB(func_ptr, =)
#define DECL_DUMP(T, N, cond) \
-int lc_opt_enum_ ## N ## _dump(char *buf, size_t n, LC_UNUSED(const char *name), LC_UNUSED(lc_opt_type_t type), void *data, LC_UNUSED(size_t len)) \
+int lc_opt_enum_ ## N ## _dump(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t len) \
{ \
lc_opt_enum_ ## N ## _var_t *var = (lc_opt_enum_ ## N ## _var_t*)data; \
const lc_opt_enum_ ## N ## _items_t *items = var->items; \
TYPE(value) = *var->value; \
int i; \
size_t l = strlen(buf); \
+ (void) name; \
+ (void) type; \
+ (void) len; \
\
if (l >= n) \
return (int)l; \
#define DECL_DUMP_VALS(T, N) \
-int lc_opt_enum_ ## N ## _dump_vals(char *buf, size_t n, LC_UNUSED(const char *name), LC_UNUSED(lc_opt_type_t type), void *data, LC_UNUSED(size_t len)) \
+int lc_opt_enum_ ## N ## _dump_vals(char *buf, size_t n, const char *name, lc_opt_type_t type, void *data, size_t len) \
{ \
lc_opt_enum_ ## N ## _var_t *var = (lc_opt_enum_ ## N ## _var_t*) data; \
const lc_opt_enum_ ## N ## _items_t *items = var->items; \
const char *prefix = ""; \
int i; \
size_t l = strlen(buf); \
+ (void) name; \
+ (void) type; \
+ (void) len; \
\
if (l >= n) \
return (int)l; \
#include "lc_opts.h"
#include "list.h"
-#include "lc_common_t.h"
#include "lc_defines.h"
typedef struct {
#include <assert.h>
#include <ctype.h>
-#include "lc_common_t.h"
#include "xmalloc.h"
#include "lc_printf.h"
#include "lc_defines.h"
return _lc_arg_get_default_env();
}
-static int lc_arg_cmp(const void *p1, const void *p2, UNUSED(size_t size))
+static int lc_arg_cmp(const void *p1, const void *p2, size_t size)
{
const lc_arg_t *a1 = (const lc_arg_t*)p1;
const lc_arg_t *a2 = (const lc_arg_t*)p2;
+ (void) size;
return strcmp(a1->name, a2->name);
}
return ent != NULL;
}
-void lc_arg_unregister(UNUSED(lc_arg_env_t *env), UNUSED(const char *name))
+void lc_arg_unregister(lc_arg_env_t *env, const char *name)
{
+ (void) env;
+ (void) name;
}
int lc_arg_append(lc_appendable_t *app, const lc_arg_occ_t *occ, const char *str, size_t len)
return modlen > 1 && mod[1] == 'h' ? lc_arg_type_char : lc_arg_type_short;
case 'l':
return modlen > 1 && mod[1] == 'l' ? lc_arg_type_long_long : lc_arg_type_long;
-#define TYPE_CASE(letter,type) case letter: return lc_arg_type_ ## type;
+#define TYPE_CASE(letter,type) case letter: return lc_arg_type_ ## type
TYPE_CASE('j', intmax_t);
TYPE_CASE('z', size_t);
TYPE_CASE('t', ptrdiff_t);
/* read the precision if given */
if (*s == '.') {
- int val;
- s = read_int(s + 1, &val);
+ int precision;
+ s = read_int(s + 1, &precision);
/* Negative or lacking precision after a '.' is treated as
* precision 0. */
- occ.precision = LC_MAX(0, val);
+ occ.precision = LC_MAX(0, precision);
}
/*
const char *named = ++s;
/* Read until the closing brace or end of the string. */
- for (ch = *s; ch != '}' && ch != '\0'; ch = *++s);
+ for (ch = *s; ch != '}' && ch != '\0'; ch = *++s) {
+ }
if (s - named) {
size_t n = s - named;
{
cl_entry *res = (cl_entry*)get_irn_link(call);
if (res == NULL) {
- cl_entry *res = OALLOC(&env->obst, cl_entry);
+ res = OALLOC(&env->obst, cl_entry);
res->next = env->cl_list;
res->call = call;
res->copyb = NULL;
set_irn_in(ret, j, new_in);
if (n_cr_opt > 0) {
- size_t i, n;
+ size_t c;
+ size_t n;
irg_walk_graph(irg, NULL, do_copy_return_opt, cr_opt);
- for (i = 0, n = ARR_LEN(cr_opt); i < n; ++i) {
- free_entity(cr_opt[i].ent);
+ for (c = 0, n = ARR_LEN(cr_opt); c < n; ++c) {
+ free_entity(cr_opt[c].ent);
}
}
}
ir_graph *irg = get_irn_irg(node);
ir_node *adr = get_Load_ptr(node);
ir_node *mem = get_Load_mem(node);
- ir_node *low, *high, *proj;
+ ir_node *low;
+ ir_node *high;
+ ir_node *proj_m;
dbg_info *dbg;
ir_node *block = get_nodes_block(node);
ir_cons_flags volatility = get_Load_volatility(node) == volatility_is_volatile
}
/* create two loads */
- dbg = get_irn_dbg_info(node);
- low = new_rd_Load(dbg, block, mem, low, low_mode, volatility);
- proj = new_r_Proj(low, mode_M, pn_Load_M);
- high = new_rd_Load(dbg, block, proj, high, mode, volatility);
+ dbg = get_irn_dbg_info(node);
+ low = new_rd_Load(dbg, block, mem, low, low_mode, volatility);
+ proj_m = new_r_Proj(low, mode_M, pn_Load_M);
+ high = new_rd_Load(dbg, block, proj_m, high, mode, volatility);
foreach_out_edge_safe(node, edge, next) {
ir_node *proj = get_edge_src_irn(edge);
{
ir_graph *irg;
ir_node *block, *adr, *mem;
- ir_node *low, *high, *proj;
+ ir_node *low, *high, *proj_m;
dbg_info *dbg;
ir_node *value = get_Store_value(node);
const lower64_entry_t *entry = get_node_entry(value);
}
/* create two Stores */
- dbg = get_irn_dbg_info(node);
- low = new_rd_Store(dbg, block, mem, low, entry->low_word, volatility);
- proj = new_r_Proj(low, mode_M, pn_Store_M);
- high = new_rd_Store(dbg, block, proj, high, entry->high_word, volatility);
+ dbg = get_irn_dbg_info(node);
+ low = new_rd_Store(dbg, block, mem, low, entry->low_word, volatility);
+ proj_m = new_r_Proj(low, mode_M, pn_Store_M);
+ high = new_rd_Store(dbg, block, proj_m, high, entry->high_word, volatility);
foreach_out_edge_safe(node, edge, next) {
ir_node *proj = get_edge_src_irn(edge);
panic("Shr lowering only implemented for two-complement modes");
}
+ block = get_nodes_block(node);
+
/* if the right operand is a 64bit value, we're only interested in the
* lower word */
if (get_irn_mode(right) == env->high_unsigned) {
right = get_lowered_low(right);
} else {
/* shift should never have signed mode on the right */
- ir_node *block = get_nodes_block(node);
assert(get_irn_mode(right) != env->high_signed);
right = create_conv(block, right, low_unsigned);
}
ir_node *res_low = new_rd_shrs(dbgi, block_false, conv, right,
low_unsigned);
int cnsti = modulo_shift2-1;
- ir_node *cnst = new_r_Const_long(irg, low_unsigned, cnsti);
+ ir_node *cnst2 = new_r_Const_long(irg, low_unsigned, cnsti);
ir_node *res_high;
if (new_rd_shrs == new_rd_Shrs) {
- res_high = new_rd_shrs(dbgi, block_false, left_high, cnst, mode);
+ res_high = new_rd_shrs(dbgi, block_false, left_high, cnst2, mode);
} else {
res_high = new_r_Const(irg, get_mode_null(mode));
}
/**
* Translate a Cond.
*/
-static void lower_Cond(ir_node *node, ir_mode *mode)
+static void lower_Cond(ir_node *node, ir_mode *high_mode)
{
ir_node *left, *right, *block;
ir_node *sel = get_Cond_selector(node);
ir_mode *m = get_irn_mode(sel);
ir_mode *cmp_mode;
const lower64_entry_t *lentry, *rentry;
- ir_node *proj, *projT = NULL, *projF = NULL;
+ ir_node *projT = NULL, *projF = NULL;
ir_node *new_bl, *irn;
ir_node *projHF, *projHT;
ir_node *dst_blk;
const ir_edge_t *edge;
const ir_edge_t *next;
- (void) mode;
+ (void) high_mode;
if (m != mode_b) {
if (m == env->high_signed || m == env->high_unsigned) {
}
if (relation == ir_relation_equal) {
+ ir_node *proj;
/* simple case:a == b <==> a_h == b_h && a_l == b_l */
dst_blk = get_cfop_destination(projF);
mark_irn_visited(proj);
exchange(projT, proj);
} else if (relation == ir_relation_less_greater) {
+ ir_node *proj;
/* simple case:a != b <==> a_h != b_h || a_l != b_l */
dst_blk = get_cfop_destination(projT);
mark_irn_visited(proj);
exchange(projF, proj);
} else {
+ ir_node *proj;
/* a rel b <==> a_h REL b_h || (a_h == b_h && a_l rel b_l) */
ir_node *dstT, *dstF, *newbl_eq, *newbl_l;
ir_node *projEqF;
*/
static void lower_Cmp(ir_node *cmp, ir_mode *m)
{
- ir_node *l = get_Cmp_left(cmp);
- ir_mode *mode = get_irn_mode(l);
+ ir_node *l = get_Cmp_left(cmp);
+ ir_mode *cmp_mode = get_irn_mode(l);
ir_node *r, *low, *high, *t, *res;
ir_relation relation;
ir_node *block;
const lower64_entry_t *rentry;
(void) m;
- if (mode != env->high_signed && mode != env->high_unsigned)
+ if (cmp_mode != env->high_signed && cmp_mode != env->high_unsigned)
return;
r = get_Cmp_right(cmp);
/* check if this return must be lowered */
for (i = 0, n = get_Return_n_ress(node); i < n; ++i) {
- ir_node *pred = get_Return_res(node, i);
- ir_mode *mode = get_irn_op_mode(pred);
+ ir_node *pred = get_Return_res(node, i);
+ ir_mode *rmode = get_irn_op_mode(pred);
- if (mode == env->high_signed || mode == env->high_unsigned)
+ if (rmode == env->high_signed || rmode == env->high_unsigned)
need_conv = 1;
}
if (! need_conv)
/**
* Translate the parameters.
*/
-static void lower_Start(ir_node *node, ir_mode *mode)
+static void lower_Start(ir_node *node, ir_mode *high_mode)
{
ir_graph *irg = get_irn_irg(node);
ir_entity *ent = get_irg_entity(irg);
size_t i, j, n_params;
const ir_edge_t *edge;
const ir_edge_t *next;
- (void) mode;
+ (void) high_mode;
if (!mtp_must_be_lowered(tp))
return;
new_projs[i] = j;
if (is_Primitive_type(ptp)) {
- ir_mode *mode = get_type_mode(ptp);
-
- if (mode == env->high_signed || mode == env->high_unsigned)
+ ir_mode *amode = get_type_mode(ptp);
+ if (amode == env->high_signed || amode == env->high_unsigned)
++j;
}
}
ir_type *ptp = get_method_param_type(tp, p);
if (is_Primitive_type(ptp)) {
- ir_mode *mode = get_type_mode(ptp);
-
- if (mode == env->high_signed || mode == env->high_unsigned) {
+ ir_mode *pmode = get_type_mode(ptp);
+ if (pmode == env->high_signed || pmode == env->high_unsigned) {
need_lower = true;
break;
}
res_numbers[i] = j;
if (is_Primitive_type(ptp)) {
- ir_mode *mode = get_type_mode(ptp);
-
- if (mode == env->high_signed || mode == env->high_unsigned) {
+ ir_mode *rmode = get_type_mode(ptp);
+ if (rmode == env->high_signed || rmode == env->high_unsigned) {
need_lower = true;
++j;
}
ir_node *block = get_nodes_block(asmn);
int arity = get_irn_arity(asmn);
ir_node **in = get_irn_in(asmn) + 1;
- int n_outs = get_ASM_n_output_constraints(asmn);
int new_n_outs = 0;
int n_clobber = get_ASM_n_clobbers(asmn);
long *proj_map = ALLOCAN(long, n_outs);
set_irg_doms_inconsistent(irg);
set_irg_extblk_inconsistent(irg);
}
+ edges_deactivate(irg);
}
ir_free_resources(irg, IR_RESOURCE_PHI_LIST | IR_RESOURCE_IRN_LINK);
static void lower_bitfields_loads(ir_node *proj, ir_node *load)
{
ir_node *sel = get_Load_ptr(load);
- ir_node *block, *n_proj, *res, *ptr;
+ ir_node *block, *res, *ptr;
ir_graph *irg;
ir_entity *ent;
ir_type *bf_type;
/* create new proj, switch off CSE or we may get the old one back */
old_cse = get_opt_cse();
set_opt_cse(0);
- res = n_proj = new_r_Proj(load, mode, pn_Load_res);
+ res = new_r_Proj(load, mode, pn_Load_res);
set_opt_cse(old_cse);
if (mode_is_signed(mode)) { /* signed */
set_irn_mode(node, mode);
res = node;
goto own_replacement;
- } else {
- panic("unexpected projb: %+F (pred: %+F)", node, pred);
}
- break;
+ panic("unexpected projb: %+F (pred: %+F)", node, pred);
}
case iro_Const: {
typedef struct walk_env_t {
unsigned spare_size; /**< the allowed spare size for table switches */
+ unsigned small_switch;
bool allow_out_of_bounds;
bool changed; /**< indicates whether a change was performed */
ir_nodeset_t processed;
ir_node *block = get_nodes_block(cond);
ir_mode *cmp_mode = get_irn_mode(sel);
ir_node **default_preds = NEW_ARR_F(ir_node*, 0);
- unsigned long default_pn = get_Cond_default_proj(cond);
+ long default_pn = get_Cond_default_proj(cond);
long delta = 0;
ir_node *max_const;
ir_node *proj_true;
/* adapt projs */
foreach_out_irn(cond, i, proj) {
- unsigned long pn = get_Proj_proj(proj);
- unsigned long new_pn = pn - delta;
+ long pn = get_Proj_proj(proj);
+ long new_pn = pn - delta;
if (pn == default_pn) {
- /* we might have to choose a new default_pn */
- if (pn < (unsigned long) env->switch_max) {
- new_pn = env->switch_max + 1;
- set_Cond_default_proj(cond, new_pn);
- } else {
- new_pn = default_pn;
- }
+ set_Cond_default_proj(cond, new_pn);
ARR_APP1(ir_node*, default_preds, proj);
}
/* adapt default block */
n_default_preds = ARR_LEN(default_preds);
if (n_default_preds > 1) {
- size_t i;
+ size_t p;
/* create new intermediate blocks so we don't have critical edges */
- for (i = 0; i < n_default_preds; ++i) {
- ir_node *proj = default_preds[i];
- ir_node *block;
- ir_node *in[1];
+ for (p = 0; p < n_default_preds; ++p) {
+ ir_node *pred = default_preds[p];
+ ir_node *split_block;
+ ir_node *block_in[1];
- in[0] = proj;
- block = new_r_Block(irg, 1, in);
+ block_in[0] = pred;
+ split_block = new_r_Block(irg, 1, block_in);
- default_preds[i] = new_r_Jmp(block);
+ default_preds[p] = new_r_Jmp(split_block);
}
}
set_irn_in(env->default_block, n_default_preds, default_preds);
dbg_info *dbgi;
cond_env_t cond_env;
unsigned long spare;
+ bool lower_switch = false;
/* because we split critical blocks only blocks with 1 predecessors may
* contain Proj->Cond nodes */
spare = (unsigned long) cond_env.switch_max
- (unsigned long) cond_env.switch_min
- (unsigned long) cond_env.num_cases + 1;
- if (spare < env->spare_size) {
+ lower_switch |= spare >= env->spare_size;
+ lower_switch |= cond_env.num_cases <= env->small_switch;
+
+ if (!lower_switch) {
/* we won't decompose the switch. But we might have to add
* out-of-bounds checking */
if (!env->allow_out_of_bounds) {
DEL_ARR_F(cond_env.defusers);
}
-void lower_switch(ir_graph *irg, unsigned spare_size, int allow_out_of_bounds)
+void lower_switch(ir_graph *irg, unsigned small_switch, unsigned spare_size,
+ int allow_out_of_bounds)
{
walk_env_t env;
env.changed = false;
env.spare_size = spare_size;
+ env.small_switch = small_switch;
env.allow_out_of_bounds = allow_out_of_bounds;
ir_nodeset_init(&env.processed);
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: Fri 13.05.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ * CVS-Id: $Id: lpp.c 27353 2010-04-07 13:33:16Z matze $
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "assert.h"
+#include "obst.h"
+#include "hashptr.h"
+#include "debug.h"
+#include "set.h"
+
+#include "sp_matrix.h"
+#include "mps.h"
+#include "lpp_t.h"
+#include "lpp_comm.h"
+#include "lpp_solvers.h"
+#include "lpp_net.h"
+
+#define HASH_NAME_T(n) HASH_STR((n)->name, strlen((n)->name))
+
+static firm_dbg_module_t *dbg = NULL;
+
+static inline char *obst_xstrdup(struct obstack *obst, const char *str)
+{
+ return obstack_copy0(obst, str, strlen(str));
+}
+
+static int cmp_name_t(const void *x, const void *y, size_t size)
+{
+ const lpp_name_t *n = x;
+ const lpp_name_t *m = y;
+ (void)size; /* stop warnings */
+ return strcmp(n->name, m->name);
+}
+
+/**
+ * Update statistic information about matrix usage.
+ */
+static void update_stats(lpp_t *lpp)
+{
+ lpp->n_elems = matrix_get_entries(lpp->m);
+ lpp->matrix_mem = lpp->n_elems * matrix_get_elem_size();
+ lpp->density = (double)lpp->n_elems / (double)(lpp->cst_next * lpp->var_next) * 100.0;
+}
+
+#define INITIAL_SIZE 64
+
+lpp_t *new_lpp(const char *name, lpp_opt_t opt_type)
+{
+ return new_lpp_userdef(name, opt_type, INITIAL_SIZE, INITIAL_SIZE, 2.0);
+}
+
+lpp_t *new_lpp_userdef(const char *name, lpp_opt_t opt_type,
+ int estimated_vars, int estimated_csts, double grow_factor)
+{
+ lpp_t *lpp;
+ int idx;
+
+ dbg = firm_dbg_register("lpp");
+ lpp = XMALLOCZ(lpp_t);
+ obstack_init(&lpp->obst);
+
+ lpp->name = obst_xstrdup(&lpp->obst, name);
+ lpp->opt_type = opt_type;
+ lpp->grow_factor = grow_factor;
+ lpp->cst2nr = new_set(cmp_name_t, estimated_csts);
+ lpp->var2nr = new_set(cmp_name_t, estimated_vars);
+ lpp->cst_size = estimated_csts;
+ lpp->var_size = estimated_vars;
+ lpp->csts = XMALLOCNZ(lpp_name_t *, estimated_csts);
+ lpp->vars = XMALLOCNZ(lpp_name_t *, estimated_vars);
+ lpp->m = new_matrix(estimated_csts, estimated_vars);
+ lpp->emphasis = lpp_balanced;
+ idx = lpp_add_cst(lpp, "obj", lpp_objective, 0);
+ assert(idx == 0);
+ idx = lpp_add_var(lpp, "rhs", lpp_rhs, 0);
+ assert(idx == 0);
+
+ return lpp;
+}
+
+void free_lpp_matrix(lpp_t *lpp)
+{
+ del_matrix(lpp->m);
+ lpp->m = NULL;
+}
+
+void free_lpp(lpp_t *lpp)
+{
+ obstack_free(&lpp->obst, NULL);
+
+ del_set(lpp->cst2nr);
+ del_set(lpp->var2nr);
+
+ /* matrix might have been already deleted */
+ if (lpp->m)
+ del_matrix(lpp->m);
+
+ free(lpp->csts);
+ free(lpp->vars);
+
+ free(lpp);
+}
+
+double lpp_get_fix_costs(lpp_t *lpp)
+{
+ return matrix_get(lpp->m, 0, 0);
+}
+
+void lpp_set_fix_costs(lpp_t *lpp, double value)
+{
+ matrix_set(lpp->m, 0, 0, value);
+}
+
+static inline int name2nr(set *where, const char *name)
+{
+ lpp_name_t find, *found;
+ find.name = name;
+ found = set_find(where, &find, sizeof(find), HASH_NAME_T(&find));
+ return (found ? found->nr : -1);
+}
+
+#define cst_nr(lpp, name) name2nr(lpp->cst2nr, name)
+#define var_nr(lpp, name) name2nr(lpp->var2nr, name)
+
+static inline char *get_next_name(lpp_t *lpp)
+{
+ char *res = obstack_alloc(&lpp->obst, 12);
+ snprintf(res, 12, "_%u", lpp->next_name_number++);
+ return res;
+}
+
+int lpp_add_cst(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs)
+{
+ lpp_name_t n, *inner;
+
+ DBG((dbg, LEVEL_2, "%s %d %g\n", cst_name, cst_type, rhs));
+
+ if (cst_name && cst_name[0] == '_')
+ return ERR_NAME_NOT_ALLOWED;
+
+ if (cst_name)
+ n.name = obst_xstrdup(&lpp->obst, cst_name);
+ else
+ n.name = get_next_name(lpp);
+
+ n.nr = -1;
+ inner = set_insert(lpp->cst2nr, &n, sizeof(n), HASH_NAME_T(&n));
+ assert(inner);
+
+ if (inner->nr == -1) {
+ inner->value_kind = lpp_none;
+ inner->value = 0.0;
+ inner->nr = lpp->cst_next;
+ inner->type.cst_type = cst_type;
+
+ if (lpp->cst_next == lpp->cst_size) {
+ lpp->cst_size = (int)((double)lpp->cst_size * lpp->grow_factor) + 1;
+ lpp->csts = XREALLOC(lpp->csts, lpp_name_t *, lpp->cst_size);
+ }
+
+ lpp->csts[lpp->cst_next] = inner;
+ lpp->cst_next++;
+ matrix_set(lpp->m, inner->nr, 0, rhs);
+ }
+
+ update_stats(lpp);
+ return inner->nr;
+}
+
+int lpp_add_cst_uniq(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs)
+{
+ if (cst_name) {
+ lpp_name_t n;
+
+ n.name = cst_name;
+ n.nr = -1;
+ assert(!set_find(lpp->cst2nr, &n, sizeof(n), HASH_NAME_T(&n)) &&
+ "constraint already exists");
+ }
+ return lpp_add_cst(lpp, cst_name, cst_type, rhs);
+}
+
+int lpp_get_cst_idx(lpp_t *lpp, const char *cst_name)
+{
+ DBG((dbg, LEVEL_2, "%s --> %d\n", cst_name, cst_nr(lpp, cst_name)));
+ return cst_nr(lpp, cst_name);
+}
+
+void lpp_get_cst_name(lpp_t *lpp, int index, char *buf, size_t buf_size)
+{
+ DBG((dbg, LEVEL_2, "%d --> %s\n", index, lpp->csts[index]->name));
+ strncpy(buf, lpp->csts[index]->name, buf_size);
+}
+
+int lpp_add_var_default(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj, double startval)
+{
+ int val;
+
+ val = lpp_add_var(lpp, var_name, var_type, obj);
+ lpp_set_start_value(lpp, val, startval);
+
+ return val;
+}
+
+int lpp_add_var(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj)
+{
+ lpp_name_t n, *inner;
+
+ DBG((dbg, LEVEL_2, "%s %d %g\n", var_name, var_type, obj));
+
+ assert(var_type != lpp_invalid && "invalid is for internal use only");
+
+ if (var_name && var_name[0] == '_')
+ return ERR_NAME_NOT_ALLOWED;
+
+ if (var_name)
+ n.name = obst_xstrdup(&lpp->obst, var_name);
+ else
+ n.name = get_next_name(lpp);
+
+ n.nr = -1;
+ inner = set_insert(lpp->var2nr, &n, sizeof(n), HASH_NAME_T(&n));
+ assert(inner);
+
+ if (inner->nr == -1) {
+ inner->nr = lpp->var_next;
+ inner->value_kind = 0;
+ inner->value = 0;
+ inner->type.var_type = var_type;
+
+ if (lpp->var_next == lpp->var_size) {
+ lpp->var_size = (int)((double)lpp->var_size * lpp->grow_factor) + 1;
+ lpp->vars = XREALLOC(lpp->vars, lpp_name_t *, lpp->var_size);
+ }
+
+ lpp->vars[lpp->var_next] = inner;
+ lpp->var_next++;
+ matrix_set(lpp->m, 0, inner->nr, obj);
+ }
+
+ update_stats(lpp);
+ return inner->nr;
+}
+
+int lpp_get_var_idx(lpp_t *lpp, const char *var_name)
+{
+ DBG((dbg, LEVEL_2, "%s --> %d\n", var_name, var_nr(lpp, var_name)));
+ return var_nr(lpp, var_name);
+}
+
+void lpp_get_var_name(lpp_t *lpp, int index, char *buf, size_t buf_size)
+{
+ DBG((dbg, LEVEL_2, "%d --> %s\n", index, lpp->vars[index]->name));
+ strncpy(buf, lpp->vars[index]->name, buf_size);
+}
+
+int lpp_set_factor(lpp_t *lpp, const char *cst_name, const char *var_name, double value)
+{
+ int cst, var;
+
+ cst = cst_nr(lpp, cst_name);
+ var = var_nr(lpp, var_name);
+ assert(cst != -1 && var != -1);
+ DBG((dbg, LEVEL_2, "%s[%d] %s[%d] %g\n", cst_name, cst, var_name, var, value));
+ matrix_set(lpp->m, cst, var, value);
+ update_stats(lpp);
+ return 0;
+}
+
+int lpp_set_factor_fast(lpp_t *lpp, int cst_idx, int var_idx, double value)
+{
+ assert(cst_idx >= 0 && var_idx >= 0);
+ assert(cst_idx < lpp->cst_next && var_idx < lpp->var_next);
+ DBG((dbg, LEVEL_2, "%s[%d] %s[%d] %g\n", lpp->csts[cst_idx]->name, cst_idx, lpp->vars[var_idx]->name, var_idx, value));
+ matrix_set(lpp->m, cst_idx, var_idx, value);
+ update_stats(lpp);
+ return 0;
+}
+
+int lpp_set_factor_fast_bulk(lpp_t *lpp, int cst_idx, int *var_idx, int num_vars, double value)
+{
+ assert(cst_idx >= 0 && cst_idx < lpp->cst_next);
+ assert(num_vars < lpp->var_next);
+ DBG((dbg, LEVEL_2, "row %s[%d] %d vars %g\n", lpp->csts[cst_idx]->name, cst_idx, num_vars, value));
+ matrix_set_row_bulk(lpp->m, cst_idx, var_idx, num_vars, value);
+ update_stats(lpp);
+ return 0;
+}
+
+void lpp_set_start_value(lpp_t *lpp, int var_idx, double value)
+{
+ assert(var_idx > 0 && var_idx < lpp->var_next);
+ DBG((dbg, LEVEL_2, "%d %s %g\n", var_idx, lpp->vars[var_idx]->name, value));
+ lpp->vars[var_idx]->value = value;
+ lpp->vars[var_idx]->value_kind = lpp_value_start;
+}
+
+lpp_sol_state_t lpp_get_solution(lpp_t *lpp, double *values, int begin, int end)
+{
+ int i;
+
+ if (lpp->sol_state < lpp_feasible)
+ return lpp->sol_state;
+
+ /* here we are feasible or optimal */
+ for (i = 0; i < end - begin + 1; ++i)
+ values[i] = lpp->vars[begin + i]->value;
+
+ return lpp->sol_state;
+}
+
+void lpp_check_startvals(lpp_t *lpp)
+{
+ int cst_idx;
+
+ for (cst_idx = 1; cst_idx < lpp->cst_next; ++cst_idx) {
+ double sum = 0.0;
+ lpp_name_t *cst = lpp->csts[cst_idx];
+ double cst_val = matrix_get(lpp->m, cst_idx, 0);
+ int var_idx;
+
+ for (var_idx = 1; var_idx < lpp->var_next; ++var_idx) {
+ if (lpp->vars[var_idx]->value_kind != lpp_value_start)
+ goto next;
+
+ sum += lpp->vars[var_idx]->value *
+ matrix_get(lpp->m, cst_idx, var_idx);
+ }
+ switch(cst->type.cst_type) {
+ case lpp_equal:
+ if(sum != cst_val) {
+ fprintf(stderr, "constraint %s unsatisfied: %g != %g\n", cst->name, sum, cst_val);
+ }
+ break;
+ case lpp_less:
+ if(sum > cst_val) {
+ fprintf(stderr, "constraint %s unsatisfied: %g > %g\n", cst->name, sum, cst_val);
+ }
+ break;
+ case lpp_greater:
+ if(sum < cst_val) {
+ fprintf(stderr, "constraint %s unsatisfied: %g < %g\n", cst->name, sum, cst_val);
+ }
+ break;
+ default:
+ assert(0 && "unknown constraint type");
+ }
+next: ;
+ }
+}
+
+void lpp_dump(lpp_t *lpp, const char *filename)
+{
+ FILE *out = fopen(filename, "wt");
+ mps_write_mps(lpp, s_mps_fixed, out);
+ fclose(out);
+}
+
+void lpp_set_log(lpp_t *lpp, FILE *log)
+{
+ lpp->log = log;
+}
+
+
+static const char *lpp_cst_op_to_str(lpp_cst_t cst)
+{
+ switch(cst) {
+ case lpp_equal:
+ return "=";
+ case lpp_less:
+ return "<=";
+ case lpp_greater:
+ return ">=";
+ default:
+ return "";
+ }
+}
+
+void lpp_dump_plain(lpp_t *lpp, FILE *f)
+{
+ int i;
+
+ for(i = 0; i < lpp->cst_next; ++i) {
+ const matrix_elem_t *elm;
+ lpp_name_t *cst = lpp->csts[i];
+
+ fprintf(f, "%16s: ", cst->name);
+ matrix_foreach_in_row(lpp->m, cst->nr, elm) {
+ lpp_name_t *var = lpp->vars[elm->col];
+ /* TODO Perhaps better a define LPP_COL_RHS */
+ if(elm->col > 0)
+ fprintf(f, "%+4.1f*%-16s ", elm->val, var->name);
+ }
+
+ fprintf(f, "%3s %+4.1f\n",
+ lpp_cst_op_to_str(cst->type.cst_type), matrix_get(lpp->m, cst->nr, 0));
+ }
+}
+
+/**
+ * Serialize a lpp to a file descriptor.
+ * @param comm The file descriptor.
+ * @param lpp The lpp.
+ */
+void lpp_serialize(lpp_comm_t *comm, const lpp_t *lpp, int with_names)
+{
+ int n, i;
+
+ lpp_writel(comm, with_names);
+ lpp_writel(comm, lpp->cst_next);
+ lpp_writel(comm, lpp->var_next);
+ lpp_writel(comm, lpp->opt_type);
+ lpp_writes(comm, lpp->name);
+
+ /* write options */
+ lpp_writel(comm, lpp->set_bound);
+ lpp_writed(comm, lpp->bound);
+ lpp_writed(comm, lpp->time_limit_secs);
+ lpp_writed(comm, lpp->emphasis);
+
+ for(i = 0; i < lpp->cst_next; ++i) {
+ lpp_name_t *name = lpp->csts[i];
+ lpp_writel(comm, name->nr);
+ lpp_writel(comm, name->value_kind);
+ lpp_writel(comm, name->type.cst_type);
+
+ if(with_names)
+ lpp_writes(comm, name->name);
+ }
+
+ for(i = 0; i < lpp->var_next; ++i) {
+ lpp_name_t *name = lpp->vars[i];
+ lpp_writel(comm, name->nr);
+ lpp_writel(comm, name->value_kind);
+ lpp_writel(comm, name->type.var_type);
+
+ if(with_names)
+ lpp_writes(comm, name->name);
+ }
+
+ {
+ const matrix_elem_t *elm;
+ n = 0;
+
+ matrix_foreach(lpp->m, elm)
+ n++;
+
+ assert(n == matrix_get_entries(lpp->m));
+ lpp_writel(comm, n);
+ matrix_foreach(lpp->m, elm) {
+ lpp_writel(comm, elm->row);
+ lpp_writel(comm, elm->col);
+ lpp_writed(comm, elm->val);
+ }
+ }
+}
+
+#define NAMELEN 64
+
+/**
+ * Deserialize an lpp from a file descriptor.
+ * @param comm The file descriptor.
+ * @return The Problem.
+ */
+lpp_t *lpp_deserialize(lpp_comm_t *comm)
+{
+ int i, n;
+ int with_names;
+
+ lpp_t *lpp = XMALLOCZ(lpp_t);
+
+ /* read general settings */
+ with_names = lpp_readl(comm);
+ lpp->cst_next = lpp_readl(comm);
+ lpp->var_next = lpp_readl(comm);
+ lpp->opt_type = lpp_readl(comm);
+ lpp->name = lpp_reads(comm);
+
+ /* read options */
+ lpp->set_bound = lpp_readl(comm);
+ lpp->bound = lpp_readd(comm);
+ lpp->time_limit_secs = lpp_readd(comm);
+ lpp->emphasis = lpp_readd(comm);
+
+ lpp->cst_size = lpp->cst_next;
+ lpp->var_size = lpp->var_next;
+
+ lpp->cst2nr = new_set(cmp_name_t, lpp->cst_next);
+ lpp->var2nr = new_set(cmp_name_t, lpp->var_next);
+
+ lpp->csts = XMALLOCNZ(lpp_name_t*, lpp->cst_next);
+ lpp->vars = XMALLOCNZ(lpp_name_t*, lpp->var_next);
+ lpp->m = new_matrix(lpp->cst_next, lpp->var_next);
+
+ for(i = 0; i < lpp->cst_next; ++i) {
+ lpp_name_t name, *res;
+
+ name.nr = lpp_readl(comm);
+ name.value_kind = lpp_readl(comm);
+ name.type.cst_type = lpp_readl(comm);
+
+ if(with_names) {
+ name.name = lpp_reads(comm);
+ } else {
+ char* buf = XMALLOCN(char, NAMELEN);
+ snprintf(buf, NAMELEN, "c%d\n", name.nr);
+ name.name = buf;
+ }
+
+ res = set_insert(lpp->cst2nr, &name, sizeof(name), HASH_NAME_T(&name));
+ lpp->csts[name.nr] = res;
+ }
+
+ for(i = 0; i < lpp->var_next; ++i) {
+ lpp_name_t name, *res;
+
+ name.nr = lpp_readl(comm);
+ name.value_kind = lpp_readl(comm);
+ name.type.var_type = lpp_readl(comm);
+
+ if(with_names) {
+ name.name = lpp_reads(comm);
+ } else {
+ char* buf = XMALLOCN(char, NAMELEN);
+ snprintf(buf, NAMELEN, "v%d\n", name.nr);
+ name.name = buf;
+ }
+
+ res = set_insert(lpp->var2nr, &name, sizeof(name), HASH_NAME_T(&name));
+ lpp->vars[name.nr] = res;
+ }
+
+ n = lpp_readl(comm);
+ for(i = 0; i < n; ++i) {
+ matrix_elem_t elm;
+ elm.row = lpp_readl(comm);
+ elm.col = lpp_readl(comm);
+ elm.val = lpp_readd(comm);
+ matrix_set(lpp->m, elm.row, elm.col, elm.val);
+ }
+
+ return lpp;
+}
+
+void lpp_serialize_values(lpp_comm_t *comm, const lpp_t *lpp, lpp_value_kind_t value_kind)
+{
+ int i, n;
+
+ for(i = 0, n = 0; i < lpp->var_next; ++i)
+ n += lpp->vars[i]->value_kind == value_kind;
+
+ /* Write the number of values to expect */
+ lpp_writel(comm, n);
+
+ /* send the values */
+ for(i = 0, n = lpp->var_next; i < n; ++i) {
+ const lpp_name_t *name = lpp->vars[i];
+ if(name->value_kind == value_kind) {
+ lpp_writel(comm, name->nr);
+ lpp_writed(comm, name->value);
+ }
+ }
+}
+
+void lpp_deserialize_values(lpp_comm_t *comm, lpp_t *lpp, lpp_value_kind_t value_kind)
+{
+ int i, n;
+
+ /* Get the number of values to read */
+ n = lpp_readl(comm);
+
+ for(i = 0; i < n; ++i) {
+ int nr = lpp_readl(comm);
+ lpp_name_t *name = lpp->vars[nr];
+
+ name->value_kind = value_kind;
+ name->value = lpp_readd(comm);
+ }
+}
+
+void lpp_serialize_stats(lpp_comm_t *comm, const lpp_t *lpp)
+{
+ lpp_writel(comm, lpp->sol_state);
+ lpp_writel(comm, lpp->iterations);
+ lpp_writed(comm, lpp->sol_time);
+ lpp_writed(comm, lpp->objval);
+ lpp_writed(comm, lpp->best_bound);
+}
+
+void lpp_deserialize_stats(lpp_comm_t *comm, lpp_t *lpp)
+{
+ lpp->sol_state = lpp_readl(comm);
+ lpp->iterations = lpp_readl(comm);
+ lpp->sol_time = lpp_readd(comm);
+ lpp->objval = lpp_readd(comm);
+ lpp->best_bound = lpp_readd(comm);
+}
+
+void lpp_solve(lpp_t *lpp, const char* host, const char* solver)
+{
+ if (host == NULL || strlen(host) == 0) {
+ lpp_solver_func_t* f = lpp_find_solver(solver);
+ if (f != NULL)
+ f(lpp);
+ } else {
+ lpp_solve_net(lpp, host, solver);
+ }
+}
+
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 16.05.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ * CVS-Id: $Id: lpp.h 16112 2007-10-07 15:50:49Z mallon $
+ *
+ * Interface for specifying an milp. Does not define a solution method.
+ */
+#ifndef _LPP_H
+#define _LPP_H
+
+#include <stdio.h>
+#include <obstack.h>
+
+#include "set.h"
+
+#include "sp_matrix.h"
+
+typedef enum _lpp_opt_t {
+ lpp_minimize,
+ lpp_maximize
+} lpp_opt_t;
+
+typedef enum _lpp_cst_t {
+ lpp_objective,
+ lpp_equal,
+ lpp_less,
+ lpp_greater
+} lpp_cst_t;
+
+typedef enum _lpp_var_t {
+ lpp_invalid,
+ lpp_rhs,
+ lpp_continous,
+ lpp_binary
+} lpp_var_t;
+
+typedef enum _lpp_sol_state_t {
+ lpp_unknown,
+ lpp_infeasible,
+ lpp_inforunb,
+ lpp_unbounded,
+ lpp_feasible,
+ lpp_optimal
+} lpp_sol_state_t;
+
+typedef enum _lpp_value_kind_t {
+ lpp_none,
+ lpp_value_start,
+ lpp_value_solution,
+} lpp_value_kind_t;
+
+typedef enum _lpp_emphasis_t {
+ lpp_balanced,
+ lpp_feasability,
+ lpp_optimality,
+ lpp_bestbound,
+ lpp_hiddenfeasibility
+} lpp_emphasis_t;
+
+typedef struct _name_t {
+ const char *name; /**< the name of the var/constraint supplied by user */
+ int nr; /**< the col/row number in the matrix */
+ lpp_value_kind_t value_kind;
+ double value;
+ union _type {
+ lpp_var_t var_type;
+ lpp_cst_t cst_type;
+ } type;
+} lpp_name_t;
+
+typedef struct _lpp_t {
+ /* The problem data */
+ const char *name; /**< A textual name for this problem */
+ FILE *log; /**< The log file. */
+ lpp_opt_t opt_type; /**< Optimization direction */
+ struct obstack obst; /**< Obstack for variable names */
+ sp_matrix_t *m; /**< The matrix holding objective, constraints and rhs */
+
+ /* Cst/Var to Nr mapping */
+ set *cst2nr; /**< Holds name_t's for constraints */
+ set *var2nr; /**< Holds name_t's for variables */
+
+ /* Nr to Cst/Var mapping */
+ int cst_size, var_size; /**< Size of the csts/vars-arrays below */
+ int cst_next, var_next; /**< Next free position in arrays below */
+ lpp_name_t **csts; /**< Pointers to the elements in the cst2nr set */
+ lpp_name_t **vars; /**< Pointers to the elements in the var2nr set */
+ double objval; /**< OUT: Value of the objective function. */
+ double best_bound; /**< OUT: best bound to the integer solution. */
+ double grow_factor; /**< The factor by which the vars and constraints are enlarged */
+
+ /* Solving options */
+ int set_bound; /**< IN: Boolean flag to set a bound for the objective function. */
+ double bound; /**< IN: The bound. Only valid if set_bound == 1. */
+ double time_limit_secs; /**< IN: Time limit to obey while solving (0.0 means no time limit) */
+
+ /* Solution stuff */
+ lpp_sol_state_t sol_state; /**< State of the solution */
+ double sol_time; /**< Time in seconds */
+ unsigned iterations; /**< Number of iterations CPLEX needed to solve the ILP (whatever this means) */
+
+ char *error;
+ unsigned next_name_number; /**< for internal use only */
+ lpp_emphasis_t emphasis; /**< On what should CPLEX concentrate (feasibility, bestbound, ...) */
+
+ /* some statistic stuff */
+ unsigned send_time; /**< in case of solve_net: send time in usec */
+ unsigned recv_time; /**< in case of solve_net: recv time in usec */
+ unsigned n_elems; /**< number of elements stored in the matrix */
+ unsigned matrix_mem; /**< memory used by matrix elements (in bytes) */
+ double density; /**< density of the matrix (percentage) */
+} lpp_t;
+
+#define ERR_NAME_NOT_ALLOWED -2
+
+/**
+ * Creates a new problem. Optimization type is minimize or maximize.
+ * Implicit row with name "obj" is inserted.
+ * Implicit col with name "rhs" is inserted.
+ */
+lpp_t *new_lpp(const char *name, lpp_opt_t opt_type);
+
+/**
+ * Creates a new problem. Optimization type is minimize or maximize.
+ * Implicit row with name "obj" is inserted.
+ * Implicit col with name "rhs" is inserted.
+ * @param estimated_vars The estimated number of variables for the problem
+ * @param estimated_csts The estimated number of constraints for the problem
+ * @param grow_factor By which factor should the problem grow, if there are
+ * more variables or constraints than estimated.
+ */
+lpp_t *new_lpp_userdef(const char *name, lpp_opt_t opt_type,
+ int estimated_vars, int estimated_csts, double grow_factor);
+
+/**
+ * Frees the matrix embedded in the LPP.
+ */
+void free_lpp_matrix(lpp_t *lpp);
+
+/**
+ * Frees all memory allocated for LPP data structure.
+ */
+void free_lpp(lpp_t *lpp);
+
+/**
+ * @return The constant term in the objective function
+ */
+double lpp_get_fix_costs(lpp_t *lpp);
+
+/**
+ * Sets the constant term in the objective function to @p value
+ */
+void lpp_set_fix_costs(lpp_t *lpp, double value);
+
+/**
+ * Adds a constraint to a problem. If a constraint with the same name already
+ * exists nothing is altered, and the index of the existing entry is returned.
+ * @param cst_name The name of the constraint (1st char only alpha-numeric!). If NULL, a default name will be used.
+ * @param cst_type The type of constraint: objective, equality, less-or-equal, greater-or-equal
+ * @param rhs The right hand side value to set for this constraint.
+ * @return The (new or existing) index of the constraint
+ */
+int lpp_add_cst(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs);
+
+/**
+ * Adds a constraint to a problem. If a constraint with the same name already
+ * exists it dies a horribly cruel death
+ * @param cst_name The name of the constraint (1st char only alpha-numeric!). If NULL, a default name will be used.
+ * @param cst_type The type of constraint: objective, equality, less-or-equal, greater-or-equal
+ * @param rhs The right hand side value to set for this constraint.
+ * @return The (new or existing) index of the constraint
+ */
+int lpp_add_cst_uniq(lpp_t *lpp, const char *cst_name, lpp_cst_t cst_type, double rhs);
+
+/**
+ * Returns the internal index of a constraint.
+ * @param cst_name The name of the constraint
+ * @return The internal index of constraint @p cst_name or -1 if it does not exist.
+ */
+int lpp_get_cst_idx(lpp_t *lpp, const char *cst_name);
+
+/**
+ * Returns the name of a constraint.
+ * @param index The internal index of a constraint.
+ * @param buf A buffer to hold the name of the constraint
+ * @param buf_size Size of the buffer
+ */
+void lpp_get_cst_name(lpp_t *lpp, int index, char *buf, size_t buf_size);
+
+/**
+ * Adds a variable to a problem. If a variable with the same name already
+ * exists nothing is altered, and the index of the existing entry is returned.
+ * @param var_name The name of the constraint (1st char only alpha-numeric!). If NULL, a default name will be used.
+ * @param var_type The type of variable: real, binary
+ * @param obj The objective value coefficient for this variable.
+ * @return The (new or existing) index of the variable
+ *
+ * NOTE: common integer or semi-continuous vars are not (yet) implemented
+ */
+int lpp_add_var(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj);
+
+/**
+ * Same as lpp_add_var() but the user can supply a default value.
+ */
+int lpp_add_var_default(lpp_t *lpp, const char *var_name, lpp_var_t var_type, double obj, double startval);
+
+/**
+ * Returns the internal index of a variable.
+ * @param cst_name The name of the variable
+ * @return The internal index of variable @p var_name or -1 if it does not exist.
+ */
+int lpp_get_var_idx(lpp_t *lpp, const char *var_name);
+
+/**
+ * Returns the name of a variable.
+ * @param index The internal index of a variable.
+ * @param buf A buffer to hold the name of the variable
+ * @param buf_size Size of the buffer
+ */
+void lpp_get_var_name(lpp_t *lpp, int index, char *buf, size_t buf_size);
+
+/**
+ * Sets the factor of the variable @p var_name in constraint @p cst_name to @p value.
+ * @return -1 if constraint or variable name does not exist.
+ * 0 otherwise
+ */
+int lpp_set_factor(lpp_t *lpp, const char *cst_name, const char *var_name, double value);
+
+/**
+ * Same as lpp_set_factor but uses the internal indices instead of names.
+ * @return -1 if an index was invalid
+ * 0 otherwise
+ */
+int lpp_set_factor_fast(lpp_t *lpp, int cst_idx, int var_idx, double value);
+
+int lpp_set_factor_fast_bulk(lpp_t *lpp, int cst_idx, int *var_idx, int num_vars, double value);
+
+/**
+ * Set a starting value for a var.
+ * @param var_idx The index of the variable to set the value for.
+ * @param value The value to set.
+ */
+void lpp_set_start_value(lpp_t *lpp, int var_idx, double value);
+
+/**
+ * @return The solution values of the variables from index begin to index end.
+ */
+lpp_sol_state_t lpp_get_solution(lpp_t *lpp, double *values, int begin, int end);
+
+/**
+ * Dumps the lpp into a file with name @p filename in MPS-format
+ */
+void lpp_dump(lpp_t *lpp, const char *filename);
+
+/**
+ * Set the log file, where the solver should write to.
+ * @param lpp The problem.
+ * @param log The logfile. NULL for no logging.
+ */
+void lpp_set_log(lpp_t *lpp, FILE *log);
+
+/**
+ * Check the start values and list conflicting constraints.
+ */
+void lpp_check_startvals(lpp_t *lpp);
+
+/**
+ * Dump problem into a text file.
+ * @param lpp The problem.
+ * @param f The file.
+ */
+void lpp_dump_plain(lpp_t *lpp, FILE *f);
+
+#define lpp_get_iter_cnt(lpp) ((lpp)->iterations)
+#define lpp_get_sol_time(lpp) ((lpp)->sol_time)
+#define lpp_get_sol_state(lpp) ((lpp)->sol_state)
+#define lpp_get_var_count(lpp) ((lpp)->var_next-1)
+#define lpp_get_cst_count(lpp) ((lpp)->cst_next-1)
+#define lpp_get_sol_state(lpp) ((lpp)->sol_state)
+#define lpp_get_var_sol(lpp,idx) ((lpp)->vars[idx]->value)
+#define lpp_is_sol_valid(lpp) (lpp_get_sol_state(lpp) >= lpp_feasible)
+
+#define lpp_set_time_limit(lpp,secs) ((lpp)->time_limit_secs = secs)
+
+/**
+ * Set a bound for the objective function.
+ * @param lpp The problem.
+ * @param bound A bound for the objective function.
+ * If the problem is a minimization problem, the bound
+ * is a lower bound. If it is a maximization problem,
+ * the bound is an upper bound.
+ */
+#define lpp_set_bound(lpp,bnd) ((lpp)->set_bound = 1, (lpp)->bound = (bnd))
+
+/**
+ * Clear a set bound.
+ * @param lpp The problem.
+ */
+#define lpp_unset_bound(lpp) ((lpp)->set_bound = 0)
+
+/**
+ * Solve an ILP.
+ * @param lpp The problem.
+ * @param host The host to solve on.
+ * @param solver The solver to use.
+ */
+void lpp_solve(lpp_t *lpp, const char* host, const char* solver);
+
+#endif /* _LPP_H */
--- /dev/null
+/**
+ * @file lpp_comm.c
+ * @date 21.07.2005
+ * @author Sebastian Hack
+ *
+ * Protocol stuff for lpp server
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+
+#define vsnprintf _vsnprintf
+
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#endif
+
+#include "irtools.h"
+#include "debug.h"
+
+#include "lpp_comm.h"
+
+/* undef to disable debugging */
+#undef ENABLE_DEBUGGING
+
+struct _lpp_comm_t {
+ int fd;
+ size_t buf_size;
+ char *w_pos;
+ char *r_pos;
+ char *r_max;
+ char *w_buf;
+ char *r_buf;
+};
+
+static inline firm_dbg_module_t *get_dbg_module(void)
+{
+ static firm_dbg_module_t *dbg = NULL;
+ if(!dbg) {
+ dbg = firm_dbg_register("lpp.comm");
+ }
+
+ return dbg;
+}
+
+#define dbg get_dbg_module()
+
+/**
+ * Try to read some bytes but block until a certain amount is read.
+ * @param fd The file descriptor.
+ * @param buf The buffer to read into.
+ * @param try The amount of bytes to try to read.
+ * @param at_least block until this many bytes are read.
+ * @return The number of bytes read or -1 on error.
+ */
+static ssize_t secure_recv(int fd, void *buf, size_t try, size_t at_least)
+{
+ ssize_t res;
+ size_t bytes_read = 0;
+ char *data = buf;
+
+ do {
+ res = recv(fd, &data[bytes_read], try - bytes_read, 0);
+ if(res <= 0) {
+ if(res == 0 || errno != EAGAIN)
+ return -1;
+ continue;
+ }
+
+ bytes_read += res;
+
+ } while(bytes_read < at_least);
+
+ return bytes_read;
+}
+
+static ssize_t secure_send(int fd, const void *buf, size_t n)
+{
+ ssize_t res;
+ size_t bytes_written = 0;
+ const char *data = buf;
+
+ do {
+ res = send(fd, &data[bytes_written], n - bytes_written, 0);
+ if(res < 0) {
+ if(errno != EAGAIN)
+ return -1;
+ continue;
+ }
+
+ bytes_written += res;
+
+ } while(bytes_written < n);
+
+ return n;
+}
+
+ssize_t lpp_flush(lpp_comm_t *comm)
+{
+ ssize_t res = 0;
+ if(comm->w_pos - comm->w_buf > 0) {
+ DBG((dbg, LEVEL_1, "flushing %d bytes\n", comm->w_pos - comm->w_buf));
+ res = secure_send(comm->fd, comm->w_buf, comm->w_pos - comm->w_buf);
+ if(res < 0)
+ return res;
+
+ comm->w_pos = comm->w_buf;
+ }
+ return res;
+}
+
+static ssize_t lpp_write(lpp_comm_t *comm, const void *buf, size_t len)
+{
+ assert(comm->w_pos - comm->w_buf >= 0);
+
+ DBG((dbg, LEVEL_1, "write of length %d\n", len));
+ if(len > 0) {
+ size_t free = (comm->w_buf + comm->buf_size) - comm->w_pos;
+ size_t copy = MIN(free, len);
+ size_t rest = len - copy;
+ const char *pos = buf;
+
+ DBG((dbg, LEVEL_1, "\tfree = %d, copy = %d, rest = %d\n", free, copy, rest));
+ if(copy > 0) {
+ memcpy(comm->w_pos, pos, copy);
+ comm->w_pos += copy;
+ pos += copy;
+ }
+
+ /*
+ * Not everything in buf fits into the buffer,
+ * so flush the buffer and write the rest.
+ */
+ if(rest > 0) {
+ size_t i;
+ size_t n_direct = rest / comm->buf_size;
+ size_t last_rest;
+
+ if(lpp_flush(comm) < 0)
+ return -1;
+
+ for(i = 0; i < n_direct; ++i) {
+ if(secure_send(comm->fd, pos, comm->buf_size) < 0)
+ return -1;
+
+ pos += comm->buf_size;
+ }
+
+ last_rest = ((const char *) buf + len) - pos;
+
+ if(last_rest > 0) {
+ assert(last_rest < comm->buf_size);
+ assert(comm->w_pos == comm->w_buf);
+ memcpy(comm->w_pos, pos, last_rest);
+ comm->w_pos += last_rest;
+ }
+ }
+ }
+
+ return len;
+}
+
+static ssize_t lpp_read(lpp_comm_t *comm, void *buf, size_t len)
+{
+ DBG((dbg, LEVEL_1, "read of length %d\n", len));
+ if(len > 0) {
+ size_t left = comm->r_max - comm->r_pos;
+ size_t copy = MIN(left, len);
+ size_t rest = len - copy;
+ char *pos = buf;
+
+ DBG((dbg, LEVEL_1, "\tleft = %d, copy = %d, rest = %d\n", left, copy, rest));
+ if(copy > 0) {
+ memcpy(pos, comm->r_pos, copy);
+ pos += copy;
+ comm->r_pos += copy;
+ }
+
+ /* We want to read more than the buffer can provide. */
+ if(rest > 0) {
+ size_t bs = comm->buf_size;
+ size_t n_direct = rest / comm->buf_size;
+ size_t i;
+ size_t last_rest;
+
+ /*
+ * The buffer is now completely read, so
+ * reset the pointers.
+ */
+ comm->r_pos = comm->r_buf;
+ comm->r_max = comm->r_buf;
+
+ for(i = 0; i < n_direct; ++i) {
+ if(secure_recv(comm->fd, pos, bs, bs) < 0)
+ return -1;
+
+ pos += comm->buf_size;
+ }
+
+ last_rest = ((const char *) buf + len) - pos;
+
+ if(last_rest > 0) {
+ ssize_t bytes_read = 0;
+
+ assert(last_rest < comm->buf_size);
+ assert(comm->r_pos == comm->r_buf);
+
+ bytes_read = secure_recv(comm->fd, comm->r_buf, bs, last_rest);
+ if(bytes_read < 0)
+ return -1;
+
+ memcpy(pos, comm->r_buf, last_rest);
+ comm->r_pos = comm->r_buf + last_rest;
+ comm->r_max = comm->r_buf + bytes_read;
+ }
+ }
+ }
+
+ return len;
+}
+
+lpp_comm_t *lpp_comm_new(int fd, size_t buf_size)
+{
+ lpp_comm_t *res = malloc(sizeof(res[0]));
+
+ res->fd = fd;
+ res->w_buf = malloc(buf_size);
+ res->w_pos = res->w_buf;
+ res->r_buf = malloc(buf_size);
+ res->r_pos = res->r_buf;
+ res->r_max = res->r_buf;
+ res->buf_size = buf_size;
+
+ return res;
+}
+
+int lpp_comm_fileno(const lpp_comm_t *comm)
+{
+ return comm->fd;
+}
+
+void lpp_comm_free(lpp_comm_t *comm)
+{
+ free(comm->w_buf);
+ free(comm->r_buf);
+ free(comm);
+}
+
+void lpp_print_err(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+void lpp_writel(lpp_comm_t *comm, uint32_t x)
+{
+ x = htonl(x);
+ ERRNO_CHECK(lpp_write(comm, &x, sizeof(x)), !=, (ssize_t)sizeof(x));
+}
+
+void lpp_writed(lpp_comm_t *comm, double dbl)
+{
+ ERRNO_CHECK(lpp_write(comm, &dbl, sizeof(dbl)), !=, (ssize_t)sizeof(dbl));
+}
+
+void lpp_writes(lpp_comm_t *comm, const char *str)
+{
+ size_t n = strlen(str);
+ lpp_writel(comm, n);
+ ERRNO_CHECK(lpp_write(comm, str, n), !=, (ssize_t) n);
+}
+
+uint32_t lpp_readl(lpp_comm_t *comm)
+{
+ uint32_t res;
+
+ ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, (ssize_t)sizeof(res));
+ return ntohl(res);
+}
+
+int lpp_read_cmd(lpp_comm_t *comm)
+{
+ uint32_t res = 0;
+ int retval;
+
+ for(;;) {
+ retval = recv(comm->fd, (char *)&res, sizeof(res), 0);
+ if(retval < 0) {
+ if(errno != EAGAIN)
+ return -1;
+ }
+
+ else
+ break;
+ }
+
+ return (int) ntohl(res);
+}
+
+double lpp_readd(lpp_comm_t *comm)
+{
+ double res;
+ ERRNO_CHECK(lpp_read(comm, &res, sizeof(res)), !=, (ssize_t)sizeof(res));
+ return res;
+}
+
+char *lpp_reads(lpp_comm_t *comm)
+{
+ size_t len = lpp_readl(comm);
+ char *res = malloc(sizeof(char) * (len + 1));
+
+ ERRNO_CHECK(lpp_read(comm, res, len), !=, (ssize_t) len);
+ res[len] = '\0';
+ return res;
+}
+
+char *lpp_readbuf(lpp_comm_t *comm, char *buf, size_t buflen)
+{
+ char dummy[1024];
+ size_t i;
+ size_t n = buflen - 1;
+ size_t len = lpp_readl(comm);
+ size_t max_read = n < len ? n : len;
+ size_t rest = len - max_read;
+
+ if(buflen > 0 && buf != NULL) {
+ ERRNO_CHECK(lpp_read(comm, buf, max_read), !=, (ssize_t) max_read);
+ buf[max_read] = '\0';
+ }
+ else
+ rest = len;
+
+ /* eat up data that didnt fit into the string */
+ for(i = 0, n = rest / sizeof(dummy); i < n; ++i)
+ ERRNO_CHECK(lpp_read(comm, dummy, sizeof(dummy)), !=, (ssize_t)sizeof(dummy));
+
+ if(rest % sizeof(dummy) > 0)
+ ERRNO_CHECK(lpp_read(comm, dummy, rest % sizeof(dummy)), !=,
+ (ssize_t) (rest % sizeof(dummy)) );
+
+ return buf;
+}
+
+int lpp_ack(lpp_comm_t *comm, char *buf, size_t buflen)
+{
+ int res = 0;
+ int cmd = lpp_readl(comm);
+
+ switch(cmd) {
+ case LPP_CMD_OK:
+ res = 1;
+ break;
+ case LPP_CMD_BAD:
+ lpp_readbuf(comm, buf, buflen);
+ default:
+ res = 0;
+ }
+
+ return res;
+}
+
+void lpp_send_res(lpp_comm_t *comm, int ok, const char *fmt, ...)
+{
+ if(!ok) {
+ char buf[1024];
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ lpp_writel(comm, LPP_CMD_BAD);
+ lpp_writes(comm, buf);
+ } else {
+ lpp_writel(comm, LPP_CMD_OK);
+ }
+}
+
+void lpp_send_ack(lpp_comm_t *comm)
+{
+ lpp_send_res(comm, 1, "");
+}
+
+const char *lpp_get_cmd_name(int cmd)
+{
+ switch(cmd) {
+ case LPP_CMD_BAD: return "BAD";
+ case LPP_CMD_OK: return "OK";
+ case LPP_CMD_PROBLEM: return "PROBLEM";
+ case LPP_CMD_SOLUTION: return "SOLUTION";
+ case LPP_CMD_SOLVER: return "SOLVER";
+ case LPP_CMD_BYE: return "BYE";
+ case LPP_CMD_SOLVERS: return "SOLVERS";
+ case LPP_CMD_SET_DEBUG: return "SET_DEBUG";
+ case LPP_CMD_INFO: return "INFO";
+ case LPP_CMD_LAST:
+ break;
+ }
+
+ return "<unknown>";
+}
--- /dev/null
+/**
+ * @file lpp_server.h
+ * @date 19.07.2005
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+
+#ifndef _LPP_COMM_H
+#define _LPP_COMM_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#define LPP_PORT 2175
+#define LPP_BUFSIZE (1 << 20)
+
+enum {
+ LPP_CMD_BAD,
+ LPP_CMD_OK,
+ LPP_CMD_PROBLEM,
+ LPP_CMD_SOLUTION,
+ LPP_CMD_SOLVER,
+ LPP_CMD_BYE,
+ LPP_CMD_SOLVERS,
+ LPP_CMD_SET_DEBUG,
+ LPP_CMD_INFO,
+ LPP_CMD_LAST
+};
+
+#define BASIC_ERR_CHECK(expr,op,cond,fmt,last) \
+do { \
+ int err_check_res; \
+ if((err_check_res = (expr)) op cond) { \
+ fprintf(stderr, "%s(%u): %d = %s(%d): ", \
+ __FILE__, (unsigned) __LINE__, err_check_res, #expr, cond); \
+ lpp_print_err fmt; \
+ fprintf(stderr, "\n"); \
+ last; \
+ } \
+} while(0)
+
+#define BASIC_ERRNO_CHECK(expr,op,cond,last) \
+do { \
+ int _basic_errno_check_res = (expr); \
+ if(_basic_errno_check_res op cond) { \
+ fprintf(stderr, "%s(%u): %d = %s(%d): %s\n", \
+ __FILE__, (unsigned) __LINE__, _basic_errno_check_res, #expr, (int) cond, strerror(errno)); \
+ last; \
+ } \
+} while(0)
+
+#define ERR_CHECK_RETURN(expr, op, cond, fmt, retval) \
+ BASIC_ERR_CHECK(expr, op, cond, fmt, return retval)
+
+#define ERRNO_CHECK_RETURN(expr, op, cond, retval) \
+ BASIC_ERRNO_CHECK(expr, op, cond, return retval)
+
+#define ERR_CHECK_RETURN_VOID(expr, op, cond, fmt) \
+ BASIC_ERR_CHECK(expr, op, cond, fmt, return)
+
+#define ERRNO_CHECK_RETURN_VOID(expr, op, cond) \
+ BASIC_ERRNO_CHECK(expr, op, cond, return)
+
+#define ERR_CHECK(expr, op, cond, fmt) \
+ BASIC_ERR_CHECK(expr, op, cond, fmt, (void) 0)
+
+#define ERRNO_CHECK(expr, op, cond) \
+ BASIC_ERRNO_CHECK(expr, op, cond, (void) 0)
+
+typedef struct _lpp_comm_t lpp_comm_t;
+
+lpp_comm_t *lpp_comm_new(int fd, size_t buf_size);
+
+int lpp_comm_fileno(const lpp_comm_t *comm);
+
+ssize_t lpp_flush(lpp_comm_t *comm);
+
+void lpp_comm_free(lpp_comm_t *comm);
+
+void lpp_print_err(const char *fmt, ...);
+
+void lpp_writel(lpp_comm_t *comm, uint32_t x);
+
+void lpp_writed(lpp_comm_t *comm, double dbl);
+
+void lpp_writes(lpp_comm_t *comm, const char *str);
+
+uint32_t lpp_readl(lpp_comm_t *comm);
+
+int lpp_read_cmd(lpp_comm_t *comm);
+
+double lpp_readd(lpp_comm_t *comm);
+
+char *lpp_reads(lpp_comm_t *comm);
+
+char *lpp_readbuf(lpp_comm_t *comm, char *buf, size_t buflen);
+
+int lpp_ack(lpp_comm_t *comm, char *buf, size_t buflen);
+
+void lpp_send_res(lpp_comm_t *comm, int ok, const char *fmt, ...);
+
+void lpp_send_ack(lpp_comm_t *comm);
+
+const char *lpp_get_cmd_name(int cmd);
+
+#endif
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#include "config.h"
+
+#ifdef WITH_CPLEX
+
+#include "lpp_cplex.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <ilcplex/cplex.h>
+
+#include "obst.h"
+#include "stat_timing.h"
+#include "sp_matrix.h"
+
+static char cpx_cst_encoding[4] = "?ELG";
+static char cpx_var_encoding[4] = "??CB";
+
+typedef struct _cpx_t {
+ lpp_t *lpp;
+ CPXENVptr env;
+ CPXLPptr prob;
+ int status;
+ char buf[1024];
+} cpx_t;
+
+static void chk_cpx_err(cpx_t *cpx)
+{
+ if (cpx->status) {
+ if (CPXgeterrorstring(cpx->env, cpx->status, cpx->buf))
+ printf("%s", cpx->buf);
+ else
+ printf("Unknown CPLEX error\n");
+ assert(0);
+ }
+}
+
+static cpx_t *new_cpx(lpp_t *lpp)
+{
+ cpx_t *cpx = XMALLOCZ(cpx_t);
+ cpx->lpp = lpp;
+ cpx->env = CPXopenCPLEX(&cpx->status);
+ chk_cpx_err(cpx);
+ cpx->prob = CPXcreateprob(cpx->env, &cpx->status, lpp->name);
+ chk_cpx_err(cpx);
+ CPXchgobjsen(cpx->env, cpx->prob, (lpp->opt_type == lpp_minimize)?1:-1);
+ chk_cpx_err(cpx);
+ if (lpp->log && CPXsetlogfile(cpx->env, lpp->log))
+ lpp->log = NULL;
+ return cpx;
+}
+
+static void free_cpx(cpx_t *cpx)
+{
+ CPXfreeprob(cpx->env, &cpx->prob);
+ CPXcloseCPLEX(&cpx->env);
+ free(cpx);
+}
+
+/**
+ * Build CPLEX data structure from LPP matrix.
+ * @note: The LPP matrix is freed after this step, to save memory.
+ */
+static void cpx_construct(cpx_t *cpx)
+{
+ const matrix_elem_t *elem;
+ int i, o, sv_cnt;
+ int numcols, numrows, numentries;
+ int objsen, *matbeg, *matcnt, *matind, *indices;
+ double *obj, *rhs, *matval, *lb, *ub, *startv;
+ char *sense, *vartype;
+ char **colname, **rowname;
+ struct obstack obst;
+ lpp_t *lpp = cpx->lpp;
+
+ numcols = lpp->var_next-1;
+ numrows = lpp->cst_next-1;
+ numentries = matrix_get_entries(lpp->m);
+ objsen = lpp->opt_type == lpp_minimize ? 1 : -1;
+ obstack_init(&obst);
+
+ obj = obstack_alloc(&obst, numcols * sizeof(*obj));
+ lb = obstack_alloc(&obst, numcols * sizeof(*lb));
+ ub = obstack_alloc(&obst, numcols * sizeof(*ub));
+ colname = obstack_alloc(&obst, numcols * sizeof(*colname));
+ rowname = obstack_alloc(&obst, numrows * sizeof(*rowname));
+ vartype = obstack_alloc(&obst, numcols * sizeof(*vartype));
+ indices = obstack_alloc(&obst, numcols * sizeof(*indices));
+ startv = obstack_alloc(&obst, numcols * sizeof(*startv));
+ matbeg = obstack_alloc(&obst, numcols * sizeof(*matbeg));
+ matcnt = obstack_alloc(&obst, numcols * sizeof(*matcnt));
+ matind = obstack_alloc(&obst, numentries * sizeof(*matind));
+ matval = obstack_alloc(&obst, numentries * sizeof(*matval));
+ rhs = obstack_alloc(&obst, numrows * sizeof(*rhs));
+ sense = obstack_alloc(&obst, numrows * sizeof(*sense));
+
+ o = 0;
+ sv_cnt = 0;
+ /* fill the CPLEX matrix*/
+ for (i = 0; i < numcols; ++i) {
+ lpp_name_t *curr_var = lpp->vars[1+i];
+
+ obj[i] = matrix_get(lpp->m, 0, 1+i);
+ lb[i] = 0.0;
+ ub[i] = CPX_INFBOUND;
+
+ colname[i] = (char*) curr_var->name;
+ vartype[i] = cpx_var_encoding[curr_var->type.var_type];
+
+ if (curr_var->value_kind == lpp_value_start) {
+ indices[sv_cnt] = i;
+ startv[sv_cnt++] = curr_var->value;
+ }
+
+ matbeg[i] = o;
+ matcnt[i] = 0;
+ matrix_foreach_in_col(lpp->m, 1 + i, elem) {
+ if (elem->row == 0)
+ continue;
+ matind[o] = elem->row-1;
+ matval[o] = elem->val;
+ matcnt[i]++;
+ o++;
+ }
+ }
+
+ /* get constraint stuff (right hand side, type, name) */
+ for (i = 0; i < numrows; ++i) {
+ lpp_name_t *curr_cst = lpp->csts[1 + i];
+
+ rhs[i] = matrix_get(lpp->m, 1 + i, 0);
+ sense[i] = cpx_cst_encoding[curr_cst->type.cst_type];
+ rowname[i] = (char*) curr_cst->name;
+ }
+
+ cpx->status = CPXcopylpwnames(cpx->env, cpx->prob,
+ numcols, numrows, objsen,
+ obj, rhs, sense,
+ matbeg, matcnt, matind, matval,
+ lb, ub, NULL,
+ colname, rowname);
+ chk_cpx_err(cpx);
+
+ cpx->status = CPXcopyctype(cpx->env, cpx->prob, vartype);
+ chk_cpx_err(cpx);
+ cpx->status = CPXcopymipstart(cpx->env, cpx->prob, sv_cnt, indices, startv);
+ chk_cpx_err(cpx);
+
+ obstack_free(&obst, NULL);
+ free_lpp_matrix(lpp);
+}
+
+static void cpx_solve(cpx_t *cpx)
+{
+ int i, CPX_state, numcols;
+ double *values;
+ timing_ticks_t tvb;
+ timing_ticks_t tva;
+
+ lpp_t *lpp = cpx->lpp;
+ numcols = CPXgetnumcols(cpx->env, cpx->prob);
+ chk_cpx_err(cpx);
+
+ /* set performance parameters */
+ // CPXsetintparam(cpx->env, CPX_PARAM_MIPSTART, CPX_ON);
+ CPXsetintparam(cpx->env, CPX_PARAM_MIPORDTYPE, CPX_MIPORDER_COST);
+ /* output every search tree node */
+ // CPXsetintparam(cpx->env, CPX_PARAM_MIPINTERVAL, 1);
+
+ /* experimental switches */
+ // CPXsetintparam(cpx->env, CPX_PARAM_VARSEL, CPX_VARSEL_STRONG);
+ // CPXsetdblparam(cpx->env, CPX_PARAM_BTTOL, 1.0);
+ // CPXsetintparam(cpx->env, CPX_PARAM_BRDIR, CPX_BRDIR_UP);
+
+
+ /* Set the time limit appropriately */
+ if(lpp->time_limit_secs > 0.0)
+ CPXsetdblparam(cpx->env, CPX_PARAM_TILIM, lpp->time_limit_secs);
+
+ /*
+ * If we have enough time, we instruct cplex to imply some
+ * of its higher order magic to pursue the best solution
+ */
+ if(lpp->emphasis) {
+ CPXsetintparam(cpx->env, CPX_PARAM_MIPEMPHASIS, lpp->emphasis);
+ }
+
+ /*
+ * If a bound of the objective function is supplied,
+ * set it accordingly, dependign on minimization or maximization.
+ */
+ if(lpp->set_bound) {
+ CPXsetdblparam(cpx->env, (lpp->opt_type == lpp_minimize
+ ? CPX_PARAM_OBJLLIM : CPX_PARAM_OBJULIM), lpp->bound);
+ }
+
+ /* turn on the fancy messages :) */
+ // CPXsetintparam (cpx->env, CPX_PARAM_SCRIND, CPX_ON);
+
+ /* solve */
+ timing_ticks(&tvb);
+ cpx->status = CPXmipopt(cpx->env, cpx->prob);
+ timing_ticks(&tva);
+ chk_cpx_err(cpx);
+
+ /* get solution status */
+ CPX_state = CPXgetstat(cpx->env, cpx->prob);
+ {
+ char buf[512];
+ CPXgetstatstring(cpx->env, CPX_state, buf);
+ fprintf(stderr, "%s\n", buf);
+ }
+ switch (CPX_state) {
+ case CPXMIP_INFEASIBLE:
+ case CPX_STAT_INFEASIBLE: lpp->sol_state = lpp_infeasible; break;
+ case CPXMIP_INForUNBD:
+ case CPX_STAT_INForUNBD: lpp->sol_state = lpp_inforunb; break;
+ case CPXMIP_UNBOUNDED:
+ case CPX_STAT_UNBOUNDED: lpp->sol_state = lpp_unbounded; break;
+ case CPXMIP_ABORT_FEAS:
+ case CPXMIP_FAIL_FEAS:
+ case CPXMIP_MEM_LIM_FEAS:
+ case CPXMIP_NODE_LIM_FEAS:
+ case CPXMIP_TIME_LIM_FEAS: lpp->sol_state = lpp_feasible; break;
+ case CPXMIP_OPTIMAL:
+ case CPXMIP_OPTIMAL_TOL: /* TODO: Is this ok? Read the docu more closely */
+ case CPX_STAT_OPTIMAL: lpp->sol_state = lpp_optimal; break;
+ default: lpp->sol_state = lpp_unknown;
+ }
+
+ /* get variable solution values */
+ values = alloca(numcols * sizeof(*values));
+ CPXgetmipx(cpx->env, cpx->prob, values, 0, numcols-1);
+ chk_cpx_err(cpx);
+ for(i=0; i<numcols; ++i) {
+ lpp->vars[1+i]->value = values[i];
+ lpp->vars[1+i]->value_kind = lpp_value_solution;
+ }
+
+ /* Get the value of the objective function. */
+ CPXgetmipobjval(cpx->env, cpx->prob, &lpp->objval);
+ CPXgetbestobjval(cpx->env, cpx->prob, &lpp->best_bound);
+
+ /* get some statistics */
+ timing_ticks_sub(tva, tvb);
+ lpp->sol_time = timing_ticks_dbl(tva);
+ lpp->iterations = CPXgetmipitcnt(cpx->env, cpx->prob);
+}
+
+void lpp_solve_cplex(lpp_t *lpp)
+{
+ cpx_t *cpx = new_cpx(lpp);
+ cpx_construct(cpx);
+ cpx_solve(cpx);
+ free_cpx(cpx);
+}
+
+#endif
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifndef LPP_CPLEX_H
+#define LPP_CPLEX_H
+
+#include "lpp.h"
+
+#ifdef WITH_CPLEX
+void lpp_solve_cplex(lpp_t *lpp);
+#endif
+
+#endif
--- /dev/null
+/**
+ * Author: Matthias Braun
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#include "config.h"
+
+#ifdef WITH_GUROBI
+#include "lpp_gurobi.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "obst.h"
+
+#include <gurobi_c.h>
+
+#include "error.h"
+#include "sp_matrix.h"
+
+static char gurobi_cst_encoding[4] = { 0, GRB_EQUAL, GRB_LESS_EQUAL, GRB_GREATER_EQUAL };
+static char gurobi_var_encoding[4] = { 0, 0, GRB_CONTINUOUS, GRB_BINARY };
+
+typedef struct _gurobi_t {
+ lpp_t *lpp;
+ GRBenv *env;
+ GRBmodel *model;
+} gurobi_t;
+
+static void check_gurobi_error(gurobi_t *grb, int error)
+{
+ if (error != 0) {
+ panic("gurobi error: %s", GRBgeterrormsg(grb->env));
+ }
+}
+
+static gurobi_t *new_gurobi(lpp_t *lpp)
+{
+ int error;
+
+ gurobi_t *grb = XMALLOCZ(gurobi_t);
+ grb->lpp = lpp;
+ error = GRBloadenv(&grb->env, NULL);
+ check_gurobi_error(grb, error);
+ error = GRBsetlogfile(grb->env, lpp->log);
+ check_gurobi_error(grb, error);
+
+ return grb;
+}
+
+static void free_gurobi(gurobi_t *grb)
+{
+ GRBfreeenv(grb->env);
+ free(grb);
+}
+
+/**
+ * Build CPLEX data structure from LPP matrix.
+ * @note: The LPP matrix is freed after this step, to save memory.
+ */
+static void gurobi_construct(gurobi_t *grb)
+{
+ const matrix_elem_t *elem;
+ int i, o;
+ //int sv_cnt;
+ //int *indices;
+ //double *startv;
+ int numcols, numrows, numentries;
+ int objsen, *matbeg, *matcnt, *matind;
+ double *obj, *rhs, *matval, *lb;
+ char *sense, *vartype;
+ char **colname, **rowname;
+ struct obstack obst;
+ lpp_t *lpp = grb->lpp;
+ int error;
+
+ numcols = lpp->var_next-1;
+ numrows = lpp->cst_next-1;
+ numentries = matrix_get_entries(lpp->m);
+ objsen = lpp->opt_type == lpp_minimize ? 1 : -1;
+ obstack_init(&obst);
+
+ obj = obstack_alloc(&obst, numcols * sizeof(*obj));
+ lb = obstack_alloc(&obst, numcols * sizeof(*lb));
+ colname = obstack_alloc(&obst, numcols * sizeof(*colname));
+ rowname = obstack_alloc(&obst, numrows * sizeof(*rowname));
+ vartype = obstack_alloc(&obst, numcols * sizeof(*vartype));
+ //indices = obstack_alloc(&obst, numcols * sizeof(*indices));
+ //startv = obstack_alloc(&obst, numcols * sizeof(*startv));
+ matbeg = obstack_alloc(&obst, numcols * sizeof(*matbeg));
+ matcnt = obstack_alloc(&obst, numcols * sizeof(*matcnt));
+ matind = obstack_alloc(&obst, numentries * sizeof(*matind));
+ matval = obstack_alloc(&obst, numentries * sizeof(*matval));
+ rhs = obstack_alloc(&obst, numrows * sizeof(*rhs));
+ sense = obstack_alloc(&obst, numrows * sizeof(*sense));
+
+ o = 0;
+ //sv_cnt = 0;
+ /* fill the CPLEX matrix*/
+ for (i = 0; i < numcols; ++i) {
+ lpp_name_t *curr_var = lpp->vars[1+i];
+
+ obj[i] = matrix_get(lpp->m, 0, 1+i);
+ lb[i] = 0.0;
+
+ colname[i] = (char*) curr_var->name;
+ vartype[i] = gurobi_var_encoding[curr_var->type.var_type];
+
+#if 0
+ if (curr_var->value_kind == lpp_value_start) {
+ panic("start values not supported in gurobi yet");
+ indices[sv_cnt] = i;
+ startv[sv_cnt++] = curr_var->value;
+ }
+#endif
+
+ matbeg[i] = o;
+ matcnt[i] = 0;
+ matrix_foreach_in_col(lpp->m, 1 + i, elem) {
+ if (elem->row == 0)
+ continue;
+ matind[o] = elem->row-1;
+ matval[o] = elem->val;
+ matcnt[i]++;
+ o++;
+ }
+ }
+
+ /* get constraint stuff (right hand side, type, name) */
+ for (i = 0; i < numrows; ++i) {
+ lpp_name_t *curr_cst = lpp->csts[1 + i];
+
+ rhs[i] = matrix_get(lpp->m, 1 + i, 0);
+ sense[i] = gurobi_cst_encoding[curr_cst->type.cst_type];
+ rowname[i] = (char*) curr_cst->name;
+ }
+
+ error = GRBloadmodel(grb->env, &grb->model, lpp->name, numcols, numrows,
+ objsen, 0, obj, sense, rhs, matbeg, matcnt, matind,
+ matval, lb, NULL, vartype, colname, rowname);
+ check_gurobi_error(grb, error);
+
+ obstack_free(&obst, NULL);
+ free_lpp_matrix(lpp);
+}
+
+static void gurobi_solve(gurobi_t *grb)
+{
+ lpp_t *lpp = grb->lpp;
+ int i;
+ int optimstatus;
+ int error;
+ int numcols = lpp->var_next-1;
+ double *values;
+ double iterations;
+
+ /* set performance parameters */
+ // CPXsetintparam(grb->env, CPX_PARAM_MIPSTART, CPX_ON);
+ //CPXsetintparam(grb->env, CPX_PARAM_MIPORDTYPE, CPX_MIPORDER_COST);
+ /* output every search tree node */
+ // CPXsetintparam(grb->env, CPX_PARAM_MIPINTERVAL, 1);
+
+ /* experimental switches */
+ // CPXsetintparam(grb->env, CPX_PARAM_VARSEL, CPX_VARSEL_STRONG);
+ // CPXsetdblparam(grb->env, CPX_PARAM_BTTOL, 1.0);
+ // CPXsetintparam(grb->env, CPX_PARAM_BRDIR, CPX_BRDIR_UP);
+
+ /* Set the time limit appropriately */
+ if(lpp->time_limit_secs > 0.0) {
+ error = GRBsetdblparam(grb->env, GRB_DBL_PAR_TIMELIMIT, lpp->time_limit_secs);
+ check_gurobi_error(grb, error);
+ }
+
+ /*
+ * If we have enough time, we instruct cplex to imply some
+ * of its higher order magic to pursue the best solution
+ */
+ if(lpp->emphasis) {
+ /* not implemented */
+ }
+
+ /*
+ * If a bound of the objective function is supplied,
+ * set it accordingly, dependign on minimization or maximization.
+ */
+ if(lpp->set_bound) {
+ //panic("bound not implemented yet");
+ fprintf(stderr, "Warning: gurobi bound not implemented yet\n");
+ }
+
+ /* solve */
+ error = GRBoptimize(grb->model);
+ check_gurobi_error(grb, error);
+
+ /* get solution status */
+ error = GRBgetintattr(grb->model, GRB_INT_ATTR_STATUS, &optimstatus);
+ check_gurobi_error(grb, error);
+
+ switch (optimstatus) {
+ case GRB_OPTIMAL: lpp->sol_state = lpp_optimal; break;
+ case GRB_INFEASIBLE: lpp->sol_state = lpp_infeasible; break;
+ case GRB_INF_OR_UNBD: lpp->sol_state = lpp_inforunb; break;
+ case GRB_UNBOUNDED: lpp->sol_state = lpp_unbounded; break;
+ /* TODO: is this correct? */
+ default: lpp->sol_state = lpp_feasible; break;
+ }
+
+ /* get variable solution values */
+ values = alloca(numcols * sizeof(*values));
+ error = GRBgetdblattrarray(grb->model, GRB_DBL_ATTR_X, 0, numcols, values);
+ check_gurobi_error(grb, error);
+ for(i=0; i<numcols; ++i) {
+ lpp->vars[1+i]->value = values[i];
+ lpp->vars[1+i]->value_kind = lpp_value_solution;
+ }
+
+ /* Get the value of the objective function. */
+ error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_OBJVAL, &lpp->objval);
+ check_gurobi_error(grb, error);
+ error = GRBgetdblattr(grb->model , GRB_DBL_ATTR_OBJBOUND, &lpp->best_bound);
+ check_gurobi_error(grb, error);
+
+ /* get some statistics */
+ error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_ITERCOUNT, &iterations);
+ check_gurobi_error(grb, error);
+ lpp->iterations = (unsigned) iterations;
+
+ error = GRBgetdblattr(grb->model, GRB_DBL_ATTR_RUNTIME, &lpp->sol_time);
+ check_gurobi_error(grb, error);
+}
+
+void lpp_solve_gurobi(lpp_t *lpp)
+{
+ gurobi_t *grb = new_gurobi(lpp);
+ gurobi_construct(grb);
+ gurobi_solve(grb);
+ free_gurobi(grb);
+}
+
+#endif
--- /dev/null
+/**
+ * Author: Matthias Braun
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifndef LPP_GUROBI_H
+#define LPP_GUROBI_H
+
+#include "lpp.h"
+
+#ifdef WITH_GUROBI
+void lpp_solve_gurobi(lpp_t *lpp);
+#endif
+
+#endif
--- /dev/null
+/**
+ * @file lpp_net.c
+ * @date 19.07.2005
+ * @author Sebastian Hack
+ *
+ * A client for an lpp solving server.
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+
+#ifdef _WIN32
+#include <winsock.h>
+#include <io.h>
+
+#else
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+
+/* solaris fix */
+#ifndef INADDR_NONE
+#define INADDR_NONE (in_addr_t)(-1)
+#endif
+
+#endif
+
+
+#include <signal.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "timing.h"
+
+#include "lpp_net.h"
+#include "lpp_t.h"
+#include "lpp_comm.h"
+
+#ifdef _WIN32
+static int winsock_init(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 2, 2 );
+
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 ) {
+ /* Tell the user that we could not find a usable */
+ /* WinSock DLL. */
+ return 0;
+ }
+
+ /* Confirm that the WinSock DLL supports 2.2.*/
+ /* Note that if the DLL supports versions greater */
+ /* than 2.2 in addition to 2.2, it will still return */
+ /* 2.2 in wVersion since that is the version we */
+ /* requested. */
+
+ if ( LOBYTE( wsaData.wVersion ) != 2 ||
+ HIBYTE( wsaData.wVersion ) != 2 ) {
+ /* Tell the user that we could not find a usable */
+ /* WinSock DLL. */
+ WSACleanup( );
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+static int connect_tcp(const char *host, uint16_t port)
+{
+ struct hostent *phe;
+ struct protoent *ppe;
+ struct sockaddr_in sin;
+ int s;
+
+#ifdef _WIN32
+ winsock_init();
+#endif
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+
+ if ((phe = gethostbyname(host)))
+ memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
+ else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
+ lpp_print_err("cannot get host entry for %s", host);
+ return -1;
+ }
+
+ ppe = getprotobyname("tcp");
+ ERRNO_CHECK_RETURN(s = socket(PF_INET, SOCK_STREAM, ppe->p_proto), <, 0, -1);
+ ERRNO_CHECK_RETURN(connect(s, (struct sockaddr *) &sin, sizeof(sin)), <, 0, -1);
+
+ return s;
+}
+
+char **lpp_get_solvers(const char *host)
+{
+ int fd, n;
+ char **res = NULL;
+ lpp_comm_t *comm;
+
+ ERR_CHECK_RETURN(fd = connect_tcp(host, LPP_PORT), <, 0,
+ ("could not connect to %s", host), NULL);
+
+ comm = lpp_comm_new(fd, LPP_BUFSIZE);
+
+ lpp_writel(comm, LPP_CMD_SOLVERS);
+ lpp_flush(comm);
+ n = lpp_readl(comm);
+ res = malloc((n + 1) * sizeof(res[0]));
+ res[n] = NULL;
+
+ if(n > 0) {
+ int i;
+ for(i = 0; i < n; ++i)
+ res[i] = lpp_reads(comm);
+ }
+
+ lpp_writel(comm, LPP_CMD_BYE);
+ lpp_flush(comm);
+ lpp_comm_free(comm);
+ close(fd);
+ return res;
+}
+
+void lpp_set_dbg(const char *host, int mask)
+{
+ int fd;
+ lpp_comm_t *comm;
+
+ ERR_CHECK_RETURN_VOID(fd = connect_tcp(host, LPP_PORT), <, 0, ("could not connect to %s", host));
+
+ comm = lpp_comm_new(fd, LPP_BUFSIZE);
+
+ lpp_writel(comm, LPP_CMD_SET_DEBUG);
+ lpp_writel(comm, mask);
+ lpp_flush(comm);
+ lpp_writel(comm, LPP_CMD_BYE);
+ lpp_flush(comm);
+ lpp_comm_free(comm);
+ close(fd);
+}
+
+void lpp_solve_net(lpp_t *lpp, const char *host, const char *solver)
+{
+ char buf[1024];
+ int n, fd, ready;
+ lpp_comm_t *comm;
+ ir_timer_t *t_send, *t_recv;
+
+ ERR_CHECK_RETURN_VOID(fd = connect_tcp(host, LPP_PORT), <, 0,
+ ("could not connect to %s", host));
+
+ comm = lpp_comm_new(fd, LPP_BUFSIZE);
+
+ /* Set the solver */
+ lpp_writel(comm, LPP_CMD_SOLVER);
+ lpp_writes(comm, solver);
+ lpp_flush(comm);
+
+#if 0
+ ERR_CHECK_RETURN_VOID(lpp_ack(fd, sizeof(buf), buf), == 0,
+ ("could not set solver: %s", solver));
+#endif
+
+ t_send = ir_timer_new();
+ t_recv = ir_timer_new();
+
+ ir_timer_push(t_send);
+ lpp_writel(comm, LPP_CMD_PROBLEM);
+ lpp_serialize(comm, lpp, 1);
+ lpp_serialize_values(comm, lpp, lpp_value_start);
+ lpp_flush(comm);
+ ir_timer_pop();
+ lpp->send_time = ir_timer_elapsed_usec(t_send);
+
+ ready = 0;
+ while (! ready) {
+ int cmd = lpp_readl(comm);
+ switch(cmd) {
+ case LPP_CMD_SOLUTION:
+ ir_timer_push(t_recv);
+ lpp_deserialize_stats(comm, lpp);
+ lpp_deserialize_values(comm, lpp, lpp_value_solution);
+ ir_timer_pop();
+ lpp->recv_time = ir_timer_elapsed_usec(t_recv);
+ ready = 1;
+ break;
+ case LPP_CMD_INFO:
+ lpp_readbuf(comm, buf, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+
+ if(lpp->log != NULL) {
+ fputs(buf, lpp->log);
+ n = strlen(buf);
+ if(buf[n - 1] != '\n')
+ putc('\n', lpp->log);
+ fflush(lpp->log);
+ }
+ break;
+ case LPP_CMD_BAD:
+ fprintf(stderr, "solver process died unexpectedly\n");
+ goto end;
+ default:
+ fprintf(stderr, "invalid command: %s(%d)\n", lpp_get_cmd_name(cmd), cmd);
+ return;
+ }
+ }
+
+ lpp_writel(comm, LPP_CMD_BYE);
+ lpp_flush(comm);
+
+end:
+ lpp_comm_free(comm);
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+}
--- /dev/null
+/**
+ * @file lpp_net.h
+ * @date 20.07.2005
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+#ifndef LPP_NET_H
+#define LPP_NET_H
+
+#include "lpp.h"
+
+char **lpp_get_solvers(const char *host);
+
+void lpp_set_dbg(const char *host, int mask);
+
+void lpp_solve_net(lpp_t *lpp, const char *host, const char *solver);
+
+#endif
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "lpp_remote.h"
+#include "assert.h"
+#include "mps.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <io.h>
+
+#define snprintf _snprintf
+#define chmod(a, b) _chmod(a, b)
+
+/* disable warning: 'foo' was declared deprecated, use 'bla' instead */
+/* of course MS had to make 'bla' incompatible to 'foo', so a simple */
+/* define will not work :-((( */
+#pragma warning( disable : 4996 )
+
+#endif
+
+/* CPLEX-account related stuff */
+#define DELETE_FILES /**< deletes all dumped files after use. Files on server are always deleted. */
+#define SSH_USER_HOST "kb61@sp-smp.rz.uni-karlsruhe.de"
+#define SSH_PASSWD_FILE "/ben/daniel/.smppw"
+#define EXPECT_FILENAME "runme" /* name of the expect-script */
+
+static FILE *ffopen(const char *base, const char *ext, const char *mode)
+{
+ FILE *out;
+ char buf[1024];
+
+ snprintf(buf, sizeof(buf), "%s.%s", base, ext);
+ if (! (out = fopen(buf, mode))) {
+ fprintf(stderr, "Cannot open file %s in mode %s\n", buf, mode);
+ return NULL;
+ }
+ return out;
+}
+
+static void lpp_write_cmd(lpp_t *lpp)
+{
+ FILE *out = ffopen(lpp->name, "cmd", "wt");
+ fprintf(out, "set logfile %s.sol\n", lpp->name);
+ fprintf(out, "set mip strategy mipstart 1\n");
+ // fprintf(out, "set mip emphasis 3\n"); /* moving best bound */
+ fprintf(out, "set mip emphasis 0\n"); /* balance optimality and feasability */
+ fprintf(out, "set mip strategy variableselect 3\n"); /* strong branching */
+ fprintf(out, "read %s.mps\n", lpp->name);
+ fprintf(out, "read %s.mst\n", lpp->name);
+ fprintf(out, "optimize\n");
+ fprintf(out, "display solution variables -\n");
+ fprintf(out, "quit\n");
+ fclose(out);
+}
+
+static void lpp_write_exp(lpp_t *lpp)
+{
+ FILE *pwfile, *out;
+ char passwd[128];
+
+ pwfile = fopen(SSH_PASSWD_FILE, "rt");
+ fgets(passwd, sizeof(passwd), pwfile);
+ fclose(pwfile);
+
+ out = ffopen(EXPECT_FILENAME, "exp", "wt");
+ fprintf(out, "#! /usr/bin/expect\n");
+ fprintf(out, "spawn scp %s.mps %s.mst %s.cmd %s:\n", lpp->name, lpp->name, lpp->name, SSH_USER_HOST); /* copy problem files */
+ fprintf(out, "expect \"word:\"\nsend \"%s\\n\"\ninteract\n", passwd);
+
+ fprintf(out, "spawn ssh %s \"./cplex90 < %s.cmd\"\n", SSH_USER_HOST, lpp->name); /* solve */
+ fprintf(out, "expect \"word:\"\nsend \"%s\\n\"\ninteract\n", passwd);
+
+ fprintf(out, "spawn scp %s:%s.sol .\n", SSH_USER_HOST, lpp->name); /*copy back solution */
+ fprintf(out, "expect \"word:\"\nsend \"%s\\n\"\ninteract\n", passwd);
+
+ fprintf(out, "spawn ssh %s ./dell\n", SSH_USER_HOST); /* clean files on server */
+ fprintf(out, "expect \"word:\"\nsend \"%s\\n\"\ninteract\n", passwd);
+ fclose(out);
+}
+
+static void lpp_read_solution(lpp_t *lpp)
+{
+ FILE *in;
+ double sol_time;
+ unsigned iter;
+ int vars_section = 0;
+ char var_name[128];
+ double var_value;
+
+ if (!(in = ffopen(lpp->name, "sol", "rt"))) {
+ lpp->sol_state = lpp_unknown;
+ return;
+ }
+ while (!feof(in)) {
+ char buf[1024];
+ fgets(buf, sizeof(buf), in);
+
+ /* error and solution state */
+ if (!strncmp(buf, "CPLEX Error", 11))
+ lpp->error = strdup(buf);
+ else if (!strncmp(buf, "Warning:", 8))
+ lpp->error = strdup(buf);
+ else if (!strncmp(buf, "Integer optimal solution:", 25))
+ lpp->sol_state = lpp_optimal;
+ else if (!strcmp(buf, "No integer feasible solution exists."))
+ lpp->sol_state = lpp_infeasible;
+ else if (!strcmp(buf, "Error termination, integer feasible:"))
+ lpp->sol_state = lpp_feasible;
+ /* stats */
+ else if (sscanf(buf, "Solution time = %lg sec. Iterations = %u", &sol_time, &iter) == 2) {
+ lpp->sol_time = sol_time;
+ lpp->iterations = iter;
+ }
+ /* variable values */
+ else if(!strcmp(buf, "Variable Name Solution Value")) {
+ int i;
+ vars_section = 1;
+ for(i=0; i<lpp->var_next; ++i) {
+ lpp_name_t *var = lpp->vars[i];
+ var->value = 0;
+ var->value_kind = lpp_value_solution;
+ }
+ }
+ else if(!strncmp(buf, "All other var", 13))
+ vars_section = 0;
+ else if (vars_section) {
+ if (sscanf(buf, "%s %lg", var_name, &var_value) == 2)
+ lpp->vars[lpp_get_var_idx(lpp, var_name)]->value = var_value;
+ else
+ assert(0 && "There should be variables to read in!");
+ }
+ }
+ fclose(in);
+ if (lpp->error) {
+ printf("\n%s\n", lpp->error);
+ assert(0);
+ }
+}
+
+#ifdef DELETE_FILES
+static void lpp_delete_files(lpp_t *lpp)
+{
+ char buf[1024];
+ int end = snprintf(buf, sizeof(buf), "%s", lpp->name);
+
+ snprintf(buf+end, sizeof(buf)-end, ".mps");
+ remove(buf);
+ snprintf(buf+end, sizeof(buf)-end, ".mst");
+ remove(buf);
+ snprintf(buf+end, sizeof(buf)-end, ".cmd");
+ remove(buf);
+ snprintf(buf+end, sizeof(buf)-end, ".sol");
+ remove(buf);
+ remove(EXPECT_FILENAME ".exp");
+}
+#endif
+
+void lpp_solve_remote(lpp_t *lpp)
+{
+ FILE *out;
+ out = ffopen(lpp->name, "mps", "wt");
+ mps_write_mps(lpp, s_mps_free, out);
+ fclose(out);
+
+ out = ffopen(lpp->name, "mst", "wt");
+ mps_write_mst(lpp, s_mps_free, out);
+ fclose(out);
+
+ lpp_write_cmd(lpp);
+ lpp_write_exp(lpp);
+
+ /* call the expect script */
+ chmod(EXPECT_FILENAME ".exp", 0700);
+ system(EXPECT_FILENAME ".exp");
+
+ lpp_read_solution(lpp);
+#ifdef DELETE_FILES
+ lpp_delete_files(lpp);
+#endif
+}
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+
+#ifndef _LPP_REMOTE_H_
+#define _LPP_REMOTE_H_
+
+#include "lpp.h"
+
+void lpp_solve_remote(lpp_t *lpp);
+
+#endif /*_LPP_REMOTE_H_*/
--- /dev/null
+/**
+ * @file lpp_solvers.c
+ * @date 16.06.2011
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2011 Saarland University
+ * Released under the LGPL
+ */
+#include "config.h"
+
+#include "lpp_cplex.h"
+#include "lpp_solvers.h"
+#include "lpp_gurobi.h"
+
+lpp_solver_t lpp_solvers[] = {
+#ifdef WITH_CPLEX
+ { lpp_solve_cplex, "cplex", 1 },
+#endif
+#ifdef WITH_GUROBI
+ { lpp_solve_gurobi, "gurobi", 1 },
+#endif
+ { NULL, NULL, 0 }
+};
+
+lpp_solver_func_t *lpp_find_solver(const char *name)
+{
+ int i;
+
+ for(i = 0; lpp_solvers[i].solver != NULL; i++)
+ if(strcmp(lpp_solvers[i].name, name) == 0)
+ return lpp_solvers[i].solver;
+
+ return NULL;
+}
--- /dev/null
+/**
+ * @file lpp_solvers.h
+ * @date 16.06.2011
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2011 Saarland University
+ * Released under the LGPL
+ */
+#ifndef LPP_SOLVER_H
+#define LPP_SOLVER_H
+
+#include "lpp.h"
+
+typedef void (lpp_solver_func_t)(lpp_t *lpp);
+
+typedef struct {
+ lpp_solver_func_t *solver;
+ const char *name;
+ int n_instances;
+} lpp_solver_t;
+
+extern lpp_solver_t lpp_solvers[];
+
+/**
+ * Find a solver for a given name.
+ */
+lpp_solver_func_t *lpp_find_solver(const char *name);
+
+#endif
--- /dev/null
+
+/**
+ * @file lpp_t.h
+ * @date 30.07.2005
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+#ifndef LPP_T_H
+#define LPP_T_H
+
+#include "lpp.h"
+#include "lpp_comm.h"
+
+/**
+ * Serialize a lpp to a file descriptor.
+ * @param comm The file descriptor.
+ * @param lpp The lpp.
+ * @param with_names Also send the names of constraints/variables.
+ */
+void lpp_serialize(lpp_comm_t *comm, const lpp_t *lpp, int with_names);
+
+/**
+ * Deserialize an lpp from a file descriptor.
+ * @param comm The file descriptor.
+ * @param with_names Also receive names of constraints/variables.
+ * @return The Problem.
+ */
+lpp_t *lpp_deserialize(lpp_comm_t *comm);
+
+/**
+ * Serialize values of the lpps for a given value kind.
+ * This function only serializes values of the given kind.
+ * @param fd The file descriptor to serialize to.
+ * @param lpp The problem.
+ * @param kind The value kind.
+ */
+void lpp_serialize_values(lpp_comm_t *comm, const lpp_t *lpp, lpp_value_kind_t kind);
+
+/**
+ * Desrialize values from a stream.
+ * @param fd The file descriptor to read from.
+ * @param lpp The problem to set the values.
+ * @param kind The value kind the values shall be assigned.
+ */
+void lpp_deserialize_values(lpp_comm_t *comm, lpp_t *lpp, lpp_value_kind_t kind);
+
+void lpp_serialize_stats(lpp_comm_t *comm, const lpp_t *lpp);
+void lpp_deserialize_stats(lpp_comm_t *comm, lpp_t *lpp);
+
+#endif
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#include "config.h"
+#include <stdarg.h>
+#include <assert.h>
+#include "mps.h"
+
+/**
+ * These must comply to the enum cst_t in lpp.h
+ */
+static const char *mps_cst_encoding[4] = {"N", "E", "L", "G"};
+
+/**
+ * Diffferent line styles which can be used in a mps file
+ */
+typedef enum _mps_line_t {l_raw,
+ l_ind_name, l_ind_objs, l_ind_rows, l_ind_cols, l_ind_rhs, l_ind_end,
+ l_data_row, l_data_col1, l_data_col2, l_data_mst, l_marker} mps_line_t;
+
+static void mps_write_line(FILE *out, style_t style, mps_line_t line_type, ...) {
+ va_list args;
+ const char *fmt = "";
+
+ assert(style == s_mps_fixed || style == s_mps_free);
+ va_start(args, line_type);
+
+ if (style == s_mps_fixed) {
+ /* white spaces are important! */
+ switch (line_type) {
+ case l_raw: fmt = "%s\n"; break;
+ case l_ind_name: fmt = "NAME %s\n"; break;
+ case l_ind_objs: fmt = "OBJSENSE\n"; break;
+ case l_ind_rows: fmt = "ROWS\n"; break;
+ case l_ind_cols: fmt = "COLUMNS\n"; break;
+ case l_ind_rhs: fmt = "RHS\n"; break;
+ case l_ind_end: fmt = "ENDATA\n"; break;
+ case l_data_row: fmt = " %-2s %-8s\n"; break; /* Field 1-2 */
+ case l_data_col1: fmt = " %-8s %-8s %12g\n"; break; /* Field 2-4 */
+ case l_data_col2: fmt = " %-8s %-8s %12g %-8s %12g\n"; break; /* Field 2-6 */
+ case l_data_mst: fmt = " %-8s %12g\n"; break; /* Field 3-4 */
+ case l_marker: fmt = " M%-7d 'MARKER' '%s'\n"; break; /* Field 2,3,5 */
+ default: assert(0);
+ }
+ } else {
+ switch (line_type) {
+ case l_raw: fmt = "%s\n"; break;
+ case l_ind_name: fmt = "NAME %s\n"; break;
+ case l_ind_objs: fmt = "OBJSENSE\n"; break;
+ case l_ind_rows: fmt = "ROWS\n"; break;
+ case l_ind_cols: fmt = "COLUMNS\n"; break;
+ case l_ind_rhs: fmt = "RHS\n"; break;
+ case l_ind_end: fmt = "ENDATA\n"; break;
+ case l_data_row: fmt = " %s\t%s\n"; break;
+ case l_data_col1: fmt = " %s\t%s\t%g\n"; break;
+ case l_data_col2: fmt = " %s\t%s\t%g\t%s\t%g\n"; break;
+ case l_data_mst: fmt = " %s\t%g\n"; break;
+ case l_marker: fmt = " M%d\t'MARKER'\t'%s'\n"; break;
+ default: assert(0);
+ }
+ }
+
+ vfprintf(out, fmt, args);
+ va_end(args);
+}
+
+static int mps_insert_markers(FILE *out, style_t style, lpp_var_t curr, lpp_var_t last, int marker_nr)
+{
+ assert(style == s_mps_fixed || style == s_mps_free);
+ if (last != curr) {
+ /* print end-marker for last */
+ if (last == lpp_binary)
+ mps_write_line(out, style, l_marker, marker_nr++, "INTEND");
+
+ /* print begin-marker for curr */
+ if (curr == lpp_binary)
+ mps_write_line(out, style, l_marker, marker_nr++, "INTORG");
+ }
+ return marker_nr;
+}
+
+void mps_write_mps(lpp_t *lpp, style_t style, FILE *out)
+{
+ int i, count, marker_nr = 0;
+ const lpp_name_t *curr;
+ const matrix_elem_t *elem, *before = NULL;
+ lpp_var_t last_type;
+ assert(style == s_mps_fixed || style == s_mps_free);
+
+ /* NAME */
+ mps_write_line(out, style, l_ind_name, lpp->name);
+
+ /* OBJSENSE */
+ if (lpp->opt_type == lpp_maximize) {
+ mps_write_line(out, style, l_ind_objs);
+ mps_write_line(out, style, l_raw, " MAX");
+ }
+
+ /* ROWS */
+ mps_write_line(out, style, l_ind_rows);
+ for(i=0; i<lpp->cst_next; ++i) {
+ curr = lpp->csts[i];
+ mps_write_line(out, style, l_data_row, mps_cst_encoding[curr->type.cst_type], curr->name);
+ }
+
+ /* COLUMNS */
+ mps_write_line(out, style, l_ind_cols);
+ last_type = lpp_invalid;
+ for(i=1; i<lpp->var_next; ++i) { /* column 0 is rhs */
+ curr = lpp->vars[i];
+
+ /* markers */
+ marker_nr = mps_insert_markers(out, style, curr->type.var_type, last_type, marker_nr);
+ last_type = curr->type.var_type;
+
+ /* participation in constraints */
+ count = 0;
+ matrix_foreach_in_col(lpp->m, curr->nr, elem) {
+ if (count == 0) {
+ before = elem;
+ count = 1;
+ } else {
+ mps_write_line(out, style, l_data_col2, curr->name, lpp->csts[before->row]->name, (double)before->val, lpp->csts[elem->row]->name, (double)elem->val);
+ count = 0;
+ }
+ }
+ if (count == 1)
+ mps_write_line(out, style, l_data_col1, curr->name, lpp->csts[before->row]->name, (double)before->val);
+ }
+ mps_insert_markers(out, style, lpp_invalid, last_type, marker_nr); /* potential end-marker */
+
+ /* RHS */
+ mps_write_line(out, style, l_ind_rhs);
+ count = 0;
+ matrix_foreach_in_col(lpp->m, 0, elem) {
+ if (count == 0) {
+ before = elem;
+ count = 1;
+ } else {
+ mps_write_line(out, style, l_data_col2, "rhs", lpp->csts[before->row]->name, (double)before->val, lpp->csts[elem->row]->name, (double)elem->val);
+ count = 0;
+ }
+ }
+ if (count == 1)
+ mps_write_line(out, style, l_data_col1, "rhs", lpp->csts[before->row]->name, (double)before->val);
+
+ /* ENDATA */
+ mps_write_line(out, style, l_ind_end);
+}
+
+void mps_write_mst(lpp_t *lpp, style_t style, FILE *out)
+{
+ int i;
+ mps_write_line(out, style, l_ind_name, "");
+ for (i=0; i<lpp->var_next; ++i) {
+ const lpp_name_t *var = lpp->vars[i];
+ if (var->value_kind == lpp_value_start)
+ mps_write_line(out, style, l_data_mst, var->name, (double)var->value);
+ }
+ mps_write_line(out, style, l_ind_end);
+}
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 02.06.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ */
+#ifndef MPS_H
+#define MPS_H
+
+#include <stdio.h>
+#include "lpp.h"
+
+/**
+ * Two styles of mps files
+ *
+ * s_mps_fixed: mps where spaces are allowed in identifiers
+ * and all things have a fixed column... :-0
+ * s_mps_free: mps where whitespace is a seperator :-)
+ */
+typedef enum _style_t {s_mps_fixed, s_mps_free} style_t;
+
+/**
+ * Writes the description of a lp problem object (lpp)
+ * to the stream out, using the specified style.
+ */
+void mps_write_mps(lpp_t *lpp, style_t style, FILE *out);
+
+/**
+ * Writes the start values of a lp problem object (lpp)
+ * to the stream out, using the specified style.
+ */
+void mps_write_mst(lpp_t *lpp, style_t style, FILE *out);
+
+#endif
--- /dev/null
+/**
+ * Author: Daniel Grund, Christian Wuerdig
+ * Date: 07.04.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ * CVS-Id: $Id: sp_matrix.c 24123 2008-11-28 15:08:27Z mallon $
+ *
+ * Sparse matrix storage with linked lists for rows and cols.
+ * Matrix is optimized for left-to-right and top-to-bottom access.
+ * Complexity is O(1) then.
+ * Random access or right-to-left and bottom-to-top is O(m*n).
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+
+#include "sp_matrix.h"
+
+#include "irtools.h"
+#include "bitset.h"
+#include "xmalloc.h"
+
+typedef enum iter_direction_t {
+ down, right, all
+} iter_direction_t;
+
+/**
+ * Embedded list pointer.
+ */
+typedef struct sp_matrix_list_head_t {
+ struct sp_matrix_list_head_t *next;
+} sp_matrix_list_head_t;
+
+/**
+ * A matrix entry.
+ */
+typedef struct entry_t {
+ sp_matrix_list_head_t col_chain; /**< points to next element in same column */
+ sp_matrix_list_head_t row_chain; /**< points to next element in same row */
+ matrix_elem_t e; /**< The actual element */
+} entry_t;
+
+struct sp_matrix_t {
+ /* These specify the dimensions of the matrix.
+ * They equal the largest values ever used in matrix_set */
+ int maxrow, maxcol;
+ /* These are the dimensions of allocated arrays below.
+ * rowc >= maxrow and colc >= maxcol hold. */
+ int rowc, colc;
+ /* number of entries */
+ int entries;
+ /* arrays of sp_matrix_list_head* as entry-points to rows and cols */
+ sp_matrix_list_head_t **rows, **cols;
+ /* for iteration: first is to remember start-point;
+ * last was returned just before
+ * next is used in case last was removed from list */
+ iter_direction_t dir;
+ sp_matrix_list_head_t *first, *last, *next;
+ int iter_row; /* used for iteration over all elements */
+ /* for each column the last inserted element in col list */
+ sp_matrix_list_head_t **last_col_el;
+ /* for each row the last inserted element in row list */
+ sp_matrix_list_head_t **last_row_el;
+};
+
+#define SP_MATRIX_INIT_LIST_HEAD(ptr) do { (ptr)->next = NULL; } while (0)
+
+#define _offsetof(type,member) ((char *) &(((type *) 0)->member) - (char *) 0)
+#define _container_of(ptr,type,member) ((type *) ((char *) (ptr) - _offsetof(type, member)))
+
+#define is_empty_row(row) (row > m->maxrow || (m->rows[row])->next == NULL)
+#define is_empty_col(col) (col > m->maxcol || (m->cols[col])->next == NULL)
+
+#define list_entry_by_col(h) (&_container_of(h, entry_t, col_chain)->e)
+#define list_entry_by_row(h) (&_container_of(h, entry_t, row_chain)->e)
+
+/**
+ * Returns the size of a single matrix element.
+ */
+unsigned matrix_get_elem_size(void)
+{
+ return sizeof(entry_t);
+}
+
+/**
+ * Returns the new size for an array of size old_size,
+ * which must at least store an entry at position min.
+ */
+static inline int m_new_size(int old_size, int min)
+{
+ unsigned bits = 0;
+ assert(min >= old_size);
+ while (min > 0) {
+ min >>= 1;
+ bits++;
+ }
+ assert(bits < sizeof(min) * 8 - 1);
+ return 1 << bits;
+}
+
+/**
+ * Allocates space for @p count entries in the rows array and
+ * initializes all entries from @p start to the end.
+ */
+static inline void m_alloc_row(sp_matrix_t *m, int start, int count)
+{
+ int p;
+
+ m->rowc = count;
+ m->rows = XREALLOC(m->rows, sp_matrix_list_head_t *, m->rowc);
+ m->last_row_el = XREALLOC(m->last_row_el, sp_matrix_list_head_t *, m->rowc);
+
+ for (p = start; p < m->rowc; ++p) {
+ m->rows[p] = XMALLOC(sp_matrix_list_head_t);
+ SP_MATRIX_INIT_LIST_HEAD(m->rows[p]);
+ m->last_row_el[p] = m->rows[p];
+ }
+}
+
+/**
+ * Allocates space for @p count entries in the cols array and
+ * initializes all entries from @p start to the end.
+ */
+static inline void m_alloc_col(sp_matrix_t *m, int start, int count)
+{
+ int p;
+
+ m->colc = count;
+ m->cols = XREALLOC(m->cols, sp_matrix_list_head_t*, m->colc);
+ m->last_col_el = XREALLOC(m->last_col_el, sp_matrix_list_head_t*, m->colc);
+
+ for (p = start; p < m->colc; ++p) {
+ m->cols[p] = XMALLOC(sp_matrix_list_head_t);
+ SP_MATRIX_INIT_LIST_HEAD(m->cols[p]);
+ m->last_col_el[p] = m->cols[p];
+ }
+}
+
+/**
+ * Searches in row @p row for the matrix element m[row, col], starting at element @p start.
+ * @return If the element exists:
+ * Element m[row, col] and @p prev points to the sp_matrix_list_head in the entry_t holding the element.
+ * Else: NULL and @p prev points to the sp_matrix_list_head after which the element would be inserted.
+ * @p prev_prev always points to the previous element of @p prev
+ */
+static inline matrix_elem_t *m_search_in_row_from(const sp_matrix_t *m,
+ int row, int col, sp_matrix_list_head_t *start, sp_matrix_list_head_t **prev, sp_matrix_list_head_t **prev_prev)
+{
+ sp_matrix_list_head_t *row_start;
+ matrix_elem_t *res = NULL;
+
+ row_start = m->rows[row];
+ *prev = start;
+
+ while ((*prev)->next != NULL && list_entry_by_row((*prev)->next)->col <= col) {
+ (*prev_prev) = (*prev);
+ *prev = (*prev)->next;
+ }
+
+ if (*prev != row_start) {
+ matrix_elem_t *me = list_entry_by_row(*prev);
+
+ if (me->row == row && me->col == col)
+ res = me;
+ }
+
+ if (res) {
+ m->last_row_el[row] = *prev;
+ }
+
+ return res;
+}
+
+/**
+ * Searches in row @p row for the matrix element m[row, col].
+ * @return If the element exists:
+ * Element m[row, col] and @p prev points to the sp_matrix_list_head in the entry_t holding the element.
+ * Else: NULL and @p prev points to the sp_matrix_list_head after which the element would be inserted.
+ * @p prev_prev always points to the previous element of @p prev
+ */
+static inline matrix_elem_t *m_search_in_row(const sp_matrix_t *m,
+ int row, int col, sp_matrix_list_head_t **prev, sp_matrix_list_head_t **prev_prev)
+{
+ sp_matrix_list_head_t *start = m->rows[row];
+
+ *prev_prev = NULL;
+
+ if (m->last_row_el[row] != start) {
+ matrix_elem_t *el = list_entry_by_row(m->last_row_el[row]);
+ if (el->col < col) {
+ *prev_prev = start = m->last_row_el[row];
+ }
+ }
+
+ return m_search_in_row_from(m, row, col, start, prev, prev_prev);
+}
+
+/**
+ * Searches in col @p col for the matrix element m[row, col], starting at @p start.
+ * @return If the element exists:
+ * Element m[row, col] and @p prev points to the sp_matrix_list_head in the entry_t holding the element.
+ * Else: NULL and @p prev points to the sp_matrix_list_head after which the element would be inserted.
+ * @p prev_prev always points to the previous element of @p prev
+ */
+static inline matrix_elem_t *m_search_in_col_from(const sp_matrix_t *m,
+ int row, int col, sp_matrix_list_head_t *start, sp_matrix_list_head_t **prev, sp_matrix_list_head_t **prev_prev)
+{
+ sp_matrix_list_head_t *col_start;
+ matrix_elem_t *res = NULL;
+
+ col_start = m->cols[col];
+ *prev = start;
+
+ while ((*prev)->next != NULL && list_entry_by_col((*prev)->next)->row <= row) {
+ *prev_prev = (*prev);
+ *prev = (*prev)->next;
+ }
+
+ if (*prev != col_start) {
+ matrix_elem_t *me = list_entry_by_col(*prev);
+
+ if (me->row == row && me->col == col)
+ res = me;
+ }
+
+ if (res) {
+ m->last_col_el[col] = *prev;
+ }
+
+ return res;
+}
+
+/**
+ * Searches in col @p col for the matrix element m[row, col].
+ * @return If the element exists:
+ * Element m[row, col] and @p prev points to the sp_matrix_list_head in the entry_t holding the element.
+ * Else: NULL and @p prev points to the sp_matrix_list_head after which the element would be inserted.
+ * @p prev_prev always points to the previous element of @p prev
+ */
+static inline matrix_elem_t *m_search_in_col(const sp_matrix_t *m,
+ int row, int col, sp_matrix_list_head_t **prev, sp_matrix_list_head_t **prev_prev)
+{
+ sp_matrix_list_head_t *start = m->cols[col];
+
+ *prev_prev = NULL;
+
+ if (m->last_col_el[col] != start) {
+ matrix_elem_t *el = list_entry_by_col(m->last_col_el[col]);
+ if (el->row < row) {
+ *prev_prev = start = m->last_col_el[col];
+ }
+ }
+
+ return m_search_in_col_from(m, row, col, start, prev, prev_prev);
+}
+
+sp_matrix_t *new_matrix(int row_init, int col_init)
+{
+ sp_matrix_t *res = XMALLOCZ(sp_matrix_t);
+ res->maxrow = -1;
+ res->maxcol = -1;
+ m_alloc_row(res, 0, MAX(0, row_init));
+ m_alloc_col(res, 0, MAX(0, col_init));
+ return res;
+}
+
+void del_matrix(sp_matrix_t *m)
+{
+ int i;
+
+ for (i = 0; i < m->rowc; ++i) {
+ if (! is_empty_row(i)) {
+ entry_t *e;
+ sp_matrix_list_head_t *n;
+
+ n = m->rows[i]->next;
+ do {
+ /* get current matrix element */
+ e = _container_of(n, entry_t, row_chain);
+ n = n->next;
+ xfree(e);
+ } while (n != NULL);
+
+ }
+ xfree(m->rows[i]);
+ }
+ for (i = 0; i < m->colc; ++i)
+ xfree(m->cols[i]);
+ xfree(m->last_col_el);
+ xfree(m->last_row_el);
+ xfree(m->rows);
+ xfree(m->cols);
+ xfree(m);
+}
+
+void matrix_set(sp_matrix_t *m, int row, int col, double val)
+{
+ matrix_elem_t *me = NULL;
+ entry_t *entr;
+ sp_matrix_list_head_t *leftof, *above;
+ sp_matrix_list_head_t *prev_leftof, *prev_above;
+
+ /* if necessary enlarge the matrix */
+ if (row > m->maxrow) {
+ m->maxrow = row;
+ if (row >= m->rowc)
+ m_alloc_row(m, m->rowc, m_new_size(m->rowc, row));
+ }
+ if (col > m->maxcol) {
+ m->maxcol = col;
+ if (col >= m->colc)
+ m_alloc_col(m, m->colc, m_new_size(m->colc, col));
+ }
+
+ /* search for existing entry */
+ if (m->maxrow < m->maxcol)
+ me = m_search_in_col(m, row, col, &above, &prev_above);
+ else
+ me = m_search_in_row(m, row, col, &leftof, &prev_leftof);
+
+ /* if it exists, set the value and return */
+ if (me) {
+ if (val != 0) {
+ me->val = (float)val;
+ } else {
+ entr = _container_of(me, entry_t, e);
+
+ /* remove row_chain entry */
+ if (prev_leftof)
+ prev_leftof->next = entr->row_chain.next;
+ else
+ m->rows[row]->next = entr->row_chain.next;
+
+ /* remove col_chain entry */
+ if (prev_above)
+ prev_above->next = entr->col_chain.next;
+ else
+ m->cols[col]->next = entr->col_chain.next;
+
+ entr->row_chain.next = NULL;
+ entr->col_chain.next = NULL;
+
+ /* set the last pointer to the "previous" element */
+ if (m->last_col_el[col] == &entr->col_chain ||
+ m->last_row_el[row] == &entr->row_chain)
+ {
+ m->last_col_el[col] = prev_above ? prev_above : m->cols[col];
+ m->last_row_el[row] = prev_leftof ? prev_leftof : m->rows[row];
+ }
+
+ free(entr);
+ m->entries--;
+ }
+ return;
+ }
+
+ /* if it does not exist and 0 should be set just quit */
+ if (val == 0)
+ return;
+
+ /* if it does not exist and val != 0 search the other direction */
+ if (m->maxrow >= m->maxcol)
+ m_search_in_col(m, row, col, &above, &prev_above);
+ else
+ m_search_in_row(m, row, col, &leftof, &prev_leftof);
+ /* now leftof and above are the entry_t's prior the new one in each direction */
+
+ /* insert new entry */
+ entr = XMALLOC(entry_t);
+ entr->e.row = row;
+ entr->e.col = col;
+ entr->e.val = (float)val;
+
+ /* add row_chain entry */
+ entr->row_chain.next = leftof->next;
+ leftof->next = &entr->row_chain;
+
+ /* add col_chain entry */
+ entr->col_chain.next = above->next;
+ above->next = &entr->col_chain;
+
+ m->last_col_el[col] = &entr->col_chain;
+ m->last_row_el[row] = &entr->row_chain;
+
+ m->entries++;
+}
+
+void matrix_set_row_bulk(sp_matrix_t *m, int row, int *cols, int num_cols, double val)
+{
+ matrix_elem_t *me = NULL;
+ entry_t *entr;
+ int i;
+ sp_matrix_list_head_t *leftof, *above;
+ sp_matrix_list_head_t *prev_leftof, *prev_above;
+
+ /* if necessary enlarge the matrix */
+ if (row > m->maxrow) {
+ m->maxrow = row;
+ if (row >= m->rowc)
+ m_alloc_row(m, m->rowc, m_new_size(m->rowc, row));
+ }
+ if (cols[num_cols - 1] > m->maxcol) {
+ m->maxcol = cols[num_cols - 1];
+ if (cols[num_cols - 1] >= m->colc)
+ m_alloc_col(m, m->colc, m_new_size(m->colc, cols[num_cols - 1]));
+ }
+
+ /* set start values */
+ prev_above = NULL;
+ prev_leftof = NULL;
+
+ for (i = 0; i < num_cols; ++i) {
+ /* search for existing entry */
+ me = m_search_in_row(m, row, cols[i], &leftof, &prev_leftof);
+
+ /* if it exists, set the value and return */
+ if (me) {
+ if (val != 0) {
+ me->val = (float)val;
+ } else {
+ entr = _container_of(me, entry_t, e);
+
+ /* remove row_chain entry */
+ if (prev_leftof)
+ prev_leftof->next = entr->row_chain.next;
+ else
+ m->rows[row]->next = entr->row_chain.next;
+
+ /* remove col_chain entry */
+ if (prev_above)
+ prev_above->next = entr->col_chain.next;
+ else
+ m->cols[cols[i]]->next = entr->col_chain.next;
+
+ entr->row_chain.next = NULL;
+ entr->col_chain.next = NULL;
+
+ /* set the last pointer to the "previous" element */
+ if (m->last_col_el[cols[i]] == &entr->col_chain ||
+ m->last_row_el[row] == &entr->row_chain)
+ {
+ m->last_col_el[cols[i]] = prev_above ? prev_above : m->cols[cols[i]];
+ m->last_row_el[row] = prev_leftof ? prev_leftof : m->rows[row];
+ }
+
+ free(entr);
+ m->entries--;
+ }
+
+ continue;
+ }
+
+ /* if it does not exist and 0 should be set just quit */
+ if (val == 0)
+ continue;
+
+ /* we have to search the col list as well, to get the above pointer */
+ m_search_in_col(m, row, cols[i], &above, &prev_above);
+
+ /* now leftof and above are the entry_t's prior the new one in each direction */
+
+ /* insert new entry */
+ entr = XMALLOC(entry_t);
+ entr->e.row = row;
+ entr->e.col = cols[i];
+ entr->e.val = (float)val;
+
+ m->last_col_el[cols[i]] = &entr->col_chain;
+ m->last_row_el[row] = &entr->row_chain;
+
+ /* add row_chain entry */
+ entr->row_chain.next = leftof->next;
+ leftof->next = &entr->row_chain;
+
+ /* add col_chain entry */
+ entr->col_chain.next = above->next;
+ above->next = &entr->col_chain;
+
+ m->entries++;
+ }
+}
+
+double matrix_get(const sp_matrix_t *m, int row, int col)
+{
+ sp_matrix_list_head_t *dummy, *dummy2;
+ matrix_elem_t *me;
+
+ if (is_empty_row(row) || is_empty_col(col))
+ return 0.0;
+
+ if (m->maxrow < m->maxcol)
+ me = m_search_in_col(m, row, col, &dummy, &dummy2);
+ else
+ me = m_search_in_row(m, row, col, &dummy, &dummy2);
+
+ if (me)
+ assert(me->col == col && me->row == row);
+
+ return me ? me->val : 0.0;
+}
+
+int matrix_get_entries(const sp_matrix_t *m)
+{
+ return m->entries;
+}
+
+int matrix_get_rowcount(const sp_matrix_t *m)
+{
+ return m->maxrow + 1;
+}
+
+int matrix_get_colcount(const sp_matrix_t *m)
+{
+ return m->maxcol + 1;
+}
+
+const matrix_elem_t *matrix_row_first(sp_matrix_t *m, int row)
+{
+ if (is_empty_row(row))
+ return NULL;
+
+ m->dir = right;
+ m->first = m->rows[row];
+ m->last = m->first->next;
+ m->next = m->last ? m->last->next : NULL;
+
+ assert (list_entry_by_row(m->last)->row == row);
+
+ return list_entry_by_row(m->last);
+}
+
+const matrix_elem_t *matrix_col_first(sp_matrix_t *m, int col)
+{
+ if (is_empty_col(col))
+ return NULL;
+
+ m->dir = down;
+ m->first = m->cols[col];
+ m->last = m->first->next;
+ m->next = m->last ? m->last->next : NULL;
+
+ assert (list_entry_by_col(m->last)->col == col);
+
+ return list_entry_by_col(m->last);
+}
+
+static inline const matrix_elem_t *matrix_first_from(sp_matrix_t *m, int startrow)
+{
+ const matrix_elem_t *res;
+ int i;
+
+ for (i = startrow; i <= m->maxrow; ++i) {
+ res = matrix_row_first(m, i);
+ if (res) {
+ m->iter_row = i;
+ m->dir = all;
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+const matrix_elem_t *matrix_first(sp_matrix_t *m)
+{
+ return matrix_first_from(m, 0);
+}
+
+const matrix_elem_t *matrix_next(sp_matrix_t *m)
+{
+ assert(m->first && "Start iteration with matrix_???_first, before calling me!");
+
+ if (m->next == NULL) {
+ if (m->dir == all)
+ return matrix_first_from(m, ++m->iter_row);
+ else
+ return NULL;
+ }
+
+ m->last = m->next;
+ m->next = m->next->next;
+
+ if (m->dir == down)
+ return list_entry_by_col(m->last);
+ else /* right or all */
+ return list_entry_by_row(m->last);
+}
+
+static int cmp_count(const void *e1, const void *e2)
+{
+ return (int *)e2 - (int *)e1;
+}
+
+static inline void matrix_fill_row(sp_matrix_t *m, int row, bitset_t *fullrow)
+{
+ const matrix_elem_t *e;
+ bitset_set(fullrow, row);
+ matrix_foreach_in_col(m, row, e) {
+ if (! bitset_is_set(fullrow, e->row)) {
+ assert(0.0 == matrix_get(m, e->col, e->row));
+ matrix_set(m, e->col, e->row, e->val);
+ matrix_set(m, e->row, e->col, 0.0);
+ }
+ }
+}
+
+void matrix_optimize(sp_matrix_t *m)
+{
+ int i, size, redo;
+ int *c;
+ const matrix_elem_t *e;
+ bitset_t *fullrow;
+
+ size = MAX(m->maxcol, m->maxrow)+1;
+
+ /* kill all double-entries (Mij and Mji are set) */
+ matrix_foreach(m, e) {
+ double t_val;
+
+ assert(e->row != e->col && "Root has itself as arg. Ok. But the arg (=root) will always have the same color as root");
+ t_val = matrix_get(m, e->col, e->row);
+ if (fabs(t_val) > 1e-10) {
+ matrix_set(m, e->col, e->row, 0);
+ matrix_set(m, e->row, e->col, e->val + t_val);
+ }
+ }
+
+ c = alloca(size * sizeof(*c));
+ redo = 1;
+ fullrow = bitset_alloca(size);
+
+ /* kill 'all' rows containing only 1 entry */
+ while (redo) {
+ redo = 0;
+ /* count elements in rows */
+ memset(c, 0, size * sizeof(*c));
+
+ matrix_foreach(m, e)
+ c[e->row]++;
+
+ for (i = 0; i<size; ++i)
+ if (c[i] == 1 && ! bitset_is_set(fullrow, i)) {
+ redo = 1;
+ /* if the other row isn't empty move the e in there, else fill e's row */
+ if (e = matrix_row_first(m, i), e) {
+ if (c[e->col] > 0)
+ matrix_fill_row(m, e->col, fullrow);
+ else
+ matrix_fill_row(m, e->row, fullrow);
+ }
+ }
+ }
+
+
+ memset(c, 0, size * sizeof(*c));
+ matrix_foreach(m, e)
+ c[e->row]++;
+
+ qsort(c, size, sizeof(*c), cmp_count);
+
+ for (i = 0; i < size; ++i) {
+ if (! bitset_is_set(fullrow, i))
+ matrix_fill_row(m, i, fullrow);
+ }
+}
+
+void matrix_dump(sp_matrix_t *m, FILE *out, int factor)
+{
+ int i, o, last_idx;
+ const matrix_elem_t *e;
+
+ for (i = 0; i <= m->maxrow; ++i) {
+ last_idx = -1;
+ matrix_foreach_in_row(m, i, e) {
+ for (o = last_idx + 1; o < e->col; ++o)
+ fprintf(out, " %4.1f" , 0.0);
+
+ fprintf(out, " %4.1f", factor * e->val);
+ last_idx = e->col;
+ }
+
+ for (o = last_idx + 1; o <= m->maxcol; ++o)
+ fprintf(out, " %4.1f" , 0.0);
+
+ fprintf(out, "\n");
+ }
+}
+
+void matrix_self_test(int d)
+{
+ int i, o;
+ const matrix_elem_t *e;
+ sp_matrix_t *m = new_matrix(10, 10);
+
+ for (i = 0; i < d; ++i)
+ for (o = 0; o < d; ++o)
+ matrix_set(m, i, o, i*o);
+
+ for (i = 0; i < d; ++i)
+ for (o = 0; o<d; ++o)
+ assert(matrix_get(m, i, o) == i*o);
+
+ i = 1;
+ matrix_foreach_in_row(m,1,e) {
+ assert(e->val == i);
+ i++;
+ }
+ assert(!matrix_next(m)); /*iter must finish */
+
+ i = d-1;
+ matrix_foreach_in_col(m,d-1,e) {
+ assert(e->val == i);
+ i += d-1;
+ }
+ assert(!matrix_next(m));
+ del_matrix(m);
+ m = new_matrix(16,16);
+ matrix_set(m, 1,1,9);
+ matrix_set(m, 1,2,8);
+ matrix_set(m, 1,3,7);
+
+ matrix_set(m, 1,3,6);
+ matrix_set(m, 1,2,5);
+ matrix_set(m, 1,1,4);
+ i = 1;
+ matrix_foreach_in_row(m, 1, e) {
+ assert(e->row == 1 && e->col == i && e->val == i+3);
+ i++;
+ }
+ assert(i == 4);
+ del_matrix(m);
+
+ m = new_matrix(5,5);
+ matrix_set(m, 1,1,1);
+ matrix_set(m, 2,2,2);
+ matrix_set(m, 3,3,3);
+ matrix_set(m, 3,5,4);
+ matrix_set(m, 4,4,5);
+ matrix_set(m, 5,5,6);
+ for (i=1, e = matrix_first(m); e; ++i, e=matrix_next(m))
+ assert(e->val == i);
+ assert(i == 7);
+ matrix_set(m, 1,1,0);
+ assert(5 == matrix_get_entries(m));
+ del_matrix(m);
+}
--- /dev/null
+/**
+ * Author: Daniel Grund
+ * Date: 07.04.2005
+ * Copyright: (c) Universitaet Karlsruhe
+ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
+ * CVS-Id: $Id: sp_matrix.h 16112 2007-10-07 15:50:49Z mallon $
+ *
+ * Sparse matrix storage with linked lists for rows and cols.
+ */
+
+#ifndef _SP_MATRIX_H
+#define _SP_MATRIX_H
+
+#include <stdio.h>
+
+/**
+ * A matrix element.
+ */
+typedef struct matrix_elem_t {
+ int row; /* row index */
+ int col; /* column index */
+ float val; /* the actual value of the entry */
+} matrix_elem_t;
+
+typedef struct sp_matrix_t sp_matrix_t;
+
+/**
+ * Allocate a new matrix and init internal data for a matrix of size
+ * row_init X col_init. Matrix cannot grow beyond these init values.
+ * All elements are initially (implicit) set to 0.
+ */
+sp_matrix_t *new_matrix(int rows, int cols);
+
+/**
+ * Free space used by matrix m
+ */
+void del_matrix(sp_matrix_t *m);
+
+/**
+ * Sets m[row, col] to val
+ */
+void matrix_set(sp_matrix_t *m, int row, int col, double val);
+
+/**
+ * Sets m[row, cols[0,...,i]] to val for i in (0, ..., num_cols - 1)
+ * Following assumptions are done here:
+ * - the current row inserted is the last inserted row so far
+ * - cols[] is sorted ascending by col number
+ */
+void matrix_set_row_bulk(sp_matrix_t *m, int row, int *cols, int num_cols, double val);
+
+/**
+ * Returns the value stored in m[row, col].
+ */
+double matrix_get(const sp_matrix_t *m, int row, int col);
+
+/**
+ * Returns the number of (not-0-)entries.
+ */
+int matrix_get_entries(const sp_matrix_t *m);
+
+/**
+ * Returns the number of rows in this matrix; the height; the first dimension
+ */
+int matrix_get_rowcount(const sp_matrix_t *m);
+
+/**
+ * Returns the number of cols in this matrix; the width; the second dimension
+ */
+int matrix_get_colcount(const sp_matrix_t *m);
+
+/**
+ * Start iteration over all matrix elements. Row by row, from top to bottom.
+ * @return NULL if the matrix is empty, else the first element.
+ */
+const matrix_elem_t *matrix_first(sp_matrix_t *m);
+
+/**
+ * Start iteration over a row. Elements are returned from left to right.
+ * @return NULL if row is empty, else the first element.
+ */
+const matrix_elem_t *matrix_row_first(sp_matrix_t *m, int row);
+
+/**
+ * Start iteration over a column. Elements are returned from top to bottom.
+ * @return NULL if column is empty, else the first element.
+ */
+const matrix_elem_t *matrix_col_first(sp_matrix_t *m, int col);
+
+/**
+ * @return the next element in iteration order or NULL if iteration is done.
+ */
+const matrix_elem_t *matrix_next(sp_matrix_t *m);
+
+/**
+ * @return the size for a single matrix element
+ */
+unsigned matrix_get_elem_size(void);
+
+/**
+ * m The matrix
+ * curr The variable to assign all elements to during iteration
+ * Save against removal of curr
+ */
+#define matrix_foreach(m,curr) \
+ for (curr = matrix_first(m); curr; curr = matrix_next(m))
+
+/**
+ * m The matrix
+ * r The row
+ * curr The variable to assign all elements to during iteration
+ * Save against removal of curr
+ */
+#define matrix_foreach_in_row(m,r,curr) \
+ for (curr = matrix_row_first(m, r); curr; curr = matrix_next(m))
+
+/**
+ * m The matrix
+ * c The col
+ * curr The variable to assign all elements to during iteration
+ * Save against removal of curr
+ */
+#define matrix_foreach_in_col(m,c,curr) \
+ for (curr = matrix_col_first(m, c); curr; curr = matrix_next(m))
+
+/**
+ * Changes the matrix into an equivalent one with maximal number zero-rows.
+ * The only equivalence transformation is:
+ * Adding a constant to Qij and subtracting it from Qji
+ */
+void matrix_optimize(sp_matrix_t *m);
+
+/**
+ * Dumps the matrix factor*m to the stream @p out.
+ * Remark: I dont need spaces between the elements. So feel free to add
+ * char *seperator to the arguments.
+ */
+void matrix_dump(sp_matrix_t *m, FILE *out, int factor);
+
+/**
+ * Perform a self test with a square matrix of dimensions d.
+ */
+void matrix_self_test(int d);
+
+#endif
}
/** checks if a given Cond node is a switch Cond. */
-static bool is_switch_Cond(ir_node *cond) {
+static bool is_switch_Cond(ir_node *cond)
+{
ir_node *sel = get_Cond_selector(cond);
return get_irn_mode(sel) != mode_b;
}
BF_IS_UNKNOWN_JUMP_TARGET = 1 << 2,
} block_flags_t;
-static bool get_phase_flag(ir_phase *block_info, ir_node *block, int flag) {
- return ((int)phase_get_irn_data(block_info, block)) & flag;
+static bool get_phase_flag(ir_phase *block_info, ir_node *block, int flag)
+{
+ return PTR_TO_INT(phase_get_irn_data(block_info, block)) & flag;
}
-static void set_phase_flag(ir_phase *block_info, ir_node *block, block_flags_t flag) {
- int data = (int)phase_get_irn_data(block_info, block);
+
+static void set_phase_flag(ir_phase *block_info, ir_node *block,
+ block_flags_t flag)
+{
+ int data = PTR_TO_INT(phase_get_irn_data(block_info, block));
data |= flag;
- phase_set_irn_data(block_info, block, (void*)data);
+ phase_set_irn_data(block_info, block, INT_TO_PTR(data));
}
-static bool has_operations(ir_phase *block_info, ir_node *block) {
+static bool has_operations(ir_phase *block_info, ir_node *block)
+{
return get_phase_flag(block_info, block, BF_HAS_OPERATIONS);
}
-static void set_has_operations(ir_phase *block_info, ir_node *block) {
+
+static void set_has_operations(ir_phase *block_info, ir_node *block)
+{
set_phase_flag(block_info, block, BF_HAS_OPERATIONS);
}
-static bool has_phis(ir_phase *block_info, ir_node *block) {
+static bool has_phis(ir_phase *block_info, ir_node *block)
+{
return get_phase_flag(block_info, block, BF_HAS_PHIS);
}
-static void set_has_phis(ir_phase *block_info, ir_node *block) {
+
+static void set_has_phis(ir_phase *block_info, ir_node *block)
+{
set_phase_flag(block_info, block, BF_HAS_PHIS);
}
-static bool is_unknown_jump_target(ir_phase *block_info, ir_node *block) {
+static bool is_unknown_jump_target(ir_phase *block_info, ir_node *block)
+{
return get_phase_flag(block_info, block, BF_IS_UNKNOWN_JUMP_TARGET);
}
-static void set_is_unknown_jump_target(ir_phase *block_info, ir_node *block) {
+
+static void set_is_unknown_jump_target(ir_phase *block_info, ir_node *block)
+{
set_phase_flag(block_info, block, BF_IS_UNKNOWN_JUMP_TARGET);
}
/*
* Some cfg optimizations, which do not touch Phi nodes
*/
-static void cfgopt_ignoring_phis(ir_graph *irg) {
+static void cfgopt_ignoring_phis(ir_graph *irg)
+{
ir_phase *block_info = new_phase(irg, NULL);
skip_env env = { false, block_info };
} walk_env_t;
/** debug handle */
-DEBUG_ONLY(firm_dbg_module_t *dbgHandle;)
+DEBUG_ONLY(static firm_dbg_module_t *dbgHandle;)
/**
* checks whether a Raise leaves a method
int n;
int i;
- assert(is_Block(node) || is_Phi(node));
+ assert(is_Block(node));
n = get_irn_arity(node);
NEW_ARR_A(ir_node*, ins, n + 1);
}
}
+/**
+ * jumpthreading produces critical edges, e.g. B-C:
+ * A A
+ * \ / \ |
+ * B => B |
+ * / \ / \|
+ * C C
+ *
+ * By splitting this critical edge more threadings might be possible.
+ */
static void split_critical_edge(ir_node *block, int pos)
{
ir_graph *irg = get_irn_irg(block);
ir_node *badX;
int cnst_pos;
+ /* we do not deal with Phis, so restrict this to exactly one cfgpred */
if (get_Block_n_cfgpreds(block) != 1)
return;
break;
default:
- ;
+ break;
}
} /* do_load_store_optimize */
ir_node *pred = get_Block_cfgpred(endblk, i);
pred = skip_Proj(pred);
- if (is_Return(pred))
+ if (is_Return(pred)) {
dfs(get_Return_mem(pred), env);
- else if (is_Raise(pred))
+ } else if (is_Raise(pred)) {
dfs(get_Raise_mem(pred), env);
- else if (is_fragile_op(pred))
+ } else if (is_fragile_op(pred)) {
dfs(get_fragile_op_mem(pred), env);
- else if (is_Bad(pred))
- /* ignore non-optimized block predecessor */;
- else {
+ } else if (is_Bad(pred)) {
+ /* ignore non-optimized block predecessor */
+ } else {
assert(0 && "Unknown EndBlock predecessor");
}
}
*/
#include "config.h"
+#include <stdbool.h>
+
#include "iroptimize.h"
#include "opt_init.h"
#include "irnode.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg);
-/* DBG print stats for every procedure. */
-#define LOOP_OPT_STATS 1
-
-/* DBG: Ignore node limits and process every possible loop. */
-#define LOOP_IGNORE_NODE_LIMITS 0
-
/**
* Convenience macro for iterating over every phi node of the given block.
* Requires phi list per block.
} unrolling_kind_flag;
/* Condition for performing visiting a node during copy_walk. */
-typedef unsigned walker_condition(ir_node *);
+typedef bool walker_condition(const ir_node *);
/* Node and position of a predecessor. */
typedef struct entry_edge {
static entry_edge *cur_head_outs;
/* Information about the loop head */
-static ir_node *loop_head = NULL;
-static unsigned loop_head_valid = 1;
+static ir_node *loop_head = NULL;
+static bool loop_head_valid = true;
/* List of all inner loops, that are processed. */
static ir_loop **loops;
-#if LOOP_OPT_STATS
-
-#define count_stats(val) (++val)
-#define print_stats() (do_print_stats())
-#define reset_stats() (do_reset_stats())
-
/* Stats */
typedef struct loop_stats_t {
unsigned loops;
static loop_stats_t stats;
/* Set stats to sero */
-static void do_reset_stats(void)
+static void reset_stats(void)
{
memset(&stats, 0, sizeof(loop_stats_t));
}
/* Print stats */
-static void do_print_stats(void)
+static void print_stats(void)
{
DB((dbg, LEVEL_2, "---------------------------------------\n"));
DB((dbg, LEVEL_2, "loops : %d\n",stats.loops));
DB((dbg, LEVEL_2, "invariant_unroll : %d\n",stats.invariant_unroll));
DB((dbg, LEVEL_2, "=======================================\n"));
}
-#else
-/* No stats */
-#define count_stats(val) ((void)0)
-#define print_stats() ((void)0)
-#define reset_stats() ((void)0)
-
-#endif
/* Commandline parameters */
typedef struct loop_opt_params_t {
unsigned max_loop_size; /* Maximum number of nodes [nodes]*/
int depth_adaption; /* Loop nest depth adaption [percent] */
unsigned allowed_calls; /* Number of calls allowed [number] */
-unsigned count_phi:1; /* Count phi nodes */
-unsigned count_proj:1; /* Count projections */
+bool count_phi; /* Count phi nodes */
+bool count_proj; /* Count projections */
unsigned max_cc_size; /* Maximum condition chain size [nodes] */
unsigned max_branches;
unsigned max_unrolled_loop_size; /* [nodes] */
-unsigned allow_const_unrolling:1;
-unsigned allow_invar_unrolling:1;
+bool allow_const_unrolling;
+bool allow_invar_unrolling;
unsigned invar_unrolling_min_size; /* [nodes] */
} loop_opt_params_t;
}
/* Returns 0 if the node or block is not in cur_loop. */
-static unsigned is_in_loop(ir_node *node)
+static bool is_in_loop(const ir_node *node)
{
- return (get_irn_loop(get_block(node)) == cur_loop);
+ return get_irn_loop(get_block_const(node)) == cur_loop;
}
/* Returns 0 if the given edge is not a backedge
* with its pred in the cur_loop. */
-static unsigned is_own_backedge(ir_node *n, int pos)
+static bool is_own_backedge(const ir_node *n, int pos)
{
- return (is_backedge(n, pos) && is_in_loop(get_irn_n(n, pos)));
+ return is_backedge(n, pos) && is_in_loop(get_irn_n(n, pos));
}
/* Finds loop head and some loop_info as calls or else if necessary. */
static void get_loop_info(ir_node *node, void *env)
{
- unsigned node_in_loop, pred_in_loop;
+ bool node_in_loop = is_in_loop(node);
int i, arity;
(void)env;
+ /* collect some loop information */
+ if (node_in_loop) {
+ if (is_Phi(node) && opt_params.count_phi)
+ ++loop_info.nodes;
+ else if (is_Proj(node) && opt_params.count_proj)
+ ++loop_info.nodes;
+ else if (!is_Confirm(node) && !is_Const(node) && !is_SymConst(node))
+ ++loop_info.nodes;
+
+ if (is_Load(node) || is_Store(node))
+ ++loop_info.ld_st;
+
+ if (is_Call(node))
+ ++loop_info.calls;
+ }
+
arity = get_irn_arity(node);
for (i = 0; i < arity; i++) {
- ir_node *pred = get_irn_n(node, i);
+ ir_node *pred = get_irn_n(node, i);
+ bool pred_in_loop = is_in_loop(pred);
- pred_in_loop = is_in_loop(pred);
- node_in_loop = is_in_loop(node);
-
- if (!node_in_loop && pred_in_loop && is_Block(node))
- {
+ if (is_Block(node) && !node_in_loop && pred_in_loop) {
entry_edge entry;
entry.node = node;
entry.pos = i;
loop_info.cf_out = entry;
}
- /* collect some loop information */
- if (node_in_loop) {
- if (is_Phi(node) && opt_params.count_phi)
- ++loop_info.nodes;
- else if (is_Proj(node) && opt_params.count_proj)
- ++loop_info.nodes;
- else if (!is_Confirm(node) && !is_Const(node) && !is_SymConst(node))
- ++loop_info.nodes;
-
- if (is_Load(node) || is_Store(node))
- ++loop_info.ld_st;
-
- if (is_Call(node))
- ++loop_info.calls;
-
- }
-
/* Find the loops head/the blocks with cfpred outside of the loop */
if (is_Block(node)) {
const ir_edge_t *edge;
unsigned outs_n = 0;
/* Count innerloop branches */
- foreach_out_edge_kind(node, edge, EDGE_KIND_NORMAL) {
- if (is_Block(get_edge_src_irn(edge)) && is_in_loop(get_edge_src_irn(edge)))
+ foreach_out_edge_kind(node, edge, EDGE_KIND_BLOCK) {
+ ir_node *succ = get_edge_src_irn(edge);
+ if (is_Block(succ) && is_in_loop(succ))
++outs_n;
}
if (outs_n > 1)
node, pred));
/* another head? We do not touch this. */
if (loop_head && loop_head != node) {
- loop_head_valid = 0;
+ loop_head_valid = false;
} else {
loop_head = node;
}
/* Returns mark of node, or its block if node is not a block.
* Used in this context to determine if node is in the condition chain. */
-static unsigned is_nodes_block_marked(ir_node* node)
+static bool is_nodes_block_marked(const ir_node* node)
{
- if (is_Block(node))
- return get_Block_mark(node);
- else
- return get_Block_mark(get_block(node));
+ return get_Block_mark(get_block_const(node));
}
/* Extends a nodes ins by node new.
* NOTE: This is slow if a node n needs to be extended more than once. */
-static void extend_irn(ir_node *n, ir_node *newnode, int new_is_backedge)
+static void extend_irn(ir_node *n, ir_node *newnode, bool new_is_backedge)
{
- ir_node **ins;
int i;
int arity = get_irn_arity(n);
int new_arity = arity + 1;
- int *bes;
-
- NEW_ARR_A(int, bes, new_arity);
- NEW_ARR_A(ir_node *, ins, new_arity);
+ ir_node **ins = XMALLOCN(ir_node*, new_arity);
+ bool *bes = XMALLOCN(bool, new_arity);
/* save bes */
/* Bes are important!
pred = get_irn_n(block, pos);
new_in = get_inversion_copy(pred);
DB((dbg, LEVEL_5, "Extend block %N by %N cp of %N\n", block, new_in, pred));
- extend_irn(block, new_in, 0);
+ extend_irn(block, new_in, false);
/* Extend block phis by copy of definition at pos */
for_each_phi(block, phi) {
new_in = cp;
DB((dbg, LEVEL_5, "Extend phi %N by %N cp of %N\n", phi, new_in, pred));
- extend_irn(phi, new_in, 0);
+ extend_irn(phi, new_in, false);
}
}
/* Returns the number of blocks backedges. With or without alien bes. */
-static int get_backedge_n(ir_node *block, unsigned with_alien)
+static int get_backedge_n(ir_node *block, bool with_alien)
{
int i;
int be_n = 0;
static void find_condition_chain(ir_node *block)
{
const ir_edge_t *edge;
- unsigned mark = 0;
- unsigned has_be = 0;
- unsigned jmp_only;
- unsigned nodes_n = 0;
+ bool mark = false;
+ bool has_be = false;
+ bool jmp_only = true;
+ unsigned nodes_n = 0;
mark_irn_visited(block);
}
/* Check if block only has a jmp instruction. */
- jmp_only = 1;
foreach_out_edge(block, edge) {
ir_node *src = get_edge_src_irn(edge);
- if (! is_Block(src) && ! is_Jmp(src)) {
- jmp_only = 0;
+ if (!is_Block(src) && !is_Jmp(src)) {
+ jmp_only = false;
}
}
ir_node *src = get_edge_src_irn(edge);
int pos = get_edge_src_pos(edge);
- if (! is_in_loop(src))
- mark = 1;
+ if (!is_in_loop(src))
+ mark = true;
/* Inverting blocks with backedge outs leads to a cf edge
* from the inverted head, into the inverted head (skipping the body).
* this would introduce another loop in the existing loop.
* This loop inversion cannot cope with this case. */
if (is_backedge(src, pos)) {
- has_be = 1;
+ has_be = true;
break;
}
}
*/
/* Collect blocks containing only a Jmp.
* Do not collect blocks with backedge outs. */
- if ((jmp_only == 1 || mark == 1) && has_be == 0) {
+ if ((jmp_only || mark) && !has_be) {
set_Block_mark(block, 1);
++inversion_blocks_in_cc;
loop_info.cc_size += nodes_n;
ir_node *head_cp = get_inversion_copy(loop_head);
ir_graph *irg = get_irn_irg(head_cp);
int arity = get_irn_arity(head_cp);
- int backedges = get_backedge_n(head_cp, 0);
+ int backedges = get_backedge_n(head_cp, false);
int new_arity = arity - backedges;
int pos;
int i;
ir_node **phis;
ir_graph *irg = get_irn_irg(loop_head);
int arity = get_irn_arity(loop_head);
- int backedges = get_backedge_n(loop_head, 0);
+ int backedges = get_backedge_n(loop_head, false);
int new_arity = backedges;
int pos;
int i;
}
/* Does the loop inversion. */
-static void inversion_walk(entry_edge *head_entries)
+static void inversion_walk(ir_graph *irg, entry_edge *head_entries)
{
size_t i;
* Any change of the order leads to lost information that would be needed later.
*/
- ir_reserve_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
+ ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
/* 1. clone condition chain */
- inc_irg_visited(current_ir_graph);
+ inc_irg_visited(irg);
for (i = 0; i < ARR_LEN(head_entries); ++i) {
entry_edge entry = head_entries[i];
copy_walk(pred, is_nodes_block_marked, cur_loop);
}
- ir_free_resources(current_ir_graph, IR_RESOURCE_IRN_VISITED);
+ ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
/* 2. Extends the head control flow successors ins
* with the definitions of the copied head node. */
}
/* Performs loop inversion of cur_loop if possible and reasonable. */
-static void loop_inversion(void)
+static void loop_inversion(ir_graph *irg)
{
int loop_depth;
unsigned max_loop_nodes = opt_params.max_loop_size;
unsigned max_loop_nodes_adapted;
int depth_adaption = opt_params.depth_adaption;
- unsigned do_inversion = 1;
+ bool do_inversion = true;
/* Depth of 0 is the procedure and 1 a topmost loop. */
loop_depth = get_loop_depth(cur_loop) - 1;
DB((dbg, LEVEL_1, "max_nodes: %d\nmax_nodes_adapted %d at depth of %d (adaption %d)\n",
max_loop_nodes, max_loop_nodes_adapted, loop_depth, depth_adaption));
- if (! (loop_info.nodes > 0))
+ if (loop_info.nodes == 0)
return;
-#if LOOP_IGNORE_NODE_LIMITS
- DB((dbg, LEVEL_1, "WARNING: Loop node limitations ignored."));
-#else
if (loop_info.nodes > max_loop_nodes) {
/* Only for stats */
DB((dbg, LEVEL_1, "Nodes %d > allowed nodes %d\n",
loop_info.nodes, loop_depth, max_loop_nodes));
- count_stats(stats.too_large);
+ ++stats.too_large;
/* no RETURN */
/* Adaption might change it */
}
if (loop_info.nodes > max_loop_nodes_adapted) {
DB((dbg, LEVEL_1, "Nodes %d > allowed nodes (depth %d adapted) %d\n",
loop_info.nodes, loop_depth, max_loop_nodes_adapted));
- count_stats(stats.too_large_adapted);
+ ++stats.too_large_adapted;
return;
}
if (loop_info.calls > opt_params.allowed_calls) {
DB((dbg, LEVEL_1, "Calls %d > allowed calls %d\n",
loop_info.calls, opt_params.allowed_calls));
- count_stats(stats.calls_limit);
+ ++stats.calls_limit;
return;
}
-#endif
/*inversion_head_node_limit = INT_MAX;*/
- ir_reserve_resources(current_ir_graph, IR_RESOURCE_BLOCK_MARK);
+ ir_reserve_resources(irg, IR_RESOURCE_BLOCK_MARK);
/* Reset block marks.
* We use block marks to flag blocks of the original condition chain. */
- irg_walk_graph(current_ir_graph, reset_block_mark, NULL, NULL);
+ irg_walk_graph(irg, reset_block_mark, NULL, NULL);
/*loop_info.blocks = get_loop_n_blocks(cur_loop);*/
cond_chain_entries = NEW_ARR_F(entry_edge, 0);
inversion_blocks_in_cc = 0;
/* Use phase to keep copy of nodes from the condition chain. */
- phase = new_phase(current_ir_graph, phase_irn_init_default);
+ phase = new_phase(irg, phase_irn_init_default);
/* Search for condition chains and temporarily save the blocks in an array. */
cc_blocks = NEW_ARR_F(ir_node *, 0);
- inc_irg_visited(current_ir_graph);
+ inc_irg_visited(irg);
find_condition_chain(loop_head);
unmark_not_allowed_cc_blocks();
DEL_ARR_F(cc_blocks);
-#if LOOP_IGNORE_NODE_LIMITS
- (void) unmark_cc_blocks;
-#else
/* Condition chain too large.
* Loop should better be small enough to fit into the cache. */
/* TODO Of course, we should take a small enough cc in the first place,
* which is not that simple. (bin packing) */
if (loop_info.cc_size > opt_params.max_cc_size) {
- count_stats(stats.cc_limit_reached);
+ ++stats.cc_limit_reached;
- do_inversion = 0;
+ do_inversion = false;
/* Unmark cc blocks except the head.
* Invert head only for possible unrolling. */
unmark_cc_blocks();
-
}
-#endif
/* We also catch endless loops here,
* because they do not have a condition chain. */
if (inversion_blocks_in_cc < 1) {
- do_inversion = 0;
+ do_inversion = false;
DB((dbg, LEVEL_3,
"Loop contains %d (less than 1) invertible blocks => No Inversion done.\n",
inversion_blocks_in_cc));
cur_head_outs = NEW_ARR_F(entry_edge, 0);
/* Get all edges pointing into the condition chain. */
- irg_walk_graph(current_ir_graph, get_head_outs, NULL, NULL);
+ irg_walk_graph(irg, get_head_outs, NULL, NULL);
/* Do the inversion */
- inversion_walk(cur_head_outs);
+ inversion_walk(irg, cur_head_outs);
DEL_ARR_F(cur_head_outs);
/* Duplicated blocks changed doms */
- set_irg_doms_inconsistent(current_ir_graph);
+ set_irg_doms_inconsistent(irg);
+ set_irg_loopinfo_state(irg, loopinfo_cf_inconsistent);
- count_stats(stats.inverted);
+ ++stats.inverted;
}
/* free */
DEL_ARR_F(cond_chain_entries);
DEL_ARR_F(head_df_loop);
- ir_free_resources(current_ir_graph, IR_RESOURCE_BLOCK_MARK);
+ ir_free_resources(irg, IR_RESOURCE_BLOCK_MARK);
}
/* Fix the original loop_heads ins for invariant unrolling case. */
* using be_block as supplier of backedge informations. */
static ir_node *clone_block_sans_bes(ir_node *node, ir_node *be_block)
{
- ir_node **ins;
int arity = get_irn_arity(node);
int i, c = 0;
+ ir_node **ins;
assert(get_irn_arity(node) == get_irn_arity(be_block));
assert(is_Block(node));
DB((dbg, LEVEL_4, "1 loop exit\n"));
-#if LOOP_IGNORE_NODE_LIMITS
- /* Ignore loop size. Probably not wise in other than testcases. */
- loop_info.max_unroll = 40;
-#else
/* Calculate maximum unroll_nr keeping node count below limit. */
loop_info.max_unroll = (int)((double)opt_params.max_unrolled_loop_size / (double)loop_info.nodes);
if (loop_info.max_unroll < 2) {
- count_stats(stats.too_large);
+ ++stats.too_large;
return NULL;
}
-#endif
-
DB((dbg, LEVEL_4, "maximum unroll factor %u, to not exceed node limit \n",
opt_params.max_unrolled_loop_size));
return 0;
}
- count_stats(stats.u_simple_counting_loop);
+ ++stats.u_simple_counting_loop;
loop_info.latest_value = is_latest_val;
if (! (loop_info.nodes > 0))
return;
-#if LOOP_IGNORE_NODE_LIMITS
- DB((dbg, LEVEL_1, "WARNING: Loop node limitations ignored."));
-#else
if (loop_info.nodes > opt_params.max_unrolled_loop_size) {
DB((dbg, LEVEL_2, "Nodes %d > allowed nodes %d\n",
loop_info.nodes, opt_params.max_unrolled_loop_size));
- count_stats(stats.too_large);
+ ++stats.too_large;
return;
}
if (loop_info.calls > 0) {
DB((dbg, LEVEL_2, "Calls %d > allowed calls 0\n",
loop_info.calls));
- count_stats(stats.calls_limit);
+ ++stats.calls_limit;
return;
}
-#endif
unroll_nr = 0;
irg_walk_graph(current_ir_graph, correct_phis, NULL, NULL);
if (loop_info.unroll_kind == constant)
- count_stats(stats.constant_unroll);
+ ++stats.constant_unroll;
else
- count_stats(stats.invariant_unroll);
+ ++stats.invariant_unroll;
set_irg_doms_inconsistent(current_ir_graph);
/* Analyzes the loop, and checks if size is within allowed range.
* Decides if loop will be processed. */
-static void init_analyze(ir_loop *loop)
+static void init_analyze(ir_graph *irg, ir_loop *loop)
{
cur_loop = loop;
- loop_head = NULL;
- loop_head_valid = 1;
+ loop_head = NULL;
+ loop_head_valid = true;
/* Reset loop info */
memset(&loop_info, 0, sizeof(loop_info_t));
get_loop_node(loop, 0)));
/* Collect loop informations: head, node counts. */
- irg_walk_graph(current_ir_graph, get_loop_info, NULL, NULL);
+ irg_walk_graph(irg, get_loop_info, NULL, NULL);
/* RETURN if there is no valid head */
if (!loop_head || !loop_head_valid) {
if (loop_info.branches > opt_params.max_branches) {
DB((dbg, LEVEL_1, "Branches %d > allowed branches %d\n",
loop_info.branches, opt_params.max_branches));
- count_stats(stats.calls_limit);
+ ++stats.calls_limit;
return;
}
switch (loop_op) {
case loop_op_inversion:
- loop_inversion();
+ loop_inversion(irg);
break;
case loop_op_unrolling:
{
opt_params.max_loop_size = 100;
opt_params.depth_adaption = -50;
- opt_params.count_phi = 1;
- opt_params.count_proj = 0;
+ opt_params.count_phi = true;
+ opt_params.count_proj = false;
opt_params.allowed_calls = 0;
opt_params.max_cc_size = 5;
- opt_params.allow_const_unrolling = 1;
- opt_params.allow_invar_unrolling = 0;
+ opt_params.allow_const_unrolling = true;
+ opt_params.allow_invar_unrolling = false;
opt_params.invar_unrolling_min_size = 20;
opt_params.max_unrolled_loop_size = 400;
edges_assure(irg);
assure_irg_outs(irg);
-
- /* NOTE: sets only the loop attribute of blocks, not nodes */
- /* NOTE: Kills links */
assure_cf_loop(irg);
ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
collect_phiprojs(irg);
- ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
loop = get_irg_loop(irg);
sons = get_loop_n_sons(loop);
find_innermost_loop(get_loop_son(loop, nr));
}
- ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
/* Set all links to NULL */
- irg_walk_graph(current_ir_graph, reset_link, NULL, NULL);
+ irg_walk_graph(irg, reset_link, NULL, NULL);
for (i = 0; i < ARR_LEN(loops); ++i) {
ir_loop *loop = loops[i];
- count_stats(stats.loops);
+ ++stats.loops;
/* Analyze and handle loop */
- init_analyze(loop);
+ init_analyze(irg, loop);
/* Copied blocks do not have their phi list yet */
collect_phiprojs(irg);
/* Set links to NULL
* TODO Still necessary? */
- irg_walk_graph(current_ir_graph, reset_link, NULL, NULL);
+ irg_walk_graph(irg, reset_link, NULL, NULL);
}
print_stats();
DEL_ARR_F(loops);
- ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
- ir_free_resources(irg, IR_RESOURCE_PHI_LIST);
+ ir_free_resources(irg, IR_RESOURCE_IRN_LINK | IR_RESOURCE_PHI_LIST);
}
void do_loop_unrolling(ir_graph *irg)
{
loop_op = loop_op_unrolling;
-
- DB((dbg, LEVEL_1, " >>> unrolling (Startnode %N) <<<\n",
- get_irg_start(irg)));
-
loop_optimization(irg);
-
- DB((dbg, LEVEL_1, " >>> unrolling done (Startnode %N) <<<\n",
- get_irg_start(irg)));
}
void do_loop_inversion(ir_graph *irg)
{
loop_op = loop_op_inversion;
-
- DB((dbg, LEVEL_1, " >>> inversion (Startnode %N) <<<\n",
- get_irg_start(irg)));
-
loop_optimization(irg);
-
- assure_cf_loop(irg);
-
- DB((dbg, LEVEL_1, " >>> inversion done (Startnode %N) <<<\n",
- get_irg_start(irg)));
}
void do_loop_peeling(ir_graph *irg)
{
loop_op = loop_op_peeling;
-
- DB((dbg, LEVEL_1, " >>> peeling (Startnode %N) <<<\n",
- get_irg_start(irg)));
-
loop_optimization(irg);
-
- DB((dbg, LEVEL_1, " >>> peeling done (Startnode %N) <<<\n",
- get_irg_start(irg)));
-
}
ir_graph_pass_t *loop_inversion_pass(const char *name)
ir_node **ins, **phi_ins;
phi_t *repr_phi, *phi;
pair_t *repr_pair, *pair;
- int i, j, k, n, block_nr, n_phis;
+ int i, j, k, n, n_phis;
list_del(&repr->block_list);
/* collect new in arrays */
end = get_irg_end(irg);
- block_nr = 0;
list_for_each_entry(block_t, bl, &part->blocks, block_list) {
block = bl->block;
- ++block_nr;
DB((dbg, LEVEL_1, "%+F, ", block));
#define DBG_OUT_TR(l_relation, l_bound, r_relation, r_bound, relation, v) \
ir_printf("In %e:\na %= %n && b %= %n ==> a %= b == %s\n", \
get_irg_entity(current_ir_graph), \
- l_relation, l_bound, r_relation, r_bound, relation, v);
+ l_relation, l_bound, r_relation, r_bound, relation, v)
/* right side */
#define DBG_OUT_R(r_relation, r_bound, left, relation, right, v) \
ir_printf("In %e:\na %= %n ==> %n %= %n == %s\n", \
get_irg_entity(current_ir_graph), \
- r_relation, r_bound, left, relation, right, v);
+ r_relation, r_bound, left, relation, right, v)
/* left side */
#define DBG_OUT_L(l_relation, l_bound, left, relation, right, v) \
ir_printf("In %e:\na %= %n ==> %n %= %n == %s\n", \
get_irg_entity(current_ir_graph), \
- l_relation, l_bound, left, relation, right, v);
+ l_relation, l_bound, left, relation, right, v)
#else
-#define DBG_OUT_TR(l_relation, l_bound, r_relation, r_bound, relation, v)
-#define DBG_OUT_R(r_relation, r_bound, left, relation, right, v)
-#define DBG_OUT_L(l_relation, l_bound, left, relation, right, v)
+#define DBG_OUT_TR(l_relation, l_bound, r_relation, r_bound, relation, v) (void)0
+#define DBG_OUT_R(r_relation, r_bound, left, relation, right, v) (void)0
+#define DBG_OUT_L(l_relation, l_bound, left, relation, right, v) (void)0
#endif /* DEBUG_CONFIRM */
*/
FIRM_API int value_not_zero(const ir_node *n, ir_node_cnst_ptr *confirm)
{
-#define RET_ON(x) if (x) { *confirm = n; return 1; }; break
+#define RET_ON(x) if (x) { *confirm = n; return 1; } break
ir_tarval *tv;
ir_mode *mode = get_irn_mode(n);
ptr = get_Confirm_value(ptr);
continue;
default:
- ;
+ break;
}
break;
}
/*
* Calculate loop info, so we could identify loop-invariant
- * code and threat it like a constant.
+ * code and treat it like a constant.
* We only need control flow loops here but can handle generic
* INTRA info as well.
*/
CASE(Eor);
CASE(Shl);
default:
- /* leave NULL */;
+ break;
}
return ops;
} /* if */
break;
default:
- ;
+ break;
} /* switch */
return op;
} /* if */
} /* if */
default:
- ;
+ break;
} /* switch */
} /* stat_update_address */
}
}
default:
- ;
+ break;
} /* switch */
/* we want to count the constant IN nodes, not the CSE'ed constant's itself */
#ifdef DISABLE_STATEV
-#define stat_ev_do(expr)
-#define stat_ev_enabled 0
-#define stat_ev_if if (0)
-#define stat_ev_dbl(name, val)
-#define stat_ev_int(name, val)
-#define stat_ev(name)
-#define stat_ev_emit(name, value)
-
-#define stat_ev_cnt_decl(var)
-#define stat_ev_cnt_inc(var)
-#define stat_ev_cnt_done(name, var)
-#define stat_ev_tim_push()
-#define stat_ev_tim_pop(name)
-
-#define stat_ev_ctx_push(key)
-#define stat_ev_ctx_push_str(key, str)
-#define stat_ev_ctx_push_fmt(key, fmt, value)
-#define stat_ev_ctx_push_fobj(key, firm_object)
-#define stat_ev_ctx_pop(key)
-#define stat_ev_flush()
+#define stat_ev_enabled 0
+#define stat_ev_dbl(name, val) ((void)0)
+#define stat_ev_int(name, val) ((void)0)
+#define stat_ev(name) ((void)0)
+#define stat_ev_emit(name, value) ((void)0)
+
+#define stat_ev_cnt_decl(var) ((void)0)
+#define stat_ev_cnt_inc(var) ((void)0)
+#define stat_ev_cnt_done(name, var) ((void)0)
+#define stat_ev_tim_push() ((void)0)
+#define stat_ev_tim_pop(name) ((void)0)
+
+#define stat_ev_ctx_push(key) ((void)0)
+#define stat_ev_ctx_push_str(key, str) ((void)0)
+#define stat_ev_ctx_push_fmt(key, fmt, value) ((void)0)
+#define stat_ev_ctx_push_fobj(key, firm_object) ((void)0)
+#define stat_ev_ctx_pop(key) ((void)0)
+#define stat_ev_flush() ((void)0)
#else
#define stat_ev_cnt_inc(var) do { ++stat_ev_cnt_var_ ## var; } while(0)
#define stat_ev_cnt_done(var, name) stat_ev_emit((name), stat_ev_cnt_var_ ## var)
-#define stat_ev_do(expr) (stat_ev_enabled ? ((expr), 1) : 0)
-#define stat_ev_if if (stat_ev_enabled)
-
/**
* Initialize the stat ev machinery.
* @param filename_prefix The prefix of the filename (.ev or .ev.gz will be appended).
ccs_env *ccs = (ccs_env *)env;
ir_class_cast_state this_state = ir_class_casts_any;
ir_type *fromtype, *totype;
- int ref_depth = 0;
if (!is_Cast(n)) return;
while (is_Pointer_type(totype) && is_Pointer_type(fromtype)) {
totype = get_pointer_points_to_type(totype);
fromtype = get_pointer_points_to_type(fromtype);
- ref_depth++;
}
if (!is_Class_type(totype)) return;
static const char *firm_verify_failure_msg;
+#if 0
/**
* Show diagnostic if an entity overwrites another one not
* in direct superclasses.
ir_fprintf(stderr, " %+F:\n", super);
}
}
+#endif
/**
* Show diagnostic if an entity overwrites a wrong number of things.
show_ent_overwrite_cnt(mem)
);
- if (false) {
+#if 0
+ {
size_t j, m;
/* check if the overwrite relation is flat, i.e. every overwrite
* is visible in every direct superclass. */
}
}
}
+#endif
}
return 0;
}
const char *get_type_state_name(ir_type_state s)
{
-#define X(a) case a: return #a;
+#define X(a) case a: return #a
switch (s) {
X(layout_undefined);
X(layout_fixed);
return;
}
- if (exp_val > a->desc.mantissa_size) {
+ if (exp_val > (long)a->desc.mantissa_size) {
if (a != result)
memcpy(result, a, calc_buffer_size);
fp_value *value;
fp_value *temp = NULL;
- int byte_offset;
+ unsigned byte_offset;
uint32_t sign;
uint32_t exponent;
if (0 < v && v < (1 << desc->exponent_size) - 1) {
/* exponent can be encoded, now check the mantissa */
v = value->desc.mantissa_size + ROUNDING_BITS - sc_get_lowest_set_bit(_mant(value));
- return v <= desc->mantissa_size;
+ return v <= (int)desc->mantissa_size;
}
return 0;
}
static float_to_int_mode current_float_to_int_mode = TRUNCATE;
+/* set this to true if infinity should be clipped to +/- MAX_FLOAT */
#define SWITCH_NOINFINITY 0
+/* set this to true if denormals should be clipped to zero */
#define SWITCH_NODENORMALS 0
/****************************************************************************
else
panic("%s:%d: Invalid tarval (null)", file, line);
}
+
+inline static
#ifdef __GNUC__
-inline static void tarval_verify(ir_tarval *tv) __attribute__ ((unused));
+ __attribute__((unused))
#endif
-
-inline static void tarval_verify(ir_tarval *tv)
+void tarval_verify(ir_tarval *tv)
{
assert(tv);
assert(tv->mode);
case TV_OVERFLOW_SATURATE:
return get_mode_min(mode);
case TV_OVERFLOW_WRAP: {
- char *temp = (char*) alloca(sc_get_buffer_length());
+ temp = (char*) alloca(sc_get_buffer_length());
memcpy(temp, value, sc_get_buffer_length());
sc_truncate(get_mode_size_bits(mode), temp);
return get_tarval(temp, length, mode);
break;
case irms_float_number:
-#ifdef SWITCH_NOINFINITY
+#if SWITCH_NOINFINITY
if (fc_is_inf((const fp_value*) value)) {
/* clip infinity to maximum value */
return fc_is_negative((const fp_value*) value) ? get_mode_min(mode) : get_mode_max(mode);
}
#endif
-
-#ifdef SWITCH_NODENORMALS
+#if SWITCH_NODENORMALS
if (fc_is_subnormal((const fp_value*) value)) {
/* clip denormals to zero */
return get_mode_null(mode);
real payload */
/* case 128: return &quad_desc; */
default:
+ (void) quad_desc;
panic("Unsupported mode in get_descriptor()");
}
}
return get_tarval(buffer, sc_get_buffer_length(), dst_mode);
default:
- /* the rest can't be converted */
- return tarval_bad;
+ break;
}
- break;
+ /* the rest can't be converted */
+ return tarval_bad;
/* cast int/characters to something */
case irms_int_number:
default:
return snprintf(buf, len, "%s%s%s", prefix, fc_print((const fp_value*) tv->value, tv_buf, sizeof(tv_buf), FC_DEC), suffix);
}
- break;
case irms_internal_boolean:
switch (mode_info->mode_output) {
res->attr.{{node.attrs_name}}{{attr["fqname"]}} = {{ attr["init"] -}};
{%- endfor %}
{{- node.init }}
- res = optimize_node(res);
irn_verify_irg(res, irg);
+ res = optimize_node(res);
{{- node.init_after_opt }}
return res;
}
#include "firm_types.h"
+#include "begin.h"
+
/**
* @addtogroup ir_node
* @{
{% endfor %}
{% for node in nodes %}
-/** Return true of the node is a {{node.name}} node. */
+/** Return true if the node is a {{node.name}} node. */
FIRM_API int is_{{node.name}}(const ir_node *node);
{%- endfor %}
/** @} */
+#include "end.h"
+
#endif
''')
yourself but the parser provides a
:meth:`~jinja2.parser.Parser.free_identifier` method that creates
a new identifier for you. This identifier is not available from the
- template and is not threated specially by the compiler.
+ template and is not treated specially by the compiler.
"""
fields = ('name',)
--- /dev/null
+/**
+ * @file lpp_server.c
+ * @date 19.07.2005
+ * @author Sebastian Hack
+ *
+ * lpp_solving server.
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+
+#ifdef _WIN32
+#error Sorry, lpp_server is for UNIX only.
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <unistd.h>
+#include <pthread.h>
+
+#include <time.h>
+#include <time.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "debug.h"
+#include "list.h"
+#include "irtools.h"
+#include "util.h"
+
+#include "lpp_t.h"
+#include "lpp_comm.h"
+#include "lpp_solvers.h"
+
+#define MAX_JOBS 128
+
+/* stack size of the solver thread. */
+static size_t solver_stack_size = PTHREAD_STACK_MIN;
+
+/* master listening socket. */
+static int msock;
+
+/* master semaphore */
+static int sem;
+
+/* title of the current process */
+static char *title;
+static int title_length;
+
+static int n_children = 0;
+
+extern char** environ;
+
+typedef struct _job_t {
+ struct list_head list;
+ int id;
+ pthread_t solver;
+ pthread_t session;
+ lpp_comm_t *comm;
+ lpp_t *lpp;
+ lpp_solver_func_t *solver_func;
+ time_t received;
+ int csock;
+} job_t;
+
+#define set_solver_stack_size(size) solver_stack_size = MAX(PTHREAD_STACK_MIN, (size))
+
+#define setproctitle(name, args...) snprintf(title,title_length,(name),##args)
+
+static void initproctitle(int argc, char **argv) {
+ int i;
+ char **envp = environ;
+
+ /*
+ * Move the environment so we can reuse the memory.
+ * (Code borrowed from sendmail.)
+ * WARNING: ugly assumptions on memory layout here;
+ * if this ever causes problems, #undef DO_PS_FIDDLING
+ */
+ for (i = 0; envp[i] != NULL; i++)
+ continue;
+ environ = (char **) malloc(sizeof(char *) * (i + 1));
+ if (environ == NULL)
+ return;
+ for (i = 0; envp[i] != NULL; i++)
+ if ((environ[i] = strdup(envp[i])) == NULL)
+ return;
+ environ[i] = NULL;
+
+ title = argv[0];
+ if (i > 0)
+ title_length = envp[i-1] + strlen(envp[i-1]) - argv[0];
+ else
+ title_length = argv[argc-1] + strlen(argv[argc-1]) - argv[0];
+
+ argv[1] = NULL;
+ memset(title, 0, title_length);
+ --title_length;
+}
+
+static void job_init(job_t *job, lpp_comm_t *comm, lpp_t *lpp, lpp_solver_func_t *solver_func)
+{
+ /* TODO MAXJOBS */
+ memset(job, 0, sizeof(job[0]));
+ job->lpp = lpp;
+ job->solver_func = solver_func;
+ job->comm = comm;
+ job->csock = lpp_comm_fileno(comm);
+ job->received = time(NULL);
+ job->session = pthread_self();
+ job->id = getpid();
+}
+
+static firm_dbg_module_t *dbg = NULL;
+
+/**
+ * Set up a socket.
+ */
+static int passive_tcp(uint16_t port, int queue_len)
+{
+ int s;
+ int one = 1;
+ struct protoent *ppe;
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
+
+ ppe = getprotobyname("tcp");
+ s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
+ setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+ if(bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ perror("bind server socket");
+ exit(1);
+ }
+
+ if(listen(s, queue_len) < 0) {
+ perror("listen server socket");
+ exit(1);
+ }
+
+ return s;
+}
+
+static void *solver_thread(void * data)
+{
+ job_t *job = data;
+ DBG((dbg, LEVEL_1, "starting solver thread pid %d tid %d\n", getpid(), pthread_self()));
+ setproctitle("lpp_server [problem solving: %s]", job->lpp->name);
+
+ /* I may be cancelled at every time. */
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+ /* solve */
+ job->solver_func(job->lpp);
+
+ /* notify the session thread that we are finished. */
+ fclose(job->lpp->log);
+
+ return NULL;
+}
+
+static int solve(lpp_comm_t *comm, job_t *job)
+{
+ char buf[1024];
+ struct timeval tv;
+ fd_set rfds;
+ int fds[2];
+ FILE *rd, *log;
+ int res = 0;
+ int retval, fd_rd, fd_comm;
+ pthread_attr_t solver_thr_attr;
+
+ struct sembuf semops;
+ /* try to acquire a lock for the solver resource. */
+ semops.sem_num = 0;
+ semops.sem_op = -1;
+ semops.sem_flg = SEM_UNDO;
+ retval = semop(sem, &semops, 1);
+ if(retval < 0) {
+ perror("free semaphore");
+ }
+ DBG((dbg, LEVEL_1, "job %d: solving problem %s\n", job->id, job->lpp->name));
+
+ /* set the log file of the lpp to the pipe. */
+ pipe(fds);
+ DBG((dbg, LEVEL_4, "pipe read %d write %d\n", fds[0], fds[1]));
+
+ fd_comm = lpp_comm_fileno(comm);
+ fd_rd = fds[0];
+ rd = fdopen(fd_rd, "r");
+ log = fdopen(fds[1], "w");
+
+ lpp_set_log(job->lpp, log);
+
+ /* also set the stack size of the solver thread to a considerable amount */
+ pthread_attr_init(&solver_thr_attr);
+ pthread_attr_setstacksize(&solver_thr_attr, solver_stack_size);
+ pthread_create(&job->solver, &solver_thr_attr, solver_thread, job);
+
+ while(1) {
+ /* set select timeout to 10 seconds */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ /* set the file descriptors. */
+ FD_ZERO(&rfds);
+ FD_SET(fd_rd, &rfds);
+ FD_SET(fd_comm, &rfds);
+ DBG((dbg, LEVEL_4, "select %d %d\n", fd_rd, fd_comm));
+ retval = select(MAX(fd_rd, fd_comm) + 1, &rfds, NULL, NULL, &tv);
+ DBG((dbg, LEVEL_4, "retval %d\n", retval));
+
+ /* an event on one of the descriptors arrived. */
+ if(retval > 0) {
+ /* A log message arrived. */
+ if(FD_ISSET(fd_rd, &rfds)) {
+
+ /* if there is nothing more to read, the child died; we go home now. */
+ if(feof(rd))
+ break;
+
+ if(fgets(buf, sizeof(buf), rd)) {
+ DBG((dbg, LEVEL_4, "receiving log message %s\n", buf));
+ /* send the message over the net. */
+ lpp_writel(comm, LPP_CMD_INFO);
+ lpp_writes(comm, buf);
+ lpp_flush(comm);
+ }
+ }
+
+ /* A network message arrived. */
+ if(FD_ISSET(fd_comm, &rfds)) {
+ int cmd;
+
+ retval = read(fd_comm, &cmd, sizeof(cmd));
+ if(retval == 0) {
+ DBG((dbg, LEVEL_2, "cancelling solver thread tid %d\n", job->solver));
+ //pthread_cancel(job->solver);
+ exit(1);
+ //res = 1;
+ //break;
+ }
+
+ switch(cmd) {
+ /* eat senseless data. */
+ default:
+ while(read(fd_comm, &cmd, sizeof(cmd)) > 0) {
+ }
+ }
+ res = 1;
+ }
+ }
+ }
+
+ pthread_join(job->solver, NULL);
+ semops.sem_num = 0;
+ semops.sem_op = 1;
+ semops.sem_flg = SEM_UNDO;
+ retval = semop(sem, &semops, 1);
+ if(retval < 0) {
+ perror("free semaphore");
+ }
+
+ fclose(rd);
+ return res;
+}
+
+static void *session(int fd)
+{
+ lpp_solver_func_t *solver = lpp_find_solver("dummy");
+ lpp_comm_t *comm = lpp_comm_new(fd, LPP_BUFSIZE);
+
+ DBG((dbg, LEVEL_1, "starting session thread pid %d tid %d\n", getpid(), pthread_self()));
+ setproctitle("lpp_server [child]");
+
+ /* install the signal handler which gets triggered when the child dies. */
+ DBG((dbg, LEVEL_1, "new thread\n"));
+ for(;;) {
+ char buf[64];
+ int cmd = lpp_readl(comm);
+
+ DBG((dbg, LEVEL_2, "command: %s(%d)\n", lpp_get_cmd_name(cmd), cmd));
+ setproctitle("lpp_server [command %s(%d)]", lpp_get_cmd_name(cmd), cmd);
+ switch(cmd) {
+ /* we could not read from the socket, so the connection died. bail out. */
+ case -1:
+ case LPP_CMD_BAD:
+ goto end;
+
+ case LPP_CMD_PROBLEM:
+ {
+ job_t job;
+ lpp_t *lpp;
+
+ lpp = lpp_deserialize(comm);
+ lpp_deserialize_values(comm, lpp, lpp_value_start);
+ DBG((dbg, LEVEL_3, "problem %s received\n", lpp->name));
+ job_init(&job, comm, lpp, solver);
+
+ DBG((dbg, LEVEL_3, "starting job for problem %s\n", lpp->name));
+ setproctitle("lpp_server [problem waiting: %s]", lpp->name);
+
+ solve(comm, &job);
+ lpp_writel(comm, LPP_CMD_SOLUTION);
+ lpp_serialize_stats(comm, lpp);
+ lpp_serialize_values(comm, lpp, lpp_value_solution);
+ lpp_flush(comm);
+ DBG((dbg, LEVEL_1, "job %d: finished with problem %s\n", job.id, lpp->name));
+ setproctitle("lpp_server [problem finished: %s]", lpp->name);
+
+ free_lpp(lpp);
+ }
+
+ break;
+
+ case LPP_CMD_SOLVER:
+ lpp_readbuf(comm, buf, sizeof(buf));
+ solver = lpp_find_solver(buf);
+ DBG((dbg, LEVEL_2, "setting solver to: %s\n", buf));
+ //lpp_send_res(comm, solver != NULL, "could not find solver: %s", buf);
+ break;
+
+ case LPP_CMD_SOLVERS: {
+ int i;
+
+ for(i = 0; lpp_solvers[i].solver != NULL; i++) {
+ }
+ lpp_writel(comm, i);
+
+ for(i = 0; lpp_solvers[i].solver != NULL; i++)
+ lpp_writes(comm, lpp_solvers[i].name);
+ lpp_flush(comm);
+ break;
+ }
+
+ case LPP_CMD_SET_DEBUG:
+ {
+ int mask = lpp_readl(comm);
+ firm_dbg_set_mask(dbg, mask);
+ }
+ break;
+
+ case LPP_CMD_BYE:
+ goto end;
+
+ default:
+ fprintf(stderr, "illegal command %d. exiting\n", cmd);
+ goto end;
+ }
+ }
+
+end:
+ /* signal the queue, bail out and we are free now. */
+ lpp_comm_free(comm);
+ close(fd);
+
+ exit(0);
+}
+
+static void child_handler(int sig)
+{
+ pid_t pid;
+ int status;
+
+ (void) sig;
+
+ pid = waitpid(-1, &status, WNOHANG);
+ do {
+ if(WIFEXITED(status)) {
+ DBG((dbg, LEVEL_1, "child %d died normally with return value %d\n", pid, WEXITSTATUS(status)));
+ --n_children;
+ if(n_children != 0)
+ setproctitle("lpp_server [main (%d %s)]", n_children, (n_children>1)?"children":"child");
+ else
+ setproctitle("lpp_server [main]");
+ } else if(WIFSIGNALED(status)) {
+ DBG((dbg, LEVEL_1, "child %d died by signal %d\n", pid, WTERMSIG(status)));
+ --n_children;
+ if(n_children != 0)
+ setproctitle("lpp_server [main (%d %s)]", n_children, (n_children>1)?"children":"child");
+ else
+ setproctitle("lpp_server [main]");
+ } else
+ DBG((dbg, LEVEL_1, "child %d did something unexpected\n", pid));
+
+ pid = waitpid(-1, &status, WNOHANG);
+ } while(pid > 0);
+}
+
+static void main_loop(void)
+{
+ int csock;
+
+ DBG((dbg, LEVEL_1, "master pid %d\n", getpid()));
+
+ msock = passive_tcp(LPP_PORT, 10);
+
+ for(;;) {
+ struct sockaddr_in fsin;
+ socklen_t len = sizeof(fsin);
+ pid_t child;
+
+ csock = accept(msock, (struct sockaddr *) &fsin, &len);
+ if(csock < 0) {
+ if(errno == EINTR)
+ continue;
+ else
+ fprintf(stderr, "could not accept: %s\n", strerror(errno));
+ }
+
+ child = fork();
+ switch(child) {
+ case 0: /* we're in the new child, start the session handler */
+ close(msock);
+ session(csock);
+ break;
+ case -1: /* error, die! */
+ perror("fork");
+ exit(1);
+ default: /* if we're in the parent just continue */
+ ++n_children;
+ setproctitle("lpp_server [main (%d %s)]", n_children, (n_children>1)?"children":"child");
+ close(csock);
+ break;
+ }
+ }
+}
+
+static void toggle_dbg(int num)
+{
+ static int mask = 0;
+ (void) num;
+ mask = ~mask;
+ firm_dbg_set_mask(dbg, mask);
+}
+
+#define SEMKEYPATH "/tmp/lppkey"
+#define SEMKEYID 42
+
+static void print_syntax(void) {
+ fprintf(stderr, "lpp_server [-g <dbg level>] [-s <thread stack size>]\n");
+}
+
+int main(int argc, char *argv[])
+{
+ key_t semkey;
+ int ret;
+ int c;
+ struct sigaction sigact1, sigact2;
+
+ dbg = firm_dbg_register("lpp.server");
+ firm_dbg_set_mask(dbg, 1);
+
+ set_solver_stack_size(128 * 1024 * 1024);
+
+ /* parse options. */
+ while((c = getopt(argc, argv, "s:g:")) != -1) {
+ switch(c) {
+ case 's':
+ set_solver_stack_size(atoi(optarg));
+ break;
+ case 'g':
+ firm_dbg_set_mask(dbg, atoi(optarg));
+ break;
+ default:
+ print_syntax();
+ exit(1);
+ }
+ }
+
+ initproctitle(argc, argv);
+ setproctitle("lpp_server [main]");
+
+ memset(&sigact1, 0, sizeof(sigact1));
+ sigact1.sa_handler = toggle_dbg;
+ sigaction(SIGUSR1, &sigact1, NULL);
+
+ memset(&sigact2, 0, sizeof(sigact2));
+ sigact2.sa_handler = child_handler;
+ sigact2.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &sigact2, NULL);
+
+ /* set up semaphore */
+ semkey = ftok(SEMKEYPATH,SEMKEYID);
+ if ( semkey == (key_t)-1 ) {
+ perror("ftok() for sem failed");
+ return 1;
+ }
+
+ sem = semget( semkey, 1, 0666 | IPC_CREAT);// | IPC_EXCL );
+ if ( sem == -1 ) {
+ perror("semget() failed");
+ return -1;
+ }
+
+ ret = semctl(sem, 0, SETVAL, 1);
+ if ( ret < 0 ) {
+ perror("semctl() failed");
+ return -1;
+ }
+
+ main_loop();
+
+ ret = semctl( sem, 0, IPC_RMID );
+ if (ret < 0) {
+ printf("semctl() remove id failed\n");
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/**
+ * @file lpp_server.h
+ * @date 19.07.2005
+ * @author Sebastian Hack
+ *
+ * Copyright (C) 2005 Universitaet Karlsruhe
+ * Released under the GPL
+ */
+
+#ifndef LPP_SERVER_H
+#define LPP_SERVER_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+
+enum {
+#define LPP_CMD(x) x,
+#include "lpp_cmd.def"
+#undef LPP_CMD
+ LPP_CMD_LAST
+};
+
+#define BASIC_ERR_CHECK(expr,cond,fmt,last) \
+ if((expr) cond) { \
+ fprintf(stderr, "%s(%d): %s %s: ", __FILE__, __LINE__, #expr, #cond); \
+ print_err fmt; \
+ fprintf(stderr, "\n"); \
+ last; \
+ }
+
+#define BASIC_ERRNO_CHECK(expr,cond,last) \
+ if((expr) cond) { \
+ fprintf(stderr, "%s(%d): %s %s: %s\n", \
+ __FILE__, __LINE__, #expr, #cond, strerror(errno)); \
+ last; \
+ }
+
+#define ERR_CHECK_RETURN(expr, cond, fmt, retval) \
+ BASIC_ERR_CHECK(expr, cond, fmt, return retval)
+
+#define ERRNO_CHECK_RETURN(expr, cond, retval) \
+ BASIC_ERRNO_CHECK(expr, cond, return retval)
+
+#define ERR_CHECK_RETURN_VOID(expr, cond, fmt) \
+ BASIC_ERR_CHECK(expr, cond, fmt, return)
+
+#define ERRNO_CHECK_RETURN_VOID(expr, cond) \
+ BASIC_ERRNO_CHECK(expr, cond, return)
+
+#define ERR_CHECK(expr, cond, fmt) \
+ BASIC_ERR_CHECK(expr, cond, fmt, (void) 0)
+
+#define ERRNO_CHECK(expr, cond) \
+ BASIC_ERRNO_CHECK(expr, cond, (void) 0)
+
+static void print_err(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+static void writel(int fd, uint32_t x)
+{
+ x = htonl(x);
+ ERRNO_CHECK(write(fd, &x, sizeof(x)), == -1);
+}
+
+static void writed(int fd, double dbl)
+{
+ ERRNO_CHECK(write(fd, &dbl, sizeof(dbl)), == -1);
+}
+
+static void writes(int fd, const char *str)
+{
+ size_t n = strlen(str);
+ writel(fd, n);
+ ERRNO_CHECK(write(fd, str, n), == -1);
+}
+
+static uint32_t readl(int fd)
+{
+ uint32_t res;
+
+ ERRNO_CHECK(read(fd, &res, sizeof(res)), == -1);
+ return ntohl(res);
+}
+
+static double readd(int fd)
+{
+ double res;
+ ERRNO_CHECK(read(fd, &res, sizeof(res)), == -1);
+ return res;
+}
+
+static char *reads(int fd)
+{
+ size_t len = readl(fd);
+ char *res = malloc(sizeof(char) * (len + 1));
+
+ ERRNO_CHECK(read(fd, res, len), == -1);
+ res[len] = '\0';
+ return res;
+}
+
+static char *readbuf(int fd, size_t buflen, char *buf)
+{
+ char dummy[1024];
+ size_t i;
+ size_t n = buflen - 1;
+ size_t len = readl(fd);
+ size_t max_read = n < len ? n : len;
+ size_t rest = len - max_read;
+
+ if(buflen > 0 && buf != NULL) {
+ ERRNO_CHECK(read(fd, buf, max_read), == -1);
+ buf[max_read] = '\0';
+ }
+
+ /* eat up data that didnt fit into the string */
+ for(i = 0, n = rest / sizeof(dummy); i < n; ++i)
+ read(fd, dummy, sizeof(dummy));
+
+ if(rest % sizeof(dummy) > 0)
+ read(fd, dummy, rest % sizeof(dummy));
+
+ return buf;
+}
+
+static int ack(int fd, size_t buflen, char *buf)
+{
+ int res = 0;
+ int cmd = readl(fd);
+
+ switch(cmd) {
+ case LPP_CMD_OK:
+ res = 1;
+ break;
+ case LPP_CMD_BAD:
+ readbuf(fd, buflen, buf);
+ default:
+ res = 0;
+ }
+
+ return res;
+}
+
+static void send_res(int fd, int ok, const char *fmt, ...)
+{
+ if(!ok) {
+ char buf[1024];
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ writel(fd, LPP_CMD_BAD);
+ writes(fd, buf);
+ }
+
+ else
+ writel(fd, LPP_CMD_OK);
+}
+
+static void send_ack(int fd)
+{
+ send_res(fd, 1, "");
+}
+
+#endif