summaryrefslogtreecommitdiff
path: root/compiler/utils/mips/assembler_mips.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils/mips/assembler_mips.h')
-rw-r--r--compiler/utils/mips/assembler_mips.h115
1 files changed, 85 insertions, 30 deletions
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index a7ff931e7e..7f9d5763f1 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -636,29 +636,69 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
void LoadSConst32(FRegister r, int32_t value, Register temp);
void Addiu32(Register rt, Register rs, int32_t value, Register rtmp = AT);
- // These will generate R2 branches or R6 branches as appropriate and take care of
- // the delay/forbidden slots.
void Bind(MipsLabel* label);
- void B(MipsLabel* label);
- void Bal(MipsLabel* label);
- void Beq(Register rs, Register rt, MipsLabel* label);
- void Bne(Register rs, Register rt, MipsLabel* label);
- void Beqz(Register rt, MipsLabel* label);
- void Bnez(Register rt, MipsLabel* label);
- void Bltz(Register rt, MipsLabel* label);
- void Bgez(Register rt, MipsLabel* label);
- void Blez(Register rt, MipsLabel* label);
- void Bgtz(Register rt, MipsLabel* label);
- void Blt(Register rs, Register rt, MipsLabel* label);
- void Bge(Register rs, Register rt, MipsLabel* label);
- void Bltu(Register rs, Register rt, MipsLabel* label);
- void Bgeu(Register rs, Register rt, MipsLabel* label);
- void Bc1f(MipsLabel* label); // R2
- void Bc1f(int cc, MipsLabel* label); // R2
- void Bc1t(MipsLabel* label); // R2
- void Bc1t(int cc, MipsLabel* label); // R2
- void Bc1eqz(FRegister ft, MipsLabel* label); // R6
- void Bc1nez(FRegister ft, MipsLabel* label); // R6
+ // When `is_bare` is false, the branches will promote to long (if the range
+ // of the individual branch instruction is insufficient) and the delay/
+ // forbidden slots will be taken care of.
+ // Use `is_bare = false` when the branch target may be out of reach of the
+ // individual branch instruction. IOW, this is for general purpose use.
+ //
+ // When `is_bare` is true, just the branch instructions will be generated
+ // leaving delay/forbidden slot filling up to the caller and the branches
+ // won't promote to long if the range is insufficient (you'll get a
+ // compilation error when the range is exceeded).
+ // Use `is_bare = true` when the branch target is known to be within reach
+ // of the individual branch instruction. This is intended for small local
+ // optimizations around delay/forbidden slots.
+ // Also prefer using `is_bare = true` if the code near the branch is to be
+ // patched or analyzed at run time (e.g. introspection) to
+ // - show the intent and
+ // - fail during compilation rather than during patching/execution if the
+ // bare branch range is insufficent but the code size and layout are
+ // expected to remain unchanged
+ //
+ // R2 branches with delay slots that are also available on R6.
+ // On R6 when `is_bare` is false these convert to equivalent R6 compact
+ // branches (to reduce code size). On R2 or when `is_bare` is true they
+ // remain R2 branches with delay slots.
+ void B(MipsLabel* label, bool is_bare = false);
+ void Bal(MipsLabel* label, bool is_bare = false);
+ void Beq(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bne(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Beqz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bnez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bltz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Blez(Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgtz(Register rt, MipsLabel* label, bool is_bare = false);
+ void Blt(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bge(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bltu(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ void Bgeu(Register rs, Register rt, MipsLabel* label, bool is_bare = false);
+ // R2-only branches with delay slots.
+ void Bc1f(MipsLabel* label, bool is_bare = false); // R2
+ void Bc1f(int cc, MipsLabel* label, bool is_bare = false); // R2
+ void Bc1t(MipsLabel* label, bool is_bare = false); // R2
+ void Bc1t(int cc, MipsLabel* label, bool is_bare = false); // R2
+ // R6-only compact branches without delay/forbidden slots.
+ void Bc(MipsLabel* label, bool is_bare = false); // R6
+ void Balc(MipsLabel* label, bool is_bare = false); // R6
+ // R6-only compact branches with forbidden slots.
+ void Beqc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bnec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Beqzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bnezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Blezc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgtzc(Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgec(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bltuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ void Bgeuc(Register rs, Register rt, MipsLabel* label, bool is_bare = false); // R6
+ // R6-only branches with delay slots.
+ void Bc1eqz(FRegister ft, MipsLabel* label, bool is_bare = false); // R6
+ void Bc1nez(FRegister ft, MipsLabel* label, bool is_bare = false); // R6
void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size);
void AdjustBaseAndOffset(Register& base,
@@ -1268,10 +1308,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
class Branch {
public:
enum Type {
- // R2 short branches.
+ // R2 short branches (can be promoted to long).
kUncondBranch,
kCondBranch,
kCall,
+ // R2 short branches (can't be promoted to long), delay slots filled manually.
+ kBareUncondBranch,
+ kBareCondBranch,
+ kBareCall,
// R2 near label.
kLabel,
// R2 near literal.
@@ -1284,10 +1328,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
kFarLabel,
// R2 far literal.
kFarLiteral,
- // R6 short branches.
+ // R6 short branches (can be promoted to long).
kR6UncondBranch,
kR6CondBranch,
kR6Call,
+ // R6 short branches (can't be promoted to long), forbidden/delay slots filled manually.
+ kR6BareUncondBranch,
+ kR6BareCondBranch,
+ kR6BareCall,
// R6 near label.
kR6Label,
// R6 near literal.
@@ -1337,7 +1385,7 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
// instructions) from the instruction containing the offset.
uint32_t pc_org;
// How large (in bits) a PC-relative offset can be for a given type of branch (kR6CondBranch
- // is an exception: use kOffset23 for beqzc/bnezc).
+ // and kR6BareCondBranch are an exception: use kOffset23 for beqzc/bnezc).
OffsetBits offset_size;
// Some MIPS instructions with PC-relative offsets shift the offset by 2. Encode the shift
// count.
@@ -1346,14 +1394,15 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
static const BranchInfo branch_info_[/* Type */];
// Unconditional branch or call.
- Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call);
+ Branch(bool is_r6, uint32_t location, uint32_t target, bool is_call, bool is_bare);
// Conditional branch.
Branch(bool is_r6,
uint32_t location,
uint32_t target,
BranchCondition condition,
Register lhs_reg,
- Register rhs_reg);
+ Register rhs_reg,
+ bool is_bare);
// Label address (in literal area) or literal.
Branch(bool is_r6,
uint32_t location,
@@ -1385,6 +1434,7 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
uint32_t GetOldSize() const;
uint32_t GetEndLocation() const;
uint32_t GetOldEndLocation() const;
+ bool IsBare() const;
bool IsLong() const;
bool IsResolved() const;
@@ -1513,9 +1563,14 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi
VectorRegister wd,
int minor_opcode);
- void Buncond(MipsLabel* label);
- void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO);
- void Call(MipsLabel* label);
+ void Buncond(MipsLabel* label, bool is_r6, bool is_bare);
+ void Bcond(MipsLabel* label,
+ bool is_r6,
+ bool is_bare,
+ BranchCondition condition,
+ Register lhs,
+ Register rhs = ZERO);
+ void Call(MipsLabel* label, bool is_r6, bool is_bare);
void FinalizeLabeledBranch(MipsLabel* label);
// Various helpers for branch delay slot management.