Commit 745ad1d8 by Karl Schimpf

Handle stack spills in ARM integrated assembler.

Add code to handle spilling stack variables. That is, add code to handle loading and storing to stack addresses. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1402403002 .
parent 1fb030c6
...@@ -72,7 +72,7 @@ void Assembler::Emit(int32_t value) { ...@@ -72,7 +72,7 @@ void Assembler::Emit(int32_t value) {
} }
#if 0 #if 0
// Moved to class AssemblerARM32. // Moved to ARM32::AssemblerARM32::emitType01()
void Assembler::EmitType01(Condition cond, void Assembler::EmitType01(Condition cond,
int type, int type,
Opcode opcode, Opcode opcode,
...@@ -102,6 +102,8 @@ void Assembler::EmitType5(Condition cond, int32_t offset, bool link) { ...@@ -102,6 +102,8 @@ void Assembler::EmitType5(Condition cond, int32_t offset, bool link) {
} }
#if 0
// Moved to ARM32::AssemblerARM32::emitMemOp()
void Assembler::EmitMemOp(Condition cond, void Assembler::EmitMemOp(Condition cond,
bool load, bool load,
bool byte, bool byte,
...@@ -117,7 +119,7 @@ void Assembler::EmitMemOp(Condition cond, ...@@ -117,7 +119,7 @@ void Assembler::EmitMemOp(Condition cond,
ad.encoding(); ad.encoding();
Emit(encoding); Emit(encoding);
} }
#endif
void Assembler::EmitMemOpAddressMode3(Condition cond, void Assembler::EmitMemOpAddressMode3(Condition cond,
int32_t mode, int32_t mode,
...@@ -194,10 +196,12 @@ void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) { ...@@ -194,10 +196,12 @@ void Assembler::eor(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), EOR, 0, rn, rd, o); EmitType01(cond, o.type(), EOR, 0, rn, rd, o);
} }
#if 0
// Moved to ARM32::AssemberARM32::sub()
void Assembler::sub(Register rd, Register rn, Operand o, Condition cond) { void Assembler::sub(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), SUB, 0, rn, rd, o); EmitType01(cond, o.type(), SUB, 0, rn, rd, o);
} }
#endif
void Assembler::rsb(Register rd, Register rn, Operand o, Condition cond) { void Assembler::rsb(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), RSB, 0, rn, rd, o); EmitType01(cond, o.type(), RSB, 0, rn, rd, o);
...@@ -209,22 +213,23 @@ void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) { ...@@ -209,22 +213,23 @@ void Assembler::rsbs(Register rd, Register rn, Operand o, Condition cond) {
#if 0 #if 0
// Moved to IceAssemberARM32::add. // Moved to ARM32::AssemberARM32::add()
void Assembler::add(Register rd, Register rn, Operand o, Condition cond) { void Assembler::add(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ADD, 0, rn, rd, o); EmitType01(cond, o.type(), ADD, 0, rn, rd, o);
} }
// Moved to ARM32::AssemberARM32::add()
void Assembler::adds(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); EmitType01(cond, o.type(), ADD, 1, rn, rd, o);
} }
#endif #endif
#if 0
// Moved to ARM32::AssemberARM32::sub()
void Assembler::subs(Register rd, Register rn, Operand o, Condition cond) { void Assembler::subs(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), SUB, 1, rn, rd, o); EmitType01(cond, o.type(), SUB, 1, rn, rd, o);
} }
#endif
void Assembler::adc(Register rd, Register rn, Operand o, Condition cond) { void Assembler::adc(Register rd, Register rn, Operand o, Condition cond) {
EmitType01(cond, o.type(), ADC, 0, rn, rd, o); EmitType01(cond, o.type(), ADC, 0, rn, rd, o);
...@@ -464,25 +469,27 @@ void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) { ...@@ -464,25 +469,27 @@ void Assembler::udiv(Register rd, Register rn, Register rm, Condition cond) {
} }
#if 0
// Moved to ARM32::AssemblerARM32::ldr()
void Assembler::ldr(Register rd, Address ad, Condition cond) { void Assembler::ldr(Register rd, Address ad, Condition cond) {
EmitMemOp(cond, true, false, rd, ad); EmitMemOp(cond, true, false, rd, ad);
} }
// Moved to ARM32::AssemblerARM32::str()
void Assembler::str(Register rd, Address ad, Condition cond) { void Assembler::str(Register rd, Address ad, Condition cond) {
EmitMemOp(cond, false, false, rd, ad); EmitMemOp(cond, false, false, rd, ad);
} }
// Moved to ARM32::AssemblerARM32::ldr()
void Assembler::ldrb(Register rd, Address ad, Condition cond) { void Assembler::ldrb(Register rd, Address ad, Condition cond) {
EmitMemOp(cond, true, true, rd, ad); EmitMemOp(cond, true, true, rd, ad);
} }
// Moved to ARM32::AssemblerARM32::str()
void Assembler::strb(Register rd, Address ad, Condition cond) { void Assembler::strb(Register rd, Address ad, Condition cond) {
EmitMemOp(cond, false, true, rd, ad); EmitMemOp(cond, false, true, rd, ad);
} }
#endif
void Assembler::ldrh(Register rd, Address ad, Condition cond) { void Assembler::ldrh(Register rd, Address ad, Condition cond) {
EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad); EmitMemOpAddressMode3(cond, L | B7 | H | B4, rd, ad);
...@@ -1441,7 +1448,7 @@ void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) { ...@@ -1441,7 +1448,7 @@ void Assembler::vcgtqs(QRegister qd, QRegister qn, QRegister qm) {
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32. // Moved to: ARM32::AssemblerARM32::bkpt()
void Assembler::bkpt(uint16_t imm16) { void Assembler::bkpt(uint16_t imm16) {
Emit(BkptEncoding(imm16)); Emit(BkptEncoding(imm16));
} }
...@@ -1458,7 +1465,7 @@ void Assembler::bl(Label* label, Condition cond) { ...@@ -1458,7 +1465,7 @@ void Assembler::bl(Label* label, Condition cond) {
} }
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32. // Moved to: ARM32::AssemblerARM32::bx()
void Assembler::bx(Register rm, Condition cond) { void Assembler::bx(Register rm, Condition cond) {
ASSERT(rm != kNoRegister); ASSERT(rm != kNoRegister);
ASSERT(cond != kNoCondition); ASSERT(cond != kNoCondition);
...@@ -2327,7 +2334,7 @@ void Assembler::BindARMv6(Label* label) { ...@@ -2327,7 +2334,7 @@ void Assembler::BindARMv6(Label* label) {
} }
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32 as method bind(Label* Label) // Moved to: ARM32::AssemblerARM32::bind(Label* Label)
// Note: Most of this code isn't needed because instruction selection has // Note: Most of this code isn't needed because instruction selection has
// already been handler // already been handler
void Assembler::BindARMv7(Label* label) { void Assembler::BindARMv7(Label* label) {
......
...@@ -140,7 +140,7 @@ class Operand : public ValueObject { ...@@ -140,7 +140,7 @@ class Operand : public ValueObject {
} }
#if 0 #if 0
// Moved to decode in IceAssemblerARM32.cpp // Moved to decodeOperand() in IceAssemblerARM32.cpp
// Data-processing operands - Rotated immediate. // Data-processing operands - Rotated immediate.
Operand(uint32_t rotate, uint32_t immed8) { Operand(uint32_t rotate, uint32_t immed8) {
ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits))); ASSERT((rotate < (1 << kRotateBits)) && (immed8 < (1 << kImmed8Bits)));
...@@ -150,7 +150,7 @@ class Operand : public ValueObject { ...@@ -150,7 +150,7 @@ class Operand : public ValueObject {
#endif #endif
#if 0 #if 0
// Moved to decode in IceAssemblerARM32.cpp // Moved to decodeOperand() in IceAssemblerARM32.cpp
// Data-processing operands - Register. // Data-processing operands - Register.
explicit Operand(Register rm) { explicit Operand(Register rm) {
type_ = 0; type_ = 0;
...@@ -277,6 +277,9 @@ class Address : public ValueObject { ...@@ -277,6 +277,9 @@ class Address : public ValueObject {
return (encoding_ == other.encoding_) && (kind_ == other.kind_); return (encoding_ == other.encoding_) && (kind_ == other.kind_);
} }
#if 0
// Moved to decodeImmRegOffset() in IceAssemblerARM32.cpp.
// Used to model stack offsets.
explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) { explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) {
ASSERT(Utils::IsAbsoluteUint(12, offset)); ASSERT(Utils::IsAbsoluteUint(12, offset));
kind_ = Immediate; kind_ = Immediate;
...@@ -287,6 +290,7 @@ class Address : public ValueObject { ...@@ -287,6 +290,7 @@ class Address : public ValueObject {
} }
encoding_ |= static_cast<uint32_t>(rn) << kRnShift; encoding_ |= static_cast<uint32_t>(rn) << kRnShift;
} }
#endif
// There is no register offset mode unless Mode is Offset, in which case the // There is no register offset mode unless Mode is Offset, in which case the
// shifted register case below should be used. // shifted register case below should be used.
...@@ -440,14 +444,17 @@ class Assembler : public ValueObject { ...@@ -440,14 +444,17 @@ class Assembler : public ValueObject {
void eor(Register rd, Register rn, Operand o, Condition cond = AL); void eor(Register rd, Register rn, Operand o, Condition cond = AL);
#if 0
// Moved to ARM32::AssemberARM32::sub()
void sub(Register rd, Register rn, Operand o, Condition cond = AL); void sub(Register rd, Register rn, Operand o, Condition cond = AL);
void subs(Register rd, Register rn, Operand o, Condition cond = AL); void subs(Register rd, Register rn, Operand o, Condition cond = AL);
#endif
void rsb(Register rd, Register rn, Operand o, Condition cond = AL); void rsb(Register rd, Register rn, Operand o, Condition cond = AL);
void rsbs(Register rd, Register rn, Operand o, Condition cond = AL); void rsbs(Register rd, Register rn, Operand o, Condition cond = AL);
#if 0 #if 0
// Moved to IceAssemblerARM32::mov // Moved to ARM32::AssemblerARM32::add()
void add(Register rd, Register rn, Operand o, Condition cond = AL); void add(Register rd, Register rn, Operand o, Condition cond = AL);
void adds(Register rd, Register rn, Operand o, Condition cond = AL); void adds(Register rd, Register rn, Operand o, Condition cond = AL);
...@@ -475,7 +482,7 @@ class Assembler : public ValueObject { ...@@ -475,7 +482,7 @@ class Assembler : public ValueObject {
void orrs(Register rd, Register rn, Operand o, Condition cond = AL); void orrs(Register rd, Register rn, Operand o, Condition cond = AL);
#if 0 #if 0
// Moved to IceAssemblerARM32::mov // Moved to IceAssemblerARM32::mov()
void mov(Register rd, Operand o, Condition cond = AL); void mov(Register rd, Operand o, Condition cond = AL);
void movs(Register rd, Operand o, Condition cond = AL); void movs(Register rd, Operand o, Condition cond = AL);
#endif #endif
...@@ -514,12 +521,18 @@ class Assembler : public ValueObject { ...@@ -514,12 +521,18 @@ class Assembler : public ValueObject {
void sdiv(Register rd, Register rn, Register rm, Condition cond = AL); void sdiv(Register rd, Register rn, Register rm, Condition cond = AL);
void udiv(Register rd, Register rn, Register rm, Condition cond = AL); void udiv(Register rd, Register rn, Register rm, Condition cond = AL);
#if 0
// Moved to 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()
void str(Register rd, Address ad, Condition cond = AL); void str(Register rd, Address ad, Condition cond = AL);
// Moved to AssemblerARM32::ldr()
void ldrb(Register rd, Address ad, Condition cond = AL); void ldrb(Register rd, Address ad, Condition cond = AL);
// Moved to AssemblerARM32::str()
void strb(Register rd, Address ad, Condition cond = AL); void strb(Register rd, Address ad, Condition cond = AL);
#endif
void ldrh(Register rd, Address ad, Condition cond = AL); void ldrh(Register rd, Address ad, Condition cond = AL);
void strh(Register rd, Address ad, Condition cond = AL); void strh(Register rd, Address ad, Condition cond = AL);
...@@ -546,7 +559,7 @@ class Assembler : public ValueObject { ...@@ -546,7 +559,7 @@ class Assembler : public ValueObject {
void nop(Condition cond = AL); void nop(Condition cond = AL);
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32. // Moved to: ARM32::AssemblerARM32::bkpt()
// Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0. // Note that gdb sets breakpoints using the undefined instruction 0xe7f001f0.
void bkpt(uint16_t imm16); void bkpt(uint16_t imm16);
...@@ -677,7 +690,7 @@ class Assembler : public ValueObject { ...@@ -677,7 +690,7 @@ class Assembler : public ValueObject {
void b(Label* label, Condition cond = AL); void b(Label* label, Condition cond = AL);
void bl(Label* label, Condition cond = AL); void bl(Label* label, Condition cond = AL);
#if 0 #if 0
// Moved to: ARM32::AssemblerARM32. // Moved to: ARM32::AssemblerARM32::bx()
void bx(Register rm, Condition cond = AL); void bx(Register rm, Condition cond = AL);
#endif #endif
void blx(Register rm, Condition cond = AL); void blx(Register rm, Condition cond = AL);
...@@ -1097,7 +1110,7 @@ class Assembler : public ValueObject { ...@@ -1097,7 +1110,7 @@ class Assembler : public ValueObject {
Register pp); Register pp);
#if 0 #if 0
// Moved to class AssemblerARM32. // Moved to ARM32::AssemblerARM32::emitType01()
void EmitType01(Condition cond, void EmitType01(Condition cond,
int type, int type,
Opcode opcode, Opcode opcode,
...@@ -1109,11 +1122,14 @@ class Assembler : public ValueObject { ...@@ -1109,11 +1122,14 @@ class Assembler : public ValueObject {
void EmitType5(Condition cond, int32_t offset, bool link); void EmitType5(Condition cond, int32_t offset, bool link);
#if 0
// Moved to ARM32::AssemberARM32::emitMemOp()
void EmitMemOp(Condition cond, void EmitMemOp(Condition cond,
bool load, bool load,
bool byte, bool byte,
Register rd, Register rd,
Address ad); Address ad);
#endif
void EmitMemOpAddressMode3(Condition cond, void EmitMemOpAddressMode3(Condition cond,
int32_t mode, int32_t mode,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "IceAssemblerARM32.h" #include "IceAssemblerARM32.h"
#include "IceUtils.h"
namespace { namespace {
...@@ -39,6 +40,14 @@ static constexpr uint32_t B24 = 1 << 24; ...@@ -39,6 +40,14 @@ static constexpr uint32_t B24 = 1 << 24;
// 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.
static constexpr uint32_t L = 1 << 20; // load (or store)
static constexpr uint32_t W = 1 << 21; // writeback base register (or leave
// unchanged)
static constexpr uint32_t B = 1 << 22; // unsigned byte (or word)
static constexpr uint32_t U = 1 << 23; // positive (or negative) offset/index
static constexpr uint32_t P = 1 << 24; // offset/pre-indexed addressing (or
// post-indexed addressing)
static constexpr uint32_t kConditionShift = 28; static constexpr uint32_t kConditionShift = 28;
static constexpr uint32_t kOpcodeShift = 21; static constexpr uint32_t kOpcodeShift = 21;
static constexpr uint32_t kRdShift = 12; static constexpr uint32_t kRdShift = 12;
...@@ -53,6 +62,9 @@ static constexpr uint32_t kImmed8Shift = 0; ...@@ -53,6 +62,9 @@ static constexpr uint32_t kImmed8Shift = 0;
static constexpr uint32_t kRotateBits = 4; static constexpr uint32_t kRotateBits = 4;
static constexpr uint32_t kRotateShift = 8; static constexpr uint32_t kRotateShift = 8;
static constexpr uint32_t kImmed12Bits = 12;
static constexpr uint32_t kImm12Shift = 0;
inline uint32_t encodeBool(bool b) { return b ? 1 : 0; } inline uint32_t encodeBool(bool b) { return b ? 1 : 0; }
inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) { inline uint32_t encodeGPRRegister(RegARM32::GPRRegister Rn) {
...@@ -75,22 +87,46 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) { ...@@ -75,22 +87,46 @@ inline uint32_t encodeCondition(CondARM32::Cond Cond) {
return static_cast<uint32_t>(Cond); return static_cast<uint32_t>(Cond);
} }
// The way an operand was decoded in function decode below. // Returns the bits in the corresponding masked value.
inline uint32_t mask(uint32_t Value, uint32_t Shift, uint32_t Bits) {
return (Value >> Shift) & ((1 << Bits) - 1);
}
// Extract out a Bit in Value.
inline bool isBitSet(uint32_t Bit, uint32_t Value) {
return (Value & Bit) == Bit;
}
// Returns the GPR register at given Shift in Value.
inline RegARM32::GPRRegister getGPRReg(uint32_t Shift, uint32_t Value) {
return static_cast<RegARM32::GPRRegister>((Value >> Shift) & 0xF);
}
// The way an operand was decoded in functions decodeOperand and decodeAddress
// below.
enum DecodedResult { enum DecodedResult {
CantDecode = 0, // I.e. will fail in test. // Unable to decode, value left undefined.
CantDecode = 0,
// Value is register found.
DecodedAsRegister, DecodedAsRegister,
DecodedAsRotatedImm8 // Value=rrrriiiiiiii where rrrr is the rotation, and iiiiiiii is the imm8
// value.
DecodedAsRotatedImm8,
// i.e. 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 is the offset.
DecodedAsImmRegOffset
}; };
DecodedResult decode(const Operand *Opnd, uint32_t &Value) { DecodedResult decodeOperand(const Operand *Opnd, uint32_t &Value) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
if (Var->hasReg()) { if (Var->hasReg()) {
Value = Var->getRegNum(); Value = Var->getRegNum();
return DecodedAsRegister; return DecodedAsRegister;
} }
} else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { } else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) {
uint32_t Immed8 = FlexImm->getImm(); const uint32_t Immed8 = FlexImm->getImm();
uint32_t Rotate = FlexImm->getRotateAmt(); const uint32_t Rotate = FlexImm->getRotateAmt();
assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))); assert((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)));
Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift); Value = (Rotate << kRotateShift) | (Immed8 << kImmed8Shift);
return DecodedAsRotatedImm8; return DecodedAsRotatedImm8;
...@@ -98,6 +134,34 @@ DecodedResult decode(const Operand *Opnd, uint32_t &Value) { ...@@ -98,6 +134,34 @@ DecodedResult decode(const Operand *Opnd, uint32_t &Value) {
return CantDecode; return CantDecode;
} }
uint32_t decodeImmRegOffset(RegARM32::GPRRegister Reg, int32_t Offset,
OperandARM32Mem::AddrMode Mode) {
uint32_t Value = Mode | (encodeGPRRegister(Reg) << kRnShift);
if (Offset < 0) {
Value = (Value ^ U) | -Offset; // Flip U to adjust sign.
} else {
Value |= Offset;
}
return Value;
}
// Decodes memory address Opnd, and encodes that information into Value,
// based on how ARM represents the address. Returns how the value was encoded.
DecodedResult decodeAddress(const Operand *Opnd, uint32_t &Value) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
// Should be a stack variable, with an offset.
if (Var->hasReg())
return CantDecode;
const int32_t Offset = Var->getStackOffset();
if (!Utils::IsAbsoluteUint(12, Offset))
return CantDecode;
Value = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, Offset,
OperandARM32Mem::Offset);
return DecodedAsImmRegOffset;
}
return CantDecode;
}
} // end of anonymous namespace } // end of anonymous namespace
namespace Ice { namespace Ice {
...@@ -140,10 +204,22 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type, ...@@ -140,10 +204,22 @@ void ARM32::AssemblerARM32::emitType01(CondARM32::Cond Cond, uint32_t Type,
assert(isGPRRegisterDefined(Rd)); assert(isGPRRegisterDefined(Rd));
assert(Cond != CondARM32::kNone); assert(Cond != CondARM32::kNone);
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
uint32_t Encoding = encodeCondition(Cond) << kConditionShift | const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) |
(Type << kTypeShift) | (Opcode << kOpcodeShift) | (Type << kTypeShift) | (Opcode << kOpcodeShift) |
(encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | (encodeBool(SetCc) << kSShift) | (Rn << kRnShift) |
(Rd << kRdShift) | Imm12; (Rd << kRdShift) | Imm12;
emitInst(Encoding);
}
void ARM32::AssemblerARM32::emitMemOp(CondARM32::Cond Cond, uint32_t InstType,
bool IsLoad, bool IsByte, uint32_t Rt,
uint32_t Address) {
assert(isGPRRegisterDefined(Rt));
assert(Cond != CondARM32::kNone);
AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) |
(InstType << kTypeShift) | (IsLoad ? L : 0) |
(IsByte ? B : 0) | (Rt << kRdShift) | Address;
emitInst(Encoding); emitInst(Encoding);
} }
...@@ -153,14 +229,14 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -153,14 +229,14 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
// Note: Loop is used so that we can short circuit using break; // Note: Loop is used so that we can short circuit using break;
do { do {
uint32_t Rd; uint32_t Rd;
if (decode(OpRd, Rd) != DecodedAsRegister) if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
break; break;
uint32_t Rn; uint32_t Rn;
if (decode(OpRn, Rn) != DecodedAsRegister) if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
break; break;
uint32_t Src1Value; uint32_t Src1Value;
// TODO(kschimpf) Other possible decodings of add. // TODO(kschimpf) Other possible decodings of add.
if (decode(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) {
// ADD (Immediate): See ARM section A8.8.5, rule A1. // ADD (Immediate): See ARM section A8.8.5, rule A1.
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value // s=SetFlags and iiiiiiiiiiii=Src1Value
...@@ -168,8 +244,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -168,8 +244,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
(Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags)) (Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
uint32_t Add = B2; // 0100 constexpr uint32_t Add = B2; // 0100
uint32_t InstType = 1; constexpr uint32_t InstType = 1;
emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value); emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value);
return; return;
} }
...@@ -179,8 +255,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -179,8 +255,8 @@ void ARM32::AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
void ARM32::AssemblerARM32::bkpt(uint16_t imm16) { void ARM32::AssemblerARM32::bkpt(uint16_t imm16) {
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 | const uint32_t Encoding = (CondARM32::AL << kConditionShift) | B24 | B21 |
((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf); ((imm16 >> 4) << 8) | B6 | B5 | B4 | (imm16 & 0xf);
emitInst(Encoding); emitInst(Encoding);
} }
...@@ -190,30 +266,62 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) { ...@@ -190,30 +266,62 @@ void ARM32::AssemblerARM32::bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond) {
assert(isGPRRegisterDefined(Rm)); assert(isGPRRegisterDefined(Rm));
assert(isConditionDefined(Cond)); assert(isConditionDefined(Cond));
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 | B21 | const uint32_t Encoding = (encodeCondition(Cond) << kConditionShift) | B24 |
(0xfff << 8) | B4 | (encodeGPRRegister(Rm) << kRmShift); B21 | (0xfff << 8) | B4 |
(encodeGPRRegister(Rm) << kRmShift);
emitInst(Encoding); emitInst(Encoding);
} }
void ARM32::AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break;
do {
uint32_t Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
break;
uint32_t Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
break;
// cccc010pu0w1nnnnttttiiiiiiiiiiii (ARM section A8.8.63, encoding A1; and
// section A8.6.68, encoding A1).
constexpr uint32_t InstType = B1; // 010
constexpr bool IsLoad = true;
const Type Ty = OpRt->getType();
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand?
break;
const bool IsByte = typeWidthInBytes(Ty) == 1;
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) ||
(!IsByte && !isBitSet(P, Address) && isBitSet(W, Address)) ||
((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
!isBitSet(P, Address) &&
isBitSet(U, Address) & !isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)))
break;
emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address);
return;
} while (0);
UnimplementedError(Ctx->getFlags());
}
void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break; // Note: Loop is used so that we can short ciruit using break;
do { do {
uint32_t Rd; uint32_t Rd;
if (decode(OpRd, Rd) != DecodedAsRegister) if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
break; break;
uint32_t Src; uint32_t Src;
// TODO(kschimpf) Handle other forms of mov. // TODO(kschimpf) Handle other forms of mov.
if (decode(OpSrc, Src) == DecodedAsRotatedImm8) { if (decodeOperand(OpSrc, Src) == DecodedAsRotatedImm8) {
// cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1) // cccc0011101s0000ddddiiiiiiiiiiii (ARM section A8.8.102, encoding A1)
// Note: We don't use movs in this assembler. // Note: We don't use movs in this assembler.
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags)) if (!isConditionDefined(Cond) || (Rd == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
uint32_t Rn = 0; constexpr uint32_t Rn = 0;
uint32_t Mov = B3 | B2 | B0; // 1101. constexpr uint32_t Mov = B3 | B2 | B0; // 1101.
uint32_t InstType = 1; constexpr uint32_t InstType = 1;
emitType01(Cond, InstType, Mov, SetFlags, Rn, Rd, Src); emitType01(Cond, InstType, Mov, SetFlags, Rn, Rd, Src);
return; return;
} }
...@@ -221,20 +329,53 @@ void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, ...@@ -221,20 +329,53 @@ void ARM32::AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
UnimplementedError(Ctx->getFlags()); UnimplementedError(Ctx->getFlags());
} }
void ARM32::AssemblerARM32::str(const Operand *OpRt, const Operand *OpAddress,
CondARM32::Cond Cond) {
// Note: Loop is used so that we can short ciruit using break;
do {
uint32_t Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
break;
uint32_t Address;
if (decodeAddress(OpAddress, Address) != DecodedAsImmRegOffset)
break;
// cccc010pub0nnnnttttiiiiiiiiiiii (ARM section A8.8.204, encoding A1; and
// section 18.8.207, encoding A1).
constexpr uint32_t InstType = B1; // 010
constexpr bool IsLoad = false;
const Type Ty = OpRt->getType();
if (!(Ty == IceType_i32 || Ty == IceType_i8)) // TODO(kschimpf) Expand?
break;
const bool IsByte = typeWidthInBytes(Ty) == 1;
// Check for rule violations.
if ((getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_pc) ||
(!isBitSet(P, Address) && isBitSet(W, Address)) ||
(!IsByte &&
(getGPRReg(kRnShift, Address) == RegARM32::Encoded_Reg_sp) &&
isBitSet(P, Address) && !isBitSet(U, Address) &&
isBitSet(W, Address) &&
(mask(Address, kImm12Shift, kImmed12Bits) == 0x8 /* 000000000100 */)))
break;
emitMemOp(Cond, InstType, IsLoad, IsByte, Rt, Address);
return;
} while (0);
UnimplementedError(Ctx->getFlags());
}
void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// Note: Loop is used so that we can short circuit using break; // Note: Loop is used so that we can short circuit using break;
do { do {
uint32_t Rd; uint32_t Rd;
if (decode(OpRd, Rd) != DecodedAsRegister) if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
break; break;
uint32_t Rn; uint32_t Rn;
if (decode(OpRn, Rn) != DecodedAsRegister) if (decodeOperand(OpRn, Rn) != DecodedAsRegister)
break; break;
uint32_t Src1Value; uint32_t Src1Value;
// TODO(kschimpf) Other possible decodings of add. // TODO(kschimpf) Other possible decodings of add.
if (decode(OpSrc1, Src1Value) == DecodedAsRotatedImm8) { if (decodeOperand(OpSrc1, Src1Value) == DecodedAsRotatedImm8) {
// Sub (Immediate): See ARM section A8.8.222, rule A1. // Sub (Immediate): See ARM section A8.8.222, rule A1.
// cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value // s=SetFlags and iiiiiiiiiiii=Src1Value
...@@ -242,8 +383,8 @@ void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, ...@@ -242,8 +383,8 @@ void ARM32::AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
(Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags)) (Rn == RegARM32::Reg_lr) || (Rn == RegARM32::Reg_pc && SetFlags))
// Conditions of rule violated. // Conditions of rule violated.
break; break;
uint32_t Add = B1; // 0010 constexpr uint32_t Add = B1; // 0010
uint32_t InstType = 1; constexpr uint32_t InstType = 1;
emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value); emitType01(Cond, InstType, Add, SetFlags, Rn, Rd, Src1Value);
return; return;
} }
......
...@@ -103,10 +103,14 @@ public: ...@@ -103,10 +103,14 @@ public:
void bkpt(uint16_t Imm16); 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 mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL); void bx(RegARM32::GPRRegister Rm, CondARM32::Cond Cond = CondARM32::AL);
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,
bool SetFlags, CondARM32::Cond Cond); bool SetFlags, CondARM32::Cond Cond);
...@@ -130,6 +134,13 @@ private: ...@@ -130,6 +134,13 @@ private:
// oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM section A5.2.3). // oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM section A5.2.3).
void emitType01(CondARM32::Cond Cond, uint32_t Type, uint32_t Opcode, void emitType01(CondARM32::Cond Cond, uint32_t Type, uint32_t Opcode,
bool SetCc, uint32_t Rn, uint32_t Rd, uint32_t imm12); bool SetCc, uint32_t Rn, uint32_t Rd, uint32_t imm12);
// Pattern ccccoooaabalnnnnttttaaaaaaaaaaaa where cccc=Cond, ooo=InstType,
// l=isLoad, b=isByte, and aaa0a0aaaa0000aaaaaaaaaaaa=Address. Note that
// Address is assumed to be defined by decodeAddress() in
// IceAssemblerARM32.cpp.
void emitMemOp(CondARM32::Cond Cond, uint32_t InstType, bool IsLoad,
bool IsByte, uint32_t Rt, uint32_t Address);
}; };
} // end of namespace ARM32 } // end of namespace ARM32
......
...@@ -617,13 +617,28 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const { ...@@ -617,13 +617,28 @@ void InstARM32Mov::emitIASSingleDestSingleSource(const Cfg *Func) const {
// Note: Loop is used so that we can short circuit using break. // Note: Loop is used so that we can short circuit using break.
do { do {
if (Dest->hasReg()) { if (Dest->hasReg()) {
Type DestTy = Dest->getType(); const Type DestTy = Dest->getType();
const bool DestIsVector = isVectorType(DestTy); const bool DestIsVector = isVectorType(DestTy);
const bool DestIsScalarFP = isScalarFloatingType(DestTy); const bool DestIsScalarFP = isScalarFloatingType(DestTy);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0); const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (DestIsVector || DestIsScalarFP || CoreVFPMove) if (DestIsVector || DestIsScalarFP || CoreVFPMove)
break; break;
Asm->mov(Dest, Src0, getPredicate()); if (isMemoryAccess(Src0)) {
// TODO(kschimpf) Figure out how to do ldr on CoreVPFMove? (see
// emitSingleDestSingleSource, local variable LoadOpcode).
Asm->ldr(Dest, Src0, getPredicate());
} else {
Asm->mov(Dest, Src0, getPredicate());
}
return;
} else {
const Type Src0Type = Src0->getType();
const bool Src0IsVector = isVectorType(Src0Type);
const bool Src0IsScalarFP = isScalarFloatingType(Src0Type);
const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
if (Src0IsVector || Src0IsScalarFP || CoreVFPMove)
break;
Asm->str(Src0, Dest, getPredicate());
return; return;
} }
} while (0); } while (0);
......
; Show that we can handle variable (i.e. stack) spills.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=ASM
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -Om1 \
; RUN: | FileCheck %s --check-prefix=IASM
define internal i32 @add1ToR0(i32 %p) {
%v = add i32 %p, 1
ret i32 %v
}
; ASM-LABEL: add1ToR0:
; IASM-LABEL: add1ToR0:
; ASM: sub sp, sp, #8
; IASM: .byte 0x8
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp, #4]
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r0, [sp, #4]
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add r0, r0, #1
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x80
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: str r0, [sp]
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: ldr r0, [sp]
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe5
; ASM-NEXT: add sp, sp, #8
; IASM-NEXT: .byte 0x8
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: bx lr
; 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