OSDN Git Service

Fix vldrd/vstrd handling of immediate offsets in ARM.
authorKarl Schimpf <kschimpf@google.com>
Fri, 22 Jan 2016 16:22:43 +0000 (08:22 -0800)
committerKarl Schimpf <kschimpf@google.com>
Fri, 22 Jan 2016 16:22:43 +0000 (08:22 -0800)
Fixes the ARM integrated assembler by dividing the immediate offset
of the instruction by 4 before encoding.

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

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

src/IceAssemblerARM32.cpp
src/IceInstARM32.cpp
tests_lit/assembler/arm32/vldr.vstr.imm.ll [new file with mode: 0644]

index 66713a9..8d456ef 100644 (file)
@@ -180,6 +180,9 @@ RegARM32::GPRRegister getGPRReg(IValueT Shift, IValueT Value) {
 enum OpEncoding {
   // No alternate layout specified.
   DefaultOpEncoding,
+  // Alternate encoding for ImmRegOffset, where the offset is divided by 4
+  // before encoding.
+  ImmRegOffsetDiv4,
   // Alternate encoding 3 for memory operands (like in strb, strh, ldrb, and
   // ldrh.
   OpEncoding3,
@@ -381,6 +384,9 @@ IValueT encodeImmRegOffset(OpEncoding AddressEncoding, IValueT Reg,
   switch (AddressEncoding) {
   case DefaultOpEncoding:
     return encodeImmRegOffset(Reg, Offset, Mode);
+  case ImmRegOffsetDiv4:
+    assert((Offset & 0x3) == 0);
+    return encodeImmRegOffset(Reg, Offset >> 2, Mode);
   case OpEncoding3:
     return encodeImmRegOffsetEnc3(Reg, Offset, Mode);
   case OpEncodingMemEx:
@@ -2214,14 +2220,16 @@ void AssemblerARM32::vldrd(const Operand *OpDd, const Operand *OpAddress,
   //   vldr<c> <Dd>, [<Rn>{, #+/-<imm>}]
   //
   // cccc1101UD01nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
-  // iiiiiiii=abs(Opcode), and U=1 if Opcode>=0,
+  // iiiiiiii=abs(Imm >> 2), and U=1 if Opcode>=0.
   constexpr const char *Vldrd = "vldrd";
   IValueT Dd = encodeDRegister(OpDd, "Dd", Vldrd);
   assert(CondARM32::isDefined(Cond));
   IValueT Address;
-  EncodedOperand AddressEncoding = encodeAddress(OpAddress, Address, TInfo);
-  (void)AddressEncoding;
-  assert(AddressEncoding == EncodedAsImmRegOffset);
+  EncodedOperand AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
+  if (AddressEncoding != EncodedAsImmRegOffset)
+    // TODO(kschimpf) Fix this.
+    return setNeedsTextFixup();
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = B27 | B26 | B24 | B20 | B11 | B9 | B8 |
                      (encodeCondition(Cond) << kConditionShift) |
@@ -2285,16 +2293,19 @@ void AssemblerARM32::vmuld(const Operand *OpDd, const Operand *OpDn,
 void AssemblerARM32::vstrd(const Operand *OpDd, const Operand *OpAddress,
                            CondARM32::Cond Cond, const TargetInfo &TInfo) {
   // VSTR - ARM section A8.8.413, encoding A1:
-  //   vstr<c> <Dd>, [<Rn>{, #+/-<imm>}]
+  //   vstr<c> <Dd>, [<Rn>{, #+/-<Imm>}]
   //
   // cccc1101UD00nnnndddd1011iiiiiiii where cccc=Cond, nnnn=Rn, Ddddd=Rd,
-  // iiiiiiii=abs(Opcode), and U=1 if Opcode>=0,
+  // iiiiiiii=abs(Imm >> 2), and U=1 if Imm>=0.
   constexpr const char *Vstrd = "vstrd";
   IValueT Dd = encodeDRegister(OpDd, "Dd", Vstrd);
   assert(CondARM32::isDefined(Cond));
   IValueT Address;
-  if (encodeAddress(OpAddress, Address, TInfo) != EncodedAsImmRegOffset)
-    assert(false);
+  IValueT AddressEncoding =
+      encodeAddress(OpAddress, Address, TInfo, ImmRegOffsetDiv4);
+  if (AddressEncoding != EncodedAsImmRegOffset)
+    // TODO(kschimpf) Fix this.
+    return setNeedsTextFixup();
   AssemblerBuffer::EnsureCapacity ensured(&Buffer);
   IValueT Encoding = B27 | B26 | B24 | B11 | B9 | B8 |
                      (encodeCondition(Cond) << kConditionShift) |
index c7d4e10..5825e69 100644 (file)
@@ -1372,13 +1372,21 @@ template <> void InstARM32Ldr::emit(const Cfg *Func) const {
 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
   assert(getSrcSize() == 1);
   Variable *Dest = getDest();
-  Type DestTy = Dest->getType();
+  const Type DestTy = Dest->getType();
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   if (isScalarFloatingType(DestTy)) {
-    if (DestTy == IceType_f32)
+    switch (DestTy) {
+    default:
+      // TODO(kschimpf) Does this happen?
+      Asm->setNeedsTextFixup();
+      break;
+    case IceType_f32:
       Asm->vldrs(Dest, getSrc(0), getPredicate(), Func->getTarget());
-    else
+      break;
+    case IceType_f64:
       Asm->vldrd(Dest, getSrc(0), getPredicate(), Func->getTarget());
+      break;
+    }
   } else if (isVectorType(DestTy))
     // TODO(kschimpf) Handle case.
     Asm->setNeedsTextFixup();
@@ -1677,10 +1685,18 @@ void InstARM32Str::emitIAS(const Cfg *Func) const {
   Type Ty = getSrc(0)->getType();
   auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
   if (isScalarFloatingType(Ty)) {
-    if (Ty == IceType_f32)
+    switch (Ty) {
+    default:
+      // TODO(kschimpf) Does this happen?
+      Asm->setNeedsTextFixup();
+      break;
+    case IceType_f32:
       Asm->vstrs(getSrc(0), getSrc(1), getPredicate(), Func->getTarget());
-    else
+      break;
+    case IceType_f64:
       Asm->vstrd(getSrc(0), getSrc(1), getPredicate(), Func->getTarget());
+      break;
+    }
   } else if (isVectorType(Ty))
     // TODO(kschimpf) Handle case.
     Asm->setNeedsTextFixup();
diff --git a/tests_lit/assembler/arm32/vldr.vstr.imm.ll b/tests_lit/assembler/arm32/vldr.vstr.imm.ll
new file mode 100644 (file)
index 0000000..0fa12b0
--- /dev/null
@@ -0,0 +1,47 @@
+; Test vldrd and vstrd when address is offset with an immediate.
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; RUN:   -reg-use d20 \
+; RUN:   | FileCheck %s --check-prefix=ASM
+
+; Show bytes in assembled standalone code.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -Om1 \
+; RUN:   -reg-use d20 \
+; RUN:   | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; RUN:   -reg-use d20 \
+; RUN:   | FileCheck %s --check-prefix=IASM
+
+; Show bytes in assembled integrated code.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
+; RUN:   --args -Om1 \
+; 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:
+
+entry:
+; ASM-NEXT: .LtestVldrStrImm$entry:
+; IASM-NEXT: .LtestVldrStrImm$entry:
+
+; ASM:  vstr    d0, [sp, #8]
+; DIS:    4:   ed8d0b02
+; IASM-NOT: vstr
+
+  %v = bitcast double %d to i64
+
+; ASM:  vldr    d20, [sp, #8]
+; DIS:    8:   eddd4b02
+; IASM-NOT: vldr
+
+  ret i64 %v
+}