This is useful for `InstAlias` where a fixed register may depend on the
HwMode. The motivating use case for this is the RISC-V RVY ISA where
certain instructions mnemonics are remapped to take a different
register class depending on the HwMode and can be used as follows:
```
def NullReg : RegisterByHwMode<PtrRC, [RV32I, RV64I, RV64Y, RV64Y],
[X0, X0, X0_Y, X0_Y]>;
```
Pull Request: https://github.com/llvm/llvm-project/pull/175227
244 lines
10 KiB
C++
244 lines
10 KiB
C++
//===- CodeGenInstAlias.cpp - CodeGen InstAlias Class Wrapper -------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the CodeGenInstAlias class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeGenInstAlias.h"
|
|
#include "CodeGenInstruction.h"
|
|
#include "CodeGenRegisters.h"
|
|
#include "CodeGenTarget.h"
|
|
#include "llvm/ADT/StringMap.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
using namespace llvm;
|
|
|
|
unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const {
|
|
if (!isRecord())
|
|
return 1;
|
|
|
|
const Record *Rec = getRecord();
|
|
if (!Rec->isSubClassOf("Operand"))
|
|
return 1;
|
|
|
|
const DagInit *MIOpInfo = Rec->getValueAsDag("MIOperandInfo");
|
|
if (MIOpInfo->getNumArgs() == 0) {
|
|
// Unspecified, so it defaults to 1
|
|
return 1;
|
|
}
|
|
|
|
return MIOpInfo->getNumArgs();
|
|
}
|
|
|
|
using ResultOperand = CodeGenInstAlias::ResultOperand;
|
|
|
|
static Expected<ResultOperand>
|
|
matchSimpleOperand(const Init *Arg, const StringInit *ArgName, const Record *Op,
|
|
const CodeGenTarget &T, ArrayRef<SMLoc> Loc) {
|
|
if (const Record *OpRC = T.getAsRegClassLike(Op)) {
|
|
if (const auto *ArgDef = dyn_cast<DefInit>(Arg)) {
|
|
const Record *ArgRec = ArgDef->getDef();
|
|
|
|
// Match 'RegClass:$name', 'RegOp:$name', or RegisterByHwMode.
|
|
if (const Record *ArgRC = T.getInitValueAsRegClassLike(Arg)) {
|
|
if (ArgRec->isSubClassOf("RegisterByHwMode")) {
|
|
// Note: constraints are validated in RegisterByHwMode ctor later.
|
|
return ResultOperand::createRegister(ArgRec);
|
|
}
|
|
if (ArgRC->isSubClassOf("RegisterClass")) {
|
|
if (!OpRC->isSubClassOf("RegisterClass") ||
|
|
!T.getRegisterClass(OpRC, Loc).hasSubClass(
|
|
&T.getRegisterClass(ArgRC, Loc)))
|
|
return createStringError(
|
|
"argument register class " + ArgRC->getName() +
|
|
" is not a subclass of operand register class " +
|
|
OpRC->getName());
|
|
if (!ArgName)
|
|
return createStringError(
|
|
"register class argument must have a name");
|
|
}
|
|
|
|
// TODO: Verify RegClassByHwMode usage
|
|
|
|
return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
|
|
ArgRec);
|
|
}
|
|
|
|
// Match 'Reg'.
|
|
if (ArgRec->isSubClassOf("Register")) {
|
|
if (!T.getRegisterClass(OpRC, Loc).contains(
|
|
T.getRegBank().getReg(ArgRec)))
|
|
return createStringError(
|
|
"register argument " + ArgRec->getName() +
|
|
" is not a member of operand register class " + OpRC->getName());
|
|
if (ArgName)
|
|
return createStringError("register argument must not have a name");
|
|
return ResultOperand::createRegister(ArgRec);
|
|
}
|
|
|
|
// Match 'zero_reg'.
|
|
if (ArgRec->getName() == "zero_reg") {
|
|
if (ArgName)
|
|
return createStringError("register argument must not have a name");
|
|
return ResultOperand::createRegister(nullptr);
|
|
}
|
|
}
|
|
|
|
return createStringError("argument must be a subclass of RegisterClass, "
|
|
"RegisterOperand, or zero_reg");
|
|
}
|
|
|
|
if (Op->isSubClassOf("Operand")) {
|
|
// Match integer or bits.
|
|
if (const auto *ArgInt = dyn_cast_or_null<IntInit>(
|
|
Arg->convertInitializerTo(IntRecTy::get(Arg->getRecordKeeper())))) {
|
|
if (ArgName)
|
|
return createStringError("integer argument must not have a name");
|
|
return ResultOperand::createImmediate(ArgInt->getValue());
|
|
}
|
|
|
|
// Match a subclass of Operand.
|
|
if (const auto *ArgDef = dyn_cast<DefInit>(Arg);
|
|
ArgDef && ArgDef->getDef()->isSubClassOf("Operand")) {
|
|
if (!ArgName)
|
|
return createStringError("argument must have a name");
|
|
return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
|
|
ArgDef->getDef());
|
|
}
|
|
}
|
|
return createStringError("argument must be a subclass of 'Operand' but got " +
|
|
Op->getName() + " instead");
|
|
}
|
|
|
|
static Expected<ResultOperand> matchComplexOperand(const Init *Arg,
|
|
const StringInit *ArgName,
|
|
const Record *Op) {
|
|
assert(Op->isSubClassOf("Operand"));
|
|
const auto *ArgDef = dyn_cast<DefInit>(Arg);
|
|
if (!ArgDef || !ArgDef->getDef()->isSubClassOf("Operand"))
|
|
return createStringError("argument must be a subclass of Operand");
|
|
if (!ArgName)
|
|
return createStringError("argument must have a name");
|
|
return ResultOperand::createRecord(ArgName->getAsUnquotedString(),
|
|
ArgDef->getDef());
|
|
}
|
|
|
|
CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T)
|
|
: TheDef(R) {
|
|
Result = R->getValueAsDag("ResultInst");
|
|
AsmString = R->getValueAsString("AsmString");
|
|
|
|
// Verify that the root of the result is an instruction.
|
|
const DefInit *DI = dyn_cast<DefInit>(Result->getOperator());
|
|
if (!DI || !DI->getDef()->isSubClassOf("Instruction"))
|
|
PrintFatalError(R->getLoc(),
|
|
"result of inst alias should be an instruction");
|
|
|
|
ResultInst = &T.getInstruction(DI->getDef());
|
|
|
|
// NameClass - If argument names are repeated, we need to verify they have
|
|
// the same class.
|
|
StringMap<const Record *> NameClass;
|
|
for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) {
|
|
const DefInit *ADI = dyn_cast<DefInit>(Result->getArg(i));
|
|
if (!ADI || !Result->getArgName(i))
|
|
continue;
|
|
// 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
|
|
// same type.
|
|
const Record *&Entry = NameClass[Result->getArgNameStr(i)];
|
|
if (Entry && Entry != ADI->getDef())
|
|
PrintFatalError(R->getLoc(), "result value $" + Result->getArgNameStr(i) +
|
|
" is both " + Entry->getName() +
|
|
" and " + ADI->getDef()->getName() +
|
|
"!");
|
|
Entry = ADI->getDef();
|
|
}
|
|
|
|
// Decode and validate the arguments of the result.
|
|
unsigned ArgIdx = 0;
|
|
for (auto [OpIdx, OpInfo] : enumerate(ResultInst->Operands)) {
|
|
// Tied registers don't have an entry in the result dag unless they're part
|
|
// of a complex operand, in which case we include them anyways, as we
|
|
// don't have any other way to specify the whole operand.
|
|
if (OpInfo.MINumOperands == 1 && OpInfo.getTiedRegister() != -1) {
|
|
// Tied operands of different RegisterClass should be explicit within an
|
|
// instruction's syntax and so cannot be skipped.
|
|
int TiedOpNum = OpInfo.getTiedRegister();
|
|
if (OpInfo.Rec->getName() ==
|
|
ResultInst->Operands[TiedOpNum].Rec->getName())
|
|
continue;
|
|
}
|
|
|
|
if (ArgIdx >= Result->getNumArgs())
|
|
PrintFatalError(R->getLoc(), "not enough arguments for instruction!");
|
|
|
|
const Record *Op = OpInfo.Rec;
|
|
if (Op->isSubClassOf("Operand") && !OpInfo.MIOperandInfo->arg_empty()) {
|
|
// Complex operand (a subclass of Operand with non-empty MIOperandInfo).
|
|
// The argument can be a DAG or a subclass of Operand.
|
|
if (auto *ArgDag = dyn_cast<DagInit>(Result->getArg(ArgIdx))) {
|
|
// The argument is a DAG. The operator must be the name of the operand.
|
|
if (auto *Operator = dyn_cast<DefInit>(ArgDag->getOperator());
|
|
!Operator || Operator->getDef()->getName() != Op->getName())
|
|
PrintFatalError(R, "argument #" + Twine(ArgIdx) +
|
|
" operator must be " + Op->getName());
|
|
// The number of sub-arguments and the number of sub-operands
|
|
// must match exactly.
|
|
unsigned NumSubOps = OpInfo.MIOperandInfo->getNumArgs();
|
|
unsigned NumSubArgs = ArgDag->getNumArgs();
|
|
if (NumSubArgs != NumSubOps)
|
|
PrintFatalError(R, "argument #" + Twine(ArgIdx) +
|
|
" must have exactly " + Twine(NumSubOps) +
|
|
" sub-arguments");
|
|
// Match sub-operands individually.
|
|
for (unsigned SubOpIdx = 0; SubOpIdx != NumSubOps; ++SubOpIdx) {
|
|
const Record *SubOp =
|
|
cast<DefInit>(OpInfo.MIOperandInfo->getArg(SubOpIdx))->getDef();
|
|
Expected<ResultOperand> ResOpOrErr = matchSimpleOperand(
|
|
ArgDag->getArg(SubOpIdx), ArgDag->getArgName(SubOpIdx), SubOp, T,
|
|
R->getLoc());
|
|
if (!ResOpOrErr)
|
|
PrintFatalError(R, "in argument #" + Twine(ArgIdx) + "." +
|
|
Twine(SubOpIdx) + ": " +
|
|
toString(ResOpOrErr.takeError()));
|
|
ResultOperands.push_back(*ResOpOrErr);
|
|
ResultInstOperandIndex.emplace_back(OpIdx, SubOpIdx);
|
|
}
|
|
} else {
|
|
// Match complex operand as a whole.
|
|
Expected<ResultOperand> ResOpOrErr = matchComplexOperand(
|
|
Result->getArg(ArgIdx), Result->getArgName(ArgIdx), Op);
|
|
if (!ResOpOrErr)
|
|
PrintFatalError(R, "in argument #" + Twine(ArgIdx) + ": " +
|
|
toString(ResOpOrErr.takeError()));
|
|
ResultOperands.push_back(*ResOpOrErr);
|
|
ResultInstOperandIndex.emplace_back(OpIdx, -1);
|
|
}
|
|
} else {
|
|
// Simple operand (RegisterClass, RegisterOperand or Operand with empty
|
|
// MIOperandInfo).
|
|
Expected<ResultOperand> ResOpOrErr =
|
|
matchSimpleOperand(Result->getArg(ArgIdx), Result->getArgName(ArgIdx),
|
|
Op, T, R->getLoc());
|
|
if (!ResOpOrErr)
|
|
PrintFatalError(R, "in argument #" + Twine(ArgIdx) + ": " +
|
|
toString(ResOpOrErr.takeError()));
|
|
ResultOperands.push_back(*ResOpOrErr);
|
|
ResultInstOperandIndex.emplace_back(OpIdx, -1);
|
|
}
|
|
ArgIdx++;
|
|
}
|
|
|
|
if (ArgIdx != Result->getNumArgs())
|
|
PrintFatalError(R->getLoc(), "too many operands for instruction!");
|
|
}
|