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,
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:
// 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) |
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) |
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();
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();
--- /dev/null
+; 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
+}