Add "sub immediate" instruction to the ARM integrated assembler.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1388323003 .
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 2195d4d..9972b44 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -28,6 +28,7 @@
// The following define individual bits.
static constexpr uint32_t B0 = 1;
+static constexpr uint32_t B1 = 1 << 1;
static constexpr uint32_t B2 = 1 << 2;
static constexpr uint32_t B3 = 1 << 3;
static constexpr uint32_t B4 = 1 << 4;
@@ -220,4 +221,34 @@
UnimplementedError(Ctx->getFlags());
}
+void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
+ const Operand *OpSrc1, bool SetFlags,
+ CondARM32::Cond Cond) {
+ // Note: Loop is used so that we can short circuit using break;
+ do {
+ uint32_t Rd;
+ if (decode(OpRd, Rd) != DecodedAsRegister)
+ break;
+ uint32_t Rn;
+ if (decode(OpRn, Rn) != DecodedAsRegister)
+ break;
+ uint32_t Src1Value;
+ // TODO(kschimpf) Other possible decodings of add.
+ if (decode(OpSrc1, Src1Value) == DecodedAsRotatedImm8) {
+ // Sub (Immediate): See ARM section A8.8.222, rule A1.
+ // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
+ // s=SetFlags and iiiiiiiiiiii=Src1Value
+ if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags) ||
+ (Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags))
+ // Conditions of rule violated.
+ break;
+ uint32_t Add = B1; // 0010
+ uint32_t InstType = 1;
+ emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value);
+ return;
+ }
+ } while (0);
+ UnimplementedError(Ctx->getFlags());
+}
+
} // end of namespace Ice
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 839b30e..d4e2c0a 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -107,6 +107,9 @@
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
+ void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
+ bool SetFlags, CondARM32::Cond Cond);
+
static bool classof(const Assembler *Asm) {
return Asm->getKind() == Asm_ARM32;
}
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index b637472..c4d9ebc 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -330,6 +330,12 @@
Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
}
+template <>
+void InstARM32ThreeAddrGPR<InstARM32::Sub>::emitIAS(const Cfg *Func) const {
+ ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
+}
+
InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
: InstARM32(Func, InstARM32::Call, 1, Dest) {
HasSideEffects = true;
diff --git a/tests_lit/assembler/arm32/add.ll b/tests_lit/assembler/arm32/add.ll
index 656137c..c6b7d28 100644
--- a/tests_lit/assembler/arm32/add.ll
+++ b/tests_lit/assembler/arm32/add.ll
@@ -14,11 +14,11 @@
}
; ASM-LABEL: add1ToR0:
-; ASM: add r0, r0, #1
-; ASM: bx lr
+; ASM: add r0, r0, #1
+; ASM: bx lr
; IASM-LABEL: add1ToR0:
-; IASM: .byte 0x1
+; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2
diff --git a/tests_lit/assembler/arm32/sub.ll b/tests_lit/assembler/arm32/sub.ll
new file mode 100644
index 0000000..e319333
--- /dev/null
+++ b/tests_lit/assembler/arm32/sub.ll
@@ -0,0 +1,25 @@
+; Show that we know how to translate instruction sub.
+; TODO(kschimpf) Currently only know how to test subtract 1 from R0.
+
+; NOTE: We use -O2 to get rid of memory stores.
+
+; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
+; RUN: | FileCheck %s --check-prefix=ASM
+; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
+; RUN: | FileCheck %s --check-prefix=IASM
+
+define internal i32 @sub1FromR0(i32 %p) {
+ %v = sub i32 %p, 1
+ ret i32 %v
+}
+
+; ASM-LABEL: sub1FromR0:
+; ASM: sub r0, r0, #1
+; ASM: bx lr
+
+; IASM-LABEL: sub1FromR0:
+; IASM: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x40
+; IASM-NEXT: .byte 0xe2
+