Commit e559be77 by Karl Schimpf

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 .
parent f4198548
...@@ -92,7 +92,7 @@ void Assembler::EmitType01(Condition cond, ...@@ -92,7 +92,7 @@ void Assembler::EmitType01(Condition cond,
Emit(encoding); Emit(encoding);
} }
// Moved to ARM32::AssemblerARM32::emitType05. // Moved to ARM32::AssemblerARM32::emitType05()
void Assembler::EmitType5(Condition cond, int32_t offset, bool link) { void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
...@@ -304,26 +304,26 @@ void Assembler::movs(Register rd, Operand o, Condition cond) { ...@@ -304,26 +304,26 @@ void Assembler::movs(Register rd, Operand o, Condition cond) {
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::bic(); // Moved to ARM32::AssemblerARM32::bic()
void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) { void Assembler::bic(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), BIC, 0, rn, rd, o); 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) { void Assembler::bics(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), BIC, 1, rn, rd, o); EmitType01(cond, o.type(), BIC, 1, rn, rd, o);
} }
#endif
// Moved to ARM32::AssemblerARM32::mvn()
void Assembler::mvn(Register rd, Operand o, Condition cond) { void Assembler::mvn(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MVN, 0, R0, rd, o); EmitType01(cond, o.type(), MVN, 0, R0, rd, o);
} }
// Moved to ARM32::AssemblerARM32::mvn()
void Assembler::mvns(Register rd, Operand o, Condition cond) { void Assembler::mvns(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MVN, 1, R0, rd, o); EmitType01(cond, o.type(), MVN, 1, R0, rd, o);
} }
#endif
void Assembler::clz(Register rd, Register rm, Condition cond) { void Assembler::clz(Register rd, Register rm, Condition cond) {
ASSERT(rd != kNoRegister); ASSERT(rd != kNoRegister);
...@@ -340,7 +340,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) { ...@@ -340,7 +340,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) {
#if #if
// Moved to ARM32::AssemblerARM32::movw // Moved to ARM32::AssemblerARM32::movw()
void Assembler::movw(Register rd, uint16_t imm16, Condition cond) { void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
...@@ -350,7 +350,7 @@ void Assembler::movw(Register rd, uint16_t imm16, Condition cond) { ...@@ -350,7 +350,7 @@ void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
} }
// Moved to ARM32::AssemblerARM32::movt // Moved to ARM32::AssemblerARM32::movt()
void Assembler::movt(Register rd, uint16_t imm16, Condition cond) { void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
...@@ -361,7 +361,7 @@ void Assembler::movt(Register rd, uint16_t imm16, Condition cond) { ...@@ -361,7 +361,7 @@ void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
#endif #endif
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::emitMulOp // Moved to ARM32::AssemblerARM32::emitMulOp()
void Assembler::EmitMulOp(Condition cond, int32_t opcode, void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Register rd, Register rn, Register rd, Register rn,
Register rm, Register rs) { Register rm, Register rs) {
...@@ -380,7 +380,7 @@ void Assembler::EmitMulOp(Condition cond, int32_t opcode, ...@@ -380,7 +380,7 @@ void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Emit(encoding); Emit(encoding);
} }
// Moved to ARM32::AssemblerARM32::mul // Moved to ARM32::AssemblerARM32::mul()
void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) { void Assembler::mul(Register rd, Register rn, Register rm, Condition cond) {
// Assembler registers rd, rn, rm are encoded as rn, rm, rs. // Assembler registers rd, rn, rm are encoded as rn, rm, rs.
EmitMulOp(cond, 0, R0, rd, rn, rm); EmitMulOp(cond, 0, R0, rd, rn, rm);
...@@ -2104,7 +2104,7 @@ void Assembler::UpdateRangeFeedback(Register value, ...@@ -2104,7 +2104,7 @@ void Assembler::UpdateRangeFeedback(Register value,
} }
#if 0 #if 0
// Moved to ::canEncodeBranchoffset in IceAssemblerARM32.cpp. // Moved to ::canEncodeBranchoffset() in IceAssemblerARM32.cpp.
static bool CanEncodeBranchOffset(int32_t offset) { static bool CanEncodeBranchOffset(int32_t offset) {
ASSERT(Utils::IsAligned(offset, 4)); ASSERT(Utils::IsAligned(offset, 4));
// Note: This check doesn't take advantage of the fact that offset>>2 // Note: This check doesn't take advantage of the fact that offset>>2
...@@ -2112,7 +2112,7 @@ static bool CanEncodeBranchOffset(int32_t offset) { ...@@ -2112,7 +2112,7 @@ static bool CanEncodeBranchOffset(int32_t offset) {
return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset); 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) { 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. // The offset is off by 8 due to the way the ARM CPUs read PC.
offset -= Instr::kPCReadOffset; offset -= Instr::kPCReadOffset;
...@@ -2129,7 +2129,7 @@ int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) { ...@@ -2129,7 +2129,7 @@ int32_t Assembler::EncodeBranchOffset(int32_t offset, int32_t inst) {
return (inst & ~kBranchOffsetMask) | offset; return (inst & ~kBranchOffsetMask) | offset;
} }
// Moved to AssemberARM32::decodeBranchOffset. // Moved to AssemberARM32::decodeBranchOffset()
int Assembler::DecodeBranchOffset(int32_t inst) { int Assembler::DecodeBranchOffset(int32_t inst) {
// Sign-extend, left-shift by 2, then add 8. // Sign-extend, left-shift by 2, then add 8.
return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset); return ((((inst & kBranchOffsetMask) << 8) >> 6) + Instr::kPCReadOffset);
......
...@@ -507,10 +507,11 @@ class Assembler : public ValueObject { ...@@ -507,10 +507,11 @@ class Assembler : public ValueObject {
// Moved to ARM32::IceAssemblerARM32::bic() // Moved to ARM32::IceAssemblerARM32::bic()
void bic(Register rd, Register rn, Operand o, Condition cond = AL); void bic(Register rd, Register rn, Operand o, Condition cond = AL);
void bics(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 mvn(Register rd, Operand o, Condition cond = AL);
void mvns(Register rd, Operand o, Condition cond = AL); void mvns(Register rd, Operand o, Condition cond = AL);
#endif
// Miscellaneous data-processing instructions. // Miscellaneous data-processing instructions.
void clz(Register rd, Register rm, Condition cond = AL); void clz(Register rd, Register rm, Condition cond = AL);
......
...@@ -187,16 +187,17 @@ enum DecodedResult { ...@@ -187,16 +187,17 @@ enum DecodedResult {
// Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
// value. // value.
DecodedAsRotatedImm8, 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 // 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. // Rn should be used, and iiiiiiiiiiii defines the rotated Imm8 value.
DecodedAsImmRegOffset, 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 // 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 // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
// writeback to Rn. // writeback to Rn.
DecodedAsShiftRotateImm5, DecodedAsShiftRotateImm5,
// i.e. 000000000000000000000iiiii0000000 iiii defines Imm5 value to shift. // Value=000000000000000000000iiiii0000000 iiii defines the Imm5 value to
// shift.
DecodedAsShiftImm5, DecodedAsShiftImm5,
// Value is 32bit integer constant. // Value is 32bit integer constant.
DecodedAsConstI32 DecodedAsConstI32
...@@ -218,8 +219,8 @@ IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift, ...@@ -218,8 +219,8 @@ IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift,
return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
} }
// Encodes mmmmtt01ssss for data-processing (2nd) operands where mmmm=Rm, // Encodes mmmmtt01ssss for data-processing operands where mmmm=Rm, ssss=Rs, and
// ssss=Rs, and tt=Shift. // tt=Shift.
IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift, IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
IValueT Rs) { IValueT Rs) {
return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 | return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 |
...@@ -481,15 +482,6 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, ...@@ -481,15 +482,6 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd,
void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond, EmitChecks RuleChecks) { 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; IValueT Src1Value;
// TODO(kschimpf) Other possible decodings of data operations. // TODO(kschimpf) Other possible decodings of data operations.
...@@ -564,8 +556,9 @@ void AssemblerARM32::emitCompareOp(IValueT Opcode, const Operand *OpRn, ...@@ -564,8 +556,9 @@ void AssemblerARM32::emitCompareOp(IValueT Opcode, const Operand *OpRn,
// XXX (register) // XXX (register)
// XXX<c> <Rn>, <Rm>{, <shift>} // XXX<c> <Rn>, <Rm>{, <shift>}
// //
// ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm, // ccccyyyxxxx1nnnn0000iiiiitt0mmmm where cccc=Cond, nnnn=Rn, mmmm=Rm, iiiii
// iiiii=Shift, tt=ShiftKind, yyy=kInstTypeDataRegister, and xxxx=Opcode. // defines shift constant, tt=ShiftKind, yyy=kInstTypeDataRegister, and
// xxxx=Opcode.
// //
// XXX (immediate) // XXX (immediate)
// XXX<c> <Rn>, #<RotatedImm8> // XXX<c> <Rn>, #<RotatedImm8>
...@@ -1047,6 +1040,28 @@ void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc, ...@@ -1047,6 +1040,28 @@ void AssemblerARM32::movt(const Operand *OpRd, const Operand *OpSrc,
emitInst(Encoding); 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, void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
......
...@@ -238,6 +238,8 @@ public: ...@@ -238,6 +238,8 @@ public:
void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); 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, void orr(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
......
...@@ -1158,6 +1158,14 @@ template <> void InstARM32Movt::emitIAS(const Cfg *Func) const { ...@@ -1158,6 +1158,14 @@ template <> void InstARM32Movt::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); 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 { template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
assert(getSrcSize() == 1); assert(getSrcSize() == 1);
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
......
; 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
}
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