MIPS32: Implement table-based packed switch
Test: booted MIPS32R2 in QEMU
Test: test-art-target-run-test-optimizing (MIPS32R2) on CI20
Test: booted MIPS64 (with 2nd arch MIPS32R6) in QEMU
Test: test-art-target-run-test-optimizing (MIPS32R6) in QEMU
Test: test-art-host-gtest
Change-Id: I2e1a65ff1ba9406b84351ba7998f853b1ce4aef9
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index d50c439..099620c 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -126,6 +126,36 @@
DISALLOW_COPY_AND_ASSIGN(Literal);
};
+// Jump table: table of labels emitted after the literals. Similar to literals.
+class JumpTable {
+ public:
+ explicit JumpTable(std::vector<MipsLabel*>&& labels)
+ : label_(), labels_(std::move(labels)) {
+ }
+
+ uint32_t GetSize() const {
+ return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
+ }
+
+ const std::vector<MipsLabel*>& GetData() const {
+ return labels_;
+ }
+
+ MipsLabel* GetLabel() {
+ return &label_;
+ }
+
+ const MipsLabel* GetLabel() const {
+ return &label_;
+ }
+
+ private:
+ MipsLabel label_;
+ std::vector<MipsLabel*> labels_;
+
+ DISALLOW_COPY_AND_ASSIGN(JumpTable);
+};
+
// Slowpath entered when Thread::Current()->_exception is non-null.
class MipsExceptionSlowPath {
public:
@@ -158,6 +188,7 @@
ds_fsm_state_(kExpectingLabel),
ds_fsm_target_pc_(0),
literals_(arena->Adapter(kArenaAllocAssembler)),
+ jump_tables_(arena->Adapter(kArenaAllocAssembler)),
last_position_adjustment_(0),
last_old_position_(0),
last_branch_id_(0),
@@ -685,6 +716,11 @@
return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
}
+ // Load label address using the base register (for R2 only) or using PC-relative loads
+ // (for R6 only; base_reg must be ZERO). To be used with data labels in the literal /
+ // jump table area only and not with regular code labels.
+ void LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label);
+
// Create a new literal with the given data.
Literal* NewLiteral(size_t size, const uint8_t* data);
@@ -692,6 +728,12 @@
// (for R6 only; base_reg must be ZERO).
void LoadLiteral(Register dest_reg, Register base_reg, Literal* literal);
+ // Create a jump table for the given labels that will be emitted when finalizing.
+ // When the table is emitted, offsets will be relative to the location of the table.
+ // The table location is determined by the location of its label (the label precedes
+ // the table data) and should be loaded using LoadLabelAddress().
+ JumpTable* CreateJumpTable(std::vector<MipsLabel*>&& labels);
+
//
// Overridden common assembler high-level functionality.
//
@@ -935,24 +977,32 @@
kUncondBranch,
kCondBranch,
kCall,
+ // R2 near label.
+ kLabel,
// R2 near literal.
kLiteral,
// R2 long branches.
kLongUncondBranch,
kLongCondBranch,
kLongCall,
+ // R2 far label.
+ kFarLabel,
// R2 far literal.
kFarLiteral,
// R6 short branches.
kR6UncondBranch,
kR6CondBranch,
kR6Call,
+ // R6 near label.
+ kR6Label,
// R6 near literal.
kR6Literal,
// R6 long branches.
kR6LongUncondBranch,
kR6LongCondBranch,
kR6LongCall,
+ // R6 far label.
+ kR6FarLabel,
// R6 far literal.
kR6FarLiteral,
};
@@ -1009,8 +1059,12 @@
BranchCondition condition,
Register lhs_reg,
Register rhs_reg);
- // Literal.
- Branch(bool is_r6, uint32_t location, Register dest_reg, Register base_reg);
+ // Label address (in literal area) or literal.
+ Branch(bool is_r6,
+ uint32_t location,
+ Register dest_reg,
+ Register base_reg,
+ Type label_or_literal_type);
// Some conditional branches with lhs = rhs are effectively NOPs, while some
// others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
@@ -1105,7 +1159,7 @@
private:
// Completes branch construction by determining and recording its type.
- void InitializeType(bool is_call, bool is_literal, bool is_r6);
+ void InitializeType(Type initial_type, bool is_r6);
// Helper for the above.
void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
@@ -1178,6 +1232,8 @@
uint32_t GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const;
void EmitLiterals();
+ void ReserveJumpTableSpace();
+ void EmitJumpTables();
void PromoteBranches();
void EmitBranch(Branch* branch);
void EmitBranches();
@@ -1227,6 +1283,9 @@
// without invalidating pointers and references to existing elements.
ArenaDeque<Literal> literals_;
+ // Jump table list.
+ ArenaDeque<JumpTable> jump_tables_;
+
// There's no PC-relative addressing on MIPS32R2. So, in order to access literals relative to PC
// we get PC using the NAL instruction. This label marks the position within the assembler buffer
// that PC (from NAL) points to.