Commit 372bdd6e by Karl Schimpf

Add "add immediate" instruction to the ARM integrated assembler.

Also does some bikeshed clean ups. In particualr, the (ARM) instruction method emitIAS only needs to choose the applicable ARM instruction, and then passes the corresponding operands to the corresponding instruction method of the assembler. The assembler method then extracts the appropriate data from the operands, and decides which rule to apply for the corresponding arm instruction. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1407613002 .
parent 85342a76
......@@ -208,6 +208,8 @@ void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
}
#if 0
// Moved to IceAssemberARM32::add.
void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ADD, 0, rn, rd, o);
}
......@@ -216,6 +218,7 @@ void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
void Assembler::adds(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ADD, 1, rn, rd, o);
}
#endif
void Assembler::subs(Register rd, Register rn, Operand o, Condition cond) {
......
......@@ -140,7 +140,7 @@ class Operand : public ValueObject {
}
#if 0
// Moved to AssemblerARM32::encodeImm12FromFlexImm.
// Moved to decode in IceAssemblerARM32.cpp
// Data-processing operands - Rotated immediate.
Operand(uint32_t rotate, uint32_t immed8) {
ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits)));
......@@ -149,11 +149,14 @@ class Operand : public ValueObject {
}
#endif
#if 0
// Moved to decode in IceAssemblerARM32.cpp
// Data-processing operands - Register.
explicit Operand(Register rm) {
type_ = 0;
encoding_ = static_cast<uint32_t>(rm);
}
#endif
// Data-processing operands - Logical shift/rotate by immediate.
Operand(Register rm, Shift shift, uint32_t shift_imm) {
......@@ -443,9 +446,12 @@ class Assembler : public ValueObject {
void rsb(Register rd, Register rn, Operand o, Condition cond = AL);
void rsbs(Register rd, Register rn, Operand o, Condition cond = AL);
#if 0
// Moved to IceAssemblerARM32::mov
void add(Register rd, Register rn, Operand o, Condition cond = AL);
void adds(Register rd, Register rn, Operand o, Condition cond = AL);
#endif
void adc(Register rd, Register rn, Operand o, Condition cond = AL);
......@@ -469,11 +475,10 @@ class Assembler : public ValueObject {
void orrs(Register rd, Register rn, Operand o, Condition cond = AL);
#if 0
// Moved to IceAssemblerARM32::mov(..FlexImm..)
// TODO(kschimpf) other forms of move.
// Moved to IceAssemblerARM32::mov
void mov(Register rd, Operand o, Condition cond = AL);
#endif
void movs(Register rd, Operand o, Condition cond = AL);
#endif
void bic(Register rd, Register rn, Operand o, Condition cond = AL);
void bics(Register rd, Register rn, Operand o, Condition cond = AL);
......
......@@ -22,7 +22,9 @@
#include "IceAssemblerARM32.h"
namespace Ice {
namespace {
using namespace Ice;
// The following define individual bits.
static constexpr uint32_t B0 = 1;
......@@ -50,9 +52,6 @@ static constexpr uint32_t kImmed8Shift = 0;
static constexpr uint32_t kRotateBits = 4;
static constexpr uint32_t kRotateShift = 8;
// Types of instructions.
static constexpr uint32_t kInstTypeImmediate = 1;
inline uint32_t encodeBool(bool b) { return b ? 1 : 0; }
inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) {
......@@ -75,14 +74,33 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) {
return static_cast<uint32_t>(Cond);
}
// Converts rotated immediate into imm12.
inline uint32_t encodeImm12FromFlexImm(const OperandARM32FlexImm &FlexImm) {
uint32_t Immed8 = FlexImm.getImm();
uint32_t Rotate = FlexImm.getRotateAmt();
assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)));
return (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
// The way an operand was decoded in function decode below.
enum DecodedResult {
CantDecode = 0, // I.e. will fail in test.
DecodedAsRegister,
DecodedAsRotatedImm8
};
DecodedResult decode(const Operand *Opnd, uint32_t &Value) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
if (Var->hasReg()) {
Value = Var->getRegNum();
return DecodedAsRegister;
}
} else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) {
uint32_t Immed8 = FlexImm->getImm();
uint32_t Rotate = FlexImm->getRotateAmt();
assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)));
Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
return DecodedAsRotatedImm8;
}
return CantDecode;
}
} // end of anonymous namespace
namespace Ice {
Label *ARM32::AssemblerARM32::getOrCreateLabel(SizeT Number,
LabelVector &Labels) {
Label *L = nullptr;
......@@ -120,6 +138,7 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
uint32_t Rd, uint32_t Imm12) {
assert(isGPRRegisterDefined(Rd));
assert(Cond != CondARM32::kNone);
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
uint32_t Encoding = encodeCondition(Cond) << kConditionShift |
(Type << kTypeShift) | (Opcode << kOpcodeShift) |
(encodeBool(SetCc) << kSShift) | (Rn << kRnShift) |
......@@ -127,6 +146,36 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
emitInst(Encoding);
}
void ARM32::AssemblerARM32::add(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) {
// ADD (Immediate): See ARM section A8.8.5, rule A1.
// cccc0010100snnnnddddiiiiiiiiiiii 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 = B2; // 0100
uint32_t InstType = 1;
emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value);
return;
}
} while (0);
UnimplementedError(Ctx->getFlags());
}
void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 |
......@@ -145,17 +194,30 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
emitInst(Encoding);
}
void ARM32::AssemblerARM32::mov(RegARM32::GPRRegister Rd,
const OperandARM32FlexImm &FlexImm,
void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) {
// cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1)
assert(isConditionDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
bool SetCc = false; // Note: We don't use movs in this assembler.
uint32_t Rn = 0;
uint32_t Mov = B3 | B2 | B0; // 1101.
emitType01(Cond, kInstTypeImmediate, Mov, SetCc, Rn, encodeGPRRegister(Rd),
encodeImm12FromFlexImm(FlexImm));
// Note: Loop is used so that we can short ciruit using break;
do {
uint32_t Rd;
if (decode(OpRd, Rd) != DecodedAsRegister)
break;
uint32_t Src;
// TODO(kschimpf) Handle other forms of mov.
if (decode(OpSrc, Src) == DecodedAsRotatedImm8) {
// cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1)
// Note: We don't use movs in this assembler.
constexpr bool SetFlags = false;
if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated.
break;
uint32_t Rn = 0;
uint32_t Mov = B3 | B2 | B0; // 1101.
uint32_t InstType = 1;
emitType01(Cond, InstType, Mov, SetFlags, Rn, Rd, Src);
return;
}
} while (0);
UnimplementedError(Ctx->getFlags());
}
} // end of namespace Ice
......@@ -93,12 +93,17 @@ public:
(void)Kind;
llvm_unreachable("Not yet implemented.");
}
void bind(Label *label);
// List of instructions implemented by integrated assembler.
void add(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
void bkpt(uint16_t Imm16);
void mov(RegARM32::GPRRegister Rd, const OperandARM32FlexImm &FlexImm,
CondARM32::Cond Cond);
void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
......
......@@ -318,6 +318,18 @@ bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
return Found;
}
template <InstARM32::InstKindARM32 K>
void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const {
(void)Func;
UnimplementedError(Func->getContext()->getFlags());
}
template <>
void InstARM32ThreeAddrGPR<InstARM32::Add>::emitIAS(const Cfg *Func) const {
ARM32::AssemblerARM32 *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
}
InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
: InstARM32(Func, InstARM32::Call, 1, Dest) {
HasSideEffects = true;
......@@ -605,11 +617,8 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (DestIsVector || DestIsScalarFP || CoreVFPMove)
break;
if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Src0)) {
Asm->mov(static_cast<RegARM32::GPRRegister>(Dest->getRegNum()),
*FlexImm, getPredicate());
return;
}
Asm->mov(Dest, Src0, getPredicate());
return;
}
} while (0);
llvm_unreachable("not yet implemented");
......@@ -1423,4 +1432,25 @@ void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const {
}
}
// Force instantition of template classes
template class InstARM32ThreeAddrGPR<InstARM32::Adc>;
template class InstARM32ThreeAddrGPR<InstARM32::Add>;
template class InstARM32ThreeAddrGPR<InstARM32::And>;
template class InstARM32ThreeAddrGPR<InstARM32::Asr>;
template class InstARM32ThreeAddrGPR<InstARM32::Bic>;
template class InstARM32ThreeAddrGPR<InstARM32::Eor>;
template class InstARM32ThreeAddrGPR<InstARM32::Lsl>;
template class InstARM32ThreeAddrGPR<InstARM32::Lsr>;
template class InstARM32ThreeAddrGPR<InstARM32::Mul>;
template class InstARM32ThreeAddrGPR<InstARM32::Orr>;
template class InstARM32ThreeAddrGPR<InstARM32::Rsb>;
template class InstARM32ThreeAddrGPR<InstARM32::Sbc>;
template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>;
template class InstARM32ThreeAddrGPR<InstARM32::Sub>;
template class InstARM32ThreeAddrGPR<InstARM32::Udiv>;
template class InstARM32ThreeAddrFP<InstARM32::Vadd>;
template class InstARM32ThreeAddrFP<InstARM32::Vdiv>;
template class InstARM32ThreeAddrFP<InstARM32::Vmul>;
template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
} // end of namespace Ice
......@@ -588,10 +588,7 @@ public:
return;
emitThreeAddr(Opcode, this, Func, SetFlags);
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm::report_fatal_error("Not yet implemented");
}
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
......
; Show that we know how to translate add.
; TODO(kschimpf) Currently only know how to test add 1 to 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 @add1ToR0(i32 %p) {
%v = add i32 %p, 1
ret i32 %v
}
; ASM-LABEL: add1ToR0:
; ASM: add r0, r0, #1
; ASM: bx lr
; IASM-LABEL: add1ToR0:
; IASM: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2
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