OSDN Git Service

Fix vldrs/vstrs handling of immediate offsets in ARM.
authorKarl Schimpf <kschimpf@google.com>
Fri, 22 Jan 2016 20:39:51 +0000 (12:39 -0800)
committerKarl Schimpf <kschimpf@google.com>
Fri, 22 Jan 2016 20:39:51 +0000 (12:39 -0800)
A previous patch fixed vldrd/vstrd by dividing the immediate offset of
the instruction by 4 before encoding. This does the same for
vldrs/vstrs. It fixes the remaining problems with compiling spec2k
using -filetype=iasm.

It also fixes a minor bug in the divsion by 4, in the case that the
immediate value is negative.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=jpp@chromium.org

Review URL: https://codereview.chromium.org/1617993005 .

src/IceAssemblerARM32.cpp
tests_lit/assembler/arm32/vldr.vstr.imm.ll

index 6090e1d..a23bcba 100644 (file)
@@ -356,14 +356,14 @@ EncodedOperand encodeOperand(const Operand *Opnd, IValueT &Value,
 }
 
 IValueT encodeImmRegOffset(IValueT Reg, IOffsetT Offset,
-                           OperandARM32Mem::AddrMode Mode) {
+                           OperandARM32Mem::AddrMode Mode,
+                           IValueT OffsetShift = 0) {
   IValueT Value = Mode | (Reg << kRnShift);
   if (Offset < 0) {
-    Value = (Value ^ U) | -Offset; // Flip U to adjust sign.
-  } else {
-    Value |= Offset;
+    Offset = -Offset;
+    Value ^= U; // Flip U to adjust sign.
   }
-  return Value;
+  return Value | (Offset >> OffsetShift);
 }
 
 // Encodes immediate register offset using encoding 3.
@@ -384,9 +384,11 @@ IValueT encodeImmRegOffset(OpEncoding AddressEncoding, IValueT Reg,
   switch (AddressEncoding) {
   case DefaultOpEncoding:
     return encodeImmRegOffset(Reg, Offset, Mode);
-  case ImmRegOffsetDiv4:
+  case ImmRegOffsetDiv4: {
     assert((Offset & 0x3) == 0);
-    return encodeImmRegOffset(Reg, Offset >> 2, Mode);
+    constexpr IValueT RightShift2 = 2;
+    return encodeImmRegOffset(Reg, Offset, Mode, RightShift2);
+  }
   case OpEncoding3:
     return encodeImmRegOffsetEnc3(Reg, Offset, Mode);
   case OpEncodingMemEx:
@@ -608,7 +610,6 @@ IValueT AssemblerARM32::encodeBranchOffset(IOffsetT Offset, IValueT Inst) {
 
   bool IsGoodOffset = canEncodeBranchOffset(Offset);
   assert(IsGoodOffset);
-  // Note: Following cast is for MINIMAL build.
   (void)IsGoodOffset;
 
   // Properly preserve only the bits supported in the instruction.
@@ -2242,9 +2243,8 @@ void AssemblerARM32::vldrd(const Operand *OpDd, const Operand *OpAddress,
   IValueT Address;
   EncodedOperand AddressEncoding =
       encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
-  if (AddressEncoding != EncodedAsImmRegOffset)
-    // TODO(kschimpf) Fix this.
-    return setNeedsTextFixup();
+  (void)AddressEncoding;
+  assert(AddressEncoding == EncodedAsImmRegOffset);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 | B8 |
                      (encodeCondition(Cond) << kConditionShift) |
@@ -2264,7 +2264,8 @@ void AssemblerARM32::vldrs(const Operand *OpSd, const Operand *OpAddress,
   IValueT Sd = encodeSRegister(OpSd, "Sd", Vldrs);
   assert(CondARM32::isDefined(Cond));
   IValueT Address;
-  EncodedOperand AddressEncoding = encodeAddress(OpAddress, Address, TInfo);
+  EncodedOperand AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
   (void)AddressEncoding;
   assert(AddressEncoding == EncodedAsImmRegOffset);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
@@ -2318,9 +2319,8 @@ void AssemblerARM32::vstrd(const Operand *OpDd, const Operand *OpAddress,
   IValueT Address;
   IValueT AddressEncoding =
       encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
-  if (AddressEncoding != EncodedAsImmRegOffset)
-    // TODO(kschimpf) Fix this.
-    return setNeedsTextFixup();
+  (void)AddressEncoding;
+  assert(AddressEncoding == EncodedAsImmRegOffset);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = B27 | B26 | B24 | B11 | B9 | B8 |
                      (encodeCondition(Cond) << kConditionShift) |
@@ -2340,8 +2340,10 @@ void AssemblerARM32::vstrs(const Operand *OpSd, const Operand *OpAddress,
   IValueT Sd = encodeSRegister(OpSd, "Sd", Vstrs);
   assert(CondARM32::isDefined(Cond));
   IValueT Address;
-  if (encodeAddress(OpAddress, Address, TInfo) != EncodedAsImmRegOffset)
-    assert(false);
+  IValueT AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
+  (void)AddressEncoding;
+  assert(AddressEncoding == EncodedAsImmRegOffset);
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding =
       B27 | B26 | B24 | B11 | B9 | (encodeCondition(Cond) << kConditionShift) |
index 0fa12b0..053dae8 100644 (file)
@@ -1,4 +1,4 @@
-; Test vldrd and vstrd when address is offset with an immediate.
+; Test vldr{s,d} and vstr{s,d} when address is offset with an immediate.
 
 ; REQUIRES: allow_dump
 
 ; RUN:   -reg-use d20 \
 ; RUN:   | FileCheck %s --check-prefix=DIS
 
-define internal i64 @testVldrStrImm(double %d) {
-; ASM-LABEL: testVldrStrImm:
-; DIS-LABEL: 00000000 <testVldrStrImm>:
-; IASM-LABEL: testVldrStrImm:
+define internal i32 @testFloatImm(float %f) {
+; ASM-LABEL: testFloatImm:
+; DIS-LABEL: 00000000 <testFloatImm>:
+; IASM-LABEL: testFloatImm:
 
 entry:
-; ASM-NEXT: .LtestVldrStrImm$entry:
-; IASM-NEXT: .LtestVldrStrImm$entry:
+; ASM: .LtestFloatImm$entry:
+; IASM: .LtestFloatImm$entry:
+
+; ASM:  vstr    s0, [sp, #4]
+; DIS:    4:    ed8d0a01
+; IASM-NOT: vstr
+
+  %v = bitcast float %f to i32
+
+; ASM:  vldr    s0, [sp, #4]
+; DIS:    8:    ed9d0a01
+; IASM-NOT: vldr
+
+  ret i32 %v
+}
+
+define internal i64 @testDoubleImm(double %d) {
+; ASM-LABEL: testDoubleImm:
+; DIS-LABEL: 00000020 <testDoubleImm>:
+; IASM-LABEL: testDoubleImm:
+
+entry:
+; ASM: .LtestDoubleImm$entry:
+; IASM: .LtestDoubleImm$entry:
 
 ; ASM:  vstr    d0, [sp, #8]
-; DIS:    4:   ed8d0b02
+; DIS:   24:    ed8d0b02
 ; IASM-NOT: vstr
 
   %v = bitcast double %d to i64
 
 ; ASM:  vldr    d20, [sp, #8]
-; DIS:    8:   eddd4b02
+; DIS:   28:    eddd4b02
 ; IASM-NOT: vldr
 
   ret i64 %v