--- /dev/null
+/* 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,
+};
--- /dev/null
+#ifndef _BEARCH_PPC32_H_
+#define _BEARCH_PPC32_H_
+
+#include "../bearch.h"
+
+extern const arch_isa_if_t ppc32_isa_if;
+
+#endif /* _BEARCH_PPC32_H_ */
--- /dev/null
+#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_ */
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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_ */
--- /dev/null
+/**
+ * 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);
+}
--- /dev/null
+#ifndef _PPC32_GEN_DECLS_H_
+#define _PPC32_GEN_DECLS_H_
+
+/**
+ * Generate all entities.
+ */
+void ppc32_gen_decls(FILE *out);
+
+#endif /* _PPC32_GEN_DECLS_H_ */
--- /dev/null
+/**
+ * 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;
+}
--- /dev/null
+#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_ */
--- /dev/null
+/**
+ * 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"
--- /dev/null
+#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_ */
--- /dev/null
+#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_ */
--- /dev/null
+# 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
--- /dev/null
+/* 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"));
+ }
+}
--- /dev/null
+#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_ */
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+#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_ */