/src/3rdparty/webkit/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h

https://bitbucket.org/ultra_iter/qt-vtl · C Header · 1795 lines · 1248 code · 166 blank · 381 comment · 315 complexity · 748633886db70f008753eab6caf345c5 MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 Apple Inc. All rights reserved.
  3. * Copyright (C) 2010 MIPS Technologies, Inc. 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 MIPS TECHNOLOGIES, INC. ``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 MIPS TECHNOLOGIES, INC. 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. #ifndef MacroAssemblerMIPS_h
  27. #define MacroAssemblerMIPS_h
  28. #if ENABLE(ASSEMBLER) && CPU(MIPS)
  29. #include "MIPSAssembler.h"
  30. #include "AbstractMacroAssembler.h"
  31. namespace JSC {
  32. class MacroAssemblerMIPS : public AbstractMacroAssembler<MIPSAssembler> {
  33. public:
  34. typedef MIPSRegisters::FPRegisterID FPRegisterID;
  35. MacroAssemblerMIPS()
  36. : m_fixedWidth(false)
  37. {
  38. }
  39. static const Scale ScalePtr = TimesFour;
  40. // For storing immediate number
  41. static const RegisterID immTempRegister = MIPSRegisters::t0;
  42. // For storing data loaded from the memory
  43. static const RegisterID dataTempRegister = MIPSRegisters::t1;
  44. // For storing address base
  45. static const RegisterID addrTempRegister = MIPSRegisters::t2;
  46. // For storing compare result
  47. static const RegisterID cmpTempRegister = MIPSRegisters::t3;
  48. // FP temp register
  49. static const FPRegisterID fpTempRegister = MIPSRegisters::f16;
  50. enum RelationalCondition {
  51. Equal,
  52. NotEqual,
  53. Above,
  54. AboveOrEqual,
  55. Below,
  56. BelowOrEqual,
  57. GreaterThan,
  58. GreaterThanOrEqual,
  59. LessThan,
  60. LessThanOrEqual
  61. };
  62. enum ResultCondition {
  63. Overflow,
  64. Signed,
  65. Zero,
  66. NonZero
  67. };
  68. enum DoubleCondition {
  69. DoubleEqual,
  70. DoubleNotEqual,
  71. DoubleGreaterThan,
  72. DoubleGreaterThanOrEqual,
  73. DoubleLessThan,
  74. DoubleLessThanOrEqual,
  75. DoubleEqualOrUnordered,
  76. DoubleNotEqualOrUnordered,
  77. DoubleGreaterThanOrUnordered,
  78. DoubleGreaterThanOrEqualOrUnordered,
  79. DoubleLessThanOrUnordered,
  80. DoubleLessThanOrEqualOrUnordered
  81. };
  82. static const RegisterID stackPointerRegister = MIPSRegisters::sp;
  83. static const RegisterID returnAddressRegister = MIPSRegisters::ra;
  84. // Integer arithmetic operations:
  85. //
  86. // Operations are typically two operand - operation(source, srcDst)
  87. // For many operations the source may be an TrustedImm32, the srcDst operand
  88. // may often be a memory location (explictly described using an Address
  89. // object).
  90. void add32(RegisterID src, RegisterID dest)
  91. {
  92. m_assembler.addu(dest, dest, src);
  93. }
  94. void add32(TrustedImm32 imm, RegisterID dest)
  95. {
  96. add32(imm, dest, dest);
  97. }
  98. void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
  99. {
  100. if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
  101. && !m_fixedWidth) {
  102. /*
  103. addiu dest, src, imm
  104. */
  105. m_assembler.addiu(dest, src, imm.m_value);
  106. } else {
  107. /*
  108. li immTemp, imm
  109. addu dest, src, immTemp
  110. */
  111. move(imm, immTempRegister);
  112. m_assembler.addu(dest, src, immTempRegister);
  113. }
  114. }
  115. void add32(TrustedImm32 imm, Address address)
  116. {
  117. if (address.offset >= -32768 && address.offset <= 32767
  118. && !m_fixedWidth) {
  119. /*
  120. lw dataTemp, offset(base)
  121. li immTemp, imm
  122. addu dataTemp, dataTemp, immTemp
  123. sw dataTemp, offset(base)
  124. */
  125. m_assembler.lw(dataTempRegister, address.base, address.offset);
  126. if (!imm.m_isPointer
  127. && imm.m_value >= -32768 && imm.m_value <= 32767
  128. && !m_fixedWidth)
  129. m_assembler.addiu(dataTempRegister, dataTempRegister,
  130. imm.m_value);
  131. else {
  132. move(imm, immTempRegister);
  133. m_assembler.addu(dataTempRegister, dataTempRegister,
  134. immTempRegister);
  135. }
  136. m_assembler.sw(dataTempRegister, address.base, address.offset);
  137. } else {
  138. /*
  139. lui addrTemp, (offset + 0x8000) >> 16
  140. addu addrTemp, addrTemp, base
  141. lw dataTemp, (offset & 0xffff)(addrTemp)
  142. li immtemp, imm
  143. addu dataTemp, dataTemp, immTemp
  144. sw dataTemp, (offset & 0xffff)(addrTemp)
  145. */
  146. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  147. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  148. m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
  149. if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth)
  150. m_assembler.addiu(dataTempRegister, dataTempRegister,
  151. imm.m_value);
  152. else {
  153. move(imm, immTempRegister);
  154. m_assembler.addu(dataTempRegister, dataTempRegister,
  155. immTempRegister);
  156. }
  157. m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
  158. }
  159. }
  160. void add32(Address src, RegisterID dest)
  161. {
  162. load32(src, dataTempRegister);
  163. add32(dataTempRegister, dest);
  164. }
  165. void add32(RegisterID src, Address dest)
  166. {
  167. if (dest.offset >= -32768 && dest.offset <= 32767 && !m_fixedWidth) {
  168. /*
  169. lw dataTemp, offset(base)
  170. addu dataTemp, dataTemp, src
  171. sw dataTemp, offset(base)
  172. */
  173. m_assembler.lw(dataTempRegister, dest.base, dest.offset);
  174. m_assembler.addu(dataTempRegister, dataTempRegister, src);
  175. m_assembler.sw(dataTempRegister, dest.base, dest.offset);
  176. } else {
  177. /*
  178. lui addrTemp, (offset + 0x8000) >> 16
  179. addu addrTemp, addrTemp, base
  180. lw dataTemp, (offset & 0xffff)(addrTemp)
  181. addu dataTemp, dataTemp, src
  182. sw dataTemp, (offset & 0xffff)(addrTemp)
  183. */
  184. m_assembler.lui(addrTempRegister, (dest.offset + 0x8000) >> 16);
  185. m_assembler.addu(addrTempRegister, addrTempRegister, dest.base);
  186. m_assembler.lw(dataTempRegister, addrTempRegister, dest.offset);
  187. m_assembler.addu(dataTempRegister, dataTempRegister, src);
  188. m_assembler.sw(dataTempRegister, addrTempRegister, dest.offset);
  189. }
  190. }
  191. void add32(TrustedImm32 imm, AbsoluteAddress address)
  192. {
  193. /*
  194. li addrTemp, address
  195. li immTemp, imm
  196. lw dataTemp, 0(addrTemp)
  197. addu dataTemp, dataTemp, immTemp
  198. sw dataTemp, 0(addrTemp)
  199. */
  200. move(TrustedImmPtr(address.m_ptr), addrTempRegister);
  201. m_assembler.lw(dataTempRegister, addrTempRegister, 0);
  202. if (!imm.m_isPointer && imm.m_value >= -32768 && imm.m_value <= 32767
  203. && !m_fixedWidth)
  204. m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
  205. else {
  206. move(imm, immTempRegister);
  207. m_assembler.addu(dataTempRegister, dataTempRegister, immTempRegister);
  208. }
  209. m_assembler.sw(dataTempRegister, addrTempRegister, 0);
  210. }
  211. void and32(RegisterID src, RegisterID dest)
  212. {
  213. m_assembler.andInsn(dest, dest, src);
  214. }
  215. void and32(TrustedImm32 imm, RegisterID dest)
  216. {
  217. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
  218. move(MIPSRegisters::zero, dest);
  219. else if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
  220. && !m_fixedWidth)
  221. m_assembler.andi(dest, dest, imm.m_value);
  222. else {
  223. /*
  224. li immTemp, imm
  225. and dest, dest, immTemp
  226. */
  227. move(imm, immTempRegister);
  228. m_assembler.andInsn(dest, dest, immTempRegister);
  229. }
  230. }
  231. void lshift32(TrustedImm32 imm, RegisterID dest)
  232. {
  233. m_assembler.sll(dest, dest, imm.m_value);
  234. }
  235. void lshift32(RegisterID shiftAmount, RegisterID dest)
  236. {
  237. m_assembler.sllv(dest, dest, shiftAmount);
  238. }
  239. void mul32(RegisterID src, RegisterID dest)
  240. {
  241. m_assembler.mul(dest, dest, src);
  242. }
  243. void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
  244. {
  245. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
  246. move(MIPSRegisters::zero, dest);
  247. else if (!imm.m_isPointer && imm.m_value == 1 && !m_fixedWidth)
  248. move(src, dest);
  249. else {
  250. /*
  251. li dataTemp, imm
  252. mul dest, src, dataTemp
  253. */
  254. move(imm, dataTempRegister);
  255. m_assembler.mul(dest, src, dataTempRegister);
  256. }
  257. }
  258. void neg32(RegisterID srcDest)
  259. {
  260. m_assembler.subu(srcDest, MIPSRegisters::zero, srcDest);
  261. }
  262. void not32(RegisterID srcDest)
  263. {
  264. m_assembler.nor(srcDest, srcDest, MIPSRegisters::zero);
  265. }
  266. void or32(RegisterID src, RegisterID dest)
  267. {
  268. m_assembler.orInsn(dest, dest, src);
  269. }
  270. void or32(TrustedImm32 imm, RegisterID dest)
  271. {
  272. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
  273. return;
  274. if (!imm.m_isPointer && imm.m_value > 0 && imm.m_value < 65535
  275. && !m_fixedWidth) {
  276. m_assembler.ori(dest, dest, imm.m_value);
  277. return;
  278. }
  279. /*
  280. li dataTemp, imm
  281. or dest, dest, dataTemp
  282. */
  283. move(imm, dataTempRegister);
  284. m_assembler.orInsn(dest, dest, dataTempRegister);
  285. }
  286. void rshift32(RegisterID shiftAmount, RegisterID dest)
  287. {
  288. m_assembler.srav(dest, dest, shiftAmount);
  289. }
  290. void rshift32(TrustedImm32 imm, RegisterID dest)
  291. {
  292. m_assembler.sra(dest, dest, imm.m_value);
  293. }
  294. void urshift32(RegisterID shiftAmount, RegisterID dest)
  295. {
  296. m_assembler.srlv(dest, dest, shiftAmount);
  297. }
  298. void urshift32(TrustedImm32 imm, RegisterID dest)
  299. {
  300. m_assembler.srl(dest, dest, imm.m_value);
  301. }
  302. void sub32(RegisterID src, RegisterID dest)
  303. {
  304. m_assembler.subu(dest, dest, src);
  305. }
  306. void sub32(TrustedImm32 imm, RegisterID dest)
  307. {
  308. if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
  309. && !m_fixedWidth) {
  310. /*
  311. addiu dest, src, imm
  312. */
  313. m_assembler.addiu(dest, dest, -imm.m_value);
  314. } else {
  315. /*
  316. li immTemp, imm
  317. subu dest, src, immTemp
  318. */
  319. move(imm, immTempRegister);
  320. m_assembler.subu(dest, dest, immTempRegister);
  321. }
  322. }
  323. void sub32(TrustedImm32 imm, Address address)
  324. {
  325. if (address.offset >= -32768 && address.offset <= 32767
  326. && !m_fixedWidth) {
  327. /*
  328. lw dataTemp, offset(base)
  329. li immTemp, imm
  330. subu dataTemp, dataTemp, immTemp
  331. sw dataTemp, offset(base)
  332. */
  333. m_assembler.lw(dataTempRegister, address.base, address.offset);
  334. if (!imm.m_isPointer
  335. && imm.m_value >= -32767 && imm.m_value <= 32768
  336. && !m_fixedWidth)
  337. m_assembler.addiu(dataTempRegister, dataTempRegister,
  338. -imm.m_value);
  339. else {
  340. move(imm, immTempRegister);
  341. m_assembler.subu(dataTempRegister, dataTempRegister,
  342. immTempRegister);
  343. }
  344. m_assembler.sw(dataTempRegister, address.base, address.offset);
  345. } else {
  346. /*
  347. lui addrTemp, (offset + 0x8000) >> 16
  348. addu addrTemp, addrTemp, base
  349. lw dataTemp, (offset & 0xffff)(addrTemp)
  350. li immtemp, imm
  351. subu dataTemp, dataTemp, immTemp
  352. sw dataTemp, (offset & 0xffff)(addrTemp)
  353. */
  354. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  355. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  356. m_assembler.lw(dataTempRegister, addrTempRegister, address.offset);
  357. if (!imm.m_isPointer
  358. && imm.m_value >= -32767 && imm.m_value <= 32768
  359. && !m_fixedWidth)
  360. m_assembler.addiu(dataTempRegister, dataTempRegister,
  361. -imm.m_value);
  362. else {
  363. move(imm, immTempRegister);
  364. m_assembler.subu(dataTempRegister, dataTempRegister,
  365. immTempRegister);
  366. }
  367. m_assembler.sw(dataTempRegister, addrTempRegister, address.offset);
  368. }
  369. }
  370. void sub32(Address src, RegisterID dest)
  371. {
  372. load32(src, dataTempRegister);
  373. sub32(dataTempRegister, dest);
  374. }
  375. void sub32(TrustedImm32 imm, AbsoluteAddress address)
  376. {
  377. /*
  378. li addrTemp, address
  379. li immTemp, imm
  380. lw dataTemp, 0(addrTemp)
  381. subu dataTemp, dataTemp, immTemp
  382. sw dataTemp, 0(addrTemp)
  383. */
  384. move(TrustedImmPtr(address.m_ptr), addrTempRegister);
  385. m_assembler.lw(dataTempRegister, addrTempRegister, 0);
  386. if (!imm.m_isPointer && imm.m_value >= -32767 && imm.m_value <= 32768
  387. && !m_fixedWidth) {
  388. m_assembler.addiu(dataTempRegister, dataTempRegister,
  389. -imm.m_value);
  390. } else {
  391. move(imm, immTempRegister);
  392. m_assembler.subu(dataTempRegister, dataTempRegister, immTempRegister);
  393. }
  394. m_assembler.sw(dataTempRegister, addrTempRegister, 0);
  395. }
  396. void xor32(RegisterID src, RegisterID dest)
  397. {
  398. m_assembler.xorInsn(dest, dest, src);
  399. }
  400. void xor32(TrustedImm32 imm, RegisterID dest)
  401. {
  402. /*
  403. li immTemp, imm
  404. xor dest, dest, immTemp
  405. */
  406. move(imm, immTempRegister);
  407. m_assembler.xorInsn(dest, dest, immTempRegister);
  408. }
  409. void sqrtDouble(FPRegisterID src, FPRegisterID dst)
  410. {
  411. m_assembler.sqrtd(dst, src);
  412. }
  413. // Memory access operations:
  414. //
  415. // Loads are of the form load(address, destination) and stores of the form
  416. // store(source, address). The source for a store may be an TrustedImm32. Address
  417. // operand objects to loads and store will be implicitly constructed if a
  418. // register is passed.
  419. /* Need to use zero-extened load byte for load8. */
  420. void load8(ImplicitAddress address, RegisterID dest)
  421. {
  422. if (address.offset >= -32768 && address.offset <= 32767
  423. && !m_fixedWidth)
  424. m_assembler.lbu(dest, address.base, address.offset);
  425. else {
  426. /*
  427. lui addrTemp, (offset + 0x8000) >> 16
  428. addu addrTemp, addrTemp, base
  429. lbu dest, (offset & 0xffff)(addrTemp)
  430. */
  431. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  432. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  433. m_assembler.lbu(dest, addrTempRegister, address.offset);
  434. }
  435. }
  436. void load32(ImplicitAddress address, RegisterID dest)
  437. {
  438. if (address.offset >= -32768 && address.offset <= 32767
  439. && !m_fixedWidth)
  440. m_assembler.lw(dest, address.base, address.offset);
  441. else {
  442. /*
  443. lui addrTemp, (offset + 0x8000) >> 16
  444. addu addrTemp, addrTemp, base
  445. lw dest, (offset & 0xffff)(addrTemp)
  446. */
  447. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  448. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  449. m_assembler.lw(dest, addrTempRegister, address.offset);
  450. }
  451. }
  452. void load32(BaseIndex address, RegisterID dest)
  453. {
  454. if (address.offset >= -32768 && address.offset <= 32767
  455. && !m_fixedWidth) {
  456. /*
  457. sll addrTemp, address.index, address.scale
  458. addu addrTemp, addrTemp, address.base
  459. lw dest, address.offset(addrTemp)
  460. */
  461. m_assembler.sll(addrTempRegister, address.index, address.scale);
  462. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  463. m_assembler.lw(dest, addrTempRegister, address.offset);
  464. } else {
  465. /*
  466. sll addrTemp, address.index, address.scale
  467. addu addrTemp, addrTemp, address.base
  468. lui immTemp, (address.offset + 0x8000) >> 16
  469. addu addrTemp, addrTemp, immTemp
  470. lw dest, (address.offset & 0xffff)(at)
  471. */
  472. m_assembler.sll(addrTempRegister, address.index, address.scale);
  473. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  474. m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
  475. m_assembler.addu(addrTempRegister, addrTempRegister,
  476. immTempRegister);
  477. m_assembler.lw(dest, addrTempRegister, address.offset);
  478. }
  479. }
  480. void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest)
  481. {
  482. if (address.offset >= -32768 && address.offset <= 32764
  483. && !m_fixedWidth) {
  484. /*
  485. sll addrTemp, address.index, address.scale
  486. addu addrTemp, addrTemp, address.base
  487. (Big-Endian)
  488. lwl dest, address.offset(addrTemp)
  489. lwr dest, address.offset+3(addrTemp)
  490. (Little-Endian)
  491. lwl dest, address.offset+3(addrTemp)
  492. lwr dest, address.offset(addrTemp)
  493. */
  494. m_assembler.sll(addrTempRegister, address.index, address.scale);
  495. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  496. #if CPU(BIG_ENDIAN)
  497. m_assembler.lwl(dest, addrTempRegister, address.offset);
  498. m_assembler.lwr(dest, addrTempRegister, address.offset + 3);
  499. #else
  500. m_assembler.lwl(dest, addrTempRegister, address.offset + 3);
  501. m_assembler.lwr(dest, addrTempRegister, address.offset);
  502. #endif
  503. } else {
  504. /*
  505. sll addrTemp, address.index, address.scale
  506. addu addrTemp, addrTemp, address.base
  507. lui immTemp, address.offset >> 16
  508. ori immTemp, immTemp, address.offset & 0xffff
  509. addu addrTemp, addrTemp, immTemp
  510. (Big-Endian)
  511. lw dest, 0(at)
  512. lw dest, 3(at)
  513. (Little-Endian)
  514. lw dest, 3(at)
  515. lw dest, 0(at)
  516. */
  517. m_assembler.sll(addrTempRegister, address.index, address.scale);
  518. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  519. m_assembler.lui(immTempRegister, address.offset >> 16);
  520. m_assembler.ori(immTempRegister, immTempRegister, address.offset);
  521. m_assembler.addu(addrTempRegister, addrTempRegister,
  522. immTempRegister);
  523. #if CPU(BIG_ENDIAN)
  524. m_assembler.lwl(dest, addrTempRegister, 0);
  525. m_assembler.lwr(dest, addrTempRegister, 3);
  526. #else
  527. m_assembler.lwl(dest, addrTempRegister, 3);
  528. m_assembler.lwr(dest, addrTempRegister, 0);
  529. #endif
  530. }
  531. }
  532. void load32(const void* address, RegisterID dest)
  533. {
  534. /*
  535. li addrTemp, address
  536. lw dest, 0(addrTemp)
  537. */
  538. move(TrustedImmPtr(address), addrTempRegister);
  539. m_assembler.lw(dest, addrTempRegister, 0);
  540. }
  541. DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest)
  542. {
  543. m_fixedWidth = true;
  544. /*
  545. lui addrTemp, address.offset >> 16
  546. ori addrTemp, addrTemp, address.offset & 0xffff
  547. addu addrTemp, addrTemp, address.base
  548. lw dest, 0(addrTemp)
  549. */
  550. DataLabel32 dataLabel(this);
  551. move(TrustedImm32(address.offset), addrTempRegister);
  552. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  553. m_assembler.lw(dest, addrTempRegister, 0);
  554. m_fixedWidth = false;
  555. return dataLabel;
  556. }
  557. /* Need to use zero-extened load half-word for load16. */
  558. void load16(ImplicitAddress address, RegisterID dest)
  559. {
  560. if (address.offset >= -32768 && address.offset <= 32767
  561. && !m_fixedWidth)
  562. m_assembler.lhu(dest, address.base, address.offset);
  563. else {
  564. /*
  565. lui addrTemp, (offset + 0x8000) >> 16
  566. addu addrTemp, addrTemp, base
  567. lhu dest, (offset & 0xffff)(addrTemp)
  568. */
  569. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  570. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  571. m_assembler.lhu(dest, addrTempRegister, address.offset);
  572. }
  573. }
  574. /* Need to use zero-extened load half-word for load16. */
  575. void load16(BaseIndex address, RegisterID dest)
  576. {
  577. if (address.offset >= -32768 && address.offset <= 32767
  578. && !m_fixedWidth) {
  579. /*
  580. sll addrTemp, address.index, address.scale
  581. addu addrTemp, addrTemp, address.base
  582. lhu dest, address.offset(addrTemp)
  583. */
  584. m_assembler.sll(addrTempRegister, address.index, address.scale);
  585. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  586. m_assembler.lhu(dest, addrTempRegister, address.offset);
  587. } else {
  588. /*
  589. sll addrTemp, address.index, address.scale
  590. addu addrTemp, addrTemp, address.base
  591. lui immTemp, (address.offset + 0x8000) >> 16
  592. addu addrTemp, addrTemp, immTemp
  593. lhu dest, (address.offset & 0xffff)(addrTemp)
  594. */
  595. m_assembler.sll(addrTempRegister, address.index, address.scale);
  596. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  597. m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
  598. m_assembler.addu(addrTempRegister, addrTempRegister,
  599. immTempRegister);
  600. m_assembler.lhu(dest, addrTempRegister, address.offset);
  601. }
  602. }
  603. DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
  604. {
  605. m_fixedWidth = true;
  606. /*
  607. lui addrTemp, address.offset >> 16
  608. ori addrTemp, addrTemp, address.offset & 0xffff
  609. addu addrTemp, addrTemp, address.base
  610. sw src, 0(addrTemp)
  611. */
  612. DataLabel32 dataLabel(this);
  613. move(TrustedImm32(address.offset), addrTempRegister);
  614. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  615. m_assembler.sw(src, addrTempRegister, 0);
  616. m_fixedWidth = false;
  617. return dataLabel;
  618. }
  619. void store32(RegisterID src, ImplicitAddress address)
  620. {
  621. if (address.offset >= -32768 && address.offset <= 32767
  622. && !m_fixedWidth)
  623. m_assembler.sw(src, address.base, address.offset);
  624. else {
  625. /*
  626. lui addrTemp, (offset + 0x8000) >> 16
  627. addu addrTemp, addrTemp, base
  628. sw src, (offset & 0xffff)(addrTemp)
  629. */
  630. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  631. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  632. m_assembler.sw(src, addrTempRegister, address.offset);
  633. }
  634. }
  635. void store32(RegisterID src, BaseIndex address)
  636. {
  637. if (address.offset >= -32768 && address.offset <= 32767
  638. && !m_fixedWidth) {
  639. /*
  640. sll addrTemp, address.index, address.scale
  641. addu addrTemp, addrTemp, address.base
  642. sw src, address.offset(addrTemp)
  643. */
  644. m_assembler.sll(addrTempRegister, address.index, address.scale);
  645. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  646. m_assembler.sw(src, addrTempRegister, address.offset);
  647. } else {
  648. /*
  649. sll addrTemp, address.index, address.scale
  650. addu addrTemp, addrTemp, address.base
  651. lui immTemp, (address.offset + 0x8000) >> 16
  652. addu addrTemp, addrTemp, immTemp
  653. sw src, (address.offset & 0xffff)(at)
  654. */
  655. m_assembler.sll(addrTempRegister, address.index, address.scale);
  656. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  657. m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
  658. m_assembler.addu(addrTempRegister, addrTempRegister,
  659. immTempRegister);
  660. m_assembler.sw(src, addrTempRegister, address.offset);
  661. }
  662. }
  663. void store32(TrustedImm32 imm, ImplicitAddress address)
  664. {
  665. if (address.offset >= -32768 && address.offset <= 32767
  666. && !m_fixedWidth) {
  667. if (!imm.m_isPointer && !imm.m_value)
  668. m_assembler.sw(MIPSRegisters::zero, address.base,
  669. address.offset);
  670. else {
  671. move(imm, immTempRegister);
  672. m_assembler.sw(immTempRegister, address.base, address.offset);
  673. }
  674. } else {
  675. /*
  676. lui addrTemp, (offset + 0x8000) >> 16
  677. addu addrTemp, addrTemp, base
  678. sw immTemp, (offset & 0xffff)(addrTemp)
  679. */
  680. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  681. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  682. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
  683. m_assembler.sw(MIPSRegisters::zero, addrTempRegister,
  684. address.offset);
  685. else {
  686. move(imm, immTempRegister);
  687. m_assembler.sw(immTempRegister, addrTempRegister,
  688. address.offset);
  689. }
  690. }
  691. }
  692. void store32(RegisterID src, const void* address)
  693. {
  694. /*
  695. li addrTemp, address
  696. sw src, 0(addrTemp)
  697. */
  698. move(TrustedImmPtr(address), addrTempRegister);
  699. m_assembler.sw(src, addrTempRegister, 0);
  700. }
  701. void store32(TrustedImm32 imm, const void* address)
  702. {
  703. /*
  704. li immTemp, imm
  705. li addrTemp, address
  706. sw src, 0(addrTemp)
  707. */
  708. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth) {
  709. move(TrustedImmPtr(address), addrTempRegister);
  710. m_assembler.sw(MIPSRegisters::zero, addrTempRegister, 0);
  711. } else {
  712. move(imm, immTempRegister);
  713. move(TrustedImmPtr(address), addrTempRegister);
  714. m_assembler.sw(immTempRegister, addrTempRegister, 0);
  715. }
  716. }
  717. // Floating-point operations:
  718. bool supportsFloatingPoint() const
  719. {
  720. #if WTF_MIPS_DOUBLE_FLOAT
  721. return true;
  722. #else
  723. return false;
  724. #endif
  725. }
  726. bool supportsFloatingPointTruncate() const
  727. {
  728. #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
  729. return true;
  730. #else
  731. return false;
  732. #endif
  733. }
  734. bool supportsFloatingPointSqrt() const
  735. {
  736. #if WTF_MIPS_DOUBLE_FLOAT && WTF_MIPS_ISA_AT_LEAST(2)
  737. return true;
  738. #else
  739. return false;
  740. #endif
  741. }
  742. // Stack manipulation operations:
  743. //
  744. // The ABI is assumed to provide a stack abstraction to memory,
  745. // containing machine word sized units of data. Push and pop
  746. // operations add and remove a single register sized unit of data
  747. // to or from the stack. Peek and poke operations read or write
  748. // values on the stack, without moving the current stack position.
  749. void pop(RegisterID dest)
  750. {
  751. m_assembler.lw(dest, MIPSRegisters::sp, 0);
  752. m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, 4);
  753. }
  754. void push(RegisterID src)
  755. {
  756. m_assembler.addiu(MIPSRegisters::sp, MIPSRegisters::sp, -4);
  757. m_assembler.sw(src, MIPSRegisters::sp, 0);
  758. }
  759. void push(Address address)
  760. {
  761. load32(address, dataTempRegister);
  762. push(dataTempRegister);
  763. }
  764. void push(TrustedImm32 imm)
  765. {
  766. move(imm, immTempRegister);
  767. push(immTempRegister);
  768. }
  769. // Register move operations:
  770. //
  771. // Move values in registers.
  772. void move(TrustedImm32 imm, RegisterID dest)
  773. {
  774. if (!imm.m_isPointer && !imm.m_value && !m_fixedWidth)
  775. move(MIPSRegisters::zero, dest);
  776. else if (imm.m_isPointer || m_fixedWidth) {
  777. m_assembler.lui(dest, imm.m_value >> 16);
  778. m_assembler.ori(dest, dest, imm.m_value);
  779. } else
  780. m_assembler.li(dest, imm.m_value);
  781. }
  782. void move(RegisterID src, RegisterID dest)
  783. {
  784. if (src != dest || m_fixedWidth)
  785. m_assembler.move(dest, src);
  786. }
  787. void move(TrustedImmPtr imm, RegisterID dest)
  788. {
  789. move(TrustedImm32(imm), dest);
  790. }
  791. void swap(RegisterID reg1, RegisterID reg2)
  792. {
  793. move(reg1, immTempRegister);
  794. move(reg2, reg1);
  795. move(immTempRegister, reg2);
  796. }
  797. void signExtend32ToPtr(RegisterID src, RegisterID dest)
  798. {
  799. if (src != dest || m_fixedWidth)
  800. move(src, dest);
  801. }
  802. void zeroExtend32ToPtr(RegisterID src, RegisterID dest)
  803. {
  804. if (src != dest || m_fixedWidth)
  805. move(src, dest);
  806. }
  807. // Forwards / external control flow operations:
  808. //
  809. // This set of jump and conditional branch operations return a Jump
  810. // object which may linked at a later point, allow forwards jump,
  811. // or jumps that will require external linkage (after the code has been
  812. // relocated).
  813. //
  814. // For branches, signed <, >, <= and >= are denoted as l, g, le, and ge
  815. // respecitvely, for unsigned comparisons the names b, a, be, and ae are
  816. // used (representing the names 'below' and 'above').
  817. //
  818. // Operands to the comparision are provided in the expected order, e.g.
  819. // jle32(reg1, TrustedImm32(5)) will branch if the value held in reg1, when
  820. // treated as a signed 32bit value, is less than or equal to 5.
  821. //
  822. // jz and jnz test whether the first operand is equal to zero, and take
  823. // an optional second operand of a mask under which to perform the test.
  824. Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right)
  825. {
  826. // Make sure the immediate value is unsigned 8 bits.
  827. ASSERT(!(right.m_value & 0xFFFFFF00));
  828. load8(left, dataTempRegister);
  829. move(right, immTempRegister);
  830. return branch32(cond, dataTempRegister, immTempRegister);
  831. }
  832. Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right)
  833. {
  834. if (cond == Equal)
  835. return branchEqual(left, right);
  836. if (cond == NotEqual)
  837. return branchNotEqual(left, right);
  838. if (cond == Above) {
  839. m_assembler.sltu(cmpTempRegister, right, left);
  840. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  841. }
  842. if (cond == AboveOrEqual) {
  843. m_assembler.sltu(cmpTempRegister, left, right);
  844. return branchEqual(cmpTempRegister, MIPSRegisters::zero);
  845. }
  846. if (cond == Below) {
  847. m_assembler.sltu(cmpTempRegister, left, right);
  848. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  849. }
  850. if (cond == BelowOrEqual) {
  851. m_assembler.sltu(cmpTempRegister, right, left);
  852. return branchEqual(cmpTempRegister, MIPSRegisters::zero);
  853. }
  854. if (cond == GreaterThan) {
  855. m_assembler.slt(cmpTempRegister, right, left);
  856. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  857. }
  858. if (cond == GreaterThanOrEqual) {
  859. m_assembler.slt(cmpTempRegister, left, right);
  860. return branchEqual(cmpTempRegister, MIPSRegisters::zero);
  861. }
  862. if (cond == LessThan) {
  863. m_assembler.slt(cmpTempRegister, left, right);
  864. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  865. }
  866. if (cond == LessThanOrEqual) {
  867. m_assembler.slt(cmpTempRegister, right, left);
  868. return branchEqual(cmpTempRegister, MIPSRegisters::zero);
  869. }
  870. ASSERT(0);
  871. return Jump();
  872. }
  873. Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right)
  874. {
  875. move(right, immTempRegister);
  876. return branch32(cond, left, immTempRegister);
  877. }
  878. Jump branch32(RelationalCondition cond, RegisterID left, Address right)
  879. {
  880. load32(right, dataTempRegister);
  881. return branch32(cond, left, dataTempRegister);
  882. }
  883. Jump branch32(RelationalCondition cond, Address left, RegisterID right)
  884. {
  885. load32(left, dataTempRegister);
  886. return branch32(cond, dataTempRegister, right);
  887. }
  888. Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right)
  889. {
  890. load32(left, dataTempRegister);
  891. move(right, immTempRegister);
  892. return branch32(cond, dataTempRegister, immTempRegister);
  893. }
  894. Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
  895. {
  896. load32(left, dataTempRegister);
  897. // Be careful that the previous load32() uses immTempRegister.
  898. // So, we need to put move() after load32().
  899. move(right, immTempRegister);
  900. return branch32(cond, dataTempRegister, immTempRegister);
  901. }
  902. Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
  903. {
  904. load32WithUnalignedHalfWords(left, dataTempRegister);
  905. // Be careful that the previous load32WithUnalignedHalfWords()
  906. // uses immTempRegister.
  907. // So, we need to put move() after load32WithUnalignedHalfWords().
  908. move(right, immTempRegister);
  909. return branch32(cond, dataTempRegister, immTempRegister);
  910. }
  911. Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
  912. {
  913. load32(left.m_ptr, dataTempRegister);
  914. return branch32(cond, dataTempRegister, right);
  915. }
  916. Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right)
  917. {
  918. load32(left.m_ptr, dataTempRegister);
  919. move(right, immTempRegister);
  920. return branch32(cond, dataTempRegister, immTempRegister);
  921. }
  922. Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right)
  923. {
  924. load16(left, dataTempRegister);
  925. return branch32(cond, dataTempRegister, right);
  926. }
  927. Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right)
  928. {
  929. ASSERT(!(right.m_value & 0xFFFF0000));
  930. load16(left, dataTempRegister);
  931. // Be careful that the previous load16() uses immTempRegister.
  932. // So, we need to put move() after load16().
  933. move(right, immTempRegister);
  934. return branch32(cond, dataTempRegister, immTempRegister);
  935. }
  936. Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask)
  937. {
  938. ASSERT((cond == Zero) || (cond == NonZero));
  939. m_assembler.andInsn(cmpTempRegister, reg, mask);
  940. if (cond == Zero)
  941. return branchEqual(cmpTempRegister, MIPSRegisters::zero);
  942. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  943. }
  944. Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
  945. {
  946. ASSERT((cond == Zero) || (cond == NonZero));
  947. if (mask.m_value == -1 && !m_fixedWidth) {
  948. if (cond == Zero)
  949. return branchEqual(reg, MIPSRegisters::zero);
  950. return branchNotEqual(reg, MIPSRegisters::zero);
  951. }
  952. move(mask, immTempRegister);
  953. return branchTest32(cond, reg, immTempRegister);
  954. }
  955. Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
  956. {
  957. load32(address, dataTempRegister);
  958. return branchTest32(cond, dataTempRegister, mask);
  959. }
  960. Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1))
  961. {
  962. load32(address, dataTempRegister);
  963. return branchTest32(cond, dataTempRegister, mask);
  964. }
  965. Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
  966. {
  967. load8(address, dataTempRegister);
  968. return branchTest32(cond, dataTempRegister, mask);
  969. }
  970. Jump jump()
  971. {
  972. return branchEqual(MIPSRegisters::zero, MIPSRegisters::zero);
  973. }
  974. void jump(RegisterID target)
  975. {
  976. m_assembler.jr(target);
  977. m_assembler.nop();
  978. }
  979. void jump(Address address)
  980. {
  981. m_fixedWidth = true;
  982. load32(address, MIPSRegisters::t9);
  983. m_assembler.jr(MIPSRegisters::t9);
  984. m_assembler.nop();
  985. m_fixedWidth = false;
  986. }
  987. // Arithmetic control flow operations:
  988. //
  989. // This set of conditional branch operations branch based
  990. // on the result of an arithmetic operation. The operation
  991. // is performed as normal, storing the result.
  992. //
  993. // * jz operations branch if the result is zero.
  994. // * jo operations branch if the (signed) arithmetic
  995. // operation caused an overflow to occur.
  996. Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest)
  997. {
  998. ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
  999. if (cond == Overflow) {
  1000. /*
  1001. move dest, dataTemp
  1002. xor cmpTemp, dataTemp, src
  1003. bltz cmpTemp, No_overflow # diff sign bit -> no overflow
  1004. addu dest, dataTemp, src
  1005. xor cmpTemp, dest, dataTemp
  1006. bgez cmpTemp, No_overflow # same sign big -> no overflow
  1007. nop
  1008. b Overflow
  1009. nop
  1010. nop
  1011. nop
  1012. nop
  1013. nop
  1014. No_overflow:
  1015. */
  1016. move(dest, dataTempRegister);
  1017. m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
  1018. m_assembler.bltz(cmpTempRegister, 10);
  1019. m_assembler.addu(dest, dataTempRegister, src);
  1020. m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
  1021. m_assembler.bgez(cmpTempRegister, 7);
  1022. m_assembler.nop();
  1023. return jump();
  1024. }
  1025. if (cond == Signed) {
  1026. add32(src, dest);
  1027. // Check if dest is negative.
  1028. m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
  1029. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  1030. }
  1031. if (cond == Zero) {
  1032. add32(src, dest);
  1033. return branchEqual(dest, MIPSRegisters::zero);
  1034. }
  1035. if (cond == NonZero) {
  1036. add32(src, dest);
  1037. return branchNotEqual(dest, MIPSRegisters::zero);
  1038. }
  1039. ASSERT(0);
  1040. return Jump();
  1041. }
  1042. Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
  1043. {
  1044. move(imm, immTempRegister);
  1045. return branchAdd32(cond, immTempRegister, dest);
  1046. }
  1047. Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
  1048. {
  1049. ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
  1050. if (cond == Overflow) {
  1051. /*
  1052. mult src, dest
  1053. mfhi dataTemp
  1054. mflo dest
  1055. sra addrTemp, dest, 31
  1056. beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
  1057. nop
  1058. b Overflow
  1059. nop
  1060. nop
  1061. nop
  1062. nop
  1063. nop
  1064. No_overflow:
  1065. */
  1066. m_assembler.mult(src, dest);
  1067. m_assembler.mfhi(dataTempRegister);
  1068. m_assembler.mflo(dest);
  1069. m_assembler.sra(addrTempRegister, dest, 31);
  1070. m_assembler.beq(dataTempRegister, addrTempRegister, 7);
  1071. m_assembler.nop();
  1072. return jump();
  1073. }
  1074. if (cond == Signed) {
  1075. mul32(src, dest);
  1076. // Check if dest is negative.
  1077. m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
  1078. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  1079. }
  1080. if (cond == Zero) {
  1081. mul32(src, dest);
  1082. return branchEqual(dest, MIPSRegisters::zero);
  1083. }
  1084. if (cond == NonZero) {
  1085. mul32(src, dest);
  1086. return branchNotEqual(dest, MIPSRegisters::zero);
  1087. }
  1088. ASSERT(0);
  1089. return Jump();
  1090. }
  1091. Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
  1092. {
  1093. move(imm, immTempRegister);
  1094. move(src, dest);
  1095. return branchMul32(cond, immTempRegister, dest);
  1096. }
  1097. Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
  1098. {
  1099. ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
  1100. if (cond == Overflow) {
  1101. /*
  1102. move dest, dataTemp
  1103. xor cmpTemp, dataTemp, src
  1104. bgez cmpTemp, No_overflow # same sign bit -> no overflow
  1105. subu dest, dataTemp, src
  1106. xor cmpTemp, dest, dataTemp
  1107. bgez cmpTemp, No_overflow # same sign bit -> no overflow
  1108. nop
  1109. b Overflow
  1110. nop
  1111. nop
  1112. nop
  1113. nop
  1114. nop
  1115. No_overflow:
  1116. */
  1117. move(dest, dataTempRegister);
  1118. m_assembler.xorInsn(cmpTempRegister, dataTempRegister, src);
  1119. m_assembler.bgez(cmpTempRegister, 10);
  1120. m_assembler.subu(dest, dataTempRegister, src);
  1121. m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
  1122. m_assembler.bgez(cmpTempRegister, 7);
  1123. m_assembler.nop();
  1124. return jump();
  1125. }
  1126. if (cond == Signed) {
  1127. sub32(src, dest);
  1128. // Check if dest is negative.
  1129. m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
  1130. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  1131. }
  1132. if (cond == Zero) {
  1133. sub32(src, dest);
  1134. return branchEqual(dest, MIPSRegisters::zero);
  1135. }
  1136. if (cond == NonZero) {
  1137. sub32(src, dest);
  1138. return branchNotEqual(dest, MIPSRegisters::zero);
  1139. }
  1140. ASSERT(0);
  1141. return Jump();
  1142. }
  1143. Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
  1144. {
  1145. move(imm, immTempRegister);
  1146. return branchSub32(cond, immTempRegister, dest);
  1147. }
  1148. Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
  1149. {
  1150. ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero));
  1151. if (cond == Signed) {
  1152. or32(src, dest);
  1153. // Check if dest is negative.
  1154. m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
  1155. return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
  1156. }
  1157. if (cond == Zero) {
  1158. or32(src, dest);
  1159. return branchEqual(dest, MIPSRegisters::zero);
  1160. }
  1161. if (cond == NonZero) {
  1162. or32(src, dest);
  1163. return branchNotEqual(dest, MIPSRegisters::zero);
  1164. }
  1165. ASSERT(0);
  1166. return Jump();
  1167. }
  1168. // Miscellaneous operations:
  1169. void breakpoint()
  1170. {
  1171. m_assembler.bkpt();
  1172. }
  1173. Call nearCall()
  1174. {
  1175. /* We need two words for relaxation. */
  1176. m_assembler.nop();
  1177. m_assembler.nop();
  1178. m_assembler.jal();
  1179. m_assembler.nop();
  1180. return Call(m_assembler.label(), Call::LinkableNear);
  1181. }
  1182. Call call()
  1183. {
  1184. m_assembler.lui(MIPSRegisters::t9, 0);
  1185. m_assembler.ori(MIPSRegisters::t9, MIPSRegisters::t9, 0);
  1186. m_assembler.jalr(MIPSRegisters::t9);
  1187. m_assembler.nop();
  1188. return Call(m_assembler.label(), Call::Linkable);
  1189. }
  1190. Call call(RegisterID target)
  1191. {
  1192. m_assembler.jalr(target);
  1193. m_assembler.nop();
  1194. return Call(m_assembler.label(), Call::None);
  1195. }
  1196. Call call(Address address)
  1197. {
  1198. m_fixedWidth = true;
  1199. load32(address, MIPSRegisters::t9);
  1200. m_assembler.jalr(MIPSRegisters::t9);
  1201. m_assembler.nop();
  1202. m_fixedWidth = false;
  1203. return Call(m_assembler.label(), Call::None);
  1204. }
  1205. void ret()
  1206. {
  1207. m_assembler.jr(MIPSRegisters::ra);
  1208. m_assembler.nop();
  1209. }
  1210. void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest)
  1211. {
  1212. if (cond == Equal) {
  1213. m_assembler.xorInsn(dest, left, right);
  1214. m_assembler.sltiu(dest, dest, 1);
  1215. } else if (cond == NotEqual) {
  1216. m_assembler.xorInsn(dest, left, right);
  1217. m_assembler.sltu(dest, MIPSRegisters::zero, dest);
  1218. } else if (cond == Above)
  1219. m_assembler.sltu(dest, right, left);
  1220. else if (cond == AboveOrEqual) {
  1221. m_assembler.sltu(dest, left, right);
  1222. m_assembler.xori(dest, dest, 1);
  1223. } else if (cond == Below)
  1224. m_assembler.sltu(dest, left, right);
  1225. else if (cond == BelowOrEqual) {
  1226. m_assembler.sltu(dest, right, left);
  1227. m_assembler.xori(dest, dest, 1);
  1228. } else if (cond == GreaterThan)
  1229. m_assembler.slt(dest, right, left);
  1230. else if (cond == GreaterThanOrEqual) {
  1231. m_assembler.slt(dest, left, right);
  1232. m_assembler.xori(dest, dest, 1);
  1233. } else if (cond == LessThan)
  1234. m_assembler.slt(dest, left, right);
  1235. else if (cond == LessThanOrEqual) {
  1236. m_assembler.slt(dest, right, left);
  1237. m_assembler.xori(dest, dest, 1);
  1238. }
  1239. }
  1240. void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest)
  1241. {
  1242. move(right, immTempRegister);
  1243. compare32(cond, left, immTempRegister, dest);
  1244. }
  1245. void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
  1246. {
  1247. ASSERT((cond == Zero) || (cond == NonZero));
  1248. load8(address, dataTempRegister);
  1249. if (mask.m_value == -1 && !m_fixedWidth) {
  1250. if (cond == Zero)
  1251. m_assembler.sltiu(dest, dataTempRegister, 1);
  1252. else
  1253. m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
  1254. } else {
  1255. move(mask, immTempRegister);
  1256. m_assembler.andInsn(cmpTempRegister, dataTempRegister,
  1257. immTempRegister);
  1258. if (cond == Zero)
  1259. m_assembler.sltiu(dest, cmpTempRegister, 1);
  1260. else
  1261. m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
  1262. }
  1263. }
  1264. void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest)
  1265. {
  1266. ASSERT((cond == Zero) || (cond == NonZero));
  1267. load32(address, dataTempRegister);
  1268. if (mask.m_value == -1 && !m_fixedWidth) {
  1269. if (cond == Zero)
  1270. m_assembler.sltiu(dest, dataTempRegister, 1);
  1271. else
  1272. m_assembler.sltu(dest, MIPSRegisters::zero, dataTempRegister);
  1273. } else {
  1274. move(mask, immTempRegister);
  1275. m_assembler.andInsn(cmpTempRegister, dataTempRegister,
  1276. immTempRegister);
  1277. if (cond == Zero)
  1278. m_assembler.sltiu(dest, cmpTempRegister, 1);
  1279. else
  1280. m_assembler.sltu(dest, MIPSRegisters::zero, cmpTempRegister);
  1281. }
  1282. }
  1283. DataLabel32 moveWithPatch(TrustedImm32 imm, RegisterID dest)
  1284. {
  1285. m_fixedWidth = true;
  1286. DataLabel32 label(this);
  1287. move(imm, dest);
  1288. m_fixedWidth = false;
  1289. return label;
  1290. }
  1291. DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest)
  1292. {
  1293. m_fixedWidth = true;
  1294. DataLabelPtr label(this);
  1295. move(initialValue, dest);
  1296. m_fixedWidth = false;
  1297. return label;
  1298. }
  1299. Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
  1300. {
  1301. m_fixedWidth = true;
  1302. dataLabel = moveWithPatch(initialRightValue, immTempRegister);
  1303. Jump temp = branch32(cond, left, immTempRegister);
  1304. m_fixedWidth = false;
  1305. return temp;
  1306. }
  1307. Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
  1308. {
  1309. m_fixedWidth = true;
  1310. load32(left, dataTempRegister);
  1311. dataLabel = moveWithPatch(initialRightValue, immTempRegister);
  1312. Jump temp = branch32(cond, dataTempRegister, immTempRegister);
  1313. m_fixedWidth = false;
  1314. return temp;
  1315. }
  1316. DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
  1317. {
  1318. m_fixedWidth = true;
  1319. DataLabelPtr dataLabel = moveWithPatch(initialValue, dataTempRegister);
  1320. store32(dataTempRegister, address);
  1321. m_fixedWidth = false;
  1322. return dataLabel;
  1323. }
  1324. DataLabelPtr storePtrWithPatch(ImplicitAddress address)
  1325. {
  1326. return storePtrWithPatch(TrustedImmPtr(0), address);
  1327. }
  1328. Call tailRecursiveCall()
  1329. {
  1330. // Like a normal call, but don't update the returned address register
  1331. m_fixedWidth = true;
  1332. move(TrustedImm32(0), MIPSRegisters::t9);
  1333. m_assembler.jr(MIPSRegisters::t9);
  1334. m_assembler.nop();
  1335. m_fixedWidth = false;
  1336. return Call(m_assembler.label(), Call::Linkable);
  1337. }
  1338. Call makeTailRecursiveCall(Jump oldJump)
  1339. {
  1340. oldJump.link(this);
  1341. return tailRecursiveCall();
  1342. }
  1343. void loadDouble(ImplicitAddress address, FPRegisterID dest)
  1344. {
  1345. #if WTF_MIPS_ISA(1)
  1346. /*
  1347. li addrTemp, address.offset
  1348. addu addrTemp, addrTemp, base
  1349. lwc1 dest, 0(addrTemp)
  1350. lwc1 dest+1, 4(addrTemp)
  1351. */
  1352. move(TrustedImm32(address.offset), addrTempRegister);
  1353. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  1354. m_assembler.lwc1(dest, addrTempRegister, 0);
  1355. m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
  1356. #else
  1357. if (address.offset >= -32768 && address.offset <= 32767
  1358. && !m_fixedWidth) {
  1359. m_assembler.ldc1(dest, address.base, address.offset);
  1360. } else {
  1361. /*
  1362. lui addrTemp, (offset + 0x8000) >> 16
  1363. addu addrTemp, addrTemp, base
  1364. ldc1 dest, (offset & 0xffff)(addrTemp)
  1365. */
  1366. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  1367. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  1368. m_assembler.ldc1(dest, addrTempRegister, address.offset);
  1369. }
  1370. #endif
  1371. }
  1372. void loadDouble(const void* address, FPRegisterID dest)
  1373. {
  1374. #if WTF_MIPS_ISA(1)
  1375. /*
  1376. li addrTemp, address
  1377. lwc1 dest, 0(addrTemp)
  1378. lwc1 dest+1, 4(addrTemp)
  1379. */
  1380. move(TrustedImmPtr(address), addrTempRegister);
  1381. m_assembler.lwc1(dest, addrTempRegister, 0);
  1382. m_assembler.lwc1(FPRegisterID(dest + 1), addrTempRegister, 4);
  1383. #else
  1384. /*
  1385. li addrTemp, address
  1386. ldc1 dest, 0(addrTemp)
  1387. */
  1388. move(TrustedImmPtr(address), addrTempRegister);
  1389. m_assembler.ldc1(dest, addrTempRegister, 0);
  1390. #endif
  1391. }
  1392. void storeDouble(FPRegisterID src, ImplicitAddress address)
  1393. {
  1394. #if WTF_MIPS_ISA(1)
  1395. /*
  1396. li addrTemp, address.offset
  1397. addu addrTemp, addrTemp, base
  1398. swc1 dest, 0(addrTemp)
  1399. swc1 dest+1, 4(addrTemp)
  1400. */
  1401. move(TrustedImm32(address.offset), addrTempRegister);
  1402. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  1403. m_assembler.swc1(src, addrTempRegister, 0);
  1404. m_assembler.swc1(FPRegisterID(src + 1), addrTempRegister, 4);
  1405. #else
  1406. if (address.offset >= -32768 && address.offset <= 32767
  1407. && !m_fixedWidth)
  1408. m_assembler.sdc1(src, address.base, address.offset);
  1409. else {
  1410. /*
  1411. lui addrTemp, (offset + 0x8000) >> 16
  1412. addu addrTemp, addrTemp, base
  1413. sdc1 src, (offset & 0xffff)(addrTemp)
  1414. */
  1415. m_assembler.lui(addrTempRegister, (address.offset + 0x8000) >> 16);
  1416. m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
  1417. m_assembler.sdc1(src, addrTempRegister, address.offset);
  1418. }
  1419. #endif
  1420. }
  1421. void addDouble(FPRegisterID src, FPRegisterID dest)
  1422. {
  1423. m_assembler.addd(dest, dest, src);
  1424. }
  1425. void addDouble(Address src, FPRegisterID dest)
  1426. {
  1427. loadDouble(src, fpTempRegister);
  1428. m_assembler.addd(dest, dest, fpTempRegister);
  1429. }
  1430. void subDouble(FPRegisterID src, FPRegisterID dest)
  1431. {
  1432. m_assembler.subd(dest, dest, src);
  1433. }
  1434. void subDouble(Address src, FPRegisterID dest)
  1435. {
  1436. loadDouble(src, fpTempRegister);
  1437. m_assembler.subd(dest, dest, fpTempRegister);
  1438. }
  1439. void mulDouble(FPRegisterID src, FPRegisterID dest)
  1440. {
  1441. m_assembler.muld(dest, dest, src);
  1442. }
  1443. void mulDouble(Address src, FPRegisterID dest)
  1444. {
  1445. loadDouble(src, fpTempRegister);
  1446. m_assembler.muld(dest, dest, fpTempRegister);
  1447. }
  1448. void divDouble(FPRegisterID src, FPRegisterID dest)
  1449. {
  1450. m_assembler.divd(dest, dest, src);
  1451. }
  1452. void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
  1453. {
  1454. m_assembler.mtc1(src, fpTempRegister);
  1455. m_assembler.cvtdw(dest, fpTempRegister);
  1456. }
  1457. void convertInt32ToDouble(Address src, FPRegisterID dest)
  1458. {
  1459. load32(src, dataTempRegister);
  1460. m_assembler.mtc1(dataTempRegister, fpTempRegister);
  1461. m_assembler.cvtdw(dest, fpTempRegister);
  1462. }
  1463. void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest)
  1464. {
  1465. load32(src.m_ptr, dataTempRegister);
  1466. m_assembler.mtc1(dataTempRegister, fpTempRegister);
  1467. m_assembler.cvtdw(dest, fpTempRegister);
  1468. }
  1469. void insertRelaxationWords()
  1470. {
  1471. /* We need four words for relaxation. */
  1472. m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 3); // Jump over nops;
  1473. m_assembler.nop();
  1474. m_assembler.nop();
  1475. m_assembler.nop();
  1476. }
  1477. Jump branchTrue()
  1478. {
  1479. m_assembler.appendJump();
  1480. m_assembler.bc1t();
  1481. m_assembler.nop();
  1482. insertRelaxationWords();
  1483. return Jump(m_assembler.label());
  1484. }
  1485. Jump branchFalse()
  1486. {
  1487. m_assembler.appendJump();
  1488. m_assembler.bc1f();
  1489. m_assembler.nop();
  1490. insertRelaxationWords();
  1491. return Jump(m_assembler.label());
  1492. }
  1493. Jump branchEqual(RegisterID rs, RegisterID rt)
  1494. {
  1495. m_assembler.appendJump();
  1496. m_assembler.beq(rs, rt, 0);
  1497. m_assembler.nop();
  1498. insertRelaxationWords();
  1499. return Jump(m_assembler.label());
  1500. }
  1501. Jump branchNotEqual(RegisterID rs, RegisterID rt)
  1502. {
  1503. m_assembler.appendJump();
  1504. m_assembler.bne(rs, rt, 0);
  1505. m_assembler.nop();
  1506. insertRelaxationWords();
  1507. return Jump(m_assembler.label());
  1508. }
  1509. Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right)
  1510. {
  1511. if (cond == DoubleEqual) {
  1512. m_assembler.ceqd(left, right);
  1513. return branchTrue();
  1514. }
  1515. if (cond == DoubleNotEqual) {
  1516. m_assembler.cueqd(left, right);
  1517. return branchFalse(); // false
  1518. }
  1519. if (cond == DoubleGreaterThan) {
  1520. m_assembler.cngtd(left, right);
  1521. return branchFalse(); // false
  1522. }
  1523. if (cond == DoubleGreaterThanOrEqual) {
  1524. m_assembler.cnged(left, right);
  1525. return branchFalse(); // false
  1526. }
  1527. if (cond == DoubleLessThan) {
  1528. m_assembler.cltd(left, right);
  1529. return branchTrue();
  1530. }
  1531. if (cond == DoubleLessThanOrEqual) {
  1532. m_assembler.cled(left, right);
  1533. return branchTrue();
  1534. }
  1535. if (cond == DoubleEqualOrUnordered) {
  1536. m_assembler.cueqd(left, right);
  1537. return branchTrue();
  1538. }
  1539. if (cond == DoubleNotEqualOrUnordered) {
  1540. m_assembler.ceqd(left, right);
  1541. return branchFalse(); // false
  1542. }
  1543. if (cond == DoubleGreaterThanOrUnordered) {
  1544. m_assembler.coled(left, right);
  1545. return branchFalse(); // false
  1546. }
  1547. if (cond == DoubleGreaterThanOrEqualOrUnordered) {
  1548. m_assembler.coltd(left, right);
  1549. return branchFalse(); // false
  1550. }
  1551. if (cond == DoubleLessThanOrUnordered) {
  1552. m_assembler.cultd(left, right);
  1553. return branchTrue();
  1554. }
  1555. if (cond == DoubleLessThanOrEqualOrUnordered) {
  1556. m_assembler.culed(left, right);
  1557. return branchTrue();
  1558. }
  1559. ASSERT(0);
  1560. return Jump();
  1561. }
  1562. // Truncates 'src' to an integer, and places the resulting 'dest'.
  1563. // If the result is not representable as a 32 bit value, branch.
  1564. // May also branch for some values that are representable in 32 bits
  1565. // (specifically, in this case, INT_MAX 0x7fffffff).
  1566. Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
  1567. {
  1568. m_assembler.truncwd(fpTempRegister, src);
  1569. m_assembler.mfc1(dest, fpTempRegister);
  1570. return branch32(Equal, dest, TrustedImm32(0x7fffffff));
  1571. }
  1572. // Convert 'src' to an integer, and places the resulting 'dest'.
  1573. // If the result is not representable as a 32 bit value, branch.
  1574. // May also branch for some values that are representable in 32 bits
  1575. // (specifically, in this case, 0).
  1576. void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp)
  1577. {
  1578. m_assembler.cvtwd(fpTempRegister, src);
  1579. m_assembler.mfc1(dest, fpTempRegister);
  1580. // If the result is zero, it might have been -0.0, and the double comparison won't catch this!
  1581. failureCases.append(branch32(Equal, dest, MIPSRegisters::zero));
  1582. // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump.
  1583. convertInt32ToDouble(dest, fpTemp);
  1584. failureCases.append(branchDouble(DoubleNotEqualOrUnordered, fpTemp, src));
  1585. }
  1586. Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
  1587. {
  1588. #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
  1589. m_assembler.mtc1(MIPSRegisters::zero, scratch);
  1590. m_assembler.mthc1(MIPSRegisters::zero, scratch);
  1591. #else
  1592. m_assembler.mtc1(MIPSRegisters::zero, scratch);
  1593. m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
  1594. #endif
  1595. return branchDouble(DoubleNotEqual, reg, scratch);
  1596. }
  1597. Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
  1598. {
  1599. #if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
  1600. m_assembler.mtc1(MIPSRegisters::zero, scratch);
  1601. m_assembler.mthc1(MIPSRegisters::zero, scratch);
  1602. #else
  1603. m_assembler.mtc1(MIPSRegisters::zero, scratch);
  1604. m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
  1605. #endif
  1606. return branchDouble(DoubleEqualOrUnordered, reg, scratch);
  1607. }
  1608. private:
  1609. // If m_fixedWidth is true, we will generate a fixed number of instructions.
  1610. // Otherwise, we can emit any number of instructions.
  1611. bool m_fixedWidth;
  1612. friend class LinkBuffer;
  1613. friend class RepatchBuffer;
  1614. static void linkCall(void* code, Call call, FunctionPtr function)
  1615. {
  1616. MIPSAssembler::linkCall(code, call.m_jmp, function.value());
  1617. }
  1618. static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
  1619. {
  1620. MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
  1621. }
  1622. static void repatchCall(CodeLocationCall call, FunctionPtr destination)
  1623. {
  1624. MIPSAssembler::relinkCall(call.dataLocation(), destination.executableAddress());
  1625. }
  1626. };
  1627. }
  1628. #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
  1629. #endif // MacroAssemblerMIPS_h