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