Add POP instruction to ARM integrated assembler.
BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334
R=jpp@chromium.org, stichnot@chromium.org
Review URL: https://codereview.chromium.org/1433743002 .
diff --git a/src/DartARM32/assembler_arm.cc b/src/DartARM32/assembler_arm.cc
index 576ca76..44ce658 100644
--- a/src/DartARM32/assembler_arm.cc
+++ b/src/DartARM32/assembler_arm.cc
@@ -549,15 +549,15 @@
}
}
-
+#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 @@
}
#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) {
diff --git a/src/DartARM32/assembler_arm.h b/src/DartARM32/assembler_arm.h
index 63a1ef8..dbc1873 100644
--- a/src/DartARM32/assembler_arm.h
+++ b/src/DartARM32/assembler_arm.h
@@ -576,11 +576,14 @@
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 @@
#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
diff --git a/src/IceAssemblerARM32.cpp b/src/IceAssemblerARM32.cpp
index d849c54..0fdddfb 100644
--- a/src/IceAssemblerARM32.cpp
+++ b/src/IceAssemblerARM32.cpp
@@ -906,11 +906,38 @@
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();
diff --git a/src/IceAssemblerARM32.h b/src/IceAssemblerARM32.h
index a7f8c20..96e800b 100644
--- a/src/IceAssemblerARM32.h
+++ b/src/IceAssemblerARM32.h
@@ -189,6 +189,11 @@
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.
diff --git a/src/IceInstARM32.cpp b/src/IceInstARM32.cpp
index 7312d84..1edaa17 100644
--- a/src/IceInstARM32.cpp
+++ b/src/IceInstARM32.cpp
@@ -1116,6 +1116,45 @@
}
}
+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::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 @@
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())
diff --git a/src/IceInstARM32.h b/src/IceInstARM32.h
index 6d28208..e1199ee 100644
--- a/src/IceInstARM32.h
+++ b/src/IceInstARM32.h
@@ -948,6 +948,7 @@
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); }
diff --git a/tests_lit/assembler/arm32/bic.ll b/tests_lit/assembler/arm32/bic.ll
index 3115d06..7943a66 100644
--- a/tests_lit/assembler/arm32/bic.ll
+++ b/tests_lit/assembler/arm32/bic.ll
@@ -86,7 +86,12 @@
; 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
diff --git a/tests_lit/assembler/arm32/push-pop.ll b/tests_lit/assembler/arm32/push-pop.ll
index 5bda8c7..c0238f9 100644
--- a/tests_lit/assembler/arm32/push-pop.ll
+++ b/tests_lit/assembler/arm32/push-pop.ll
@@ -61,7 +61,11 @@
; 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 @@
; 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