Support additional instructions in ARM and thumb assemblers
This adds the following support for the ARM and thumb assemblers:
1. Shifting by a register.
2. LDR/STR with a register offset, possibly shifted.
3. LDR(literal).
4. STR PC relative.
Also adds tests for them in the thumb assembler gtest.
Change-Id: Ie467e3c1d06b699cacbdef3482ed9a92e4f1809b
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 7b662e1..be19174 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -68,7 +68,7 @@
}
uint32_t encodingArm() const;
- uint32_t encodingThumb(int version) const;
+ uint32_t encodingThumb() const;
bool IsEmpty() const {
return type_ == kUnknown;
@@ -196,8 +196,26 @@
NegPostIndex = (0|0|0) << 21 // negative post-indexed with writeback
};
- explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), offset_(offset),
- am_(am) {
+ Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
+ offset_(offset),
+ am_(am), is_immed_offset_(true), shift_(LSL) {
+ }
+
+ Address(Register rn, Register rm, Mode am = Offset) : rn_(rn), rm_(rm), offset_(0),
+ am_(am), is_immed_offset_(false), shift_(LSL) {
+ CHECK_NE(rm, PC);
+ }
+
+ Address(Register rn, Register rm, Shift shift, uint32_t count, Mode am = Offset) :
+ rn_(rn), rm_(rm), offset_(count),
+ am_(am), is_immed_offset_(false), shift_(shift) {
+ CHECK_NE(rm, PC);
+ }
+
+ // LDR(literal) - pc relative load.
+ explicit Address(int32_t offset) :
+ rn_(PC), rm_(R0), offset_(offset),
+ am_(Offset), is_immed_offset_(false), shift_(LSL) {
}
static bool CanHoldLoadOffsetArm(LoadOperandType type, int offset);
@@ -207,7 +225,7 @@
static bool CanHoldStoreOffsetThumb(StoreOperandType type, int offset);
uint32_t encodingArm() const;
- uint32_t encodingThumb(int version) const;
+ uint32_t encodingThumb(bool is_32bit) const;
uint32_t encoding3() const;
uint32_t vencoding() const;
@@ -218,6 +236,10 @@
return rn_;
}
+ Register GetRegisterOffset() const {
+ return rm_;
+ }
+
int32_t GetOffset() const {
return offset_;
}
@@ -226,10 +248,26 @@
return am_;
}
+ bool IsImmediate() const {
+ return is_immed_offset_;
+ }
+
+ Shift GetShift() const {
+ return shift_;
+ }
+
+ int32_t GetShiftCount() const {
+ CHECK(!is_immed_offset_);
+ return offset_;
+ }
+
private:
Register rn_;
- int32_t offset_;
+ Register rm_;
+ int32_t offset_; // Used as shift amount for register offset.
Mode am_;
+ bool is_immed_offset_;
+ Shift shift_;
};
// Instruction encoding bits.
@@ -544,11 +582,25 @@
// Convenience shift instructions. Use mov instruction with shifter operand
// for variants setting the status flags or using a register shift count.
- virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0;
- virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0;
- virtual void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0;
- virtual void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL) = 0;
- virtual void Rrx(Register rd, Register rm, Condition cond = AL) = 0;
+ virtual void Lsl(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Lsr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Asr(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Ror(Register rd, Register rm, uint32_t shift_imm, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Rrx(Register rd, Register rm, bool setcc = false,
+ Condition cond = AL) = 0;
+
+ virtual void Lsl(Register rd, Register rm, Register rn, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Lsr(Register rd, Register rm, Register rn, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Asr(Register rd, Register rm, Register rn, bool setcc = false,
+ Condition cond = AL) = 0;
+ virtual void Ror(Register rd, Register rm, Register rn, bool setcc = false,
+ Condition cond = AL) = 0;
static bool IsInstructionForExceptionHandling(uword pc);
@@ -673,6 +725,14 @@
static uint32_t ModifiedImmediate(uint32_t value);
+ static bool IsLowRegister(Register r) {
+ return r < R8;
+ }
+
+ static bool IsHighRegister(Register r) {
+ return r >= R8;
+ }
+
protected:
// Returns whether or not the given register is used for passing parameters.
static int RegisterCompare(const Register* reg1, const Register* reg2) {