/** Supported libFirm builtins. */
/** Supported libFirm builtins. */
typedef enum {
+ ir_bk_trap, /**< GCC __builtin_trap(): insert debug break */
ir_bk_return_address, /**< GCC __builtin_return_address() */
ir_bk_frame_addess, /**< GCC __builtin_frame_address() */
ir_bk_prefetch, /**< GCC __builtin_prefetch() */
ir_bk_ctz, /**< GCC __builtin_ctz(): count trailing zero */
ir_bk_popcount, /**< GCC __builtin_popcount(): population count */
ir_bk_parity, /**< GCC __builtin_parity(): parity */
+ ir_bk_bswap, /**< byte swap */
} ir_builtin_kind;
#endif
c->use_sse_prefetch = FLAGS(arch, (arch_feature_3DNowE | arch_feature_sse1));
c->use_3dnow_prefetch = FLAGS(arch, arch_feature_3DNow);
c->use_popcnt = FLAGS(arch, (arch_feature_sse4_2 | arch_feature_sse4a));
+ c->use_i486 = (arch & arch_mask) >= arch_i486;
c->optimize_cc = opt_cc;
c->use_unsafe_floatconv = opt_unsafe_floatconv;
unsigned use_3dnow_prefetch:1;
/** use SSE4.2 or SSE4a popcnt instruction */
unsigned use_popcnt:1;
+ /** use i486 instructions */
+ unsigned use_i486:1;
/** optimize calling convention where possible */
unsigned optimize_cc:1;
/**
* |_| |_|
*************************************************************/
+/**
+ * Emit the name of the 8bit low register
+ */
static void emit_8bit_register(const arch_register_t *reg)
{
const char *reg_name = arch_register_get_name(reg);
be_emit_char('l');
}
+/**
+ * Emit the name of the 8bit high register
+ */
+static void emit_8bit_register_high(const arch_register_t *reg)
+{
+ const char *reg_name = arch_register_get_name(reg);
+
+ be_emit_char('%');
+ be_emit_char(reg_name[1]);
+ be_emit_char('h');
+}
+
static void emit_16bit_register(const arch_register_t *reg)
{
const char *reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
{
const arch_register_t *reg;
- ir_node *in = get_irn_n(node, pos);
+ const ir_node *in = get_irn_n(node, pos);
if (is_ia32_Immediate(in)) {
emit_ia32_Immediate(in);
return;
emit_8bit_register(reg);
}
+void ia32_emit_8bit_high_source_register(const ir_node *node, int pos)
+{
+ const ir_node *in = get_irn_n(node, pos);
+ const arch_register_t *reg = get_in_reg(node, pos);
+ emit_8bit_register_high(reg);
+}
+
void ia32_emit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
void ia32_emit_x87_register(const ir_node *node, int pos);
void ia32_emit_source_register_or_immediate(const ir_node *node, int pos);
void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos);
+void ia32_emit_8bit_high_source_register(const ir_node *node, int pos);
void ia32_emit_mode_suffix(const ir_node *node);
void ia32_emit_x87_mode_suffix(const ir_node *node);
void ia32_emit_xmm_mode_suffix(const ir_node *node);
/** Initializes the Emitter. */
void ia32_init_emitter(void);
-
#endif
S1 => "${arch}_emit_source_register(node, 1);",
S2 => "${arch}_emit_source_register(node, 2);",
S3 => "${arch}_emit_source_register(node, 3);",
+ SB0 => "${arch}_emit_8bit_source_register_or_immediate(node, 0);",
SB1 => "${arch}_emit_8bit_source_register_or_immediate(node, 1);",
SB2 => "${arch}_emit_8bit_source_register_or_immediate(node, 2);",
SB3 => "${arch}_emit_8bit_source_register_or_immediate(node, 3);",
+ SH0 => "${arch}_emit_8bit_high_source_register(node, 0);",
SI1 => "${arch}_emit_source_register_or_immediate(node, 1);",
SI3 => "${arch}_emit_source_register_or_immediate(node, 3);",
D0 => "${arch}_emit_dest_register(node, 0);",
mode => $mode_gp
},
+#
+# bswap
+#
+Bswap => {
+ irn_flags => "R",
+ reg_req => { in => [ "gp" ],
+ out => [ "in_r1" ] },
+ emit => '. bswap%M %S0',
+ ins => [ "val" ],
+ units => [ "GP" ],
+ latency => 1,
+ mode => $mode_gp,
+},
+
+#
+# bswap16, use xchg here
+#
+Bswap16 => {
+ irn_flags => "R",
+ reg_req => { in => [ "eax ebx ecx edx" ],
+ out => [ "in_r1" ] },
+ emit => '. xchg %SB0, %SH0',
+ ins => [ "val" ],
+ units => [ "GP" ],
+ latency => 1,
+ mode => $mode_gp,
+},
+
+#
+# BreakPoint
+#
+Breakpoint => {
+ state => "pinned",
+ reg_req => { in => [ "none" ], out => [ "none" ] },
+ ins => [ "mem" ],
+ latency => 0,
+ emit => ". int3",
+ units => [ "GP" ],
+ mode => mode_M,
+},
+
#
# Intel style prefetching
#
return call;
}
+/**
+ * Transform Builtin trap
+ */
+static ir_node *gen_trap(ir_node *node) {
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *mem = be_transform_node(get_Builtin_mem(node));
+
+ return new_bd_ia32_Breakpoint(dbgi, block, mem);
+}
+
/**
* Transform Builtin return_address
*/
}
/**
- * Transform ...
+ * Transform bsf like node
*/
static ir_node *gen_unop_AM(ir_node *node, construct_binop_dest_func *func)
{
return new_bd_ia32_Lea(dbgi, new_block, m13, s5);
}
+/**
+ * Transform builtin byte swap.
+ */
+static ir_node *gen_bswap(ir_node *node) {
+ ir_node *param = be_transform_node(get_Builtin_param(node, 0));
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_mode *mode = get_irn_mode(param);
+ unsigned size = get_mode_size_bits(mode);
+ ir_node *m1, *m2, *m3, *m4, *s1, *s2, *s3, *s4, *noreg, *nomem;
+
+ switch (size) {
+ case 32:
+ if (ia32_cg_config.use_i486) {
+ /* swap available */
+ return new_bd_ia32_Bswap(dbgi, new_block, param);
+ }
+ s1 = new_bd_ia32_Shl(dbgi, new_block, param, create_Immediate(NULL, 0, 24));
+ s2 = new_bd_ia32_Shl(dbgi, new_block, param, create_Immediate(NULL, 0, 8));
+
+ noreg = ia32_new_NoReg_gp(env_cg);
+ nomem = new_NoMem();
+
+ m1 = new_bd_ia32_And(dbgi, new_block, noreg, noreg, nomem, s2, create_Immediate(NULL, 0, 0xFF00));
+ m2 = new_bd_ia32_Lea(dbgi, new_block, s1, m1);
+
+ s3 = new_bd_ia32_Shr(dbgi, new_block, param, create_Immediate(NULL, 0, 8));
+
+ m3 = new_bd_ia32_And(dbgi, new_block, noreg, noreg, nomem, s3, create_Immediate(NULL, 0, 0xFF0000));
+ m4 = new_bd_ia32_Lea(dbgi, new_block, m2, m3);
+
+ s4 = new_bd_ia32_Shr(dbgi, new_block, param, create_Immediate(NULL, 0, 24));
+ return new_bd_ia32_Lea(dbgi, new_block, m4, s4);
+
+ case 16:
+ /* swap16 always available */
+ return new_bd_ia32_Bswap16(dbgi, new_block, param);
+
+ default:
+ panic("Invalid bswap size (%d)", size);
+ }
+}
+
/**
* Transform Builtin node.
*/
ir_builtin_kind kind = get_Builtin_kind(node);
switch (kind) {
+ case ir_bk_trap:
+ return gen_trap(node);
case ir_bk_return_address:
return gen_return_address(node);
case ir_bk_frame_addess:
return gen_parity(node);
case ir_bk_popcount:
return gen_popcount(node);
+ case ir_bk_bswap:
+ return gen_bswap(node);
}
panic("Builtin %s not implemented in IA32", get_builtin_kind_name(kind));
}
case ir_bk_ctz:
case ir_bk_parity:
case ir_bk_popcount:
+ case ir_bk_bswap:
assert(get_Proj_proj(proj) == pn_Builtin_1_result);
return new_node;
+ case ir_bk_trap:
case ir_bk_prefetch:
assert(get_Proj_proj(proj) == pn_Builtin_M);
return new_node;
const char *get_builtin_kind_name(ir_builtin_kind kind) {
#define X(a) case a: return #a + 6;
switch (kind) {
+ X(ir_bk_trap);
X(ir_bk_return_address);
X(ir_bk_frame_addess);
X(ir_bk_prefetch);
+ X(ir_bk_ffs);
+ X(ir_bk_clz);
+ X(ir_bk_ctz);
+ X(ir_bk_popcount);
+ X(ir_bk_parity);
+ X(ir_bk_bswap);
}
return "<unknown>";
#undef X