1 /*
2  * Copyright (C) 1995-2010 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19 
20 /**
21  * @file
22  * @brief    Sparc 64bit lowering
23  * @author   Matthias Braun
24  */
25 #include "config.h"
26 
27 #include "bearch_sparc_t.h"
28 #include "gen_sparc_new_nodes.h"
29 #include "lower_dw.h"
30 #include "ircons_t.h"
31 #include "util.h"
32 
lower64_add(ir_node * node,ir_mode * mode)33 static void lower64_add(ir_node *node, ir_mode *mode)
34 {
35 	dbg_info *dbgi       = get_irn_dbg_info(node);
36 	ir_node  *block      = get_nodes_block(node);
37 	ir_node  *left       = get_Add_left(node);
38 	ir_node  *right      = get_Add_right(node);
39 	ir_node  *left_low   = get_lowered_low(left);
40 	ir_node  *left_high  = get_lowered_high(left);
41 	ir_node  *right_low  = get_lowered_low(right);
42 	ir_node  *right_high = get_lowered_high(right);
43 	ir_node  *addcc      = new_bd_sparc_AddCC_t(dbgi, block, left_low,
44 	                                            right_low);
45 	ir_node  *res_low    = new_r_Proj(addcc, mode_Iu, pn_sparc_AddCC_t_res);
46 	ir_node  *res_flags  = new_r_Proj(addcc, mode_ANY, pn_sparc_AddCC_t_flags);
47 	ir_node  *addx       = new_bd_sparc_AddX_t(dbgi, block, left_high,
48 	                                           right_high, res_flags, mode);
49 	ir_set_dw_lowered(node, res_low, addx);
50 }
51 
lower64_sub(ir_node * node,ir_mode * mode)52 static void lower64_sub(ir_node *node, ir_mode *mode)
53 {
54 	dbg_info *dbgi       = get_irn_dbg_info(node);
55 	ir_node  *block      = get_nodes_block(node);
56 	ir_node  *left       = get_Sub_left(node);
57 	ir_node  *right      = get_Sub_right(node);
58 	ir_node  *left_low   = get_lowered_low(left);
59 	ir_node  *left_high  = get_lowered_high(left);
60 	ir_node  *right_low  = get_lowered_low(right);
61 	ir_node  *right_high = get_lowered_high(right);
62 	ir_node  *subcc      = new_bd_sparc_SubCC_t(dbgi, block, left_low,
63 	                                            right_low);
64 	ir_node  *res_low    = new_r_Proj(subcc, mode_Iu, pn_sparc_SubCC_t_res);
65 	ir_node  *res_flags  = new_r_Proj(subcc, mode_ANY, pn_sparc_SubCC_t_flags);
66 	ir_node  *subx       = new_bd_sparc_SubX_t(dbgi, block, left_high,
67 	                                           right_high, res_flags, mode);
68 	ir_set_dw_lowered(node, res_low, subx);
69 }
70 
lower64_minus(ir_node * node,ir_mode * mode)71 static void lower64_minus(ir_node *node, ir_mode *mode)
72 {
73 	dbg_info *dbgi         = get_irn_dbg_info(node);
74 	ir_graph *irg          = get_irn_irg(node);
75 	ir_node  *block        = get_nodes_block(node);
76 	ir_node  *op           = get_Minus_op(node);
77 	ir_node  *right_low    = get_lowered_low(op);
78 	ir_node  *right_high   = get_lowered_high(op);
79 	ir_mode  *low_unsigned = get_irn_mode(right_low);
80 	ir_node  *left_low     = new_r_Const(irg, get_mode_null(low_unsigned));
81 	ir_node  *left_high    = new_r_Const(irg, get_mode_null(mode));
82 	ir_node  *subcc        = new_bd_sparc_SubCC_t(dbgi, block, left_low,
83 	                                              right_low);
84 	ir_node  *res_low      = new_r_Proj(subcc, mode_Iu, pn_sparc_SubCC_t_res);
85 	ir_node  *res_flags    = new_r_Proj(subcc, mode_ANY, pn_sparc_SubCC_t_flags);
86 	ir_node  *subx         = new_bd_sparc_SubX_t(dbgi, block, left_high,
87 	                                             right_high, res_flags, mode);
88 	ir_set_dw_lowered(node, res_low, subx);
89 }
90 
create_64_intrinsic_fkt(ir_type * method,const ir_op * op,const ir_mode * imode,const ir_mode * omode,void * context)91 static ir_entity *create_64_intrinsic_fkt(ir_type *method, const ir_op *op,
92                                           const ir_mode *imode,
93                                           const ir_mode *omode, void *context)
94 {
95 	ir_type    *glob = get_glob_type();
96 	const char *name;
97 	ident      *id;
98 	ir_entity  *result;
99 	(void) context;
100 	(void) omode;
101 
102 	if (op == op_Mul) {
103 		name = "__muldi3";
104 	} else if (op == op_Div) {
105 		name = mode_is_signed(imode) ? "__divdi3" : "__udivdi3";
106 	} else if (op == op_Mod) {
107 		name = mode_is_signed(imode) ? "__moddi3" : "__umoddi3";
108 	} else if (op == op_Conv) {
109 		if (mode_is_float(imode)) {
110 			assert(get_mode_size_bits(omode) == 64);
111 			if (get_mode_size_bits(imode) == 64) {
112 				name = mode_is_signed(omode) ? "__fixdfdi" : "__fixunsdfdi";
113 			} else if (get_mode_size_bits(imode) == 32) {
114 				name = mode_is_signed(omode) ? "__fixsfdi" : "__fixunssfdi";
115 			} else {
116 				assert(get_mode_size_bits(imode) == 128);
117 				panic("can't conver long double to long long yet");
118 			}
119 		} else if (mode_is_float(omode)) {
120 			assert(get_mode_size_bits(imode) == 64);
121 			if (get_mode_size_bits(omode) == 64) {
122 				name = mode_is_signed(imode) ? "__floatdidf" : "__floatundidf";
123 			} else if (get_mode_size_bits(omode) == 32) {
124 				name = mode_is_signed(imode) ? "__floatdisf" : "__floatundisf";
125 			} else {
126 				assert(get_mode_size_bits(omode) == 128);
127 				panic("can't convert long long to long double yet");
128 			}
129 		} else {
130 			panic("can't lower 64bit Conv");
131 		}
132 	} else {
133 		panic("Can't lower unexpected 64bit operation %s", get_op_name(op));
134 	}
135 	id     = new_id_from_str(name);
136 	result = new_entity(glob, id, method);
137 	set_entity_ld_ident(result, id);
138 	set_entity_visibility(result, ir_visibility_external);
139 	return result;
140 }
141 
sparc_lower_64bit(void)142 void sparc_lower_64bit(void)
143 {
144 	lwrdw_param_t lower_dw_params = {
145 		0,  /* big endian */
146 		64, /* doubleword size */
147 		create_64_intrinsic_fkt,
148 		NULL
149 	};
150 
151 	/* make sure opcodes are initialized */
152 	sparc_create_opcodes(&sparc_irn_ops);
153 
154 	ir_prepare_dw_lowering(&lower_dw_params);
155 	ir_register_dw_lower_function(op_Add,   lower64_add);
156 	ir_register_dw_lower_function(op_Minus, lower64_minus);
157 	ir_register_dw_lower_function(op_Sub,   lower64_sub);
158 	ir_lower_dw_ops();
159 }
160