Commit 00c30380 by Karl Schimpf

Fix ARM assembler to pop registers in reverse order of pushes.

BUG=None R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1669973002 .
parent 658bae20
...@@ -900,13 +900,23 @@ void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func, ...@@ -900,13 +900,23 @@ void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func,
Str << "}"; Str << "}";
} }
void InstARM32RegisterStackOp::emitSRegsOp(const Cfg *Func, EmitForm Form,
const Variable *BaseReg,
SizeT RegCount,
SizeT InstIndex) const {
if (Form == Emit_Text && BuildDefs::dump() && InstIndex > 0) {
startNextInst(Func);
Func->getContext()->getStrEmit() << "\n";
}
emitSRegs(Func, Form, BaseReg, RegCount);
}
namespace { namespace {
bool isAssignedConsecutiveRegisters(const Variable *Before, bool isAssignedConsecutiveRegisters(const Variable *Before,
const Variable *After) { const Variable *After) {
assert(Before->hasReg()); return RegARM32::getEncodedSReg(Before->getRegNum()) + 1 ==
assert(After->hasReg()); RegARM32::getEncodedSReg(After->getRegNum());
return Before->getRegNum() + 1 == After->getRegNum();
} }
} // end of anonymous namespace } // end of anonymous namespace
...@@ -918,7 +928,7 @@ void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func, ...@@ -918,7 +928,7 @@ void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func,
const auto *Reg = llvm::cast<Variable>(getStackReg(0)); const auto *Reg = llvm::cast<Variable>(getStackReg(0));
if (isScalarIntegerType(Reg->getType())) { if (isScalarIntegerType(Reg->getType())) {
// Pop GPR registers. // Push/pop GPR registers.
SizeT IntegerCount = 0; SizeT IntegerCount = 0;
ARM32::IValueT GPRegisters = 0; ARM32::IValueT GPRegisters = 0;
const Variable *LastDest = nullptr; const Variable *LastDest = nullptr;
...@@ -935,33 +945,45 @@ void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func, ...@@ -935,33 +945,45 @@ void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func,
} else { } else {
emitMultipleGPRs(Func, Form, GPRegisters); emitMultipleGPRs(Func, Form, GPRegisters);
} }
} else { return;
// Pop vector/floating point registers. }
const Variable *BaseReg = nullptr;
SizeT RegCount = 0; // Push/pop floating point registers. Divide into a list of instructions,
for (SizeT i = 0; i < NumRegs; ++i) { // defined on consecutive register ranges. Then generate the corresponding
const Variable *NextReg = getStackReg(i); // instructions.
if (BaseReg == nullptr) {
BaseReg = NextReg; // Typical max number of registers ranges pushed/popd is no more than 5.
RegCount = 1; llvm::SmallVector<std::pair<const Variable *, SizeT>, 5> InstData;
} else if (RegCount < VpushVpopMaxConsecRegs && const Variable *BaseReg = nullptr;
isAssignedConsecutiveRegisters(Reg, NextReg)) { SizeT RegCount = 0;
++RegCount; for (SizeT i = 0; i < NumRegs; ++i) {
} else { const Variable *NextReg = getStackReg(i);
emitSRegs(Func, Form, BaseReg, RegCount); assert(NextReg->hasReg());
if (Form == Emit_Text && BuildDefs::dump()) { if (BaseReg == nullptr) {
startNextInst(Func); BaseReg = NextReg;
Func->getContext()->getStrEmit() << "\n"; RegCount = 1;
} } else if (RegCount < VpushVpopMaxConsecRegs &&
BaseReg = NextReg; isAssignedConsecutiveRegisters(Reg, NextReg)) {
RegCount = 1; ++RegCount;
} } else {
Reg = NextReg; InstData.emplace_back(BaseReg, RegCount);
} BaseReg = NextReg;
if (RegCount) { RegCount = 1;
emitSRegs(Func, Form, BaseReg, RegCount);
} }
Reg = NextReg;
}
if (RegCount) {
InstData.emplace_back(BaseReg, RegCount);
}
SizeT InstCount = 0;
if (llvm::isa<InstARM32Push>(*this)) {
for (const auto &Pair : InstData)
emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++);
return;
} }
assert(llvm::isa<InstARM32Pop>(*this));
for (const auto &Pair : reverse_range(InstData))
emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++);
} }
InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests)
......
...@@ -1094,6 +1094,8 @@ protected: ...@@ -1094,6 +1094,8 @@ protected:
void emitGPRsAsText(const Cfg *Func) const; void emitGPRsAsText(const Cfg *Func) const;
void emitSRegsAsText(const Cfg *Func, const Variable *BaseReg, void emitSRegsAsText(const Cfg *Func, const Variable *BaseReg,
SizeT Regcount) const; SizeT Regcount) const;
void emitSRegsOp(const Cfg *Func, const EmitForm, const Variable *BaseReg,
SizeT RegCount, SizeT InstIndex) const;
virtual const char *getDumpOpcode() const { return getGPROpcode(); } virtual const char *getDumpOpcode() const { return getGPROpcode(); }
virtual const char *getGPROpcode() const = 0; virtual const char *getGPROpcode() const = 0;
virtual const char *getSRegOpcode() const = 0; virtual const char *getSRegOpcode() const = 0;
...@@ -1109,7 +1111,7 @@ protected: ...@@ -1109,7 +1111,7 @@ protected:
/// Pops a list of registers. It may be a list of GPRs, or a list of VFP "s" /// Pops a list of registers. It may be a list of GPRs, or a list of VFP "s"
/// regs, but not both. In any case, the list must be sorted. /// regs, but not both. In any case, the list must be sorted.
class InstARM32Pop : public InstARM32RegisterStackOp { class InstARM32Pop final : public InstARM32RegisterStackOp {
InstARM32Pop() = delete; InstARM32Pop() = delete;
InstARM32Pop(const InstARM32Pop &) = delete; InstARM32Pop(const InstARM32Pop &) = delete;
InstARM32Pop &operator=(const InstARM32Pop &) = delete; InstARM32Pop &operator=(const InstARM32Pop &) = delete;
...@@ -1132,13 +1134,12 @@ private: ...@@ -1132,13 +1134,12 @@ private:
IValueT Registers) const final; IValueT Registers) const final;
void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg, void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg,
SizeT RegCount) const final; SizeT RegCount) const final;
VarList Dests; VarList Dests;
}; };
/// Pushes a list of registers. Just like Pop (see above), the list may be of /// Pushes a list of registers. Just like Pop (see above), the list may be of
/// GPRs, or VFP "s" registers, but not both. /// GPRs, or VFP "s" registers, but not both.
class InstARM32Push : public InstARM32RegisterStackOp { class InstARM32Push final : public InstARM32RegisterStackOp {
InstARM32Push() = delete; InstARM32Push() = delete;
InstARM32Push(const InstARM32Push &) = delete; InstARM32Push(const InstARM32Push &) = delete;
InstARM32Push &operator=(const InstARM32Push &) = delete; InstARM32Push &operator=(const InstARM32Push &) = delete;
......
; Show that pops are generated in reverse order of pushes.
; NOTE: Restricts to nonconsecutive S registers to force the generation of
; multiple vpush/vpop instructions. Also tests that we generate them in the
; right order (the reverse of the corresponding push). Uses -O2 to keep all
; results in S registers.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 -allow-extern \
; RUN: -reg-use s20,s22,s23 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 -allow-extern \
; RUN: -reg-use s20,s22,s23 \
; RUN: | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 -allow-extern \
; RUN: -reg-use s20,s22,s23 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 -allow-extern \
; RUN: -reg-use s20,s22,s23 \
; RUN: | FileCheck %s --check-prefix=DIS
declare external void @f()
define internal float @test2SPops(float %p1, float %p2) {
; ASM-LABEL: test2SPops:
; DIS-LABEL: 00000000 <test2SPops>:
; IASM-LABEL: test2SPops:
; ASM: vpush {s20}
; ASM-NEXT: vpush {s22, s23}
; ASM-NEXT: push {lr}
; DIS: 0: ed2daa01
; DIS-NEXT: 4: ed2dba02
; DIS-NEXT: 8: e52de004
; IASM-NOT: vpush
; IASM-NOT: push
%v1 = fadd float %p1, %p2
%v2 = fsub float %p1, %p2
%v3 = fsub float %p2, %p1
call void @f()
%v4 = fadd float %v1, %v2
%res = fadd float %v3, %v4
; ASM: pop {lr}
; ASM-NEXT: # lr = def.pseudo
; ASM-NEXT: vpop {s22, s23}
; ASM-NEXT: vpop {s20}
; DIS: 40: e49de004
; DIS-NEXT: 44: ecbdba02
; DIS-NEXT: 48: ecbdaa01
; IASM-NOT: pop
; IASM-NOT: vpop
ret float %res
}
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