Commit 697dc796 by Karl Schimpf

Add SDIV to ARM integrated assembler.

Also clean up some comments on where code was moved from in Dart sourced. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1429003002 .
parent e849a572
...@@ -286,7 +286,7 @@ void Assembler::orrs(Register rd, Register rn, Operand o, Condition cond) { ...@@ -286,7 +286,7 @@ void Assembler::orrs(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ORR, 1, rn, rd, o); EmitType01(cond, o.type(), ORR, 1, rn, rd, o);
} }
// Moved to AssemblerARM32::mov() // Moved to ARM32::AssemblerARM32::mov()
// TODO(kschimpf) other forms of move. // TODO(kschimpf) other forms of move.
void Assembler::mov(Register rd, Operand o, Condition cond) { void Assembler::mov(Register rd, Operand o, Condition cond) {
EmitType01(cond, o.type(), MOV, 0, R0, rd, o); EmitType01(cond, o.type(), MOV, 0, R0, rd, o);
...@@ -333,7 +333,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) { ...@@ -333,7 +333,7 @@ void Assembler::clz(Register rd, Register rm, Condition cond) {
#if #if
// Moved to ARM::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 |
...@@ -343,7 +343,7 @@ void Assembler::movw(Register rd, uint16_t imm16, Condition cond) { ...@@ -343,7 +343,7 @@ void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
} }
// Moved to ARM::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 |
...@@ -446,6 +446,8 @@ void Assembler::umaal(Register rd_lo, Register rd_hi, ...@@ -446,6 +446,8 @@ void Assembler::umaal(Register rd_lo, Register rd_hi,
} }
#if 0
// Moved to ARM32::AssemblerARM32::emitDivOp()
void Assembler::EmitDivOp(Condition cond, int32_t opcode, void Assembler::EmitDivOp(Condition cond, int32_t opcode,
Register rd, Register rn, Register rm) { Register rd, Register rn, Register rm) {
ASSERT(TargetCPUFeatures::integer_division_supported()); ASSERT(TargetCPUFeatures::integer_division_supported());
...@@ -457,16 +459,17 @@ void Assembler::EmitDivOp(Condition cond, int32_t opcode, ...@@ -457,16 +459,17 @@ void Assembler::EmitDivOp(Condition cond, int32_t opcode,
(static_cast<int32_t>(cond) << kConditionShift) | (static_cast<int32_t>(cond) << kConditionShift) |
(static_cast<int32_t>(rn) << kDivRnShift) | (static_cast<int32_t>(rn) << kDivRnShift) |
(static_cast<int32_t>(rd) << kDivRdShift) | (static_cast<int32_t>(rd) << kDivRdShift) |
// TODO(kschimpf): Why not also: B15 | B14 | B13 | B12?
B26 | B25 | B24 | B20 | B4 | B26 | B25 | B24 | B20 | B4 |
(static_cast<int32_t>(rm) << kDivRmShift); (static_cast<int32_t>(rm) << kDivRmShift);
Emit(encoding); Emit(encoding);
} }
// Moved to ARM32::AssemblerARM32::sdiv()
void Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) { void Assembler::sdiv(Register rd, Register rn, Register rm, Condition cond) {
EmitDivOp(cond, 0, rd, rn, rm); EmitDivOp(cond, 0, rd, rn, rm);
} }
#endif
void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) { void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
EmitDivOp(cond, B21 , rd, rn, rm); EmitDivOp(cond, B21 , rd, rn, rm);
...@@ -2096,7 +2099,7 @@ static bool CanEncodeBranchOffset(int32_t offset) { ...@@ -2096,7 +2099,7 @@ static bool CanEncodeBranchOffset(int32_t offset) {
return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset); return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
} }
// Moved to 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;
......
...@@ -503,7 +503,7 @@ class Assembler : public ValueObject { ...@@ -503,7 +503,7 @@ class Assembler : public ValueObject {
// Multiply instructions. // Multiply instructions.
#if 0 #if 0
// Moved to AssemblerARM32::mul() // Moved to ARM32::AssemblerARM32::mul()
void mul(Register rd, Register rn, Register rm, Condition cond = AL); void mul(Register rd, Register rn, Register rm, Condition cond = AL);
void muls(Register rd, Register rn, Register rm, Condition cond = AL); void muls(Register rd, Register rn, Register rm, Condition cond = AL);
#endif #endif
...@@ -526,19 +526,22 @@ class Assembler : public ValueObject { ...@@ -526,19 +526,22 @@ class Assembler : public ValueObject {
void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm); void umaal(Register rd_lo, Register rd_hi, Register rn, Register rm);
// Division instructions. // Division instructions.
#if 0
// Moved to ARM32::AssemblerARM32::sdiv()
void sdiv(Register rd, Register rn, Register rm, Condition cond = AL); void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
#endif
void udiv(Register rd, Register rn, Register rm, Condition cond = AL); void udiv(Register rd, Register rn, Register rm, Condition cond = AL);
#if 0 #if 0
// Moved to AssemblerARM32::ldr() // Moved to ARM32::AssemblerARM32::ldr()
// Load/store instructions. // Load/store instructions.
void ldr(Register rd, Address ad, Condition cond = AL); void ldr(Register rd, Address ad, Condition cond = AL);
// Moved to AssemblerARM32::str() // Moved to ARM32::AssemblerARM32::str()
void str(Register rd, Address ad, Condition cond = AL); void str(Register rd, Address ad, Condition cond = AL);
// Moved to AssemblerARM32::ldr() // Moved to ARM32::AssemblerARM32::ldr()
void ldrb(Register rd, Address ad, Condition cond = AL); void ldrb(Register rd, Address ad, Condition cond = AL);
// Moved to AssemblerARM32::str() // Moved to ARM32::AssemblerARM32::str()
void strb(Register rd, Address ad, Condition cond = AL); void strb(Register rd, Address ad, Condition cond = AL);
#endif #endif
...@@ -1173,13 +1176,14 @@ class Assembler : public ValueObject { ...@@ -1173,13 +1176,14 @@ class Assembler : public ValueObject {
Register rn, Register rn,
Register rm, Register rm,
Register rs); Register rs);
#endif
// Moved to ARM32::AssemblerAR32::emitDivOp();
void EmitDivOp(Condition cond, void EmitDivOp(Condition cond,
int32_t opcode, int32_t opcode,
Register rd, Register rd,
Register rn, Register rn,
Register rm); Register rm);
#endif
void EmitMultiVSMemOp(Condition cond, void EmitMultiVSMemOp(Condition cond,
BlockAddressMode am, BlockAddressMode am,
......
...@@ -38,10 +38,16 @@ static constexpr IValueT B4 = 1 << 4; ...@@ -38,10 +38,16 @@ static constexpr IValueT B4 = 1 << 4;
static constexpr IValueT B5 = 1 << 5; static constexpr IValueT B5 = 1 << 5;
static constexpr IValueT B6 = 1 << 6; static constexpr IValueT B6 = 1 << 6;
static constexpr IValueT B7 = 1 << 7; static constexpr IValueT B7 = 1 << 7;
static constexpr IValueT B12 = 1 << 12;
static constexpr IValueT B13 = 1 << 13;
static constexpr IValueT B14 = 1 << 14;
static constexpr IValueT B15 = 1 << 15;
static constexpr IValueT B20 = 1 << 20;
static constexpr IValueT B21 = 1 << 21; static constexpr IValueT B21 = 1 << 21;
static constexpr IValueT B22 = 1 << 22; static constexpr IValueT B22 = 1 << 22;
static constexpr IValueT B24 = 1 << 24; static constexpr IValueT B24 = 1 << 24;
static constexpr IValueT B25 = 1 << 25; static constexpr IValueT B25 = 1 << 25;
static constexpr IValueT B26 = 1 << 26;
// Constants used for the decoding or encoding of the individual fields of // Constants used for the decoding or encoding of the individual fields of
// instructions. Based on ARM section A5.1. // instructions. Based on ARM section A5.1.
...@@ -79,6 +85,11 @@ static constexpr IValueT kShiftShift = 5; ...@@ -79,6 +85,11 @@ static constexpr IValueT kShiftShift = 5;
static constexpr IValueT kImmed12Bits = 12; static constexpr IValueT kImmed12Bits = 12;
static constexpr IValueT kImm12Shift = 0; static constexpr IValueT kImm12Shift = 0;
// Div instruction register field encodings.
static constexpr IValueT kDivRdShift = 16;
static constexpr IValueT kDivRmShift = 8;
static constexpr IValueT kDivRnShift = 0;
// Type of instruction encoding (bits 25-27). See ARM section A5.1 // Type of instruction encoding (bits 25-27). See ARM section A5.1
static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000 static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000
static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001 static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001
...@@ -439,6 +450,19 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType, ...@@ -439,6 +450,19 @@ void AssemblerARM32::emitMemOp(CondARM32::Cond Cond, IValueT InstType,
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) ||
!isGPRRegisterDefined(Rm) || !isConditionDefined(Cond))
return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
(Rn << kDivRnShift) | (Rd << kDivRdShift) | B26 |
B25 | B24 | B20 | B15 | B14 | B13 | B12 | B4 |
(Rm << kDivRmShift);
emitInst(Encoding);
}
void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, IValueT Rs, bool SetCc) { IValueT Rn, IValueT Rm, IValueT Rs, bool SetCc) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) || if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) ||
...@@ -691,6 +715,30 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, ...@@ -691,6 +715,30 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
emitType01(Sbc, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Sbc, OpRd, OpRn, OpSrc1, SetFlags, Cond);
} }
void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, CondARM32::Cond Cond) {
// SDIV - ARM section A8.8.165, encoding A1.
// sdiv<c> <Rd>, <Rn>, <Rm>
//
// cccc01110001dddd1111mmmm0001nnnn where cccc=Cond, dddd=Rd, nnnn=Rn, and
// mmmm=Rm.
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();
if (Rd == RegARM32::Encoded_Reg_pc || Rn == RegARM32::Encoded_Reg_pc ||
Rm == RegARM32::Encoded_Reg_pc)
llvm::report_fatal_error("Sdiv instruction unpredictable on pc");
// Assembler registers rd, rn, rm are encoded as rn, rm, rs.
constexpr IValueT Opcode = 0;
emitDivOp(Cond, Opcode, Rd, Rn, Rm);
}
void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress, void AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
IValueT Rt; IValueT Rt;
......
...@@ -170,6 +170,9 @@ public: ...@@ -170,6 +170,9 @@ public:
void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void sbc(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
void sdiv(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
CondARM32::Cond Cond);
void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond); void str(const Operand *OpRt, const Operand *OpAddress, CondARM32::Cond Cond);
void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1, void sub(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
...@@ -213,6 +216,11 @@ private: ...@@ -213,6 +216,11 @@ private:
void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad, void emitMemOp(CondARM32::Cond Cond, IValueT InstType, bool IsLoad,
bool IsByte, uint32_t Rt, uint32_t Address); bool IsByte, uint32_t Rt, uint32_t Address);
// Pattern cccc011100x1dddd1111mmmm0001nnn where cccc=Cond,
// x=Opcode, dddd=Rd, nnnn=Rn, mmmm=Rm.
void emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm);
// Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, ssss=Rs, f=SetCc, and xxxxxxx=Opcode. // mmmm=Rm, ssss=Rs, f=SetCc, and xxxxxxx=Opcode.
void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
......
...@@ -393,6 +393,14 @@ template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const { ...@@ -393,6 +393,14 @@ template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Sdiv::emitIAS(const Cfg *Func) const {
assert(!SetFlags);
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sdiv(getDest(), getSrc(0), getSrc(1), getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <> void InstARM32Sub::emitIAS(const Cfg *Func) const { template <> void InstARM32Sub::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
......
; Show that we know how to translate sdiv
; 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 -mattr=hwdiv-arm \
; 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 -mattr=hwdiv-arm | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 -mattr=hwdiv-arm \
; 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 -mattr=hwdiv-arm | FileCheck %s --check-prefix=DIS
define internal i32 @SdivTwoRegs(i32 %a, i32 %b) {
%v = sdiv i32 %a, %b
ret i32 %v
}
; ASM-LABEL:SdivTwoRegs:
; ASM-NEXT:.LSdivTwoRegs$__0:
; ASM-NEXT: tst r1, r1
; ASM-NEXT: bne .LSdivTwoRegs$local$__0
; ASM-NEXT: .long 0xe7fedef0
; ASM-NEXT:.LSdivTwoRegs$local$__0:
; ASM-NEXT: sdiv r0, r0, r1
; ASM-NEXT: bx lr
; DIS-LABEL:00000000 <SdivTwoRegs>:
; DIS-NEXT: 0: e1110001
; DIS-NEXT: 4: 1a000000
; DIS-NEXT: 8: e7fedef0
; DIS-NEXT: c: e710f110
; DIS-NEXT: 10: e12fff1e
; IASM-LABEL:SdivTwoRegs:
; IASM-NEXT:.LSdivTwoRegs$__0:
; IASM-NEXT: tst r1, r1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x1a
; IASM-NEXT: .long 0xe7fedef0
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xf1
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0xe7
; 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