Commit f66a85b2 by Karl Schimpf

Add POP instruction to ARM integrated assembler.

parent 42356fb7
...@@ -549,15 +549,15 @@ void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) { ...@@ -549,15 +549,15 @@ void Assembler::strd(Register rd, Register rn, int32_t offset, Condition cond) {
} }
} }
#if 0
// Folded into ARM32::AssemblerARM32::popList(), since it is its only
// use (and doesn't implement ARM STM instruction).
void Assembler::ldm(BlockAddressMode am, Register base, RegList regs, void Assembler::ldm(BlockAddressMode am, Register base, RegList regs,
Condition cond) { Condition cond) {
ASSERT(regs != 0); ASSERT(regs != 0);
EmitMultiMemOp(cond, am, true, base, regs); EmitMultiMemOp(cond, am, true, base, regs);
} }
#if 0
// Folded into ARM32::AssemblerARM32::pushList(), since it is its only // Folded into ARM32::AssemblerARM32::pushList(), since it is its only
// use (and doesn't implement ARM STM instruction). // use (and doesn't implement ARM STM instruction).
void Assembler::stm(BlockAddressMode am, Register base, RegList regs, void Assembler::stm(BlockAddressMode am, Register base, RegList regs,
...@@ -2568,27 +2568,26 @@ bool Address::CanHoldImmediateOffset( ...@@ -2568,27 +2568,26 @@ bool Address::CanHoldImmediateOffset(
} }
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::push(); // Moved to ARM32::AssemblerARM32::push().
void Assembler::Push(Register rd, Condition cond) { void Assembler::Push(Register rd, Condition cond) {
str(rd, Address(SP, -kWordSize, Address::PreIndex), cond); str(rd, Address(SP, -kWordSize, Address::PreIndex), cond);
} }
#endif
// Moved to ARM32::AssemblerARM32::pop().
void Assembler::Pop(Register rd, Condition cond) { void Assembler::Pop(Register rd, Condition cond) {
ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond); ldr(rd, Address(SP, kWordSize, Address::PostIndex), cond);
} }
#if 0 // Moved to ARM32::AssemblerARM32::pushList().
// Moved to ARM32::AssemblerARM32::pushList();
void Assembler::PushList(RegList regs, Condition cond) { void Assembler::PushList(RegList regs, Condition cond) {
stm(DB_W, SP, regs, cond); stm(DB_W, SP, regs, cond);
} }
#endif
// Moved to ARM32::AssemblerARM32::popList().
void Assembler::PopList(RegList regs, Condition cond) { void Assembler::PopList(RegList regs, Condition cond) {
ldm(IA_W, SP, regs, cond); ldm(IA_W, SP, regs, cond);
} }
#endif
void Assembler::MoveRegister(Register rd, Register rm, Condition cond) { void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
if (rd != rm) { if (rd != rm) {
......
...@@ -576,11 +576,14 @@ class Assembler : public ValueObject { ...@@ -576,11 +576,14 @@ class Assembler : public ValueObject {
void ldrd(Register rd, Register rn, int32_t offset, Condition cond = AL); void ldrd(Register rd, Register rn, int32_t offset, Condition cond = AL);
void strd(Register rd, Register rn, int32_t offset, Condition cond = AL); void strd(Register rd, Register rn, int32_t offset, Condition cond = AL);
#if 0
// Folded into ARM32::AssemblerARM32::popList(), since it is its only use (and
// doesn't implement ARM LDM instructions).
void ldm(BlockAddressMode am, Register base, void ldm(BlockAddressMode am, Register base,
RegList regs, Condition cond = AL); RegList regs, Condition cond = AL);
#if 0
// Folded into ARM32::AssemblerARM32::pushList(), since it is its only // Folded into ARM32::AssemblerARM32::pushList(), since it is its only use
// use (and doesn't implement ARM STM instruction). // (and doesn't implement ARM STM instruction).
void stm(BlockAddressMode am, Register base, void stm(BlockAddressMode am, Register base,
RegList regs, Condition cond = AL); RegList regs, Condition cond = AL);
#endif #endif
...@@ -936,15 +939,16 @@ class Assembler : public ValueObject { ...@@ -936,15 +939,16 @@ class Assembler : public ValueObject {
#if 0 #if 0
// Moved to ARM32::AssemblerARM32::push(). // Moved to ARM32::AssemblerARM32::push().
void Push(Register rd, Condition cond = AL); void Push(Register rd, Condition cond = AL);
#endif
// Moved to ARM32::AssemblerARM32::pop().
void Pop(Register rd, Condition cond = AL); void Pop(Register rd, Condition cond = AL);
#if 0 // Moved to ARM32::AssemblerARM32::pushList().
// Moved to ARM32::AssemblerARM32::pushList();
void PushList(RegList regs, Condition cond = AL); void PushList(RegList regs, Condition cond = AL);
#endif
void PopList(RegList regs, Condition cond = AL);
// Moved to ARM32::AssemblerARM32::popList().
void PopList(RegList regs, Condition cond = AL);
#endif
void MoveRegister(Register rd, Register rm, Condition cond = AL); void MoveRegister(Register rd, Register rm, Condition cond = AL);
// Convenience shift instructions. Use mov instruction with shifter operand // Convenience shift instructions. Use mov instruction with shifter operand
......
...@@ -906,11 +906,38 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, ...@@ -906,11 +906,38 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond);
} }
void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
// POP - ARM section A8.8.132, encoding A2:
// pop<c> {Rt}
//
// cccc010010011101dddd000000000100 where dddd=Rt and cccc=Cond.
IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup();
assert(Rt != RegARM32::Encoded_Reg_sp);
// Same as load instruction.
constexpr bool IsLoad = true;
constexpr bool IsByte = false;
IValueT Address = decodeImmRegOffset(RegARM32::Encoded_Reg_sp, kWordSize,
OperandARM32Mem::PostIndex);
emitMemOp(Cond, kInstTypeMemImmediate, IsLoad, IsByte, Rt, Address);
}
void AssemblerARM32::popList(const IValueT Registers, CondARM32::Cond Cond) {
// POP - ARM section A8.*.131, encoding A1:
// pop<c> <registers>
//
// cccc100010111101rrrrrrrrrrrrrrrr where cccc=Cond and
// rrrrrrrrrrrrrrrr=Registers (one bit for each GP register).
constexpr bool IsLoad = true;
emitMultiMemOp(Cond, IA_W, IsLoad, RegARM32::Encoded_Reg_sp, Registers);
}
void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) { void AssemblerARM32::push(const Operand *OpRt, CondARM32::Cond Cond) {
// PUSH - ARM section A8.8.133, encoding A2: // PUSH - ARM section A8.8.133, encoding A2:
// push<c> {Rt} // push<c> {Rt}
// //
// cccc010100101101dddd000000000100 where dddd=Rd and cccc=Cond. // cccc010100101101dddd000000000100 where dddd=Rt and cccc=Cond.
IValueT Rt; IValueT Rt;
if (decodeOperand(OpRt, Rt) != DecodedAsRegister) if (decodeOperand(OpRt, Rt) != DecodedAsRegister)
return setNeedsTextFixup(); return setNeedsTextFixup();
......
...@@ -189,6 +189,11 @@ public: ...@@ -189,6 +189,11 @@ public:
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);
void pop(const Operand *OpRt, CondARM32::Cond Cond);
// Note: Registers is a bitset, where bit n corresponds to register Rn.
void popList(const IValueT Registers, CondARM32::Cond Cond);
void push(const Operand *OpRt, CondARM32::Cond Cond); void push(const Operand *OpRt, CondARM32::Cond Cond);
// Note: Registers is a bitset, where bit n corresponds to register Rn. // Note: Registers is a bitset, where bit n corresponds to register Rn.
......
...@@ -1116,6 +1116,45 @@ void InstARM32Pop::emit(const Cfg *Func) const { ...@@ -1116,6 +1116,45 @@ void InstARM32Pop::emit(const Cfg *Func) const {
} }
} }
void InstARM32Pop::emitIAS(const Cfg *Func) const {
SizeT IntegerCount = 0;
ARM32::IValueT GPRegisters = 0;
const Variable *LastDest = nullptr;
for (const Variable *Var : Dests) {
if (!isScalarIntegerType(Var->getType()))
// TODO(kschimpf) Implement vpush.
return emitUsingTextFixup(Func);
assert((Var && Var->hasReg()) && "pop only applies to registers");
int32_t Reg = Var->getRegNum();
assert(Reg != RegARM32::Encoded_Not_GPR);
LastDest = Var;
GPRegisters |= (1 << Reg);
++IntegerCount;
}
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
switch (IntegerCount) {
case 0:
return;
case 1:
// Note: Can only apply pop register if single register is not sp.
assert((RegARM32::Encoded_Reg_sp != LastDest->getRegNum()) &&
"Effects of pop register SP is undefined!");
// TODO(kschimpf) ARM sandbox does not allow the single register form of
// pop, and the popList form expects multiple registers. Convert this
// assert to a conditional check once it has been shown that popList
// works.
assert(!Func->getContext()->getFlags().getUseSandboxing() &&
"pop register not in ARM sandbox!");
Asm->pop(LastDest, CondARM32::AL);
break;
default:
Asm->popList(GPRegisters, CondARM32::AL);
break;
}
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Pop::dump(const Cfg *Func) const { void InstARM32Pop::dump(const Cfg *Func) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
...@@ -1197,19 +1236,19 @@ void InstARM32Push::emit(const Cfg *Func) const { ...@@ -1197,19 +1236,19 @@ void InstARM32Push::emit(const Cfg *Func) const {
} }
void InstARM32Push::emitIAS(const Cfg *Func) const { void InstARM32Push::emitIAS(const Cfg *Func) const {
SizeT SrcReg = 0;
SizeT IntegerCount = 0; SizeT IntegerCount = 0;
ARM32::IValueT GPURegisters = 0; ARM32::IValueT GPRegisters = 0;
for (SizeT i = 0; i < getSrcSize(); ++i) { const Variable *LastSrc = nullptr;
if (!isScalarIntegerType(getSrc(i)->getType())) for (SizeT Index = 0; Index < getSrcSize(); ++Index) {
if (!isScalarIntegerType(getSrc(Index)->getType()))
// TODO(kschimpf) Implement vpush. // TODO(kschimpf) Implement vpush.
return emitUsingTextFixup(Func); return emitUsingTextFixup(Func);
auto *Var = llvm::dyn_cast<Variable>(getSrc(i)); const auto *Var = llvm::dyn_cast<Variable>(getSrc(Index));
assert((Var && Var->hasReg()) && "push only applies to registers"); assert((Var && Var->hasReg()) && "push only applies to registers");
ARM32::IValueT Reg = Var->getRegNum(); int32_t Reg = Var->getRegNum();
assert(Reg != static_cast<ARM32::IValueT>(RegARM32::Encoded_Not_GPR)); assert(Reg != RegARM32::Encoded_Not_GPR);
SrcReg = i; LastSrc = Var;
GPURegisters |= (1 << Reg); GPRegisters |= (1 << Reg);
++IntegerCount; ++IntegerCount;
} }
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
...@@ -1217,9 +1256,8 @@ void InstARM32Push::emitIAS(const Cfg *Func) const { ...@@ -1217,9 +1256,8 @@ void InstARM32Push::emitIAS(const Cfg *Func) const {
case 0: case 0:
return; return;
case 1: { case 1: {
if (auto *Var = llvm::dyn_cast<Variable>(getSrc(SrcReg))) {
// Note: Can only apply push register if single register is not sp. // Note: Can only apply push register if single register is not sp.
assert((RegARM32::Encoded_Reg_sp != Var->getRegNum()) && assert((RegARM32::Encoded_Reg_sp != LastSrc->getRegNum()) &&
"Effects of push register SP is undefined!"); "Effects of push register SP is undefined!");
// TODO(kschimpf) ARM sandbox does not allow the single register form of // TODO(kschimpf) ARM sandbox does not allow the single register form of
// push, and the pushList form expects multiple registers. Convert this // push, and the pushList form expects multiple registers. Convert this
...@@ -1227,14 +1265,12 @@ void InstARM32Push::emitIAS(const Cfg *Func) const { ...@@ -1227,14 +1265,12 @@ void InstARM32Push::emitIAS(const Cfg *Func) const {
// works. // works.
assert(!Func->getContext()->getFlags().getUseSandboxing() && assert(!Func->getContext()->getFlags().getUseSandboxing() &&
"push register not in ARM sandbox!"); "push register not in ARM sandbox!");
Asm->push(Var, CondARM32::AL); Asm->push(LastSrc, CondARM32::AL);
break; break;
} }
// Intentionally fall to next case.
}
default: default:
// TODO(kschimpf) Implement pushList in assembler. // TODO(kschimpf) Implement pushList in assembler.
Asm->pushList(GPURegisters, CondARM32::AL); Asm->pushList(GPRegisters, CondARM32::AL);
break; break;
} }
if (Asm->needsTextFixup()) if (Asm->needsTextFixup())
......
...@@ -948,6 +948,7 @@ public: ...@@ -948,6 +948,7 @@ public:
return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests);
} }
void emit(const Cfg *Func) const override; void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override; void dump(const Cfg *Func) const override;
static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); } static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); }
......
...@@ -86,7 +86,12 @@ define internal i32 @AllocBigAlign() { ...@@ -86,7 +86,12 @@ define internal i32 @AllocBigAlign() {
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0xa0 ; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1 ; IASM-NEXT: .byte 0xe1
; IASM: pop {fp}
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe4
; IASM: .byte 0x1e ; IASM: .byte 0x1e
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
; IASM-NEXT: .byte 0x2f ; IASM-NEXT: .byte 0x2f
......
...@@ -61,7 +61,11 @@ define internal void @SinglePushPop() { ...@@ -61,7 +61,11 @@ define internal void @SinglePushPop() {
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; IASM-NEXT: pop {lr}
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x9d
; IASM-NEXT: .byte 0xe4
; IASM: .byte 0x1e ; IASM: .byte 0x1e
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
...@@ -141,7 +145,11 @@ define internal i32 @MultPushPop(i32 %v1, i32 %v2) { ...@@ -141,7 +145,11 @@ define internal i32 @MultPushPop(i32 %v1, i32 %v2) {
; IASM-NEXT: .byte 0xd0 ; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x8d ; IASM-NEXT: .byte 0x8d
; IASM-NEXT: .byte 0xe2 ; IASM-NEXT: .byte 0xe2
; IASM-NEXT: pop {r4, r5, lr}
; IASM-NEXT: .byte 0x30
; IASM-NEXT: .byte 0x40
; IASM-NEXT: .byte 0xbd
; IASM-NEXT: .byte 0xe8
; IASM: .byte 0x1e ; IASM: .byte 0x1e
; IASM-NEXT: .byte 0xff ; IASM-NEXT: .byte 0xff
......
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