blob: 865a5683cc643d8ab706ef802a21593ee40fb38f [file] [log] [blame]
Paul Lind2bc2b792012-02-01 10:54:19 -08001/* libs/pixelflinger/codeflinger/MIPSAssembler.cpp
2**
3** Copyright 2012, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18
19/* MIPS assembler and ARM->MIPS assembly translator
20**
21** The approach is to leave the GGLAssembler and associated files largely
22** un-changed, still utilizing all Arm instruction generation. Via the
23** ArmToMipsAssembler (subclassed from ArmAssemblerInterface) each Arm
24** instruction is translated to one or more Mips instructions as necessary. This
25** is clearly less efficient than a direct implementation within the
26** GGLAssembler, but is far cleaner, more maintainable, and has yielded very
27** significant performance gains on Mips compared to the generic pixel pipeline.
28**
29**
30** GGLAssembler changes
31**
32** - The register allocator has been modified to re-map Arm registers 0-15 to mips
33** registers 2-17. Mips register 0 cannot be used as general-purpose register,
34** and register 1 has traditional uses as a short-term temporary.
35**
36** - Added some early bailouts for OUT_OF_REGISTERS in texturing.cpp and
37** GGLAssembler.cpp, since this is not fatal, and can be retried at lower
38** optimization level.
39**
40**
41** ARMAssembler and ARMAssemblerInterface changes
42**
43** Refactored ARM address-mode static functions (imm(), reg_imm(), imm12_pre(), etc.)
44** to virtual, so they can be overridden in MIPSAssembler. The implementation of these
45** functions on ARM is moved from ARMAssemblerInterface.cpp to ARMAssembler.cpp, and
46** is unchanged from the original. (This required duplicating 2 of these as static
47** functions in ARMAssemblerInterface.cpp so they could be used as static initializers).
48*/
49
Paul Lind2bc2b792012-02-01 10:54:19 -080050#define LOG_TAG "MIPSAssembler"
51
52#include <stdio.h>
53#include <stdlib.h>
Paul Lind2bc2b792012-02-01 10:54:19 -080054
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070055#include <cutils/properties.h>
Mark Salyzyn30f991f2017-01-10 13:19:54 -080056#include <log/log.h>
Paul Lind2bc2b792012-02-01 10:54:19 -080057#include <private/pixelflinger/ggl_context.h>
58
Mathias Agopian9857d992013-04-01 15:17:55 -070059#include "CodeCache.h"
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070060#include "MIPSAssembler.h"
Mathias Agopian9857d992013-04-01 15:17:55 -070061#include "mips_disassem.h"
Paul Lind2bc2b792012-02-01 10:54:19 -080062
63// Choose MIPS arch variant following gcc flags
64#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
65#define mips32r2 1
66#else
67#define mips32r2 0
68#endif
69
70
71#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
72
73
74
75// ----------------------------------------------------------------------------
76
77namespace android {
78
79// ----------------------------------------------------------------------------
80#if 0
81#pragma mark -
82#pragma mark ArmToMipsAssembler...
83#endif
84
85ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly,
86 char *abuf, int linesz, int instr_count)
87 : ARMAssemblerInterface(),
88 mArmDisassemblyBuffer(abuf),
89 mArmLineLength(linesz),
90 mArmInstrCount(instr_count),
91 mInum(0),
92 mAssembly(assembly)
93{
94 mMips = new MIPSAssembler(assembly, this);
95 mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
96 init_conditional_labels();
97}
98
99ArmToMipsAssembler::~ArmToMipsAssembler()
100{
101 delete mMips;
102 free((void *) mArmPC);
103}
104
105uint32_t* ArmToMipsAssembler::pc() const
106{
107 return mMips->pc();
108}
109
110uint32_t* ArmToMipsAssembler::base() const
111{
112 return mMips->base();
113}
114
115void ArmToMipsAssembler::reset()
116{
117 cond.labelnum = 0;
118 mInum = 0;
119 mMips->reset();
120}
121
122int ArmToMipsAssembler::getCodegenArch()
123{
124 return CODEGEN_ARCH_MIPS;
125}
126
127void ArmToMipsAssembler::comment(const char* string)
128{
129 mMips->comment(string);
130}
131
132void ArmToMipsAssembler::label(const char* theLabel)
133{
134 mMips->label(theLabel);
135}
136
137void ArmToMipsAssembler::disassemble(const char* name)
138{
139 mMips->disassemble(name);
140}
141
142void ArmToMipsAssembler::init_conditional_labels()
143{
144 int i;
145 for (i=0;i<99; ++i) {
146 sprintf(cond.label[i], "cond_%d", i);
147 }
148}
149
150
151
152#if 0
153#pragma mark -
154#pragma mark Prolog/Epilog & Generate...
155#endif
156
157void ArmToMipsAssembler::prolog()
158{
159 mArmPC[mInum++] = pc(); // save starting PC for this instr
160
161 mMips->ADDIU(R_sp, R_sp, -(5 * 4));
162 mMips->SW(R_s0, R_sp, 0);
163 mMips->SW(R_s1, R_sp, 4);
164 mMips->SW(R_s2, R_sp, 8);
165 mMips->SW(R_s3, R_sp, 12);
166 mMips->SW(R_s4, R_sp, 16);
167 mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0)
168}
169
170void ArmToMipsAssembler::epilog(uint32_t touched)
171{
172 mArmPC[mInum++] = pc(); // save starting PC for this instr
173
174 mMips->LW(R_s0, R_sp, 0);
175 mMips->LW(R_s1, R_sp, 4);
176 mMips->LW(R_s2, R_sp, 8);
177 mMips->LW(R_s3, R_sp, 12);
178 mMips->LW(R_s4, R_sp, 16);
179 mMips->ADDIU(R_sp, R_sp, (5 * 4));
180 mMips->JR(R_ra);
181
182}
183
184int ArmToMipsAssembler::generate(const char* name)
185{
186 return mMips->generate(name);
187}
188
189uint32_t* ArmToMipsAssembler::pcForLabel(const char* label)
190{
191 return mMips->pcForLabel(label);
192}
193
194
195
196//----------------------------------------------------------
197
198#if 0
199#pragma mark -
200#pragma mark Addressing modes & shifters...
201#endif
202
203
204// do not need this for MIPS, but it is in the Interface (virtual)
205int ArmToMipsAssembler::buildImmediate(
206 uint32_t immediate, uint32_t& rot, uint32_t& imm)
207{
208 // for MIPS, any 32-bit immediate is OK
209 rot = 0;
210 imm = immediate;
211 return 0;
212}
213
214// shifters...
215
216bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate)
217{
218 // for MIPS, any 32-bit immediate is OK
219 return true;
220}
221
222uint32_t ArmToMipsAssembler::imm(uint32_t immediate)
223{
224 // ALOGW("immediate value %08x at pc %08x\n", immediate, (int)pc());
225 amode.value = immediate;
226 return AMODE_IMM;
227}
228
229uint32_t ArmToMipsAssembler::reg_imm(int Rm, int type, uint32_t shift)
230{
231 amode.reg = Rm;
232 amode.stype = type;
233 amode.value = shift;
234 return AMODE_REG_IMM;
235}
236
237uint32_t ArmToMipsAssembler::reg_rrx(int Rm)
238{
239 // reg_rrx mode is not used in the GLLAssember code at this time
240 return AMODE_UNSUPPORTED;
241}
242
243uint32_t ArmToMipsAssembler::reg_reg(int Rm, int type, int Rs)
244{
245 // reg_reg mode is not used in the GLLAssember code at this time
246 return AMODE_UNSUPPORTED;
247}
248
249
250// addressing modes...
251// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
252uint32_t ArmToMipsAssembler::immed12_pre(int32_t immed12, int W)
253{
254 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
255 "LDR(B)/STR(B)/PLD immediate too big (%08x)",
256 immed12);
257 amode.value = immed12;
258 amode.writeback = W;
259 return AMODE_IMM_12_PRE;
260}
261
262uint32_t ArmToMipsAssembler::immed12_post(int32_t immed12)
263{
264 LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
265 "LDR(B)/STR(B)/PLD immediate too big (%08x)",
266 immed12);
267
268 amode.value = immed12;
269 return AMODE_IMM_12_POST;
270}
271
272uint32_t ArmToMipsAssembler::reg_scale_pre(int Rm, int type,
273 uint32_t shift, int W)
274{
275 LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
276
277 amode.reg = Rm;
278 // amode.stype = type; // more advanced modes not used in GGLAssembler yet
279 // amode.value = shift;
280 // amode.writeback = W;
281 return AMODE_REG_SCALE_PRE;
282}
283
284uint32_t ArmToMipsAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
285{
286 LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
287 return AMODE_UNSUPPORTED;
288}
289
290// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
291uint32_t ArmToMipsAssembler::immed8_pre(int32_t immed8, int W)
292{
293 // uint32_t offset = abs(immed8);
294
295 LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
296
297 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
298 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
299 immed8);
300 return AMODE_IMM_8_PRE;
301}
302
303uint32_t ArmToMipsAssembler::immed8_post(int32_t immed8)
304{
305 // uint32_t offset = abs(immed8);
306
307 LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
308 "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
309 immed8);
310 amode.value = immed8;
311 return AMODE_IMM_8_POST;
312}
313
314uint32_t ArmToMipsAssembler::reg_pre(int Rm, int W)
315{
316 LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
317 amode.reg = Rm;
318 return AMODE_REG_PRE;
319}
320
321uint32_t ArmToMipsAssembler::reg_post(int Rm)
322{
323 LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
324 return AMODE_UNSUPPORTED;
325}
326
327
328
329// ----------------------------------------------------------------------------
330
331#if 0
332#pragma mark -
333#pragma mark Data Processing...
334#endif
335
336
337static const char * const dpOpNames[] = {
338 "AND", "EOR", "SUB", "RSB", "ADD", "ADC", "SBC", "RSC",
339 "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN"
340};
341
342// check if the operand registers from a previous CMP or S-bit instruction
343// would be overwritten by this instruction. If so, move the value to a
344// safe register.
345// Note that we cannot tell at _this_ instruction time if a future (conditional)
346// instruction will _also_ use this value (a defect of the simple 1-pass, one-
347// instruction-at-a-time translation). Therefore we must be conservative and
348// save the value before it is overwritten. This costs an extra MOVE instr.
349
350void ArmToMipsAssembler::protectConditionalOperands(int Rd)
351{
352 if (Rd == cond.r1) {
353 mMips->MOVE(R_cmp, cond.r1);
354 cond.r1 = R_cmp;
355 }
356 if (cond.type == CMP_COND && Rd == cond.r2) {
357 mMips->MOVE(R_cmp2, cond.r2);
358 cond.r2 = R_cmp2;
359 }
360}
361
362
363// interprets the addressing mode, and generates the common code
364// used by the majority of data-processing ops. Many MIPS instructions
365// have a register-based form and a different immediate form. See
366// opAND below for an example. (this could be inlined)
367//
368// this works with the imm(), reg_imm() methods above, which are directly
369// called by the GLLAssembler.
370// note: _signed parameter defaults to false (un-signed)
371// note: tmpReg parameter defaults to 1, MIPS register AT
372int ArmToMipsAssembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
373{
374 if (op < AMODE_REG) {
375 source = op;
376 return SRC_REG;
377 } else if (op == AMODE_IMM) {
378 if ((!_signed && amode.value > 0xffff)
379 || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
380 mMips->LUI(tmpReg, (amode.value >> 16));
381 if (amode.value & 0x0000ffff) {
382 mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
383 }
384 source = tmpReg;
385 return SRC_REG;
386 } else {
387 source = amode.value;
388 return SRC_IMM;
389 }
390 } else if (op == AMODE_REG_IMM) {
391 switch (amode.stype) {
392 case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
393 case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
394 case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
395 case ROR: if (mips32r2) {
396 mMips->ROTR(tmpReg, amode.reg, amode.value);
397 } else {
398 mMips->RORIsyn(tmpReg, amode.reg, amode.value);
399 }
400 break;
401 }
402 source = tmpReg;
403 return SRC_REG;
404 } else { // adr mode RRX is not used in GGL Assembler at this time
405 // we are screwed, this should be exception, assert-fail or something
406 LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
407 return SRC_ERROR;
408 }
409}
410
411
412void ArmToMipsAssembler::dataProcessing(int opcode, int cc,
413 int s, int Rd, int Rn, uint32_t Op2)
414{
415 int src; // src is modified by dataProcAdrModes() - passed as int&
416
417
418 if (cc != AL) {
419 protectConditionalOperands(Rd);
420 // the branch tests register(s) set by prev CMP or instr with 'S' bit set
421 // inverse the condition to jump past this conditional instruction
422 ArmToMipsAssembler::B(cc^1, cond.label[++cond.labelnum]);
423 } else {
424 mArmPC[mInum++] = pc(); // save starting PC for this instr
425 }
426
427 switch (opcode) {
428 case opAND:
429 if (dataProcAdrModes(Op2, src) == SRC_REG) {
430 mMips->AND(Rd, Rn, src);
431 } else { // adr mode was SRC_IMM
432 mMips->ANDI(Rd, Rn, src);
433 }
434 break;
435
436 case opADD:
437 // set "signed" to true for adr modes
438 if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
439 mMips->ADDU(Rd, Rn, src);
440 } else { // adr mode was SRC_IMM
441 mMips->ADDIU(Rd, Rn, src);
442 }
443 break;
444
445 case opSUB:
446 // set "signed" to true for adr modes
447 if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
448 mMips->SUBU(Rd, Rn, src);
449 } else { // adr mode was SRC_IMM
450 mMips->SUBIU(Rd, Rn, src);
451 }
452 break;
453
454 case opEOR:
455 if (dataProcAdrModes(Op2, src) == SRC_REG) {
456 mMips->XOR(Rd, Rn, src);
457 } else { // adr mode was SRC_IMM
458 mMips->XORI(Rd, Rn, src);
459 }
460 break;
461
462 case opORR:
463 if (dataProcAdrModes(Op2, src) == SRC_REG) {
464 mMips->OR(Rd, Rn, src);
465 } else { // adr mode was SRC_IMM
466 mMips->ORI(Rd, Rn, src);
467 }
468 break;
469
470 case opBIC:
471 if (dataProcAdrModes(Op2, src) == SRC_IMM) {
472 // if we are 16-bit imnmediate, load to AT reg
473 mMips->ORI(R_at, 0, src);
474 src = R_at;
475 }
476 mMips->NOT(R_at, src);
477 mMips->AND(Rd, Rn, R_at);
478 break;
479
480 case opRSB:
481 if (dataProcAdrModes(Op2, src) == SRC_IMM) {
482 // if we are 16-bit imnmediate, load to AT reg
483 mMips->ORI(R_at, 0, src);
484 src = R_at;
485 }
486 mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed
487 break;
488
489 case opMOV:
490 if (Op2 < AMODE_REG) { // op2 is reg # in this case
491 mMips->MOVE(Rd, Op2);
492 } else if (Op2 == AMODE_IMM) {
493 if (amode.value > 0xffff) {
494 mMips->LUI(Rd, (amode.value >> 16));
495 if (amode.value & 0x0000ffff) {
496 mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
497 }
498 } else {
499 mMips->ORI(Rd, 0, amode.value);
500 }
501 } else if (Op2 == AMODE_REG_IMM) {
502 switch (amode.stype) {
503 case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
504 case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
505 case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
506 case ROR: if (mips32r2) {
507 mMips->ROTR(Rd, amode.reg, amode.value);
508 } else {
509 mMips->RORIsyn(Rd, amode.reg, amode.value);
510 }
511 break;
512 }
513 }
514 else {
515 // adr mode RRX is not used in GGL Assembler at this time
516 mMips->UNIMPL();
517 }
518 break;
519
520 case opMVN: // this is a 1's complement: NOT
521 if (Op2 < AMODE_REG) { // op2 is reg # in this case
522 mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0
523 break;
524 } else if (Op2 == AMODE_IMM) {
525 if (amode.value > 0xffff) {
526 mMips->LUI(Rd, (amode.value >> 16));
527 if (amode.value & 0x0000ffff) {
528 mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
529 }
530 } else {
531 mMips->ORI(Rd, 0, amode.value);
532 }
533 } else if (Op2 == AMODE_REG_IMM) {
534 switch (amode.stype) {
535 case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
536 case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
537 case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
538 case ROR: if (mips32r2) {
539 mMips->ROTR(Rd, amode.reg, amode.value);
540 } else {
541 mMips->RORIsyn(Rd, amode.reg, amode.value);
542 }
543 break;
544 }
545 }
546 else {
547 // adr mode RRX is not used in GGL Assembler at this time
548 mMips->UNIMPL();
549 }
550 mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0
551 break;
552
553 case opCMP:
554 // Either operand of a CMP instr could get overwritten by a subsequent
555 // conditional instruction, which is ok, _UNLESS_ there is a _second_
556 // conditional instruction. Under MIPS, this requires doing the comparison
557 // again (SLT), and the original operands must be available. (and this
558 // pattern of multiple conditional instructions from same CMP _is_ used
559 // in GGL-Assembler)
560 //
561 // For now, if a conditional instr overwrites the operands, we will
562 // move them to dedicated temp regs. This is ugly, and inefficient,
563 // and should be optimized.
564 //
565 // WARNING: making an _Assumption_ that CMP operand regs will NOT be
566 // trashed by intervening NON-conditional instructions. In the general
567 // case this is legal, but it is NOT currently done in GGL-Assembler.
568
569 cond.type = CMP_COND;
570 cond.r1 = Rn;
571 if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
572 cond.r2 = src;
573 } else { // adr mode was SRC_IMM
574 mMips->ORI(R_cmp2, R_zero, src);
575 cond.r2 = R_cmp2;
576 }
577
578 break;
579
580
581 case opTST:
582 case opTEQ:
583 case opCMN:
584 case opADC:
585 case opSBC:
586 case opRSC:
587 mMips->UNIMPL(); // currently unused in GGL Assembler code
588 break;
589 }
590
591 if (cc != AL) {
592 mMips->label(cond.label[cond.labelnum]);
593 }
594 if (s && opcode != opCMP) {
595 cond.type = SBIT_COND;
596 cond.r1 = Rd;
597 }
598}
599
600
601
602#if 0
603#pragma mark -
604#pragma mark Multiply...
605#endif
606
607// multiply, accumulate
608void ArmToMipsAssembler::MLA(int cc, int s,
609 int Rd, int Rm, int Rs, int Rn) {
610
611 mArmPC[mInum++] = pc(); // save starting PC for this instr
612
613 mMips->MUL(R_at, Rm, Rs);
614 mMips->ADDU(Rd, R_at, Rn);
615 if (s) {
616 cond.type = SBIT_COND;
617 cond.r1 = Rd;
618 }
619}
620
621void ArmToMipsAssembler::MUL(int cc, int s,
622 int Rd, int Rm, int Rs) {
623 mArmPC[mInum++] = pc();
624 mMips->MUL(Rd, Rm, Rs);
625 if (s) {
626 cond.type = SBIT_COND;
627 cond.r1 = Rd;
628 }
629}
630
631void ArmToMipsAssembler::UMULL(int cc, int s,
632 int RdLo, int RdHi, int Rm, int Rs) {
633 mArmPC[mInum++] = pc();
634 mMips->MULT(Rm, Rs);
635 mMips->MFHI(RdHi);
636 mMips->MFLO(RdLo);
637 if (s) {
638 cond.type = SBIT_COND;
639 cond.r1 = RdHi; // BUG...
640 LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
641 }
642}
643
644void ArmToMipsAssembler::UMUAL(int cc, int s,
645 int RdLo, int RdHi, int Rm, int Rs) {
646 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
647 "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
648 // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
649 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
650 mArmPC[mInum++] = pc();
651 mMips->NOP2();
652 NOT_IMPLEMENTED();
653 if (s) {
654 cond.type = SBIT_COND;
655 cond.r1 = RdHi; // BUG...
656 LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
657 }
658}
659
660void ArmToMipsAssembler::SMULL(int cc, int s,
661 int RdLo, int RdHi, int Rm, int Rs) {
662 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
663 "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
664 // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
665 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
666 mArmPC[mInum++] = pc();
667 mMips->NOP2();
668 NOT_IMPLEMENTED();
669 if (s) {
670 cond.type = SBIT_COND;
671 cond.r1 = RdHi; // BUG...
672 LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
673 }
674}
675void ArmToMipsAssembler::SMUAL(int cc, int s,
676 int RdLo, int RdHi, int Rm, int Rs) {
677 LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
678 "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
679 // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
680 // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
681 mArmPC[mInum++] = pc();
682 mMips->NOP2();
683 NOT_IMPLEMENTED();
684 if (s) {
685 cond.type = SBIT_COND;
686 cond.r1 = RdHi; // BUG...
687 LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
688 }
689}
690
691
692
693#if 0
694#pragma mark -
695#pragma mark Branches...
696#endif
697
698// branches...
699
700void ArmToMipsAssembler::B(int cc, const char* label)
701{
702 mArmPC[mInum++] = pc();
703 if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
704
705 switch(cc) {
706 case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
707 case NE: mMips->BNE(cond.r1, cond.r2, label); break;
708 case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
709 case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
710 case MI: mMips->BLT(cond.r1, cond.r2, label); break;
711 case PL: mMips->BGE(cond.r1, cond.r2, label); break;
712
713 case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
714 case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
715 case GE: mMips->BGE(cond.r1, cond.r2, label); break;
716 case LT: mMips->BLT(cond.r1, cond.r2, label); break;
717 case GT: mMips->BGT(cond.r1, cond.r2, label); break;
718 case LE: mMips->BLE(cond.r1, cond.r2, label); break;
719 case AL: mMips->B(label); break;
720 case NV: /* B Never - no instruction */ break;
721
722 case VS:
723 case VC:
724 default:
725 LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
726 break;
727 }
728}
729
730void ArmToMipsAssembler::BL(int cc, const char* label)
731{
732 LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
733 mArmPC[mInum++] = pc();
734}
735
736// no use for Branches with integer PC, but they're in the Interface class ....
737void ArmToMipsAssembler::B(int cc, uint32_t* to_pc)
738{
739 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
740 mArmPC[mInum++] = pc();
741}
742
743void ArmToMipsAssembler::BL(int cc, uint32_t* to_pc)
744{
745 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
746 mArmPC[mInum++] = pc();
747}
748
749void ArmToMipsAssembler::BX(int cc, int Rn)
750{
751 LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
752 mArmPC[mInum++] = pc();
753}
754
755
756
757#if 0
758#pragma mark -
759#pragma mark Data Transfer...
760#endif
761
762// data transfer...
763void ArmToMipsAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset)
764{
765 mArmPC[mInum++] = pc();
766 // work-around for ARM default address mode of immed12_pre(0)
767 if (offset > AMODE_UNSUPPORTED) offset = 0;
768 switch (offset) {
769 case 0:
770 amode.value = 0;
771 amode.writeback = 0;
772 // fall thru to next case ....
773 case AMODE_IMM_12_PRE:
774 if (Rn == ARMAssemblerInterface::SP) {
775 Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
776 }
777 mMips->LW(Rd, Rn, amode.value);
778 if (amode.writeback) { // OPTIONAL writeback on pre-index mode
779 mMips->ADDIU(Rn, Rn, amode.value);
780 }
781 break;
782 case AMODE_IMM_12_POST:
783 if (Rn == ARMAssemblerInterface::SP) {
784 Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
785 }
786 mMips->LW(Rd, Rn, 0);
787 mMips->ADDIU(Rn, Rn, amode.value);
788 break;
789 case AMODE_REG_SCALE_PRE:
790 // we only support simple base + index, no advanced modes for this one yet
791 mMips->ADDU(R_at, Rn, amode.reg);
792 mMips->LW(Rd, R_at, 0);
793 break;
794 }
795}
796
797void ArmToMipsAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset)
798{
799 mArmPC[mInum++] = pc();
800 // work-around for ARM default address mode of immed12_pre(0)
801 if (offset > AMODE_UNSUPPORTED) offset = 0;
802 switch (offset) {
803 case 0:
804 amode.value = 0;
805 amode.writeback = 0;
806 // fall thru to next case ....
807 case AMODE_IMM_12_PRE:
808 mMips->LBU(Rd, Rn, amode.value);
809 if (amode.writeback) { // OPTIONAL writeback on pre-index mode
810 mMips->ADDIU(Rn, Rn, amode.value);
811 }
812 break;
813 case AMODE_IMM_12_POST:
814 mMips->LBU(Rd, Rn, 0);
815 mMips->ADDIU(Rn, Rn, amode.value);
816 break;
817 case AMODE_REG_SCALE_PRE:
818 // we only support simple base + index, no advanced modes for this one yet
819 mMips->ADDU(R_at, Rn, amode.reg);
820 mMips->LBU(Rd, R_at, 0);
821 break;
822 }
823
824}
825
826void ArmToMipsAssembler::STR(int cc, int Rd, int Rn, uint32_t offset)
827{
828 mArmPC[mInum++] = pc();
829 // work-around for ARM default address mode of immed12_pre(0)
830 if (offset > AMODE_UNSUPPORTED) offset = 0;
831 switch (offset) {
832 case 0:
833 amode.value = 0;
834 amode.writeback = 0;
835 // fall thru to next case ....
836 case AMODE_IMM_12_PRE:
837 if (Rn == ARMAssemblerInterface::SP) {
838 Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
839 }
840 if (amode.writeback) { // OPTIONAL writeback on pre-index mode
841 // If we will writeback, then update the index reg, then store.
842 // This correctly handles stack-push case.
843 mMips->ADDIU(Rn, Rn, amode.value);
844 mMips->SW(Rd, Rn, 0);
845 } else {
846 // No writeback so store offset by value
847 mMips->SW(Rd, Rn, amode.value);
848 }
849 break;
850 case AMODE_IMM_12_POST:
851 mMips->SW(Rd, Rn, 0);
852 mMips->ADDIU(Rn, Rn, amode.value); // post index always writes back
853 break;
854 case AMODE_REG_SCALE_PRE:
855 // we only support simple base + index, no advanced modes for this one yet
856 mMips->ADDU(R_at, Rn, amode.reg);
857 mMips->SW(Rd, R_at, 0);
858 break;
859 }
860}
861
862void ArmToMipsAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset)
863{
864 mArmPC[mInum++] = pc();
865 // work-around for ARM default address mode of immed12_pre(0)
866 if (offset > AMODE_UNSUPPORTED) offset = 0;
867 switch (offset) {
868 case 0:
869 amode.value = 0;
870 amode.writeback = 0;
871 // fall thru to next case ....
872 case AMODE_IMM_12_PRE:
873 mMips->SB(Rd, Rn, amode.value);
874 if (amode.writeback) { // OPTIONAL writeback on pre-index mode
875 mMips->ADDIU(Rn, Rn, amode.value);
876 }
877 break;
878 case AMODE_IMM_12_POST:
879 mMips->SB(Rd, Rn, 0);
880 mMips->ADDIU(Rn, Rn, amode.value);
881 break;
882 case AMODE_REG_SCALE_PRE:
883 // we only support simple base + index, no advanced modes for this one yet
884 mMips->ADDU(R_at, Rn, amode.reg);
885 mMips->SB(Rd, R_at, 0);
886 break;
887 }
888}
889
890void ArmToMipsAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset)
891{
892 mArmPC[mInum++] = pc();
893 // work-around for ARM default address mode of immed8_pre(0)
894 if (offset > AMODE_UNSUPPORTED) offset = 0;
895 switch (offset) {
896 case 0:
897 amode.value = 0;
898 // fall thru to next case ....
899 case AMODE_IMM_8_PRE: // no support yet for writeback
900 mMips->LHU(Rd, Rn, amode.value);
901 break;
902 case AMODE_IMM_8_POST:
903 mMips->LHU(Rd, Rn, 0);
904 mMips->ADDIU(Rn, Rn, amode.value);
905 break;
906 case AMODE_REG_PRE:
907 // we only support simple base +/- index
908 if (amode.reg >= 0) {
909 mMips->ADDU(R_at, Rn, amode.reg);
910 } else {
911 mMips->SUBU(R_at, Rn, abs(amode.reg));
912 }
913 mMips->LHU(Rd, R_at, 0);
914 break;
915 }
916}
917
918void ArmToMipsAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset)
919{
920 mArmPC[mInum++] = pc();
921 mMips->NOP2();
922 NOT_IMPLEMENTED();
923}
924
925void ArmToMipsAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset)
926{
927 mArmPC[mInum++] = pc();
928 mMips->NOP2();
929 NOT_IMPLEMENTED();
930}
931
932void ArmToMipsAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset)
933{
934 mArmPC[mInum++] = pc();
935 // work-around for ARM default address mode of immed8_pre(0)
936 if (offset > AMODE_UNSUPPORTED) offset = 0;
937 switch (offset) {
938 case 0:
939 amode.value = 0;
940 // fall thru to next case ....
941 case AMODE_IMM_8_PRE: // no support yet for writeback
942 mMips->SH(Rd, Rn, amode.value);
943 break;
944 case AMODE_IMM_8_POST:
945 mMips->SH(Rd, Rn, 0);
946 mMips->ADDIU(Rn, Rn, amode.value);
947 break;
948 case AMODE_REG_PRE:
949 // we only support simple base +/- index
950 if (amode.reg >= 0) {
951 mMips->ADDU(R_at, Rn, amode.reg);
952 } else {
953 mMips->SUBU(R_at, Rn, abs(amode.reg));
954 }
955 mMips->SH(Rd, R_at, 0);
956 break;
957 }
958}
959
960
961
962#if 0
963#pragma mark -
964#pragma mark Block Data Transfer...
965#endif
966
967// block data transfer...
968void ArmToMipsAssembler::LDM(int cc, int dir,
969 int Rn, int W, uint32_t reg_list)
970{ // ED FD EA FA IB IA DB DA
971 // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
972 // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
973 // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
974 // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
975 mArmPC[mInum++] = pc();
976 mMips->NOP2();
977 NOT_IMPLEMENTED();
978}
979
980void ArmToMipsAssembler::STM(int cc, int dir,
981 int Rn, int W, uint32_t reg_list)
982{ // FA EA FD ED IB IA DB DA
983 // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
984 // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
985 // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
986 // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
987 mArmPC[mInum++] = pc();
988 mMips->NOP2();
989 NOT_IMPLEMENTED();
990}
991
992
993
994#if 0
995#pragma mark -
996#pragma mark Special...
997#endif
998
999// special...
1000void ArmToMipsAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
1001 // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
1002 mArmPC[mInum++] = pc();
1003 mMips->NOP2();
1004 NOT_IMPLEMENTED();
1005}
1006
1007void ArmToMipsAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
1008 // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
1009 mArmPC[mInum++] = pc();
1010 mMips->NOP2();
1011 NOT_IMPLEMENTED();
1012}
1013
1014void ArmToMipsAssembler::SWI(int cc, uint32_t comment) {
1015 // *mPC++ = (cc<<28) | (0xF<<24) | comment;
1016 mArmPC[mInum++] = pc();
1017 mMips->NOP2();
1018 NOT_IMPLEMENTED();
1019}
1020
1021
1022#if 0
1023#pragma mark -
1024#pragma mark DSP instructions...
1025#endif
1026
1027// DSP instructions...
1028void ArmToMipsAssembler::PLD(int Rn, uint32_t offset) {
1029 LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
1030 "PLD only P=1, W=0");
1031 // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
1032 mArmPC[mInum++] = pc();
1033 mMips->NOP2();
1034 NOT_IMPLEMENTED();
1035}
1036
1037void ArmToMipsAssembler::CLZ(int cc, int Rd, int Rm)
1038{
1039 mArmPC[mInum++] = pc();
1040 mMips->CLZ(Rd, Rm);
1041}
1042
1043void ArmToMipsAssembler::QADD(int cc, int Rd, int Rm, int Rn)
1044{
1045 // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
1046 mArmPC[mInum++] = pc();
1047 mMips->NOP2();
1048 NOT_IMPLEMENTED();
1049}
1050
1051void ArmToMipsAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
1052{
1053 // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
1054 mArmPC[mInum++] = pc();
1055 mMips->NOP2();
1056 NOT_IMPLEMENTED();
1057}
1058
1059void ArmToMipsAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
1060{
1061 // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
1062 mArmPC[mInum++] = pc();
1063 mMips->NOP2();
1064 NOT_IMPLEMENTED();
1065}
1066
1067void ArmToMipsAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
1068{
1069 // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
1070 mArmPC[mInum++] = pc();
1071 mMips->NOP2();
1072 NOT_IMPLEMENTED();
1073}
1074
1075// 16 x 16 signed multiply (like SMLAxx without the accumulate)
1076void ArmToMipsAssembler::SMUL(int cc, int xy,
1077 int Rd, int Rm, int Rs)
1078{
1079 mArmPC[mInum++] = pc();
1080
1081 // the 16 bits may be in the top or bottom half of 32-bit source reg,
1082 // as defined by the codes BB, BT, TB, TT (compressed param xy)
1083 // where x corresponds to Rm and y to Rs
1084
1085 // select half-reg for Rm
1086 if (xy & xyTB) {
1087 // use top 16-bits
1088 mMips->SRA(R_at, Rm, 16);
1089 } else {
1090 // use bottom 16, but sign-extend to 32
1091 if (mips32r2) {
1092 mMips->SEH(R_at, Rm);
1093 } else {
1094 mMips->SLL(R_at, Rm, 16);
1095 mMips->SRA(R_at, R_at, 16);
1096 }
1097 }
1098 // select half-reg for Rs
1099 if (xy & xyBT) {
1100 // use top 16-bits
1101 mMips->SRA(R_at2, Rs, 16);
1102 } else {
1103 // use bottom 16, but sign-extend to 32
1104 if (mips32r2) {
1105 mMips->SEH(R_at2, Rs);
1106 } else {
1107 mMips->SLL(R_at2, Rs, 16);
1108 mMips->SRA(R_at2, R_at2, 16);
1109 }
1110 }
1111 mMips->MUL(Rd, R_at, R_at2);
1112}
1113
1114// signed 32b x 16b multiple, save top 32-bits of 48-bit result
1115void ArmToMipsAssembler::SMULW(int cc, int y,
1116 int Rd, int Rm, int Rs)
1117{
1118 mArmPC[mInum++] = pc();
1119
1120 // the selector yT or yB refers to reg Rs
1121 if (y & yT) {
1122 // zero the bottom 16-bits, with 2 shifts, it can affect result
1123 mMips->SRL(R_at, Rs, 16);
1124 mMips->SLL(R_at, R_at, 16);
1125
1126 } else {
1127 // move low 16-bit half, to high half
1128 mMips->SLL(R_at, Rs, 16);
1129 }
1130 mMips->MULT(Rm, R_at);
1131 mMips->MFHI(Rd);
1132}
1133
1134// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
1135void ArmToMipsAssembler::SMLA(int cc, int xy,
1136 int Rd, int Rm, int Rs, int Rn)
1137{
1138 mArmPC[mInum++] = pc();
1139
1140 // the 16 bits may be in the top or bottom half of 32-bit source reg,
1141 // as defined by the codes BB, BT, TB, TT (compressed param xy)
1142 // where x corresponds to Rm and y to Rs
1143
1144 // select half-reg for Rm
1145 if (xy & xyTB) {
1146 // use top 16-bits
1147 mMips->SRA(R_at, Rm, 16);
1148 } else {
1149 // use bottom 16, but sign-extend to 32
1150 if (mips32r2) {
1151 mMips->SEH(R_at, Rm);
1152 } else {
1153 mMips->SLL(R_at, Rm, 16);
1154 mMips->SRA(R_at, R_at, 16);
1155 }
1156 }
1157 // select half-reg for Rs
1158 if (xy & xyBT) {
1159 // use top 16-bits
1160 mMips->SRA(R_at2, Rs, 16);
1161 } else {
1162 // use bottom 16, but sign-extend to 32
1163 if (mips32r2) {
1164 mMips->SEH(R_at2, Rs);
1165 } else {
1166 mMips->SLL(R_at2, Rs, 16);
1167 mMips->SRA(R_at2, R_at2, 16);
1168 }
1169 }
1170
1171 mMips->MUL(R_at, R_at, R_at2);
1172 mMips->ADDU(Rd, R_at, Rn);
1173}
1174
1175void ArmToMipsAssembler::SMLAL(int cc, int xy,
1176 int RdHi, int RdLo, int Rs, int Rm)
1177{
1178 // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
1179 mArmPC[mInum++] = pc();
1180 mMips->NOP2();
1181 NOT_IMPLEMENTED();
1182}
1183
1184void ArmToMipsAssembler::SMLAW(int cc, int y,
1185 int Rd, int Rm, int Rs, int Rn)
1186{
1187 // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
1188 mArmPC[mInum++] = pc();
1189 mMips->NOP2();
1190 NOT_IMPLEMENTED();
1191}
1192
1193// used by ARMv6 version of GGLAssembler::filter32
1194void ArmToMipsAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
1195{
1196 mArmPC[mInum++] = pc();
1197
1198 //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
1199 //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
1200
1201 mMips->ROTR(Rm, Rm, rotate * 8);
1202 mMips->AND(Rd, Rm, 0x00FF00FF);
1203}
1204
1205void ArmToMipsAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
1206{
1207 /* Placeholder for UBFX */
1208 mArmPC[mInum++] = pc();
1209
1210 mMips->NOP2();
1211 NOT_IMPLEMENTED();
1212}
1213
1214
1215
1216
1217
1218#if 0
1219#pragma mark -
1220#pragma mark MIPS Assembler...
1221#endif
1222
1223
1224//**************************************************************************
1225//**************************************************************************
1226//**************************************************************************
1227
1228
1229/* mips assembler
1230** this is a subset of mips32r2, targeted specifically at ARM instruction
1231** replacement in the pixelflinger/codeflinger code.
1232**
1233** To that end, there is no need for floating point, or priviledged
1234** instructions. This all runs in user space, no float.
1235**
1236** The syntax makes no attempt to be as complete as the assember, with
1237** synthetic instructions, and automatic recognition of immedate operands
1238** (use the immediate form of the instruction), etc.
1239**
1240** We start with mips32r1, and may add r2 and dsp extensions if cpu
1241** supports. Decision will be made at compile time, based on gcc
1242** options. (makes sense since android will be built for a a specific
1243** device)
1244*/
1245
1246MIPSAssembler::MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent)
1247 : mParent(parent),
1248 mAssembly(assembly)
1249{
1250 mBase = mPC = (uint32_t *)assembly->base();
1251 mDuration = ggl_system_time();
1252}
1253
Ljubomir Papugae0c9f2b2015-12-15 15:23:01 +01001254MIPSAssembler::MIPSAssembler(void* assembly)
1255 : mParent(NULL), mAssembly(NULL)
1256{
1257 mBase = mPC = (uint32_t *)assembly;
1258}
1259
Paul Lind2bc2b792012-02-01 10:54:19 -08001260MIPSAssembler::~MIPSAssembler()
1261{
1262}
1263
1264
1265uint32_t* MIPSAssembler::pc() const
1266{
1267 return mPC;
1268}
1269
1270uint32_t* MIPSAssembler::base() const
1271{
1272 return mBase;
1273}
1274
1275void MIPSAssembler::reset()
1276{
1277 mBase = mPC = (uint32_t *)mAssembly->base();
1278 mBranchTargets.clear();
1279 mLabels.clear();
1280 mLabelsInverseMapping.clear();
1281 mComments.clear();
1282}
1283
1284
1285// convert tabs to spaces, and remove any newline
1286// works with strings of limited size (makes a temp copy)
1287#define TABSTOP 8
1288void MIPSAssembler::string_detab(char *s)
1289{
1290 char *os = s;
1291 char temp[100];
1292 char *t = temp;
1293 int len = 99;
1294 int i = TABSTOP;
1295
1296 while (*s && len-- > 0) {
1297 if (*s == '\n') { s++; continue; }
1298 if (*s == '\t') {
1299 s++;
1300 for ( ; i>0; i--) {*t++ = ' '; len--; }
1301 } else {
1302 *t++ = *s++;
1303 }
1304 if (i <= 0) i = TABSTOP;
1305 i--;
1306 }
1307 *t = '\0';
1308 strcpy(os, temp);
1309}
1310
1311void MIPSAssembler::string_pad(char *s, int padded_len)
1312{
1313 int len = strlen(s);
1314 s += len;
1315 for (int i = padded_len - len; i > 0; --i) {
1316 *s++ = ' ';
1317 }
1318 *s = '\0';
1319}
1320
1321// ----------------------------------------------------------------------------
1322
1323void MIPSAssembler::disassemble(const char* name)
1324{
1325 char di_buf[140];
1326
1327 if (name) {
1328 ALOGW("%s:\n", name);
1329 }
1330
1331 bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
1332
1333 typedef char dstr[40];
1334 dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
1335
1336 if (mParent->mArmDisassemblyBuffer != NULL) {
1337 for (int i=0; i<mParent->mArmInstrCount; ++i) {
1338 string_detab(lines[i]);
1339 }
1340 }
1341
1342 // iArm is an index to Arm instructions 1...n for this assembly sequence
1343 // mArmPC[iArm] holds the value of the Mips-PC for the first MIPS
1344 // instruction corresponding to that Arm instruction number
1345
1346 int iArm = 0;
1347 size_t count = pc()-base();
1348 uint32_t* mipsPC = base();
1349 while (count--) {
1350 ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
1351 if (label >= 0) {
1352 ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
1353 }
1354 ssize_t comment = mComments.indexOfKey(mipsPC);
1355 if (comment >= 0) {
1356 ALOGW("; %s\n", mComments.valueAt(comment));
1357 }
1358 // ALOGW("%08x: %08x ", int(i), int(i[0]));
1359 ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
1360 string_detab(di_buf);
1361 string_pad(di_buf, 30);
Elliott Hughes606d4ae2015-11-05 18:55:20 +00001362 ALOGW("%08x: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf);
Paul Lind2bc2b792012-02-01 10:54:19 -08001363 mipsPC++;
1364 }
1365}
1366
1367void MIPSAssembler::comment(const char* string)
1368{
1369 mComments.add(pc(), string);
1370}
1371
1372void MIPSAssembler::label(const char* theLabel)
1373{
1374 mLabels.add(theLabel, pc());
1375 mLabelsInverseMapping.add(pc(), theLabel);
1376}
1377
1378
1379void MIPSAssembler::prolog()
1380{
1381 // empty - done in ArmToMipsAssembler
1382}
1383
1384void MIPSAssembler::epilog(uint32_t touched)
1385{
1386 // empty - done in ArmToMipsAssembler
1387}
1388
1389int MIPSAssembler::generate(const char* name)
1390{
1391 // fixup all the branches
1392 size_t count = mBranchTargets.size();
1393 while (count--) {
1394 const branch_target_t& bt = mBranchTargets[count];
1395 uint32_t* target_pc = mLabels.valueFor(bt.label);
1396 LOG_ALWAYS_FATAL_IF(!target_pc,
1397 "error resolving branch targets, target_pc is null");
1398 int32_t offset = int32_t(target_pc - (bt.pc+1));
1399 *bt.pc |= offset & 0x00FFFF;
1400 }
1401
1402 mAssembly->resize( int(pc()-base())*4 );
1403
1404 // the instruction & data caches are flushed by CodeCache
1405 const int64_t duration = ggl_system_time() - mDuration;
1406 const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
1407 ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
1408
Paul Lind2bc2b792012-02-01 10:54:19 -08001409 char value[PROPERTY_VALUE_MAX];
1410 value[0] = '\0';
1411
1412 property_get("debug.pf.disasm", value, "0");
1413
1414 if (atoi(value) != 0) {
1415 disassemble(name);
1416 }
1417
1418 return NO_ERROR;
1419}
1420
1421uint32_t* MIPSAssembler::pcForLabel(const char* label)
1422{
1423 return mLabels.valueFor(label);
1424}
1425
1426
1427
1428#if 0
1429#pragma mark -
1430#pragma mark Arithmetic...
1431#endif
1432
1433void MIPSAssembler::ADDU(int Rd, int Rs, int Rt)
1434{
1435 *mPC++ = (spec_op<<OP_SHF) | (addu_fn<<FUNC_SHF)
1436 | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
1437}
1438
1439// MD00086 pdf says this is: ADDIU rt, rs, imm -- they do not use Rd
1440void MIPSAssembler::ADDIU(int Rt, int Rs, int16_t imm)
1441{
1442 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1443}
1444
1445
1446void MIPSAssembler::SUBU(int Rd, int Rs, int Rt)
1447{
1448 *mPC++ = (spec_op<<OP_SHF) | (subu_fn<<FUNC_SHF) |
1449 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
1450}
1451
1452
1453void MIPSAssembler::SUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j)
1454{
1455 *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
1456}
1457
1458
1459void MIPSAssembler::NEGU(int Rd, int Rs) // really subu(d, zero, s)
1460{
1461 MIPSAssembler::SUBU(Rd, 0, Rs);
1462}
1463
1464void MIPSAssembler::MUL(int Rd, int Rs, int Rt)
1465{
1466 *mPC++ = (spec2_op<<OP_SHF) | (mul_fn<<FUNC_SHF) |
1467 (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
1468}
1469
1470void MIPSAssembler::MULT(int Rs, int Rt) // dest is hi,lo
1471{
1472 *mPC++ = (spec_op<<OP_SHF) | (mult_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1473}
1474
1475void MIPSAssembler::MULTU(int Rs, int Rt) // dest is hi,lo
1476{
1477 *mPC++ = (spec_op<<OP_SHF) | (multu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1478}
1479
1480void MIPSAssembler::MADD(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
1481{
1482 *mPC++ = (spec2_op<<OP_SHF) | (madd_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1483}
1484
1485void MIPSAssembler::MADDU(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
1486{
1487 *mPC++ = (spec2_op<<OP_SHF) | (maddu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1488}
1489
1490
1491void MIPSAssembler::MSUB(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
1492{
1493 *mPC++ = (spec2_op<<OP_SHF) | (msub_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1494}
1495
1496void MIPSAssembler::MSUBU(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
1497{
1498 *mPC++ = (spec2_op<<OP_SHF) | (msubu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
1499}
1500
1501
1502void MIPSAssembler::SEB(int Rd, int Rt) // sign-extend byte (mips32r2)
1503{
1504 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seb_fn << SA_SHF) |
1505 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1506}
1507
1508void MIPSAssembler::SEH(int Rd, int Rt) // sign-extend half-word (mips32r2)
1509{
1510 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seh_fn << SA_SHF) |
1511 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1512}
1513
1514
1515
1516#if 0
1517#pragma mark -
1518#pragma mark Comparisons...
1519#endif
1520
1521void MIPSAssembler::SLT(int Rd, int Rs, int Rt)
1522{
1523 *mPC++ = (spec_op<<OP_SHF) | (slt_fn<<FUNC_SHF) |
1524 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1525}
1526
1527void MIPSAssembler::SLTI(int Rt, int Rs, int16_t imm)
1528{
1529 *mPC++ = (slti_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1530}
1531
1532
1533void MIPSAssembler::SLTU(int Rd, int Rs, int Rt)
1534{
1535 *mPC++ = (spec_op<<OP_SHF) | (sltu_fn<<FUNC_SHF) |
1536 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1537}
1538
1539void MIPSAssembler::SLTIU(int Rt, int Rs, int16_t imm)
1540{
1541 *mPC++ = (sltiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1542}
1543
1544
1545
1546#if 0
1547#pragma mark -
1548#pragma mark Logical...
1549#endif
1550
1551void MIPSAssembler::AND(int Rd, int Rs, int Rt)
1552{
1553 *mPC++ = (spec_op<<OP_SHF) | (and_fn<<FUNC_SHF) |
1554 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1555}
1556
1557void MIPSAssembler::ANDI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
1558{
1559 *mPC++ = (andi_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1560}
1561
1562
1563void MIPSAssembler::OR(int Rd, int Rs, int Rt)
1564{
1565 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
1566 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1567}
1568
1569void MIPSAssembler::ORI(int Rt, int Rs, uint16_t imm)
1570{
1571 *mPC++ = (ori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1572}
1573
1574void MIPSAssembler::NOR(int Rd, int Rs, int Rt)
1575{
1576 *mPC++ = (spec_op<<OP_SHF) | (nor_fn<<FUNC_SHF) |
1577 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1578}
1579
1580void MIPSAssembler::NOT(int Rd, int Rs)
1581{
1582 MIPSAssembler::NOR(Rd, Rs, 0); // NOT(d,s) = NOR(d,s,zero)
1583}
1584
1585void MIPSAssembler::XOR(int Rd, int Rs, int Rt)
1586{
1587 *mPC++ = (spec_op<<OP_SHF) | (xor_fn<<FUNC_SHF) |
1588 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1589}
1590
1591void MIPSAssembler::XORI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
1592{
1593 *mPC++ = (xori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
1594}
1595
1596void MIPSAssembler::SLL(int Rd, int Rt, int shft)
1597{
1598 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) |
1599 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1600}
1601
1602void MIPSAssembler::SLLV(int Rd, int Rt, int Rs)
1603{
1604 *mPC++ = (spec_op<<OP_SHF) | (sllv_fn<<FUNC_SHF) |
1605 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1606}
1607
1608void MIPSAssembler::SRL(int Rd, int Rt, int shft)
1609{
1610 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
1611 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1612}
1613
1614void MIPSAssembler::SRLV(int Rd, int Rt, int Rs)
1615{
1616 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
1617 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1618}
1619
1620void MIPSAssembler::SRA(int Rd, int Rt, int shft)
1621{
1622 *mPC++ = (spec_op<<OP_SHF) | (sra_fn<<FUNC_SHF) |
1623 (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1624}
1625
1626void MIPSAssembler::SRAV(int Rd, int Rt, int Rs)
1627{
1628 *mPC++ = (spec_op<<OP_SHF) | (srav_fn<<FUNC_SHF) |
1629 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1630}
1631
1632void MIPSAssembler::ROTR(int Rd, int Rt, int shft) // mips32r2
1633{
1634 // note weird encoding (SRL + 1)
1635 *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
1636 (1<<RS_SHF) | (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
1637}
1638
1639void MIPSAssembler::ROTRV(int Rd, int Rt, int Rs) // mips32r2
1640{
1641 // note weird encoding (SRLV + 1)
1642 *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
1643 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (1<<RE_SHF);
1644}
1645
1646// uses at2 register (mapped to some appropriate mips reg)
1647void MIPSAssembler::RORsyn(int Rd, int Rt, int Rs)
1648{
1649 // synthetic: d = t rotated by s
1650 MIPSAssembler::NEGU(R_at2, Rs);
1651 MIPSAssembler::SLLV(R_at2, Rt, R_at2);
1652 MIPSAssembler::SRLV(Rd, Rt, Rs);
1653 MIPSAssembler::OR(Rd, Rd, R_at2);
1654}
1655
1656// immediate version - uses at2 register (mapped to some appropriate mips reg)
1657void MIPSAssembler::RORIsyn(int Rd, int Rt, int rot)
1658{
1659 // synthetic: d = t rotated by immed rot
1660 // d = s >> rot | s << (32-rot)
1661 MIPSAssembler::SLL(R_at2, Rt, 32-rot);
1662 MIPSAssembler::SRL(Rd, Rt, rot);
1663 MIPSAssembler::OR(Rd, Rd, R_at2);
1664}
1665
1666void MIPSAssembler::CLO(int Rd, int Rs)
1667{
1668 // Rt field must have same gpr # as Rd
1669 *mPC++ = (spec2_op<<OP_SHF) | (clo_fn<<FUNC_SHF) |
1670 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
1671}
1672
1673void MIPSAssembler::CLZ(int Rd, int Rs)
1674{
1675 // Rt field must have same gpr # as Rd
1676 *mPC++ = (spec2_op<<OP_SHF) | (clz_fn<<FUNC_SHF) |
1677 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
1678}
1679
1680void MIPSAssembler::WSBH(int Rd, int Rt) // mips32r2
1681{
1682 *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (wsbh_fn << SA_SHF) |
1683 (Rt<<RT_SHF) | (Rd<<RD_SHF);
1684}
1685
1686
1687
1688#if 0
1689#pragma mark -
1690#pragma mark Load/store...
1691#endif
1692
1693void MIPSAssembler::LW(int Rt, int Rbase, int16_t offset)
1694{
1695 *mPC++ = (lw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1696}
1697
1698void MIPSAssembler::SW(int Rt, int Rbase, int16_t offset)
1699{
1700 *mPC++ = (sw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1701}
1702
1703// lb is sign-extended
1704void MIPSAssembler::LB(int Rt, int Rbase, int16_t offset)
1705{
1706 *mPC++ = (lb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1707}
1708
1709void MIPSAssembler::LBU(int Rt, int Rbase, int16_t offset)
1710{
1711 *mPC++ = (lbu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1712}
1713
1714void MIPSAssembler::SB(int Rt, int Rbase, int16_t offset)
1715{
1716 *mPC++ = (sb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1717}
1718
1719// lh is sign-extended
1720void MIPSAssembler::LH(int Rt, int Rbase, int16_t offset)
1721{
1722 *mPC++ = (lh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1723}
1724
1725void MIPSAssembler::LHU(int Rt, int Rbase, int16_t offset)
1726{
1727 *mPC++ = (lhu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1728}
1729
1730void MIPSAssembler::SH(int Rt, int Rbase, int16_t offset)
1731{
1732 *mPC++ = (sh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1733}
1734
1735void MIPSAssembler::LUI(int Rt, int16_t offset)
1736{
1737 *mPC++ = (lui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
1738}
1739
1740
1741
1742#if 0
1743#pragma mark -
1744#pragma mark Register move...
1745#endif
1746
1747void MIPSAssembler::MOVE(int Rd, int Rs)
1748{
1749 // encoded as "or rd, rs, zero"
1750 *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
1751 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (0<<RT_SHF);
1752}
1753
1754void MIPSAssembler::MOVN(int Rd, int Rs, int Rt)
1755{
1756 *mPC++ = (spec_op<<OP_SHF) | (movn_fn<<FUNC_SHF) |
1757 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1758}
1759
1760void MIPSAssembler::MOVZ(int Rd, int Rs, int Rt)
1761{
1762 *mPC++ = (spec_op<<OP_SHF) | (movz_fn<<FUNC_SHF) |
1763 (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
1764}
1765
1766void MIPSAssembler::MFHI(int Rd)
1767{
1768 *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1769}
1770
1771void MIPSAssembler::MFLO(int Rd)
1772{
1773 *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF);
1774}
1775
1776void MIPSAssembler::MTHI(int Rs)
1777{
1778 *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF);
1779}
1780
1781void MIPSAssembler::MTLO(int Rs)
1782{
1783 *mPC++ = (spec_op<<OP_SHF) | (mtlo_fn<<FUNC_SHF) | (Rs<<RS_SHF);
1784}
1785
1786
1787
1788#if 0
1789#pragma mark -
1790#pragma mark Branch...
1791#endif
1792
1793// temporarily forcing a NOP into branch-delay slot, just to be safe
1794// todo: remove NOP, optimze use of delay slots
1795void MIPSAssembler::B(const char* label)
1796{
1797 mBranchTargets.add(branch_target_t(label, mPC));
1798
1799 // encoded as BEQ zero, zero, offset
1800 *mPC++ = (beq_op<<OP_SHF) | (0<<RT_SHF)
1801 | (0<<RS_SHF) | 0; // offset filled in later
1802
1803 MIPSAssembler::NOP();
1804}
1805
1806void MIPSAssembler::BEQ(int Rs, int Rt, const char* label)
1807{
1808 mBranchTargets.add(branch_target_t(label, mPC));
1809 *mPC++ = (beq_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
1810 MIPSAssembler::NOP();
1811}
1812
1813void MIPSAssembler::BNE(int Rs, int Rt, const char* label)
1814{
1815 mBranchTargets.add(branch_target_t(label, mPC));
1816 *mPC++ = (bne_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
1817 MIPSAssembler::NOP();
1818}
1819
1820void MIPSAssembler::BLEZ(int Rs, const char* label)
1821{
1822 mBranchTargets.add(branch_target_t(label, mPC));
1823 *mPC++ = (blez_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
1824 MIPSAssembler::NOP();
1825}
1826
1827void MIPSAssembler::BLTZ(int Rs, const char* label)
1828{
1829 mBranchTargets.add(branch_target_t(label, mPC));
1830 *mPC++ = (regimm_op<<OP_SHF) | (bltz_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
1831 MIPSAssembler::NOP();
1832}
1833
1834void MIPSAssembler::BGTZ(int Rs, const char* label)
1835{
1836 mBranchTargets.add(branch_target_t(label, mPC));
1837 *mPC++ = (bgtz_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
1838 MIPSAssembler::NOP();
1839}
1840
1841
1842void MIPSAssembler::BGEZ(int Rs, const char* label)
1843{
1844 mBranchTargets.add(branch_target_t(label, mPC));
1845 *mPC++ = (regimm_op<<OP_SHF) | (bgez_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
1846 MIPSAssembler::NOP();
1847}
1848
1849void MIPSAssembler::JR(int Rs)
1850{
1851 *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jr_fn << FUNC_SHF);
1852 MIPSAssembler::NOP();
1853}
1854
1855
1856#if 0
1857#pragma mark -
1858#pragma mark Synthesized Branch...
1859#endif
1860
1861// synthetic variants of branches (using slt & friends)
1862void MIPSAssembler::BEQZ(int Rs, const char* label)
1863{
1864 BEQ(Rs, R_zero, label);
1865}
1866
1867void MIPSAssembler::BNEZ(int Rs, const char* label)
1868{
1869 BNE(R_at, R_zero, label);
1870}
1871
1872void MIPSAssembler::BGE(int Rs, int Rt, const char* label)
1873{
1874 SLT(R_at, Rs, Rt);
1875 BEQ(R_at, R_zero, label);
1876}
1877
1878void MIPSAssembler::BGEU(int Rs, int Rt, const char* label)
1879{
1880 SLTU(R_at, Rs, Rt);
1881 BEQ(R_at, R_zero, label);
1882}
1883
1884void MIPSAssembler::BGT(int Rs, int Rt, const char* label)
1885{
1886 SLT(R_at, Rt, Rs); // rev
1887 BNE(R_at, R_zero, label);
1888}
1889
1890void MIPSAssembler::BGTU(int Rs, int Rt, const char* label)
1891{
1892 SLTU(R_at, Rt, Rs); // rev
1893 BNE(R_at, R_zero, label);
1894}
1895
1896void MIPSAssembler::BLE(int Rs, int Rt, const char* label)
1897{
1898 SLT(R_at, Rt, Rs); // rev
1899 BEQ(R_at, R_zero, label);
1900}
1901
1902void MIPSAssembler::BLEU(int Rs, int Rt, const char* label)
1903{
1904 SLTU(R_at, Rt, Rs); // rev
1905 BEQ(R_at, R_zero, label);
1906}
1907
1908void MIPSAssembler::BLT(int Rs, int Rt, const char* label)
1909{
1910 SLT(R_at, Rs, Rt);
1911 BNE(R_at, R_zero, label);
1912}
1913
1914void MIPSAssembler::BLTU(int Rs, int Rt, const char* label)
1915{
1916 SLTU(R_at, Rs, Rt);
1917 BNE(R_at, R_zero, label);
1918}
1919
1920
1921
1922
1923#if 0
1924#pragma mark -
1925#pragma mark Misc...
1926#endif
1927
1928void MIPSAssembler::NOP(void)
1929{
1930 // encoded as "sll zero, zero, 0", which is all zero
1931 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF);
1932}
1933
1934// using this as special opcode for not-yet-implemented ARM instruction
1935void MIPSAssembler::NOP2(void)
1936{
1937 // encoded as "sll zero, zero, 2", still a nop, but a unique code
1938 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (2 << RE_SHF);
1939}
1940
1941// using this as special opcode for purposefully NOT implemented ARM instruction
1942void MIPSAssembler::UNIMPL(void)
1943{
1944 // encoded as "sll zero, zero, 3", still a nop, but a unique code
1945 *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (3 << RE_SHF);
1946}
1947
1948
1949}; // namespace android:
1950
1951