Commit c411dbf1 by Karl Schimpf

Refactor PUSH/POP in ARM assemblers.

Refactors methods emit() and emitIAS() of InstARM32Push and InstARM32Pop to separate out the selection of assembler instructions from instruction emission, using template methods. Template method assemble() provides a single implementation for emit() and emitIAS(). This method calls template functions in the assembler to generate textual and binary forms of the instruction. BUG= None R=jpp@chromium.org, stichnot@chromium.org Review URL: https://codereview.chromium.org/1535233002 .
parent d8777b0d
...@@ -192,7 +192,7 @@ IValueT getEncodedGPRegNum(const Variable *Var) { ...@@ -192,7 +192,7 @@ IValueT getEncodedGPRegNum(const Variable *Var) {
assert(Var->hasReg()); assert(Var->hasReg());
int32_t Reg = Var->getRegNum(); int32_t Reg = Var->getRegNum();
return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg) return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
: RegARM32::getEncodedGPReg(Reg); : RegARM32::getEncodedGPR(Reg);
} }
IValueT getEncodedSRegNum(const Variable *Var) { IValueT getEncodedSRegNum(const Variable *Var) {
...@@ -1728,7 +1728,7 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, ...@@ -1728,7 +1728,7 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
OrrName); OrrName);
} }
void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { void AssemblerARM32::pop(const Variable *OpRt, CondARM32::Cond Cond) {
// POP - ARM section A8.8.132, encoding A2: // POP - ARM section A8.8.132, encoding A2:
// pop<c> {Rt} // pop<c> {Rt}
// //
......
...@@ -38,12 +38,6 @@ ...@@ -38,12 +38,6 @@
namespace Ice { namespace Ice {
namespace ARM32 { namespace ARM32 {
/// Encoding of an ARM 32-bit instruction.
using IValueT = uint32_t;
/// An Offset value (+/-) used in an ARM 32-bit instruction.
using IOffsetT = int32_t;
/// Handles encoding of bottom/top 16 bits of an address using movw/movt. /// Handles encoding of bottom/top 16 bits of an address using movw/movt.
class MoveRelocatableFixup final : public AssemblerFixup { class MoveRelocatableFixup final : public AssemblerFixup {
MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete; MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete;
...@@ -255,7 +249,7 @@ public: ...@@ -255,7 +249,7 @@ 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); void pop(const Variable *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.
void popList(const IValueT Registers, CondARM32::Cond Cond); void popList(const IValueT Registers, CondARM32::Cond Cond);
......
...@@ -705,8 +705,129 @@ void validatePushOrPopRegisterListOrDie(const VarList &RegList) { ...@@ -705,8 +705,129 @@ void validatePushOrPopRegisterListOrDie(const VarList &RegList) {
} }
} // end of anonymous namespace } // end of anonymous namespace
void InstARM32RegisterStackOp::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
emitUsingForm(Func, Emit_Text);
}
void InstARM32RegisterStackOp::emitIAS(const Cfg *Func) const {
emitUsingForm(Func, Emit_Binary);
assert(!Func->getAssembler<ARM32::AssemblerARM32>()->needsTextFixup());
}
void InstARM32RegisterStackOp::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << getDumpOpcode() << " ";
SizeT NumRegs = getNumStackRegs();
for (SizeT I = 0; I < NumRegs; ++I) {
if (I > 0)
Str << ", ";
getStackReg(I)->dump(Func);
}
}
void InstARM32RegisterStackOp::emitGPRsAsText(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << getGPROpcode() << "\t{";
getStackReg(0)->emit(Func);
const SizeT NumRegs = getNumStackRegs();
for (SizeT i = 1; i < NumRegs; ++i) {
Str << ", ";
getStackReg(i)->emit(Func);
}
Str << "}";
}
void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func,
const Variable *BaseReg,
SizeT RegCount) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << getSRegOpcode() << "\t{";
bool IsFirst = true;
int32_t Base = BaseReg->getRegNum();
for (SizeT i = 0; i < RegCount; ++i) {
if (IsFirst)
IsFirst = false;
else
Str << ", ";
Str << RegARM32::getSRegName(Base + i);
}
Str << "}";
}
namespace {
bool isAssignedConsecutiveRegisters(const Variable *Before,
const Variable *After) {
assert(Before->hasReg());
assert(After->hasReg());
return Before->getRegNum() + 1 == After->getRegNum();
}
} // end of anonymous namespace
void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func,
const EmitForm Form) const {
SizeT NumRegs = getNumStackRegs();
assert(NumRegs);
const auto *Reg = llvm::cast<Variable>(getStackReg(0));
if (isScalarIntegerType(Reg->getType())) {
// Pop GPR registers.
SizeT IntegerCount = 0;
ARM32::IValueT GPRegisters = 0;
const Variable *LastDest = nullptr;
for (SizeT i = 0; i < NumRegs; ++i) {
const Variable *Var = getStackReg(i);
assert(Var->hasReg() && "stack op only applies to registers");
int32_t Reg = RegARM32::getEncodedGPR(Var->getRegNum());
LastDest = Var;
GPRegisters |= (1 << Reg);
++IntegerCount;
}
if (IntegerCount == 1) {
emitSingleGPR(Func, Form, LastDest);
} else {
emitMultipleGPRs(Func, Form, GPRegisters);
}
} else {
// Pop vector/floating point registers.
const Variable *BaseReg = nullptr;
SizeT RegCount = 0;
for (SizeT i = 0; i < NumRegs; ++i) {
const Variable *NextReg = getStackReg(i);
if (BaseReg == nullptr) {
BaseReg = NextReg;
RegCount = 1;
} else if (RegCount < VpushVpopMaxConsecRegs &&
isAssignedConsecutiveRegisters(Reg, NextReg)) {
++RegCount;
} else {
emitSRegs(Func, Form, BaseReg, RegCount);
if (Form == Emit_Text && BuildDefs::dump()) {
startNextInst(Func);
Func->getContext()->getStrEmit() << "\n";
}
BaseReg = NextReg;
RegCount = 1;
}
Reg = NextReg;
}
if (RegCount) {
emitSRegs(Func, Form, BaseReg, RegCount);
}
}
}
InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests)
: InstARM32(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) { : InstARM32RegisterStackOp(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) {
// Track modifications to Dests separately via FakeDefs. Also, a pop // Track modifications to Dests separately via FakeDefs. Also, a pop
// instruction affects the stack pointer and so it should not be allowed to // instruction affects the stack pointer and so it should not be allowed to
// be automatically dead-code eliminated. This is automatic since we leave // be automatically dead-code eliminated. This is automatic since we leave
...@@ -715,7 +836,7 @@ InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests) ...@@ -715,7 +836,7 @@ InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests)
} }
InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs) InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs)
: InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) { : InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) {
validatePushOrPopRegisterListOrDie(Srcs); validatePushOrPopRegisterListOrDie(Srcs);
for (Variable *Source : Srcs) { for (Variable *Source : Srcs) {
addSource(Source); addSource(Source);
...@@ -1390,278 +1511,98 @@ template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const { ...@@ -1390,278 +1511,98 @@ template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
namespace { const char *InstARM32Pop::getGPROpcode() const { return "pop"; }
bool isAssignedConsecutiveRegisters(const Variable *Before, const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; }
const Variable *After) {
assert(Before->hasReg());
assert(After->hasReg());
return Before->getRegNum() + 1 == After->getRegNum();
}
} // end of anonymous namespace Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; }
void InstARM32Pop::emit(const Cfg *Func) const { SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); }
if (!BuildDefs::dump())
return;
const SizeT DestSize = Dests.size(); void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form,
if (DestSize == 0) { const Variable *Reg) const {
assert(false && "Empty pop list"); switch (Form) {
case Emit_Text:
emitGPRsAsText(Func);
return; return;
} case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL);
Ostream &Str = Func->getContext()->getStrEmit();
Variable *Reg = Dests[0];
if (isScalarIntegerType(Reg->getType())) {
// GPR push.
Str << "\t"
"pop"
"\t{";
Reg->emit(Func);
for (SizeT i = 1; i < DestSize; ++i) {
Str << ", ";
Reg = Dests[i];
Reg->emit(Func);
}
Str << "}";
return; return;
} }
// VFP "s" reg push.
SizeT End = DestSize - 1;
SizeT Start = DestSize - 1;
Reg = Dests[DestSize - 1];
Str << "\t"
"vpop"
"\t{";
for (SizeT i = 2; i <= DestSize; ++i) {
Variable *PreviousReg = Dests[DestSize - i];
if (!isAssignedConsecutiveRegisters(PreviousReg, Reg)) {
Dests[Start]->emit(Func);
for (SizeT j = Start + 1; j <= End; ++j) {
Str << ", ";
Dests[j]->emit(Func);
}
startNextInst(Func);
Str << "}\n\t"
"vpop"
"\t{";
End = DestSize - i;
}
Reg = PreviousReg;
Start = DestSize - i;
}
Dests[Start]->emit(Func);
for (SizeT j = Start + 1; j <= End; ++j) {
Str << ", ";
Dests[j]->emit(Func);
}
Str << "}";
} }
void InstARM32Pop::emitIAS(const Cfg *Func) const { void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
// Pop can't be emitted if there are no registers to load. This should never IValueT Registers) const {
// happen, but if it does, we don't need to bring Subzero down -- we just skip switch (Form) {
// emitting the pop instruction (and maybe emit a nop?) The assert() is here case Emit_Text:
// so that we can detect this error during development. emitGPRsAsText(Func);
const SizeT DestSize = Dests.size();
if (DestSize == 0) {
assert(false && "Empty pop list");
return; return;
} case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers,
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); CondARM32::AL);
const auto *Reg = llvm::cast<Variable>(Dests[0]);
if (isScalarIntegerType(Reg->getType())) {
// Pop GPR registers.
SizeT IntegerCount = 0;
ARM32::IValueT GPRegisters = 0;
const Variable *LastDest = nullptr;
for (const Variable *Var : Dests) {
assert(Var->hasReg() && "pop only applies to registers");
int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
LastDest = Var;
GPRegisters |= (1 << Reg);
++IntegerCount;
}
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!");
Asm->pop(LastDest, CondARM32::AL);
break;
default:
Asm->popList(GPRegisters, CondARM32::AL);
break;
}
} else {
// Pop vector/floating point registers.
const Variable *BaseReg = nullptr;
SizeT RegCount = 0;
for (const Variable *NextReg : Dests) {
if (BaseReg == nullptr) {
BaseReg = NextReg;
RegCount = 1;
} else if (RegCount < VpushVpopMaxConsecRegs &&
isAssignedConsecutiveRegisters(Reg, NextReg)) {
++RegCount;
} else {
Asm->vpop(BaseReg, RegCount, CondARM32::AL);
BaseReg = NextReg;
RegCount = 1;
}
Reg = NextReg;
}
if (RegCount)
Asm->vpop(BaseReg, RegCount, CondARM32::AL);
}
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Pop::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
return; return;
Ostream &Str = Func->getContext()->getStrDump();
Str << "pop"
<< " ";
for (SizeT I = 0; I < Dests.size(); ++I) {
if (I > 0)
Str << ", ";
Dests[I]->dump(Func);
} }
} }
void InstARM32Push::emit(const Cfg *Func) const { void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form,
if (!BuildDefs::dump()) const Variable *BaseReg, SizeT RegCount) const {
switch (Form) {
case Emit_Text:
emitSRegsAsText(Func, BaseReg, RegCount);
return; return;
case Emit_Binary:
// Push can't be emitted if there are no registers to save. This should never Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount,
// happen, but if it does, we don't need to bring Subzero down -- we just skip CondARM32::AL);
// emitting the push instruction (and maybe emit a nop?) The assert() is here
// so that we can detect this error during development.
const SizeT SrcSize = getSrcSize();
if (SrcSize == 0) {
assert(false && "Empty push list");
return; return;
} }
}
Ostream &Str = Func->getContext()->getStrEmit(); const char *InstARM32Push::getGPROpcode() const { return "push"; }
const auto *Reg = llvm::cast<Variable>(getSrc(0)); const char *InstARM32Push::getSRegOpcode() const { return "vpush"; }
if (isScalarIntegerType(Reg->getType())) {
// GPR push.
Str << "\t"
"push"
"\t{";
Reg->emit(Func);
for (SizeT i = 1; i < SrcSize; ++i) {
Str << ", ";
getSrc(i)->emit(Func);
}
Str << "}";
return;
}
// VFP "s" reg push. Variable *InstARM32Push::getStackReg(SizeT Index) const {
Str << "\t" return llvm::cast<Variable>(getSrc(Index));
"vpush"
"\t{";
Reg->emit(Func);
SizeT RegCount = 1;
for (SizeT i = 1; i < SrcSize; ++i) {
const auto *NextReg = llvm::cast<Variable>(getSrc(i));
if (RegCount < VpushVpopMaxConsecRegs &&
isAssignedConsecutiveRegisters(Reg, NextReg)) {
++RegCount;
Str << ", ";
} else {
startNextInst(Func);
RegCount = 1;
Str << "}\n\t"
"vpush"
"\t{";
}
Reg = NextReg;
Reg->emit(Func);
}
Str << "}";
} }
void InstARM32Push::emitIAS(const Cfg *Func) const { SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); }
// Push can't be emitted if there are no registers to save. This should never
// happen, but if it does, we don't need to bring Subzero down -- we just skip void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form,
// emitting the push instruction (and maybe emit a nop?) The assert() is here const Variable *Reg) const {
// so that we can detect this error during development. switch (Form) {
const SizeT SrcSize = getSrcSize(); case Emit_Text:
if (SrcSize == 0) { emitGPRsAsText(Func);
assert(false && "Empty push list"); return;
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL);
return; return;
} }
}
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
const auto *Reg = llvm::cast<Variable>(getSrc(0)); IValueT Registers) const {
if (isScalarIntegerType(Reg->getType())) { switch (Form) {
// Push GPR registers. case Emit_Text:
SizeT IntegerCount = 0; emitGPRsAsText(Func);
ARM32::IValueT GPRegisters = 0; return;
const Variable *LastSrc = nullptr; case Emit_Binary:
for (SizeT Index = 0; Index < getSrcSize(); ++Index) { Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers,
const auto *Var = llvm::cast<Variable>(getSrc(Index)); CondARM32::AL);
int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum()); return;
assert(Reg != RegARM32::Encoded_Not_GPR);
LastSrc = Var;
GPRegisters |= (1 << Reg);
++IntegerCount;
}
switch (IntegerCount) {
case 0:
return;
case 1: {
// 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!");
Asm->push(LastSrc, CondARM32::AL);
break;
}
default:
Asm->pushList(GPRegisters, CondARM32::AL);
break;
}
} else {
// Push vector/Floating point registers.
const Variable *BaseReg = Reg;
SizeT RegCount = 1;
for (SizeT i = 1; i < SrcSize; ++i) {
const auto *NextReg = llvm::cast<Variable>(getSrc(i));
if (RegCount < VpushVpopMaxConsecRegs &&
isAssignedConsecutiveRegisters(Reg, NextReg)) {
++RegCount;
} else {
Asm->vpush(BaseReg, RegCount, CondARM32::AL);
BaseReg = NextReg;
RegCount = 1;
}
Reg = NextReg;
}
Asm->vpush(BaseReg, RegCount, CondARM32::AL);
} }
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
} }
void InstARM32Push::dump(const Cfg *Func) const { void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form,
if (!BuildDefs::dump()) const Variable *BaseReg, SizeT RegCount) const {
switch (Form) {
case Emit_Text:
emitSRegsAsText(Func, BaseReg, RegCount);
return; return;
Ostream &Str = Func->getContext()->getStrDump(); case Emit_Binary:
Str << "push" Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount,
<< " "; CondARM32::AL);
dumpSources(Func); return;
}
} }
void InstARM32Ret::emit(const Cfg *Func) const { void InstARM32Ret::emit(const Cfg *Func) const {
......
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
namespace Ice { namespace Ice {
namespace ARM32 { namespace ARM32 {
/// Encoding of an ARM 32-bit instruction.
using IValueT = uint32_t;
/// An Offset value (+/-) used in an ARM 32-bit instruction.
using IOffsetT = int32_t;
class TargetARM32; class TargetARM32;
/// OperandARM32 extends the Operand hierarchy. Its subclasses are /// OperandARM32 extends the Operand hierarchy. Its subclasses are
...@@ -364,6 +370,9 @@ class InstARM32 : public InstTarget { ...@@ -364,6 +370,9 @@ class InstARM32 : public InstTarget {
InstARM32 &operator=(const InstARM32 &) = delete; InstARM32 &operator=(const InstARM32 &) = delete;
public: public:
// Defines form that assembly instruction should be synthesized.
enum EmitForm { Emit_Text, Emit_Binary };
enum InstKindARM32 { enum InstKindARM32 {
k__Start = Inst::Target, k__Start = Inst::Target,
Adc, Adc,
...@@ -1056,9 +1065,41 @@ private: ...@@ -1056,9 +1065,41 @@ private:
InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget); InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
}; };
class InstARM32RegisterStackOp : public InstARM32 {
InstARM32RegisterStackOp() = delete;
InstARM32RegisterStackOp(const InstARM32RegisterStackOp &) = delete;
InstARM32RegisterStackOp &
operator=(const InstARM32RegisterStackOp &) = delete;
public:
void emit(const Cfg *Func) const override;
void emitIAS(const Cfg *Func) const override;
void dump(const Cfg *Func) const override;
protected:
InstARM32RegisterStackOp(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs,
Variable *Dest)
: InstARM32(Func, Kind, Maxsrcs, Dest) {}
void emitUsingForm(const Cfg *Func, const EmitForm Form) const;
void emitGPRsAsText(const Cfg *Func) const;
void emitSRegsAsText(const Cfg *Func, const Variable *BaseReg,
SizeT Regcount) const;
virtual const char *getDumpOpcode() const { return getGPROpcode(); }
virtual const char *getGPROpcode() const = 0;
virtual const char *getSRegOpcode() const = 0;
virtual Variable *getStackReg(SizeT Index) const = 0;
virtual SizeT getNumStackRegs() const = 0;
virtual void emitSingleGPR(const Cfg *Func, const EmitForm Form,
const Variable *Reg) const = 0;
virtual void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
IValueT Registers) const = 0;
virtual void emitSRegs(const Cfg *Func, const EmitForm Form,
const Variable *BaseReg, SizeT RegCount) const = 0;
};
/// 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 InstARM32 { class InstARM32Pop : public InstARM32RegisterStackOp {
InstARM32Pop() = delete; InstARM32Pop() = delete;
InstARM32Pop(const InstARM32Pop &) = delete; InstARM32Pop(const InstARM32Pop &) = delete;
InstARM32Pop &operator=(const InstARM32Pop &) = delete; InstARM32Pop &operator=(const InstARM32Pop &) = delete;
...@@ -1067,20 +1108,27 @@ public: ...@@ -1067,20 +1108,27 @@ public:
static InstARM32Pop *create(Cfg *Func, const VarList &Dests) { static InstARM32Pop *create(Cfg *Func, const VarList &Dests) {
return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests); 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); } static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); }
private: private:
InstARM32Pop(Cfg *Func, const VarList &Dests); InstARM32Pop(Cfg *Func, const VarList &Dests);
virtual const char *getGPROpcode() const final;
virtual const char *getSRegOpcode() const final;
Variable *getStackReg(SizeT Index) const final;
SizeT getNumStackRegs() const final;
void emitSingleGPR(const Cfg *Func, const EmitForm Form,
const Variable *Reg) const final;
void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
IValueT Registers) const final;
void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg,
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 InstARM32 { class InstARM32Push : public InstARM32RegisterStackOp {
InstARM32Push() = delete; InstARM32Push() = delete;
InstARM32Push(const InstARM32Push &) = delete; InstARM32Push(const InstARM32Push &) = delete;
InstARM32Push &operator=(const InstARM32Push &) = delete; InstARM32Push &operator=(const InstARM32Push &) = delete;
...@@ -1089,13 +1137,20 @@ public: ...@@ -1089,13 +1137,20 @@ public:
static InstARM32Push *create(Cfg *Func, const VarList &Srcs) { static InstARM32Push *create(Cfg *Func, const VarList &Srcs) {
return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs); return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs);
} }
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, Push); } static bool classof(const Inst *Inst) { return isClassof(Inst, Push); }
private: private:
InstARM32Push(Cfg *Func, const VarList &Srcs); InstARM32Push(Cfg *Func, const VarList &Srcs);
const char *getGPROpcode() const final;
const char *getSRegOpcode() const final;
Variable *getStackReg(SizeT Index) const final;
SizeT getNumStackRegs() const final;
void emitSingleGPR(const Cfg *Func, const EmitForm Form,
const Variable *Reg) const final;
void emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
IValueT Registers) const final;
void emitSRegs(const Cfg *Func, const EmitForm Form, const Variable *BaseReg,
SizeT RegCount) const final;
}; };
/// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr" /// Ret pseudo-instruction. This is actually a "bx" instruction with an "lr"
......
...@@ -157,7 +157,7 @@ public: ...@@ -157,7 +157,7 @@ public:
return Table[RegNum].IsGPR; return Table[RegNum].IsGPR;
} }
static constexpr inline SizeT getNumGPRegs() { static constexpr SizeT getNumGPRegs() {
return 0 return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \ #define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \ isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
...@@ -167,11 +167,31 @@ public: ...@@ -167,11 +167,31 @@ public:
; ;
} }
static inline GPRRegister getEncodedGPReg(int32_t RegNum) { static inline GPRRegister getEncodedGPR(int32_t RegNum) {
assert(isGPRegister(RegNum)); assert(isGPRegister(RegNum));
return GPRRegister(Table[RegNum].Encoding); return GPRRegister(Table[RegNum].Encoding);
} }
static constexpr SizeT getNumGPRs() {
return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
+(isGPR)
REGARM32_TABLE
#undef X
;
}
static inline bool isGPR(SizeT RegNum) {
assertRegisterDefined(RegNum);
return Table[RegNum].IsGPR;
}
static inline IceString getGPRName(SizeT RegNum) {
assert(isGPR(RegNum));
return Table[RegNum].Name;
}
static inline GPRRegister getI64PairFirstGPRNum(int32_t RegNum) { static inline GPRRegister getI64PairFirstGPRNum(int32_t RegNum) {
assert(isI64RegisterPair(RegNum)); assert(isI64RegisterPair(RegNum));
return GPRRegister(Table[RegNum].Encoding); return GPRRegister(Table[RegNum].Encoding);
...@@ -192,7 +212,7 @@ public: ...@@ -192,7 +212,7 @@ public:
return Table[RegNum].IsFP32; return Table[RegNum].IsFP32;
} }
static constexpr inline SizeT getNumSRegs() { static constexpr SizeT getNumSRegs() {
return 0 return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \ #define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \ isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
...@@ -202,6 +222,11 @@ public: ...@@ -202,6 +222,11 @@ public:
; ;
} }
static inline IceString getSRegName(SizeT RegNum) {
assert(isEncodedSReg(RegNum));
return Table[RegNum].Name;
}
static inline SRegister getEncodedSReg(int32_t RegNum) { static inline SRegister getEncodedSReg(int32_t RegNum) {
assert(isEncodedSReg(RegNum)); assert(isEncodedSReg(RegNum));
return SRegister(Table[RegNum].Encoding); return SRegister(Table[RegNum].Encoding);
......
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