mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
334 lines
11 KiB
C++
334 lines
11 KiB
C++
//===- SetTheory.cpp - Generate ordered sets from DAG expressions ---------===//
|
|
//
|
|
// 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 SetTheory class that computes ordered sets of
|
|
// Records from DAG expressions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/SMLoc.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/SetTheory.h"
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
using namespace llvm;
|
|
|
|
// Define the standard operators.
|
|
namespace {
|
|
|
|
using RecSet = SetTheory::RecSet;
|
|
using RecVec = SetTheory::RecVec;
|
|
|
|
// (add a, b, ...) Evaluate and union all arguments.
|
|
struct AddOp : public SetTheory::Operator {
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts, Loc);
|
|
}
|
|
};
|
|
|
|
// (sub Add, Sub, ...) Set difference.
|
|
struct SubOp : public SetTheory::Operator {
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
if (Expr->arg_size() < 2)
|
|
PrintFatalError(Loc, "Set difference needs at least two arguments: " +
|
|
Expr->getAsString());
|
|
RecSet Add, Sub;
|
|
ST.evaluate(*Expr->arg_begin(), Add, Loc);
|
|
ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Sub, Loc);
|
|
for (RecSet::iterator I = Add.begin(), E = Add.end(); I != E; ++I)
|
|
if (!Sub.count(*I))
|
|
Elts.insert(*I);
|
|
}
|
|
};
|
|
|
|
// (and S1, S2) Set intersection.
|
|
struct AndOp : public SetTheory::Operator {
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
if (Expr->arg_size() != 2)
|
|
PrintFatalError(Loc, "Set intersection requires two arguments: " +
|
|
Expr->getAsString());
|
|
RecSet S1, S2;
|
|
ST.evaluate(Expr->arg_begin()[0], S1, Loc);
|
|
ST.evaluate(Expr->arg_begin()[1], S2, Loc);
|
|
for (RecSet::iterator I = S1.begin(), E = S1.end(); I != E; ++I)
|
|
if (S2.count(*I))
|
|
Elts.insert(*I);
|
|
}
|
|
};
|
|
|
|
// SetIntBinOp - Abstract base class for (Op S, N) operators.
|
|
struct SetIntBinOp : public SetTheory::Operator {
|
|
virtual void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N,
|
|
RecSet &Elts, ArrayRef<SMLoc> Loc) = 0;
|
|
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
if (Expr->arg_size() != 2)
|
|
PrintFatalError(Loc, "Operator requires (Op Set, Int) arguments: " +
|
|
Expr->getAsString());
|
|
RecSet Set;
|
|
ST.evaluate(Expr->arg_begin()[0], Set, Loc);
|
|
IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1]);
|
|
if (!II)
|
|
PrintFatalError(Loc, "Second argument must be an integer: " +
|
|
Expr->getAsString());
|
|
apply2(ST, Expr, Set, II->getValue(), Elts, Loc);
|
|
}
|
|
};
|
|
|
|
// (shl S, N) Shift left, remove the first N elements.
|
|
struct ShlOp : public SetIntBinOp {
|
|
void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N,
|
|
RecSet &Elts, ArrayRef<SMLoc> Loc) override {
|
|
if (N < 0)
|
|
PrintFatalError(Loc, "Positive shift required: " +
|
|
Expr->getAsString());
|
|
if (unsigned(N) < Set.size())
|
|
Elts.insert(Set.begin() + N, Set.end());
|
|
}
|
|
};
|
|
|
|
// (trunc S, N) Truncate after the first N elements.
|
|
struct TruncOp : public SetIntBinOp {
|
|
void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N,
|
|
RecSet &Elts, ArrayRef<SMLoc> Loc) override {
|
|
if (N < 0)
|
|
PrintFatalError(Loc, "Positive length required: " +
|
|
Expr->getAsString());
|
|
if (unsigned(N) > Set.size())
|
|
N = Set.size();
|
|
Elts.insert(Set.begin(), Set.begin() + N);
|
|
}
|
|
};
|
|
|
|
// Left/right rotation.
|
|
struct RotOp : public SetIntBinOp {
|
|
const bool Reverse;
|
|
|
|
RotOp(bool Rev) : Reverse(Rev) {}
|
|
|
|
void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N,
|
|
RecSet &Elts, ArrayRef<SMLoc> Loc) override {
|
|
if (Reverse)
|
|
N = -N;
|
|
// N > 0 -> rotate left, N < 0 -> rotate right.
|
|
if (Set.empty())
|
|
return;
|
|
if (N < 0)
|
|
N = Set.size() - (-N % Set.size());
|
|
else
|
|
N %= Set.size();
|
|
Elts.insert(Set.begin() + N, Set.end());
|
|
Elts.insert(Set.begin(), Set.begin() + N);
|
|
}
|
|
};
|
|
|
|
// (decimate S, N) Pick every N'th element of S.
|
|
struct DecimateOp : public SetIntBinOp {
|
|
void apply2(SetTheory &ST, DagInit *Expr, RecSet &Set, int64_t N,
|
|
RecSet &Elts, ArrayRef<SMLoc> Loc) override {
|
|
if (N <= 0)
|
|
PrintFatalError(Loc, "Positive stride required: " +
|
|
Expr->getAsString());
|
|
for (unsigned I = 0; I < Set.size(); I += N)
|
|
Elts.insert(Set[I]);
|
|
}
|
|
};
|
|
|
|
// (interleave S1, S2, ...) Interleave elements of the arguments.
|
|
struct InterleaveOp : public SetTheory::Operator {
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
// Evaluate the arguments individually.
|
|
SmallVector<RecSet, 4> Args(Expr->getNumArgs());
|
|
unsigned MaxSize = 0;
|
|
for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i) {
|
|
ST.evaluate(Expr->getArg(i), Args[i], Loc);
|
|
MaxSize = std::max(MaxSize, unsigned(Args[i].size()));
|
|
}
|
|
// Interleave arguments into Elts.
|
|
for (unsigned n = 0; n != MaxSize; ++n)
|
|
for (unsigned i = 0, e = Expr->getNumArgs(); i != e; ++i)
|
|
if (n < Args[i].size())
|
|
Elts.insert(Args[i][n]);
|
|
}
|
|
};
|
|
|
|
// (sequence "Format", From, To) Generate a sequence of records by name.
|
|
struct SequenceOp : public SetTheory::Operator {
|
|
void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts,
|
|
ArrayRef<SMLoc> Loc) override {
|
|
int Step = 1;
|
|
if (Expr->arg_size() > 4)
|
|
PrintFatalError(Loc, "Bad args to (sequence \"Format\", From, To): " +
|
|
Expr->getAsString());
|
|
else if (Expr->arg_size() == 4) {
|
|
if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[3])) {
|
|
Step = II->getValue();
|
|
} else
|
|
PrintFatalError(Loc, "Stride must be an integer: " +
|
|
Expr->getAsString());
|
|
}
|
|
|
|
std::string Format;
|
|
if (StringInit *SI = dyn_cast<StringInit>(Expr->arg_begin()[0]))
|
|
Format = SI->getValue();
|
|
else
|
|
PrintFatalError(Loc, "Format must be a string: " + Expr->getAsString());
|
|
|
|
int64_t From, To;
|
|
if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[1]))
|
|
From = II->getValue();
|
|
else
|
|
PrintFatalError(Loc, "From must be an integer: " + Expr->getAsString());
|
|
if (From < 0 || From >= (1 << 30))
|
|
PrintFatalError(Loc, "From out of range");
|
|
|
|
if (IntInit *II = dyn_cast<IntInit>(Expr->arg_begin()[2]))
|
|
To = II->getValue();
|
|
else
|
|
PrintFatalError(Loc, "To must be an integer: " + Expr->getAsString());
|
|
if (To < 0 || To >= (1 << 30))
|
|
PrintFatalError(Loc, "To out of range");
|
|
|
|
RecordKeeper &Records =
|
|
cast<DefInit>(Expr->getOperator())->getDef()->getRecords();
|
|
|
|
Step *= From <= To ? 1 : -1;
|
|
while (true) {
|
|
if (Step > 0 && From > To)
|
|
break;
|
|
else if (Step < 0 && From < To)
|
|
break;
|
|
std::string Name;
|
|
raw_string_ostream OS(Name);
|
|
OS << format(Format.c_str(), unsigned(From));
|
|
Record *Rec = Records.getDef(OS.str());
|
|
if (!Rec)
|
|
PrintFatalError(Loc, "No def named '" + Name + "': " +
|
|
Expr->getAsString());
|
|
// Try to reevaluate Rec in case it is a set.
|
|
if (const RecVec *Result = ST.expand(Rec))
|
|
Elts.insert(Result->begin(), Result->end());
|
|
else
|
|
Elts.insert(Rec);
|
|
|
|
From += Step;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Expand a Def into a set by evaluating one of its fields.
|
|
struct FieldExpander : public SetTheory::Expander {
|
|
StringRef FieldName;
|
|
|
|
FieldExpander(StringRef fn) : FieldName(fn) {}
|
|
|
|
void expand(SetTheory &ST, Record *Def, RecSet &Elts) override {
|
|
ST.evaluate(Def->getValueInit(FieldName), Elts, Def->getLoc());
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
// Pin the vtables to this file.
|
|
void SetTheory::Operator::anchor() {}
|
|
void SetTheory::Expander::anchor() {}
|
|
|
|
SetTheory::SetTheory() {
|
|
addOperator("add", llvm::make_unique<AddOp>());
|
|
addOperator("sub", llvm::make_unique<SubOp>());
|
|
addOperator("and", llvm::make_unique<AndOp>());
|
|
addOperator("shl", llvm::make_unique<ShlOp>());
|
|
addOperator("trunc", llvm::make_unique<TruncOp>());
|
|
addOperator("rotl", llvm::make_unique<RotOp>(false));
|
|
addOperator("rotr", llvm::make_unique<RotOp>(true));
|
|
addOperator("decimate", llvm::make_unique<DecimateOp>());
|
|
addOperator("interleave", llvm::make_unique<InterleaveOp>());
|
|
addOperator("sequence", llvm::make_unique<SequenceOp>());
|
|
}
|
|
|
|
void SetTheory::addOperator(StringRef Name, std::unique_ptr<Operator> Op) {
|
|
Operators[Name] = std::move(Op);
|
|
}
|
|
|
|
void SetTheory::addExpander(StringRef ClassName, std::unique_ptr<Expander> E) {
|
|
Expanders[ClassName] = std::move(E);
|
|
}
|
|
|
|
void SetTheory::addFieldExpander(StringRef ClassName, StringRef FieldName) {
|
|
addExpander(ClassName, llvm::make_unique<FieldExpander>(FieldName));
|
|
}
|
|
|
|
void SetTheory::evaluate(Init *Expr, RecSet &Elts, ArrayRef<SMLoc> Loc) {
|
|
// A def in a list can be a just an element, or it may expand.
|
|
if (DefInit *Def = dyn_cast<DefInit>(Expr)) {
|
|
if (const RecVec *Result = expand(Def->getDef()))
|
|
return Elts.insert(Result->begin(), Result->end());
|
|
Elts.insert(Def->getDef());
|
|
return;
|
|
}
|
|
|
|
// Lists simply expand.
|
|
if (ListInit *LI = dyn_cast<ListInit>(Expr))
|
|
return evaluate(LI->begin(), LI->end(), Elts, Loc);
|
|
|
|
// Anything else must be a DAG.
|
|
DagInit *DagExpr = dyn_cast<DagInit>(Expr);
|
|
if (!DagExpr)
|
|
PrintFatalError(Loc, "Invalid set element: " + Expr->getAsString());
|
|
DefInit *OpInit = dyn_cast<DefInit>(DagExpr->getOperator());
|
|
if (!OpInit)
|
|
PrintFatalError(Loc, "Bad set expression: " + Expr->getAsString());
|
|
auto I = Operators.find(OpInit->getDef()->getName());
|
|
if (I == Operators.end())
|
|
PrintFatalError(Loc, "Unknown set operator: " + Expr->getAsString());
|
|
I->second->apply(*this, DagExpr, Elts, Loc);
|
|
}
|
|
|
|
const RecVec *SetTheory::expand(Record *Set) {
|
|
// Check existing entries for Set and return early.
|
|
ExpandMap::iterator I = Expansions.find(Set);
|
|
if (I != Expansions.end())
|
|
return &I->second;
|
|
|
|
// This is the first time we see Set. Find a suitable expander.
|
|
ArrayRef<std::pair<Record *, SMRange>> SC = Set->getSuperClasses();
|
|
for (const auto &SCPair : SC) {
|
|
// Skip unnamed superclasses.
|
|
if (!isa<StringInit>(SCPair.first->getNameInit()))
|
|
continue;
|
|
auto I = Expanders.find(SCPair.first->getName());
|
|
if (I != Expanders.end()) {
|
|
// This breaks recursive definitions.
|
|
RecVec &EltVec = Expansions[Set];
|
|
RecSet Elts;
|
|
I->second->expand(*this, Set, Elts);
|
|
EltVec.assign(Elts.begin(), Elts.end());
|
|
return &EltVec;
|
|
}
|
|
}
|
|
|
|
// Set is not expandable.
|
|
return nullptr;
|
|
}
|