Add MVN (register, immediate) to ARM integrated assembler.
Also removes redundant rule checks in emitType01().
BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=jpp@chromium.org
Review URL: https://codereview.chromium.org/1460523005 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index e99f70b..b2abcdf 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -92,7 +92,7 @@
Emit(encoding);
}
-// Moved to ARM32::AssemblerARM32::emitType05.
+// Moved to ARM32::AssemblerARM32::emitType05()
void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -304,26 +304,26 @@
#if 0
-// Moved to ARM32::AssemblerARM32::bic();
+// Moved to ARM32::AssemblerARM32::bic()
void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), BIC, 0, rn, rd, o);
}
-// Moved to ARM32::AssemblerARM32::bic();
+// Moved to ARM32::AssemblerARM32::bic()
void Assembler::bics(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
}
-#endif
+// Moved to ARM32::AssemblerARM32::mvn()
void Assembler::mvn(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
}
-
+// Moved to ARM32::AssemblerARM32::mvn()
void Assembler::mvns(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MVN, 1, R0, rd, o);
}
-
+#endif
void Assembler::clz(Register rd, Register rm, Condition cond) {
ASSERT(rd != kNoRegister);
@@ -340,7 +340,7 @@
#if
-// Moved to ARM32::AssemblerARM32::movw
+// Moved to ARM32::AssemblerARM32::movw()
void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -350,7 +350,7 @@
}
-// Moved to ARM32::AssemblerARM32::movt
+// Moved to ARM32::AssemblerARM32::movt()
void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
@@ -361,7 +361,7 @@
#endif
#if 0
-// Moved to ARM32::AssemblerARM32::emitMulOp
+// Moved to ARM32::AssemblerARM32::emitMulOp()
void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Register rd, Register rn,
Register rm, Register rs) {
@@ -380,7 +380,7 @@
Emit(encoding);
}
-// Moved to ARM32::AssemblerARM32::mul
+// Moved to ARM32::AssemblerARM32::mul()
void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
// Assembler registers rd, rn, rm are encoded as rn, rm, rs.
EmitMulOp(cond, 0, R0, rd, rn, rm);
@@ -2104,7 +2104,7 @@
}
#if 0
-// Moved to ::canEncodeBranchoffset in IceAssemblerARM32.cpp.
+// Moved to ::canEncodeBranchoffset() in IceAssemblerARM32.cpp.
static bool CanEncodeBranchOffset(int32_t offset) {
ASSERT(Utils::IsAligned(offset, 4));
// Note: This check doesn't take advantage of the fact that offset>>2
@@ -2112,7 +2112,7 @@
return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
}
-// Moved to ARM32::AssemblerARM32::encodeBranchOffset.
+// Moved to ARM32::AssemblerARM32::encodeBranchOffset()
int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
// The offset is off by 8 due to the way the ARM CPUs read PC.
offset -= Instr::kPCReadOffset;
@@ -2129,7 +2129,7 @@
return (inst & ~kBranchOffsetMask) | offset;
}
-// Moved to AssemberARM32::decodeBranchOffset.
+// Moved to AssemberARM32::decodeBranchOffset()
int Assembler::DecodeBranchOffset(int32_t inst) {
// Sign-extend, left-shift by 2, then add 8.
return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 688104b..de7d50e 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -507,10 +507,11 @@
// Moved to ARM32::IceAssemblerARM32::bic()
void bic(Register rd, Register rn, Operand o, Condition cond = AL);
void bics(Register rd, Register rn, Operand o, Condition cond = AL);
-#endif
+ // Moved to ARM32::IceAssemblerARM32::mvn()
void mvn(Register rd, Operand o, Condition cond = AL);
void mvns(Register rd, Operand o, Condition cond = AL);
+#endif
// Miscellaneous data-processing instructions.
void clz(Register rd, Register rm, Condition cond = AL);
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index 08ec155..cd4735b 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -187,16 +187,17 @@
// Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
// value.
DecodedAsRotatedImm8,
- // i.e. 0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
+ // Value=0000000pu0w0nnnn0000iiiiiiiiiiii where nnnn is the base register Rn,
// p=1 if pre-indexed addressing, u=1 if offset positive, w=1 if writeback to
// Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
DecodedAsImmRegOffset,
- // i.e. 0000000pu0w00nnnnttttiiiiiss0mmmm where nnnn is the base register Rn,
+ // Value=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,
- // i.e. 000000000000000000000iiiii0000000 iiii defines Imm5 value to shift.
+ // Value=000000000000000000000iiiii0000000 iiii defines the Imm5 value to
+ // shift.
DecodedAsShiftImm5,
// Value is 32bit integer constant.
DecodedAsConstI32
@@ -218,8 +219,8 @@
return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
}
-// Encodes mmmmtt01ssss for data-processing (2nd) operands where mmmm=Rm,
-// ssss=Rs, and tt=Shift.
+// Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and
+// tt=Shift.
IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
IValueT Rs) {
return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 |
@@ -481,15 +482,6 @@
void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond, EmitChecks RuleChecks) {
- switch (RuleChecks) {
- case NoChecks:
- break;
- case RdIsPcAndSetFlags:
- if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
- // Conditions of rule violated.
- return setNeedsTextFixup();
- break;
- }
IValueT Src1Value;
// TODO(kschimpf) Other possible decodings of data operations.
@@ -564,8 +556,9 @@
// XXX (register)
// XXX<c> <Rn>, <Rm>{, <shift>}
//
- // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm,
- // iiiii=Shift, tt=ShiftKind, yyy=kInstTypeDataRegister, and xxxx=Opcode.
+ // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm, iiiii
+ // defines shift constant, tt=ShiftKind, yyy=kInstTypeDataRegister, and
+ // xxxx=Opcode.
//
// XXX (immediate)
// XXX<c> <Rn>, #<RotatedImm8>
@@ -1047,6 +1040,28 @@
emitInst(Encoding);
}
+void AssemblerARM32::mvn(const Operand *OpRd, const Operand *OpSrc,
+ CondARM32::Cond Cond) {
+ // MVN (immediate) - ARM section A8.8.115, encoding A1:
+ // mvn{s}<c> <Rd>, #<const>
+ //
+ // cccc0011111s0000ddddiiiiiiiiiiii where cccc=Cond, s=SetFlags=0, dddd=Rd,
+ // and iiiiiiiiiiii=const
+ //
+ // MVN (register) - ARM section A8.8.116, encoding A1:
+ // mvn{s}<c> <Rd>, <Rm>{, <shift>
+ //
+ // cccc0001111s0000ddddiiiiitt0mmmm where cccc=Cond, s=SetFlags=0, dddd=Rd,
+ // mmmm=Rm, iiii defines shift constant, and tt=ShiftKind.
+ IValueT Rd;
+ if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
+ return setNeedsTextFixup();
+ constexpr IValueT MvnOpcode = B3 | B2 | B1 | B0; // i.e. 1111
+ constexpr IValueT Rn = 0;
+ constexpr bool SetFlags = false;
+ emitType01(MvnOpcode, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags);
+}
+
void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index 4372085..59383fb 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -238,6 +238,8 @@
void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
+ void mvn(const Operand *OpRd, const Operand *OpScc, CondARM32::Cond Cond);
+
void orr(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 0ca2d6a..24a9e0b 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1158,6 +1158,14 @@
emitUsingTextFixup(Func);
}
+template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const {
+ assert(getSrcSize() == 1);
+ auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
+ Asm->mvn(getDest(), getSrc(0), getPredicate());
+ if (Asm->needsTextFixup())
+ emitUsingTextFixup(Func);
+}
+
template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
diff --git a/tests_lit/assembler/arm32/mvn.ll b/tests_lit/assembler/arm32/mvn.ll
new file mode 100644
index 0000000..f23d218
--- /dev/null
+++ b/tests_lit/assembler/arm32/mvn.ll
@@ -0,0 +1,145 @@
+; Tests MVN instruction.
+
+; 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 void @mvmEx(i32 %a, i32 %b) {
+; ASM-LABEL:mvmEx:
+; DIS-LABEL:00000000 <mvmEx>:
+; IASM-LABEL:mvmEx:
+
+entry:
+; ASM-NEXT:.LmvmEx$entry:
+; IASM-NEXT:.LmvmEx$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: str r1, [sp, #16]
+; ASM-NEXT: # [sp, #16] = def.pseudo
+; DIS-NEXT: 8: e58d1010
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+ %b.arg_trunc = trunc i32 %b to i1
+
+; ASM-NEXT: ldr r0, [sp, #16]
+; DIS-NEXT: c: e59d0010
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x9d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: and r0, r0, #1
+; DIS-NEXT: 10: e2000001
+; IASM-NEXT: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xe2
+
+; ASM-NEXT: strb r0, [sp, #12]
+; ASM-NEXT: # [sp, #12] = def.pseudo
+; DIS-NEXT: 14: e5cd000c
+; IASM-NEXT: strb r0, [sp, #12]
+
+ %a.arg_trunc = trunc i32 %a to i1
+
+; ASM-NEXT: ldr r0, [sp, #20]
+; DIS-NEXT: 18: e59d0014
+; IASM-NEXT: .byte 0x14
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x9d
+; IASM-NEXT: .byte 0xe5
+
+; ASM-NEXT: and r0, r0, #1
+; DIS-NEXT: 1c: e2000001
+; IASM-NEXT: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xe2
+
+; ASM-NEXT: strb r0, [sp, #8]
+; ASM-NEXT: # [sp, #8] = def.pseudo
+; DIS-NEXT: 20: e5cd0008
+; IASM-NEXT: strb r0, [sp, #8]
+
+ %conv = zext i1 %a.arg_trunc to i32
+
+; ASM-NEXT: ldrb r0, [sp, #8]
+; DIS-NEXT: 24: e5dd0008
+; IASM-NEXT: ldrb r0, [sp, #8]
+
+; ASM-NEXT: str r0, [sp, #4]
+; ASM-NEXT: # [sp, #4] = def.pseudo
+; DIS-NEXT: 28: e58d0004
+; IASM-NEXT: .byte 0x4
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x8d
+; IASM-NEXT: .byte 0xe5
+
+ %ignore = sext i1 %b.arg_trunc to i32
+
+; ASM-NEXT: mov r0, #0
+; DIS-NEXT: 2c: e3a00000
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xa0
+; IASM-NEXT: .byte 0xe3
+
+; ASM-NEXT: ldrb r1, [sp, #12]
+; DIS-NEXT: 30: e5dd100c
+; IASM-NEXT: ldrb r1, [sp, #12]
+
+; ASM-NEXT: tst r1, #1
+; DIS-NEXT: 34: e3110001
+; IASM-NEXT: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x11
+; IASM-NEXT: .byte 0xe3
+
+; ********* Use of MVN ********
+; ASM-NEXT: mvn r1, #0
+; DIS-NEXT: 38: e3e01000
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0x10
+; IASM-NEXT: .byte 0xe0
+; IASM-NEXT: .byte 0xe3
+
+; ASM-NEXT: movne r0, r1
+; DIS-NEXT: 3c: 11a00001
+; IASM-NEXT: .byte 0x1
+; IASM-NEXT: .byte 0x0
+; IASM-NEXT: .byte 0xa0
+; IASM-NEXT: .byte 0x11
+
+ ret void
+}