PageRenderTime 63ms CodeModel.GetById 30ms app.highlight 14ms RepoModel.GetById 16ms app.codeStats 1ms

/opengles/src/codegen/arm-codegen.c

http://ftk.googlecode.com/
C | 208 lines | 120 code | 36 blank | 52 comment | 39 complexity | 560592e601db1b44d73ccdbf999fb679 MD5 | raw file
  1/*
  2 * arm-codegen.c
  3 * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
  4 *
  5 * Copyright (c) 2002 Wild West Software
  6 * Copyright (c) 2001, 2002 Sergey Chaban
  7 * 
  8 * Permission is hereby granted, free of charge, to any person
  9 * obtaining a copy of this software and associated documentation
 10 * files (the "Software"), to deal in the Software without restriction,
 11 * including without limitation the rights to use, copy, modify, merge,
 12 * publish, distribute, sublicense, and/or sell copies of the Software,
 13 * and to permit persons to whom the Software is furnished to do so,
 14 * subject to the following conditions:
 15 * 
 16 * The above copyright notice and this permission notice shall be included
 17 * in all copies or substantial portions of the Software.
 18 * 
 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
 25 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 26 *
 27 */
 28
 29#include "arm-codegen.h"
 30
 31
 32void arm_emit_std_prologue(cg_segment_t * segment, unsigned int local_size) {
 33	ARM_MOV_REG_REG(segment, ARMREG_IP, ARMREG_SP);
 34
 35	/* save args */
 36	ARM_PUSH(segment,   (1 << ARMREG_A1)
 37	            | (1 << ARMREG_A2)
 38	            | (1 << ARMREG_A3)
 39	            | (1 << ARMREG_A4));
 40
 41	ARM_PUSH(segment, (1U << ARMREG_IP) | (1U << ARMREG_LR));
 42
 43	if (local_size != 0) {
 44		if ((local_size & (~0xFF)) == 0) {
 45			ARM_SUB_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
 46		} else {
 47			/* TODO: optimize */
 48			arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
 49			ARM_SUB_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
 50			ARM_ADD_REG_IMM8(segment, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
 51			ARM_LDR_REG_REG(segment, ARMREG_IP, ARMREG_SP, ARMREG_IP);
 52		}
 53	}
 54}
 55
 56void arm_emit_std_epilogue(cg_segment_t * segment, unsigned int local_size, int pop_regs) {
 57	if (local_size != 0) {
 58		if ((local_size & (~0xFF)) == 0) {
 59			ARM_ADD_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
 60		} else {
 61			/* TODO: optimize */
 62			arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
 63			ARM_ADD_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
 64		}
 65	}
 66
 67	ARM_POP_NWB(segment, (1 << ARMREG_SP) | (1 << ARMREG_PC) | (pop_regs & 0x3FF));
 68}
 69
 70
 71/* do not push A1-A4 */
 72void arm_emit_lean_prologue(cg_segment_t * segment, unsigned int local_size, int push_regs) {
 73	ARM_MOV_REG_REG(segment, ARMREG_IP, ARMREG_SP);
 74	/* push_regs upto R10 will be saved */
 75	ARM_PUSH(segment, (1U << ARMREG_IP) | (1U << ARMREG_LR) | (push_regs & 0x3FF));
 76
 77	if (local_size != 0) {
 78		if ((local_size & (~0xFF)) == 0) {
 79			ARM_SUB_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
 80		} else {
 81			/* TODO: optimize */
 82			arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
 83			ARM_SUB_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
 84			/* restore IP from stack */
 85			ARM_ADD_REG_IMM8(segment, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
 86			ARM_LDR_REG_REG(segment, ARMREG_IP, ARMREG_SP, ARMREG_IP);
 87		}
 88	}
 89}
 90
 91/* Bit scan forward. */
 92int arm_bsf(armword_t val) {
 93	int i;
 94	armword_t mask;
 95
 96	if (val == 0) return 0;
 97	for (i=1, mask=1; (i <= 8 * sizeof(armword_t)) && ((val & mask) == 0); ++i, mask<<=1);
 98
 99	return i;
100}
101
102
103int arm_is_power_of_2(armword_t val) {
104	return ((val & (val-1)) == 0);
105}
106
107
108/*
109 * returns:
110 *   1 - unable to represent
111 *   positive even number - MOV-representable
112 *   negative even number - MVN-representable
113 */
114int calc_arm_mov_const_shift(armword_t val) {
115	armword_t mask;
116	int res = 1, shift;
117
118	for (shift=0; shift < 32; shift+=2) {
119		mask = ARM_SCALE(0xFF, shift);
120		if ((val & (~mask)) == 0) {
121			res = shift;
122			break;
123		}
124		if (((~val) & (~mask)) == 0) {
125			res = -shift - 2;
126			break;
127		}
128	}
129
130	return res;
131}
132
133
134int is_arm_const(armword_t val) {
135	int res;
136	res = arm_is_power_of_2(val);
137	if (!res) {
138		res = calc_arm_mov_const_shift(val);
139		res = !(res < 0 || res == 1);
140	}
141	return res;
142}
143
144
145int arm_const_steps(armword_t val) {
146	int shift, steps = 0;
147
148	while (val != 0) {
149		shift = (arm_bsf(val) - 1) & (~1);
150		val &= ~(0xFF << shift);
151		++steps;
152	}
153	return steps;
154}
155
156
157/*
158 * ARM cannot load arbitrary 32-bit constants directly into registers;
159 * widely used work-around for this is to store constants into a
160 * PC-addressable pool and use LDR instruction with PC-relative address
161 * to load constant into register. Easiest way to implement this is to
162 * embed constant inside a function with unconditional branch around it.
163 * The above method is not used at the moment.
164 * This routine always emits sequence of instructions to generate
165 * requested constant. In the worst case it takes 4 instructions to
166 * synthesize a constant - 1 MOV and 3 subsequent ORRs.
167 */
168void arm_mov_reg_imm32_cond(cg_segment_t * segment, int reg, armword_t imm32, int cond) {
169	int mov_op;
170	int step_op;
171	int snip;
172	int shift = calc_arm_mov_const_shift(imm32);
173
174	if ((shift & 0x80000001) != 1) {
175		if (shift >= 0) {
176			ARM_MOV_REG_IMM_COND(segment, reg, imm32 >> ((32 - shift) & 31), shift, cond);
177		} else {
178			ARM_MVN_REG_IMM_COND(segment, reg, (imm32 ^ (~0)) >> ((32 + 2 + shift) & 31), (-shift - 2), cond);
179		}
180	} else {
181		mov_op = ARMOP_MOV;
182		step_op = ARMOP_ORR;
183
184		if (arm_const_steps(imm32) > arm_const_steps(~imm32)) {
185			mov_op = ARMOP_MVN;
186			step_op = ARMOP_SUB;
187			imm32 = ~imm32;
188		}
189
190		shift = (arm_bsf(imm32) - 1) & (~1);
191		snip = imm32 & (0xFF << shift);
192		ARM_EMIT(segment, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, 0, 0, mov_op, cond));
193
194		while ((imm32 ^= snip) != 0) {
195			shift = (arm_bsf(imm32) - 1) & (~1);
196			snip = imm32 & (0xFF << shift);
197			ARM_EMIT(segment, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, reg, 0, step_op, cond));
198		}
199	}
200}
201
202
203void arm_mov_reg_imm32(cg_segment_t * segment, int reg, armword_t imm32) {
204	arm_mov_reg_imm32_cond(segment, reg, imm32, ARMCOND_AL);
205}
206
207
208