Commit f4d0a7a5 by Karl Schimpf

Add LSL (register, immediate) to ARM integrated assembler.

Also does some clean up on emitType01 methods (making optional argument explicit, and moving rule checks to the lowest level). BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org Review URL: https://codereview.chromium.org/1456783003 .
parent 3f6b47d5
...@@ -2596,7 +2596,8 @@ void Assembler::MoveRegister(Register rd, Register rm, Condition cond) { ...@@ -2596,7 +2596,8 @@ void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
} }
} }
#if 0
// Moved to ARM32::AssemblerARM32::lsl()
void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm, void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
Condition cond) { Condition cond) {
ASSERT(shift_imm.type() == 1); ASSERT(shift_imm.type() == 1);
...@@ -2604,10 +2605,11 @@ void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm, ...@@ -2604,10 +2605,11 @@ void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond); mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond);
} }
// Moved to ARM32::AssemblerARM32::lsl()
void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) { void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
mov(rd, Operand(rm, LSL, rs), cond); mov(rd, Operand(rm, LSL, rs), cond);
} }
#endif
void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm, void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
......
...@@ -158,7 +158,7 @@ class Operand : public ValueObject { ...@@ -158,7 +158,7 @@ class Operand : public ValueObject {
encoding_ = static_cast<uint32_t>(rm); encoding_ = static_cast<uint32_t>(rm);
} }
// Moved to encodeShiftRotateImm5() // Moved to encodeShiftRotateImm5() in IceAssemblerARM32.cpp
// Data-processing operands - Logical shift/rotate by immediate. // Data-processing operands - Logical shift/rotate by immediate.
Operand(Register rm, Shift shift, uint32_t shift_imm) { Operand(Register rm, Shift shift, uint32_t shift_imm) {
ASSERT(shift_imm < (1 << kShiftImmBits)); ASSERT(shift_imm < (1 << kShiftImmBits));
...@@ -167,8 +167,8 @@ class Operand : public ValueObject { ...@@ -167,8 +167,8 @@ class Operand : public ValueObject {
static_cast<uint32_t>(shift) << kShiftShift | static_cast<uint32_t>(shift) << kShiftShift |
static_cast<uint32_t>(rm); static_cast<uint32_t>(rm);
} }
#endif
// Moved to encodeShiftRotateReg() in IceAssemblerARM32.cpp
// Data-processing operands - Logical shift/rotate by register. // Data-processing operands - Logical shift/rotate by register.
Operand(Register rm, Shift shift, Register rs) { Operand(Register rm, Shift shift, Register rs) {
type_ = 0; type_ = 0;
...@@ -177,7 +177,6 @@ class Operand : public ValueObject { ...@@ -177,7 +177,6 @@ class Operand : public ValueObject {
static_cast<uint32_t>(rm); static_cast<uint32_t>(rm);
} }
#if 0
// Already defined as ARM32::OperandARM32FlexImm::canHoldImm(). // Already defined as ARM32::OperandARM32FlexImm::canHoldImm().
static bool CanHold(uint32_t immediate, Operand* o) { static bool CanHold(uint32_t immediate, Operand* o) {
// Avoid the more expensive test for frequent small immediate values. // Avoid the more expensive test for frequent small immediate values.
...@@ -956,9 +955,13 @@ class Assembler : public ValueObject { ...@@ -956,9 +955,13 @@ class Assembler : public ValueObject {
// Convenience shift instructions. Use mov instruction with shifter operand // Convenience shift instructions. Use mov instruction with shifter operand
// for variants setting the status flags. // for variants setting the status flags.
#if 0
// Moved to ARM32::AssemblerARM32::lsl()
void Lsl(Register rd, Register rm, const Operand& shift_imm, void Lsl(Register rd, Register rm, const Operand& shift_imm,
Condition cond = AL); Condition cond = AL);
// Moved to ARM32::AssemblerARM32::lsl()
void Lsl(Register rd, Register rm, Register rs, Condition cond = AL); void Lsl(Register rd, Register rm, Register rs, Condition cond = AL);
#endif
void Lsr(Register rd, Register rm, const Operand& shift_imm, void Lsr(Register rd, Register rm, const Operand& shift_imm,
Condition cond = AL); Condition cond = AL);
void Lsr(Register rd, Register rm, Register rs, Condition cond = AL); void Lsr(Register rd, Register rm, Register rs, Condition cond = AL);
......
...@@ -223,6 +223,9 @@ public: ...@@ -223,6 +223,9 @@ public:
ldr(OpRt, OpAddress, Cond, TInfo); ldr(OpRt, OpAddress, Cond, TInfo);
} }
void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
...@@ -312,28 +315,27 @@ private: ...@@ -312,28 +315,27 @@ private:
void emitInst(IValueT Value) { Buffer.emit<IValueT>(Value); } void emitInst(IValueT Value) { Buffer.emit<IValueT>(Value); }
// List of possible checks to apply when calling emitType01() (below).
enum EmitChecks { NoChecks, RdIsPcAndSetFlags };
// Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type, // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type,
// oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM section A5.2.3). // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM
// section A5.2.3).
void emitType01(CondARM32::Cond Cond, IValueT Type, IValueT Opcode, void emitType01(CondARM32::Cond Cond, IValueT Type, IValueT Opcode,
bool SetCc, IValueT Rn, IValueT Rd, IValueT imm12); bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12,
EmitChecks RuleChecks);
// List of possible checks to apply when calling emitType01() (below).
enum Type01Checks {
NoChecks,
RdIsPcAndSetFlags,
};
// Converts appropriate representation on a data operation, and then calls // Converts appropriate representation on a data operation, and then calls
// emitType01 above. // emitType01 above.
void emitType01(IValueT Opcode, const Operand *OpRd, const Operand *OpRn, void emitType01(IValueT Opcode, const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond,
Type01Checks RuleChecks = RdIsPcAndSetFlags); EmitChecks RuleChecks);
// Same as above, but the value for Rd and Rn have already been converted // Same as above, but the value for Rd and Rn have already been converted
// into instruction values. // into instruction values.
void emitType01(IValueT Opcode, IValueT OpRd, IValueT OpRn, void emitType01(IValueT Opcode, IValueT OpRd, IValueT OpRn,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond,
Type01Checks RuleChecks = RdIsPcAndSetFlags); EmitChecks RuleChecks);
void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link); void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link);
...@@ -356,9 +358,9 @@ private: ...@@ -356,9 +358,9 @@ private:
IValueT Rm); IValueT Rm);
// Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, ssss=Rs, f=SetCc, and xxxxxxx=Opcode. // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode.
void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, IValueT Rs, bool SetCc); IValueT Rm, IValueT Rs, bool SetFlags);
// Implements various forms of Unsigned extend value, using pattern // Implements various forms of Unsigned extend value, using pattern
// ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
......
...@@ -485,6 +485,13 @@ template <> void InstARM32Eor::emitIAS(const Cfg *Func) const { ...@@ -485,6 +485,13 @@ template <> void InstARM32Eor::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Lsl::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->lsl(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <> void InstARM32Orr::emitIAS(const Cfg *Func) const { template <> void InstARM32Orr::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
......
; Show that we know how to translate lsl.
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
define internal i32 @_Z8testUdivhh(i32 %a, i32 %b) {
; ASM-LABEL:_Z8testUdivhh:
; DIS-LABEL:00000000 <_Z8testUdivhh>:
; IASM-LABEL:_Z8testUdivhh:
entry:
; ASM-NEXT:.L_Z8testUdivhh$entry:
; ASM-NEXT: push {lr}
; DIS-NEXT: 0: e52de004
; IASM-NEXT:.L_Z8testUdivhh$entry:
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
%b.arg_trunc = trunc i32 %b to i8
%a.arg_trunc = trunc i32 %a to i8
%div3 = udiv i8 %a.arg_trunc, %b.arg_trunc
; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 4: e24dd00c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: lsls r2, r1, #24
; DIS-NEXT: 8: e1b02c01
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x2c
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0xe1
%div3.ret_ext = zext i8 %div3 to i32
ret i32 %div3.ret_ext
}
define internal i32 @_Z7testShljj(i32 %a, i32 %b) {
; ASM-LABEL:_Z7testShljj:
; DIS-LABEL:00000030 <_Z7testShljj>:
; IASM-LABEL:_Z7testShljj:
entry:
; ASM-NEXT:.L_Z7testShljj$entry:
; IASM-NEXT:.L_Z7testShljj$entry:
%shl = shl i32 %a, %b
; ASM-NEXT: lsl r0, r0, r1
; DIS-NEXT: 30: e1a00110
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
ret i32 %shl
}
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