Commit 396de532 by Karl Schimpf

Add mul instruction to ARM integrated assembler.

Also cleans up a couple of template definitions by using the appropriate "using" type name. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1430713003 .
parent c33f7bbd
......@@ -353,7 +353,8 @@ void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
}
#endif
#if 0
// Moved to ARM32::AssemblerARM32::emitMulOp
void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Register rd, Register rn,
Register rm, Register rs) {
......@@ -372,12 +373,12 @@ void Assembler::EmitMulOp(Condition cond, int32_t opcode,
Emit(encoding);
}
// 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);
}
#endif
// Like mul, but sets condition flags.
void Assembler::muls(Register rd, Register rn, Register rm, Condition cond) {
......
......@@ -500,8 +500,11 @@ class Assembler : public ValueObject {
void clz(Register rd, Register rm, Condition cond = AL);
// Multiply instructions.
#if 0
// Moved to AssemblerARM32::mul()
void mul(Register rd, Register rn, Register rm, Condition cond = AL);
void muls(Register rd, Register rn, Register rm, Condition cond = AL);
#endif
void mla(Register rd, Register rn, Register rm, Register ra,
Condition cond = AL);
void mls(Register rd, Register rn, Register rm, Register ra,
......@@ -1160,12 +1163,15 @@ class Assembler : public ValueObject {
Register rm,
Operand o);
#if 0
// Moved to ARM32::AssemblerARM32::emitMulOp()
void EmitMulOp(Condition cond,
int32_t opcode,
Register rd,
Register rn,
Register rm,
Register rs);
#endif
void EmitDivOp(Condition cond,
int32_t opcode,
......
......@@ -37,6 +37,7 @@ static constexpr IValueT B3 = 1 << 3;
static constexpr IValueT B4 = 1 << 4;
static constexpr IValueT B5 = 1 << 5;
static constexpr IValueT B6 = 1 << 6;
static constexpr IValueT B7 = 1 << 7;
static constexpr IValueT B21 = 1 << 21;
static constexpr IValueT B22 = 1 << 22;
static constexpr IValueT B24 = 1 << 24;
......@@ -60,6 +61,7 @@ static constexpr IValueT kOpcodeShift = 21;
static constexpr IValueT kRdShift = 12;
static constexpr IValueT kRmShift = 0;
static constexpr IValueT kRnShift = 16;
static constexpr IValueT kRsShift = 8;
static constexpr IValueT kSShift = 20;
static constexpr IValueT kTypeShift = 25;
......@@ -376,6 +378,20 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
emitInst(Encoding);
}
void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, IValueT Rs, bool SetCc) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) ||
!isGPRRegisterDefined(Rm) || !isGPRRegisterDefined(Rs) ||
!isConditionDefined(Cond))
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
(encodeBool(SetCc) << kSShift) | (Rn << kRnShift) |
(Rd << kRdShift) | (Rs << kRsShift) | B7 | B4 |
(Rm << kRmShift);
emitInst(Encoding);
}
void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
......@@ -736,6 +752,31 @@ void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
}
void AssemblerARM32::mul(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
IValueT Rd;
if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Rn;
if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Rm;
if (decodeOperand(OpSrc1, Rm) != DecodedAsRegister)
return setNeedsTextFixup();
// MUL - ARM section A8.8.114, encoding A1.
// mul{s}<c> <Rd>, <Rn>, <Rm>
//
// cccc0000000sdddd0000mmmm1001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, and s=SetFlags.
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc ||
Rm == RegARM32::Encoded_Reg_pc)
llvm::report_fatal_error("Mul instruction unpredictable on pc");
// Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT MulOpcode = 0;
emitMulOp(Cond, MulOpcode, RegARM32::Encoded_Reg_r0, Rd, Rn, Rm, SetFlags);
}
void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
......
......@@ -146,18 +146,21 @@ public:
void b(Label *L, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
void bkpt(uint16_t Imm16);
void ldr(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond);
void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void mul(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void movt(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
......@@ -199,6 +202,11 @@ private:
void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
bool IsByte, uint32_t Rt, uint32_t Address);
// Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, ssss=Rs, f=SetCc, and xxxxxxx=Opcode.
void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, IValueT Rs, bool SetCc);
void emitBranch(Label *L, CondARM32::Cond, bool Link);
// Encodes the given Offset into the branch instruction Inst.
......
......@@ -344,16 +344,14 @@ void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func);
}
template <>
void InstARM32ThreeAddrGPR<InstARM32::Adc>::emitIAS(const Cfg *Func) const {
template <> void InstARM32Adc::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->adc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <>
void InstARM32ThreeAddrGPR<InstARM32::Add>::emitIAS(const Cfg *Func) const {
template <> void InstARM32Add::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
......@@ -367,16 +365,21 @@ template <> void InstARM32And::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func);
}
template <>
void InstARM32ThreeAddrGPR<InstARM32::Sbc>::emitIAS(const Cfg *Func) const {
template <> void InstARM32Mul::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->mul(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sbc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <>
void InstARM32ThreeAddrGPR<InstARM32::Sub>::emitIAS(const Cfg *Func) const {
template <> void InstARM32Sub::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
......
; Show that we know how to translate mul.
; 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 @MulTwoRegs(i32 %a, i32 %b) {
%v = mul i32 %a, %b
ret i32 %v
}
; ASM-LABEL:MulTwoRegs:
; ASM-NEXT:.LMulTwoRegs$__0:
; ASM-NEXT: mul r0, r0, r1
; DIS-LABEL:00000000 <MulTwoRegs>:
; DIS-NEXT: 0: e0000190
; IASM-LABEL:MulTwoRegs:
; IASM-NEXT:.LMulTwoRegs$__0:
; IASM-NEXT: .byte 0x90
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0xe0
define internal i64 @MulTwoI64Regs(i64 %a, i64 %b) {
%v = mul i64 %a, %b
ret i64 %v
}
; ASM-LABEL:MulTwoI64Regs:
; ASM-NEXT:.LMulTwoI64Regs$__0:
; ASM-NEXT: mul r3, r0, r3
; ASM-NEXT: mla r1, r2, r1, r3
; ASM-NEXT: umull r0, r2, r0, r2
; ASM: add r2, r2, r1
; ASM-NEXT: mov r1, r2
; ASM: bx lr
; DIS-LABEL:00000010 <MulTwoI64Regs>:
; DIS-NEXT: 10: e0030390
; DIS-NEXT: 14: e0213192
; DIS-NEXT: 18: e0820290
; DIS-NEXT: 1c: e0822001
; DIS-NEXT: 20: e1a01002
; DIS-NEXT: 24: e12fff1e
; IASM-LABEL:MulTwoI64Regs:
; IASM-NEXT:.LMulTwoI64Regs$__0:
; IASM-NEXT: .byte 0x90
; IASM-NEXT: .byte 0x3
; IASM-NEXT: .byte 0x3
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: mla r1, r2, r1, r3
; IASM-NEXT: umull r0, r2, r0, r2
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x20
; IASM-NEXT: .byte 0x82
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: mov r1, r2
; IASM-NEXT: .byte 0x1e
; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f
; IASM-NEXT: .byte 0xe1
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