/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. #include "arm-codegen.h"
  29. void arm_emit_std_prologue(cg_segment_t * segment, unsigned int local_size) {
  30. ARM_MOV_REG_REG(segment, ARMREG_IP, ARMREG_SP);
  31. /* save args */
  32. ARM_PUSH(segment, (1 << ARMREG_A1)
  33. | (1 << ARMREG_A2)
  34. | (1 << ARMREG_A3)
  35. | (1 << ARMREG_A4));
  36. ARM_PUSH(segment, (1U << ARMREG_IP) | (1U << ARMREG_LR));
  37. if (local_size != 0) {
  38. if ((local_size & (~0xFF)) == 0) {
  39. ARM_SUB_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
  40. } else {
  41. /* TODO: optimize */
  42. arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
  43. ARM_SUB_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
  44. ARM_ADD_REG_IMM8(segment, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
  45. ARM_LDR_REG_REG(segment, ARMREG_IP, ARMREG_SP, ARMREG_IP);
  46. }
  47. }
  48. }
  49. void arm_emit_std_epilogue(cg_segment_t * segment, unsigned int local_size, int pop_regs) {
  50. if (local_size != 0) {
  51. if ((local_size & (~0xFF)) == 0) {
  52. ARM_ADD_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
  53. } else {
  54. /* TODO: optimize */
  55. arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
  56. ARM_ADD_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
  57. }
  58. }
  59. ARM_POP_NWB(segment, (1 << ARMREG_SP) | (1 << ARMREG_PC) | (pop_regs & 0x3FF));
  60. }
  61. /* do not push A1-A4 */
  62. void arm_emit_lean_prologue(cg_segment_t * segment, unsigned int local_size, int push_regs) {
  63. ARM_MOV_REG_REG(segment, ARMREG_IP, ARMREG_SP);
  64. /* push_regs upto R10 will be saved */
  65. ARM_PUSH(segment, (1U << ARMREG_IP) | (1U << ARMREG_LR) | (push_regs & 0x3FF));
  66. if (local_size != 0) {
  67. if ((local_size & (~0xFF)) == 0) {
  68. ARM_SUB_REG_IMM8(segment, ARMREG_SP, ARMREG_SP, local_size);
  69. } else {
  70. /* TODO: optimize */
  71. arm_mov_reg_imm32(segment, ARMREG_IP, local_size);
  72. ARM_SUB_REG_REG(segment, ARMREG_SP, ARMREG_SP, ARMREG_IP);
  73. /* restore IP from stack */
  74. ARM_ADD_REG_IMM8(segment, ARMREG_IP, ARMREG_IP, sizeof(armword_t));
  75. ARM_LDR_REG_REG(segment, ARMREG_IP, ARMREG_SP, ARMREG_IP);
  76. }
  77. }
  78. }
  79. /* Bit scan forward. */
  80. int arm_bsf(armword_t val) {
  81. int i;
  82. armword_t mask;
  83. if (val == 0) return 0;
  84. for (i=1, mask=1; (i <= 8 * sizeof(armword_t)) && ((val & mask) == 0); ++i, mask<<=1);
  85. return i;
  86. }
  87. int arm_is_power_of_2(armword_t val) {
  88. return ((val & (val-1)) == 0);
  89. }
  90. /*
  91. * returns:
  92. * 1 - unable to represent
  93. * positive even number - MOV-representable
  94. * negative even number - MVN-representable
  95. */
  96. int calc_arm_mov_const_shift(armword_t val) {
  97. armword_t mask;
  98. int res = 1, shift;
  99. for (shift=0; shift < 32; shift+=2) {
  100. mask = ARM_SCALE(0xFF, shift);
  101. if ((val & (~mask)) == 0) {
  102. res = shift;
  103. break;
  104. }
  105. if (((~val) & (~mask)) == 0) {
  106. res = -shift - 2;
  107. break;
  108. }
  109. }
  110. return res;
  111. }
  112. int is_arm_const(armword_t val) {
  113. int res;
  114. res = arm_is_power_of_2(val);
  115. if (!res) {
  116. res = calc_arm_mov_const_shift(val);
  117. res = !(res < 0 || res == 1);
  118. }
  119. return res;
  120. }
  121. int arm_const_steps(armword_t val) {
  122. int shift, steps = 0;
  123. while (val != 0) {
  124. shift = (arm_bsf(val) - 1) & (~1);
  125. val &= ~(0xFF << shift);
  126. ++steps;
  127. }
  128. return steps;
  129. }
  130. /*
  131. * ARM cannot load arbitrary 32-bit constants directly into registers;
  132. * widely used work-around for this is to store constants into a
  133. * PC-addressable pool and use LDR instruction with PC-relative address
  134. * to load constant into register. Easiest way to implement this is to
  135. * embed constant inside a function with unconditional branch around it.
  136. * The above method is not used at the moment.
  137. * This routine always emits sequence of instructions to generate
  138. * requested constant. In the worst case it takes 4 instructions to
  139. * synthesize a constant - 1 MOV and 3 subsequent ORRs.
  140. */
  141. void arm_mov_reg_imm32_cond(cg_segment_t * segment, int reg, armword_t imm32, int cond) {
  142. int mov_op;
  143. int step_op;
  144. int snip;
  145. int shift = calc_arm_mov_const_shift(imm32);
  146. if ((shift & 0x80000001) != 1) {
  147. if (shift >= 0) {
  148. ARM_MOV_REG_IMM_COND(segment, reg, imm32 >> ((32 - shift) & 31), shift, cond);
  149. } else {
  150. ARM_MVN_REG_IMM_COND(segment, reg, (imm32 ^ (~0)) >> ((32 + 2 + shift) & 31), (-shift - 2), cond);
  151. }
  152. } else {
  153. mov_op = ARMOP_MOV;
  154. step_op = ARMOP_ORR;
  155. if (arm_const_steps(imm32) > arm_const_steps(~imm32)) {
  156. mov_op = ARMOP_MVN;
  157. step_op = ARMOP_SUB;
  158. imm32 = ~imm32;
  159. }
  160. shift = (arm_bsf(imm32) - 1) & (~1);
  161. snip = imm32 & (0xFF << shift);
  162. ARM_EMIT(segment, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, 0, 0, mov_op, cond));
  163. while ((imm32 ^= snip) != 0) {
  164. shift = (arm_bsf(imm32) - 1) & (~1);
  165. snip = imm32 & (0xFF << shift);
  166. ARM_EMIT(segment, ARM_DEF_DPI_IMM_COND((unsigned)snip >> shift, (32 - shift) >> 1, reg, reg, 0, step_op, cond));
  167. }
  168. }
  169. }
  170. void arm_mov_reg_imm32(cg_segment_t * segment, int reg, armword_t imm32) {
  171. arm_mov_reg_imm32_cond(segment, reg, imm32, ARMCOND_AL);
  172. }