PPC32 backend from the backend praktikum
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 15:43:36 +0000 (15:43 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Mon, 27 Mar 2006 15:43:36 +0000 (15:43 +0000)
17 files changed:
ir/be/ppc32/bearch_ppc32.c [new file with mode: 0644]
ir/be/ppc32/bearch_ppc32.h [new file with mode: 0644]
ir/be/ppc32/bearch_ppc32_t.h [new file with mode: 0644]
ir/be/ppc32/ppc32_emitter.c [new file with mode: 0644]
ir/be/ppc32/ppc32_emitter.h [new file with mode: 0644]
ir/be/ppc32/ppc32_gen_decls.c [new file with mode: 0644]
ir/be/ppc32/ppc32_gen_decls.h [new file with mode: 0644]
ir/be/ppc32/ppc32_map_regs.c [new file with mode: 0644]
ir/be/ppc32/ppc32_map_regs.h [new file with mode: 0644]
ir/be/ppc32/ppc32_new_nodes.c [new file with mode: 0644]
ir/be/ppc32/ppc32_new_nodes.h [new file with mode: 0644]
ir/be/ppc32/ppc32_nodes_attr.h [new file with mode: 0644]
ir/be/ppc32/ppc32_spec.pl [new file with mode: 0644]
ir/be/ppc32/ppc32_transform.c [new file with mode: 0644]
ir/be/ppc32/ppc32_transform.h [new file with mode: 0644]
ir/be/ppc32/ppc32_transform_conv.c [new file with mode: 0644]
ir/be/ppc32/ppc32_transform_conv.h [new file with mode: 0644]

diff --git a/ir/be/ppc32/bearch_ppc32.c b/ir/be/ppc32/bearch_ppc32.c
new file mode 100644 (file)
index 0000000..79b8ad4
--- /dev/null
@@ -0,0 +1,862 @@
+/* The main ppc backend driver file. */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pseudo_irg.h"
+#include "irgwalk.h"
+#include "irprog.h"
+#include "irprintf.h"
+#include "ircons.h"
+#include "irgmod.h"
+#include "irdump.h"
+
+#include "bitset.h"
+#include "debug.h"
+
+#include "../bearch.h"                /* the general register allocator interface */
+#include "../benode_t.h"
+#include "../belower.h"
+#include "../besched_t.h"
+#include "../be.h"
+#include "../beabi.h"
+
+#include "pset.h"
+
+#include "bearch_ppc32_t.h"
+
+#include "ppc32_new_nodes.h"           /* ppc nodes interface */
+#include "gen_ppc32_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
+#include "ppc32_gen_decls.h"           /* interface declaration emitter */
+#include "ppc32_transform.h"
+#include "ppc32_transform_conv.h"
+#include "ppc32_emitter.h"
+#include "ppc32_map_regs.h"
+
+#define DEBUG_MODULE "firm.be.ppc.isa"
+
+int isleaf;
+pset *symbol_pset = NULL;
+
+/* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */
+static set *cur_reg_set = NULL;
+
+/**************************************************
+ *                         _ _              _  __
+ *                        | | |            (_)/ _|
+ *  _ __ ___  __ _    __ _| | | ___   ___   _| |_
+ * | '__/ _ \/ _` |  / _` | | |/ _ \ / __| | |  _|
+ * | | |  __/ (_| | | (_| | | | (_) | (__  | | |
+ * |_|  \___|\__, |  \__,_|_|_|\___/ \___| |_|_|
+ *            __/ |
+ *           |___/
+ **************************************************/
+
+static ir_node *my_skip_proj(const ir_node *n) {
+       while (is_Proj(n))
+               n = get_Proj_pred(n);
+       return (ir_node *)n;
+}
+
+/**
+ * Return register requirements for a ppc node.
+ * If the node returns a tuple (mode_T) then the proj's
+ * will be asked for this information.
+ */
+static const arch_register_req_t *ppc32_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
+       const ppc32_register_req_t *irn_req;
+       long               node_pos = pos == -1 ? 0 : pos;
+       ir_mode           *mode     = get_irn_mode(irn);
+       firm_dbg_module_t *mod      = firm_dbg_register(DEBUG_MODULE);
+
+       if (is_Block(irn) || mode == mode_X || mode == mode_M) {
+               DBG((mod, LEVEL_1, "ignoring block, mode_X or mode_M node %+F\n", irn));
+               return NULL;
+       }
+
+       if (mode == mode_T && pos < 0) {
+               DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F", irn));
+               return NULL;
+       }
+
+       DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn));
+
+       if (is_Proj(irn)) {
+               /* in case of a proj, we need to get the correct OUT slot */
+               /* of the node corresponding to the proj number */
+               if (pos == -1) {
+                       node_pos = ppc32_translate_proj_pos(irn);
+               }
+               else {
+                       node_pos = pos;
+               }
+
+               irn = my_skip_proj(irn);
+
+               DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos));
+       }
+
+       /* get requirements for our own nodes */
+       if (is_ppc32_irn(irn)) {
+               if (pos >= 0) {
+                       irn_req = get_ppc32_in_req(irn, pos);
+               }
+               else {
+                       irn_req = get_ppc32_out_req(irn, node_pos);
+               }
+
+               DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos));
+
+               memcpy(req, &(irn_req->req), sizeof(*req));
+
+               if (arch_register_req_is(&(irn_req->req), should_be_same)) {
+                       assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI");
+                       req->other_same = get_irn_n(irn, irn_req->same_pos);
+               }
+
+               if (arch_register_req_is(&(irn_req->req), should_be_different)) {
+                       assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI");
+                       req->other_different = get_irn_n(irn, irn_req->different_pos);
+               }
+       }
+       /* get requirements for FIRM nodes */
+       else {
+               /* treat Phi like Const with default requirements */
+               if (is_Phi(irn)) {
+                       DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn));
+
+                       if (mode_is_float(mode)) {
+                               memcpy(req, &(ppc32_default_req_ppc32_floating_point.req), sizeof(*req));
+                       }
+                       else if (mode_is_int(mode) || mode_is_reference(mode)) {
+                               memcpy(req, &(ppc32_default_req_ppc32_general_purpose.req), sizeof(*req));
+                       }
+                       else if (mode == mode_T || mode == mode_M) {
+                               DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn));
+                               return NULL;
+                       }
+                       else {
+                               assert(0 && "unsupported Phi-Mode");
+                       }
+               }
+               else {
+                       DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn));
+                       req = NULL;
+               }
+       }
+
+       return req;
+}
+
+static void ppc32_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) {
+       int pos = 0;
+
+       if (is_Proj(irn)) {
+
+               if (get_irn_mode(irn) == mode_X) {
+                       return;
+               }
+
+               pos = ppc32_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_ppc32_irn(irn)) {
+               const arch_register_t **slots;
+
+               slots      = get_ppc32_slots(irn);
+               slots[pos] = reg;
+       }
+       else {
+               /* here we set the registers for the Phi nodes */
+               ppc32_set_firm_reg(irn, reg, cur_reg_set);
+       }
+}
+
+static const arch_register_t *ppc32_get_irn_reg(const void *self, const ir_node *irn) {
+       int pos = 0;
+       const arch_register_t *reg = NULL;
+
+       if (is_Proj(irn)) {
+
+               if (get_irn_mode(irn) == mode_X) {
+                       return NULL;
+               }
+
+               pos = ppc32_translate_proj_pos(irn);
+               irn = my_skip_proj(irn);
+       }
+
+       if (is_ppc32_irn(irn)) {
+               const arch_register_t **slots;
+               slots = get_ppc32_slots(irn);
+               reg   = slots[pos];
+       }
+       else {
+               reg = ppc32_get_firm_reg(irn, cur_reg_set);
+       }
+
+       return reg;
+}
+
+static arch_irn_class_t ppc32_classify(const void *self, const ir_node *irn) {
+       irn = my_skip_proj(irn);
+
+       if (is_cfop(irn)) {
+               return arch_irn_class_branch;
+       }
+       else if (is_ppc32_irn(irn)) {
+               return arch_irn_class_normal;
+       }
+
+       return 0;
+}
+
+static arch_irn_flags_t ppc32_get_flags(const void *self, const ir_node *irn) {
+       irn = my_skip_proj(irn);
+
+       if (is_ppc32_irn(irn)) {
+               return get_ppc32_flags(irn);
+       }
+       else if (is_Unknown(irn)) {
+               return arch_irn_flags_ignore;
+       }
+
+       return 0;
+}
+
+static entity *ppc32_get_frame_entity(const void *self, const ir_node *irn) {
+       if(!is_ppc32_irn(irn)) return NULL;
+       if(get_ppc32_type(irn)!=ppc32_ac_FrameEntity) return NULL;
+       return get_ppc32_frame_entity(irn);
+}
+
+/**
+ * This function is called by the generic backend to correct offsets for
+ * nodes accessing the stack.
+ */
+static void ppc32_set_stack_bias(const void *self, ir_node *irn, int bias) {
+       set_ppc32_offset(irn, bias);
+}
+
+typedef struct
+{
+       const be_abi_call_t *call;
+       ir_graph *irg;
+} ppc32_abi_env;
+
+/**
+ * Initialize the callback object.
+ * @param call The call object.
+ * @param aenv The architecture environment.
+ * @param irg  The graph with the method.
+ * @return     Some pointer. This pointer is passed to all other callback functions as self object.
+ */
+static void *ppc32_abi_init(const be_abi_call_t *call, const arch_env_t *aenv, ir_graph *irg)
+{
+       ppc32_abi_env *env = xmalloc(sizeof(ppc32_abi_env));
+       env->call = call;
+       env->irg = irg;
+       return env;
+}
+
+/**
+ * Destroy the callback object.
+ * @param self The callback object.
+ */
+static void ppc32_abi_done(void *self)
+{
+       free(self);
+}
+
+/**
+ * Get the between type for that call.
+ * @param self The callback object.
+ * @return The between type of for that call.
+ */
+static ir_type *ppc32_abi_get_between_type(void *self)
+{
+       static ir_type *between_type = NULL;
+       static entity *old_bp_ent    = NULL;
+
+       if(!between_type) {
+               entity *ret_addr_ent;
+               ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
+               ir_type *old_bp_type   = new_type_primitive(new_id_from_str("bp"), mode_P);
+
+               between_type           = new_type_class(new_id_from_str("ppc32_between_type"));
+               old_bp_ent             = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type);
+               ret_addr_ent           = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type);
+
+               set_entity_offset_bytes(old_bp_ent, 0);
+               set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type));
+               set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type));
+       }
+
+       return between_type;
+}
+
+/**
+ * Put all registers which are saved by the prologue/epilogue in a set.
+ * @param self The callback object.
+ * @param regs A set.
+ */
+static void ppc32_abi_regs_saved_by_me(void *self, pset *regs)
+{
+}
+
+/**
+ * Generate the prologue.
+ * @param self    The callback object.
+ * @param mem     A pointer to the mem node. Update this if you define new memory.
+ * @param reg_map A mapping mapping all callee_save/ignore/parameter registers to their defining nodes.
+ * @return        The register which shall be used as a stack frame base.
+ *
+ * All nodes which define registers in @p reg_map must keep @p reg_map current.
+ */
+static const arch_register_t *ppc32_abi_prologue(void *self, ir_node **mem, pmap *reg_map)
+{
+       ppc32_abi_env *env = (ppc32_abi_env *) self;
+       be_abi_call_flags_t flags = be_abi_call_get_flags(env->call);
+       isleaf = flags.bits.irg_is_leaf;
+
+       if(flags.bits.try_omit_fp)
+               return &ppc32_general_purpose_regs[REG_R1];
+       else
+               return &ppc32_general_purpose_regs[REG_R31];
+}
+
+/**
+ * Generate the epilogue.
+ * @param self    The callback object.
+ * @param mem     Memory one can attach to.
+ * @param reg_map A mapping mapping all callee_save/ignore/return registers to their defining nodes.
+ *
+ * All nodes which define registers in @p reg_map must keep @p reg_map current.
+ * Also, the @p mem variable must be updated, if memory producing nodes are inserted.
+ */
+static void ppc32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map)
+{
+}
+
+static const be_abi_callbacks_t ppc32_abi_callbacks = {
+       ppc32_abi_init,
+       ppc32_abi_done,
+       ppc32_abi_get_between_type,
+       ppc32_abi_regs_saved_by_me,
+       ppc32_abi_prologue,
+       ppc32_abi_epilogue,
+};
+
+/* fill register allocator interface */
+
+static const arch_irn_ops_if_t ppc32_irn_ops_if = {
+       ppc32_get_irn_reg_req,
+       ppc32_set_irn_reg,
+       ppc32_get_irn_reg,
+       ppc32_classify,
+       ppc32_get_flags,
+       ppc32_get_frame_entity,
+       ppc32_set_stack_bias
+};
+
+ppc32_irn_ops_t ppc32_irn_ops = {
+       &ppc32_irn_ops_if,
+       NULL
+};
+
+
+
+/**************************************************
+ *                _                         _  __
+ *               | |                       (_)/ _|
+ *   ___ ___   __| | ___  __ _  ___ _ __    _| |_
+ *  / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \  | |  _|
+ * | (_| (_) | (_| |  __/ (_| |  __/ | | | | | |
+ *  \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
+ *                        __/ |
+ *                       |___/
+ **************************************************/
+
+static void ppc32_before_abi(void *self) {
+       ppc32_code_gen_t *cg = self;
+       ir_type *frame_type = get_irg_frame_type(cg->irg);
+
+       frame_alloc_area(frame_type, 24, 4, 1);
+
+       ppc32_init_conv_walk();
+       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_conv_walk, cg);
+
+       if (cg->area_size) {
+               if(cg->area_size < 32) cg->area_size = 32;
+               cg->area = frame_alloc_area(get_irg_frame_type(cg->irg), cg->area_size+24, 16, 1);
+       }
+}
+
+static void ppc32_search_start_successor(ir_node *block, void *env) {
+       ppc32_code_gen_t *cg = env;
+       int n = get_Block_n_cfgpreds(block);
+       ir_node *startblock = get_irg_start_block(cg->irg);
+       if(block == startblock) return;
+
+       for (n--; n >= 0; n--) {
+               ir_node *predblock = get_irn_n(get_Block_cfgpred(block, n), -1);
+               if(predblock == startblock)
+               {
+                       cg->start_succ_block = block;
+                       return;
+               }
+       }
+}
+
+/**
+ * Transforms the standard firm graph into
+ * a ppc firm graph
+ */
+static void ppc32_prepare_graph(void *self) {
+       ppc32_code_gen_t *cg = self;
+
+       irg_block_walk_graph(cg->irg, NULL, ppc32_search_start_successor, cg);
+       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_pretransform_walk, cg);
+       be_dump(cg->irg, "-pretransformed", dump_ir_block_graph);
+
+       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_transform_node, cg);
+       be_dump(cg->irg, "-transformed", dump_ir_block_graph);
+       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_transform_const, cg);
+}
+
+
+
+/**
+ * Called immediatly before emit phase.
+ */
+static void ppc32_finish_irg(ir_graph *irg, ppc32_code_gen_t *cg) {
+       /* TODO: - fix offsets for nodes accessing stack
+                        - ...
+       */
+}
+
+
+/**
+ * These are some hooks which must be filled but are probably not needed.
+ */
+static void ppc32_before_sched(void *self) {
+       /* Some stuff you need to do after scheduling but before register allocation */
+}
+
+/**
+ * Called before the register allocator.
+ * Calculate a block schedule here. We need it for the x87
+ * simulator and the emitter.
+ */
+static void ppc32_before_ra(void *self) {
+       ppc32_code_gen_t *cg = self;
+       cg->blk_sched = sched_create_block_schedule(cg->irg);
+}
+
+static void ppc32_transform_spill(ir_node *node, void *env)
+{
+       ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
+
+       if(be_is_Spill(node))
+       {
+               ir_node *store, *proj;
+               dbg_info *dbg = get_irn_dbg_info(node);
+               ir_node *block = get_nodes_block(node);
+               ir_mode *mode = get_irn_mode(node);
+
+               const arch_register_class_t *regclass = arch_get_irn_reg_class(cgenv->arch_env, node, 1);
+
+               if (regclass == &ppc32_reg_classes[CLASS_ppc32_general_purpose])
+               {
+                       store = new_rd_ppc32_Stw(dbg, current_ir_graph, block,
+                               get_irn_n(node, 0), get_irn_n(node, 1), new_rd_NoMem(current_ir_graph), mode_T);
+               }
+               else if (regclass == &ppc32_reg_classes[CLASS_ppc32_floating_point])
+               {
+                       store = new_rd_ppc32_Stfd(dbg, current_ir_graph, block,
+                               get_irn_n(node, 0), get_irn_n(node, 1), new_rd_NoMem(current_ir_graph), mode_T);
+               }
+               else assert(0 && "Spill for register class not supported yet!");
+
+               set_ppc32_frame_entity(store, be_get_frame_entity(node));
+
+               proj = new_rd_Proj(dbg, current_ir_graph, block, store, mode_M, pn_Store_M);
+
+               if (sched_is_scheduled(node)) {
+                       sched_add_after(sched_prev(node), store);
+                       sched_add_after(store, proj);
+
+                       sched_remove(node);
+               }
+
+               exchange(node, proj);
+       }
+
+       if(be_is_Reload(node))
+       {
+               ir_node *load, *proj;
+               const arch_register_t *reg;
+               dbg_info *dbg = get_irn_dbg_info(node);
+               ir_node *block = get_nodes_block(node);
+               ir_mode *mode = get_irn_mode(node);
+
+               const arch_register_class_t *regclass = arch_get_irn_reg_class(cgenv->arch_env, node, -1);
+
+               if (regclass == &ppc32_reg_classes[CLASS_ppc32_general_purpose])
+               {
+                       load = new_rd_ppc32_Lwz(dbg, current_ir_graph, block,
+                               get_irn_n(node, 0), get_irn_n(node, 1), mode_T);
+               }
+               else if (regclass == &ppc32_reg_classes[CLASS_ppc32_floating_point])
+               {
+                       load = new_rd_ppc32_Lfd(dbg, current_ir_graph, block,
+                               get_irn_n(node, 0), get_irn_n(node, 1), mode_T);
+               }
+               else assert(0 && "Reload for register class not supported yet!");
+
+               set_ppc32_frame_entity(load, be_get_frame_entity(node));
+
+               proj = new_rd_Proj(dbg, current_ir_graph, block, load, mode, pn_Load_res);
+
+               if (sched_is_scheduled(node)) {
+                       sched_add_after(sched_prev(node), load);
+                       sched_add_after(load, proj);
+
+                       sched_remove(node);
+               }
+
+               /* copy the register from the old node to the new Load */
+               reg = arch_get_irn_register(cgenv->arch_env, node);
+               arch_set_irn_register(cgenv->arch_env, load, reg);
+
+               exchange(node, proj);
+       }
+}
+
+/**
+ * Some stuff to do immediately after register allocation
+ */
+static void ppc32_after_ra(void *self) {
+       ppc32_code_gen_t *cg = self;
+       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_transform_spill, cg);
+}
+
+/**
+ * Emits the code, closes the output file and frees
+ * the code generator interface.
+ */
+static void ppc32_emit_and_done(void *self) {
+       ppc32_code_gen_t *cg = self;
+       ir_graph           *irg = cg->irg;
+       FILE               *out = cg->out;
+
+       if (cg->emit_decls) {
+               ppc32_gen_decls(cg->out);
+               cg->emit_decls = 0;
+       }
+
+       ppc32_finish_irg(irg, cg);
+       dump_ir_block_graph_sched(irg, "-ppc-finished");
+       ppc32_gen_routine(out, irg, cg);
+
+       cur_reg_set = NULL;
+
+       /* de-allocate code generator */
+       del_set(cg->reg_set);
+       free(self);
+
+       if(symbol_pset)
+       {
+               del_pset(symbol_pset);
+               symbol_pset = NULL;
+       }
+}
+
+int is_direct_entity(entity *ent);
+
+/**
+ * Collects all SymConsts which need to be accessed "indirectly"
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void ppc32_collect_symconsts_walk(ir_node *node, void *env) {
+       ppc32_code_gen_t *cg = env;
+       if(get_irn_op(node)==op_SymConst)
+       {
+               entity *ent = get_SymConst_entity(node);
+               if(!is_direct_entity(ent))
+                       pset_insert_ptr(symbol_pset, ent);
+       }
+}
+
+static void *ppc32_cg_init(FILE *F, const be_irg_t *birg);
+
+static const arch_code_generator_if_t ppc32_code_gen_if = {
+       ppc32_cg_init,
+       ppc32_before_abi,
+       ppc32_prepare_graph,
+       ppc32_before_sched,   /* before scheduling hook */
+       ppc32_before_ra,      /* before register allocation hook */
+       ppc32_after_ra,
+       ppc32_emit_and_done
+};
+
+/**
+ * Initializes the code generator.
+ */
+static void *ppc32_cg_init(FILE *F, const be_irg_t *birg) {
+       ppc32_isa_t      *isa = (ppc32_isa_t *)birg->main_env->arch_env->isa;
+       ppc32_code_gen_t *cg  = xmalloc(sizeof(*cg));
+
+       cg->impl      = &ppc32_code_gen_if;
+       cg->irg       = birg->irg;
+       cg->reg_set   = new_set(ppc32_cmp_irn_reg_assoc, 1024);
+       cg->mod       = firm_dbg_register("firm.be.ppc.cg");
+       cg->out       = F;
+       cg->arch_env  = birg->main_env->arch_env;
+       cg->birg      = birg;
+       cg->area_size = 0;
+       cg->area      = NULL;
+       cg->start_succ_block = NULL;
+       cg->blk_sched = NULL;
+
+       isa->num_codegens++;
+
+       if (isa->num_codegens > 1)
+               cg->emit_decls = 0;
+       else
+       {
+               int i;
+               cg->emit_decls = 1;
+               symbol_pset = pset_new_ptr(8);
+               for(i=0; i<get_irp_n_irgs(); i++)
+               {
+                       cg->irg = get_irp_irg(i);
+                       irg_walk_blkwise_graph(cg->irg, NULL, ppc32_collect_symconsts_walk, cg);
+               }
+               cg->irg = birg->irg;
+       }
+
+       cur_reg_set = cg->reg_set;
+
+       ppc32_irn_ops.cg = cg;
+
+       return (arch_code_generator_t *)cg;
+}
+
+
+
+/*****************************************************************
+ *  ____             _                  _   _____  _____
+ * |  _ \           | |                | | |_   _|/ ____|  /\
+ * | |_) | __ _  ___| | _____ _ __   __| |   | | | (___   /  \
+ * |  _ < / _` |/ __| |/ / _ \ '_ \ / _` |   | |  \___ \ / /\ \
+ * | |_) | (_| | (__|   <  __/ | | | (_| |  _| |_ ____) / ____ \
+ * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/    \_\
+ *
+ *****************************************************************/
+
+static ppc32_isa_t ppc32_isa_template = {
+       &ppc32_isa_if,
+       &ppc32_general_purpose_regs[REG_R1],    // stack pointer
+       &ppc32_general_purpose_regs[REG_R31],   // base pointer
+       -1,                                                                 // stack is decreasing
+       0                                                                       // num codegens... ??
+};
+
+/**
+ * Initializes the backend ISA and opens the output file.
+ */
+static void *ppc32_init(void) {
+       static int inited = 0;
+       ppc32_isa_t *isa;
+
+       if(inited)
+               return NULL;
+
+       isa = xcalloc(1, sizeof(*isa));
+       memcpy(isa, &ppc32_isa_template, sizeof(*isa));
+
+       ppc32_register_init(isa);
+       ppc32_create_opcodes();
+
+       inited = 1;
+
+       return isa;
+}
+
+
+
+/**
+ * Closes the output file and frees the ISA structure.
+ */
+static void ppc32_done(void *self) {
+       free(self);
+}
+
+
+
+static int ppc32_get_n_reg_class(const void *self) {
+       return N_CLASSES;
+}
+
+static const arch_register_class_t *ppc32_get_reg_class(const void *self, int i) {
+       assert(i >= 0 && i < N_CLASSES && "Invalid ppc register class requested.");
+       return &ppc32_reg_classes[i];
+}
+
+
+
+/**
+ * Get the register class which shall be used to store a value of a given mode.
+ * @param self The this pointer.
+ * @param mode The mode in question.
+ * @return A register class which can hold values of the given mode.
+ */
+const arch_register_class_t *ppc32_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
+       if (mode_is_float(mode))
+               return &ppc32_reg_classes[CLASS_ppc32_floating_point];
+       else
+               return &ppc32_reg_classes[CLASS_ppc32_general_purpose];
+}
+
+
+/**
+ * Get the ABI restrictions for procedure calls.
+ * @param self        The this pointer.
+ * @param method_type The type of the method (procedure) in question.
+ * @param abi         The abi object to be modified
+ */
+static void ppc32_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
+       ir_type  *tp;
+       ir_mode  *mode;
+       int       i, n = get_method_n_params(method_type);
+       int               stackoffs = 0, lastoffs = 0, stackparamsize;
+
+       int               gpregi = REG_R3;
+       int               fpregi = REG_F1;
+
+       const arch_register_t *reg;
+       be_abi_call_flags_t call_flags = { 0, 0, 1, 0, 0, 0, 1 };
+
+       if(get_type_visibility(method_type)!=visibility_external_allocated)
+               call_flags.bits.call_has_imm = 1;
+
+       /* set stack parameter passing style */
+       be_abi_call_set_flags(abi, call_flags, &ppc32_abi_callbacks);
+
+       for (i = 0; i < n; i++) {
+               tp   = get_method_param_type(method_type, i);
+               if(is_atomic_type(tp))
+               {
+                       mode = get_type_mode(tp);
+
+                       if(mode_is_float(mode))
+                       {
+                               if(fpregi <= REG_F13)
+                               {
+                                       if(get_mode_size_bits(mode) == 32) gpregi++, stackparamsize=4;
+                                       else gpregi += 2, stackparamsize=8;                                                             // mode == irm_D
+                                       reg = &ppc32_floating_point_regs[fpregi++];
+                               }
+                               else
+                               {
+                                       if(get_mode_size_bits(mode) == 32) stackparamsize=4;
+                                       else stackparamsize=8;                                                          // mode == irm_D
+                                       reg = NULL;
+                               }
+                       }
+                       else
+                       {
+                               if(gpregi <= REG_R10)
+                                       reg = &ppc32_general_purpose_regs[gpregi++];
+                               else
+                                       reg = NULL;
+                               stackparamsize=4;
+                       }
+
+                       if(reg)
+                               be_abi_call_param_reg(abi, i, reg);
+                       else
+                       {
+                               be_abi_call_param_stack(abi, i, 4, stackoffs-lastoffs, 0);
+                               lastoffs = stackoffs+stackparamsize;
+                       }
+                       stackoffs += stackparamsize;
+               }
+               else
+               {
+                       be_abi_call_param_stack(abi, i, 4, stackoffs-lastoffs, 0);
+                       stackoffs += (get_type_size_bytes(tp)+3) & -4;
+                       lastoffs = stackoffs;
+               }
+       }
+
+       /* explain where result can be found if any */
+       if (get_method_n_ress(method_type) > 0) {
+               tp   = get_method_res_type(method_type, 0);
+               mode = get_type_mode(tp);
+
+               be_abi_call_res_reg(abi, 0,
+                       mode_is_float(mode) ? &ppc32_floating_point_regs[REG_F1] : &ppc32_general_purpose_regs[REG_R3]);
+       }
+}
+
+static const void *ppc32_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
+       return &ppc32_irn_ops;
+}
+
+const arch_irn_handler_t ppc32_irn_handler = {
+       ppc32_get_irn_ops
+};
+
+const arch_irn_handler_t *ppc32_get_irn_handler(const void *self) {
+       return &ppc32_irn_handler;
+}
+
+int ppc32_to_appear_in_schedule(void *block_env, const ir_node *irn) {
+       return is_ppc32_irn(irn);
+}
+
+/**
+ * Initializes the code generator interface.
+ */
+static const arch_code_generator_if_t *ppc32_get_code_generator_if(void *self) {
+       return &ppc32_code_gen_if;
+}
+
+list_sched_selector_t ppc32_sched_selector;
+
+/**
+ * Returns the reg_pressure scheduler with to_appear_in_schedule() overloaded
+ */
+static const list_sched_selector_t *ppc32_get_list_sched_selector(const void *self) {
+       memcpy(&ppc32_sched_selector, trivial_selector, sizeof(list_sched_selector_t));
+       ppc32_sched_selector.to_appear_in_schedule = ppc32_to_appear_in_schedule;
+       return &ppc32_sched_selector;
+}
+
+#ifdef WITH_LIBCORE
+static void ppc32_register_options(lc_opt_entry_t *ent)
+{
+}
+#endif /* WITH_LIBCORE */
+
+const arch_isa_if_t ppc32_isa_if = {
+#ifdef WITH_LIBCORE
+       ppc32_register_options,
+#endif
+       ppc32_init,
+       ppc32_done,
+       ppc32_get_n_reg_class,
+       ppc32_get_reg_class,
+       ppc32_get_reg_class_for_mode,
+       ppc32_get_call_abi,
+       ppc32_get_irn_handler,
+       ppc32_get_code_generator_if,
+       ppc32_get_list_sched_selector,
+};
diff --git a/ir/be/ppc32/bearch_ppc32.h b/ir/be/ppc32/bearch_ppc32.h
new file mode 100644 (file)
index 0000000..16b0472
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _BEARCH_PPC32_H_
+#define _BEARCH_PPC32_H_
+
+#include "../bearch.h"
+
+extern const arch_isa_if_t ppc32_isa_if;
+
+#endif /* _BEARCH_PPC32_H_ */
diff --git a/ir/be/ppc32/bearch_ppc32_t.h b/ir/be/ppc32/bearch_ppc32_t.h
new file mode 100644 (file)
index 0000000..a3b2037
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _BEARCH_PPC32_T_H_
+#define _BEARCH_PPC32_T_H_
+
+#include "debug.h"
+#include "bearch_ppc32.h"
+#include "ppc32_nodes_attr.h"
+#include "../be.h"
+#include "set.h"
+
+typedef struct _ppc32_code_gen_t {
+       const arch_code_generator_if_t *impl;             /**< implementation */
+       ir_graph                       *irg;              /**< current irg */
+       FILE                           *out;              /**< output file */
+       const arch_env_t               *arch_env;         /**< the arch env */
+       set                            *reg_set;          /**< set to memorize registers for FIRM nodes (e.g. phi) */
+       firm_dbg_module_t              *mod;              /**< debugging module */
+       int                             emit_decls;       /**< flag indicating if decls were already emitted */
+       const be_irg_t                 *birg;             /**< The be-irg (contains additional information about the irg) */
+       unsigned                        area_size;        /**< size of call area for the current irg */
+       entity                         *area;             /**< the entity representing the call area or NULL for leaf functions */
+       ir_node                        *start_succ_block; /**< the block succeeding the start block in the cfg */
+       ir_node                        **blk_sched;       /**< an array containing the scheduled blocks */
+} ppc32_code_gen_t;
+
+
+typedef struct _ppc32_isa_t {
+       const arch_isa_if_t   *impl;
+       const arch_register_t *sp;            /**< The stack pointer register. */
+       const arch_register_t *bp;            /**< The base pointer register. */
+       const int              stack_dir;     /**< -1 for decreasing, 1 for increasing. */
+       int                  num_codegens;
+} ppc32_isa_t;
+
+
+typedef struct _ppc32_irn_ops_t {
+       const arch_irn_ops_if_t *impl;
+       ppc32_code_gen_t     *cg;
+} ppc32_irn_ops_t;
+
+
+/** this is a struct to minimize the number of parameters
+   for transformation walker */
+typedef struct _ppc32_transform_env_t {
+       firm_dbg_module_t *mod;      /**< The firm debugger */
+       dbg_info          *dbg;      /**< The node debug info */
+       ir_graph          *irg;      /**< The irg, the node should be created in */
+       ir_node           *block;    /**< The block, the node should belong to */
+       ir_node           *irn;      /**< The irn, to be transformed */
+       ir_mode           *mode;     /**< The mode of the irn */
+} ppc32_transform_env_t;
+
+
+#endif /* _BEARCH_PPC32_T_H_ */
diff --git a/ir/be/ppc32/ppc32_emitter.c b/ir/be/ppc32/ppc32_emitter.c
new file mode 100644 (file)
index 0000000..393278f
--- /dev/null
@@ -0,0 +1,726 @@
+/* ppc emitter */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <limits.h>
+
+#include "xmalloc.h"
+#include "tv.h"
+#include "iredges.h"
+#include "debug.h"
+#include "irgwalk.h"
+#include "irprintf.h"
+#include "irop_t.h"
+#include "irnode_t.h"
+#include "irargs_t.h"
+
+#include "../besched_t.h"
+#include "../benode_t.h"
+
+#include "ppc32_emitter.h"
+#include "gen_ppc32_emitter.h"
+#include "gen_ppc32_regalloc_if.h"
+#include "ppc32_nodes_attr.h"
+#include "ppc32_new_nodes.h"
+#include "ppc32_map_regs.h"
+
+#define SNPRINTF_BUF_LEN 128
+
+static const arch_env_t *arch_env = NULL;
+static char printbuf[SNPRINTF_BUF_LEN];
+static char printbuf2[SNPRINTF_BUF_LEN];
+
+extern int isleaf;
+
+
+/*************************************************************
+ *             _       _    __   _          _
+ *            (_)     | |  / _| | |        | |
+ *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
+ * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
+ * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
+ * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
+ * | |                                       | |
+ * |_|                                       |_|
+ *************************************************************/
+
+const char *ppc32_rlwimi_emit_helper(const ir_node *n, ppc32_emit_env_t *env) {
+       rlwimi_const_t *rlwimi_const = get_ppc32_rlwimi_const(n);
+       snprintf(printbuf, SNPRINTF_BUF_LEN, "%i, %i, %i", rlwimi_const->shift,
+               rlwimi_const->maskA, rlwimi_const->maskB);
+       return printbuf;
+}
+
+
+/**
+ * Return a const or symconst as string.
+ */
+static const char *node_const_to_str(ir_node *n) {
+       const char *buf;
+       switch(get_ppc32_type(n))
+       {
+               case ppc32_ac_Const:
+                       tarval_snprintf(printbuf, SNPRINTF_BUF_LEN, get_ppc32_constant_tarval(n));
+                       buf=printbuf;
+                       break;
+               case ppc32_ac_SymConst:
+                       buf=get_id_str(get_ppc32_symconst_ident(n));
+                       break;
+               case ppc32_ac_Offset:
+                       snprintf(printbuf, SNPRINTF_BUF_LEN, "%i", get_ppc32_offset(n));
+                       return printbuf;
+               default:
+                       assert(0 && "node_const_to_str(): Illegal offset type");
+                       return 0;
+       }
+       switch(get_ppc32_offset_mode(n))
+       {
+               case ppc32_ao_None:
+                       return buf;
+               case ppc32_ao_Lo16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "lo16(%s)", buf);
+                       return printbuf2;
+               case ppc32_ao_Hi16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "hi16(%s)", buf);
+                       return printbuf2;
+               case ppc32_ao_Ha16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "ha16(%s)", buf);
+                       return printbuf2;
+               default:
+                       assert(0 && "node_const_to_str(): Illegal offset mode");
+                       return 0;
+       }
+}
+
+/**
+ * Returns node's offset as string.
+ */
+static const char *node_offset_to_str(ir_node *n) {
+       const char *buf;
+       if(get_ppc32_type(n)==ppc32_ac_None) return "0";
+       switch(get_ppc32_type(n))
+       {
+               case ppc32_ac_Const:
+                       tarval_snprintf(printbuf, SNPRINTF_BUF_LEN, get_ppc32_constant_tarval(n));
+                       buf=printbuf;
+                       break;
+               case ppc32_ac_SymConst:
+                       buf=get_id_str(get_ppc32_symconst_ident(n));
+                       break;
+               case ppc32_ac_Offset:
+                       snprintf(printbuf, SNPRINTF_BUF_LEN, "%i", get_ppc32_offset(n));
+                       return printbuf;
+               default:
+                       assert(0 && "node_offset_to_str(): Illegal offset type");
+                       return 0;
+       }
+       switch(get_ppc32_offset_mode(n))
+       {
+               case ppc32_ao_None:
+                       return buf;
+               case ppc32_ao_Lo16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "lo16(%s)", buf);
+                       return printbuf2;
+               case ppc32_ao_Hi16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "hi16(%s)", buf);
+                       return printbuf2;
+               case ppc32_ao_Ha16:
+                       snprintf(printbuf2, SNPRINTF_BUF_LEN, "ha16(%s)", buf);
+                       return printbuf2;
+               default:
+                       assert(0 && "node_offset_to_str(): Illegal offset mode");
+                       return 0;
+       }
+}
+
+/* We always pass the ir_node which is a pointer. */
+static int ppc32_get_arg_type(const lc_arg_occ_t *occ) {
+       return lc_arg_type_ptr;
+}
+
+
+/**
+ * Returns the register at in position pos.
+ */
+static const arch_register_t *get_in_reg(ir_node *irn, int pos) {
+       ir_node                *op;
+       const arch_register_t  *reg = NULL;
+
+       assert(get_irn_arity(irn) > pos && "Invalid IN position");
+
+       /* The out register of the operator at position pos is the
+          in register we need. */
+       op = get_irn_n(irn, pos);
+
+       reg = arch_get_irn_register(arch_env, op);
+
+       assert(reg && "no in register found");
+       return reg;
+}
+
+/**
+ * Returns the register at out position pos.
+ */
+static const arch_register_t *get_out_reg(ir_node *irn, int pos) {
+       ir_node                *proj;
+       const arch_register_t  *reg = NULL;
+
+       assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
+
+       /* 1st case: irn is not of mode_T, so it has only                 */
+       /*           one OUT register -> good                             */
+       /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
+       /*           Proj with the corresponding projnum for the register */
+
+       if (get_irn_mode(irn) != mode_T) {
+               reg = arch_get_irn_register(arch_env, irn);
+       }
+       else if (is_ppc32_irn(irn)) {
+               reg = get_ppc32_out_reg(irn, pos);
+       }
+       else {
+               const ir_edge_t *edge;
+
+               foreach_out_edge(irn, edge) {
+                       proj = get_edge_src_irn(edge);
+                       assert(is_Proj(proj) && "non-Proj from mode_T node");
+                       if (get_Proj_proj(proj) == pos) {
+                               reg = arch_get_irn_register(arch_env, proj);
+                               break;
+                       }
+               }
+       }
+
+       assert(reg && "no out register found");
+       return reg;
+}
+
+/**
+ * Returns the number of the in register at position pos.
+ */
+int get_ppc32_reg_nr(ir_node *irn, int pos, int in_out) {
+       const arch_register_t *reg;
+
+       if (in_out == 1) {
+               reg = get_in_reg(irn, pos);
+       }
+       else {
+               reg = get_out_reg(irn, pos);
+       }
+
+       return arch_register_get_index(reg);
+}
+
+/**
+ * Returns the name of the in register at position pos.
+ */
+const char *get_ppc32_reg_name(ir_node *irn, int pos, int in_out) {
+       const arch_register_t *reg;
+
+       if (in_out == 1) {
+               reg = get_in_reg(irn, pos);
+       }
+       else {
+               reg = get_out_reg(irn, pos);
+       }
+
+       return arch_register_get_name(reg);
+}
+
+/**
+ * Get the register name for a node.
+ */
+static int ppc32_get_reg_name(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       const char *buf;
+       ir_node    *X  = arg->v_ptr;
+       int         nr = occ->width - 1;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (occ->conversion == 'S') {
+               buf = get_ppc32_reg_name(X, nr, 1);
+       }
+       else { /* 'D' */
+               buf = get_ppc32_reg_name(X, nr, 0);
+       }
+
+//     lc_appendable_chadd(app, '%');
+       return lc_arg_append(app, occ, buf, strlen(buf));
+}
+
+/**
+ * Returns the tarval or offset of an ppc node as a string.
+ */
+static int ppc32_const_to_str(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       const char *buf;
+       ir_node    *X = arg->v_ptr;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (occ->conversion == 'C') {
+               buf = node_const_to_str(X);
+       }
+       else { /* 'O' */
+               buf = node_offset_to_str(X);
+       }
+
+       return lc_arg_append(app, occ, buf, strlen(buf));
+}
+
+/**
+ * Determines the SSE suffix depending on the mode.
+ */
+static int ppc32_get_mode_suffix(lc_appendable_t *app,
+    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
+{
+       ir_node *X = arg->v_ptr;
+
+       if (!X)
+               return lc_arg_append(app, occ, "(null)", 6);
+
+       if (get_mode_size_bits(get_irn_mode(X)) == 32)
+               return lc_appendable_chadd(app, 's');
+       else
+               return lc_appendable_chadd(app, 'd');
+}
+
+/**
+ * Return the ppc printf arg environment.
+ * We use the firm environment with some additional handlers.
+ */
+const lc_arg_env_t *ppc32_get_arg_env(void) {
+       static lc_arg_env_t *env = NULL;
+
+       static const lc_arg_handler_t ppc32_reg_handler   = { ppc32_get_arg_type, ppc32_get_reg_name };
+       static const lc_arg_handler_t ppc32_const_handler = { ppc32_get_arg_type, ppc32_const_to_str };
+       static const lc_arg_handler_t ppc32_mode_handler  = { ppc32_get_arg_type, ppc32_get_mode_suffix };
+
+       if(env == NULL) {
+               /* extend the firm printer */
+               env = firm_get_arg_env();
+                       //lc_arg_new_env();
+
+               lc_arg_register(env, "ppc:sreg", 'S', &ppc32_reg_handler);
+               lc_arg_register(env, "ppc:dreg", 'D', &ppc32_reg_handler);
+               lc_arg_register(env, "ppc:cnst", 'C', &ppc32_const_handler);
+               lc_arg_register(env, "ppc:offs", 'O', &ppc32_const_handler);
+               lc_arg_register(env, "ppc:mode", 'M', &ppc32_mode_handler);
+       }
+
+       return env;
+}
+
+/*
+ * Add a number to a prefix. This number will not be used a second time.
+ */
+static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
+       static unsigned long id = 0;
+       snprintf(buf, buflen, "%s%lu", prefix, ++id);
+       return buf;
+}
+
+
+/**
+ * Returns the target label for a control flow node.
+ */
+static char *get_cfop_target(const ir_node *irn, char *buf) {
+       ir_node *bl = get_irn_link(irn);
+
+       snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
+       return buf;
+}
+
+/**
+ * Emits code for a unconditional jump.
+ */
+static void emit_Jmp(const ir_node *irn, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       ir_node *block;
+
+       block = get_nodes_block(irn);
+       if(get_irn_link(irn) != get_irn_link(block))
+               ir_fprintf(F, "\tb %s\t\t\t/* Branch(%+F) */\n", get_cfop_target(irn, printbuf), get_irn_link(irn));
+       else
+               ir_fprintf(F, "\t\t\t\t\t\t/* fallthrough(%+F) */\n", get_irn_link(irn));
+}
+
+/**
+ * Emits code for a call
+ */
+static void emit_be_Call(const ir_node *irn, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       entity *call_ent = be_Call_get_entity(irn);
+
+       if(call_ent)
+       {
+               ir_fprintf(F, "\tbl      %s\t\t\t/* Branch and link(%+F) */\n", get_entity_name(call_ent), irn);
+       }
+       else
+       {
+               ir_node *node = get_irn_n(irn, be_pos_Call_ptr);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmtlr %1D\t\t\t/* Move to link register */\n", node);
+               ir_fprintf(F, "\tblrl\t\t\t/* Branch to link register and link(%+F) */\n", irn);
+       }
+}
+
+char *branchops[8] = { 0, "beq", "blt", "ble", "bgt", "bge", "bne", "b" };
+
+static void emit_ppc32_Branch(const ir_node *n, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       int projnum = get_ppc32_proj_nr(n);
+
+       const ir_edge_t *edge = get_irn_out_edge_first(n);
+       ir_node *proj = get_edge_src_irn(edge);
+
+       int opind;
+
+       if(get_Proj_proj(proj) == pn_Cond_true)
+               opind = projnum;
+       else
+               opind = 7-projnum;
+
+       assert(opind>=0 && opind<8);
+
+       if(opind)
+       {
+               get_cfop_target(proj, printbuf);
+               lc_efprintf(ppc32_get_arg_env(), F, "\t%-8s%1S, %s\t\t\t/* Branch(%1S) to %s */\n",
+                       branchops[opind], n, printbuf, n, printbuf);
+       }
+
+       edge = get_irn_out_edge_next(n, edge);
+
+       if(edge)
+       {
+               ir_node *irn = get_edge_src_irn(edge);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tb       %s\t\t\t/* Branch(%+F) */\n",
+                       get_cfop_target(irn, printbuf), get_irn_link(irn));
+       }
+}
+
+static void emit_ppc32_LoopCopy(const ir_node *n, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       fprintf(F, "LOOP_%ld:\n", get_irn_node_nr(n));
+       lc_efprintf(ppc32_get_arg_env(), F, "\tlwzu    %5D, 4(%2S)\t\t\t/* Load with update */\n",n,n);
+       lc_efprintf(ppc32_get_arg_env(), F, "\tstwu    %5D, 4(%3S)\t\t\t/* Store with update */\n",n,n);
+       lc_efprintf(ppc32_get_arg_env(), F, "\tbdnz    LOOP_%i\t\t\t/* Branch with decrement if CTR != 0 */\n",
+               get_irn_node_nr(n));
+}
+
+static void emit_ppc32_Switch(const ir_node *n, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       ir_node *proj,*defproj=NULL;
+       int pn;
+
+       const ir_edge_t* edge;
+       foreach_out_edge(n, edge) {
+               proj = get_edge_src_irn(edge);
+               assert(is_Proj(proj) && "Only proj allowed at Switch");
+               if(get_irn_mode(proj) != mode_X) continue;
+
+               pn = get_Proj_proj(proj);
+               /* check for default proj */
+               if (pn == get_ppc32_proj_nr(n)) {
+                       assert(defproj == NULL && "found two defProjs at Switch");
+                       defproj = proj;
+               }
+               else
+               {
+
+                       lc_efprintf(ppc32_get_arg_env(), F, "\taddis   %2S, 0, hi16(%i)\t\t\t/* Load upper immediate */\n",n,pn);
+                       lc_efprintf(ppc32_get_arg_env(), F, "\tori     %2S, %2S, lo16(%i)\t\t\t/* Load lower immediate */\n",n,n,pn);
+                       lc_efprintf(ppc32_get_arg_env(), F, "\tcmp     %3S, %1S, %2S\t\t\t/* Compare */\n",n,n,n);
+                       lc_efprintf(ppc32_get_arg_env(), F, "\tbeq     %3S, %s\t\t\t/* Branch if equal */\n",
+                               n,get_cfop_target(proj, printbuf));
+               }
+       }
+       assert(defproj != NULL && "didn't find defProj at Switch");
+       lc_efprintf(ppc32_get_arg_env(), F, "\tb       %s\t\t\t/* Default case */\n", get_cfop_target(defproj, printbuf));
+}
+
+/**
+ * Emits code for a backend Copy node
+ */
+static void emit_be_Copy(const ir_node *n, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       const arch_register_class_t *regclass = arch_get_irn_reg_class(env->arch_env, n, 0);
+
+       if (regclass == &ppc32_reg_classes[CLASS_ppc32_general_purpose])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmr      %1D, %1S\t\t\t/* Move register */\n",n,n);
+       }
+       else if (regclass == &ppc32_reg_classes[CLASS_ppc32_floating_point])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\tfmr     %1D, %1S\t\t\t/* Move register */\n",n,n);
+       }
+       else if (regclass == &ppc32_reg_classes[CLASS_ppc32_condition])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmcrf    %1D, %1S\t\t\t/* Move register */\n",n,n);
+       }
+       else assert(0 && "Illegal register class for Copy");
+}
+
+/**
+ * Emits code for a backend Perm node
+ */
+static void emit_be_Perm(const ir_node *n, ppc32_emit_env_t *env) {
+       FILE *F = env->out;
+       const arch_register_class_t *regclass = arch_get_irn_reg_class(env->arch_env, n, 0);
+
+       if (regclass == &ppc32_reg_classes[CLASS_ppc32_general_purpose])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\txor     %1S, %1S, %2S\t\t\t/* Swap %1S, %2S with XOR */\n",n,n,n,n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\txor     %2S, %1S, %2S\t\t\t/* (continued) */\n",n,n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\txor     %1S, %1S, %2S\t\t\t/* (continued) */\n",n,n,n);
+       }
+       else if (regclass == &ppc32_reg_classes[CLASS_ppc32_floating_point])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\tfmr     f0, %1S\t\t\t/* Swap %1S, %2S with moves */\n",n,n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tfmr     %1S, %2S\t\t\t/* (continued) */\n",n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tfmr     %2S, f0\t\t\t/* (continued) */\n",n);
+       }
+       else if (regclass == &ppc32_reg_classes[CLASS_ppc32_condition])
+       {
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmcrf    cr7, %1S\t\t\t/* Swap %1S, %2S with moves */\n",n,n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmcrf    %1S, %2S\t\t\t/* (continued) */\n",n,n);
+               lc_efprintf(ppc32_get_arg_env(), F, "\tmcrf    %2S, cr7\t\t\t/* (continued) */\n",n);
+       }
+       else assert(0 && "Illegal register class for Perm");
+
+}
+
+
+/**
+ * Emits code for a proj -> node
+ */
+static void emit_Proj(const ir_node *irn, ppc32_emit_env_t *env) {
+       ir_node *pred = get_Proj_pred(irn);
+
+       if (get_irn_op(pred) == op_Start) {
+               switch(get_Proj_proj(irn)) {
+                       case pn_Start_X_initial_exec:
+                               emit_Jmp(irn, env);
+                               break;
+                       default:
+                               break;
+               }
+       }
+}
+
+static void emit_be_IncSP(const ir_node *irn, ppc32_emit_env_t *emit_env) {
+       FILE          *F    = emit_env->out;
+       unsigned       offs = be_get_IncSP_offset(irn);
+       be_stack_dir_t dir  = be_get_IncSP_direction(irn);
+
+       fprintf(F, "\t\t\t\t\t/* ignored IncSP with %c%i */\n", dir==be_stack_dir_expand ? '-' : ' ', offs);
+
+//     if (offs) {
+//             assert(offs<=0x7fff);
+//             lc_efprintf(ppc32_get_arg_env(), F, "\taddi    %1S, %1S,%s%u\t\t\t/* %+F (IncSP) */\n", irn, irn,
+//                     (dir == be_stack_dir_expand) ? " -" : " ", offs, irn);
+//     }
+//     else {
+//             fprintf(F, "\t\t\t\t\t/* omitted IncSP with 0 */\n");
+//     }
+}
+
+/*static void emit_Spill(const ir_node *irn, ppc32_emit_env_t *emit_env) {
+       ir_node *context = be_get_Spill_context(irn);
+       entity *entity = be_get_spill_entity(irn);
+}*/
+
+/***********************************************************************************
+ *                  _          __                                             _
+ *                 (_)        / _|                                           | |
+ *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
+ * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
+ * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
+ * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
+ *
+ ***********************************************************************************/
+
+static void ppc32_register_emitters(void) {
+       /* first clear generic function pointers */
+       clear_irp_opcodes_generic_func();
+
+       /* register generated emitter functions */
+       ppc32_register_spec_emitters();
+
+#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a
+
+       EMIT(ppc32_Branch);
+       EMIT(ppc32_LoopCopy);
+       EMIT(ppc32_Switch);
+       EMIT(be_Call);
+       EMIT(Jmp);
+       EMIT(Proj);
+       EMIT(be_IncSP);
+       EMIT(be_Copy);
+       EMIT(be_Perm);
+//     EMIT(Spill);
+//     EMIT(Reload);
+}
+
+/**
+ * Emits code for a node.
+ */
+static void ppc32_emit_node(ir_node *irn, void *env) {
+       ppc32_emit_env_t *emit_env   = env;
+       firm_dbg_module_t *mod = emit_env->mod;
+       FILE              *F   = emit_env->out;
+       ir_op             *op = get_irn_op(irn);
+
+       DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
+
+       if (op->ops.generic) {
+           void (*emit)(ir_node *, void *) = (void (*)(ir_node *, void *))op->ops.generic;
+               (*emit)(irn, env);
+       }
+       else {
+               ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
+       }
+}
+
+
+/**
+ * Walks over the nodes in a block connected by scheduling edges
+ * and emits code for each node.
+ */
+static void ppc32_gen_block(ir_node *block, void *env) {
+       ir_node *irn;
+
+       if (! is_Block(block))
+               return;
+
+       fprintf(((ppc32_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
+       sched_foreach(block, irn) {
+               ppc32_emit_node(irn, env);
+       }
+}
+
+
+/**
+ * Emits code for function start.
+ */
+void ppc32_emit_start(FILE *F, ir_graph *irg, ppc32_emit_env_t *env) {
+       const char *irg_name = get_entity_ld_name(get_irg_entity(irg));
+       int framesize = get_type_size_bytes(get_irg_frame_type(env->cg->irg));
+
+       if(!strcmp(irg_name, "main"))                                              // XXX: underscore hack
+       {
+               fprintf(F, "\t.text\n");
+               fprintf(F, "\t.globl _main\n", irg_name);
+               fprintf(F, "\t.align 4\n");
+               fprintf(F, "_main:\n", irg_name);
+       }
+       else
+       {
+               fprintf(F, "\t.text\n");
+               fprintf(F, "\t.globl %s\n", irg_name);
+               fprintf(F, "\t.align 4\n");
+               fprintf(F, "%s:\n", irg_name);
+       }
+
+       if(framesize>24)
+       {
+               fprintf(F, "\tmflr    r0\n");
+               fprintf(F, "\tstw     r0, 8(r1)\n");
+               fprintf(F, "\tstwu    r1, -%i(r1)\n", framesize);
+       }
+       else
+       {
+               fprintf(F, "\t\t\t\t\t/* set new frame omitted */\n", framesize);
+       }
+
+
+/*     if(!isleaf)
+       {
+               // store link register in linkage area (TODO: if needed)
+
+               fprintf(F, "\tmflr    r0\n");
+               fprintf(F, "\tstwu    r0, -4(r1)\n");   // stw r0, 8(SP)
+       }*/
+}
+
+/**
+ * Emits code for function end
+ */
+void ppc32_emit_end(FILE *F, ir_graph *irg, ppc32_emit_env_t *env) {
+       const char *irg_name = get_entity_ld_name(get_irg_entity(irg));
+       int framesize = get_type_size_bytes(get_irg_frame_type(env->cg->irg));
+
+/*     if(!isleaf)
+       {
+               // restore link register
+
+               fprintf(F, "\tlwz     r0, 0(r1)\n");
+               fprintf(F, "\taddi    r1, r1, 4\n");
+               fprintf(F, "\tmtlr    r0\n");
+       }*/
+       if(framesize>24)
+       {
+               fprintf(F, "\tlwz     r1, 0(r1)\n");
+               fprintf(F, "\tlwz     r0, 8(r1)\n");
+               fprintf(F, "\tmtlr    r0\n");
+       }
+       fprintf(F, "\tblr\n\n");
+}
+
+/**
+ * Sets labels for control flow nodes (jump target)
+ * TODO: Jump optimization
+ */
+void ppc32_gen_labels(ir_node *block, void *env) {
+       ir_node *pred;
+       int n;
+
+       for (n = get_Block_n_cfgpreds(block) - 1; n >= 0; --n) {
+               pred = get_Block_cfgpred(block, n);
+               set_irn_link(pred, block);
+       }
+}
+
+/**
+ * Main driver: generates code for one routine
+ */
+void ppc32_gen_routine(FILE *F, ir_graph *irg, const ppc32_code_gen_t *cg) {
+       ppc32_emit_env_t emit_env;
+       ir_node *block;
+       int i, n;
+
+       emit_env.mod      = firm_dbg_register("firm.be.ppc.emit");
+       emit_env.out      = F;
+       emit_env.arch_env = cg->arch_env;
+       emit_env.cg       = cg;
+
+       /* set the global arch_env (needed by print hooks) */
+       arch_env = cg->arch_env;
+
+       ppc32_register_emitters();
+
+       ppc32_emit_start(F, irg, &emit_env);
+       irg_block_walk_graph(irg, ppc32_gen_labels, NULL, &emit_env);
+
+       n = ARR_LEN(cg->blk_sched);
+       for (i = 0; i < n;) {
+               ir_node *next_bl;
+
+               block   = cg->blk_sched[i];
+               ++i;
+               next_bl = i < n ? cg->blk_sched[i] : NULL;
+
+               /* set here the link. the emitter expects to find the next block here */
+               set_irn_link(block, next_bl);
+               ppc32_gen_block(block, &emit_env);
+       }
+       ppc32_emit_end(F, irg, &emit_env);
+}
diff --git a/ir/be/ppc32/ppc32_emitter.h b/ir/be/ppc32/ppc32_emitter.h
new file mode 100644 (file)
index 0000000..1074480
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _PPC32_EMITTER_H_
+#define _PPC32_EMITTER_H_
+
+#include "irargs_t.h"  // this also inlucdes <libcore/lc_print.h>
+#include "irnode.h"
+#include "debug.h"
+
+#include "../bearch.h"
+
+#include "bearch_ppc32_t.h"
+
+typedef struct _emit_env_t {
+       firm_dbg_module_t         *mod;
+       FILE                      *out;
+       const arch_env_t          *arch_env;
+       const ppc32_code_gen_t    *cg;
+} ppc32_emit_env_t;
+
+const lc_arg_env_t *ppc32_get_arg_env(void);
+
+void equalize_dest_src(FILE *F, ir_node *n);
+
+int get_ppc32_reg_nr(ir_node *irn, int posi, int in_out);
+const char *get_ppc32_in_reg_name(ir_node *irn, int pos);
+
+void ppc32_gen_routine(FILE *F, ir_graph *irg, const ppc32_code_gen_t *cg);
+
+const char *ppc32_rlwimi_emit_helper(const ir_node *n, ppc32_emit_env_t *env);
+
+
+#endif /* _PPC32_EMITTER_H_ */
diff --git a/ir/be/ppc32/ppc32_gen_decls.c b/ir/be/ppc32/ppc32_gen_decls.c
new file mode 100644 (file)
index 0000000..f53fbfe
--- /dev/null
@@ -0,0 +1,626 @@
+/**
+ * Dumps global variables and constants as ppc assembler.
+ * @date 14.02.2006
+ * @version $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "xmalloc.h"
+#include <obstack.h>
+
+#ifdef obstack_chunk_alloc
+# undef obstack_chunk_alloc
+# define obstack_chunk_alloc xmalloc
+#else
+# define obstack_chunk_alloc xmalloc
+# define obstack_chunk_free free
+#endif
+
+extern int obstack_printf(struct obstack *obst, char *fmt, ...);
+
+#include "tv.h"
+#include "irnode.h"
+#include "entity.h"
+#include "irprog.h"
+#include "pset.h"
+
+#include "ppc32_gen_decls.h"
+
+extern pset *symbol_pset;
+
+/************************************************************************/
+
+/*
+ * returns the highest bit value
+ */
+static unsigned highest_bit(unsigned v)
+{
+  int res = -1;
+
+  if (v >= (1U << 16U)) {
+    res += 16;
+    v >>= 16;
+  }
+  if (v >= (1U << 8U)) {
+    res += 8;
+    v >>= 8;
+  }
+  if (v >= (1U << 4U)) {
+    res += 4;
+    v >>= 4;
+  }
+  if (v >= (1U << 2U)) {
+    res += 2;
+    v >>= 2;
+  }
+  if (v >= (1U << 1U)) {
+    res += 1;
+    v >>= 1;
+  }
+  if (v >= 1)
+    res += 1;
+
+  return res;
+}
+
+/*
+ * output the alignment
+ */
+static void ppc32_dump_align(struct obstack *obst, int align)
+{
+  int h = highest_bit(align);
+
+  if ((1 << h) < align)
+    ++h;
+  align = (1 << h);
+
+  if (align > 1)
+    obstack_printf(obst, "\t.align %d\n", align);
+}
+
+static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
+{
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 2:
+    obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 4:
+    obstack_printf(obst, "0x%02x%02x%02x%02x",
+       get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 8:
+    obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
+       get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4),
+       get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0));
+    break;
+
+  case 10:
+  case 12:
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+}
+
+/*
+ * dump an arithmetic tarval
+ */
+static void ppc32_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes)
+{
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "\t.byte\t");
+    break;
+
+  case 2:
+    obstack_printf(obst, "\t.value\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.long\t");
+    break;
+
+  case 8:
+    obstack_printf(obst, "\t.quad\t");
+    break;
+
+  case 10:
+  case 12:
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+  dump_arith_tarval(obst, tv, bytes);
+}
+
+
+/*
+ * dump an atomic value
+ */
+static void do_dump_atomic_init(struct obstack *obst, ir_node *init)
+{
+  ir_mode *mode = get_irn_mode(init);
+  int bytes     = get_mode_size_bytes(mode);
+  tarval *tv;
+
+  switch (get_irn_opcode(init)) {
+
+  case iro_Cast:
+    do_dump_atomic_init(obst, get_Cast_op(init));
+    return;
+
+  case iro_Conv:
+    do_dump_atomic_init(obst, get_Conv_op(init));
+    return;
+
+  case iro_Const:
+    tv = get_Const_tarval(init);
+
+    /* beware of old stuff */
+    assert(! mode_is_reference(mode));
+
+    /* it's a arithmetic value */
+    dump_arith_tarval(obst, tv, bytes);
+    return;
+
+  case iro_SymConst:
+    switch (get_SymConst_kind(init)) {
+    case symconst_addr_name:
+      obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init)));
+      break;
+
+    case symconst_addr_ent:
+      obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init)));
+      break;
+
+    case symconst_size:
+      obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init)));
+      break;
+
+    default:
+      assert(0 && "dump_atomic_init(): don't know how to init from this SymConst");
+    }
+    return;
+
+  case iro_Add:
+    do_dump_atomic_init(obst, get_Add_left(init));
+    obstack_printf(obst, " + ");
+    do_dump_atomic_init(obst, get_Add_right(init));
+    return;
+
+  case iro_Sub:
+    do_dump_atomic_init(obst, get_Sub_left(init));
+    obstack_printf(obst, " - ");
+    do_dump_atomic_init(obst, get_Sub_right(init));
+    return;
+
+  case iro_Mul:
+    do_dump_atomic_init(obst, get_Mul_left(init));
+    obstack_printf(obst, " * ");
+    do_dump_atomic_init(obst, get_Mul_right(init));
+    return;
+
+  default:
+    assert(0 && "dump_atomic_init(): unknown IR-node");
+  }
+}
+
+/*
+ * dump an atomic value
+ */
+static void dump_atomic_init(struct obstack *obst, ir_node *init)
+{
+  ir_mode *mode = get_irn_mode(init);
+  int bytes     = get_mode_size_bytes(mode);
+
+  switch (bytes) {
+
+  case 1:
+    obstack_printf(obst, "\t.byte\t");
+    break;
+
+  case 2:
+    obstack_printf(obst, "\t.value\t");
+    break;
+
+  case 4:
+    obstack_printf(obst, "\t.long\t");
+    break;
+
+  case 8:
+    obstack_printf(obst, "\t.quad\t");
+    break;
+
+  case 10:
+  case 12:
+    /* handled in arith */
+    break;
+
+  default:
+    fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes);
+    assert(0);
+  }
+
+  do_dump_atomic_init(obst, init);
+  obstack_printf(obst, "\n");
+}
+
+/************************************************************************/
+/* Routines to dump global variables                                    */
+/************************************************************************/
+
+/**
+ * Determine if an entity is a string constant
+ * @param ent The entity
+ * @return 1 if it is a string constant, 0 otherwise
+ */
+static int ent_is_string_const(entity *ent)
+{
+  int res = 0;
+  ir_type *ty;
+
+  ty = get_entity_type(ent);
+
+  /* if it's an array */
+  if (is_Array_type(ty)) {
+    ir_type *elm_ty = get_array_element_type(ty);
+
+    /* and the array's element type is primitive */
+    if (is_Primitive_type(elm_ty)) {
+      ir_mode *mode = get_type_mode(elm_ty);
+
+      /*
+       * and the mode of the element type is an int of
+       * the same size as the byte mode
+       */
+      if (mode_is_int(mode)
+        && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs))
+      {
+       int i, c, n;
+
+       n = get_compound_ent_n_values(ent);
+       for (i = 0; i < n; ++i) {
+         ir_node *irn = get_compound_ent_value(ent, i);
+         if(get_irn_opcode(irn) != iro_Const)
+           return 0;
+
+         c = (int) get_tarval_long(get_Const_tarval(irn));
+
+         if((i < n - 1 && !(isgraph(c) || isspace(c)))
+            || (i == n - 1 && c != '\0'))
+           return 0;
+       }
+
+       res = 1;
+      }
+    }
+  }
+
+  return res;
+}
+
+/**
+ * Dump a atring constant.
+ * No checks are made!!
+ * @param obst The obst to dump on.
+ * @param ent The entity to dump.
+ */
+static void dump_string_cst(struct obstack *obst, entity *ent)
+{
+  int i, n;
+
+  obstack_printf(obst, "\t.asciz \"");
+  n = get_compound_ent_n_values(ent);
+
+  for (i = 0; i < n-1; ++i) {
+    ir_node *irn;
+    int c;
+
+    irn = get_compound_ent_value(ent, i);
+    c = (int) get_tarval_long(get_Const_tarval(irn));
+
+    switch (c) {
+    case '"' : obstack_printf(obst, "\\\""); break;
+    case '\n': obstack_printf(obst, "\\n"); break;
+    case '\r': obstack_printf(obst, "\\r"); break;
+    case '\t': obstack_printf(obst, "\\t"); break;
+    default  :
+      if (isprint(c))
+       obstack_printf(obst, "%c", c);
+      else
+       obstack_printf(obst, "%O", c);
+      break;
+    }
+  }
+  obstack_printf(obst, "\"\n");
+}
+
+struct arr_info {
+  int n_elems;
+  int visit_cnt;
+  int size;
+};
+
+/*
+ * Dumps the initialization of global variables that are not
+ * "uninitialized".
+ */
+static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, entity *ent)
+{
+  ir_type *ty         = get_entity_type(ent);
+  const char *ld_name = get_entity_ld_name(ent);
+  int align; //, h;
+  struct obstack *obst = data_obstack;
+
+  /*
+   * FIXME: did NOT work for partly constant values
+   */
+  if (! is_Method_type(ty)) {
+    ent_variability variability = get_entity_variability(ent);
+    visibility visibility = get_entity_visibility(ent);
+
+    if (variability == variability_constant) {
+      /* a constant entity, put it on the rdata */
+      obst = rdata_obstack;
+    }
+
+    /* check, whether it is initialized, if yes create data */
+    if (variability != variability_uninitialized) {
+      if (visibility == visibility_external_visible) {
+        obstack_printf(obst, ".globl\t%s\n", ld_name);
+      }
+//      obstack_printf(obst, "\t.type\t%s,@object\n", ld_name);
+//      obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
+
+      align = get_type_alignment_bytes(ty);
+      ppc32_dump_align(obst, align);
+
+      obstack_printf(obst, "%s:\n", ld_name);
+
+      if (is_atomic_type(ty)) {
+       if (get_entity_visibility(ent) != visibility_external_allocated)
+          dump_atomic_init(obst, get_atomic_ent_value(ent));
+      }
+      else {
+       int i, size = 0;
+
+       if (ent_is_string_const(ent)) {
+         dump_string_cst(obst, ent);
+       }
+       else if (is_Array_type(ty)) {
+          int filler;
+
+          /* potential spare values should be already included! */
+                 for (i = 0; i < get_compound_ent_n_values(ent); ++i) {
+            entity *step = get_compound_ent_value_member(ent, i);
+            ir_type *stype = get_entity_type(step);
+
+            if (get_type_mode(stype)) {
+              int align = (get_type_alignment_bits(stype) + 7) >> 3;
+              int n     = size % align;
+
+              if (n > 0) {
+                obstack_printf(obst, "\t.zero\t%d\n", align - n);
+                size += align - n;
+              }
+            }
+            dump_atomic_init(obst, get_compound_ent_value(ent, i));
+            size += get_type_size_bytes(stype);
+         }
+          filler = get_type_size_bytes(ty) - size;
+
+          if (filler > 0)
+            obstack_printf(obst, "\t.zero\t%d\n", filler);
+        }
+        else if (is_compound_type(ty)) {
+          ir_node **vals;
+          int type_size, j;
+
+          /* Compound entities are NOT sorted.
+           * The sorting strategy used doesn't work for `value' compound fields nor
+           * for partially_constant entities.
+           */
+
+          /*
+           * in the worst case, every entity allocates one byte, so the type
+           * size should be equal or bigger the number of fields
+           */
+          type_size = get_type_size_bytes(ty);
+          vals      = xcalloc(type_size, sizeof(*vals));
+
+          /* collect the values and store them at the offsets */
+          for(i = 0; i < get_compound_ent_n_values(ent); ++i) {
+            int                 graph_length, aipos, offset;
+            struct arr_info     *ai;
+            int                 all_n = 1;
+            compound_graph_path *path = get_compound_ent_value_path(ent, i);
+
+            /* get the access path to the costant value */
+            graph_length = get_compound_graph_path_length(path);
+            ai = xcalloc(graph_length, sizeof(struct arr_info));
+
+            /* We wanna know how many arrays are on the path to the entity. We also have to know how
+             * many elements each array holds to calculate the offset for the entity. */
+            for (j = 0; j < graph_length; j++) {
+              entity  *step      = get_compound_graph_path_node(path, j);
+              ir_type *step_type = get_entity_type(step);
+              int     ty_size    = (get_type_size_bits(step_type) + 7) >> 3;
+              int     k, n       = 0;
+
+              if (is_Array_type(step_type))
+                for (k = 0; k < get_array_n_dimensions(step_type); k++)
+                  n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k)));
+              if (n) all_n *= n;
+              ai[j].n_elems = n ? all_n + 1 : 0;
+              ai[j].visit_cnt = 0;
+              ai[j].size = ty_size;
+            }
+
+            aipos = graph_length - 1;
+            if (aipos) aipos--;
+
+            for (offset = j = 0; j < graph_length; j++) {
+              entity *step       = get_compound_graph_path_node(path, j);
+              ir_type *step_type = get_entity_type(step);
+              int ent_ofs        = get_entity_offset_bytes(step);
+              int stepsize       = 0;
+
+              /* add all positive offsets (= offsets in structs) */
+              if (ent_ofs >= 0) offset += ent_ofs;
+
+              if (j == graph_length - 1) {
+                stepsize = (get_type_size_bits(step_type) + 7) >> 3;
+
+                /* Search the next free position in vals depending on the information from above (ai). */
+                while (vals[offset]) {
+                  if (ai[aipos].visit_cnt < ai[aipos].n_elems) {
+                    offset += stepsize;
+                    ai[aipos].visit_cnt++;
+                  }
+                  else
+                    while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) {
+                      stepsize = ai[aipos--].size;
+                      offset  += stepsize;
+                  }
+                }
+
+                assert(aipos >= 0 && "couldn't store entity");
+                vals[offset] = get_compound_ent_value(ent, i);
+              }
+            }
+
+            free(ai);
+          }
+
+          /* now write them sorted */
+          for(i = 0; i < type_size; ) {
+            if (vals[i]) {
+              dump_atomic_init(obst, vals[i]);
+              i += (get_mode_size_bytes(get_irn_mode(vals[i])));
+            }
+            else {
+              /* a gap */
+              obstack_printf(obst, "\t.byte\t0\n");
+              ++i;
+            }
+          }
+          free(vals);
+        }
+        else {
+          assert(0 && "unsupported type");
+        }
+      }
+      obstack_printf(obst, "\n");
+    }
+    else if (visibility != visibility_external_allocated) {
+      if (visibility == visibility_local) {
+        obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name);
+      }
+
+      /* calculate the alignment */
+/*      align = get_type_alignment_bytes(ty);
+      h = highest_bit(align);
+
+      if ((1 << h) < align)
+       ++h;
+      align = (1 << h);
+
+      if (align < 1)
+       align = 1;
+
+      obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align);*/
+      obstack_printf(comm_obstack, "\t.comm\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3);
+    }
+  }
+}
+
+/*
+ * Dumps declarations of global variables and the initialization code.
+ */
+void ppc32_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack)
+{
+  ir_type *gt = get_glob_type();
+  int i, n = get_class_n_members(gt);
+
+  for (i = 0; i < n; i++)
+    dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i));
+}
+
+void ppc32_dump_indirect_symbols(struct obstack *isyms)
+{
+       entity *ent;
+       for(ent=pset_first(symbol_pset); ent; ent=pset_next(symbol_pset))
+       {
+               const char *ld_name = get_entity_ld_name(ent);
+               obstack_printf(isyms, ".non_lazy_symbol_pointer\n%s:\n\t.indirect_symbol _%s\n\t.long 0\n\n",ld_name,ld_name);
+       }
+}
+
+/************************************************************************/
+
+void ppc32_gen_decls(FILE *out) {
+  struct obstack rodata, data, comm, isyms;
+  int    size;
+  char   *cp;
+
+  obstack_init(&rodata);
+  obstack_init(&data);
+  obstack_init(&comm);
+
+  ppc32_dump_globals(&rodata, &data, &comm);
+
+  size = obstack_object_size(&data);
+  cp   = obstack_finish(&data);
+  if (size > 0) {
+    fprintf(out, "\t.data\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  size = obstack_object_size(&rodata);
+  cp   = obstack_finish(&rodata);
+  if (size > 0) {
+    fprintf(out, "\t.const_data\n");
+    fwrite(cp, 1, size, out);
+  }
+
+  size = obstack_object_size(&comm);
+  cp   = obstack_finish(&comm);
+  if (size > 0) {
+//    fprintf(out, "\t.common\n");
+    fwrite(cp, 1, size, out);
+    fprintf(out, "\n");
+  }
+
+  obstack_free(&rodata, NULL);
+  obstack_free(&data, NULL);
+  obstack_free(&comm, NULL);
+
+  obstack_init(&isyms);
+
+  ppc32_dump_indirect_symbols(&isyms);
+
+  size = obstack_object_size(&isyms);
+  cp   = obstack_finish(&isyms);
+  if (size > 0) {
+         fprintf(out, "\t.data\n");
+         fwrite(cp, 1, size, out);
+  }
+
+  obstack_free(&isyms,NULL);
+}
diff --git a/ir/be/ppc32/ppc32_gen_decls.h b/ir/be/ppc32/ppc32_gen_decls.h
new file mode 100644 (file)
index 0000000..ab1695a
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _PPC32_GEN_DECLS_H_
+#define _PPC32_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void ppc32_gen_decls(FILE *out);
+
+#endif /* _PPC32_GEN_DECLS_H_ */
diff --git a/ir/be/ppc32/ppc32_map_regs.c b/ir/be/ppc32/ppc32_map_regs.c
new file mode 100644 (file)
index 0000000..6fd6afd
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * Register mapping for firm nodes. Stolen from bearch_firm :)
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "ppc32_map_regs.h"
+#include "ppc32_new_nodes.h"
+
+/* Mapping to store registers in firm nodes */
+
+struct ppc32_irn_reg_assoc {
+       const ir_node *irn;
+       const arch_register_t *reg;
+};
+
+int ppc32_cmp_irn_reg_assoc(const void *a, const void *b, size_t len) {
+       const struct ppc32_irn_reg_assoc *x = a;
+       const struct ppc32_irn_reg_assoc *y = b;
+
+       return x->irn != y->irn;
+}
+
+static struct ppc32_irn_reg_assoc *get_irn_reg_assoc(const ir_node *irn, set *reg_set) {
+       struct ppc32_irn_reg_assoc templ;
+       unsigned int hash;
+
+       templ.irn = irn;
+       templ.reg = NULL;
+       hash = HASH_PTR(irn);
+
+       return set_insert(reg_set, &templ, sizeof(templ), hash);
+}
+
+void ppc32_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set) {
+       struct ppc32_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+       assoc->reg = reg;
+}
+
+const arch_register_t *ppc32_get_firm_reg(const ir_node *irn, set *reg_set) {
+       struct ppc32_irn_reg_assoc *assoc = get_irn_reg_assoc(irn, reg_set);
+       return assoc->reg;
+}
+
+
+int is_ppc32_Load(const ir_node *n)
+{
+       ir_op *op = get_irn_op(n);
+       if(op == op_ppc32_Lbz) return 1;
+       if(op == op_ppc32_Lhz) return 1;
+       if(op == op_ppc32_Lha) return 1;
+       if(op == op_ppc32_Lwz) return 1;
+       if(op == op_ppc32_Lfd) return 1;
+       if(op == op_ppc32_Lfs) return 1;
+
+       return 0;
+}
+
+int is_ppc32_Store(const ir_node *n)
+{
+       ir_op *op = get_irn_op(n);
+       if(op == op_ppc32_Stb) return 1;
+       if(op == op_ppc32_Sth) return 1;
+       if(op == op_ppc32_Stw) return 1;
+       if(op == op_ppc32_Stfd) return 1;
+       if(op == op_ppc32_Stfs) return 1;
+
+       return 0;
+}
+
+
+/**
+ * Translates the projnum into a "real" argument position for register
+ * requirements dependend on the predecessor.
+ */
+long ppc32_translate_proj_pos(const ir_node *proj) {
+       ir_node *pred = get_Proj_pred(proj);
+       long nr       = get_Proj_proj(proj);
+
+
+       if (is_ppc32_Load(pred)) {
+               if (nr == pn_Load_res)
+                       return 0;
+               assert(0 && "unsupported Proj(Load) number");
+       }
+       else if (is_ppc32_Store(pred)) {
+               return 0;
+       }
+       else if (is_ppc32_fDiv(pred)) {
+               if (nr == pn_Quot_res)
+                       return 0;
+               else
+                       assert(0 && "there should be no more Projs for a fDiv");
+       }
+       else if (is_ppc32_Divw(pred) || is_ppc32_Divwu(pred)) {
+               if (nr == pn_DivMod_res_div)
+                       return 0;
+               else
+                       assert(0 && "there should be no more Projs for a ppc32_Divw or ppc32_Divwu");
+       }
+
+       else if(is_ppc32_Cmp(pred))
+               return 0;
+       else if(is_ppc32_Cmpi(pred))
+               return 0;
+       else if(is_ppc32_Cmpl(pred))
+               return 0;
+       else if(is_ppc32_Cmpli(pred))
+               return 0;
+
+
+
+//     assert(0 && "unsupported Proj(X)");
+       return nr;
+}
diff --git a/ir/be/ppc32/ppc32_map_regs.h b/ir/be/ppc32/ppc32_map_regs.h
new file mode 100644 (file)
index 0000000..28cd252
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PPC32_MAP_REGS_H_
+#define _PPC32_MAP_REGS_H_
+
+#include "irnode.h"
+#include "set.h"
+
+#include "../bearch.h"
+#include "ppc32_nodes_attr.h"
+
+int  ppc32_cmp_irn_reg_assoc(const void *a, const void *b, size_t len);
+void ppc32_set_firm_reg(ir_node *irn, const arch_register_t *reg, set *reg_set);
+const arch_register_t *ppc32_get_firm_reg(const ir_node *irn, set *reg_set);
+
+long ppc32_translate_proj_pos(const ir_node *proj);
+
+#endif /* _PPC32_MAP_REGS_H_ */
diff --git a/ir/be/ppc32/ppc32_new_nodes.c b/ir/be/ppc32/ppc32_new_nodes.c
new file mode 100644 (file)
index 0000000..bf3a475
--- /dev/null
@@ -0,0 +1,561 @@
+/**
+ * This file implements the creation of the achitecture specific firm opcodes
+ * and the coresponding node constructors for the ppc assembler irg.
+ * $Id$
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+#include <stdlib.h>
+
+#include "irprog_t.h"
+#include "irgraph_t.h"
+#include "irnode_t.h"
+#include "irmode_t.h"
+#include "ircons_t.h"
+#include "iropt_t.h"
+#include "irop.h"
+#include "firm_common_t.h"
+#include "irvrfy_t.h"
+#include "irprintf.h"
+
+#include "../bearch.h"
+
+#include "ppc32_nodes_attr.h"
+#include "ppc32_new_nodes.h"
+#include "gen_ppc32_regalloc_if.h"
+
+
+
+/***********************************************************************************
+ *      _                                   _       _             __
+ *     | |                                 (_)     | |           / _|
+ *   __| |_   _ _ __ ___  _ __   ___ _ __   _ _ __ | |_ ___ _ __| |_ __ _  ___ ___
+ *  / _` | | | | '_ ` _ \| '_ \ / _ \ '__| | | '_ \| __/ _ \ '__|  _/ _` |/ __/ _ \
+ * | (_| | |_| | | | | | | |_) |  __/ |    | | | | | ||  __/ |  | || (_| | (_|  __/
+ *  \__,_|\__,_|_| |_| |_| .__/ \___|_|    |_|_| |_|\__\___|_|  |_| \__,_|\___\___|
+ *                       | |
+ *                       |_|
+ ***********************************************************************************/
+
+/**
+ * Returns a string containing the names of all registers within the limited bitset
+ */
+static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) {
+       bitset_t *bs   = bitset_alloca(req->cls->n_regs);
+       char     *p    = buf;
+       int       size = 0;
+       int       i, cnt;
+
+       req->limited(NULL, bs);
+
+       for (i = 0; i < req->cls->n_regs; i++) {
+               if (bitset_is_set(bs, i)) {
+                       cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name);
+                       if (cnt < 0) {
+                               fprintf(stderr, "dumper problem, exiting\n");
+                               exit(1);
+                       }
+
+                       p    += cnt;
+                       size += cnt;
+
+                       if (size >= max)
+                               break;
+               }
+       }
+
+       return buf;
+}
+
+/**
+ * Dumps the register requirements for either in or out.
+ */
+static void dump_reg_req(FILE *F, ir_node *n, const ppc32_register_req_t **reqs, int inout) {
+       char *dir = inout ? "out" : "in";
+       int   max = inout ? get_ppc32_n_res(n) : get_irn_arity(n);
+       char *buf = alloca(1024);
+       int   i;
+
+       memset(buf, 0, 1024);
+
+       if (reqs) {
+               for (i = 0; i < max; i++) {
+                       fprintf(F, "%sreq #%d =", dir, i);
+
+                       if (reqs[i]->req.type == arch_register_req_type_none) {
+                               fprintf(F, " n/a");
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_normal) {
+                               fprintf(F, " %s", reqs[i]->req.cls->name);
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_limited) {
+                               fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024));
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_should_be_same) {
+                               ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos));
+                       }
+
+                       if (reqs[i]->req.type & arch_register_req_type_should_be_different) {
+                               ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos));
+                       }
+
+                       fprintf(F, "\n");
+               }
+
+               fprintf(F, "\n");
+       }
+       else {
+               fprintf(F, "%sreq = N/A\n", dir);
+       }
+}
+
+
+/**
+ * Dumper interface for dumping ppc32 nodes in vcg.
+ * @param n        the node to dump
+ * @param F        the output file
+ * @param reason   indicates which kind of information should be dumped
+ * @return 0 on success or != 0 on failure
+ */
+static int dump_node_ppc32(ir_node *n, FILE *F, dump_reason_t reason) {
+       ir_mode     *mode = NULL;
+       int          bad  = 0;
+       int          i;
+       ppc32_attr_t *attr;
+       const ppc32_register_req_t **reqs;
+       const arch_register_t     **slots;
+
+       switch (reason) {
+               case dump_node_opcode_txt:
+                       fprintf(F, "%s", get_irn_opname(n));
+                       break;
+
+               case dump_node_mode_txt:
+                       mode = get_irn_mode(n);
+
+                       if (mode) {
+                               fprintf(F, "[%s]", get_mode_name(mode));
+                       }
+                       else {
+                               fprintf(F, "[?NOMODE?]");
+                       }
+                       break;
+
+               case dump_node_nodeattr_txt:
+
+                       /* TODO: dump some attributes which should show up */
+                       /* in node name in dump (e.g. consts or the like)  */
+
+                       break;
+
+               case dump_node_info_txt:
+                       attr = get_ppc32_attr(n);
+                       fprintf(F, "=== ppc attr begin ===\n");
+
+                       /* dump IN requirements */
+                       if (get_irn_arity(n) > 0) {
+                               reqs = get_ppc32_in_req_all(n);
+                               dump_reg_req(F, n, reqs, 0);
+                       }
+
+                       /* dump OUT requirements */
+                       if (attr->n_res > 0) {
+                               reqs = get_ppc32_out_req_all(n);
+                               dump_reg_req(F, n, reqs, 1);
+                       }
+
+                       /* dump assigned registers */
+                       slots = get_ppc32_slots(n);
+                       if (slots && attr->n_res > 0) {
+                               for (i = 0; i < attr->n_res; i++) {
+                                       if (slots[i]) {
+                                               fprintf(F, "reg #%d = %s\n", i, slots[i]->name);
+                                       }
+                                       else {
+                                               fprintf(F, "reg #%d = n/a\n", i);
+                                       }
+                               }
+                       }
+                       fprintf(F, "\n");
+
+                       /* dump n_res */
+                       fprintf(F, "n_res = %d\n", get_ppc32_n_res(n));
+
+                       /* dump flags */
+                       fprintf(F, "flags =");
+                       if (attr->flags == arch_irn_flags_none) {
+                               fprintf(F, " none");
+                       }
+                       else {
+                               if (attr->flags & arch_irn_flags_dont_spill) {
+                                       fprintf(F, " unspillable");
+                               }
+                               if (attr->flags & arch_irn_flags_rematerializable) {
+                                       fprintf(F, " remat");
+                               }
+                               if (attr->flags & arch_irn_flags_ignore) {
+                                       fprintf(F, " ignore");
+                               }
+                       }
+                       fprintf(F, " (%d)\n", attr->flags);
+
+                       /* TODO: dump all additional attributes */
+
+                       fprintf(F, "=== ppc attr end ===\n");
+                       /* end of: case dump_node_info_txt */
+                       break;
+       }
+
+
+       return bad;
+}
+
+
+
+/***************************************************************************************************
+ *        _   _                   _       __        _                    _   _               _
+ *       | | | |                 | |     / /       | |                  | | | |             | |
+ *   __ _| |_| |_ _ __   ___  ___| |_   / /_ _  ___| |_   _ __ ___   ___| |_| |__   ___   __| |___
+ *  / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| |    \__ \  __/ |_ / / (_| |  __/ |_  | | | | | |  __/ |_| | | | (_) | (_| \__ \
+ *  \__,_|\__|\__|_|    |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ *                                        __/ |
+ *                                       |___/
+ ***************************************************************************************************/
+
+/**
+ * Wraps get_irn_generic_attr() as it takes no const ir_node, so we need to do a cast.
+ * Firm was made by people hating const :-(
+ */
+ppc32_attr_t *get_ppc32_attr(const ir_node *node) {
+       assert(is_ppc32_irn(node) && "need ppc node to get attributes");
+       return (ppc32_attr_t *)get_irn_generic_attr((ir_node *)node);
+}
+
+/**
+ * Returns the argument register requirements of a ppc node.
+ */
+const ppc32_register_req_t **get_ppc32_in_req_all(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->in_req;
+}
+
+/**
+ * Returns the result register requirements of an ppc node.
+ */
+const ppc32_register_req_t **get_ppc32_out_req_all(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->out_req;
+}
+
+/**
+ * Returns the argument register requirement at position pos of an ppc node.
+ */
+const ppc32_register_req_t *get_ppc32_in_req(const ir_node *node, int pos) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->in_req[pos];
+}
+
+/**
+ * Returns the result register requirement at position pos of an ppc node.
+ */
+const ppc32_register_req_t *get_ppc32_out_req(const ir_node *node, int pos) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->out_req[pos];
+}
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_ppc32_req_out(ir_node *node, const ppc32_register_req_t *req, int pos) {
+       ppc32_attr_t *attr   = get_ppc32_attr(node);
+       attr->out_req[pos] = req;
+}
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_ppc32_req_in(ir_node *node, const ppc32_register_req_t *req, int pos) {
+       ppc32_attr_t *attr  = get_ppc32_attr(node);
+       attr->in_req[pos] = req;
+}
+
+/**
+ * Returns the register flag of an ppc node.
+ */
+arch_irn_flags_t get_ppc32_flags(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->flags;
+}
+
+/**
+ * Sets the register flag of an ppc node.
+ */
+void set_ppc32_flags(const ir_node *node, arch_irn_flags_t flags) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->flags      = flags;
+}
+
+/**
+ * Returns the result register slots of an ppc node.
+ */
+const arch_register_t **get_ppc32_slots(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->slots;
+}
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_ppc32_out_reg_name(const ir_node *node, int pos) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+
+       assert(is_ppc32_irn(node) && "Not an ppc node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return arch_register_get_name(attr->slots[pos]);
+}
+
+/**
+ * Returns the index of the OUT register at position pos within its register class.
+ */
+int get_ppc32_out_regnr(const ir_node *node, int pos) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+
+       assert(is_ppc32_irn(node) && "Not an ppc node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return arch_register_get_index(attr->slots[pos]);
+}
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_ppc32_out_reg(const ir_node *node, int pos) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+
+       assert(is_ppc32_irn(node) && "Not an ppc node.");
+       assert(pos < attr->n_res && "Invalid OUT position.");
+       assert(attr->slots[pos]  && "No register assigned");
+
+       return attr->slots[pos];
+}
+
+/**
+ * Sets the number of results.
+ */
+void set_ppc32_n_res(ir_node *node, int n_res) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->n_res      = n_res;
+}
+
+/**
+ * Returns the number of results.
+ */
+int get_ppc32_n_res(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->n_res;
+}
+
+/**
+ * Sets the type of the constant (if any)
+ * May be either iro_Const or iro_SymConst
+ */
+/* void set_ppc32_type(const ir_node *node, opcode type) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->type      = type;
+}  */
+
+/**
+ * Returns the type of the content (if any)
+ */
+ppc32_attr_content_type get_ppc32_type(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->content_type;
+}
+
+/**
+ * Sets a tarval type content (also updating the content_type)
+ */
+void set_ppc32_constant_tarval(const ir_node *node, tarval *const_tarval) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_Const;
+       attr->constant_tarval = const_tarval;
+}
+
+/**
+ * Returns a tarval type constant
+ */
+tarval *get_ppc32_constant_tarval(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->constant_tarval;
+}
+
+/**
+ * Sets an ident type constant (also updating the content_type)
+ */
+void set_ppc32_symconst_ident(const ir_node *node, ident *symconst_ident) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_SymConst;
+       attr->symconst_ident = symconst_ident;
+}
+
+/**
+ * Returns an ident type constant
+ */
+ident *get_ppc32_symconst_ident(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->symconst_ident;
+}
+
+
+/**
+ * Sets an entity (also updating the content_type)
+ */
+void set_ppc32_frame_entity(const ir_node *node, entity *ent) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_FrameEntity;
+       attr->frame_entity = ent;
+}
+
+/**
+ * Returns an entity
+ */
+entity *get_ppc32_frame_entity(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->frame_entity;
+}
+
+/**
+ * Sets a Rlwimi const (also updating the content_type)
+ */
+void set_ppc32_rlwimi_const(const ir_node *node, unsigned shift, unsigned maskA, unsigned maskB) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_RlwimiConst;
+       attr->rlwimi_const.shift = shift;
+       attr->rlwimi_const.maskA = maskA;
+       attr->rlwimi_const.maskB = maskB;
+}
+
+/**
+ * Returns the rlwimi const structure
+ */
+rlwimi_const_t *get_ppc32_rlwimi_const(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return &attr->rlwimi_const;
+}
+
+/**
+ * Sets a Proj number (also updating the content_type)
+ */
+void set_ppc32_proj_nr(const ir_node *node, int proj_nr) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_BranchProj;
+       attr->proj_nr = proj_nr;
+}
+
+/**
+ * Returns the proj number
+ */
+int get_ppc32_proj_nr(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->proj_nr;
+}
+
+/**
+ * Sets an offset for a memory access (also updating the content_type)
+ */
+void set_ppc32_offset(const ir_node *node, int offset) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->content_type = ppc32_ac_Offset;
+       attr->proj_nr = offset;
+}
+
+/**
+ * Returns the offset
+ */
+int get_ppc32_offset(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->offset;
+}
+
+/**
+ * Sets the offset mode (ppc32_ao_None, ppc32_ao_Lo16, ppc32_ao_Hi16 or ppc32_ao_Ha16)
+ */
+void set_ppc32_offset_mode(const ir_node *node, ppc32_attr_offset_mode mode) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       attr->offset_mode = mode;
+}
+
+/**
+ * Returns the offset mode
+ */
+ppc32_attr_offset_mode get_ppc32_offset_mode(const ir_node *node) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+       return attr->offset_mode;
+}
+
+
+/**
+ * Initializes ppc specific node attributes
+ */
+void init_ppc32_attributes(ir_node *node, int flags,
+                                                const ppc32_register_req_t **in_reqs, const ppc32_register_req_t **out_reqs, int n_res) {
+       ppc32_attr_t *attr = get_ppc32_attr(node);
+
+       attr->flags = flags;
+       attr->in_req = in_reqs;
+       attr->out_req = out_reqs;
+       attr->n_res = n_res;
+
+       attr->slots = NULL;
+
+       if (n_res) {
+               attr->slots = xcalloc(n_res, sizeof(attr->slots[0]));
+       }
+
+       attr->content_type = ppc32_ac_None;
+       attr->offset_mode = ppc32_ao_Illegal;
+       attr->empty = NULL;
+}
+
+/**
+ * Hook to create additional opcodes.
+ */
+void ppc32_register_additional_opcodes(int opcode_num){
+}
+
+
+
+
+
+
+
+
+
+
+/***************************************************************************************
+ *                  _                            _                   _
+ *                 | |                          | |                 | |
+ *  _ __   ___   __| | ___    ___ ___  _ __  ___| |_ _ __ _   _  ___| |_ ___  _ __ ___
+ * | '_ \ / _ \ / _` |/ _ \  / __/ _ \| '_ \/ __| __| '__| | | |/ __| __/ _ \| '__/ __|
+ * | | | | (_) | (_| |  __/ | (_| (_) | | | \__ \ |_| |  | |_| | (__| || (_) | |  \__ \
+ * |_| |_|\___/ \__,_|\___|  \___\___/|_| |_|___/\__|_|   \__,_|\___|\__\___/|_|  |___/
+ *
+ ***************************************************************************************/
+
+/* Include the generated constructor functions */
+#include "gen_ppc32_new_nodes.c.inl"
diff --git a/ir/be/ppc32/ppc32_new_nodes.h b/ir/be/ppc32/ppc32_new_nodes.h
new file mode 100644 (file)
index 0000000..08e9e08
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef _PPC32_NEW_NODES_H_
+#define _PPC32_NEW_NODES_H_
+
+/**
+ * Function prototypes for the assembler ir node constructors.
+ * $Id$
+ */
+
+#include "ppc32_nodes_attr.h"
+
+/***************************************************************************************************
+ *        _   _                   _       __        _                    _   _               _
+ *       | | | |                 | |     / /       | |                  | | | |             | |
+ *   __ _| |_| |_ _ __   ___  ___| |_   / /_ _  ___| |_   _ __ ___   ___| |_| |__   ___   __| |___
+ *  / _` | __| __| '__| / __|/ _ \ __| / / _` |/ _ \ __| | '_ ` _ \ / _ \ __| '_ \ / _ \ / _` / __|
+ * | (_| | |_| |_| |    \__ \  __/ |_ / / (_| |  __/ |_  | | | | | |  __/ |_| | | | (_) | (_| \__ \
+ *  \__,_|\__|\__|_|    |___/\___|\__/_/ \__, |\___|\__| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|___/
+ *                                        __/ |
+ *                                       |___/
+ ***************************************************************************************************/
+
+/**
+ * Returns the attributes of an ppc node.
+ */
+ppc32_attr_t *get_ppc32_attr(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an ppc node.
+ */
+const ppc32_register_req_t **get_ppc32_in_req_all(const ir_node *node);
+
+/**
+ * Returns the result register requirements of an ppc node.
+ */
+const ppc32_register_req_t **get_ppc32_out_req_all(const ir_node *node);
+
+/**
+ * Returns the argument register requirements of an ppc node.
+ */
+const ppc32_register_req_t *get_ppc32_in_req(const ir_node *node, int pos);
+
+/**
+ * Returns the result register requirements of an ppc node.
+ */
+const ppc32_register_req_t *get_ppc32_out_req(const ir_node *node, int pos);
+
+/**
+ * Sets the OUT register requirements at position pos.
+ */
+void set_ppc32_req_out(ir_node *node, const ppc32_register_req_t *req, int pos);
+
+/**
+ * Sets the IN register requirements at position pos.
+ */
+void set_ppc32_req_in(ir_node *node, const ppc32_register_req_t *req, int pos);
+
+/**
+ * Returns the register flag of an ppc node.
+ */
+arch_irn_flags_t get_ppc32_flags(const ir_node *node);
+
+/**
+ * Sets the register flag of an ppc node.
+ */
+void set_ppc32_flags(const ir_node *node, arch_irn_flags_t flags);
+
+/**
+ * Returns the result register slots of an ppc node.
+ */
+const arch_register_t **get_ppc32_slots(const ir_node *node);
+
+/**
+ * Returns the name of the OUT register at position pos.
+ */
+const char *get_ppc32_out_reg_name(const ir_node *node, int pos);
+
+/**
+ * Returns the index of the OUT register at position pos within its register class.
+ */
+int get_ppc32_out_regnr(const ir_node *node, int pos);
+
+/**
+ * Returns the OUT register at position pos.
+ */
+const arch_register_t *get_ppc32_out_reg(const ir_node *node, int pos);
+
+/**
+ * Sets the number of results.
+ */
+void set_ppc32_n_res(ir_node *node, int n_res);
+
+/**
+ * Returns the number of results.
+ */
+int get_ppc32_n_res(const ir_node *node);
+
+ppc32_attr_content_type get_ppc32_type(const ir_node *node);
+
+void set_ppc32_constant_tarval(const ir_node *node, tarval *const_tarval);
+tarval *get_ppc32_constant_tarval(const ir_node *node);
+
+void set_ppc32_symconst_ident(const ir_node *node, ident *symconst_ident);
+ident *get_ppc32_symconst_ident(const ir_node *node);
+
+void set_ppc32_frame_entity(const ir_node *node, entity *ent);
+entity *get_ppc32_frame_entity(const ir_node *node);
+
+void set_ppc32_rlwimi_const(const ir_node *node, unsigned shift, unsigned maskA, unsigned maskB);
+rlwimi_const_t *get_ppc32_rlwimi_const(const ir_node *node);
+
+void set_ppc32_proj_nr(const ir_node *node, int proj_nr);
+int get_ppc32_proj_nr(const ir_node *node);
+
+void set_ppc32_offset(const ir_node *node, int offset);
+int get_ppc32_offset(const ir_node *node);
+
+void set_ppc32_offset_mode(const ir_node *node, ppc32_attr_offset_mode mode);
+ppc32_attr_offset_mode get_ppc32_offset_mode(const ir_node *node);
+
+void init_ppc32_attributes(ir_node *node, int flags,
+                                                const ppc32_register_req_t **in_reqs, const ppc32_register_req_t **out_reqs, int n_res);
+
+void ppc32_register_additional_opcodes(int opcode_num);
+
+/* Include the generated headers */
+#include "gen_ppc32_new_nodes.h"
+
+#endif /* _PPC32_NEW_NODES_H_ */
diff --git a/ir/be/ppc32/ppc32_nodes_attr.h b/ir/be/ppc32/ppc32_nodes_attr.h
new file mode 100644 (file)
index 0000000..a85f7bb
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _PPC32_NODES_ATTR_H_
+#define _PPC32_NODES_ATTR_H_
+
+#include "../bearch.h"
+
+typedef struct _ppc32_register_req_t {
+       const arch_register_req_t req;
+       int same_pos;        /**<< in case of "should be same" we need to remember the pos to get the irn */
+       int different_pos;   /**<< in case of "should be different" we need to remember the pos to get the irn */
+} ppc32_register_req_t;
+
+typedef struct
+{
+       unsigned shift:5;
+       unsigned maskA:5;
+       unsigned maskB:5;
+} rlwimi_const_t;
+
+
+typedef enum {
+       ppc32_ac_None, ppc32_ac_Const, ppc32_ac_SymConst, ppc32_ac_FrameEntity, ppc32_ac_RlwimiConst, ppc32_ac_BranchProj,
+       ppc32_ac_Offset
+} ppc32_attr_content_type;
+
+typedef enum {
+       ppc32_ao_None, ppc32_ao_Lo16, ppc32_ao_Hi16, ppc32_ao_Ha16, ppc32_ao_Illegal
+} ppc32_attr_offset_mode;
+
+typedef struct _ppc32_attr_t {
+       arch_irn_flags_t flags;     /**<< indicating if spillable, rematerializeable ... etc. */
+       int              n_res;     /**<< number of results for this node */
+
+       const ppc32_register_req_t **in_req;  /**<< register requirements for arguments */
+       const ppc32_register_req_t **out_req; /**<< register requirements for results */
+
+       const arch_register_t **slots;          /**<< register slots for assigned registers */
+
+       ppc32_attr_content_type content_type;
+       ppc32_attr_offset_mode offset_mode;
+       union {
+               tarval *constant_tarval;
+               ident *symconst_ident;
+               entity *frame_entity;
+               rlwimi_const_t rlwimi_const;
+               int proj_nr;
+               int offset;
+               void* empty;
+       };
+
+} ppc32_attr_t;
+
+#endif /* _PPC32_NODES_ATTR_H_ */
diff --git a/ir/be/ppc32/ppc32_spec.pl b/ir/be/ppc32/ppc32_spec.pl
new file mode 100644 (file)
index 0000000..e865300
--- /dev/null
@@ -0,0 +1,945 @@
+# Creation: 2006/02/13
+# $Id$
+# This is a template specification for the Firm-Backend
+
+# the cpu architecture (ia32, ia64, mips, sparc, ppc32, ...)
+
+$arch = "ppc32";
+
+$comment_string = "/*";
+
+# The node description is done as a perl hash initializer with the
+# following structure:
+#
+# %nodes = (
+#
+# <op-name> => {
+#   "op_flags"  => "N|L|C|X|I|F|Y|H|c|K",
+#   "irn_flags" => "R|N|I"
+#   "arity"     => "0|1|2|3 ... |variable|dynamic|any",
+#   "state"     => "floats|pinned|mem_pinned|exc_pinned",
+#   "args"      => [
+#                    { "type" => "type 1", "name" => "name 1" },
+#                    { "type" => "type 2", "name" => "name 2" },
+#                    ...
+#                  ],
+#   "comment"   => "any comment for constructor",
+#   "reg_req"   => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] },
+#   "cmp_attr"  => "c source code for comparing node attributes",
+#   "emit"      => "emit code with templates",
+#   "rd_constructor" => "c source code which constructs an ir_node"
+# },
+#
+# ... # (all nodes you need to describe)
+#
+# ); # close the %nodes initializer
+
+# op_flags: flags for the operation, OPTIONAL (default is "N")
+# the op_flags correspond to the firm irop_flags:
+#   N   irop_flag_none
+#   L   irop_flag_labeled
+#   C   irop_flag_commutative
+#   X   irop_flag_cfopcode
+#   I   irop_flag_ip_cfopcode
+#   F   irop_flag_fragile
+#   Y   irop_flag_forking
+#   H   irop_flag_highlevel
+#   c   irop_flag_constlike
+#   K   irop_flag_keep
+#
+# irn_flags: special node flags, OPTIONAL (default is 0)
+# following irn_flags are supported:
+#   R   rematerializeable
+#   N   not spillable
+#   I   ignore for register allocation
+#
+# state: state of the operation, OPTIONAL (default is "floats")
+#
+# arity: arity of the operation, MUST NOT BE OMITTED
+#
+# args:  the OPTIONAL arguments of the node constructor (debug, irg and block
+#        are always the first 3 arguments and are always autmatically
+#        created)
+#        If this key is missing the following arguments will be created:
+#        for i = 1 .. arity: ir_node *op_i
+#        ir_mode *mode
+#
+# comment: OPTIONAL comment for the node constructor
+#
+# rd_constructor: for every operation there will be a
+#      new_rd_<arch>_<op-name> function with the arguments from above
+#      which creates the ir_node corresponding to the defined operation
+#      you can either put the complete source code of this function here
+#
+#      This key is OPTIONAL. If omitted, the following constructor will
+#      be created:
+#      if (!op_<arch>_<op-name>) assert(0);
+#      for i = 1 to arity
+#         set in[i] = op_i
+#      done
+#      res = new_ir_node(db, irg, block, op_<arch>_<op-name>, mode, arity, in)
+#      return res
+#
+# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3
+
+# 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)
+# NOTE: Last entry of each class is the largest Firm-Mode a register can hold
+%reg_classes = (
+  "general_purpose" => [
+                         { "name" => "r0", "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" => 1 },
+                         { "name" => "r8", "type" => 1 },
+                         { "name" => "r9", "type" => 1 },
+                         { "name" => "r10", "type" => 1 },
+#                        { "name" => "r11", "type" => 1 },
+#                        { "name" => "r12", "type" => 1 },
+                         { "name" => "r13", "type" => 2 },
+                         { "name" => "r14", "type" => 2 },
+                         { "name" => "r15", "type" => 2 },
+#                        { "name" => "r16", "type" => 2 },
+#                        { "name" => "r17", "type" => 2 },
+#                        { "name" => "r18", "type" => 2 },
+#                        { "name" => "r19", "type" => 2 },
+#                        { "name" => "r20", "type" => 2 },
+#                        { "name" => "r21", "type" => 2 },
+#                        { "name" => "r22", "type" => 2 },
+#                        { "name" => "r23", "type" => 2 },
+#                        { "name" => "r24", "type" => 2 },
+#                        { "name" => "r25", "type" => 2 },
+#                        { "name" => "r26", "type" => 2 },
+#                        { "name" => "r27", "type" => 2 },
+#                        { "name" => "r28", "type" => 2 },
+#                        { "name" => "r29", "type" => 2 },
+#                        { "name" => "r30", "type" => 2 },
+                         { "name" => "r31", "type" => 2 },
+                         { "name" => "r1", "type" => 6 }, # this is our stackpointer
+                         { "mode" => "mode_P" }
+                       ],
+  "floating_point"  => [
+#                        { "name" => "f0", "type" => 1 }, # => reserved for FP Perm
+                         { "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" => 2 },
+                         { "name" => "f15", "type" => 2 },
+                         { "name" => "f16", "type" => 2 },
+#                        { "name" => "f17", "type" => 2 },
+#                        { "name" => "f18", "type" => 2 },
+#                        { "name" => "f19", "type" => 2 },
+#                        { "name" => "f20", "type" => 2 },
+#                        { "name" => "f21", "type" => 2 },
+#                        { "name" => "f22", "type" => 2 },
+#                        { "name" => "f23", "type" => 2 },
+#                        { "name" => "f24", "type" => 2 },
+#                        { "name" => "f25", "type" => 2 },
+#                        { "name" => "f26", "type" => 2 },
+#                        { "name" => "f27", "type" => 2 },
+#                        { "name" => "f28", "type" => 2 },
+#                        { "name" => "f29", "type" => 2 },
+#                        { "name" => "f30", "type" => 2 },
+#                        { "name" => "f31", "type" => 2 },
+                         { "mode" => "mode_D" }
+                       ],
+  "condition"          => [
+                                                { "name" => "cr0", "type" => 1 },
+                                                { "name" => "cr1", "type" => 1 },
+                                                { "name" => "cr2", "type" => 2 },
+                                                { "name" => "cr3", "type" => 2 },
+                                                { "name" => "cr4", "type" => 2 },
+                                                { "name" => "cr5", "type" => 1 },
+                                                { "name" => "cr6", "type" => 1 },
+#                                               { "name" => "cr7", "type" => 1 }, # => reserved for Condition Perm
+                                                { "mode" => "mode_P" } # real mode is 4 bit, but doesn't matter ...
+                                          ],
+  "link"                       => [
+                                                { "name" => "lr", "type" => 4 }, # 3
+                         { "mode" => "mode_P" }
+                                          ],
+  "count"                      => [
+                                                { "name" => "ctr", "type" => 1 },
+                         { "mode" => "mode_P" }
+                                          ]
+); # %reg_classes
+
+#--------------------------------------------------#
+#                        _                         #
+#                       (_)                        #
+#  _ __   _____      __  _ _ __    ___  _ __  ___  #
+# | '_ \ / _ \ \ /\ / / | | '__|  / _ \| '_ \/ __| #
+# | | | |  __/\ V  V /  | | |    | (_) | |_) \__ \ #
+# |_| |_|\___| \_/\_/   |_|_|     \___/| .__/|___/ #
+#                                      | |         #
+#                                      |_|         #
+#--------------------------------------------------#
+
+%nodes = (
+
+#-----------------------------------------------------------------#
+#  _       _                                         _            #
+# (_)     | |                                       | |           #
+#  _ _ __ | |_ ___  __ _  ___ _ __   _ __   ___   __| | ___  ___  #
+# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| #
+# | | | | | ||  __/ (_| |  __/ |    | | | | (_) | (_| |  __/\__ \ #
+# |_|_| |_|\__\___|\__, |\___|_|    |_| |_|\___/ \__,_|\___||___/ #
+#                   __/ |                                         #
+#                  |___/                                          #
+#-----------------------------------------------------------------#
+
+# commutative operations
+
+"Add" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Add: Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. add     %D1, %S1, %S2\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Addi" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "construct Add: Addi(a, const) = Addi(const, a) = a + const",
+  "reg_req"   => { "in" => [ "!r0" ], "out" => [ "general_purpose" ] },
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. addi    %D1, %S1, %C\t\t\t/* Addi(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+
+"Mullw" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Mul: Mullw(a, b) = Mullw(b, a) = lo32(a * b)",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. mullw   %D1, %S1, %S2\t\t\t/* Mullw(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Mulhw" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Mul: Mulhw(a, b) = Mulhw(b, a) = hi32(a * b)",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. mulhw   %D1, %S1, %S2\t\t\t/* Mulhw(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Mulhwu" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Mul: Mulhwu(a, b) = Mulhwu(b, a) = hi32(a * b)",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. mulhwu  %D1, %S1, %S2\t\t\t/* Mulhwu(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Mul_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Mul: Mul(a, const) = Mul(const, a) = a * const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. mul %S1, %C, %D1\t\t\t/* signed Mul(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+"And" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct And: And(a, b) = And(b, a) = a AND b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. and     %D1, %S1, %S2\t\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"And_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct And: And(a, const) = And(const, a) = a AND const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. and %S1, %C, %D1\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+"Or" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Or: Or(a, b) = Or(b, a) = a OR b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. or      %D1, %S1, %S2\t\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Or_i" => {
+#  "op_flags"  => "C",
+#  "irn_flags" => "R",
+#  "comment"   => "construct Or: Or(a, const) = Or(const, a) = a OR const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. or %S1, %C, %D1\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+"Xor" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct Xor: Xor(a, b) = Xor(b, a) = a XOR b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. xor     %D1, %S1, %S2\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Xor_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Xor: Xor(a, const) = Xor(const, a) = a EOR const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. xor %S1, %C, %D1\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */'
+#},
+
+# not commutative operations
+
+"Sub" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Sub: Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. sub     %D1, %S1, %S2\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Sub_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Sub: Sub(a, const) = a - const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. subl %S1, %C, %D1\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */'
+#},
+
+"Slw" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shl: Shl(a, b) = a << b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. slw     %D1, %S1, %S2\t\t\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Shl_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Shl: Shl(a, const) = a << const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. shl %S1, %C, %D1\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */'
+#},
+
+"Srw" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shr: Srw(a, b): c = a >> b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. srw     %D1, %S1, %S2\t\t\t/* Srw(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+#"Shr_i" => {
+#  "irn_flags" => "R",
+#  "comment"   => "construct Shr: Shr(a, const) = a >> const",
+#  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+#  "emit"      => '. shr %S1, %C, %D1\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */'
+#},
+
+"Sraw" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shrs: Sraw(a, b): c = a >> b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. sraw    %D1, %S1, %S2\t\t\t/* Sraw(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Srawi" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Shrs: Srawi(a, const): c = a >> const",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. sraw    %D1, %S1, %C\t\t\t/* Sraw(%S1, %C) -> %D1, (%A1, const) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+
+},
+
+"Rlwnm" => {
+  "irn_flags" => "R",
+  "comment"   => "construct ???: Rlwnm(a, b): c = a ROTL b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. rlwnm   %D1, %S1, %S2\t\t\t/* Rlwnm(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Rlwinm" => {
+  "irn_flags" => "R",
+  "comment"   => "construct ???: Rlwinm(a, b_const, c_const, d_const): (m = MASK(c, d)) e = (a ROTL b) & m",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. rlwinm  %D1, %S1, %ppc32_rlwimi_emit_helper\t\t\t/* Rlwinm(%S1, %ppc32_rlwimi_emit_helper) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+
+"Neg" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Minus: Neg(a) = -a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. neg     %D1, %S1\t\t\t/* Neg(%S1) -> %D1, (%A1) */'
+},
+
+"Not" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Not: Not(a) = !a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. nor     %D1, %S1, %S1\t\t\t/* Not(%S1) -> %D1, (%A1) */'
+},
+
+"Extsb" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Sign extension of byte: Extsb(char a) = (int) a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. extsb   %D1, %S1\t\t\t/* Extsb(%S1) -> %D1, (%A1) */'
+},
+
+"Extsh" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Sign extension of halfword: Extsh(char a) = (short) a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. extsh   %D1, %S1\t\t\t/* Extsh(%S1) -> %D1, (%A1) */'
+},
+
+"Divw" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Div (signed): Div(a, b) = a div b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. divw    %D1, %S1, %S2\t\t\t/* Div(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Divwu" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Div (unsigned): Div(a, b) = a div b",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. divwu   %D1, %S1, %S2\t\t\t/* Div(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Mtctr" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Mtctr: Ctr = a",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "count" ] },
+  "emit"      => '. mtctr   %S1\t\t\t/* Mtctr(%S1) -> %D1, (%A1) */'
+},
+
+
+# other operations
+
+"Const" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "Const (high-level node)",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "cmp_attr"  =>
+'
+       return attr_a->constant_tarval!=attr_b->constant_tarval;
+'
+},
+
+"fConst" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "float Const (high-level node)",
+  "reg_req"   => { "out" => [ "floating_point" ] },
+  "cmp_attr"  =>
+'
+       return attr_a->constant_tarval!=attr_b->constant_tarval;
+'
+},
+
+"SymConst" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "SymConst (high-level node)",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "cmp_attr"  =>
+'
+       return attr_a->constant_tarval!=attr_b->constant_tarval;
+'
+},
+
+"Unknown" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "construct unknown register",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "emit"      => '. \t\t\t\t\t/* use %D1 as uninitialized value */',
+  "cmp_attr"  =>
+'
+       return 1;
+'
+},
+
+"fUnknown" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "construct unknown float register",
+  "reg_req"   => { "out" => [ "floating_point" ] },
+  "emit"      => '. \t\t\t\t\t/* use %D1 as uninitialized value */',
+  "cmp_attr"  =>
+'
+       return 1;
+'
+},
+
+"cUnknown" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "construct unknown condition register",
+  "reg_req"   => { "out" => [ "condition" ] },
+  "emit"      => '. \t\t\t\t\t/* use %D1 as uninitialized value */',
+  "cmp_attr"  =>
+'
+       return 1;
+'
+},
+
+"Addi_zero" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "load constant (16bit with sign extension)",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "emit"      => '. addi    %D1, 0, %C\t\t\t/* lower 16 bit of %C (sign extended) -> %D1 */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Branch" => {
+  "op_flags"  => "L|X|Y",
+  "comment"   => "branch somewhere",
+  "reg_req"   => { "in" => [ "condition" ], "out" => [ "none", "none" ] },
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"LoopCopy" => {
+  "irn_flags" => "R",
+  "comment"   => "construct LoopCopy(src, dest, count, mem): Copy count words from src to dest",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "count", "none" ], "out" => [ "none", "in_r1", "in_r2", "in_r3", "general_purpose" ] },
+},
+
+"Switch" => {
+  "op_flags" => "L|X|Y",
+  "comment"   => "construct Switch(selector): Jump to whatever",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose", "condition" ], "out" => [ "none" ] },
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Addis_zero" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "load the constant to higher 16 bit of register",
+  "reg_req"   => { "out" => [ "general_purpose" ] },
+  "emit"      => '. addis   %D1, 0, %C\t\t\t/* %C << 16 -> %D1 */',
+  "attr"      => "ppc32_attr_offset_mode om, tarval *tv, ident *id",
+  "init_attr" =>
+'
+       attr->offset_mode = om;
+       if (tv) {
+               attr->content_type = ppc32_ac_Const;
+               attr->constant_tarval = tv;
+       }
+       else if (id) {
+               attr->content_type = ppc32_ac_SymConst;
+               attr->symconst_ident = id;
+       }
+',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Ori" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "ors constant with register",
+  "reg_req"   => { "in" => [ "general_purpose"], "out" => [ "general_purpose" ] },
+  "emit"      => '. ori     %D1, %S1, %C\t\t\t/* Ori(%S1,%C) -> %D1 */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Andi_dot" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "ands constant with register with cr0 update",
+  "reg_req"   => { "in" => [ "general_purpose"], "out" => [ "general_purpose", "cr0" ] },
+  "emit"      => '. andi.   %D1, %S1,%C\t\t\t/* Andi(%S1,%C) -> %D1 (%D2 changed) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Cmp" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Cmp: Cmp(a, b) = Flags in crX",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "condition" ] },
+  "emit"      => '. cmp     %D1, 0, %S1, %S2\t\t\t/* Cmp(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Cmpi" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Cmp immediate: Cmpi(a, const) = Flags in crX",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "condition" ] },
+  "emit"      => '. cmpi    %D1, 0, %S1, %C\t\t\t/* Cmpi(%S1, %C) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+
+"Cmpl" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Cmp logical: Cmpl(a, b) = Flags in crX",
+  "reg_req"   => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "condition" ] },
+  "emit"      => '. cmpl    %D1, 0, %S1, %S2\t\t\t/* Cmpl(%S1, %S2) -> %D1, (%A1, %A2) */'
+},
+
+"Cmpli" => {
+  "irn_flags" => "R",
+  "comment"   => "construct Cmp logical immediate: Cmpli(a, const) = Flags in crX",
+  "reg_req"   => { "in" => [ "general_purpose" ], "out" => [ "condition" ] },
+  "emit"      => '. cmpli   %D1, 0, %S1, %C\t\t\t/* Cmpli(%S1, %C) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+
+# Load / Store
+
+"Lbz" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load (byte unsigned): Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. lbz     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Lhz" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load (halfword unsigned): Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. lhz     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Lha" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load (halfword signed): Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. lha     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Lwz" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load (word): Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "general_purpose" ] },
+  "emit"      => '. lwz     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Lwzu" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Load with update (word): Load(ptr, mem) = LD ptr -> reg",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "general_purpose", "in_r1"] },
+  "emit"      => '. lwzu    %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1, %S1 += %O, (%A1) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Stb" => {
+  "op_flags"  => "L|F",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store (byte) (ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "!r0", "general_purpose", "none" ] },
+  "emit"      => '. stb     %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Sth" => {
+  "op_flags"  => "L|F",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store (halfword) (ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "!r0", "general_purpose", "none" ] },
+  "emit"      => '. sth     %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Stw" => {
+  "op_flags"  => "L|F",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store: Store (word) (ptr, val, mem) = ST ptr,val",
+  "reg_req"   => { "in" => [ "!r0", "general_purpose", "none" ] },
+  "emit"      => '. stw     %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+#--------------------------------------------------------#
+#    __ _             _                     _            #
+#   / _| |           | |                   | |           #
+#  | |_| | ___   __ _| |_   _ __   ___   __| | ___  ___  #
+#  |  _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| #
+#  | | | | (_) | (_| | |_  | | | | (_) | (_| |  __/\__ \ #
+#  |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ #
+#--------------------------------------------------------#
+
+# commutative operations
+
+"fAdd" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Add: Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fadd    %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fAdds" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Add (single): Add(a, b) = Add(b, a) = a + b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fadds   %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */'
+},
+
+"fMul" => {
+  "op_flags"  => "C",
+  "comment"   => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fmul    %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fMuls" => {
+  "op_flags"  => "C",
+  "comment"   => "construct FP Mul (single): Mul(a, b) = Mul(b, a) = a * b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fmuls   %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */'
+},
+
+"fNeg" => {
+  "comment"   => "construct FP Negation: fNeg(a) = -a",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fneg    %D1, %S1\t\t\t/* FP fNeg(%S1) -> %D1 */'
+},
+
+
+"fMax" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fmax    %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */'
+},
+
+"fMin" => {
+  "op_flags"  => "C",
+  "irn_flags" => "R",
+  "comment"   => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fmin    %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */'
+},
+
+# not commutative operations
+
+"fSub" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Sub: Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fsub    %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fSubs" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Sub (single): Sub(a, b) = a - b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fsub    %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */'
+},
+
+"fDiv" => {
+  "comment"   => "construct FP Div: Div(a, b) = a / b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fdiv    %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fDivs" => {
+  "comment"   => "construct FP Div (single): Div(a, b) = a / b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fdivs   %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */'
+},
+
+"fMinus" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Minus: fMinus(a) = -a",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fneg    %D1, %S1\t\t\t/* FP fMinus(%S1) -> %D1 */'
+},
+
+"fCtiw" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Convert to integer word: fCtiw(a) = (int) a",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fctiw   %D1, %S1\t\t\t/* FP fCtiw(%S1) -> %D1 */'
+},
+
+"fRsp" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Round to single: fRsp(a) = (float) a",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. frsp    %D1, %S1\t\t\t/* FP fRsp(%S1) -> %D1 */'
+},
+
+"fAbs" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Abs: fAbs(a) = |a|",
+  "reg_req"   => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] },
+  "emit"      => '. fabs    %D1, %S1\t\t\t/* FP fAbs(%S1) -> %D1 */'
+},
+
+"fCmpu" => {
+  "irn_flags" => "R",
+  "comment"   => "construct FP Cmp unordered: fCmpu(a, b) = a ? b",
+  "reg_req"   => { "in" => [ "floating_point", "floating_point" ], "out" => [ "condition" ] },
+  "emit"      => '. fcmpu   %D1, %S1, %S2\t\t\t/* FP fCmpu(%S1, %S2) -> %D1 */'
+},
+
+# other operations
+
+#"fConst" => {
+#  "op_flags"  => "c",
+#  "irn_flags" => "R",
+#  "comment"   => "represents a FP constant",
+#  "reg_req"   => { "out" => [ "floating_point" ] },
+#  "emit"      => '. fmov %C, %D1\t\t\t/* Mov fConst into register */',
+#  "cmp_attr"  =>
+#'
+#      /* TODO: compare fConst attributes */
+#      return 1;
+#'
+#},
+
+"fUnknown" => {
+  "op_flags"  => "c",
+  "irn_flags" => "R",
+  "comment"   => "construct unknown floating point register",
+  "reg_req"   => { "out" => [ "floating_point" ] },
+  "emit"      => '. \t\t\t\t\t/* use %D1 as uninitialized value */',
+  "cmp_attr"  =>
+'
+       return 1;
+'
+},
+
+# Load / Store
+
+"Lfd" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct FP Load (double): Load(ptr, mem) = LD ptr",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "floating_point" ] },
+  "emit"      => '. lfd     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1 */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Lfs" => {
+  "op_flags"  => "L|F",
+  "irn_flags" => "R",
+  "state"     => "exc_pinned",
+  "comment"   => "construct FP Load (single): Load(ptr, mem) = LD ptr",
+  "reg_req"   => { "in" => [ "!r0", "none" ], "out" => [ "floating_point" ] },
+  "emit"      => '. lfs     %D1, %O(%S1)\t\t\t/* Load(%O(%S1)) -> %D1 */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Stfd" => {
+  "op_flags"  => "L|F",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store (double): Store(ptr, val, mem)  = ST ptr,val",
+  "reg_req"   => { "in" => [ "!r0", "floating_point", "none" ] },
+  "emit"      => '. stfd    %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+"Stfs" => {
+  "op_flags"  => "L|F",
+  "state"     => "exc_pinned",
+  "comment"   => "construct Store (single): Store(ptr, val, mem)  = ST ptr,val",
+  "reg_req"   => { "in" => [ "!r0", "floating_point", "none" ] },
+  "emit"      => '. stfs    %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */',
+  "cmp_attr"  =>
+'
+       return (attr_a->constant_tarval!=attr_b->constant_tarval);
+'
+},
+
+); # end of %nodes
diff --git a/ir/be/ppc32/ppc32_transform.c b/ir/be/ppc32/ppc32_transform.c
new file mode 100644 (file)
index 0000000..6aaa91e
--- /dev/null
@@ -0,0 +1,1759 @@
+/* The codegenerator (transform FIRM into ppc FIRM) */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "irnode_t.h"
+#include "irgraph_t.h"
+#include "irmode_t.h"
+#include "irgmod.h"
+#include "iredges.h"
+#include "iredges_t.h"
+#include "irvrfy.h"
+#include "ircons.h"
+#include "dbginfo.h"
+#include "iropt_t.h"
+#include "debug.h"
+
+#include "../benode_t.h"
+#include "bearch_ppc32_t.h"
+
+#include "ppc32_nodes_attr.h"
+#include "../arch/archop.h"     /* we need this for Min and Max nodes */
+#include "ppc32_transform.h"
+#include "ppc32_new_nodes.h"
+#include "ppc32_map_regs.h"
+
+#include "gen_ppc32_regalloc_if.h"
+
+extern pset *symbol_pset;
+extern ir_op *get_op_Mulh(void);
+
+int is_direct_entity(entity *ent);
+
+ir_mode* ppc32_mode_Cond = NULL;
+
+/**
+ * Returns the proj of a given node with the given proj number
+ */
+static INLINE ir_node *get_succ_Proj(ir_node *node, long proj)
+{
+       const ir_edge_t *edge;
+       foreach_out_edge(node, edge)
+       {
+               if (is_Proj(edge->src) && get_Proj_proj(edge->src) == proj)
+                       return edge->src;
+       }
+       return NULL;
+}
+
+/**
+ * Returns a singleton condition mode
+ */
+ir_mode *get_ppc32_mode_Cond(void) {
+       if (ppc32_mode_Cond)
+               return ppc32_mode_Cond;
+       else {
+               ppc32_mode_Cond = new_ir_mode("mode_Cond", irms_character, 4, 0, irma_none, 0);
+               return ppc32_mode_Cond;
+       }
+}
+
+/**
+ * Calculates the modecode with size, sort and signed attributes
+ */
+modecode get_nice_modecode(ir_mode *irmode)
+{
+       modecode mode = irm_max;
+       int sign = mode_is_signed(irmode);
+       int bits = get_mode_size_bits(irmode);
+       if(mode_is_int(irmode))
+       {
+               switch(bits)
+               {
+                       case 8:
+                               mode = sign ? irm_Bs : irm_Bu;
+                               break;
+                       case 16:
+                               mode = sign ? irm_Hs : irm_Hu;
+                               break;
+                       case 32:
+                               mode = sign ? irm_Is : irm_Iu;
+                               break;
+               }
+       }
+       else if(mode_is_float(irmode))
+       {
+               switch(bits)
+               {
+                       case 32:
+                               mode = irm_F;
+                               break;
+                       case 64:
+                               mode = irm_D;
+                               break;
+               }
+       }
+       else if(mode_is_reference(irmode))
+       {
+               switch(bits)
+               {
+                       case 32:
+                               mode = irm_P;
+                               break;
+               }
+       }
+       return mode;
+}
+
+/**
+ * Returns true, if the given node is a Const node and it's value fits into
+ * a signed 16-bit variable
+ */
+int is_16bit_signed_const(ir_node *node)
+{
+       tarval *tv_const;
+
+       if(!is_ppc32_Const(node)) return 0;
+
+       tv_const = get_ppc32_constant_tarval(node);
+
+       switch(get_nice_modecode(get_irn_mode(node)))
+       {
+               case irm_Bu:
+               case irm_Bs:
+               case irm_Hs:
+                       return 1;
+               case irm_Iu:
+               case irm_P:
+               {
+                       unsigned char val2 = get_tarval_sub_bits(tv_const, 2);
+                       unsigned char val3 = get_tarval_sub_bits(tv_const, 3);
+                       if(val2 || val3)
+                               return 0;
+
+                       // fall through
+               }
+               case irm_Hu:
+               {
+                       unsigned char val1 = get_tarval_sub_bits(tv_const, 1);
+                       if(val1&0x80)
+                               return 0;
+                       return 1;
+               }
+
+               case irm_Is:
+               {
+                       unsigned char val2 = get_tarval_sub_bits(tv_const, 2);
+                       unsigned char val3 = get_tarval_sub_bits(tv_const, 3);
+                       if(val2==0 && val3==0)
+                       {
+                               unsigned char val1 = get_tarval_sub_bits(tv_const, 1);
+                               if(val1&0x80)
+                                       return 0;
+                               return 1;
+                       }
+                       if(!(val2==0xff && val3==0xff))
+                       {
+                               unsigned char val1 = get_tarval_sub_bits(tv_const, 1);
+                               if(!(val1&0x80))
+                                       return 0;
+                               return 1;
+                       }
+                       return 0;
+               }
+               default:
+                       fprintf(stderr, "is_16bit_signed_const(): Mode not supported: %s\n", get_mode_name(get_irn_mode(node)));
+                       assert(0);
+                       return 0;
+       }
+}
+
+/**
+ * Returns true, if the given node is a Const node and it's value fits into
+ * a unsigned 16-bit variable
+ */
+int is_16bit_unsigned_const(ir_node *node)
+{
+       tarval *tv_const;
+
+       if(!is_ppc32_Const(node)) return 0;
+
+       tv_const = get_ppc32_constant_tarval(node);
+       switch(get_nice_modecode(get_irn_mode(node)))
+       {
+               case irm_Bu:
+               case irm_Bs:
+               case irm_Hs:
+               case irm_Hu:
+                       return 1;
+               case irm_Iu:
+               case irm_P:
+               case irm_Is:
+               {
+                       unsigned char val2 = get_tarval_sub_bits(tv_const, 2);
+                       unsigned char val3 = get_tarval_sub_bits(tv_const, 3);
+                       if(val2 || val3)
+                               return 0;
+                       return 1;
+               }
+               default:
+                       fprintf(stderr, "is_16bit_unsigned_const(): Mode not supported: %s\n", get_mode_name(get_irn_mode(node)));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+/****************************************************************************************************
+ *                  _        _                        __                           _   _
+ *                 | |      | |                      / _|                         | | (_)
+ *  _ __   ___   __| | ___  | |_ _ __ __ _ _ __  ___| |_ ___  _ __ _ __ ___   __ _| |_ _  ___  _ __
+ * | '_ \ / _ \ / _` |/ _ \ | __| '__/ _` | '_ \/ __|  _/ _ \| '__| '_ ` _ \ / _` | __| |/ _ \| '_ \
+ * | | | | (_) | (_| |  __/ | |_| | | (_| | | | \__ \ || (_) | |  | | | | | | (_| | |_| | (_) | | | |
+ * |_| |_|\___/ \__,_|\___|  \__|_|  \__,_|_| |_|___/_| \___/|_|  |_| |_| |_|\__,_|\__|_|\___/|_| |_|
+ *
+ ****************************************************************************************************/
+
+/**
+ * Creates an ppc Add.
+ *
+ * @param env   The transformation environment
+ * @param op1   first operator
+ * @param op2   second operator
+ * @return the created ppc Add node
+ */
+static ir_node *gen_Add(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+                       return new_rd_ppc32_fAdd(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_F:
+                       return new_rd_ppc32_fAdds(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_Is:
+               case irm_Iu:
+               case irm_Hs:
+               case irm_Hu:
+               case irm_Bs:
+               case irm_Bu:
+               case irm_P:
+                       if(is_16bit_signed_const(op1))
+                       {
+                               ir_node *addnode = new_rd_ppc32_Addi(env->dbg, env->irg, env->block, op2, env->mode);
+                               set_ppc32_constant_tarval(addnode, get_ppc32_constant_tarval(op1));
+                               set_ppc32_offset_mode(addnode, ppc32_ao_None);
+                               return addnode;
+                       }
+                       if(is_16bit_signed_const(op2))
+                       {
+                               ir_node *addnode = new_rd_ppc32_Addi(env->dbg, env->irg, env->block, op1, env->mode);
+                               set_ppc32_constant_tarval(addnode, get_ppc32_constant_tarval(op2));
+                               set_ppc32_offset_mode(addnode, ppc32_ao_None);
+                               return addnode;
+                       }
+
+                       return new_rd_ppc32_Add(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               default:
+                       fprintf(stderr, "Mode for Add not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+
+/**
+ * Creates an ppc Mul.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Mul node
+ */
+static ir_node *gen_Mul(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+                       return new_rd_ppc32_fMul(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_F:
+                       return new_rd_ppc32_fMuls(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_Is:
+               case irm_Iu:
+               case irm_Hs:
+               case irm_Hu:
+               case irm_Bs:
+               case irm_Bu:
+                       return new_rd_ppc32_Mullw(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               case irm_P:
+               default:
+                       fprintf(stderr, "Mode for Mul not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+/**
+ * Creates an ppc Mulh.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Mulh node
+ */
+static ir_node *gen_Mulh(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_Is:
+               case irm_Hs:
+               case irm_Bs:
+                       return new_rd_ppc32_Mulhw(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               case irm_Iu:
+               case irm_Hu:
+               case irm_Bu:
+                       return new_rd_ppc32_Mulhwu(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               case irm_D:
+               case irm_F:
+               case irm_P:
+               default:
+                       fprintf(stderr, "Mode for Mulh not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+/**
+ * Creates an ppc And.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc And node
+ */
+static ir_node *gen_And(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       return new_rd_ppc32_And(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+
+/**
+ * Creates an ppc Or.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Or node
+ */
+static ir_node *gen_Or(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       return new_rd_ppc32_Or(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+
+/**
+ * Creates an ppc Xor.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Xor node
+ */
+static ir_node *gen_Eor(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       return new_rd_ppc32_Xor(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+
+/**
+ * Creates an ppc Sub.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Sub node
+ */
+static ir_node *gen_Sub(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+                       return new_rd_ppc32_fSub(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_F:
+                       return new_rd_ppc32_fSubs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_Is:
+               case irm_Iu:
+               case irm_Hs:
+               case irm_Hu:
+               case irm_Bs:
+               case irm_Bu:
+               case irm_P:
+                       return new_rd_ppc32_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               default:
+                       fprintf(stderr, "Mode for Sub not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+
+/**
+ * Creates an ppc floating Div.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc fDiv node
+ */
+static ir_node *gen_Quot(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+                       return new_rd_ppc32_fDiv(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               case irm_F:
+                       return new_rd_ppc32_fDivs(env->dbg, env->irg, env->block, op1, op2, env->mode);
+
+               default:
+                       fprintf(stderr, "Mode for Quot not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+/**
+ * Creates an ppc integer Div.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Div node
+ */
+static ir_node *gen_Div(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *proj_div = NULL;
+       const ir_edge_t *edge;
+
+       foreach_out_edge(env->irn, edge)
+       {
+               if (is_Proj(edge->src) && get_Proj_proj(edge->src) == pn_DivMod_res_div)
+                       proj_div = edge->src;
+       }
+
+       switch(get_nice_modecode(get_irn_mode(proj_div))){
+               case irm_Is:
+               case irm_Hs:
+               case irm_Bs:
+                       return new_rd_ppc32_Divw(env->dbg, env->irg, env->block, op1, op2, mode_T);
+
+               case irm_Iu:
+               case irm_Hu:
+               case irm_Bu:
+                       return new_rd_ppc32_Divwu(env->dbg, env->irg, env->block, op1, op2, mode_T);
+
+               default:
+                       fprintf(stderr, "Mode for Div not supported: %s\n", get_mode_name(get_irn_mode(proj_div)));
+                       assert(0);
+                       return 0;
+       }
+}
+
+/**
+ * Creates an ppc integer Div and Mod.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Div node
+ */
+static ir_node *gen_DivMod(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *proj_div = NULL, *proj_mod = NULL;
+       ir_node *div_result;
+       const ir_edge_t *edge;
+       ir_mode *res_mode;
+
+       foreach_out_edge(env->irn, edge)
+       {
+               if (is_Proj(edge->src))
+               {
+                       switch(get_Proj_proj(edge->src)){
+                               case pn_DivMod_res_div:
+                                       proj_div = edge->src;
+                                       break;
+                               case pn_DivMod_res_mod:
+                                       proj_mod = edge->src;
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+       }
+
+       assert(proj_div!=NULL || proj_mod!=NULL);
+
+       res_mode = get_irn_mode(proj_div);
+
+       switch(get_nice_modecode(res_mode))
+       {
+               case irm_Is:
+               case irm_Hs:
+               case irm_Bs:
+                       div_result = new_rd_ppc32_Divw(env->dbg, env->irg, env->block, op1, op2, mode_T);
+                       break;
+
+               case irm_Iu:
+               case irm_Hu:
+               case irm_Bu:
+                       div_result = new_rd_ppc32_Divwu(env->dbg, env->irg, env->block, op1, op2, mode_T);
+                       break;
+
+               default:
+                       fprintf(stderr, "Mode for DivMod not supported: %s\n", get_mode_name(res_mode));
+                       assert(0);
+                       return 0;
+
+       }
+
+       if (proj_div == NULL)
+               proj_div = new_rd_Proj(env->dbg, env->irg, env->block, div_result, get_irn_mode(proj_mod), pn_DivMod_res_div);
+
+       if (proj_mod!=NULL){
+               ir_node *mul_result;
+               ir_node *mod_result;
+
+               mul_result = new_rd_ppc32_Mullw(env->dbg, env->irg, env->block, proj_div, op2, res_mode);
+               mod_result = new_rd_ppc32_Sub(env->dbg, env->irg, env->block, op1, mul_result, res_mode);
+
+               exchange(proj_mod, mod_result);
+       }
+
+       return div_result;
+}
+
+/**
+ * Creates an ppc integer Mod.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Mod result node
+ */
+static ir_node *gen_Mod(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       ir_node *proj_div = NULL, *proj_mod = NULL;
+       ir_node *div_result;
+       ir_mode *res_mode;
+       ir_node *mul_result;
+       ir_node *mod_result;
+
+       proj_mod = get_succ_Proj(env->irn, pn_Mod_res);
+
+       assert(proj_mod!=NULL);
+       res_mode = get_irn_mode(proj_mod);
+
+       switch(get_nice_modecode(res_mode))
+       {
+               case irm_Is:
+               case irm_Hs:
+               case irm_Bs:
+                       div_result = new_rd_ppc32_Divw(env->dbg, env->irg, env->block, op1, op2, mode_T);
+                       break;
+
+               case irm_Iu:
+               case irm_Hu:
+               case irm_Bu:
+                       div_result = new_rd_ppc32_Divwu(env->dbg, env->irg, env->block, op1, op2, mode_T);
+                       break;
+
+               default:
+                       fprintf(stderr, "Mode for Mod not supported: %s\n", get_mode_name(res_mode));
+                       assert(0);
+                       return 0;
+
+       }
+
+       proj_div = new_rd_Proj(env->dbg, env->irg, env->block, div_result, res_mode, pn_DivMod_res_div);
+
+       mul_result = new_rd_ppc32_Mullw(env->dbg, env->irg, env->block, proj_div, op2, res_mode);
+       mod_result = new_rd_ppc32_Sub(env->dbg, env->irg, env->block, op1, mul_result, res_mode);
+
+       exchange(proj_mod, mod_result);
+
+
+
+       return div_result;
+}
+
+
+/**
+ * Creates an ppc Shl.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Shl node
+ */
+static ir_node *gen_Shl(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       if(is_ppc32_Const(op2))
+       {
+               ir_node *shift = new_rd_ppc32_Rlwinm(env->dbg, env->irg, env->block, op1, env->mode);
+               tarval *tv_const = get_ppc32_constant_tarval(op2);
+               int sh = get_tarval_long(tv_const);
+               assert(0<=sh && sh<=31);
+               set_ppc32_rlwimi_const(shift, sh, 0, 31-sh);
+               return shift;
+       }
+       return new_rd_ppc32_Slw(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+
+/**
+ * Creates an ppc Srw.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Shr node
+ */
+static ir_node *gen_Shr(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       if(is_ppc32_Const(op2))
+       {
+               ir_node *shift = new_rd_ppc32_Rlwinm(env->dbg, env->irg, env->block, op1, env->mode);
+               tarval *tv_const = get_ppc32_constant_tarval(op2);
+               int sh = get_tarval_long(tv_const);
+               assert(0<=sh && sh<=31);
+               set_ppc32_rlwimi_const(shift, 32-sh, sh, 31);
+               return shift;
+       }
+       return new_rd_ppc32_Srw(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an ppc Sraw.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Sraw node
+ */
+static ir_node *gen_Shrs(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       if(is_ppc32_Const(op2))
+       {
+               ir_node *shift = new_rd_ppc32_Srawi(env->dbg, env->irg, env->block, op1, env->mode);
+               tarval *tv_const = get_ppc32_constant_tarval(op2);
+               int sh = get_tarval_long(tv_const);
+               assert(0<=sh && sh<=31);
+               set_ppc32_constant_tarval(shift, tv_const);
+               set_ppc32_offset_mode(shift, ppc32_ao_None);
+               return shift;
+       }
+       return new_rd_ppc32_Sraw(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an ppc RotL.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc RotL node
+ */
+static ir_node *gen_Rot(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       if(is_ppc32_Const(op2))
+       {
+               ir_node *rot = new_rd_ppc32_Rlwinm(env->dbg, env->irg, env->block, op1, env->mode);
+               tarval *tv_const = get_ppc32_constant_tarval(op2);
+               int sh = get_tarval_long(tv_const);
+               assert(0<=sh && sh<=31);
+               set_ppc32_rlwimi_const(rot, sh, 0, 31);
+               return rot;
+       }
+       return new_rd_ppc32_Rlwnm(env->dbg, env->irg, env->block, op1, op2, env->mode);
+}
+
+
+/**
+ * Creates an ppc Cmp.
+ *
+ * @param dbg       firm node dbg
+ * @param block     the block the new node should belong to
+ * @param op1       first operator
+ * @param op2       second operator
+ * @param mode      node mode
+ * @return the created ppc Cmp node
+ */
+static ir_node *gen_Cmp(ppc32_transform_env_t *env, ir_node *op1, ir_node *op2) {
+       const ir_edge_t *edge;
+       foreach_out_edge(env->irn, edge)
+       {
+               if (is_Proj(edge->src))
+                       set_irn_mode(edge->src, get_ppc32_mode_Cond());
+       }
+
+       if(mode_is_float(env->mode))
+               return new_rd_ppc32_fCmpu(env->dbg, env->irg, env->block, op1, op2, env->mode);
+       else if(mode_is_signed(env->mode))
+       {
+               if(is_16bit_signed_const(op2))
+               {
+                       ir_node *cmp = new_rd_ppc32_Cmpi(env->dbg, env->irg, env->block, op1, env->mode);
+                       tarval *tv_const = get_ppc32_constant_tarval(op2);
+                       set_ppc32_constant_tarval(cmp, tv_const);
+                       set_ppc32_offset_mode(cmp, ppc32_ao_None);
+                       return cmp;
+               }
+               else
+               {
+                       return new_rd_ppc32_Cmp(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               }
+       }
+       else
+       {
+               if(is_16bit_unsigned_const(op2))
+               {
+                       ir_node *cmp = new_rd_ppc32_Cmpli(env->dbg, env->irg, env->block, op1, env->mode);
+                       tarval *tv_const = get_ppc32_constant_tarval(op2);
+                       set_ppc32_constant_tarval(cmp, tv_const);
+                       set_ppc32_offset_mode(cmp, ppc32_ao_None);
+
+                       return cmp;
+               }
+               else
+               {
+                       return new_rd_ppc32_Cmpl(env->dbg, env->irg, env->block, op1, op2, env->mode);
+               }
+       }
+}
+
+
+/**
+ * Transforms a Minus node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Minus node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created ppc Minus node
+ */
+static ir_node *gen_Minus(ppc32_transform_env_t *env, ir_node *op) {
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+               case irm_F:
+                       return new_rd_ppc32_fNeg(env->dbg, env->irg, env->block, op, env->mode);
+               case irm_Is:
+               case irm_Iu:
+               case irm_Hs:
+               case irm_Hu:
+               case irm_Bs:
+               case irm_Bu:
+               case irm_P:
+                       return new_rd_ppc32_Neg(env->dbg, env->irg, env->block, op, env->mode);
+
+               default:
+                       fprintf(stderr, "Mode for Neg not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+}
+
+
+
+/**
+ * Transforms a Not node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Not node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created ppc Not node
+ */
+static ir_node *gen_Not(ppc32_transform_env_t *env, ir_node *op) {
+       return new_rd_ppc32_Not(env->dbg, env->irg, env->block, op, env->mode);
+}
+
+
+static ir_node *own_gen_Andi_dot_lo16(ppc32_transform_env_t *env, ir_node *op, int mask)
+{
+       ir_node *andi = new_rd_ppc32_Andi_dot(env->dbg, env->irg, env->block, op, mode_T);
+       ir_node* in[1];
+       set_ppc32_offset_mode(andi, ppc32_ao_Lo16);
+       set_ppc32_constant_tarval(andi, new_tarval_from_long(mask, mode_Is));
+       in[0] = new_rd_Proj(env->dbg, env->irg, env->block, andi, env->mode,1);
+       be_new_Keep(&ppc32_reg_classes[CLASS_ppc32_condition], env->irg, env->block, 1, in);
+       return new_rd_Proj(env->dbg, env->irg, env->block, andi, env->mode,0);
+}
+
+/**
+ * Transforms a Conv node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Conv node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created ppc Conv node
+ */
+static ir_node *gen_Conv(ppc32_transform_env_t *env, ir_node *op) {
+       modecode from_mode=get_nice_modecode(get_irn_mode(get_irn_n(env->irn,0)));
+       modecode to_mode=get_nice_modecode(env->mode);
+
+#define SKIP return get_irn_n(env->irn, 0)
+
+       if(from_mode == to_mode) SKIP;
+
+       switch(from_mode){
+               case irm_F:
+                       switch(to_mode)
+                       {
+                               case irm_D: SKIP;
+                       }
+                       break;
+
+               case irm_D:
+                       switch(to_mode)
+                       {
+                               case irm_F:
+                                       return new_rd_ppc32_fRsp(env->dbg, env->irg, env->block, op, env->mode);
+                       }
+                       break;
+
+               case irm_Is:
+               case irm_Iu:
+                       switch(to_mode)
+                       {
+                               case irm_Hs:
+                                       return new_rd_ppc32_Extsh(env->dbg, env->irg, env->block, op, env->mode);
+                               case irm_Hu:
+                                       return own_gen_Andi_dot_lo16(env, op, 0xffff);
+                               case irm_Bs:
+                                       return new_rd_ppc32_Extsb(env->dbg, env->irg, env->block, op, env->mode);
+                               case irm_Bu:
+                                       return own_gen_Andi_dot_lo16(env, op, 0xff);
+                               case irm_Is:
+                               case irm_Iu:
+                                       SKIP;
+                       }
+                       break;
+
+               case irm_Hs:
+               case irm_Hu:
+                       switch(to_mode)
+                       {
+                               case irm_Iu:
+                                       if(from_mode==irm_Hu)
+                               case irm_Hu:
+                                               return own_gen_Andi_dot_lo16(env, op, 0xffff);
+                               case irm_Is:
+                                       SKIP;
+                               case irm_Bs:
+                                       return new_rd_ppc32_Extsb(env->dbg, env->irg, env->block, op, env->mode);
+                               case irm_Bu:
+                                       return own_gen_Andi_dot_lo16(env, op, 0xff);
+                               case irm_Hs:
+                                       return new_rd_ppc32_Extsh(env->dbg, env->irg, env->block, op, env->mode);
+                       }
+                       break;
+
+               case irm_Bs:
+               case irm_Bu:
+                       switch(to_mode)
+                       {
+                               case irm_Iu:
+                               case irm_Hu:
+                                       if(from_mode==irm_Bs)
+                               case irm_Bu:
+                                               return own_gen_Andi_dot_lo16(env, op, 0xff);
+                               case irm_Is:
+                               case irm_Hs:
+                                       SKIP;
+                               case irm_Bs:
+                                       return new_rd_ppc32_Extsb(env->dbg, env->irg, env->block, op, env->mode);
+                       }
+                       break;
+               case irm_P:
+                       if(to_mode==irm_Is || to_mode==irm_Iu) SKIP;
+                       break;
+       }
+
+       fprintf(stderr, "Mode for Conv not supported: %s -> %s\n",
+               get_mode_name(get_irn_mode(get_irn_n(env->irn,0))),get_mode_name(env->mode));
+       assert(0);
+       return 0;
+}
+
+#undef SKIP
+
+
+/**
+ * Transforms an Abs node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Not node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the ppc node generating the absolute value
+ */
+static ir_node *gen_Abs(ppc32_transform_env_t *env, ir_node *op) {
+       int shift = 7;
+       switch(get_nice_modecode(env->mode))
+       {
+               case irm_F:
+               case irm_D:
+                       return new_rd_ppc32_fAbs(env->dbg, env->irg, env->block, op, env->mode);
+
+               {
+                       ir_node *n1,*n2;
+               case irm_Is:
+                       shift += 16;
+               case irm_Hs:
+                       shift += 8;
+               case irm_Bs: ;
+                       n1 = new_rd_ppc32_Srawi(env->dbg, env->irg, env->block, op, env->mode);
+                       set_ppc32_constant_tarval(n1, new_tarval_from_long(shift, mode_Is));
+                       set_ppc32_offset_mode(n1, ppc32_ao_None);
+                       n2 = new_rd_ppc32_Add(env->dbg, env->irg, env->block, op, n1, env->mode);
+                       return new_rd_ppc32_Xor(env->dbg, env->irg, env->block, n2, n1, env->mode);
+               }
+       }
+       fprintf(stderr, "Mode for Abs not supported: %s\n", get_mode_name(env->mode));
+       assert(0);
+       return 0;
+}
+
+/**
+ * Transforms an Cond node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Not node
+ * @param op      operator
+ * @param mode    node mode
+ * @return a ppc branch node
+ */
+static ir_node *gen_Cond(ppc32_transform_env_t *env) {
+       ir_node *selector = get_Cond_selector(env->irn);
+       ir_mode *projmode = get_irn_mode(selector);
+       if(is_Proj(selector) && projmode==get_ppc32_mode_Cond())
+       {
+               int projnum = get_Proj_proj(selector);
+               ir_node *branch = new_rd_ppc32_Branch(env->dbg, env->irg, env->block, selector, env->mode);
+               set_ppc32_proj_nr(branch, projnum);
+               return branch;
+       }
+       else
+       {
+               ir_node *unknown_gpr = new_rd_ppc32_Unknown(env->dbg, env->irg, env->block, mode_Is);
+               ir_node *unknown_cond = new_rd_ppc32_cUnknown(env->dbg, env->irg, env->block, get_ppc32_mode_Cond());
+
+               ir_node *switch_node = new_rd_ppc32_Switch(env->dbg, env->irg, env->block, selector,
+                       unknown_gpr, unknown_cond, env->mode);
+               set_ppc32_proj_nr(switch_node, get_Cond_defaultProj(env->irn));
+
+               return switch_node;
+       }
+
+}
+
+/**
+ * Transforms an Unknown node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Not node
+ * @param op      operator
+ * @param mode    node mode
+ * @return a ppc Unknown node
+ */
+static ir_node *gen_Unknown(ppc32_transform_env_t *env) {
+       if(mode_is_float(env->mode))
+               return new_rd_ppc32_fUnknown(env->dbg, env->irg, env->block, env->mode);
+       else if (mode_is_int(env->mode))
+               return new_rd_ppc32_Unknown(env->dbg, env->irg, env->block, env->mode);
+       else
+       {
+               fprintf(stderr, "Mode %s for unknown value not supported.\n", get_mode_name(env->mode));
+               assert(0);
+               return 0;
+       }
+}
+
+static ir_node *ldst_insert_const(ir_node *ptr, tarval **ptv, ident **pid, ppc32_transform_env_t *env) {
+       tarval *tv_const = NULL;
+       ident *id_symconst = NULL;
+
+       if(is_ppc32_Const(ptr))
+       {
+               tv_const = get_ppc32_constant_tarval(ptr);
+               ptr = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, mode_P, ppc32_ao_Ha16, tv_const, NULL);
+       }
+       else if(is_ppc32_SymConst(ptr))
+       {
+               entity *ent = get_ppc32_frame_entity(ptr);
+               if(is_direct_entity(ent))
+               {
+                       id_symconst = get_entity_ident(ent);
+                       ptr = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, mode_P, ppc32_ao_Ha16, NULL, id_symconst);
+               }
+       }
+       *ptv = tv_const;
+       *pid = id_symconst;
+       return ptr;
+}
+
+/**
+ * Transforms a Load.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Load node
+ * @param mode    node mode
+ * @return the created ppc Load node
+ */
+static ir_node *gen_Load(ppc32_transform_env_t *env) {
+       ir_node *node = env->irn;
+       ir_node *loadptr = get_Load_ptr(node);
+       ir_node *load;
+       ir_mode *mode = get_Load_mode(node);
+       tarval *tv_const = NULL;
+       ident *id_symconst = NULL;
+
+       loadptr = ldst_insert_const(loadptr, &tv_const, &id_symconst, env);
+       switch(get_nice_modecode(mode)){
+               case irm_Bu:
+                       load = new_rd_ppc32_Lbz(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+
+               case irm_Bs:
+               {
+                       ir_node *proj_load, *extsb_node;
+                       load =  new_rd_ppc32_Lbz(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       proj_load = new_rd_Proj(env->dbg, env->irg, env->block, load, mode, pn_Load_res);
+                       extsb_node = new_rd_ppc32_Extsb(env->dbg, env->irg, env->block, proj_load, mode);
+                       exchange(get_succ_Proj(env->irn, pn_Load_res), extsb_node);
+                       break;
+               }
+
+
+               case irm_Hu:
+                       load = new_rd_ppc32_Lhz(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+               case irm_Hs:
+                       load =new_rd_ppc32_Lha(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+               case irm_Is:
+               case irm_Iu:
+               case irm_P:
+                       load = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+
+               case irm_D:
+                       load = new_rd_ppc32_Lfd(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+               case irm_F:
+                       load = new_rd_ppc32_Lfs(env->dbg, env->irg, env->block, loadptr, get_Load_mem(node), env->mode);
+                       break;
+
+               default:
+                       fprintf(stderr, "Mode for Load not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+
+       if(tv_const)
+       {
+               set_ppc32_offset_mode(load, ppc32_ao_Lo16);
+               set_ppc32_constant_tarval(load, tv_const);
+       }
+       else if(id_symconst)
+       {
+               set_ppc32_offset_mode(load, ppc32_ao_Lo16);
+               set_ppc32_symconst_ident(load, id_symconst);
+       }
+       return load;
+}
+
+
+
+/**
+ * Transforms a Store.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Store node
+ * @param mode    node mode
+ * @return the created ppc Store node
+ */
+static ir_node *gen_Store(ppc32_transform_env_t *env) {
+       ir_node *node = env->irn;
+       ir_node *storeptr = get_Store_ptr(node);
+       ir_node *valuenode = get_Store_value(node);
+       ir_mode *mode = get_irn_mode(valuenode);
+       ir_node *store;
+       tarval *tv_const = NULL;
+       ident *id_symconst = NULL;
+
+       storeptr = ldst_insert_const(storeptr, &tv_const, &id_symconst, env);
+
+       switch(get_nice_modecode(mode)){
+               case irm_Bu:
+               case irm_Bs:
+                       store = new_rd_ppc32_Stb(env->dbg, env->irg, env->block, storeptr, get_Store_value(node), get_Store_mem(node), env->mode);
+                       break;
+
+               case irm_Hu:
+               case irm_Hs:
+                       store = new_rd_ppc32_Sth(env->dbg, env->irg, env->block, storeptr, get_Store_value(node), get_Store_mem(node), env->mode);
+                       break;
+               case irm_Is:
+               case irm_Iu:
+               case irm_P:
+                       store = new_rd_ppc32_Stw(env->dbg, env->irg, env->block, storeptr, get_Store_value(node), get_Store_mem(node), env->mode);
+                       break;
+
+               case irm_D:
+                       store = new_rd_ppc32_Stfd(env->dbg, env->irg, env->block, storeptr, get_Store_value(node), get_Store_mem(node), env->mode);
+                       break;
+               case irm_F:
+                       store = new_rd_ppc32_Stfs(env->dbg, env->irg, env->block, storeptr, get_Store_value(node), get_Store_mem(node), env->mode);
+                       break;
+
+               default:
+                       fprintf(stderr, "Mode for Store not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+       if(tv_const)
+       {
+               set_ppc32_offset_mode(store, ppc32_ao_Lo16);
+               set_ppc32_constant_tarval(store, tv_const);
+       }
+       else if(id_symconst)
+       {
+               set_ppc32_offset_mode(store, ppc32_ao_Lo16);
+               set_ppc32_symconst_ident(store, id_symconst);
+       }
+       return store;
+}
+
+/**
+ * Transforms a CopyB.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Store node
+ * @param mode    node mode
+ * @return the created ppc CopyB node
+ */
+static ir_node *gen_CopyB(ppc32_transform_env_t *env) {
+       ir_node *mem = get_CopyB_mem(env->irn);
+       ir_node *src = get_CopyB_src(env->irn);
+       ir_node *dest = get_CopyB_dst(env->irn);
+       ir_type *type = get_CopyB_type(env->irn);
+       int size = get_type_size_bytes(type);
+       int offset = 0;
+
+       ir_node *load, *store;
+
+       if(size/4>=1)
+       {
+               ir_node *res;
+               tarval *offset0 = new_tarval_from_long(0, mode_Is);
+               tarval *offset4 = new_tarval_from_long(4, mode_Is);
+
+               load = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, src, mem, mode_T);
+               set_ppc32_constant_tarval(load, offset0);
+               set_ppc32_offset_mode(load, ppc32_ao_None);
+               mem = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_M, pn_Load_M);
+               res = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_Is, pn_Load_res);
+
+               store = new_rd_ppc32_Stw(env->dbg, env->irg, env->block, dest, res, mem, mode_T);
+               set_ppc32_constant_tarval(store, offset0);
+               set_ppc32_offset_mode(store, ppc32_ao_None);
+               mem = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
+
+               if(size/4==2)
+               {
+                       load = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, src, mem, mode_T);
+                       set_ppc32_constant_tarval(load, offset4);
+                       set_ppc32_offset_mode(load, ppc32_ao_None);
+                       mem = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_M, pn_Load_M);
+                       res = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_Is, pn_Load_res);
+
+                       store = new_rd_ppc32_Stw(env->dbg, env->irg, env->block, dest, res, mem, mode_T);
+                       set_ppc32_constant_tarval(store, offset4);
+                       set_ppc32_offset_mode(store, ppc32_ao_None);
+                       mem = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
+
+                       offset = 8;
+               }
+               else
+               {
+                       ir_node *ornode, *mtctrnode;
+                       ir_node* in[3];
+                       assert(size/4-1<=0xffff);
+                       if(size/4-1<0x8000)
+                       {
+                               ornode = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, mode_Is);
+                               set_ppc32_offset_mode(ornode, ppc32_ao_None);
+                       }
+                       else
+                       {
+                               ir_node *zeroreg = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, mode_Is);
+                               set_ppc32_offset_mode(zeroreg, ppc32_ao_None);
+                               set_ppc32_constant_tarval(zeroreg, new_tarval_from_long(0, mode_Is));
+                               ornode = new_rd_ppc32_Ori(env->dbg, env->irg, env->block, zeroreg, mode_Is);
+                               set_ppc32_offset_mode(ornode, ppc32_ao_Lo16);
+                       }
+
+                       set_ppc32_constant_tarval(ornode, new_tarval_from_long(size/4-1, mode_Is));
+                       mtctrnode = new_rd_ppc32_Mtctr(env->dbg, env->irg, env->block, ornode, mode_Is);
+                       store = new_rd_ppc32_LoopCopy(env->dbg, env->irg, env->block, src, dest, mtctrnode, mem, mode_T);
+
+                       in[0] = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_Is, 1); // src
+                       in[1] = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_Is, 2); // dest
+                       in[2] = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_Is, 4); // temp
+                       be_new_Keep(&ppc32_reg_classes[CLASS_ppc32_general_purpose], env->irg, env->block, 3, in);
+                       in[0] = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_Is, 3); // ctr
+                       be_new_Keep(&ppc32_reg_classes[CLASS_ppc32_count], env->irg, env->block, 1, in);
+
+                       mem = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, 0);
+
+                       offset = 4;
+               }
+       }
+
+       if((size & 2) == 2)
+       {
+               ir_node *res;
+               tarval* offset_tarval = new_tarval_from_long(offset, mode_Is);
+               load = new_rd_ppc32_Lhz(env->dbg, env->irg, env->block, src, mem, mode_T);
+               set_ppc32_constant_tarval(load, offset_tarval);
+               set_ppc32_offset_mode(load, ppc32_ao_None);
+               mem = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_M, pn_Load_M);
+               res = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_Is, pn_Load_res);
+
+               store = new_rd_ppc32_Sth(env->dbg, env->irg, env->block, dest, res, mem, mode_T);
+               set_ppc32_constant_tarval(store, offset_tarval);
+               set_ppc32_offset_mode(store, ppc32_ao_None);
+               mem = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
+
+               offset += 2;
+       }
+
+       if((size & 1) == 1)
+       {
+               ir_node *res;
+               tarval* offset_tarval = new_tarval_from_long(offset, mode_Is);
+               load = new_rd_ppc32_Lbz(env->dbg, env->irg, env->block, src, mem, mode_T);
+               set_ppc32_constant_tarval(load, offset_tarval);
+               set_ppc32_offset_mode(load, ppc32_ao_None);
+               mem = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_M, pn_Load_M);
+               res = new_rd_Proj(env->dbg, env->irg, env->block, load, mode_Is, pn_Load_res);
+
+               store = new_rd_ppc32_Stb(env->dbg, env->irg, env->block, dest, res, mem, mode_T);
+               set_ppc32_constant_tarval(store, offset_tarval);
+               set_ppc32_offset_mode(store, ppc32_ao_None);
+               // mem = new_rd_Proj(env->dbg, env->irg, env->block, store, mode_M, pn_Store_M);
+       }
+
+       return store;
+}
+
+/**
+ * Transforms a FrameAddr into a ppc Add.
+ */
+static ir_node *gen_FrameAddr(ppc32_transform_env_t *env) {
+       ir_node *op = get_irn_n(env->irn, 0);
+       ir_node *add = new_rd_ppc32_Addi(env->dbg, env->irg, env->block, op, mode_P);
+       set_ppc32_frame_entity(add, be_get_frame_entity(env->irn));
+       return add;
+}
+
+/**
+ * Transforms a StackParam into a ppc Load
+ */
+static ir_node *gen_StackParam(ppc32_transform_env_t *env) {
+       ir_node *load = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, get_irn_n(env->irn, 0), new_NoMem(), mode_T);
+       ir_node *proj = new_rd_Proj(env->dbg, env->irg, env->block, load, env->mode, pn_Load_res);
+       set_ppc32_frame_entity(load, be_get_frame_entity(env->irn));
+       return proj;
+}
+
+
+/*********************************************************
+ *                  _             _      _
+ *                 (_)           | |    (_)
+ *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
+ * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
+ * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
+ * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
+ *
+ *********************************************************/
+
+
+
+/**
+ * Transforms the given firm node (and maybe some other related nodes)
+ * into one or more assembler nodes.
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void ppc32_transform_node(ir_node *node, void *env) {
+       ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
+       opcode  code               = get_irn_opcode(node);
+       ir_node *asm_node          = NULL;
+       ppc32_transform_env_t tenv;
+
+       if (is_Block(node))
+               return;
+
+       tenv.block    = get_nodes_block(node);
+       tenv.dbg      = get_irn_dbg_info(node);
+       tenv.irg      = current_ir_graph;
+       tenv.irn      = node;
+       tenv.mod      = cgenv->mod;
+       tenv.mode     = get_irn_mode(node);
+
+#define UNOP(a)        case iro_##a: asm_node = gen_##a(&tenv, get_##a##_op(node)); break
+#define BINOP(a)       case iro_##a: asm_node = gen_##a(&tenv, get_##a##_left(node), get_##a##_right(node)); break
+#define GEN(a)         case iro_##a: asm_node = gen_##a(&tenv); break
+#define IGN(a)         case iro_##a: break
+#define BAD(a)         case iro_##a: goto bad
+#define OTHER_BIN(a)                                                       \
+       if (get_irn_op(node) == get_op_##a()) {                                \
+               asm_node = gen_##a(&tenv, get_irn_n(node, 0), get_irn_n(node, 1)); \
+               break;                                                             \
+       }
+#define BE_GEN(a)                  \
+       if (be_is_##a(node)) {         \
+               asm_node = gen_##a(&tenv); \
+               break;                     \
+       }
+
+       DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
+
+       switch (code) {
+               BINOP(Add);
+               BINOP(Mul);
+               BINOP(And);
+               BINOP(Or);
+               BINOP(Eor);
+
+               BINOP(Sub);
+               BINOP(Shl);
+               BINOP(Shr);
+               BINOP(Shrs);
+               BINOP(Rot);
+               BINOP(Quot);
+               BINOP(Div);
+               BINOP(DivMod);
+               BINOP(Mod);
+               BINOP(Cmp);
+
+               UNOP(Minus);
+               UNOP(Not);
+               UNOP(Conv);
+               UNOP(Abs);
+
+               GEN(Load);
+               GEN(Store);
+               GEN(Cond);
+               GEN(Unknown);
+               GEN(CopyB);
+
+               /* TODO: implement these nodes */
+               IGN(Mux);
+
+               /* You probably don't need to handle the following nodes */
+
+               IGN(Call);
+               IGN(Proj);
+               IGN(Alloc);
+
+               IGN(Block);
+               IGN(Start);
+               IGN(End);
+               IGN(NoMem);
+               IGN(Phi);
+               IGN(IJmp);
+               IGN(Jmp);
+               IGN(Break);
+               IGN(Sync);
+
+               BAD(Raise);
+               BAD(Sel);
+               BAD(InstOf);
+               BAD(Cast);
+               BAD(Free);
+               BAD(Tuple);
+               BAD(Id);
+               BAD(Bad);
+               BAD(Confirm);
+               BAD(Filter);
+               BAD(CallBegin);
+               BAD(EndReg);
+               BAD(EndExcept);
+
+               default:
+                       OTHER_BIN(Mulh);
+                       BE_GEN(FrameAddr);
+                       BE_GEN(StackParam);
+                       if (get_irn_op(node) == get_op_Max() ||
+                               get_irn_op(node) == get_op_Min())
+                       {
+                               /* TODO: implement */
+                               /* ignore for now  */
+                       }
+                       break;
+bad:
+               fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node));
+               assert(0);
+       }
+
+       if (asm_node) {
+               exchange(node, asm_node);
+               DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
+       }
+       else {
+               DB((tenv.mod, LEVEL_1, "ignored\n"));
+       }
+}
+
+/**
+ * Constant generating code
+ */
+
+struct tv_ent {
+       entity *ent;
+       tarval *tv;
+};
+
+/** Compares two (entity, tarval) combinations */
+static int cmp_tv_ent(const void *a, const void *b, size_t len) {
+       const struct tv_ent *e1 = a;
+       const struct tv_ent *e2 = b;
+
+       return !(e1->tv == e2->tv);
+}
+
+/** Generates a SymConst node for a known FP const */
+static ir_node *gen_fp_known_symconst(ppc32_transform_env_t *env, tarval *known_const) {
+       static set    *const_set = NULL;
+       static ir_type *tp = NULL;
+       struct tv_ent  key;
+       struct tv_ent *entry;
+       ir_node       *cnst,*symcnst;
+       ir_graph      *rem;
+       entity        *ent;
+
+       if(!const_set)
+               const_set = new_set(cmp_tv_ent, 10);
+       if(!tp)
+               tp = new_type_primitive(new_id_from_str("const_double_t"), env->mode);
+
+       key.tv  = known_const;
+       key.ent = NULL;
+
+       entry = set_insert(const_set, &key, sizeof(key), HASH_PTR(key.tv));
+
+       if(!entry->ent) {
+               char buf[80];
+               sprintf(buf, "const_%i", get_irn_node_nr(env->irn));
+               ent = new_entity(get_glob_type(), new_id_from_str(buf), tp);
+
+               set_entity_ld_ident(ent, get_entity_ident(ent));
+               set_entity_visibility(ent, visibility_local);
+               set_entity_variability(ent, variability_constant);
+               set_entity_allocation(ent, allocation_static);
+
+               /* we create a new entity here: It's initialization must resist on the
+                   const code irg */
+               rem = current_ir_graph;
+               current_ir_graph = get_const_code_irg();
+               cnst = new_Const(env->mode, key.tv);
+               current_ir_graph = rem;
+
+               set_atomic_ent_value(ent, cnst);
+
+               /* set the entry for hashmap */
+               entry->ent = ent;
+       }                                                                          // TODO: Wird nicht richtig in global type gesteckt, ppc32_gen_decls.c findet ihn nicht
+
+       symcnst = new_rd_ppc32_SymConst(env->dbg, env->irg, env->block, env->mode);
+       set_ppc32_frame_entity(symcnst, ent);
+       return symcnst;
+}
+
+static ir_node *gen_ppc32_SymConst(ppc32_transform_env_t *env);
+
+/**
+ * Transforms a Const.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Const node
+ * @param mode    node mode
+ * @return the created ppc Load immediate node
+ */
+static ir_node *gen_ppc32_Const(ppc32_transform_env_t *env) {
+       tarval *tv_const = get_ppc32_constant_tarval(env->irn);
+       ir_node *node;
+
+       switch(get_nice_modecode(env->mode)){
+               case irm_Hu:
+               {
+                       unsigned char val1 = get_tarval_sub_bits(tv_const, 1);
+                       if(val1&0x80)
+                       {
+                               ir_node *zeroreg = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, mode_Is);
+                               set_ppc32_constant_tarval(zeroreg, new_tarval_from_long(0, mode_Is));
+                               set_ppc32_offset_mode(zeroreg, ppc32_ao_None);
+                               node = new_rd_ppc32_Ori(env->dbg, env->irg, env->block, zeroreg, mode_Is);
+                               set_ppc32_offset_mode(node, ppc32_ao_Lo16);
+                               break;
+                       }
+               }
+               case irm_Bu:
+               case irm_Bs:
+               case irm_Hs:
+                       node = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, env->mode);
+                       set_ppc32_offset_mode(node, ppc32_ao_None);
+                       break;
+               case irm_Is:
+               case irm_Iu:
+               case irm_P:
+               {
+                       unsigned char val2 = get_tarval_sub_bits(tv_const,2);
+                       unsigned char val3 = get_tarval_sub_bits(tv_const,3);
+                       if(!val2 && !val3)
+                       {
+                               unsigned char val1 = get_tarval_sub_bits(tv_const, 1);
+                               if(val1&0x80)
+                               {
+                                       ir_node *zeroreg = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, mode_Is);
+                                       set_ppc32_constant_tarval(zeroreg, new_tarval_from_long(0, mode_Is));
+                                       set_ppc32_offset_mode(zeroreg, ppc32_ao_None);
+                                       node = new_rd_ppc32_Ori(env->dbg, env->irg, env->block, zeroreg, mode_Is);
+                                       set_ppc32_offset_mode(node, ppc32_ao_Lo16);
+                               }
+                               else
+                               {
+                                       node = new_rd_ppc32_Addi_zero(env->dbg, env->irg, env->block, env->mode);
+                                       set_ppc32_offset_mode(node, ppc32_ao_None);
+                               }
+                       }
+                       else
+                       {
+                               unsigned char val0 = get_tarval_sub_bits(tv_const,0);
+                               unsigned char val1 = get_tarval_sub_bits(tv_const,1);
+                               node = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, env->mode, ppc32_ao_Hi16, tv_const, NULL);
+                               if(val0 || val1)
+                               {
+                                       set_ppc32_constant_tarval(node, tv_const);
+                                       node = new_rd_ppc32_Ori(env->dbg, env->irg, env->block, node, env->mode);
+                                       set_ppc32_offset_mode(node, ppc32_ao_Lo16);
+                               }
+                       }
+                       break;
+               }
+
+               default:
+                       fprintf(stderr, "Mode for Const not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+       set_ppc32_constant_tarval(node, tv_const);
+       return node;
+}
+
+/**
+ * Transforms a fConst.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Const node
+ * @param mode    node mode
+ * @return the created ppc float Load node
+ */
+static ir_node *gen_ppc32_fConst(ppc32_transform_env_t *env) {
+       tarval *tv_const = get_ppc32_constant_tarval(env->irn);
+
+       switch(get_nice_modecode(env->mode)){
+               case irm_D:
+               case irm_F:
+               {
+                       ir_node *addr, *load;
+                       ir_mode *mode = env->mode;
+                       entity *ent;
+                       env->irn = gen_fp_known_symconst(env, tv_const);
+                       env->mode = mode_P;
+                       ent = get_ppc32_frame_entity(env->irn);
+                       if(is_direct_entity(ent))
+                       {
+                               ident *id_symconst = get_entity_ident(ent);
+                               ir_node *node_addis = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, env->mode, ppc32_ao_Ha16, NULL, id_symconst);
+
+                               if(mode==mode_D)
+                                       load = new_rd_ppc32_Lfd(env->dbg, env->irg, env->block, node_addis, new_NoMem(), mode_T);
+                               else // mode_F
+                                       load = new_rd_ppc32_Lfs(env->dbg, env->irg, env->block, node_addis, new_NoMem(), mode_T);
+
+                               set_ppc32_symconst_ident(load, id_symconst);
+                               set_ppc32_offset_mode(load, ppc32_ao_Lo16);
+                       }
+                       else
+                       {
+                               addr = gen_ppc32_SymConst (env);
+                               if(mode==mode_D)
+                                       load = new_rd_ppc32_Lfd(env->dbg, env->irg, env->block, addr, new_NoMem(), mode_T);
+                               else // mode_F
+                                       load = new_rd_ppc32_Lfs(env->dbg, env->irg, env->block, addr, new_NoMem(), mode_T);
+                       }
+                       return new_rd_Proj(env->dbg, env->irg, env->block, load, mode, pn_Load_res);
+               }
+
+               default:
+                       fprintf(stderr, "Mode for fConst not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+       assert(0 && "Dead end!");
+}
+
+
+/**
+ * Returns true, if the entity can be accessed directly,
+ * or false, if the address must be loaded first
+ */
+int is_direct_entity(entity *ent) {
+       return get_entity_visibility(ent)!=visibility_external_allocated;
+/*     visibility vis = get_entity_visibility(ent);
+       if(is_Method_type(get_entity_type(ent)))
+       {
+               return (vis!=visibility_external_allocated);
+       }
+       else
+       {
+               return (vis==visibility_local);
+       }*/
+}
+
+/**
+ * Transforms a SymConst.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Const node
+ * @param mode    node mode
+ * @return the created ppc Load immediate node
+ */
+static ir_node *gen_ppc32_SymConst(ppc32_transform_env_t *env) {
+       entity *ent = get_ppc32_frame_entity(env->irn);
+       ident *id_symconst = get_entity_ident(ent);
+       ir_node *node;
+       switch(get_nice_modecode(env->mode)){
+               case irm_P:
+               {
+                       if (is_direct_entity(ent))
+                       {
+                               ir_node *node_addis = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, env->mode, ppc32_ao_Hi16, NULL, id_symconst);
+                               node = new_rd_ppc32_Ori(env->dbg, env->irg, env->block, node_addis, env->mode);
+                               set_ppc32_symconst_ident(node, id_symconst);
+                               set_ppc32_offset_mode(node, ppc32_ao_Lo16);
+                       }
+                       else
+                       {
+                               ir_node *node_addis = new_rd_ppc32_Addis_zero(env->dbg, env->irg, env->block, env->mode, ppc32_ao_Ha16, NULL, id_symconst);
+                               node = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, node_addis, new_NoMem(), mode_T);
+                               set_ppc32_symconst_ident(node, id_symconst);
+                               set_ppc32_offset_mode(node, ppc32_ao_Lo16);
+                               node = new_rd_Proj(env->dbg, env->irg, env->block, node, env->mode, pn_Load_res);
+//                             pset_insert_ptr(symbol_pset, ent);
+                       }
+                       break;
+               }
+
+               default:
+                       fprintf(stderr, "Mode for SymConst not supported: %s\n", get_mode_name(env->mode));
+                       assert(0);
+                       return 0;
+       }
+       return node;
+}
+
+/**
+ * Transforms the given firm node (and maybe some other related nodes)
+ * into one or more assembler nodes.
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void ppc32_transform_const(ir_node *node, void *env) {
+       ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
+       opcode  code               = get_irn_opcode(node);
+       ir_node *asm_node          = NULL;
+       ppc32_transform_env_t tenv;
+
+       if (is_Block(node))
+               return;
+
+       tenv.block    = get_nodes_block(node);
+       tenv.dbg      = get_irn_dbg_info(node);
+       tenv.irg      = current_ir_graph;
+       tenv.irn      = node;
+       tenv.mod      = cgenv->mod;
+       tenv.mode     = get_irn_mode(node);
+
+#define OTHER_GEN(a)                                                       \
+       if (get_irn_op(node) == get_op_##a()) {                                \
+               asm_node = gen_##a(&tenv);                                         \
+       }
+
+       DBG((tenv.mod, LEVEL_1, "check %+F ... ", node));
+
+       OTHER_GEN(ppc32_Const)
+       else OTHER_GEN(ppc32_fConst)
+       else OTHER_GEN(ppc32_SymConst)
+
+       if (asm_node) {
+               exchange(node, asm_node);
+               DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node));
+       }
+       else {
+               DB((tenv.mod, LEVEL_1, "ignored\n"));
+       }
+}
diff --git a/ir/be/ppc32/ppc32_transform.h b/ir/be/ppc32/ppc32_transform.h
new file mode 100644 (file)
index 0000000..e13ffa1
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _PPC32_TRANSFORM_H_
+#define _PPC32_TRANSFORM_H_
+
+void ppc32_transform_node(ir_node *node, void *env);
+void ppc32_transform_const(ir_node *node, void *env);
+
+#endif /* _PPC32_TRANSFORM_H_ */
diff --git a/ir/be/ppc32/ppc32_transform_conv.c b/ir/be/ppc32/ppc32_transform_conv.c
new file mode 100644 (file)
index 0000000..6b70914
--- /dev/null
@@ -0,0 +1,473 @@
+/* The codegenerator (transform FIRM Conv nodes into ppc FIRM) */
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "irnode_t.h"
+#include "irgraph_t.h"
+#include "irmode_t.h"
+#include "irgmod.h"
+#include "iredges.h"
+#include "iredges_t.h"
+#include "irvrfy.h"
+#include "ircons.h"
+#include "dbginfo.h"
+#include "iropt_t.h"
+#include "debug.h"
+
+#include "../benode_t.h"
+#include "bearch_ppc32_t.h"
+
+#include "ppc32_nodes_attr.h"
+//#include "../arch/archop.h"     /* we need this for Min and Max nodes */
+#include "ppc32_transform_conv.h"
+#include "ppc32_new_nodes.h"
+#include "ppc32_map_regs.h"
+
+#include "gen_ppc32_regalloc_if.h"
+
+typedef struct
+{
+       ir_node *first_conv;
+       ir_node **convs;
+       int conv_count;
+} cw_block_attr;
+
+
+ir_node *current_block;
+int conv_nodes_found;
+entity *memslot;
+ir_node *memory;
+
+/**
+ * Conv walker initialization
+ */
+void ppc32_init_conv_walk(void)
+{
+       current_block = NULL;
+       conv_nodes_found = 0;
+       memslot = NULL;
+}
+
+static ir_node *own_gen_convert_call(ppc32_transform_env_t *env, ir_node *op, const char *funcname,
+                                                                        ir_mode *from_mode, ir_mode *to_mode)
+{
+       ir_type *method_type;
+       entity  *method_ent;
+       ir_node *in[1] = {op};
+       ir_node *call, *callee, *call_results;
+
+       method_type = new_type_method(new_id_from_str("convert_call_type"), 1, 1);
+       set_method_param_type(method_type, 0, new_type_primitive(new_id_from_str("conv_param"), from_mode));
+       set_method_res_type(method_type, 0, new_type_primitive(new_id_from_str("conv_result"), to_mode));
+
+       method_ent = new_entity(get_glob_type(), new_id_from_str(funcname), method_type);
+
+       callee = new_rd_SymConst_addr_ent(env->dbg, env->irg, method_ent, method_type);
+
+       call = new_rd_Call(env->dbg, env->irg, env->block, memory, callee, 1, in, method_type);
+
+       call_results = new_rd_Proj(env->dbg, env->irg, env->block, call, mode_T, pn_Call_T_result);
+       memory = new_rd_Proj(env->dbg, env->irg, env->block, call, mode_M, pn_Call_M_regular);
+       return new_rd_Proj(env->dbg, env->irg, env->block, call_results, to_mode, 0);
+}
+
+/**
+ * Transforms a Conv node.
+ *
+ * @param mod     the debug module
+ * @param block   the block the new node should belong to
+ * @param node    the ir Conv node
+ * @param op      operator
+ * @param mode    node mode
+ * @return the created ppc Conv node
+ */
+static ir_node *gen_Conv(ppc32_transform_env_t *env, ir_node *op) {
+       ir_mode *from_mode = get_irn_mode(get_irn_n(env->irn,0));
+       ir_mode *to_mode = env->mode;
+       modecode from_modecode=get_mode_modecode(from_mode);
+       modecode to_modecode=get_mode_modecode(to_mode);
+
+       switch(from_modecode){
+               case irm_F:
+                       op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_D);
+                       // fall through
+               case irm_D:
+               {
+                       ir_node *res;
+                       if (mode_is_signed(to_mode))  // Float to integer
+                       {
+                               ir_node *fctiw = new_rd_ppc32_fCtiw(env->dbg, env->irg, env->block, op, from_mode);
+                               ir_node *stfd = new_rd_ppc32_Stfd(env->dbg, env->irg, env->block, get_irg_frame(env->irg),
+                                       fctiw, memory, mode_T);
+                               ir_node *storememproj = new_rd_Proj(env->dbg, env->irg, env->block, stfd, mode_M, pn_Store_M);
+                               ir_node *lwz = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, get_irg_frame(env->irg),
+                                       storememproj, mode_T);
+                               set_ppc32_frame_entity(stfd, memslot);
+                               set_ppc32_offset_mode(stfd, ppc32_ao_Lo16);     // TODO: only allows a 16-bit offset on stack
+                               set_ppc32_frame_entity(lwz, memslot);
+                               set_ppc32_offset_mode(stfd, ppc32_ao_Lo16);     // TODO: only allows a 16-bit offset on stack
+                               memory = new_rd_Proj(env->dbg, env->irg, env->block, lwz, mode_M, pn_Store_M);
+                               res = new_rd_Proj(env->dbg, env->irg, env->block, lwz, to_mode, pn_Load_res);
+
+                       }
+                       else
+                       {
+                               res = own_gen_convert_call(env, op, "conv_double_to_unsigned_int", mode_D, mode_Iu);
+                       }
+
+                       switch(to_modecode)
+                       {
+                               case irm_Bs:
+                               case irm_Hs:
+                               case irm_Bu:
+                               case irm_Hu:
+                                       return new_rd_Conv(env->dbg, env->irg, env->block, res, to_mode);
+                               case irm_Is:
+                               case irm_Iu:
+                                       return res;
+                       }
+                       break;
+               }
+               case irm_Hs:
+               case irm_Bs:
+                       op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_Is);
+               case irm_Is:
+                       return own_gen_convert_call(env, op, (to_mode == mode_D) ? "conv_int_to_double" : "conv_int_to_single", mode_Is, to_mode);
+
+
+               case irm_Hu:
+               case irm_Bu:
+                       op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_Iu);
+               case irm_Iu:
+                       return own_gen_convert_call(env, op, (to_mode == mode_D) ? "conv_unsigned_int_to_double": "conv_unsigned_int_to_single", mode_Iu, to_mode);
+
+               case irm_P:
+                       break;
+       }
+       fprintf(stderr, "Mode for Conv not supported: %s -> %s\n", get_mode_name(from_mode), get_mode_name(to_mode));
+       assert(0);
+       return 0;
+
+       // return op;
+}
+
+int search_from_node_in_block(ir_node *from, ir_node *to)
+{
+       int n = get_irn_arity(from), i;
+       for(i=0;i<n;i++)
+       {
+               ir_node *pred = get_irn_n(from, i);
+               if(pred==to) return 1;
+               if(get_irn_n(pred, -1)==current_block)
+               {
+                       if(search_from_node_in_block(pred, to)) return 1;
+               }
+       }
+       return 0;
+}
+
+int nodes_dependency_order(ir_node **a, ir_node **b)
+{
+       if(search_from_node_in_block(*a,*b)) return 1;
+       if(search_from_node_in_block(*b,*a)) return -1;
+       return 0;
+}
+
+void finalize_block(ppc32_code_gen_t *cgenv)
+{
+       int i;
+       ir_node *current_conv;
+       cw_block_attr *attr = current_block->link;
+       ppc32_transform_env_t tenv;
+
+       if(!attr->conv_count) return;
+
+       if(!memslot)
+       {
+               ir_type *frame_type = get_irg_frame_type(cgenv->irg);
+               memslot = frame_alloc_area(frame_type, get_mode_size_bytes(mode_D), 4, 0);
+       }
+
+       attr->convs = xmalloc(attr->conv_count * sizeof(ir_node *));
+
+       for (i=0, current_conv=attr->first_conv; i<attr->conv_count; i++, current_conv=current_conv->link)
+       {
+               attr->convs[i] = current_conv;
+       }
+
+       qsort(attr->convs, attr->conv_count, sizeof(ir_node *),
+               (int (*)(const void *, const void *)) nodes_dependency_order);
+
+       tenv.block    = current_block;
+       tenv.irg      = current_ir_graph;
+       tenv.mod      = cgenv->mod;
+
+       memory = get_irg_no_mem(current_ir_graph);
+       for(i=0; i<attr->conv_count; i++)
+       {
+               tenv.dbg      = get_irn_dbg_info(attr->convs[i]);
+               tenv.irn      = attr->convs[i];
+               tenv.mode     = get_irn_mode(attr->convs[i]);
+
+               exchange(attr->convs[i], gen_Conv(&tenv, get_Conv_op(attr->convs[i])));
+       }
+}
+
+void init_block()
+{
+       cw_block_attr *attr;
+       attr = xmalloc(sizeof(cw_block_attr));
+       attr->first_conv = NULL;
+       attr->convs = NULL;                             // attr->convs is set in finalize_block()
+       attr->conv_count = 0;
+       current_block->link = attr;
+}
+
+/**
+ * Constant generating code
+ */
+
+struct tv_ent {
+       entity *ent;
+       tarval *tv;
+};
+
+/* Compares two (entity, tarval) combinations */
+static int cmp_tv_ent(const void *a, const void *b, size_t len) {
+       const struct tv_ent *e1 = a;
+       const struct tv_ent *e2 = b;
+
+       return !(e1->tv == e2->tv);
+}
+
+/* Generates a SymConst node for a known FP const */
+static ir_node *gen_fp_known_symconst(ppc32_transform_env_t *env, tarval *known_const) {
+       static set    *const_set = NULL;
+       static ir_type *tp = NULL;
+       struct tv_ent  key;
+       struct tv_ent *entry;
+       ir_node       *cnst;
+       ir_graph      *rem;
+       entity        *ent;
+
+       if(!const_set)
+               const_set = new_set(cmp_tv_ent, 10);
+       if(!tp)
+               tp = new_type_primitive(new_id_from_str("const_double_t"), env->mode);
+
+
+       key.tv  = known_const;
+       key.ent = NULL;
+
+       entry = set_insert(const_set, &key, sizeof(key), HASH_PTR(key.tv));
+
+       if(!entry->ent) {
+               char buf[80];
+               sprintf(buf, "const_%i", get_irn_node_nr(env->irn));
+               ent = new_entity(get_glob_type(), new_id_from_str(buf), tp);
+
+               set_entity_ld_ident(ent, get_entity_ident(ent));
+               set_entity_visibility(ent, visibility_local);
+               set_entity_variability(ent, variability_constant);
+               set_entity_allocation(ent, allocation_static);
+
+               /* we create a new entity here: It's initialization must resist on the
+                   const code irg */
+               rem = current_ir_graph;
+               current_ir_graph = get_const_code_irg();
+               cnst = new_Const(env->mode, key.tv);
+               current_ir_graph = rem;
+
+               set_atomic_ent_value(ent, cnst);
+
+               /* set the entry for hashmap */
+               entry->ent = ent;
+       }
+
+       return new_rd_SymConst_addr_ent(env->dbg, env->irg, ent, tp);
+}
+
+/**
+ * Transforms a Const
+ *
+ * @param env transformation environment
+ * @return the created ppc Const node
+ */
+static ir_node *gen_Const(ppc32_transform_env_t *env) {
+       tarval *tv_const = get_Const_tarval(env->irn);
+       ir_node *constant;
+
+       if (mode_is_float(env->mode))
+               constant = new_rd_ppc32_fConst(env->dbg, env->irg, env->block, env->mode);
+       else
+               constant = new_rd_ppc32_Const(env->dbg, env->irg, env->block, env->mode);
+       set_ppc32_constant_tarval(constant, tv_const);
+       return constant;
+}
+
+/**
+ * Transforms a SymConst.
+ *
+ * @param env transformation environment
+ * @return the created ppc SymConst node
+ */
+static ir_node *gen_SymConst(ppc32_transform_env_t *env) {
+       ir_node *symconst;
+       symconst = new_rd_ppc32_SymConst(env->dbg, env->irg, env->block, env->mode);
+       set_ppc32_frame_entity(symconst, get_SymConst_entity(env->irn));
+       return symconst;
+}
+
+/*********************************************************
+ *                  _             _      _
+ *                 (_)           | |    (_)
+ *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
+ * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
+ * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
+ * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
+ *
+ *********************************************************/
+
+
+
+/**
+ * Transforms all conv nodes into ppc convs before abi
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void ppc32_conv_walk(ir_node *node, void *env) {
+       ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
+       opcode  code          = get_irn_opcode(node);
+       ppc32_transform_env_t tenv;
+
+       if (is_Block(node))
+       {
+               if(current_block != NULL)
+                       finalize_block(cgenv);
+
+               current_block = node;
+               init_block();
+
+               return;
+       }
+
+       tenv.irg = current_ir_graph;
+       tenv.mod = cgenv->mod;
+
+       if (code == iro_Conv)
+       {
+               modecode from_mode=get_mode_modecode(get_irn_mode(get_irn_n(node,0)));
+               modecode to_mode=get_mode_modecode(get_irn_mode(node));
+               cw_block_attr *attr;
+
+               if(from_mode == to_mode) return;
+               if(from_mode == irm_F || from_mode == irm_D)
+               {
+                       switch(to_mode)
+                       {
+                               case irm_Bs:
+                               case irm_Bu:
+                               case irm_Hs:
+                               case irm_Hu:
+                               case irm_Is:
+                               case irm_Iu:
+                                       break;
+                               default:
+                                       return;
+
+                       }
+               }
+               else if(to_mode == irm_F || to_mode == irm_D)
+               {
+                       switch(from_mode)
+                       {
+                               case irm_Bs:
+                               case irm_Bu:
+                               case irm_Hs:
+                               case irm_Hu:
+                               case irm_Is:
+                               case irm_Iu:
+                                       break;
+                               default:
+                                       return;
+                       }
+               }
+               else return;
+
+               /* in Liste eintragen */
+               attr = get_irn_link(current_block);
+               set_irn_link(node, attr->first_conv);
+               attr->first_conv = node;
+               attr->conv_count++;
+               conv_nodes_found++;
+       }
+       else if (code == iro_Call) {
+               int i, size = 0;
+               ir_type *tp = get_Call_type(node);
+               ir_type *ptp;
+               int stack_alignment = 4;
+
+               for (i = get_Call_n_params(node) - 1; i >= 0; --i) {
+                       ir_mode *mode = get_irn_mode(get_Call_param(node, i));
+                       int s;
+
+                       if (mode_is_reference(mode)) {
+                               /* might be a compound parameter */
+                               ptp = get_method_param_type(tp, i);
+
+                               if (is_compound_type(ptp)) {
+                                       s = (get_type_size_bytes(ptp) + stack_alignment - 1) & -stack_alignment;
+
+                                       size += s;
+                                       continue;
+                               }
+                       }
+                       s = (get_mode_size_bytes(mode) + stack_alignment - 1) & -stack_alignment;
+                       size += s;
+               }
+               if ((unsigned) size > cgenv->area_size)
+                       cgenv->area_size = size;
+       }
+}
+
+/**
+ * Transforms all const nodes into ppc const nodes inside the using block
+ *
+ * @param node    the firm node
+ * @param env     the debug module
+ */
+void ppc32_pretransform_walk(ir_node *node, void *env) {
+       ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
+       opcode  code          = get_irn_opcode(node);
+       ppc32_transform_env_t tenv;
+
+       if (is_Block(node))
+       {
+               current_block = node;
+               return;
+       }
+
+       tenv.irg = current_ir_graph;
+       tenv.mod = cgenv->mod;
+
+       if(code == iro_Const || code == iro_SymConst)
+       {
+               ir_node *newconst;
+
+               tenv.block    = cgenv->start_succ_block;
+               tenv.irn      = node;
+               tenv.mode     = get_irn_mode(node);
+               tenv.dbg      = get_irn_dbg_info(node);
+
+               if(code == iro_Const)
+                       newconst = gen_Const(&tenv);
+               else
+                       newconst = gen_SymConst(&tenv);
+
+               exchange(node, newconst);
+       }
+}
diff --git a/ir/be/ppc32/ppc32_transform_conv.h b/ir/be/ppc32/ppc32_transform_conv.h
new file mode 100644 (file)
index 0000000..fad366f
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _PPC32_TRANSFORM_CONV_H_
+#define _PPC32_TRANSFORM_CONV_H_
+
+void ppc32_init_conv_walk(void);
+
+void ppc32_conv_walk(ir_node *node, void *env);
+void ppc32_pretransform_walk(ir_node *node, void *env);
+
+#endif /* _PPC32_TRANSFORM_CONV_H_ */