diff options
| author | 2016-08-04 16:46:17 +0000 | |
|---|---|---|
| committer | 2016-08-04 16:46:17 +0000 | |
| commit | 1a2e5e67bc6fd9df4154f0add1d1163af6aa9bf2 (patch) | |
| tree | ace009be8b3d29fa54dff3c833aa4c2f67e6ba2f /compiler/utils/arm | |
| parent | e250cb82e55e47009fdddbebaec9c3f09b36a41b (diff) | |
| parent | 3a656e183ab3131d4a0e1fa79acc79e8da762508 (diff) | |
Merge "Thumb2: Clean up 16-bit LDR/STR detection."
Diffstat (limited to 'compiler/utils/arm')
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2.cc | 31 | ||||
| -rw-r--r-- | compiler/utils/arm/assembler_thumb2_test.cc | 142 |
2 files changed, 159 insertions, 14 deletions
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 353c729249..4be7aae243 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -2325,7 +2325,7 @@ void Thumb2Assembler::EmitLoadStore(Condition cond, } Register rn = ad.GetRegister(); - if (IsHighRegister(rn) && rn != SP && rn != PC) { + if (IsHighRegister(rn) && (byte || half || (rn != SP && rn != PC))) { must_be_32bit = true; } @@ -2337,24 +2337,24 @@ void Thumb2Assembler::EmitLoadStore(Condition cond, // Immediate offset int32_t offset = ad.GetOffset(); - // The 16 bit SP relative instruction can only have a 10 bit offset. - if (rn == SP && offset >= (1 << 10)) { - must_be_32bit = true; - } - if (byte) { // 5 bit offset, no shift. - if (offset >= (1 << 5)) { + if ((offset & ~0x1f) != 0) { must_be_32bit = true; } } else if (half) { - // 6 bit offset, shifted by 1. - if (offset >= (1 << 6)) { + // 5 bit offset, shifted by 1. + if ((offset & ~(0x1f << 1)) != 0) { + must_be_32bit = true; + } + } else if (rn == SP || rn == PC) { + // The 16 bit SP/PC relative instruction can only have an (imm8 << 2) offset. + if ((offset & ~(0xff << 2)) != 0) { must_be_32bit = true; } } else { - // 7 bit offset, shifted by 2. - if (offset >= (1 << 7)) { + // 5 bit offset, shifted by 2. + if ((offset & ~(0x1f << 2)) != 0) { must_be_32bit = true; } } @@ -2370,7 +2370,7 @@ void Thumb2Assembler::EmitLoadStore(Condition cond, } else { // 16 bit thumb1. uint8_t opA = 0; - bool sp_relative = false; + bool sp_or_pc_relative = false; if (byte) { opA = 7U /* 0b0111 */; @@ -2379,7 +2379,10 @@ void Thumb2Assembler::EmitLoadStore(Condition cond, } else { if (rn == SP) { opA = 9U /* 0b1001 */; - sp_relative = true; + sp_or_pc_relative = true; + } else if (rn == PC) { + opA = 4U; + sp_or_pc_relative = true; } else { opA = 6U /* 0b0110 */; } @@ -2388,7 +2391,7 @@ void Thumb2Assembler::EmitLoadStore(Condition cond, (load ? B11 : 0); CHECK_GE(offset, 0); - if (sp_relative) { + if (sp_or_pc_relative) { // SP relative, 10 bit offset. CHECK_LT(offset, (1 << 10)); CHECK_ALIGNED(offset, 4); diff --git a/compiler/utils/arm/assembler_thumb2_test.cc b/compiler/utils/arm/assembler_thumb2_test.cc index abb09f726f..3ca37145d5 100644 --- a/compiler/utils/arm/assembler_thumb2_test.cc +++ b/compiler/utils/arm/assembler_thumb2_test.cc @@ -279,6 +279,148 @@ TEST_F(AssemblerThumb2Test, smull) { DriverStr(expected, "smull"); } +TEST_F(AssemblerThumb2Test, LoadByteFromThumbOffset) { + arm::LoadOperandType type = arm::kLoadUnsignedByte; + + __ LoadFromOffset(type, arm::R0, arm::R7, 0); + __ LoadFromOffset(type, arm::R1, arm::R7, 31); + __ LoadFromOffset(type, arm::R2, arm::R7, 32); + __ LoadFromOffset(type, arm::R3, arm::R7, 4095); + __ LoadFromOffset(type, arm::R4, arm::SP, 0); + + const char* expected = + "ldrb r0, [r7, #0]\n" + "ldrb r1, [r7, #31]\n" + "ldrb.w r2, [r7, #32]\n" + "ldrb.w r3, [r7, #4095]\n" + "ldrb.w r4, [sp, #0]\n"; + DriverStr(expected, "LoadByteFromThumbOffset"); +} + +TEST_F(AssemblerThumb2Test, StoreByteToThumbOffset) { + arm::StoreOperandType type = arm::kStoreByte; + + __ StoreToOffset(type, arm::R0, arm::R7, 0); + __ StoreToOffset(type, arm::R1, arm::R7, 31); + __ StoreToOffset(type, arm::R2, arm::R7, 32); + __ StoreToOffset(type, arm::R3, arm::R7, 4095); + __ StoreToOffset(type, arm::R4, arm::SP, 0); + + const char* expected = + "strb r0, [r7, #0]\n" + "strb r1, [r7, #31]\n" + "strb.w r2, [r7, #32]\n" + "strb.w r3, [r7, #4095]\n" + "strb.w r4, [sp, #0]\n"; + DriverStr(expected, "StoreByteToThumbOffset"); +} + +TEST_F(AssemblerThumb2Test, LoadHalfFromThumbOffset) { + arm::LoadOperandType type = arm::kLoadUnsignedHalfword; + + __ LoadFromOffset(type, arm::R0, arm::R7, 0); + __ LoadFromOffset(type, arm::R1, arm::R7, 62); + __ LoadFromOffset(type, arm::R2, arm::R7, 64); + __ LoadFromOffset(type, arm::R3, arm::R7, 4094); + __ LoadFromOffset(type, arm::R4, arm::SP, 0); + __ LoadFromOffset(type, arm::R5, arm::R7, 1); // Unaligned + + const char* expected = + "ldrh r0, [r7, #0]\n" + "ldrh r1, [r7, #62]\n" + "ldrh.w r2, [r7, #64]\n" + "ldrh.w r3, [r7, #4094]\n" + "ldrh.w r4, [sp, #0]\n" + "ldrh.w r5, [r7, #1]\n"; + DriverStr(expected, "LoadHalfFromThumbOffset"); +} + +TEST_F(AssemblerThumb2Test, StoreHalfToThumbOffset) { + arm::StoreOperandType type = arm::kStoreHalfword; + + __ StoreToOffset(type, arm::R0, arm::R7, 0); + __ StoreToOffset(type, arm::R1, arm::R7, 62); + __ StoreToOffset(type, arm::R2, arm::R7, 64); + __ StoreToOffset(type, arm::R3, arm::R7, 4094); + __ StoreToOffset(type, arm::R4, arm::SP, 0); + __ StoreToOffset(type, arm::R5, arm::R7, 1); // Unaligned + + const char* expected = + "strh r0, [r7, #0]\n" + "strh r1, [r7, #62]\n" + "strh.w r2, [r7, #64]\n" + "strh.w r3, [r7, #4094]\n" + "strh.w r4, [sp, #0]\n" + "strh.w r5, [r7, #1]\n"; + DriverStr(expected, "StoreHalfToThumbOffset"); +} + +TEST_F(AssemblerThumb2Test, LoadWordFromSpPlusOffset) { + arm::LoadOperandType type = arm::kLoadWord; + + __ LoadFromOffset(type, arm::R0, arm::SP, 0); + __ LoadFromOffset(type, arm::R1, arm::SP, 124); + __ LoadFromOffset(type, arm::R2, arm::SP, 128); + __ LoadFromOffset(type, arm::R3, arm::SP, 1020); + __ LoadFromOffset(type, arm::R4, arm::SP, 1024); + __ LoadFromOffset(type, arm::R5, arm::SP, 4092); + __ LoadFromOffset(type, arm::R6, arm::SP, 1); // Unaligned + + const char* expected = + "ldr r0, [sp, #0]\n" + "ldr r1, [sp, #124]\n" + "ldr r2, [sp, #128]\n" + "ldr r3, [sp, #1020]\n" + "ldr.w r4, [sp, #1024]\n" + "ldr.w r5, [sp, #4092]\n" + "ldr.w r6, [sp, #1]\n"; + DriverStr(expected, "LoadWordFromSpPlusOffset"); +} + +TEST_F(AssemblerThumb2Test, StoreWordToSpPlusOffset) { + arm::StoreOperandType type = arm::kStoreWord; + + __ StoreToOffset(type, arm::R0, arm::SP, 0); + __ StoreToOffset(type, arm::R1, arm::SP, 124); + __ StoreToOffset(type, arm::R2, arm::SP, 128); + __ StoreToOffset(type, arm::R3, arm::SP, 1020); + __ StoreToOffset(type, arm::R4, arm::SP, 1024); + __ StoreToOffset(type, arm::R5, arm::SP, 4092); + __ StoreToOffset(type, arm::R6, arm::SP, 1); // Unaligned + + const char* expected = + "str r0, [sp, #0]\n" + "str r1, [sp, #124]\n" + "str r2, [sp, #128]\n" + "str r3, [sp, #1020]\n" + "str.w r4, [sp, #1024]\n" + "str.w r5, [sp, #4092]\n" + "str.w r6, [sp, #1]\n"; + DriverStr(expected, "StoreWordToSpPlusOffset"); +} + +TEST_F(AssemblerThumb2Test, LoadWordFromPcPlusOffset) { + arm::LoadOperandType type = arm::kLoadWord; + + __ LoadFromOffset(type, arm::R0, arm::PC, 0); + __ LoadFromOffset(type, arm::R1, arm::PC, 124); + __ LoadFromOffset(type, arm::R2, arm::PC, 128); + __ LoadFromOffset(type, arm::R3, arm::PC, 1020); + __ LoadFromOffset(type, arm::R4, arm::PC, 1024); + __ LoadFromOffset(type, arm::R5, arm::PC, 4092); + __ LoadFromOffset(type, arm::R6, arm::PC, 1); // Unaligned + + const char* expected = + "ldr r0, [pc, #0]\n" + "ldr r1, [pc, #124]\n" + "ldr r2, [pc, #128]\n" + "ldr r3, [pc, #1020]\n" + "ldr.w r4, [pc, #1024]\n" + "ldr.w r5, [pc, #4092]\n" + "ldr.w r6, [pc, #1]\n"; + DriverStr(expected, "LoadWordFromPcPlusOffset"); +} + TEST_F(AssemblerThumb2Test, StoreWordToThumbOffset) { arm::StoreOperandType type = arm::kStoreWord; int32_t offset = 4092; |