mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-04-13 15:37:24 +00:00
add (and document) the ability for alias results to have
fixed physical registers. Start moving fp comparison aliases to the .td file (which default to using %st1 if nothing is specified). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@118352 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
8d5acb7007
commit
90fd797dc7
@ -1998,12 +1998,20 @@ def : InstAlias<"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg)>;
|
||||
<p>This example also shows that tied operands are only listed once. In the X86
|
||||
backend, XOR8rr has two input GR8's and one output GR8 (where an input is tied
|
||||
to the output). InstAliases take a flattened operand list without duplicates
|
||||
for tied operands. The result of an instruction alias can also use immediates,
|
||||
which are added as simple immediate operands in the result, for example:</p>
|
||||
for tied operands. The result of an instruction alias can also use immediates
|
||||
and fixed physical registers which are added as simple immediate operands in the
|
||||
result, for example:</p>
|
||||
|
||||
<div class="doc_code">
|
||||
<pre>
|
||||
// Fixed Immediate operand.
|
||||
def : InstAlias<"aad", (AAD8i8 10)>;
|
||||
|
||||
// Fixed register operand.
|
||||
def : InstAlias<"fcomi", (COM_FIr ST1)>;
|
||||
|
||||
// Simple alias.
|
||||
def : InstAlias<"fcomi $reg", (COM_FIr RST:$reg)>;
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
@ -821,7 +821,7 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||
|
||||
// The assembler accepts these instructions with no operand as a synonym for
|
||||
// an instruction acting on st(1). e.g. "fxch" -> "fxch %st(1)".
|
||||
if ((Name == "fxch" || Name == "fucom" || Name == "fucomp" ||
|
||||
if ((Name == "fxch" ||
|
||||
Name == "faddp" || Name == "fsubp" || Name == "fsubrp" ||
|
||||
Name == "fmulp" || Name == "fdivp" || Name == "fdivrp") &&
|
||||
Operands.size() == 1) {
|
||||
@ -829,18 +829,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
|
||||
NameLoc, NameLoc));
|
||||
}
|
||||
|
||||
// The assembler accepts these instructions with two few operands as a synonym
|
||||
// for taking %st(1),%st(0) or X, %st(0).
|
||||
if ((Name == "fcomi" || Name == "fucomi" || Name == "fucompi" ||
|
||||
Name == "fcompi" ) &&
|
||||
Operands.size() < 3) {
|
||||
if (Operands.size() == 1)
|
||||
Operands.push_back(X86Operand::CreateReg(MatchRegisterName("st(1)"),
|
||||
NameLoc, NameLoc));
|
||||
Operands.push_back(X86Operand::CreateReg(MatchRegisterName("st(0)"),
|
||||
NameLoc, NameLoc));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -854,6 +842,8 @@ MatchAndEmitInstruction(SMLoc IDLoc,
|
||||
|
||||
// First, handle aliases that expand to multiple instructions.
|
||||
// FIXME: This should be replaced with a real .td file alias mechanism.
|
||||
// Also, MatchInstructionImpl should do actually *do* the EmitInstruction
|
||||
// call.
|
||||
if (Op->getToken() == "fstsw" || Op->getToken() == "fstcw" ||
|
||||
Op->getToken() == "fstsww" || Op->getToken() == "fstcww" ||
|
||||
Op->getToken() == "finit" || Op->getToken() == "fsave" ||
|
||||
|
@ -1377,6 +1377,19 @@ def : InstAlias<"clrw $reg", (XOR16rr GR16:$reg, GR16:$reg)>;
|
||||
def : InstAlias<"clrl $reg", (XOR32rr GR32:$reg, GR32:$reg)>;
|
||||
def : InstAlias<"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg)>;
|
||||
|
||||
// Default arguments for various fp stack instructions.
|
||||
def : InstAlias<"fucom", (UCOM_Fr ST1)>;
|
||||
def : InstAlias<"fucomp", (UCOM_FPr ST1)>;
|
||||
def : InstAlias<"fcomi", (COM_FIr ST1)>;
|
||||
def : InstAlias<"fcomi $reg", (COM_FIr RST:$reg)>;
|
||||
def : InstAlias<"fcomip", (COM_FIPr ST1)>;
|
||||
def : InstAlias<"fcomip $reg", (COM_FIPr RST:$reg)>;
|
||||
def : InstAlias<"fucomi", (UCOM_FIr ST1)>;
|
||||
def : InstAlias<"fucomi $reg", (UCOM_FIr RST:$reg)>;
|
||||
def : InstAlias<"fucomip", (UCOM_FIPr ST1)>;
|
||||
def : InstAlias<"fucomip $reg", (UCOM_FIPr RST:$reg)>;
|
||||
|
||||
|
||||
// We accepts "fnstsw %eax" even though it only writes %ax.
|
||||
def : InstAlias<"fnstsw %eax", (FNSTSW8r)>;
|
||||
def : InstAlias<"fnstsw %al" , (FNSTSW8r)>;
|
||||
|
@ -274,7 +274,10 @@ struct MatchableInfo {
|
||||
|
||||
/// ImmOperand - This represents an immediate value that is dumped into
|
||||
/// the operand.
|
||||
ImmOperand
|
||||
ImmOperand,
|
||||
|
||||
/// RegOperand - This represents a fixed register that is dumped in.
|
||||
RegOperand
|
||||
} Kind;
|
||||
|
||||
union {
|
||||
@ -288,6 +291,9 @@ struct MatchableInfo {
|
||||
|
||||
/// ImmVal - This is the immediate value added to the instruction.
|
||||
int64_t ImmVal;
|
||||
|
||||
/// Register - This is the register record.
|
||||
Record *Register;
|
||||
};
|
||||
|
||||
/// OpInfo - This is the information about the instruction operand that is
|
||||
@ -320,6 +326,16 @@ struct MatchableInfo {
|
||||
X.OpInfo = Op;
|
||||
return X;
|
||||
}
|
||||
|
||||
static ResOperand getRegOp(Record *Reg,
|
||||
const CGIOperandList::OperandInfo *Op) {
|
||||
ResOperand X;
|
||||
X.Kind = RegOperand;
|
||||
X.Register = Reg;
|
||||
X.OpInfo = Op;
|
||||
return X;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// TheDef - This is the definition of the instruction or InstAlias that this
|
||||
@ -1243,7 +1259,8 @@ void MatchableInfo::BuildAliasResultOperands() {
|
||||
|
||||
// Find out what operand from the asmparser that this MCInst operand comes
|
||||
// from.
|
||||
if (CGA.ResultOperands[AliasOpNo].isRecord()) {
|
||||
switch (CGA.ResultOperands[AliasOpNo].Kind) {
|
||||
case CodeGenInstAlias::ResultOperand::K_Record: {
|
||||
StringRef Name = CGA.ResultOperands[AliasOpNo++].getName();
|
||||
int SrcOperand = FindAsmOperandNamed(Name);
|
||||
if (SrcOperand != -1) {
|
||||
@ -1255,10 +1272,18 @@ void MatchableInfo::BuildAliasResultOperands() {
|
||||
TheDef->getName() + "' has operand '" + OpInfo.Name +
|
||||
"' that doesn't appear in asm string!");
|
||||
}
|
||||
|
||||
int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
|
||||
ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
|
||||
continue;
|
||||
case CodeGenInstAlias::ResultOperand::K_Imm: {
|
||||
int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
|
||||
ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
|
||||
continue;
|
||||
}
|
||||
|
||||
case CodeGenInstAlias::ResultOperand::K_Reg: {
|
||||
Record *Reg = CGA.ResultOperands[AliasOpNo++].getRegister();
|
||||
ResOperands.push_back(ResOperand::getRegOp(Reg, &OpInfo));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1341,6 +1366,11 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
|
||||
Signature += "__imm" + itostr(Val);
|
||||
break;
|
||||
}
|
||||
case MatchableInfo::ResOperand::RegOperand: {
|
||||
std::string N = getQualifiedName(OpInfo.Register);
|
||||
CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n";
|
||||
Signature += "__reg" + OpInfo.Register->getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,6 +419,30 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
|
||||
|
||||
|
||||
Init *Arg = Result->getArg(AliasOpNo);
|
||||
Record *ResultOpRec = ResultInst->Operands[i].Rec;
|
||||
|
||||
// Handle explicit registers.
|
||||
if (DefInit *ADI = dynamic_cast<DefInit*>(Arg)) {
|
||||
if (ADI->getDef()->isSubClassOf("Register")) {
|
||||
if (!Result->getArgName(AliasOpNo).empty())
|
||||
throw TGError(R->getLoc(), "result fixed register argument must "
|
||||
"not have a name!");
|
||||
|
||||
if (!ResultOpRec->isSubClassOf("RegisterClass"))
|
||||
throw TGError(R->getLoc(), "result fixed register argument is not "
|
||||
"passed to a RegisterClass operand!");
|
||||
|
||||
if (!T.getRegisterClass(ResultOpRec).containsRegister(ADI->getDef()))
|
||||
throw TGError(R->getLoc(), "fixed register " +ADI->getDef()->getName()
|
||||
+ " is not a member of the " + ResultOpRec->getName() +
|
||||
" register class!");
|
||||
|
||||
// Now that it is validated, add it.
|
||||
ResultOperands.push_back(ResultOperand(ADI->getDef()));
|
||||
++AliasOpNo;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the operand is a record, it must have a name, and the record type must
|
||||
// match up with the instruction's argument type.
|
||||
@ -427,11 +451,11 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
|
||||
throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
|
||||
" must have a name!");
|
||||
|
||||
if (ADI->getDef() != ResultInst->Operands[i].Rec)
|
||||
if (ADI->getDef() != ResultOpRec)
|
||||
throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
|
||||
" declared with class " + ADI->getDef()->getName() +
|
||||
", instruction operand is class " +
|
||||
ResultInst->Operands[i].Rec->getName());
|
||||
ResultOpRec->getName());
|
||||
|
||||
// Verify we don't have something like: (someinst GR16:$foo, GR32:$foo)
|
||||
// $foo can exist multiple times in the result list, but it must have the
|
||||
@ -456,9 +480,9 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
|
||||
throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
|
||||
" must not have a name!");
|
||||
if (ResultInst->Operands[i].MINumOperands != 1 ||
|
||||
!ResultInst->Operands[i].Rec->isSubClassOf("Operand"))
|
||||
!ResultOpRec->isSubClassOf("Operand"))
|
||||
throw TGError(R->getLoc(), "invalid argument class " +
|
||||
ResultInst->Operands[i].Rec->getName() +
|
||||
ResultOpRec->getName() +
|
||||
" for integer result operand!");
|
||||
ResultOperands.push_back(ResultOperand(II->getValue()));
|
||||
++AliasOpNo;
|
||||
|
@ -275,18 +275,22 @@ namespace llvm {
|
||||
public:
|
||||
enum {
|
||||
K_Record,
|
||||
K_Imm
|
||||
K_Imm,
|
||||
K_Reg
|
||||
} Kind;
|
||||
|
||||
ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {}
|
||||
ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
|
||||
ResultOperand(Record *r) : R(r), Kind(K_Reg) {}
|
||||
|
||||
bool isRecord() const { return Kind == K_Record; }
|
||||
bool isImm() const { return Kind == K_Imm; }
|
||||
bool isReg() const { return Kind == K_Reg; }
|
||||
|
||||
StringRef getName() const { assert(isRecord()); return Name; }
|
||||
Record *getRecord() const { assert(isRecord()); return R; }
|
||||
int64_t getImm() const { assert(isImm()); return Imm; }
|
||||
Record *getRegister() const { assert(isReg()); return R; }
|
||||
};
|
||||
|
||||
/// ResultOperands - The decoded operands for the result instruction.
|
||||
|
@ -57,6 +57,12 @@ namespace llvm {
|
||||
abort();
|
||||
}
|
||||
|
||||
bool containsRegister(Record *R) const {
|
||||
for (unsigned i = 0, e = Elements.size(); i != e; ++i)
|
||||
if (Elements[i] == R) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns true if RC is a strict subclass.
|
||||
// RC is a sub-class of this class if it is a valid replacement for any
|
||||
// instruction operand where a register of this classis required. It must
|
||||
|
Loading…
x
Reference in New Issue
Block a user