X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Farm%2Farm_spec.pl;h=968b36443d7da36a61ca4e82f72532d362aa945f;hb=72fca46dfebc45e1c8466d0b7035a68b9d1495fe;hp=cc5a3c54decae2fbc1cfa38ba38b5db0045db6b0;hpb=5da0fab6d0c10e01c19ecf6fdc3cc83d982dc8a5;p=libfirm diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index cc5a3c54d..968b36443 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -1,704 +1,643 @@ # Creation: 2006/02/13 # $Id$ -# This is a template specification for the Firm-Backend # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) $arch = "arm"; -# $comment_string = 'WIRHABENKEINEKOMMENTARE'; -$comment_string = '/*'; - -# the number of additional opcodes you want to register -#$additional_opcodes = 0; - -# 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 +# Modes # -# 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 +$mode_gp = "mode_Iu"; +$mode_flags = "mode_Bu"; +$mode_fpa = "mode_E"; # 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) +$normal = 0; # no special type +$caller_save = 1; # caller save (register must be saved by the caller of a function) +$callee_save = 2; # callee save (register must be saved by the called function) +$ignore = 4; # ignore (do not assign this register) +$arbitrary = 8; # emitter can choose an arbitrary register of this class +$virtual = 16; # the register is a virtual one +$state = 32; # register represents a state # NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( - "gp" => [ - { "name" => "r0", "type" => 1 }, - { "name" => "r1", "type" => 1 }, - { "name" => "r2", "type" => 1 }, - { "name" => "r3", "type" => 1 }, - { "name" => "r4", "type" => 2 }, - { "name" => "r5", "type" => 2 }, - { "name" => "r6", "type" => 2 }, - { "name" => "r7", "type" => 2 }, - { "name" => "r8", "type" => 2 }, - { "name" => "r9", "type" => 2 }, - { "name" => "r10", "type" => 2 }, - { "name" => "r11", "type" => 2 }, - { "name" => "r12", "type" => 6 }, # reserved for linker - { "name" => "sp", "type" => 6 }, # this is our stack pointer - { "name" => "lr", "type" => 3 }, # this is our return address - { "name" => "pc", "type" => 6 }, # this is our program counter - { "name" => "rxx", "type" => 6 }, # dummy register for no_mem - { "mode" => "mode_Iu" } - ], - "fp" => [ - { "name" => "f0", "type" => 1 }, - { "name" => "f1", "type" => 1 }, - { "name" => "f2", "type" => 1 }, - { "name" => "f3", "type" => 1 }, - { "name" => "f4", "type" => 2 }, - { "name" => "f5", "type" => 2 }, - { "name" => "f6", "type" => 2 }, - { "name" => "f7", "type" => 2 }, - { "name" => "fxx", "type" => 6 }, # dummy register for no_mem - { "mode" => "mode_D" } - ] -); # %reg_classes - -#--------------------------------------------------# -# _ # -# (_) # -# _ __ _____ __ _ _ __ ___ _ __ ___ # -# | '_ \ / _ \ \ /\ / / | | '__| / _ \| '_ \/ __| # -# | | | | __/\ V V / | | | | (_) | |_) \__ \ # -# |_| |_|\___| \_/\_/ |_|_| \___/| .__/|___/ # -# | | # -# |_| # -#--------------------------------------------------# + gp => [ + { name => "r0", type => $caller_save }, + { name => "r1", type => $caller_save }, + { name => "r2", type => $caller_save }, + { name => "r3", type => $caller_save }, + { name => "r4", type => $callee_save }, + { name => "r5", type => $callee_save }, + { name => "r6", type => $callee_save }, + { name => "r7", type => $callee_save }, + { name => "r8", type => $callee_save }, + { name => "r9", type => $callee_save }, + { name => "r10", type => $callee_save }, + { name => "r11", type => $callee_save }, + { name => "r12", type => $ignore }, # reserved for linker/immediate fixups + { name => "sp", type => $ignore }, # this is our stack pointer + { name => "lr", type => $callee_save | $caller_save }, # this is our return address + { name => "pc", type => $ignore }, # this is our program counter + { mode => $mode_gp } + ], + fpa => [ + { name => "f0", type => $caller_save }, + { name => "f1", type => $caller_save }, + { name => "f2", type => $caller_save }, + { name => "f3", type => $caller_save }, + { name => "f4", type => $caller_save }, + { name => "f5", type => $caller_save }, + { name => "f6", type => $caller_save }, + { name => "f7", type => $caller_save }, + { mode => $mode_fpa } + ], + flags => [ + { name => "fl", type => 0 }, + { mode => $mode_flags, flags => "manual_ra" } + ], +); + +%emit_templates = ( + M => "${arch}_emit_mode(node);", + LM => "${arch}_emit_load_mode(node);", + SM => "${arch}_emit_store_mode(node);", + SO => "${arch}_emit_shifter_operand(node);", + S0 => "${arch}_emit_source_register(node, 0);", + S1 => "${arch}_emit_source_register(node, 1);", + S2 => "${arch}_emit_source_register(node, 2);", + S3 => "${arch}_emit_source_register(node, 3);", + S4 => "${arch}_emit_source_register(node, 4);", + D0 => "${arch}_emit_dest_register(node, 0);", + D1 => "${arch}_emit_dest_register(node, 1);", + D2 => "${arch}_emit_dest_register(node, 2);", + O => "${arch}_emit_offset(node);", +); + +$default_attr_type = "arm_attr_t"; +$default_copy_attr = "arm_copy_attr"; + +%init_attr = ( + arm_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", + arm_SymConst_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_arm_SymConst_attributes(res, entity);", + arm_CondJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", + arm_SwitchJmp_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", + arm_fpaConst_attr_t => "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);", + arm_load_store_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_arm_load_store_attributes(res, ls_mode, entity, entity_sign, offset, is_frame_entity);", + arm_shifter_operand_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n", + arm_cmp_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n", + arm_CopyB_attr_t => + "\tinit_arm_attributes(res, flags, in_reqs, exec_units, n_res);\n". + "\tinit_arm_CopyB_attributes(res, size);", +); + +%compare_attr = ( + arm_attr_t => "cmp_attr_arm", + arm_SymConst_attr_t => "cmp_attr_arm_SymConst", + arm_CondJmp_attr_t => "cmp_attr_arm_CondJmp", + arm_SwitchJmp_attr_t => "cmp_attr_arm_SwitchJmp", + arm_fpaConst_attr_t => "cmp_attr_arm_fpaConst", + arm_load_store_attr_t => "cmp_attr_arm_load_store", + arm_shifter_operand_t => "cmp_attr_arm_shifter_operand", + arm_CopyB_attr_t => "cmp_attr_arm_CopyB", + arm_cmp_attr_t => "cmp_attr_arm_cmp", +); + +my %unop_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot", + custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);", + reg_req => { in => [], out => [ "gp" ] }, + }, + reg => { + custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + }, +); + +my %binop_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot", + custominit => "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + ins => [ "left" ], + }, + reg => { + custominit => "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right" ], + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, 0);", + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right", "shift" ], + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate", + custominit => "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);", + reg_req => { in => [ "gp", "gp" ], out => [ "gp" ] }, + ins => [ "left", "right" ], + }, +); + +my %cmp_shifter_operand_constructors = ( + imm => { + attr => "unsigned char immediate_value, unsigned char immediate_rot, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, immediate_value, ARM_SHF_IMM, immediate_rot);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp" ], out => [ "flags" ] }, + ins => [ "left" ], + }, + reg => { + attr => "bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, ARM_SHF_REG, 0);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + }, + reg_shift_reg => { + attr => "arm_shift_modifier shift_modifier, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, shift_modifier, 0);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right", "shift" ], + }, + reg_shift_imm => { + attr => "arm_shift_modifier shift_modifier, unsigned shift_immediate, bool ins_permuted, bool is_unsigned", + custominit => + "init_arm_shifter_operand(res, 0, shift_modifier, shift_immediate);\n". + "\tinit_arm_cmp_attr(res, ins_permuted, is_unsigned);", + reg_req => { in => [ "gp", "gp" ], out => [ "flags" ] }, + ins => [ "left", "right" ], + }, +); + %nodes = ( -#-----------------------------------------------------------------# -# _ _ _ # -# (_) | | | | # -# _ _ __ | |_ ___ __ _ ___ _ __ _ __ ___ __| | ___ ___ # -# | | '_ \| __/ _ \/ _` |/ _ \ '__| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | | || __/ (_| | __/ | | | | | (_) | (_| | __/\__ \ # -# |_|_| |_|\__\___|\__, |\___|_| |_| |_|\___/ \__,_|\___||___/ # -# __/ | # -# |___/ # -#-----------------------------------------------------------------# - -# commutative operations - -"Add" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. ADD %D1, %S1, %S2%X0 /* Add(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Add_i" => { - "irn_flags" => "R", - "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "cmp_attr" => 'return attr_a->value != attr_b->value;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. ADD %D1, %S1, %C /* Add(%C, %S1) -> %D1, (%A1, const) */' -}, - -"Mul" => { - #"op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "!in_r1" ] }, - "emit" =>'. MUL %D1, %S1, %S2 /* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Mla" => { - #"op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Mla: Mla(a, b, c) = a * b + c", - "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in_r1" ] }, - "emit" =>'. MLA %D1, %S1, %S2, %S3 /* Mla(%S1, %S2, %S3) -> %D1, (%A1, %A2, %A3) */' -}, - -"And" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct And: And(a, b) = And(b, a) = a AND b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. AND %D1, %S1, %S2%X0 /* And(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"And_i" => { - "irn_flags" => "R", - "comment" => "construct And: And(a, const) = And(const, a) = a AND const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. AND %D1, %S1, %C /* And(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => 'return attr_a->value != attr_b->value;' -}, - -"Or" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. ORR %D1, %S1, %S2%X0 /* Or(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Or_i" => { - "irn_flags" => "R", - "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "cmp_attr" => 'return attr_a->value != attr_b->value;', - "emit" => '. ORR %D1, %S1, %C /* Or(%C, %S1) -> %D1, (%A1, const) */' -}, - -"Eor" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. EOR %D1, %S1, %S2%X0 /* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Eor_i" => { - "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "cmp_attr" => 'return attr_a->value != attr_b->value;', - "emit" => '. EOR %D1, %S1, %C /* Xor(%C, %S1) -> %D1, (%A1, const) */' -}, - -# not commutative operations - -"Bic" => { - "irn_flags" => "R", - "comment" => "construct Bic: Bic(a, b) = a AND ~b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. BIC %D1, %S1, %S2%X0 /* AndNot(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Bic_i" => { - "irn_flags" => "R", - "comment" => "construct Bic: Bic(a, const) = a AND ~const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. BIC %D1, %S1, %C /* AndNot(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => 'return attr_a->value != attr_b->value;' -}, - -"Sub" => { - "irn_flags" => "R", - "comment" => "construct Sub: Sub(a, b) = a - b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. SUB %D1, %S1, %S2%X0 /* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Sub_i" => { - "irn_flags" => "R", - "comment" => "construct Sub: Sub(a, const) = a - const", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "cmp_attr" => 'return attr_a->value != attr_b->value;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. SUB %D1, %S1, %C /* Sub(%S1, %C) -> %D1, (%A1, const) */', -}, - -"Rsb" => { - "irn_flags" => "R", - "comment" => "construct Rsb: Rsb(a, b) = b - a", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. RSB %D1, %S1, %S2%X0 /* Rsb(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Rsb_i" => { - "irn_flags" => "R", - "comment" => "construct Rsb: Rsb(a, const) = const - a", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. RSB %D1, %S1, %C /* Rsb(%S1, %C) -> %D1, (%A1, const) */', - "cmp_attr" => 'return attr_a->value != attr_b->value;' -}, - -"Shl" => { - "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, b) = a << b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, - "emit" => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Shr" => { - "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, b) = a >> b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. MOV %D1, %S1, LSR %S2 /* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -"Shrs" => { - "irn_flags" => "R", - "comment" => "construct Shrs: Shrs(a, b) = a >> b", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. MOV %D1, %S1, ASR %S2\t\t /* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */' -}, - -#"RotR" => { -# "irn_flags" => "R", -# "comment" => "construct RotR: RotR(a, b) = a ROTR b", -# "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, -# "emit" => '. MOV %D1, %S1, ROR %S2 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' -## "emit" => '. ror %S1, %S2, %D1 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' -#}, - -#"RotL" => { -# "irn_flags" => "R", -# "comment" => "construct RotL: RotL(a, b) = a ROTL b", -# "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, -# "emit" => '. rol %S1, %S2, %D1 /* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' -#}, - -#"RotL_i" => { -# "irn_flags" => "R", -# "comment" => "construct RotL: RotL(a, const) = a ROTL const", -# "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, -# "emit" => '. rol %S1, %C, %D1 /* RotL(%S1, %C) -> %D1, (%A1, const) */' -#}, - -"Mov" => { - "irn_flags" => "R", - "comment" => "construct Mov: a = b", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. MOV %D1, %S1%X0\t/* Mov(%S1%X0) -> %D1, (%A1) */' -}, - -"Mov_i" => { - "irn_flags" => "R", - "comment" => "represents an integer constant", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "reg_req" => { "out" => [ "gp" ] }, - "emit" => '. MOV %D1, %C /* Mov Const into register */', - "cmp_attr" => 'return attr_a->value != attr_b->value;' -}, - -"Mvn" => { - "irn_flags" => "R", - "comment" => "construct Not: Not(a) = !a", - "attr" => "arm_shift_modifier mod, tarval *shf", - "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', - "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => '. MVN %D1, %S1%X0 /* ~(%S1%X0) -> %D1, (%A1) */' -}, - -"Mvn_i" => { - "irn_flags" => "R", - "comment" => "represents a negated integer constant", - "attr" => "tarval *tv", - "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', - "cmp_attr" => 'return attr_a->value != attr_b->value;', - "reg_req" => { "out" => [ "gp" ] }, - "emit" => '. MVN %D1, %C /* Mov ~Const into register */', -}, - -"Abs" => { - "irn_flags" => "R", - "comment" => "construct Abs: Abs(a) = |a|", - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, - "emit" => -'. MOVS %S1, %S1, #0 /* set condition flag */\n -. RSBMI %D1, %S1, #0 /* Neg(%S1) -> %D1, (%A1) */' -}, - -# other operations - -"EmptyReg" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "just to get an empty register for calculations", - "reg_req" => { "out" => [ "gp" ] }, - "emit" => '. /* %D1 now available for calculations */', - "cmp_attr" => 'return 1;' -}, - -"Copy" => { - "comment" => "implements a register copy", - "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, -}, - -"CopyB" => { - "op_flags" => "F|H", - "state" => "pinned", - "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)", - "reg_req" => { "in" => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], "out" => [ "none" ] }, -}, - -"SymConst" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents a symbolic constant", - "attr" => "const char *label", - "init_attr" => ' attr->symconst_label = label;', - "reg_req" => { "out" => [ "gp" ] }, -# "emit" => '. LDR %D1, %C /* Mov Const into register */', - "cmp_attr" => -' /* should be identical but ...*/ - return strcmp(attr_a->symconst_label, attr_b->symconst_label);' -}, - -"CondJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL", - "cmp_attr" => " return arm_comp_condJmp(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "none", "none"] }, -}, - -"SwitchJmp" => { - "op_flags" => "L|X|Y", - "comment" => "construct switch", - "reg_req" => { "in" => [ "gp" ], "out" => [ "none" ] }, - "cmp_attr" => " return 0;\n", -}, - -# Load / Store - -"Load" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, - "emit" => '. LDR %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDR %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' -}, - -"Loadb" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, - "emit" => '. LDRB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' -}, - -"Loadbs" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, - "emit" => '. LDRSB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRSB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' -}, - -"Loadh" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, - "emit" => '. LDRH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' -}, - -"Loadhs" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, - "emit" => '. LDRSH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRSH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' +Add => { + irn_flags => "R", + emit => '. add %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, }, -"Storeb" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. STRB %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' +Mul => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp" ], out => [ "!in_r1" ] }, + emit =>'. mul %D0, %S0, %S1', + mode => $mode_gp, }, -"Storebs" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. STRSB %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' -}, +Smull => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] }, + emit =>'. smull %D0, %D1, %S0, %S1', + outs => [ "low", "high" ], +}, -"Storeh" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. STRH %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' +Umull => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp" ], out => [ "gp", "gp" ] }, + emit =>'. umull %D0, %D1, %S0, %S1', + outs => [ "low", "high" ], + mode => $mode_gp, +}, + +Mla => { + irn_flags => "R", + reg_req => { in => [ "gp", "gp", "gp" ], out => [ "!in_r1" ] }, + emit =>'. mla %D0, %S0, %S1, %S2', + mode => $mode_gp, +}, + +And => { + irn_flags => "R", + emit => '. and %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Or => { + irn_flags => "R", + emit => '. orr %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Eor => { + irn_flags => "R", + emit => '. eor %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Bic => { + irn_flags => "R", + emit => '. bic %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Sub => { + irn_flags => "R", + emit => '. sub %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Rsb => { + irn_flags => "R", + emit => '. rsb %D0, %S0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%binop_shifter_operand_constructors, +}, + +Mov => { + irn_flags => "R", + arity => "variable", + emit => '. mov %D0, %SO', + mode => $mode_gp, + attr_type => "arm_shifter_operand_t", + constructors => \%unop_shifter_operand_constructors, +}, + +Mvn => { + irn_flags => "R", + attr_type => "arm_shifter_operand_t", + arity => "variable", + emit => '. mvn %D0, %SO', + mode => $mode_gp, + constructors => \%unop_shifter_operand_constructors, +}, + +# Deprecated - we should construct the movs and rsbmi directly... +Abs => { + irn_flags => "R", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + emit => +'. movs %S0, %S0, #0 +. rsbmi %D0, %S0, #0', + mode => $mode_gp, +}, + +# this node produces ALWAYS an empty (tempary) gp reg and cannot be CSE'd +EmptyReg => { + op_flags => "c", + irn_flags => "R", + reg_req => { out => [ "gp" ] }, + emit => '. /* %D0 now available for calculations */', + cmp_attr => 'return 1;', + mode => $mode_gp, +}, + +CopyB => { + op_flags => "F|H", + state => "pinned", + attr => "unsigned size", + attr_type => "arm_CopyB_attr_t", + reg_req => { in => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], out => [ "none" ] }, + outs => [ "M" ], +}, + +FrameAddr => { + op_flags => "c", + irn_flags => "R", + attr => "ir_entity *entity", + reg_req => { in => [ "gp" ], out => [ "gp" ] }, + ins => [ "base" ], + attr_type => "arm_SymConst_attr_t", + mode => $mode_gp, +}, + +SymConst => { + op_flags => "c", + irn_flags => "R", + attr => "ir_entity *entity", + reg_req => { out => [ "gp" ] }, + attr_type => "arm_SymConst_attr_t", + mode => $mode_gp, +}, + +Cmp => { + irn_flags => "R|F", + emit => '. cmp %S0, %SO', + mode => $mode_flags, + attr_type => "arm_cmp_attr_t", + constructors => \%cmp_shifter_operand_constructors, +}, + +Tst => { + irn_flags => "R|F", + emit => '. tst %S0, %SO', + mode => $mode_flags, + attr_type => "arm_cmp_attr_t", + constructors => \%cmp_shifter_operand_constructors, +}, + +B => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + reg_req => { in => [ "flags" ], out => [ "none", "none" ] }, + attr => "int proj_num", + attr_type => "arm_CondJmp_attr_t", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", }, - -"Storehs" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. STRSH%S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' + +Jmp => { + state => "pinned", + op_flags => "X", + irn_flags => "J", + reg_req => { out => [ "none" ] }, + mode => "mode_X", +}, + +SwitchJmp => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + attr => "int n_projs, long def_proj_num", + init_attr => "\tset_arm_SwitchJmp_n_projs(res, n_projs);\n". + "\tset_arm_SwitchJmp_default_proj_num(res, def_proj_num);", + reg_req => { in => [ "gp" ], out => [ "none" ] }, + attr_type => "arm_SwitchJmp_attr_t", +}, + +Ldr => { + op_flags => "L|F", + state => "exc_pinned", + ins => [ "ptr", "mem" ], + outs => [ "res", "M" ], + reg_req => { in => [ "gp", "none" ], out => [ "gp", "none" ] }, + emit => '. ldr%LM %D0, [%S0, #%O]', + attr_type => "arm_load_store_attr_t", + attr => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity", }, -"Store" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. STR %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' +Str => { + op_flags => "L|F", + state => "exc_pinned", + ins => [ "ptr", "val", "mem" ], + outs => [ "mem" ], + reg_req => { in => [ "gp", "gp", "none" ], out => [ "none" ] }, + emit => '. str%SM %S1, [%S0, #%O]', + mode => "mode_M", + attr_type => "arm_load_store_attr_t", + attr => "ir_mode *ls_mode, ir_entity *entity, int entity_sign, long offset, bool is_frame_entity", }, -"StoreStackM4Inc" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "sp", "gp", "gp", "gp", "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. STMFD %S1!, {%S2, %S3, %S4, %S5} /* Store multiple on Stack*/' +StoreStackM4Inc => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "sp", "gp", "gp", "gp", "gp", "none" ], out => [ "sp:I|S", "none" ] }, + emit => '. stmfd %S0!, {%S1, %S2, %S3, %S4}', + outs => [ "ptr", "M" ], }, -"LoadStackM3" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "sp", "none" ], "out" => [ "gp", "gp", "gp", "none" ] }, - "emit" => '. LDMFD %S1, {%D1, %D2, %D3} /* Load multiple from Stack */' +LoadStackM3Epilogue => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + reg_req => { in => [ "sp", "none" ], out => [ "r11:I", "sp:I|S", "pc:I", "none" ] }, + emit => '. ldmfd %S0, {%D0, %D1, %D2}', + outs => [ "res0", "res1", "res2", "M" ], }, +fpaAdf => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit => '. adf%M %D0, %S0, %S1', +}, + +fpaMuf => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit =>'. muf%M %D0, %S0, %S1', +}, +fpaFml => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit =>'. fml%M %D0, %S0, %S1', +}, +fpaMax => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit =>'. fmax %S0, %S1, %D0', +}, +fpaMin => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit =>'. fmin %S0, %S1, %D0', +}, +fpaSuf => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit => '. suf%M %D0, %S0, %S1' +}, + +fpaRsf => { + irn_flags => "R", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa" ] }, + emit => '. rsf%M %D0, %S0, %S1' +}, -#--------------------------------------------------------# -# __ _ _ _ # -# / _| | | | | | # -# | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#--------------------------------------------------------# +fpaDvf => { + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, + emit =>'. dvf%M %D0, %S0, %S1', + outs => [ "res", "M" ], +}, -# commutative operations +fpaRdf => { + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, + emit =>'. rdf%M %D0, %S0, %S1', + outs => [ "res", "M" ], +}, -"fAdd" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" => '. FADD%Mx %D1, %S1, %S2 /* FP Add(%S1, %S2) -> %D1 */' +fpaFdv => { + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, + emit =>'. fdv%M %D0, %S0, %S1', + outs => [ "res", "M" ], }, -"fMul" => { - "op_flags" => "C", - "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. FMUL%Mx %D1, %S1, %S2 /* FP Mul(%S1, %S2) -> %D1 */' +fpaFrd => { + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "fpa", "fpa" ], out => [ "fpa", "none" ] }, + emit =>'. frd%M %D0, %S0, %S1', + outs => [ "res", "M" ], }, -"fDiv" => { - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. FDIV%Mx %D1, %S1, %S2 /* FP Div(%S1, %S2) -> %D1 */' +fpaMvf => { + irn_flags => "R", + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, + emit => '. mvf%M %S0, %D0', }, -"fMax" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. fmax %S1, %S2, %D1 /* FP Max(%S1, %S2) -> %D1 */' +fpaMnf => { + irn_flags => "R", + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, + emit => '. mnf%M %S0, %D0', }, -"fMin" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. fmin %S1, %S2, %D1 /* FP Min(%S1, %S2) -> %D1 */' +fpaAbs => { + irn_flags => "R", + reg_req => { in => [ "fpa" ], out => [ "fpa" ] }, + emit => '. abs%M %D0, %S0', }, -# not commutative operations +fpaFlt => { + irn_flags => "R", + reg_req => { in => ["gp"], out => [ "fpa" ] }, + emit => '. flt%M %D0, %S0', +}, -"fSub" => { - "irn_flags" => "R", - "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" => '. FSUB%Mx %D1, %S1, %S2 /* FP Sub(%S1, %S2) -> %D1 */' +fpaFix => { + irn_flags => "R", + reg_req => { in => ["fpa"], out => [ "gp" ] }, + emit => '. fix %D0, %S0', }, -"fMinus" => { - "irn_flags" => "R", - "comment" => "construct FP Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. fneg %S1, %D1 /* FP Minus(%S1) -> %D1 */' +fpaCmfBra => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + attr => "int proj_num", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, + attr_type => "arm_CondJmp_attr_t", }, -"fAbs" => { - "irn_flags" => "R", - "comment" => "construct FP Absolute value: fAbsd(a) = |a|", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FABS%Mx %D1, %S1 /* FP Absd(%S1) -> %D1 */' +fpaCnfBra => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + attr => "int proj_num", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, + attr_type => "arm_CondJmp_attr_t", }, -# other operations +fpaCmfeBra => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + attr => "int proj_num", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, + attr_type => "arm_CondJmp_attr_t", +}, -"fConst" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents a FP constant", - "reg_req" => { "out" => [ "fp" ] }, - "emit" => '. FMOV %D1, %C /* Mov fConst into register */', - "cmp_attr" => 'return attr_a->value != attr_b->value;' +fpaCnfeBra => { + op_flags => "L|X|Y", + state => "pinned", + mode => "mode_T", + attr => "int proj_num", + init_attr => "\tset_arm_CondJmp_proj_num(res, proj_num);", + reg_req => { in => [ "fpa", "fpa" ], out => [ "none", "none"] }, + attr_type => "arm_CondJmp_attr_t", }, -"fConvD2S" => { - "irn_flags" => "R", - "comment" => "convert double to single", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FCVTSD %D1, %S1 /* Convert double to single */', +fpaLdf => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "gp", "none" ], out => [ "fpa", "none" ] }, + emit => '. ldf%M %D0, [%S0]', + outs => [ "res", "M" ], }, -"fConvS2D" => { - "irn_flags" => "R", - "comment" => "convert single to double", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FCVTDS %D1, %S1 /* Convert single to double */', +fpaStf => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + attr => "ir_mode *op_mode", + init_attr => "attr->op_mode = op_mode;", + reg_req => { in => [ "gp", "fpa", "none" ], out => [ "none" ] }, + emit => '. stf%M %S1, [%S0]', + mode => "mode_M", }, +fpaDbl2GP => { + op_flags => "L|F", + irn_flags => "R", + reg_req => { in => [ "fpa", "none" ], out => [ "gp", "gp", "none" ] }, + outs => [ "low", "high", "M" ], +}, -# Load / Store +AddSP => { + reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "none" ] }, + emit => '. add %D0, %S0, %S1', + outs => [ "stack", "M" ], +}, -"fLoad" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "fp" ] }, - "emit" => '. FLD%Mx %D1, %S1 /* Load((%S1)) -> %D1 */' +SubSPandCopy => { + reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "gp", "none" ] }, + ins => [ "stack", "size", "mem" ], + emit => ". sub %D0, %S0, %S1\n". + ". mov sp, %D1", + outs => [ "stack", "addr", "M" ], }, -"fStore" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "fp", "none" ] }, - "emit" => '. FST%Mx %S2, %S1 /* Store(%S2) -> (%S1), (%A1, %A2) */' +LdTls => { + irn_flags => "R", + reg_req => { out => [ "gp" ] }, }, + +# +# floating point constants +# +fpaConst => { + op_flags => "c", + irn_flags => "R", + attr => "tarval *tv", + init_attr => "attr->tv = tv;", + mode => "get_tarval_mode(tv)", + reg_req => { out => [ "fpa" ] }, + attr_type => "arm_fpaConst_attr_t", +} + ); # end of %nodes