ARMAssembler.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. /*
  2. * Copyright (C) 2009 University of Szeged
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR
  18. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  21. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include "config.h"
  27. #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)
  28. #include "ARMAssembler.h"
  29. namespace JSC {
  30. // Patching helpers
  31. void ARMAssembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
  32. {
  33. ARMWord *ldr = reinterpret_cast<ARMWord*>(loadAddr);
  34. ARMWord diff = reinterpret_cast<ARMWord*>(constPoolAddr) - ldr;
  35. ARMWord index = (*ldr & 0xfff) >> 1;
  36. ASSERT(diff >= 1);
  37. if (diff >= 2 || index > 0) {
  38. diff = (diff + index - 2) * sizeof(ARMWord);
  39. ASSERT(diff <= 0xfff);
  40. *ldr = (*ldr & ~0xfff) | diff;
  41. } else
  42. *ldr = (*ldr & ~(0xfff | ARMAssembler::DataTransferUp)) | sizeof(ARMWord);
  43. }
  44. // Handle immediates
  45. ARMWord ARMAssembler::getOp2(ARMWord imm)
  46. {
  47. int rol;
  48. if (imm <= 0xff)
  49. return Op2Immediate | imm;
  50. if ((imm & 0xff000000) == 0) {
  51. imm <<= 8;
  52. rol = 8;
  53. }
  54. else {
  55. imm = (imm << 24) | (imm >> 8);
  56. rol = 0;
  57. }
  58. if ((imm & 0xff000000) == 0) {
  59. imm <<= 8;
  60. rol += 4;
  61. }
  62. if ((imm & 0xf0000000) == 0) {
  63. imm <<= 4;
  64. rol += 2;
  65. }
  66. if ((imm & 0xc0000000) == 0) {
  67. imm <<= 2;
  68. rol += 1;
  69. }
  70. if ((imm & 0x00ffffff) == 0)
  71. return Op2Immediate | (imm >> 24) | (rol << 8);
  72. return InvalidImmediate;
  73. }
  74. int ARMAssembler::genInt(int reg, ARMWord imm, bool positive)
  75. {
  76. // Step1: Search a non-immediate part
  77. ARMWord mask;
  78. ARMWord imm1;
  79. ARMWord imm2;
  80. int rol;
  81. mask = 0xff000000;
  82. rol = 8;
  83. while(1) {
  84. if ((imm & mask) == 0) {
  85. imm = (imm << rol) | (imm >> (32 - rol));
  86. rol = 4 + (rol >> 1);
  87. break;
  88. }
  89. rol += 2;
  90. mask >>= 2;
  91. if (mask & 0x3) {
  92. // rol 8
  93. imm = (imm << 8) | (imm >> 24);
  94. mask = 0xff00;
  95. rol = 24;
  96. while (1) {
  97. if ((imm & mask) == 0) {
  98. imm = (imm << rol) | (imm >> (32 - rol));
  99. rol = (rol >> 1) - 8;
  100. break;
  101. }
  102. rol += 2;
  103. mask >>= 2;
  104. if (mask & 0x3)
  105. return 0;
  106. }
  107. break;
  108. }
  109. }
  110. ASSERT((imm & 0xff) == 0);
  111. if ((imm & 0xff000000) == 0) {
  112. imm1 = Op2Immediate | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
  113. imm2 = Op2Immediate | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
  114. } else if (imm & 0xc0000000) {
  115. imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
  116. imm <<= 8;
  117. rol += 4;
  118. if ((imm & 0xff000000) == 0) {
  119. imm <<= 8;
  120. rol += 4;
  121. }
  122. if ((imm & 0xf0000000) == 0) {
  123. imm <<= 4;
  124. rol += 2;
  125. }
  126. if ((imm & 0xc0000000) == 0) {
  127. imm <<= 2;
  128. rol += 1;
  129. }
  130. if ((imm & 0x00ffffff) == 0)
  131. imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
  132. else
  133. return 0;
  134. } else {
  135. if ((imm & 0xf0000000) == 0) {
  136. imm <<= 4;
  137. rol += 2;
  138. }
  139. if ((imm & 0xc0000000) == 0) {
  140. imm <<= 2;
  141. rol += 1;
  142. }
  143. imm1 = Op2Immediate | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
  144. imm <<= 8;
  145. rol += 4;
  146. if ((imm & 0xf0000000) == 0) {
  147. imm <<= 4;
  148. rol += 2;
  149. }
  150. if ((imm & 0xc0000000) == 0) {
  151. imm <<= 2;
  152. rol += 1;
  153. }
  154. if ((imm & 0x00ffffff) == 0)
  155. imm2 = Op2Immediate | (imm >> 24) | ((rol & 0xf) << 8);
  156. else
  157. return 0;
  158. }
  159. if (positive) {
  160. mov(reg, imm1);
  161. orr(reg, reg, imm2);
  162. } else {
  163. mvn(reg, imm1);
  164. bic(reg, reg, imm2);
  165. }
  166. return 1;
  167. }
  168. ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert)
  169. {
  170. ARMWord tmp;
  171. // Do it by 1 instruction
  172. tmp = getOp2(imm);
  173. if (tmp != InvalidImmediate)
  174. return tmp;
  175. tmp = getOp2(~imm);
  176. if (tmp != InvalidImmediate) {
  177. if (invert)
  178. return tmp | Op2InvertedImmediate;
  179. mvn(tmpReg, tmp);
  180. return tmpReg;
  181. }
  182. return encodeComplexImm(imm, tmpReg);
  183. }
  184. void ARMAssembler::moveImm(ARMWord imm, int dest)
  185. {
  186. ARMWord tmp;
  187. // Do it by 1 instruction
  188. tmp = getOp2(imm);
  189. if (tmp != InvalidImmediate) {
  190. mov(dest, tmp);
  191. return;
  192. }
  193. tmp = getOp2(~imm);
  194. if (tmp != InvalidImmediate) {
  195. mvn(dest, tmp);
  196. return;
  197. }
  198. encodeComplexImm(imm, dest);
  199. }
  200. ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest)
  201. {
  202. #if WTF_ARM_ARCH_AT_LEAST(7)
  203. ARMWord tmp = getImm16Op2(imm);
  204. if (tmp != InvalidImmediate) {
  205. movw(dest, tmp);
  206. return dest;
  207. }
  208. movw(dest, getImm16Op2(imm & 0xffff));
  209. movt(dest, getImm16Op2(imm >> 16));
  210. return dest;
  211. #else
  212. // Do it by 2 instruction
  213. if (genInt(dest, imm, true))
  214. return dest;
  215. if (genInt(dest, ~imm, false))
  216. return dest;
  217. ldrImmediate(dest, imm);
  218. return dest;
  219. #endif
  220. }
  221. // Memory load/store helpers
  222. void ARMAssembler::dataTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, int32_t offset)
  223. {
  224. if (offset >= 0) {
  225. if (offset <= 0xfff)
  226. dtrUp(transferType, srcDst, base, offset);
  227. else if (offset <= 0xfffff) {
  228. add(ARMRegisters::S0, base, Op2Immediate | (offset >> 12) | (10 << 8));
  229. dtrUp(transferType, srcDst, ARMRegisters::S0, (offset & 0xfff));
  230. } else {
  231. moveImm(offset, ARMRegisters::S0);
  232. dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  233. }
  234. } else {
  235. if (offset >= -0xfff)
  236. dtrDown(transferType, srcDst, base, -offset);
  237. else if (offset >= -0xfffff) {
  238. sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 12) | (10 << 8));
  239. dtrDown(transferType, srcDst, ARMRegisters::S0, (-offset & 0xfff));
  240. } else {
  241. moveImm(offset, ARMRegisters::S0);
  242. dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  243. }
  244. }
  245. }
  246. void ARMAssembler::baseIndexTransfer32(DataTransferTypeA transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
  247. {
  248. ASSERT(scale >= 0 && scale <= 3);
  249. ARMWord op2 = lsl(index, scale);
  250. if (!offset) {
  251. dtrUpRegister(transferType, srcDst, base, op2);
  252. return;
  253. }
  254. if (offset <= 0xfffff && offset >= -0xfffff) {
  255. add(ARMRegisters::S0, base, op2);
  256. dataTransfer32(transferType, srcDst, ARMRegisters::S0, offset);
  257. return;
  258. }
  259. moveImm(offset, ARMRegisters::S0);
  260. add(ARMRegisters::S0, ARMRegisters::S0, op2);
  261. dtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  262. }
  263. void ARMAssembler::dataTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, int32_t offset)
  264. {
  265. if (offset >= 0) {
  266. if (offset <= 0xff)
  267. halfDtrUp(transferType, srcDst, base, getOp2Half(offset));
  268. else if (offset <= 0xffff) {
  269. add(ARMRegisters::S0, base, Op2Immediate | (offset >> 8) | (12 << 8));
  270. halfDtrUp(transferType, srcDst, ARMRegisters::S0, getOp2Half(offset & 0xff));
  271. } else {
  272. moveImm(offset, ARMRegisters::S0);
  273. halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  274. }
  275. } else {
  276. if (offset >= -0xff)
  277. halfDtrDown(transferType, srcDst, base, getOp2Half(-offset));
  278. else if (offset >= -0xffff) {
  279. sub(ARMRegisters::S0, base, Op2Immediate | (-offset >> 8) | (12 << 8));
  280. halfDtrDown(transferType, srcDst, ARMRegisters::S0, getOp2Half(-offset & 0xff));
  281. } else {
  282. moveImm(offset, ARMRegisters::S0);
  283. halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  284. }
  285. }
  286. }
  287. void ARMAssembler::baseIndexTransfer16(DataTransferTypeB transferType, RegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
  288. {
  289. if (!scale && !offset) {
  290. halfDtrUpRegister(transferType, srcDst, base, index);
  291. return;
  292. }
  293. ARMWord op2 = lsl(index, scale);
  294. if (offset <= 0xffff && offset >= -0xffff) {
  295. add(ARMRegisters::S0, base, op2);
  296. dataTransfer16(transferType, srcDst, ARMRegisters::S0, offset);
  297. return;
  298. }
  299. moveImm(offset, ARMRegisters::S0);
  300. add(ARMRegisters::S0, ARMRegisters::S0, op2);
  301. halfDtrUpRegister(transferType, srcDst, base, ARMRegisters::S0);
  302. }
  303. void ARMAssembler::dataTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, int32_t offset)
  304. {
  305. // VFP cannot directly access memory that is not four-byte-aligned
  306. if (!(offset & 0x3)) {
  307. if (offset <= 0x3ff && offset >= 0) {
  308. doubleDtrUp(transferType, srcDst, base, offset >> 2);
  309. return;
  310. }
  311. if (offset <= 0x3ffff && offset >= 0) {
  312. add(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
  313. doubleDtrUp(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
  314. return;
  315. }
  316. offset = -offset;
  317. if (offset <= 0x3ff && offset >= 0) {
  318. doubleDtrDown(transferType, srcDst, base, offset >> 2);
  319. return;
  320. }
  321. if (offset <= 0x3ffff && offset >= 0) {
  322. sub(ARMRegisters::S0, base, Op2Immediate | (offset >> 10) | (11 << 8));
  323. doubleDtrDown(transferType, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff);
  324. return;
  325. }
  326. offset = -offset;
  327. }
  328. moveImm(offset, ARMRegisters::S0);
  329. add(ARMRegisters::S0, ARMRegisters::S0, base);
  330. doubleDtrUp(transferType, srcDst, ARMRegisters::S0, 0);
  331. }
  332. void ARMAssembler::baseIndexTransferFloat(DataTransferTypeFloat transferType, FPRegisterID srcDst, RegisterID base, RegisterID index, int scale, int32_t offset)
  333. {
  334. add(ARMRegisters::S1, base, lsl(index, scale));
  335. dataTransferFloat(transferType, srcDst, ARMRegisters::S1, offset);
  336. }
  337. PassRefPtr<ExecutableMemoryHandle> ARMAssembler::executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
  338. {
  339. // 64-bit alignment is required for next constant pool and JIT code as well
  340. m_buffer.flushWithoutBarrier(true);
  341. if (!m_buffer.isAligned(8))
  342. bkpt(0);
  343. RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(vm, ownerUID, effort);
  344. char* data = reinterpret_cast<char*>(result->start());
  345. for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
  346. // The last bit is set if the constant must be placed on constant pool.
  347. int pos = (iter->m_offset) & (~0x1);
  348. ARMWord* ldrAddr = reinterpret_cast_ptr<ARMWord*>(data + pos);
  349. ARMWord* addr = getLdrImmAddress(ldrAddr);
  350. if (*addr != InvalidBranchTarget) {
  351. if (!(iter->m_offset & 1)) {
  352. intptr_t difference = reinterpret_cast_ptr<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetchOffset);
  353. if ((difference <= MaximumBranchOffsetDistance && difference >= MinimumBranchOffsetDistance)) {
  354. *ldrAddr = B | getConditionalField(*ldrAddr) | (difference & BranchOffsetMask);
  355. continue;
  356. }
  357. }
  358. *addr = reinterpret_cast<ARMWord>(data + *addr);
  359. }
  360. }
  361. return result;
  362. }
  363. #if OS(LINUX) && COMPILER(RVCT)
  364. __asm void ARMAssembler::cacheFlush(void* code, size_t size)
  365. {
  366. ARM
  367. push {r7}
  368. add r1, r1, r0
  369. mov r7, #0xf0000
  370. add r7, r7, #0x2
  371. mov r2, #0x0
  372. svc #0x0
  373. pop {r7}
  374. bx lr
  375. }
  376. #endif
  377. } // namespace JSC
  378. #endif // ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL)