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) {
assert(Var->hasReg());
int32_t Reg = Var->getRegNum();
return llvm::isa<Variable64On32>(Var) ? RegARM32::getI64PairFirstGPRNum(Reg)
: RegARM32::getEncodedGPReg(Reg);
: RegARM32::getEncodedGPR(Reg);
}
IValueT getEncodedSRegNum(const Variable *Var) {
......@@ -1728,7 +1728,7 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
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<c> {Rt}
//
......
......@@ -38,12 +38,6 @@
namespace Ice {
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.
class MoveRelocatableFixup final : public AssemblerFixup {
MoveRelocatableFixup &operator=(const MoveRelocatableFixup &) = delete;
......@@ -255,7 +249,7 @@ 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);
void pop(const Variable *OpRt, CondARM32::Cond Cond);
// Note: Registers is a bitset, where bit n corresponds to register Rn.
void popList(const IValueT Registers, CondARM32::Cond Cond);
......
......@@ -705,8 +705,129 @@ void validatePushOrPopRegisterListOrDie(const VarList &RegList) {
}
} // 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)
: 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
// instruction affects the stack pointer and so it should not be allowed to
// be automatically dead-code eliminated. This is automatic since we leave
......@@ -715,7 +836,7 @@ InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests)
}
InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs)
: InstARM32(Func, InstARM32::Push, Srcs.size(), nullptr) {
: InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) {
validatePushOrPopRegisterListOrDie(Srcs);
for (Variable *Source : Srcs) {
addSource(Source);
......@@ -1390,278 +1511,98 @@ template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func);
}
namespace {
const char *InstARM32Pop::getGPROpcode() const { return "pop"; }
bool isAssignedConsecutiveRegisters(const Variable *Before,
const Variable *After) {
assert(Before->hasReg());
assert(After->hasReg());
return Before->getRegNum() + 1 == After->getRegNum();
}
const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; }
} // end of anonymous namespace
Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; }
void InstARM32Pop::emit(const Cfg *Func) const {
if (!BuildDefs::dump())
return;
SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); }
const SizeT DestSize = Dests.size();
if (DestSize == 0) {
assert(false && "Empty pop list");
void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form,
const Variable *Reg) const {
switch (Form) {
case Emit_Text:
emitGPRsAsText(Func);
return;
}
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 << "}";
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL);
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 {
// Pop can't be emitted if there are no registers to load. This should never
// happen, but if it does, we don't need to bring Subzero down -- we just skip
// emitting the pop instruction (and maybe emit a nop?) The assert() is here
// so that we can detect this error during development.
const SizeT DestSize = Dests.size();
if (DestSize == 0) {
assert(false && "Empty pop list");
void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
IValueT Registers) const {
switch (Form) {
case Emit_Text:
emitGPRsAsText(Func);
return;
}
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
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())
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers,
CondARM32::AL);
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 {
if (!BuildDefs::dump())
void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form,
const Variable *BaseReg, SizeT RegCount) const {
switch (Form) {
case Emit_Text:
emitSRegsAsText(Func, BaseReg, RegCount);
return;
// 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
// 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");
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount,
CondARM32::AL);
return;
}
}
Ostream &Str = Func->getContext()->getStrEmit();
const char *InstARM32Push::getGPROpcode() const { return "push"; }
const auto *Reg = llvm::cast<Variable>(getSrc(0));
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;
}
const char *InstARM32Push::getSRegOpcode() const { return "vpush"; }
// VFP "s" reg push.
Str << "\t"
"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 << "}";
Variable *InstARM32Push::getStackReg(SizeT Index) const {
return llvm::cast<Variable>(getSrc(Index));
}
void InstARM32Push::emitIAS(const Cfg *Func) const {
// 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
// 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");
SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); }
void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form,
const Variable *Reg) const {
switch (Form) {
case Emit_Text:
emitGPRsAsText(Func);
return;
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL);
return;
}
}
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
const auto *Reg = llvm::cast<Variable>(getSrc(0));
if (isScalarIntegerType(Reg->getType())) {
// Push GPR registers.
SizeT IntegerCount = 0;
ARM32::IValueT GPRegisters = 0;
const Variable *LastSrc = nullptr;
for (SizeT Index = 0; Index < getSrcSize(); ++Index) {
const auto *Var = llvm::cast<Variable>(getSrc(Index));
int32_t Reg = RegARM32::getEncodedGPReg(Var->getRegNum());
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);
void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
IValueT Registers) const {
switch (Form) {
case Emit_Text:
emitGPRsAsText(Func);
return;
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers,
CondARM32::AL);
return;
}
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
void InstARM32Push::dump(const Cfg *Func) const {
if (!BuildDefs::dump())
void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form,
const Variable *BaseReg, SizeT RegCount) const {
switch (Form) {
case Emit_Text:
emitSRegsAsText(Func, BaseReg, RegCount);
return;
Ostream &Str = Func->getContext()->getStrDump();
Str << "push"
<< " ";
dumpSources(Func);
case Emit_Binary:
Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount,
CondARM32::AL);
return;
}
}
void InstARM32Ret::emit(const Cfg *Func) const {
......
......@@ -27,6 +27,12 @@
namespace Ice {
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;
/// OperandARM32 extends the Operand hierarchy. Its subclasses are
......@@ -364,6 +370,9 @@ class InstARM32 : public InstTarget {
InstARM32 &operator=(const InstARM32 &) = delete;
public:
// Defines form that assembly instruction should be synthesized.
enum EmitForm { Emit_Text, Emit_Binary };
enum InstKindARM32 {
k__Start = Inst::Target,
Adc,
......@@ -1056,9 +1065,41 @@ private:
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"
/// regs, but not both. In any case, the list must be sorted.
class InstARM32Pop : public InstARM32 {
class InstARM32Pop : public InstARM32RegisterStackOp {
InstARM32Pop() = delete;
InstARM32Pop(const InstARM32Pop &) = delete;
InstARM32Pop &operator=(const InstARM32Pop &) = delete;
......@@ -1067,20 +1108,27 @@ public:
static InstARM32Pop *create(Cfg *Func, const VarList &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); }
private:
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;
};
/// Pushes a list of registers. Just like Pop (see above), the list may be of
/// GPRs, or VFP "s" registers, but not both.
class InstARM32Push : public InstARM32 {
class InstARM32Push : public InstARM32RegisterStackOp {
InstARM32Push() = delete;
InstARM32Push(const InstARM32Push &) = delete;
InstARM32Push &operator=(const InstARM32Push &) = delete;
......@@ -1089,13 +1137,20 @@ public:
static InstARM32Push *create(Cfg *Func, const VarList &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); }
private:
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"
......
......@@ -157,7 +157,7 @@ public:
return Table[RegNum].IsGPR;
}
static constexpr inline SizeT getNumGPRegs() {
static constexpr SizeT getNumGPRegs() {
return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
......@@ -167,11 +167,31 @@ public:
;
}
static inline GPRRegister getEncodedGPReg(int32_t RegNum) {
static inline GPRRegister getEncodedGPR(int32_t RegNum) {
assert(isGPRegister(RegNum));
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) {
assert(isI64RegisterPair(RegNum));
return GPRRegister(Table[RegNum].Encoding);
......@@ -192,7 +212,7 @@ public:
return Table[RegNum].IsFP32;
}
static constexpr inline SizeT getNumSRegs() {
static constexpr SizeT getNumSRegs() {
return 0
#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
......@@ -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) {
assert(isEncodedSReg(RegNum));
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