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