/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

Large files are truncated click here to view the full 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_fix