Add RSB instruction to the ARM integrated assembler.
Adds RSB (immediate) and RSB (register) to the ARM integrated assembler.
Also moves udiv method to corresponding (sorted) position in cpp file.
BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1494433005 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index d3f3d92..998c41b 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -202,17 +202,17 @@
void Assembler::sub(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), SUB, 0, rn, rd, o);
}
-#endif
+// Moved to ARM32::AssemberARM32::rsb()
void Assembler::rsb(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), RSB, 0, rn, rd, o);
}
+// Moved to ARM32::AssemberARM32::rsb()
void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), RSB, 1, rn, rd, o);
}
-#if 0
// Moved to ARM32::AssemberARM32::add()
void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ADD, 0, rn, rd, o);
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index ddf1c5f..a2426c0 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -459,12 +459,11 @@
// Moved to ARM32::AssemberARM32::sub()
void sub(Register rd, Register rn, Operand o, Condition cond = AL);
void subs(Register rd, Register rn, Operand o, Condition cond = AL);
-#endif
+ // Moved to ARM32::AssemberARM32::rsb()
void rsb(Register rd, Register rn, Operand o, Condition cond = AL);
void rsbs(Register rd, Register rn, Operand o, Condition cond = AL);
-#if 0
// Moved to ARM32::AssemblerARM32::add()
void add(Register rd, Register rn, Operand o, Condition cond = AL);
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 3908de3..6611aa0 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -1477,23 +1477,24 @@
MulName);
}
-void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn,
- const Operand *OpSrc1, CondARM32::Cond Cond) {
- // UDIV - ARM section A8.8.248, encoding A1.
- // udiv<c> <Rd>, <Rn>, <Rm>
+void AssemblerARM32::rsb(const Operand *OpRd, const Operand *OpRn,
+ const Operand *OpSrc1, bool SetFlags,
+ CondARM32::Cond Cond) {
+ // RSB (immediate) - ARM section A8.8.152, encoding A1.
+ // rsb{s}<c> <Rd>, <Rn>, #<RotatedImm8>
//
- // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
- // mmmm=Rm.
- constexpr const char *UdivName = "udiv";
- IValueT Rd = encodeRegister(OpRd, "Rd", UdivName);
- IValueT Rn = encodeRegister(OpRn, "Rn", UdivName);
- IValueT Rm = encodeRegister(OpSrc1, "Rm", UdivName);
- verifyRegNotPc(Rd, "Rd", UdivName);
- verifyRegNotPc(Rn, "Rn", UdivName);
- verifyRegNotPc(Rm, "Rm", UdivName);
- // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
- constexpr IValueT UdivOpcode = B21;
- emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm, UdivName);
+ // cccc0010011snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
+ // s=setFlags and iiiiiiiiiiii defines the RotatedImm8 value.
+ //
+ // RSB (register) - ARM section A8.8.163, encoding A1.
+ // rsb{s}<c> <Rd>, <Rn>, <Rm>{, <Shift>}
+ //
+ // cccc0000011snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
+ // mmmm=Rm, iiiii=shift, tt==ShiftKind, and s=SetFlags.
+ constexpr const char *RsbName = "rsb";
+ constexpr IValueT RsbOpcode = B1 | B0; // 0011
+ emitType01(Cond, RsbOpcode, OpRd, OpRn, OpSrc1, SetFlags, RdIsPcAndSetFlags,
+ RsbName);
}
void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
@@ -1505,7 +1506,7 @@
// sub{s}<c> <Rd>, sp, <Rm>{, <Shift>}
//
// cccc0000010snnnnddddiiiiitt0mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
- // mmmm=Rm, iiiiii=shift, tt=ShiftKind, and s=SetFlags.
+ // mmmm=Rm, iiiii=shift, tt=ShiftKind, and s=SetFlags.
//
// Sub (Immediate) - ARM section A8.8.222, encoding A1:
// sub{s}<c> <Rd>, <Rn>, #<RotatedImm8>
@@ -1538,6 +1539,25 @@
emitCompareOp(Cond, TstOpcode, OpRn, OpSrc1, TstName);
}
+void AssemblerARM32::udiv(const Operand *OpRd, const Operand *OpRn,
+ const Operand *OpSrc1, CondARM32::Cond Cond) {
+ // UDIV - ARM section A8.8.248, encoding A1.
+ // udiv<c> <Rd>, <Rn>, <Rm>
+ //
+ // cccc01110011dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
+ // mmmm=Rm.
+ constexpr const char *UdivName = "udiv";
+ IValueT Rd = encodeRegister(OpRd, "Rd", UdivName);
+ IValueT Rn = encodeRegister(OpRn, "Rn", UdivName);
+ IValueT Rm = encodeRegister(OpSrc1, "Rm", UdivName);
+ verifyRegNotPc(Rd, "Rd", UdivName);
+ verifyRegNotPc(Rn, "Rn", UdivName);
+ verifyRegNotPc(Rm, "Rm", UdivName);
+ // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
+ constexpr IValueT UdivOpcode = B21;
+ emitDivOp(Cond, UdivOpcode, Rd, Rn, Rm, UdivName);
+}
+
void AssemblerARM32::umull(const Operand *OpRdLo, const Operand *OpRdHi,
const Operand *OpRn, const Operand *OpRm,
CondARM32::Cond Cond) {
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index c45fc70..37ea441 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -249,6 +249,9 @@
// Note: Registers is a bitset, where bit n corresponds to register Rn.
void pushList(const IValueT Registers, CondARM32::Cond Cond);
+ void rsb(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
+ bool SetFlags, CondARM32::Cond Cond);
+
void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index c7adce8..6932d2f 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -506,6 +506,13 @@
emitUsingTextFixup(Func);
}
+template <> void InstARM32Rsb::emitIAS(const Cfg *Func) const {
+ auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Asm->rsb(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
+ if (Asm->needsTextFixup())
+ emitUsingTextFixup(Func);
+}
+
template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sbc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
diff --git a/tests_lit/assembler/arm32/rsb.ll b/tests_lit/assembler/arm32/rsb.ll
new file mode 100644
index 0000000..c5586ba
--- /dev/null
+++ b/tests_lit/assembler/arm32/rsb.ll
@@ -0,0 +1,123 @@
+; Show that we know how to translate rsb. Uses shl as example, because it
+; uses rsb for type i64
+
+; REQUIRES: allow_dump
+
+; Compile using standalone assembler.
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
+; 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 | FileCheck %s --check-prefix=DIS
+
+; Compile using integrated assembler.
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
+; 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 | FileCheck %s --check-prefix=DIS
+
+define internal i64 @shiftLeft(i64 %v, i64 %l) {
+; ASM-LABEL:shiftLeft:
+; DIS-LABEL:00000000 <shiftLeft>:
+; IASM-LABEL:shiftLeft:
+
+entry:
+; ASM-NEXT:.LshiftLeft$entry:
+; IASM-NEXT:.LshiftLeft$entry:
+
+; ASM-NEXT: sub sp, sp, #24
+; DIS-NEXT: 0: e24dd018
+; IASM-NEXT: .byte 0x18
+; IASM-NEXT: .byte 0xd0
+; IASM-NEXT: .byte 0x4d
+; IASM-NEXT: .byte 0xe2
+
+; ASM-NEXT: str r0, [sp, #20]
+; ASM-NEXT: # [sp, #20] = def.pseudo
+; DIS-NEXT: 4: e58d0014
+; IASM-NEXT: .byte 0x14
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: mov r0, r1
+; DIS-NEXT: 8: e1a00001
+; IASM-NEXT: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xa0
+; IASM-NEXT: .byte 0xe1
+
+; ASM-NEXT: str r0, [sp, #16]
+; ASM-NEXT: # [sp, #16] = def.pseudo
+; DIS-NEXT: c: e58d0010
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: mov r0, r2
+; DIS-NEXT: 10: e1a00002
+; IASM-NEXT: .byte 0x2
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xa0
+; IASM-NEXT: .byte 0xe1
+
+; ASM-NEXT: str r0, [sp, #12]
+; ASM-NEXT: # [sp, #12] = def.pseudo
+; DIS-NEXT: 14: e58d000c
+; IASM-NEXT: .byte 0xc
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: mov r0, r3
+; DIS-NEXT: 18: e1a00003
+; IASM-NEXT: .byte 0x3
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xa0
+; IASM-NEXT: .byte 0xe1
+
+; ASM-NEXT: str r0, [sp, #8]
+; ASM-NEXT: # [sp, #8] = def.pseudo
+; DIS-NEXT: 1c: e58d0008
+; IASM-NEXT: .byte 0x8
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+ %result = shl i64 %v, %l
+
+; ASM-NEXT: ldr r0, [sp, #20]
+; DIS-NEXT: 20: e59d0014
+; IASM-NEXT: .byte 0x14
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x9d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: ldr r1, [sp, #16]
+; DIS-NEXT: 24: e59d1010
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x9d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: ldr r2, [sp, #12]
+; DIS-NEXT: 28: e59d200c
+; IASM-NEXT: .byte 0xc
+; IASM-NEXT: .byte 0x20
+; IASM-NEXT: .byte 0x9d
+; IASM-NEXT: .byte 0xe5
+
+; ****** Here is the example of rsb *****
+; ASM-NEXT: rsb r3, r2, #32
+; DIS-NEXT: 2c: e2623020
+; IASM-NEXT: .byte 0x20
+; IASM-NEXT: .byte 0x30
+; IASM-NEXT: .byte 0x62
+; IASM-NEXT: .byte 0xe2
+
+ ret i64 %result
+}