Commit cdb3ed68 by Karl Schimpf

Add LDR/LDRB (register) to ARM integrated assembler.

parent 23bee884
...@@ -102,6 +102,7 @@ static constexpr IValueT kDivRnShift = 0; ...@@ -102,6 +102,7 @@ static constexpr IValueT kDivRnShift = 0;
static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000 static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000
static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001 static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001
static constexpr IValueT kInstTypeMemImmediate = 2; // i.e. 010 static constexpr IValueT kInstTypeMemImmediate = 2; // i.e. 010
static constexpr IValueT kInstTypeRegisterShift = 3; // i.e. 011
// Offset modifier to current PC for next instruction. The offset is off by 8 // Offset modifier to current PC for next instruction. The offset is off by 8
// due to the way the ARM CPUs read PC. // due to the way the ARM CPUs read PC.
...@@ -187,8 +188,13 @@ enum DecodedResult { ...@@ -187,8 +188,13 @@ enum DecodedResult {
DecodedAsRotatedImm8, DecodedAsRotatedImm8,
// i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn, // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
// p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to // p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
// Rn should be used, and iiiiiiiiiiii is the offset. // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
DecodedAsImmRegOffset, DecodedAsImmRegOffset,
// i.e. 0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
// mmmm is the index register Rm, iiiii is the shift amount, ss is the shift
// kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
// writeback to Rn.
DecodedAsShiftRotateImm5,
// Value is 32bit integer constant. // Value is 32bit integer constant.
DecodedAsConstI32 DecodedAsConstI32
}; };
...@@ -263,15 +269,23 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value, ...@@ -263,15 +269,23 @@ DecodedResult decodeAddress(const Operand *Opnd, IValueT &Value,
return DecodedAsImmRegOffset; return DecodedAsImmRegOffset;
} }
if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) { if (const auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Opnd)) {
if (Mem->isRegReg())
// TODO(kschimpf) Add this case.
return CantDecode;
Variable *Var = Mem->getBase(); Variable *Var = Mem->getBase();
if (!Var->hasReg()) if (!Var->hasReg())
return CantDecode; return CantDecode;
IValueT Rn = Var->getRegNum();
if (Mem->isRegReg()) {
const Variable *Index = Mem->getIndex();
if (Var == nullptr)
return CantDecode;
Value = (Rn << kRnShift) | Mem->getAddrMode() |
encodeShiftRotateImm5(Index->getRegNum(), Mem->getShiftOp(),
Mem->getShiftAmt());
return DecodedAsShiftRotateImm5;
}
// Decoded as immediate register offset.
ConstantInteger32 *Offset = Mem->getOffset(); ConstantInteger32 *Offset = Mem->getOffset();
Value = decodeImmRegOffset(decodeGPRRegister(Var->getRegNum()), Value = decodeImmRegOffset(decodeGPRRegister(Rn), Offset->getValue(),
Offset->getValue(), Mem->getAddrMode()); Mem->getAddrMode());
return DecodedAsImmRegOffset; return DecodedAsImmRegOffset;
} }
return CantDecode; return CantDecode;
...@@ -723,39 +737,82 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn, ...@@ -723,39 +737,82 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond, const TargetInfo &TInfo) { CondARM32::Cond Cond, const TargetInfo &TInfo) {
constexpr bool IsLoad = true;
IValueT Rt; IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup(); return setNeedsTextFixup();
IValueT Address;
if (decodeAddress(OpAddress, Address, TInfo) != DecodedAsImmRegOffset)
return setNeedsTextFixup();
// LDR (immediate) - ARM section A8.8.63, encoding A1:
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// LDRB (immediate) - ARM section A8.8.68, encoding A1:
// ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=1 if STRB, u=1 if +.
constexpr bool IsLoad = true;
const Type Ty = OpRt->getType(); const Type Ty = OpRt->getType();
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand? if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand?
return setNeedsTextFixup(); return setNeedsTextFixup();
const bool IsByte = isByteSizedType(Ty); const bool IsByte = isByteSizedType(Ty);
// Check conditions of rules violated. IValueT Address;
if (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) switch (decodeAddress(OpAddress, Address, TInfo)) {
return setNeedsTextFixup(); default:
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if (!IsByte && (getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
!isBitSet(P, Address) && isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
return setNeedsTextFixup(); return setNeedsTextFixup();
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address); case DecodedAsImmRegOffset: {
// LDR (immediate) - ARM section A8.8.63, encoding A1:
// ldr<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldr<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldr<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// LDRB (immediate) - ARM section A8.8.68, encoding A1:
// ldrb<c> <Rt>, [<Rn>{, #+/-<imm12>}] ; p=1, w=0
// ldrb<c> <Rt>, [<Rn>], #+/-<imm12> ; p=1, w=1
// ldrb<c> <Rt>, [<Rn>, #+/-<imm12>]! ; p=0, w=1
//
// cccc010pubw1nnnnttttiiiiiiiiiiii where cccc=Cond, tttt=Rt, nnnn=Rn,
// iiiiiiiiiiii=imm12, b=1 if LDRB, u=1 if +, pu0w is a BlockAddr, and
// pu0w0nnnn0000iiiiiiiiiiii=Address.
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
// Check if conditions of rules violated.
if (Rn == RegARM32::Encoded_Reg_pc)
return setNeedsTextFixup();
if (!isBitSet(P, Address) && isBitSet(W, Address))
return setNeedsTextFixup();
if (!IsByte && (Rn == RegARM32::Encoded_Reg_sp) && !isBitSet(P, Address) &&
isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */))
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
}
case DecodedAsShiftRotateImm5: {
// LDR (register) - ARM section A8.8.66, encoding A1:
// ldr<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
// ldr<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
//
// LDRB (register) - ARM section A8.8.70, encoding A1:
// ldrb<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
// ldrb<c> <Rt>, [<Rn>], +-<Rm>{, <shift>}
//
// cccc011pubw1nnnnttttiiiiiss0mmmm where cccc=Cond, tttt=Rt,
// b=1 if LDRB, U=1 if +, pu0b is a BlockAddr, and
// pu0w0nnnn0000iiiiiss0mmmm=Address.
RegARM32::GPRRegister Rn = getGPRReg(kRnShift, Address);
RegARM32::GPRRegister Rm = getGPRReg(kRmShift, Address);
// Check if conditions of rules violated.
if (isBitSet(P, Address) && isBitSet(W, Address))
// Instruction LDRBT!
return setNeedsTextFixup();
if (IsByte &&
((Rt == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc)))
// Unpredictable.
return setNeedsTextFixup();
if (!IsByte && Rm == RegARM32::Encoded_Reg_pc)
// Unpredictable.
return setNeedsTextFixup();
if (isBitSet(W, Address) &&
((Rn == RegARM32::Encoded_Reg_pc) || encodeGPRRegister(Rn) == Rt))
// Unpredictable
return setNeedsTextFixup();
return emitMemOp(Cond, kInstTypeRegisterShift, IsLoad, IsByte, Rt, Address);
}
}
} }
void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
......
...@@ -76,7 +76,7 @@ public: ...@@ -76,7 +76,7 @@ public:
/// The enum value also carries the encoding. /// The enum value also carries the encoding.
// TODO(jvoung): unify with the assembler. // TODO(jvoung): unify with the assembler.
enum AddrMode { enum AddrMode {
// bit encoding P U W // bit encoding P U 0 W
Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base) Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base)
PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback
PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback
......
; Show that we know how to translate LDR (register).
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %lc2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %lc2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %lc2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
@ArrayInitPartial = internal global [40 x i8] c"<\00\00\00F\00\00\00P\00\00\00Z\00\00\00d\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", align 4
@NumArraysElements = internal global [4 x i8] c"\01\00\00\00", align 4
@Arrays = internal constant <{ i32, [4 x i8] }> <{ i32 ptrtoint ([40 x i8]* @ArrayInitPartial to i32), [4 x i8] c"\14\00\00\00" }>, align 4
define internal void @_Z8getArrayjRj(i32 %WhichArray, i32 %Len) {
; ASM-LABEL:_Z8getArrayjRj:
; DIS-LABEL:00000000 <_Z8getArrayjRj>:
; IASM-LABEL:_Z8getArrayjRj:
entry:
; ASM-NEXT:.L_Z8getArrayjRj$entry:
; IASM-NEXT:.L_Z8getArrayjRj$entry:
%gep_array = mul i32 %WhichArray, 8
%expanded1 = ptrtoint <{ i32, [4 x i8] }>* @Arrays to i32
%gep = add i32 %expanded1, %gep_array
; ASM-NEXT: movw r2, #:lower16:Arrays
; ASM-NEXT: movt r2, #:upper16:Arrays
; DIS-NEXT: 0: e3002000
; DIS-NEXT: 4: e3402000
; IASM-NEXT: movw r2, #:lower16:Arrays @ .word e3002000
; IASM-NEXT: movt r2, #:upper16:Arrays @ .word e3402000
%gep3 = add i32 %gep, 4
; ASM-NEXT: add r2, r2, #4
; DIS-NEXT: 8: e2822004
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x82
; IASM-NEXT: .byte 0xe2
; ***** Here is the use of a LDR (register) instruction.
%gep3.asptr = inttoptr i32 %gep3 to i32*
%v1 = load i32, i32* %gep3.asptr, align 1
; ASM-NEXT: ldr r2, [r2, r0, lsl #3]
; DIS-NEXT: c: e7922180
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0x21
; IASM-NEXT: .byte 0x92
; IASM-NEXT: .byte 0xe7
%Len.asptr3 = inttoptr i32 %Len to i32*
store i32 %v1, i32* %Len.asptr3, align 1
; ASM-NEXT: str r2, [r1]
; DIS-NEXT: 10: e5812000
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x81
; IASM-NEXT: .byte 0xe5
ret void
; ASM-NEXT: bx lr
; DIS-NEXT: 14: e12fff1e
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment