+/**
+ * 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;
+
+ 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, ia32_create_Immediate(NULL, 0, 24));
+ s2 = new_bd_ia32_Shl(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
+
+ m1 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s2, ia32_create_Immediate(NULL, 0, 0xFF00));
+ m2 = new_bd_ia32_Lea(dbgi, new_block, s1, m1);
+
+ s3 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_create_Immediate(NULL, 0, 8));
+
+ m3 = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, s3, ia32_create_Immediate(NULL, 0, 0xFF0000));
+ m4 = new_bd_ia32_Lea(dbgi, new_block, m2, m3);
+
+ s4 = new_bd_ia32_Shr(dbgi, new_block, param, ia32_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 outport.
+ */
+static ir_node *gen_outport(ir_node *node)
+{
+ ir_node *port = create_immediate_or_transform(get_Builtin_param(node, 0), 0);
+ ir_node *oldv = get_Builtin_param(node, 1);
+ ir_mode *mode = get_irn_mode(oldv);
+ ir_node *value = be_transform_node(oldv);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *mem = be_transform_node(get_Builtin_mem(node));
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ ir_node *res = new_bd_ia32_Outport(dbgi, block, port, value, mem);
+ set_ia32_ls_mode(res, mode);
+ return res;
+}
+
+/**
+ * Transform builtin inport.
+ */
+static ir_node *gen_inport(ir_node *node)
+{
+ ir_type *tp = get_Builtin_type(node);
+ ir_type *rstp = get_method_res_type(tp, 0);
+ ir_mode *mode = get_type_mode(rstp);
+ ir_node *port = create_immediate_or_transform(get_Builtin_param(node, 0), 0);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *mem = be_transform_node(get_Builtin_mem(node));
+ dbg_info *dbgi = get_irn_dbg_info(node);
+
+ ir_node *res = new_bd_ia32_Inport(dbgi, block, port, mem);
+ set_ia32_ls_mode(res, mode);
+
+ /* check for missing Result Proj */
+ return res;
+}
+
+/**
+ * Transform a builtin inner trampoline
+ */
+static ir_node *gen_inner_trampoline(ir_node *node)
+{
+ ir_node *ptr = get_Builtin_param(node, 0);
+ ir_node *callee = get_Builtin_param(node, 1);
+ ir_node *env = be_transform_node(get_Builtin_param(node, 2));
+ ir_node *mem = get_Builtin_mem(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *val;
+ ir_node *store;
+ ir_node *rel;
+ ir_node *trampoline;
+ ir_node *in[2];
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ia32_address_t addr;
+
+ /* construct store address */
+ memset(&addr, 0, sizeof(addr));
+ ia32_create_address_mode(&addr, ptr, 0);
+
+ if (addr.base == NULL) {
+ addr.base = noreg_GP;
+ } else {
+ addr.base = be_transform_node(addr.base);
+ }
+
+ if (addr.index == NULL) {
+ addr.index = noreg_GP;
+ } else {
+ addr.index = be_transform_node(addr.index);
+ }
+ addr.mem = be_transform_node(mem);
+
+ /* mov ecx, <env> */
+ val = ia32_create_Immediate(NULL, 0, 0xB9);
+ store = new_bd_ia32_Store8Bit(dbgi, new_block, addr.base,
+ addr.index, addr.mem, val);
+ set_irn_pinned(store, get_irn_pinned(node));
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_ls_mode(store, mode_Bu);
+ set_address(store, &addr);
+ addr.mem = store;
+ addr.offset += 1;
+
+ store = new_bd_ia32_Store(dbgi, new_block, addr.base,
+ addr.index, addr.mem, env);
+ set_irn_pinned(store, get_irn_pinned(node));
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_ls_mode(store, mode_Iu);
+ set_address(store, &addr);
+ addr.mem = store;
+ addr.offset += 4;
+
+ /* jmp rel <callee> */
+ val = ia32_create_Immediate(NULL, 0, 0xE9);
+ store = new_bd_ia32_Store8Bit(dbgi, new_block, addr.base,
+ addr.index, addr.mem, val);
+ set_irn_pinned(store, get_irn_pinned(node));
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_ls_mode(store, mode_Bu);
+ set_address(store, &addr);
+ addr.mem = store;
+ addr.offset += 1;
+
+ trampoline = be_transform_node(ptr);
+
+ /* the callee is typically an immediate */
+ if (is_SymConst(callee)) {
+ rel = new_bd_ia32_Const(dbgi, new_block, get_SymConst_entity(callee), 0, 0, -10);
+ } else {
+ rel = new_bd_ia32_Lea(dbgi, new_block, be_transform_node(callee), ia32_create_Immediate(NULL, 0, -10));
+ }
+ rel = new_bd_ia32_Sub(dbgi, new_block, noreg_GP, noreg_GP, nomem, rel, trampoline);
+
+ store = new_bd_ia32_Store(dbgi, new_block, addr.base,
+ addr.index, addr.mem, rel);
+ set_irn_pinned(store, get_irn_pinned(node));
+ set_ia32_op_type(store, ia32_AddrModeD);
+ set_ia32_ls_mode(store, mode_Iu);
+ set_address(store, &addr);
+
+ in[0] = store;
+ in[1] = trampoline;
+
+ return new_r_Tuple(new_block, 2, in);
+}
+