2003-10-06 03:27:59 +08:00
|
|
|
//===- Record.cpp - Record implementation ---------------------------------===//
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2003-10-21 04:20:30 +08:00
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-30 04:37:13 +08:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2005-04-22 08:00:37 +08:00
|
|
|
//
|
2003-10-21 04:20:30 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2003-10-06 03:27:59 +08:00
|
|
|
//
|
2006-04-01 05:53:49 +08:00
|
|
|
// Implement the tablegen record classes.
|
2003-10-06 03:27:59 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-16 08:43:26 +08:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2011-07-30 03:07:11 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
|
|
|
#include "llvm/ADT/FoldingSet.h"
|
2016-12-04 13:48:06 +08:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2007-11-21 06:25:16 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2011-07-30 03:07:14 +08:00
|
|
|
#include "llvm/ADT/StringMap.h"
|
2017-06-16 08:43:26 +08:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
#include "llvm/Support/Allocator.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2017-06-16 08:43:26 +08:00
|
|
|
#include "llvm/Support/SMLoc.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/TableGen/Error.h"
|
2017-06-16 08:43:26 +08:00
|
|
|
#include "llvm/TableGen/Record.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
2017-06-16 08:43:26 +08:00
|
|
|
#include <memory>
|
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
#include <vector>
|
2005-12-26 13:08:55 +08:00
|
|
|
|
2004-08-01 11:55:39 +08:00
|
|
|
using namespace llvm;
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
static BumpPtrAllocator Allocator;
|
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2011-07-19 01:02:57 +08:00
|
|
|
BitRecTy BitRecTy::Shared;
|
2016-07-06 05:22:55 +08:00
|
|
|
CodeRecTy CodeRecTy::Shared;
|
2011-07-19 01:02:57 +08:00
|
|
|
IntRecTy IntRecTy::Shared;
|
|
|
|
StringRecTy StringRecTy::Shared;
|
|
|
|
DagRecTy DagRecTy::Shared;
|
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void RecTy::dump() const { print(errs()); }
|
2017-01-28 10:02:38 +08:00
|
|
|
#endif
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2011-07-19 01:02:57 +08:00
|
|
|
ListRecTy *RecTy::getListTy() {
|
|
|
|
if (!ListTy)
|
2016-12-04 13:48:20 +08:00
|
|
|
ListTy = new(Allocator) ListRecTy(this);
|
|
|
|
return ListTy;
|
2011-07-19 01:02:57 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool RecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
|
|
|
assert(RHS && "NULL pointer");
|
2013-01-07 10:30:19 +08:00
|
|
|
return Kind == RHS->getRecTyKind();
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool BitRecTy::typeIsConvertibleTo(const RecTy *RHS) const{
|
2015-06-06 09:34:01 +08:00
|
|
|
if (RecTy::typeIsConvertibleTo(RHS) || RHS->getRecTyKind() == IntRecTyKind)
|
2013-01-07 10:30:19 +08:00
|
|
|
return true;
|
2015-06-06 09:34:01 +08:00
|
|
|
if (const BitsRecTy *BitsTy = dyn_cast<BitsRecTy>(RHS))
|
2013-01-07 10:30:19 +08:00
|
|
|
return BitsTy->getNumBits() == 1;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-19 01:02:57 +08:00
|
|
|
BitsRecTy *BitsRecTy::get(unsigned Sz) {
|
2016-12-04 13:48:20 +08:00
|
|
|
static std::vector<BitsRecTy*> Shared;
|
2011-07-19 01:02:57 +08:00
|
|
|
if (Sz >= Shared.size())
|
|
|
|
Shared.resize(Sz + 1);
|
2016-12-04 13:48:20 +08:00
|
|
|
BitsRecTy *&Ty = Shared[Sz];
|
2011-07-19 01:02:57 +08:00
|
|
|
if (!Ty)
|
2016-12-04 13:48:20 +08:00
|
|
|
Ty = new(Allocator) BitsRecTy(Sz);
|
|
|
|
return Ty;
|
2011-07-19 01:02:57 +08:00
|
|
|
}
|
|
|
|
|
2007-11-21 06:25:16 +08:00
|
|
|
std::string BitsRecTy::getAsString() const {
|
|
|
|
return "bits<" + utostr(Size) + ">";
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool BitsRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
|
|
|
if (RecTy::typeIsConvertibleTo(RHS)) //argument and the sender are same type
|
2013-01-07 10:30:19 +08:00
|
|
|
return cast<BitsRecTy>(RHS)->Size == Size;
|
|
|
|
RecTyKind kind = RHS->getRecTyKind();
|
|
|
|
return (kind == BitRecTyKind && Size == 1) || (kind == IntRecTyKind);
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool IntRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
2013-01-07 10:30:19 +08:00
|
|
|
RecTyKind kind = RHS->getRecTyKind();
|
|
|
|
return kind==BitRecTyKind || kind==BitsRecTyKind || kind==IntRecTyKind;
|
|
|
|
}
|
|
|
|
|
2018-02-22 23:27:03 +08:00
|
|
|
bool CodeRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
|
|
|
RecTyKind Kind = RHS->getRecTyKind();
|
|
|
|
return Kind == CodeRecTyKind || Kind == StringRecTyKind;
|
|
|
|
}
|
|
|
|
|
2015-06-01 14:44:18 +08:00
|
|
|
std::string StringRecTy::getAsString() const {
|
|
|
|
return "string";
|
|
|
|
}
|
2006-04-01 05:53:49 +08:00
|
|
|
|
2018-02-22 23:27:03 +08:00
|
|
|
bool StringRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
|
|
|
RecTyKind Kind = RHS->getRecTyKind();
|
|
|
|
return Kind == StringRecTyKind || Kind == CodeRecTyKind;
|
|
|
|
}
|
|
|
|
|
2007-11-21 06:25:16 +08:00
|
|
|
std::string ListRecTy::getAsString() const {
|
|
|
|
return "list<" + Ty->getAsString() + ">";
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool ListRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
|
|
|
if (const auto *ListTy = dyn_cast<ListRecTy>(RHS))
|
|
|
|
return Ty->typeIsConvertibleTo(ListTy->getElementType());
|
2013-01-07 10:30:19 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-01 14:44:18 +08:00
|
|
|
std::string DagRecTy::getAsString() const {
|
|
|
|
return "dag";
|
|
|
|
}
|
|
|
|
|
2011-07-19 01:02:57 +08:00
|
|
|
RecordRecTy *RecordRecTy::get(Record *R) {
|
2015-04-22 10:59:06 +08:00
|
|
|
return dyn_cast<RecordRecTy>(R->getDefInit()->getType());
|
2011-07-19 01:02:57 +08:00
|
|
|
}
|
|
|
|
|
2007-11-21 06:25:16 +08:00
|
|
|
std::string RecordRecTy::getAsString() const {
|
|
|
|
return Rec->getName();
|
|
|
|
}
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
bool RecordRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
|
2013-01-07 10:30:19 +08:00
|
|
|
const RecordRecTy *RTy = dyn_cast<RecordRecTy>(RHS);
|
|
|
|
if (!RTy)
|
|
|
|
return false;
|
|
|
|
|
2015-05-30 15:36:01 +08:00
|
|
|
if (RTy->getRecord() == Rec || Rec->isSubClassOf(RTy->getRecord()))
|
2010-06-18 07:00:16 +08:00
|
|
|
return true;
|
|
|
|
|
2018-02-23 19:31:49 +08:00
|
|
|
for (const auto &SCPair : RTy->getRecord()->getSuperClasses())
|
|
|
|
if (Rec->isSubClassOf(SCPair.first))
|
|
|
|
return true;
|
|
|
|
|
2010-06-18 07:00:16 +08:00
|
|
|
return false;
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2009-06-09 04:23:18 +08:00
|
|
|
RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) {
|
2012-09-19 10:14:59 +08:00
|
|
|
if (T1->typeIsConvertibleTo(T2))
|
|
|
|
return T2;
|
|
|
|
if (T2->typeIsConvertibleTo(T1))
|
|
|
|
return T1;
|
|
|
|
|
|
|
|
// If one is a Record type, check superclasses
|
2012-10-05 11:31:58 +08:00
|
|
|
if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) {
|
2012-09-19 10:14:59 +08:00
|
|
|
// See if T2 inherits from a type T1 also inherits from
|
2016-01-19 03:52:37 +08:00
|
|
|
for (const auto &SuperPair1 : RecTy1->getRecord()->getSuperClasses()) {
|
|
|
|
RecordRecTy *SuperRecTy1 = RecordRecTy::get(SuperPair1.first);
|
2012-09-19 10:14:59 +08:00
|
|
|
RecTy *NewType1 = resolveTypes(SuperRecTy1, T2);
|
2015-04-22 13:27:11 +08:00
|
|
|
if (NewType1)
|
2012-09-19 10:14:59 +08:00
|
|
|
return NewType1;
|
|
|
|
}
|
|
|
|
}
|
2012-10-05 11:31:58 +08:00
|
|
|
if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2)) {
|
2012-09-19 10:14:59 +08:00
|
|
|
// See if T1 inherits from a type T2 also inherits from
|
2016-01-19 03:52:37 +08:00
|
|
|
for (const auto &SuperPair2 : RecTy2->getRecord()->getSuperClasses()) {
|
|
|
|
RecordRecTy *SuperRecTy2 = RecordRecTy::get(SuperPair2.first);
|
2012-09-19 10:14:59 +08:00
|
|
|
RecTy *NewType2 = resolveTypes(T1, SuperRecTy2);
|
2015-04-22 13:27:11 +08:00
|
|
|
if (NewType2)
|
2012-09-19 10:14:59 +08:00
|
|
|
return NewType2;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
}
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Initializer implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-16 08:43:26 +08:00
|
|
|
void Init::anchor() {}
|
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void Init::dump() const { return print(errs()); }
|
2017-01-28 10:02:38 +08:00
|
|
|
#endif
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
UnsetInit *UnsetInit::get() {
|
|
|
|
static UnsetInit TheInit;
|
2011-07-30 03:07:09 +08:00
|
|
|
return &TheInit;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *UnsetInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
|
|
|
|
SmallVector<Init *, 16> NewBits(BRT->getNumBits());
|
|
|
|
|
|
|
|
for (unsigned i = 0; i != BRT->getNumBits(); ++i)
|
|
|
|
NewBits[i] = UnsetInit::get();
|
|
|
|
|
|
|
|
return BitsInit::get(NewBits);
|
|
|
|
}
|
|
|
|
|
|
|
|
// All other types can just be returned.
|
|
|
|
return const_cast<UnsetInit *>(this);
|
|
|
|
}
|
2011-12-20 10:50:00 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
BitInit *BitInit::get(bool V) {
|
|
|
|
static BitInit True(true);
|
|
|
|
static BitInit False(false);
|
2011-07-30 03:07:10 +08:00
|
|
|
|
|
|
|
return V ? &True : &False;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *BitInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<BitRecTy>(Ty))
|
|
|
|
return const_cast<BitInit *>(this);
|
|
|
|
|
|
|
|
if (isa<IntRecTy>(Ty))
|
|
|
|
return IntInit::get(getValue());
|
|
|
|
|
|
|
|
if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
|
|
|
|
// Can only convert single bit.
|
|
|
|
if (BRT->getNumBits() == 1)
|
|
|
|
return BitsInit::get(const_cast<BitInit *>(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2011-07-30 03:07:11 +08:00
|
|
|
static void
|
2011-07-30 06:43:06 +08:00
|
|
|
ProfileBitsInit(FoldingSetNodeID &ID, ArrayRef<Init *> Range) {
|
2011-07-30 03:07:11 +08:00
|
|
|
ID.AddInteger(Range.size());
|
|
|
|
|
2015-04-29 15:13:14 +08:00
|
|
|
for (Init *I : Range)
|
|
|
|
ID.AddPointer(I);
|
2011-07-30 03:07:11 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
BitsInit *BitsInit::get(ArrayRef<Init *> Range) {
|
2015-04-24 13:38:48 +08:00
|
|
|
static FoldingSet<BitsInit> ThePool;
|
2011-07-30 03:07:11 +08:00
|
|
|
|
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileBitsInit(ID, Range);
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
void *IP = nullptr;
|
2011-07-30 06:43:06 +08:00
|
|
|
if (BitsInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
2011-07-30 03:07:11 +08:00
|
|
|
return I;
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Range.size()),
|
|
|
|
alignof(BitsInit));
|
|
|
|
BitsInit *I = new(Mem) BitsInit(Range.size());
|
2016-01-19 03:52:24 +08:00
|
|
|
std::uninitialized_copy(Range.begin(), Range.end(),
|
|
|
|
I->getTrailingObjects<Init *>());
|
2011-07-30 03:07:11 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BitsInit::Profile(FoldingSetNodeID &ID) const {
|
2016-01-19 03:52:24 +08:00
|
|
|
ProfileBitsInit(ID, makeArrayRef(getTrailingObjects<Init *>(), NumBits));
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *BitsInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<BitRecTy>(Ty)) {
|
|
|
|
if (getNumBits() != 1) return nullptr; // Only accept if just one bit!
|
|
|
|
return getBit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
|
|
|
|
// If the number of bits is right, return it. Otherwise we need to expand
|
|
|
|
// or truncate.
|
|
|
|
if (getNumBits() != BRT->getNumBits()) return nullptr;
|
|
|
|
return const_cast<BitsInit *>(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isa<IntRecTy>(Ty)) {
|
|
|
|
int64_t Result = 0;
|
|
|
|
for (unsigned i = 0, e = getNumBits(); i != e; ++i)
|
|
|
|
if (auto *Bit = dyn_cast<BitInit>(getBit(i)))
|
|
|
|
Result |= static_cast<int64_t>(Bit->getValue()) << i;
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
return IntInit::get(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *
|
2016-12-05 14:41:51 +08:00
|
|
|
BitsInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
|
2011-07-30 06:43:06 +08:00
|
|
|
SmallVector<Init *, 16> NewBits(Bits.size());
|
2011-07-30 03:07:00 +08:00
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
2011-07-30 03:07:00 +08:00
|
|
|
if (Bits[i] >= getNumBits())
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-07-30 03:07:00 +08:00
|
|
|
NewBits[i] = getBit(Bits[i]);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2011-07-30 03:07:07 +08:00
|
|
|
return BitsInit::get(NewBits);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string BitsInit::getAsString() const {
|
|
|
|
std::string Result = "{ ";
|
2003-10-06 03:27:59 +08:00
|
|
|
for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
|
2007-11-23 05:05:25 +08:00
|
|
|
if (i) Result += ", ";
|
2011-07-30 06:43:06 +08:00
|
|
|
if (Init *Bit = getBit(e-i-1))
|
2007-11-23 05:05:25 +08:00
|
|
|
Result += Bit->getAsString();
|
2003-10-06 03:27:59 +08:00
|
|
|
else
|
2007-11-23 05:05:25 +08:00
|
|
|
Result += "*";
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2007-11-23 05:05:25 +08:00
|
|
|
return Result + " }";
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
// Fix bit initializer to preserve the behavior that bit reference from a unset
|
|
|
|
// bits initializer will resolve into VarBitInit to keep the field name and bit
|
|
|
|
// number used in targets with fixed insn length.
|
2018-03-05 23:20:51 +08:00
|
|
|
static Init *fixBitInit(const Resolver &R, Init *Before, Init *After) {
|
|
|
|
if (!isa<UnsetInit>(After) || !R.keepUnsetBits())
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
return After;
|
|
|
|
return Before;
|
|
|
|
}
|
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
// resolveReferences - If there are any field references that refer to fields
|
|
|
|
// that have been filled in, we can propagate the values now.
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *BitsInit::resolveReferences(Resolver &R) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
bool Changed = false;
|
2011-07-30 06:43:06 +08:00
|
|
|
SmallVector<Init *, 16> NewBits(getNumBits());
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
Init *CachedInit = nullptr;
|
|
|
|
Init *CachedBitVar = nullptr;
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
bool CachedBitVarChanged = false;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = getNumBits(); i != e; ++i) {
|
2016-01-19 03:52:24 +08:00
|
|
|
Init *CurBit = getBit(i);
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
Init *CurBitVar = CurBit->getBitVar();
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2011-07-30 03:07:00 +08:00
|
|
|
NewBits[i] = CurBit;
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
|
|
|
|
if (CurBitVar == CachedBitVar) {
|
|
|
|
if (CachedBitVarChanged) {
|
|
|
|
Init *Bit = CachedInit->getBit(CurBit->getBitNum());
|
2018-03-05 23:20:51 +08:00
|
|
|
NewBits[i] = fixBitInit(R, CurBit, Bit);
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
CachedBitVar = CurBitVar;
|
|
|
|
CachedBitVarChanged = false;
|
|
|
|
|
|
|
|
Init *B;
|
|
|
|
do {
|
|
|
|
B = CurBitVar;
|
2018-03-05 23:20:51 +08:00
|
|
|
CurBitVar = CurBitVar->resolveReferences(R);
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
CachedBitVarChanged |= B != CurBitVar;
|
|
|
|
Changed |= B != CurBitVar;
|
|
|
|
} while (B != CurBitVar);
|
|
|
|
CachedInit = CurBitVar;
|
|
|
|
|
|
|
|
if (CachedBitVarChanged) {
|
|
|
|
Init *Bit = CurBitVar->getBit(CurBit->getBitNum());
|
2018-03-05 23:20:51 +08:00
|
|
|
NewBits[i] = fixBitInit(R, CurBit, Bit);
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
}
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Changed)
|
2011-07-30 03:07:07 +08:00
|
|
|
return BitsInit::get(NewBits);
|
2011-07-30 03:07:00 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<BitsInit *>(this);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
IntInit *IntInit::get(int64_t V) {
|
2016-12-04 13:48:20 +08:00
|
|
|
static DenseMap<int64_t, IntInit*> ThePool;
|
2011-07-30 03:07:12 +08:00
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
IntInit *&I = ThePool[V];
|
|
|
|
if (!I) I = new(Allocator) IntInit(V);
|
|
|
|
return I;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string IntInit::getAsString() const {
|
|
|
|
return itostr(Value);
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
static bool canFitInBitfield(int64_t Value, unsigned NumBits) {
|
|
|
|
// For example, with NumBits == 4, we permit Values from [-7 .. 15].
|
|
|
|
return (NumBits >= sizeof(Value) * 8) ||
|
|
|
|
(Value >> NumBits == 0) || (Value >> (NumBits-1) == -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
Init *IntInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<IntRecTy>(Ty))
|
|
|
|
return const_cast<IntInit *>(this);
|
|
|
|
|
|
|
|
if (isa<BitRecTy>(Ty)) {
|
|
|
|
int64_t Val = getValue();
|
|
|
|
if (Val != 0 && Val != 1) return nullptr; // Only accept 0 or 1 for a bit!
|
|
|
|
return BitInit::get(Val != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
|
|
|
|
int64_t Value = getValue();
|
|
|
|
// Make sure this bitfield is large enough to hold the integer value.
|
|
|
|
if (!canFitInBitfield(Value, BRT->getNumBits()))
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
SmallVector<Init *, 16> NewBits(BRT->getNumBits());
|
|
|
|
for (unsigned i = 0; i != BRT->getNumBits(); ++i)
|
|
|
|
NewBits[i] = BitInit::get(Value & (1LL << i));
|
|
|
|
|
|
|
|
return BitsInit::get(NewBits);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *
|
2016-12-05 14:41:51 +08:00
|
|
|
IntInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
|
2011-07-30 06:43:06 +08:00
|
|
|
SmallVector<Init *, 16> NewBits(Bits.size());
|
2003-10-06 03:27:59 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0, e = Bits.size(); i != e; ++i) {
|
2011-07-30 03:07:00 +08:00
|
|
|
if (Bits[i] >= 64)
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-07-30 03:07:00 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
NewBits[i] = BitInit::get(Value & (INT64_C(1) << Bits[i]));
|
2011-07-12 02:25:51 +08:00
|
|
|
}
|
2011-07-30 03:07:07 +08:00
|
|
|
return BitsInit::get(NewBits);
|
|
|
|
}
|
|
|
|
|
2016-07-06 05:22:55 +08:00
|
|
|
CodeInit *CodeInit::get(StringRef V) {
|
2017-05-30 05:49:37 +08:00
|
|
|
static StringMap<CodeInit*, BumpPtrAllocator &> ThePool(Allocator);
|
2016-07-06 05:22:55 +08:00
|
|
|
|
2017-05-30 05:49:37 +08:00
|
|
|
auto &Entry = *ThePool.insert(std::make_pair(V, nullptr)).first;
|
|
|
|
if (!Entry.second)
|
|
|
|
Entry.second = new(Allocator) CodeInit(Entry.getKey());
|
|
|
|
return Entry.second;
|
2016-07-06 05:22:55 +08:00
|
|
|
}
|
|
|
|
|
2012-01-13 11:16:35 +08:00
|
|
|
StringInit *StringInit::get(StringRef V) {
|
2017-05-30 05:49:37 +08:00
|
|
|
static StringMap<StringInit*, BumpPtrAllocator &> ThePool(Allocator);
|
2011-07-30 03:07:14 +08:00
|
|
|
|
2017-05-30 05:49:37 +08:00
|
|
|
auto &Entry = *ThePool.insert(std::make_pair(V, nullptr)).first;
|
|
|
|
if (!Entry.second)
|
|
|
|
Entry.second = new(Allocator) StringInit(Entry.getKey());
|
|
|
|
return Entry.second;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *StringInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<StringRecTy>(Ty))
|
|
|
|
return const_cast<StringInit *>(this);
|
2018-02-22 23:27:03 +08:00
|
|
|
if (isa<CodeRecTy>(Ty))
|
|
|
|
return CodeInit::get(getValue());
|
2015-05-30 15:34:51 +08:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-06 05:22:55 +08:00
|
|
|
Init *CodeInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<CodeRecTy>(Ty))
|
|
|
|
return const_cast<CodeInit *>(this);
|
2018-02-22 23:27:03 +08:00
|
|
|
if (isa<StringRecTy>(Ty))
|
|
|
|
return StringInit::get(getValue());
|
2016-07-06 05:22:55 +08:00
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2011-07-30 03:07:16 +08:00
|
|
|
static void ProfileListInit(FoldingSetNodeID &ID,
|
2011-07-30 06:43:06 +08:00
|
|
|
ArrayRef<Init *> Range,
|
2011-07-30 03:07:16 +08:00
|
|
|
RecTy *EltTy) {
|
|
|
|
ID.AddInteger(Range.size());
|
|
|
|
ID.AddPointer(EltTy);
|
|
|
|
|
2015-04-29 15:13:14 +08:00
|
|
|
for (Init *I : Range)
|
|
|
|
ID.AddPointer(I);
|
2011-07-30 03:07:16 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInit *ListInit::get(ArrayRef<Init *> Range, RecTy *EltTy) {
|
2015-04-24 13:38:48 +08:00
|
|
|
static FoldingSet<ListInit> ThePool;
|
2011-07-30 03:07:16 +08:00
|
|
|
|
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileListInit(ID, Range, EltTy);
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
void *IP = nullptr;
|
2011-07-30 06:43:06 +08:00
|
|
|
if (ListInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
2011-07-30 03:07:16 +08:00
|
|
|
return I;
|
|
|
|
|
2018-02-22 23:27:12 +08:00
|
|
|
assert(Range.empty() || !isa<TypedInit>(Range[0]) ||
|
|
|
|
cast<TypedInit>(Range[0])->getType()->typeIsConvertibleTo(EltTy));
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(Range.size()),
|
|
|
|
alignof(ListInit));
|
|
|
|
ListInit *I = new(Mem) ListInit(Range.size(), EltTy);
|
2016-01-19 03:52:24 +08:00
|
|
|
std::uninitialized_copy(Range.begin(), Range.end(),
|
|
|
|
I->getTrailingObjects<Init *>());
|
2011-07-30 03:07:16 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListInit::Profile(FoldingSetNodeID &ID) const {
|
2015-04-29 15:13:05 +08:00
|
|
|
RecTy *EltTy = cast<ListRecTy>(getType())->getElementType();
|
2011-07-30 03:07:16 +08:00
|
|
|
|
2016-01-19 03:52:24 +08:00
|
|
|
ProfileListInit(ID, getValues(), EltTy);
|
2011-07-12 02:25:51 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *ListInit::convertInitializerTo(RecTy *Ty) const {
|
2016-12-05 14:41:47 +08:00
|
|
|
if (getType() == Ty)
|
|
|
|
return const_cast<ListInit*>(this);
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
if (auto *LRT = dyn_cast<ListRecTy>(Ty)) {
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init*, 8> Elements;
|
2016-12-05 14:41:47 +08:00
|
|
|
Elements.reserve(getValues().size());
|
2015-05-30 15:34:51 +08:00
|
|
|
|
|
|
|
// Verify that all of the elements of the list are subclasses of the
|
|
|
|
// appropriate class!
|
2016-12-05 14:41:47 +08:00
|
|
|
bool Changed = false;
|
|
|
|
RecTy *ElementType = LRT->getElementType();
|
2015-06-02 12:15:51 +08:00
|
|
|
for (Init *I : getValues())
|
2016-12-05 14:41:47 +08:00
|
|
|
if (Init *CI = I->convertInitializerTo(ElementType)) {
|
2015-05-30 15:34:51 +08:00
|
|
|
Elements.push_back(CI);
|
2016-12-05 14:41:47 +08:00
|
|
|
if (CI != I)
|
|
|
|
Changed = true;
|
2017-08-28 14:47:47 +08:00
|
|
|
} else
|
2015-05-30 15:34:51 +08:00
|
|
|
return nullptr;
|
|
|
|
|
2016-12-05 14:41:47 +08:00
|
|
|
if (!Changed)
|
|
|
|
return const_cast<ListInit*>(this);
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(Elements, ElementType);
|
2015-05-30 15:34:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-12-05 14:41:51 +08:00
|
|
|
Init *ListInit::convertInitListSlice(ArrayRef<unsigned> Elements) const {
|
|
|
|
SmallVector<Init*, 8> Vals;
|
2016-12-05 15:00:44 +08:00
|
|
|
Vals.reserve(Elements.size());
|
|
|
|
for (unsigned Element : Elements) {
|
|
|
|
if (Element >= size())
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2016-12-05 15:00:44 +08:00
|
|
|
Vals.push_back(getElement(Element));
|
Add initial support for list slices. This currently allows you to do stuff
like this:
def B {
list<int> X = [10, 20, 30, 4, 1, 1231, 20] [2-4,2,2,0-6];
}
... which isn't particularly useful, but more is to come.
llvm-svn: 15247
2004-07-27 07:21:34 +08:00
|
|
|
}
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(Vals, getElementType());
|
Add initial support for list slices. This currently allows you to do stuff
like this:
def B {
list<int> X = [10, 20, 30, 4, 1, 1231, 20] [2-4,2,2,0-6];
}
... which isn't particularly useful, but more is to come.
llvm-svn: 15247
2004-07-27 07:21:34 +08:00
|
|
|
}
|
|
|
|
|
2007-02-28 06:08:27 +08:00
|
|
|
Record *ListInit::getElementAsRecord(unsigned i) const {
|
2016-01-19 03:59:05 +08:00
|
|
|
assert(i < NumValues && "List element index out of range!");
|
2016-01-19 03:52:24 +08:00
|
|
|
DefInit *DI = dyn_cast<DefInit>(getElement(i));
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!DI)
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("Expected record in list!");
|
2007-02-28 06:08:27 +08:00
|
|
|
return DI->getDef();
|
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *ListInit::resolveReferences(Resolver &R) const {
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init*, 8> Resolved;
|
2015-06-02 12:15:57 +08:00
|
|
|
Resolved.reserve(size());
|
2004-07-27 09:01:21 +08:00
|
|
|
bool Changed = false;
|
|
|
|
|
2015-06-02 12:15:51 +08:00
|
|
|
for (Init *CurElt : getValues()) {
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *E;
|
2004-07-27 09:01:21 +08:00
|
|
|
|
|
|
|
do {
|
|
|
|
E = CurElt;
|
2018-03-05 23:20:51 +08:00
|
|
|
CurElt = CurElt->resolveReferences(R);
|
2004-07-27 09:01:21 +08:00
|
|
|
Changed |= E != CurElt;
|
|
|
|
} while (E != CurElt);
|
|
|
|
Resolved.push_back(E);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Changed)
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(Resolved, getElementType());
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<ListInit *>(this);
|
2004-07-27 09:01:21 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string ListInit::getAsString() const {
|
|
|
|
std::string Result = "[";
|
2016-12-05 15:00:44 +08:00
|
|
|
const char *sep = "";
|
|
|
|
for (Init *Element : *this) {
|
|
|
|
Result += sep;
|
|
|
|
sep = ", ";
|
|
|
|
Result += Element->getAsString();
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2007-11-23 05:05:25 +08:00
|
|
|
return Result + "]";
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
Init *OpInit::getBit(unsigned Bit) const {
|
|
|
|
if (getType() == BitRecTy::get())
|
|
|
|
return const_cast<OpInit*>(this);
|
|
|
|
return VarBitInit::get(const_cast<OpInit*>(this), Bit);
|
|
|
|
}
|
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
static void
|
|
|
|
ProfileUnOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *Op, RecTy *Type) {
|
|
|
|
ID.AddInteger(Opcode);
|
|
|
|
ID.AddPointer(Op);
|
|
|
|
ID.AddPointer(Type);
|
|
|
|
}
|
2011-07-30 03:07:18 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
UnOpInit *UnOpInit::get(UnaryOp Opc, Init *LHS, RecTy *Type) {
|
|
|
|
static FoldingSet<UnOpInit> ThePool;
|
2011-07-30 03:07:18 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileUnOpInit(ID, Opc, LHS, Type);
|
|
|
|
|
|
|
|
void *IP = nullptr;
|
|
|
|
if (UnOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
|
|
|
return I;
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
UnOpInit *I = new(Allocator) UnOpInit(Opc, LHS, Type);
|
2016-01-19 04:36:06 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UnOpInit::Profile(FoldingSetNodeID &ID) const {
|
|
|
|
ProfileUnOpInit(ID, getOpcode(), getOperand(), getType());
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
|
2009-05-15 05:22:49 +08:00
|
|
|
switch (getOpcode()) {
|
2017-06-16 08:43:26 +08:00
|
|
|
case CAST:
|
2015-05-28 14:38:28 +08:00
|
|
|
if (isa<StringRecTy>(getType())) {
|
2012-10-11 04:24:47 +08:00
|
|
|
if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
|
2009-06-30 04:05:29 +08:00
|
|
|
return LHSs;
|
2009-05-15 05:22:49 +08:00
|
|
|
|
2012-10-11 04:24:47 +08:00
|
|
|
if (DefInit *LHSd = dyn_cast<DefInit>(LHS))
|
2015-05-28 14:38:32 +08:00
|
|
|
return StringInit::get(LHSd->getAsString());
|
2012-01-31 04:47:04 +08:00
|
|
|
|
2012-10-11 04:24:47 +08:00
|
|
|
if (IntInit *LHSi = dyn_cast<IntInit>(LHS))
|
2012-01-31 04:47:04 +08:00
|
|
|
return StringInit::get(LHSi->getAsString());
|
2009-11-22 12:24:42 +08:00
|
|
|
} else {
|
2016-12-05 14:00:36 +08:00
|
|
|
if (StringInit *Name = dyn_cast<StringInit>(LHS)) {
|
2009-06-30 04:05:29 +08:00
|
|
|
// From TGParser::ParseIDValue
|
|
|
|
if (CurRec) {
|
|
|
|
if (const RecordVal *RV = CurRec->getValue(Name)) {
|
2010-10-06 08:19:21 +08:00
|
|
|
if (RV->getType() != getType())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("type mismatch in cast");
|
2011-07-30 03:07:07 +08:00
|
|
|
return VarInit::get(Name, RV->getType());
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
2011-10-19 21:02:42 +08:00
|
|
|
Init *TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name,
|
|
|
|
":");
|
2015-05-04 09:35:39 +08:00
|
|
|
|
2009-06-30 04:05:29 +08:00
|
|
|
if (CurRec->isTemplateArg(TemplateArgName)) {
|
|
|
|
const RecordVal *RV = CurRec->getValue(TemplateArgName);
|
|
|
|
assert(RV && "Template arg doesn't exist??");
|
2009-05-15 05:22:49 +08:00
|
|
|
|
2010-10-06 08:19:21 +08:00
|
|
|
if (RV->getType() != getType())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("type mismatch in cast");
|
2009-05-15 05:22:49 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
return VarInit::get(TemplateArgName, RV->getType());
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-30 04:05:29 +08:00
|
|
|
if (CurMultiClass) {
|
2015-05-04 09:35:39 +08:00
|
|
|
Init *MCName = QualifyName(CurMultiClass->Rec, CurMultiClass, Name,
|
|
|
|
"::");
|
2011-10-19 21:02:42 +08:00
|
|
|
|
2009-06-30 04:05:29 +08:00
|
|
|
if (CurMultiClass->Rec.isTemplateArg(MCName)) {
|
|
|
|
const RecordVal *RV = CurMultiClass->Rec.getValue(MCName);
|
|
|
|
assert(RV && "Template arg doesn't exist??");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2010-10-06 08:19:21 +08:00
|
|
|
if (RV->getType() != getType())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("type mismatch in cast");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
return VarInit::get(MCName, RV->getType());
|
2009-06-30 04:05:29 +08:00
|
|
|
}
|
|
|
|
}
|
2014-12-13 05:48:03 +08:00
|
|
|
assert(CurRec && "NULL pointer");
|
2016-12-05 14:00:36 +08:00
|
|
|
if (Record *D = (CurRec->getRecords()).getDef(Name->getValue()))
|
2011-07-19 01:02:57 +08:00
|
|
|
return DefInit::get(D);
|
2009-05-15 05:22:49 +08:00
|
|
|
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(CurRec->getLoc(),
|
2016-12-05 14:00:36 +08:00
|
|
|
"Undefined reference:'" + Name->getValue() + "'\n");
|
2009-06-30 04:05:29 +08:00
|
|
|
}
|
2015-07-31 09:12:06 +08:00
|
|
|
|
|
|
|
if (isa<IntRecTy>(getType())) {
|
|
|
|
if (BitsInit *BI = dyn_cast<BitsInit>(LHS)) {
|
|
|
|
if (Init *NewInit = BI->convertInitializerTo(IntRecTy::get()))
|
|
|
|
return NewInit;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
break;
|
2017-06-16 08:43:26 +08:00
|
|
|
|
|
|
|
case HEAD:
|
2012-10-11 04:24:47 +08:00
|
|
|
if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) {
|
2015-05-16 13:42:13 +08:00
|
|
|
assert(!LHSl->empty() && "Empty list in head");
|
2009-05-15 06:38:31 +08:00
|
|
|
return LHSl->getElement(0);
|
|
|
|
}
|
|
|
|
break;
|
2017-06-16 08:43:26 +08:00
|
|
|
|
|
|
|
case TAIL:
|
2012-10-11 04:24:47 +08:00
|
|
|
if (ListInit *LHSl = dyn_cast<ListInit>(LHS)) {
|
2015-05-16 13:42:13 +08:00
|
|
|
assert(!LHSl->empty() && "Empty list in tail");
|
2011-07-30 03:07:07 +08:00
|
|
|
// Note the +1. We can't just pass the result of getValues()
|
|
|
|
// directly.
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(LHSl->getValues().slice(1), LHSl->getElementType());
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
|
|
|
break;
|
2017-06-16 08:43:26 +08:00
|
|
|
|
2018-02-23 18:46:07 +08:00
|
|
|
case SIZE:
|
|
|
|
if (ListInit *LHSl = dyn_cast<ListInit>(LHS))
|
|
|
|
return IntInit::get(LHSl->size());
|
|
|
|
break;
|
|
|
|
|
2017-06-16 08:43:26 +08:00
|
|
|
case EMPTY:
|
2015-05-16 13:42:11 +08:00
|
|
|
if (ListInit *LHSl = dyn_cast<ListInit>(LHS))
|
|
|
|
return IntInit::get(LHSl->empty());
|
|
|
|
if (StringInit *LHSs = dyn_cast<StringInit>(LHS))
|
|
|
|
return IntInit::get(LHSs->getValue().empty());
|
2009-05-15 06:38:31 +08:00
|
|
|
break;
|
|
|
|
}
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<UnOpInit *>(this);
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *UnOpInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *lhs = LHS->resolveReferences(R);
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-05-15 05:22:49 +08:00
|
|
|
if (LHS != lhs)
|
2018-03-05 23:20:51 +08:00
|
|
|
return (UnOpInit::get(getOpcode(), lhs, getType()))
|
|
|
|
->Fold(R.getCurrentRecord(), nullptr);
|
|
|
|
return Fold(R.getCurrentRecord(), nullptr);
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string UnOpInit::getAsString() const {
|
|
|
|
std::string Result;
|
2016-01-04 14:28:49 +08:00
|
|
|
switch (getOpcode()) {
|
2009-05-15 05:22:49 +08:00
|
|
|
case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break;
|
2011-01-08 01:05:37 +08:00
|
|
|
case HEAD: Result = "!head"; break;
|
|
|
|
case TAIL: Result = "!tail"; break;
|
2018-02-23 18:46:07 +08:00
|
|
|
case SIZE: Result = "!size"; break;
|
2011-01-08 01:05:37 +08:00
|
|
|
case EMPTY: Result = "!empty"; break;
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
return Result + "(" + LHS->getAsString() + ")";
|
|
|
|
}
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
static void
|
|
|
|
ProfileBinOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *LHS, Init *RHS,
|
|
|
|
RecTy *Type) {
|
|
|
|
ID.AddInteger(Opcode);
|
|
|
|
ID.AddPointer(LHS);
|
|
|
|
ID.AddPointer(RHS);
|
|
|
|
ID.AddPointer(Type);
|
|
|
|
}
|
2011-07-30 03:07:19 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
BinOpInit *BinOpInit::get(BinaryOp Opc, Init *LHS,
|
|
|
|
Init *RHS, RecTy *Type) {
|
|
|
|
static FoldingSet<BinOpInit> ThePool;
|
2011-07-30 03:07:19 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileBinOpInit(ID, Opc, LHS, RHS, Type);
|
2011-07-30 03:07:19 +08:00
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
void *IP = nullptr;
|
|
|
|
if (BinOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
|
|
|
return I;
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
BinOpInit *I = new(Allocator) BinOpInit(Opc, LHS, RHS, Type);
|
2016-01-19 04:36:06 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BinOpInit::Profile(FoldingSetNodeID &ID) const {
|
|
|
|
ProfileBinOpInit(ID, getOpcode(), getLHS(), getRHS(), getType());
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 13:21:18 +08:00
|
|
|
static StringInit *ConcatStringInits(const StringInit *I0,
|
|
|
|
const StringInit *I1) {
|
|
|
|
SmallString<80> Concat(I0->getValue());
|
|
|
|
Concat.append(I1->getValue());
|
|
|
|
return StringInit::get(Concat);
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
|
2006-04-01 05:53:49 +08:00
|
|
|
switch (getOpcode()) {
|
2007-05-15 09:23:24 +08:00
|
|
|
case CONCAT: {
|
2012-10-11 04:24:43 +08:00
|
|
|
DagInit *LHSs = dyn_cast<DagInit>(LHS);
|
|
|
|
DagInit *RHSs = dyn_cast<DagInit>(RHS);
|
2007-05-15 09:23:24 +08:00
|
|
|
if (LHSs && RHSs) {
|
2012-10-11 04:24:43 +08:00
|
|
|
DefInit *LOp = dyn_cast<DefInit>(LHSs->getOperator());
|
|
|
|
DefInit *ROp = dyn_cast<DefInit>(RHSs->getOperator());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LOp || !ROp || LOp->getDef() != ROp->getDef())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("Concated Dag operators do not match!");
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init*, 8> Args;
|
|
|
|
SmallVector<StringInit*, 8> ArgNames;
|
2007-05-15 09:23:24 +08:00
|
|
|
for (unsigned i = 0, e = LHSs->getNumArgs(); i != e; ++i) {
|
|
|
|
Args.push_back(LHSs->getArg(i));
|
|
|
|
ArgNames.push_back(LHSs->getArgName(i));
|
|
|
|
}
|
|
|
|
for (unsigned i = 0, e = RHSs->getNumArgs(); i != e; ++i) {
|
|
|
|
Args.push_back(RHSs->getArg(i));
|
|
|
|
ArgNames.push_back(RHSs->getArgName(i));
|
|
|
|
}
|
2016-12-05 14:00:41 +08:00
|
|
|
return DagInit::get(LHSs->getOperator(), nullptr, Args, ArgNames);
|
2007-05-15 09:23:24 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2014-05-07 18:13:19 +08:00
|
|
|
case LISTCONCAT: {
|
|
|
|
ListInit *LHSs = dyn_cast<ListInit>(LHS);
|
|
|
|
ListInit *RHSs = dyn_cast<ListInit>(RHS);
|
|
|
|
if (LHSs && RHSs) {
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init *, 8> Args;
|
2014-05-07 18:13:19 +08:00
|
|
|
Args.insert(Args.end(), LHSs->begin(), LHSs->end());
|
|
|
|
Args.insert(Args.end(), RHSs->begin(), RHSs->end());
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(Args, LHSs->getElementType());
|
2014-05-07 18:13:19 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2006-04-01 05:53:49 +08:00
|
|
|
case STRCONCAT: {
|
2012-10-11 04:24:43 +08:00
|
|
|
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
|
|
|
StringInit *RHSs = dyn_cast<StringInit>(RHS);
|
2016-12-05 13:21:18 +08:00
|
|
|
if (LHSs && RHSs)
|
|
|
|
return ConcatStringInits(LHSs, RHSs);
|
2006-04-01 05:53:49 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-01-06 03:11:42 +08:00
|
|
|
case EQ: {
|
2010-06-17 07:24:12 +08:00
|
|
|
// try to fold eq comparison for 'bit' and 'int', otherwise fallback
|
|
|
|
// to string objects.
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
IntInit *L =
|
2012-10-11 04:24:43 +08:00
|
|
|
dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get()));
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
IntInit *R =
|
2012-10-11 04:24:43 +08:00
|
|
|
dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get()));
|
2010-06-17 07:24:12 +08:00
|
|
|
|
|
|
|
if (L && R)
|
2011-07-30 03:07:07 +08:00
|
|
|
return IntInit::get(L->getValue() == R->getValue());
|
2010-06-17 07:24:12 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
|
|
|
StringInit *RHSs = dyn_cast<StringInit>(RHS);
|
2010-06-17 07:24:12 +08:00
|
|
|
|
|
|
|
// Make sure we've resolved
|
2010-01-06 03:11:42 +08:00
|
|
|
if (LHSs && RHSs)
|
2011-07-30 03:07:07 +08:00
|
|
|
return IntInit::get(LHSs->getValue() == RHSs->getValue());
|
2010-01-06 03:11:42 +08:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2013-01-25 22:49:08 +08:00
|
|
|
case ADD:
|
2014-08-05 17:43:25 +08:00
|
|
|
case AND:
|
2016-11-15 14:49:28 +08:00
|
|
|
case OR:
|
2006-04-01 05:53:49 +08:00
|
|
|
case SHL:
|
|
|
|
case SRA:
|
|
|
|
case SRL: {
|
2014-07-18 01:04:27 +08:00
|
|
|
IntInit *LHSi =
|
|
|
|
dyn_cast_or_null<IntInit>(LHS->convertInitializerTo(IntRecTy::get()));
|
|
|
|
IntInit *RHSi =
|
|
|
|
dyn_cast_or_null<IntInit>(RHS->convertInitializerTo(IntRecTy::get()));
|
2006-04-01 05:53:49 +08:00
|
|
|
if (LHSi && RHSi) {
|
2008-10-17 09:33:43 +08:00
|
|
|
int64_t LHSv = LHSi->getValue(), RHSv = RHSi->getValue();
|
|
|
|
int64_t Result;
|
2006-04-01 05:53:49 +08:00
|
|
|
switch (getOpcode()) {
|
2012-02-07 13:05:23 +08:00
|
|
|
default: llvm_unreachable("Bad opcode!");
|
2013-01-25 22:49:08 +08:00
|
|
|
case ADD: Result = LHSv + RHSv; break;
|
2014-08-05 17:43:25 +08:00
|
|
|
case AND: Result = LHSv & RHSv; break;
|
2016-11-15 14:49:28 +08:00
|
|
|
case OR: Result = LHSv | RHSv; break;
|
2006-04-01 05:53:49 +08:00
|
|
|
case SHL: Result = LHSv << RHSv; break;
|
|
|
|
case SRA: Result = LHSv >> RHSv; break;
|
2008-10-17 09:33:43 +08:00
|
|
|
case SRL: Result = (uint64_t)LHSv >> (uint64_t)RHSv; break;
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
2011-07-30 03:07:07 +08:00
|
|
|
return IntInit::get(Result);
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<BinOpInit *>(this);
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *BinOpInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *lhs = LHS->resolveReferences(R);
|
|
|
|
Init *rhs = RHS->resolveReferences(R);
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2006-04-01 05:53:49 +08:00
|
|
|
if (LHS != lhs || RHS != rhs)
|
2018-03-05 23:20:51 +08:00
|
|
|
return (BinOpInit::get(getOpcode(), lhs, rhs, getType()))
|
|
|
|
->Fold(R.getCurrentRecord(), nullptr);
|
|
|
|
return Fold(R.getCurrentRecord(), nullptr);
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string BinOpInit::getAsString() const {
|
|
|
|
std::string Result;
|
2016-01-04 14:28:49 +08:00
|
|
|
switch (getOpcode()) {
|
2007-11-23 05:05:25 +08:00
|
|
|
case CONCAT: Result = "!con"; break;
|
2013-01-25 22:49:08 +08:00
|
|
|
case ADD: Result = "!add"; break;
|
2014-08-05 17:43:25 +08:00
|
|
|
case AND: Result = "!and"; break;
|
2016-11-15 14:49:28 +08:00
|
|
|
case OR: Result = "!or"; break;
|
2007-11-23 05:05:25 +08:00
|
|
|
case SHL: Result = "!shl"; break;
|
|
|
|
case SRA: Result = "!sra"; break;
|
|
|
|
case SRL: Result = "!srl"; break;
|
2010-01-06 03:11:42 +08:00
|
|
|
case EQ: Result = "!eq"; break;
|
2014-05-07 18:13:19 +08:00
|
|
|
case LISTCONCAT: Result = "!listconcat"; break;
|
2007-11-23 05:05:25 +08:00
|
|
|
case STRCONCAT: Result = "!strconcat"; break;
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
2007-11-23 05:05:25 +08:00
|
|
|
return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")";
|
2006-04-01 05:53:49 +08:00
|
|
|
}
|
|
|
|
|
2016-01-19 04:36:06 +08:00
|
|
|
static void
|
|
|
|
ProfileTernOpInit(FoldingSetNodeID &ID, unsigned Opcode, Init *LHS, Init *MHS,
|
|
|
|
Init *RHS, RecTy *Type) {
|
|
|
|
ID.AddInteger(Opcode);
|
|
|
|
ID.AddPointer(LHS);
|
|
|
|
ID.AddPointer(MHS);
|
|
|
|
ID.AddPointer(RHS);
|
|
|
|
ID.AddPointer(Type);
|
|
|
|
}
|
|
|
|
|
|
|
|
TernOpInit *TernOpInit::get(TernaryOp Opc, Init *LHS, Init *MHS, Init *RHS,
|
2015-05-04 09:35:39 +08:00
|
|
|
RecTy *Type) {
|
2016-01-19 04:36:06 +08:00
|
|
|
static FoldingSet<TernOpInit> ThePool;
|
|
|
|
|
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileTernOpInit(ID, Opc, LHS, MHS, RHS, Type);
|
|
|
|
|
|
|
|
void *IP = nullptr;
|
|
|
|
if (TernOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
|
|
|
return I;
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
TernOpInit *I = new(Allocator) TernOpInit(Opc, LHS, MHS, RHS, Type);
|
2016-01-19 04:36:06 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TernOpInit::Profile(FoldingSetNodeID &ID) const {
|
|
|
|
ProfileTernOpInit(ID, getOpcode(), getLHS(), getMHS(), getRHS(), getType());
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
static Init *ForeachApply(Init *LHS, Init *MHSe, Init *RHS, Record *CurRec) {
|
|
|
|
MapResolver R(CurRec);
|
|
|
|
R.set(LHS, MHSe);
|
|
|
|
return RHS->resolveReferences(R);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Init *ForeachDagApply(Init *LHS, DagInit *MHSd, Init *RHS,
|
|
|
|
Record *CurRec) {
|
|
|
|
bool Change = false;
|
|
|
|
Init *Val = ForeachApply(LHS, MHSd->getOperator(), RHS, CurRec);
|
|
|
|
if (Val != MHSd->getOperator())
|
|
|
|
Change = true;
|
|
|
|
|
|
|
|
SmallVector<std::pair<Init *, StringInit *>, 8> NewArgs;
|
|
|
|
for (unsigned int i = 0; i < MHSd->getNumArgs(); ++i) {
|
|
|
|
Init *Arg = MHSd->getArg(i);
|
|
|
|
Init *NewArg;
|
|
|
|
StringInit *ArgName = MHSd->getArgName(i);
|
|
|
|
|
|
|
|
if (DagInit *Argd = dyn_cast<DagInit>(Arg))
|
|
|
|
NewArg = ForeachDagApply(LHS, Argd, RHS, CurRec);
|
|
|
|
else
|
|
|
|
NewArg = ForeachApply(LHS, Arg, RHS, CurRec);
|
|
|
|
|
|
|
|
NewArgs.push_back(std::make_pair(NewArg, ArgName));
|
|
|
|
if (Arg != NewArg)
|
|
|
|
Change = true;
|
2009-05-15 06:23:47 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
if (Change)
|
|
|
|
return DagInit::get(Val, nullptr, NewArgs);
|
|
|
|
return MHSd;
|
2009-05-15 06:23:47 +08:00
|
|
|
}
|
|
|
|
|
2018-02-10 02:37:55 +08:00
|
|
|
// Applies RHS to all elements of MHS, using LHS as a temp variable.
|
2018-02-22 23:26:45 +08:00
|
|
|
static Init *ForeachHelper(Init *LHS, Init *MHS, Init *RHS, RecTy *Type,
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
Record *CurRec) {
|
|
|
|
if (DagInit *MHSd = dyn_cast<DagInit>(MHS))
|
|
|
|
return ForeachDagApply(LHS, MHSd, RHS, CurRec);
|
2009-05-15 06:23:47 +08:00
|
|
|
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
if (ListInit *MHSl = dyn_cast<ListInit>(MHS)) {
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init *, 8> NewList(MHSl->begin(), MHSl->end());
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
|
|
|
|
for (Init *&Item : NewList) {
|
|
|
|
Init *NewItem = ForeachApply(LHS, Item, RHS, CurRec);
|
|
|
|
if (NewItem != Item)
|
|
|
|
Item = NewItem;
|
2009-05-15 06:23:47 +08:00
|
|
|
}
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
return ListInit::get(NewList, cast<ListRecTy>(Type)->getElementType());
|
2009-05-15 06:23:47 +08:00
|
|
|
}
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:23:47 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *TernOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) const {
|
2009-05-15 05:54:42 +08:00
|
|
|
switch (getOpcode()) {
|
|
|
|
case SUBST: {
|
2012-10-11 04:24:43 +08:00
|
|
|
DefInit *LHSd = dyn_cast<DefInit>(LHS);
|
|
|
|
VarInit *LHSv = dyn_cast<VarInit>(LHS);
|
|
|
|
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
2009-05-15 05:54:42 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
DefInit *MHSd = dyn_cast<DefInit>(MHS);
|
|
|
|
VarInit *MHSv = dyn_cast<VarInit>(MHS);
|
|
|
|
StringInit *MHSs = dyn_cast<StringInit>(MHS);
|
2009-05-15 05:54:42 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
DefInit *RHSd = dyn_cast<DefInit>(RHS);
|
|
|
|
VarInit *RHSv = dyn_cast<VarInit>(RHS);
|
|
|
|
StringInit *RHSs = dyn_cast<StringInit>(RHS);
|
2009-05-15 05:54:42 +08:00
|
|
|
|
2015-05-14 13:54:02 +08:00
|
|
|
if (LHSd && MHSd && RHSd) {
|
|
|
|
Record *Val = RHSd->getDef();
|
|
|
|
if (LHSd->getAsString() == RHSd->getAsString())
|
|
|
|
Val = MHSd->getDef();
|
|
|
|
return DefInit::get(Val);
|
|
|
|
}
|
|
|
|
if (LHSv && MHSv && RHSv) {
|
|
|
|
std::string Val = RHSv->getName();
|
|
|
|
if (LHSv->getAsString() == RHSv->getAsString())
|
|
|
|
Val = MHSv->getName();
|
|
|
|
return VarInit::get(Val, getType());
|
|
|
|
}
|
|
|
|
if (LHSs && MHSs && RHSs) {
|
|
|
|
std::string Val = RHSs->getValue();
|
|
|
|
|
|
|
|
std::string::size_type found;
|
|
|
|
std::string::size_type idx = 0;
|
2015-05-16 13:42:03 +08:00
|
|
|
while (true) {
|
2015-05-14 13:54:02 +08:00
|
|
|
found = Val.find(LHSs->getValue(), idx);
|
2015-05-16 13:42:03 +08:00
|
|
|
if (found == std::string::npos)
|
|
|
|
break;
|
|
|
|
Val.replace(found, LHSs->getValue().size(), MHSs->getValue());
|
|
|
|
idx = found + MHSs->getValue().size();
|
|
|
|
}
|
2015-05-14 13:54:02 +08:00
|
|
|
|
|
|
|
return StringInit::get(Val);
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
break;
|
2009-11-22 12:24:42 +08:00
|
|
|
}
|
2009-05-15 05:54:42 +08:00
|
|
|
|
|
|
|
case FOREACH: {
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
if (Init *Result = ForeachHelper(LHS, MHS, RHS, getType(), CurRec))
|
2009-05-15 06:23:47 +08:00
|
|
|
return Result;
|
2009-05-15 05:54:42 +08:00
|
|
|
break;
|
|
|
|
}
|
2009-05-15 07:26:46 +08:00
|
|
|
|
|
|
|
case IF: {
|
2012-10-11 04:24:43 +08:00
|
|
|
IntInit *LHSi = dyn_cast<IntInit>(LHS);
|
2011-07-30 06:43:06 +08:00
|
|
|
if (Init *I = LHS->convertInitializerTo(IntRecTy::get()))
|
2012-10-11 04:24:43 +08:00
|
|
|
LHSi = dyn_cast<IntInit>(I);
|
2009-05-15 07:26:46 +08:00
|
|
|
if (LHSi) {
|
2015-05-04 09:35:39 +08:00
|
|
|
if (LHSi->getValue())
|
2009-05-15 07:26:46 +08:00
|
|
|
return MHS;
|
2015-05-04 09:35:39 +08:00
|
|
|
return RHS;
|
2009-05-15 07:26:46 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<TernOpInit *>(this);
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *TernOpInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *lhs = LHS->resolveReferences(R);
|
2009-06-09 03:16:56 +08:00
|
|
|
|
2016-01-04 14:28:49 +08:00
|
|
|
if (getOpcode() == IF && lhs != LHS) {
|
2012-10-11 04:24:43 +08:00
|
|
|
IntInit *Value = dyn_cast<IntInit>(lhs);
|
2011-07-30 06:43:06 +08:00
|
|
|
if (Init *I = lhs->convertInitializerTo(IntRecTy::get()))
|
2012-10-11 04:24:43 +08:00
|
|
|
Value = dyn_cast<IntInit>(I);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (Value) {
|
2009-06-09 03:16:56 +08:00
|
|
|
// Short-circuit
|
|
|
|
if (Value->getValue()) {
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *mhs = MHS->resolveReferences(R);
|
|
|
|
return (TernOpInit::get(getOpcode(), lhs, mhs, RHS, getType()))
|
|
|
|
->Fold(R.getCurrentRecord(), nullptr);
|
2009-06-09 03:16:56 +08:00
|
|
|
}
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *rhs = RHS->resolveReferences(R);
|
|
|
|
return (TernOpInit::get(getOpcode(), lhs, MHS, rhs, getType()))
|
|
|
|
->Fold(R.getCurrentRecord(), nullptr);
|
2009-06-09 03:16:56 +08:00
|
|
|
}
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *mhs = MHS->resolveReferences(R);
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
Init *rhs;
|
|
|
|
|
|
|
|
if (getOpcode() == FOREACH) {
|
|
|
|
ShadowResolver SR(R);
|
|
|
|
SR.addShadow(lhs);
|
|
|
|
rhs = RHS->resolveReferences(SR);
|
|
|
|
} else {
|
|
|
|
rhs = RHS->resolveReferences(R);
|
|
|
|
}
|
2009-06-09 03:16:56 +08:00
|
|
|
|
2009-05-15 05:54:42 +08:00
|
|
|
if (LHS != lhs || MHS != mhs || RHS != rhs)
|
2018-03-05 23:20:51 +08:00
|
|
|
return (TernOpInit::get(getOpcode(), lhs, mhs, rhs, getType()))
|
|
|
|
->Fold(R.getCurrentRecord(), nullptr);
|
|
|
|
return Fold(R.getCurrentRecord(), nullptr);
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string TernOpInit::getAsString() const {
|
|
|
|
std::string Result;
|
2016-01-04 14:28:49 +08:00
|
|
|
switch (getOpcode()) {
|
2009-05-15 05:54:42 +08:00
|
|
|
case SUBST: Result = "!subst"; break;
|
2009-11-22 12:24:42 +08:00
|
|
|
case FOREACH: Result = "!foreach"; break;
|
|
|
|
case IF: Result = "!if"; break;
|
2015-04-30 13:54:22 +08:00
|
|
|
}
|
|
|
|
return Result + "(" + LHS->getAsString() + ", " + MHS->getAsString() + ", " +
|
|
|
|
RHS->getAsString() + ")";
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
2009-04-24 05:25:15 +08:00
|
|
|
|
2016-12-05 14:00:36 +08:00
|
|
|
RecTy *TypedInit::getFieldType(StringInit *FieldName) const {
|
2012-10-05 11:32:00 +08:00
|
|
|
if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType()))
|
|
|
|
if (RecordVal *Field = RecordType->getRecord()->getValue(FieldName))
|
2010-09-04 05:00:49 +08:00
|
|
|
return Field->getType();
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2010-09-04 05:00:49 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *
|
|
|
|
TypedInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<IntRecTy>(Ty)) {
|
|
|
|
if (getType()->typeIsConvertibleTo(Ty))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isa<StringRecTy>(Ty)) {
|
|
|
|
if (isa<StringRecTy>(getType()))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-07-06 05:22:55 +08:00
|
|
|
if (isa<CodeRecTy>(Ty)) {
|
|
|
|
if (isa<CodeRecTy>(getType()))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
if (isa<BitRecTy>(Ty)) {
|
|
|
|
// Accept variable if it is already of bit type!
|
|
|
|
if (isa<BitRecTy>(getType()))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
if (auto *BitsTy = dyn_cast<BitsRecTy>(getType())) {
|
|
|
|
// Accept only bits<1> expression.
|
|
|
|
if (BitsTy->getNumBits() == 1)
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// Ternary !if can be converted to bit, but only if both sides are
|
|
|
|
// convertible to a bit.
|
|
|
|
if (const auto *TOI = dyn_cast<TernOpInit>(this)) {
|
|
|
|
if (TOI->getOpcode() == TernOpInit::TernaryOp::IF &&
|
|
|
|
TOI->getMHS()->convertInitializerTo(BitRecTy::get()) &&
|
|
|
|
TOI->getRHS()->convertInitializerTo(BitRecTy::get()))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *BRT = dyn_cast<BitsRecTy>(Ty)) {
|
|
|
|
if (BRT->getNumBits() == 1 && isa<BitRecTy>(getType()))
|
|
|
|
return BitsInit::get(const_cast<TypedInit *>(this));
|
|
|
|
|
|
|
|
if (getType()->typeIsConvertibleTo(BRT)) {
|
|
|
|
SmallVector<Init *, 16> NewBits(BRT->getNumBits());
|
|
|
|
|
|
|
|
for (unsigned i = 0; i != BRT->getNumBits(); ++i)
|
|
|
|
NewBits[i] = VarBitInit::get(const_cast<TypedInit *>(this), i);
|
|
|
|
return BitsInit::get(NewBits);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *DLRT = dyn_cast<ListRecTy>(Ty)) {
|
|
|
|
if (auto *SLRT = dyn_cast<ListRecTy>(getType()))
|
|
|
|
if (SLRT->getElementType()->typeIsConvertibleTo(DLRT->getElementType()))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *DRT = dyn_cast<DagRecTy>(Ty)) {
|
|
|
|
if (getType()->typeIsConvertibleTo(DRT))
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *SRRT = dyn_cast<RecordRecTy>(Ty)) {
|
|
|
|
// Ensure that this is compatible with Rec.
|
|
|
|
if (RecordRecTy *DRRT = dyn_cast<RecordRecTy>(getType()))
|
|
|
|
if (DRRT->getRecord()->isSubClassOf(SRRT->getRecord()) ||
|
|
|
|
DRRT->getRecord() == SRRT->getRecord())
|
|
|
|
return const_cast<TypedInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-12-05 14:41:51 +08:00
|
|
|
Init *TypedInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
|
2012-10-05 11:31:58 +08:00
|
|
|
BitsRecTy *T = dyn_cast<BitsRecTy>(getType());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!T) return nullptr; // Cannot subscript a non-bits variable.
|
2003-10-06 03:27:59 +08:00
|
|
|
unsigned NumBits = T->getNumBits();
|
|
|
|
|
2016-12-05 15:00:44 +08:00
|
|
|
SmallVector<Init *, 16> NewBits;
|
|
|
|
NewBits.reserve(Bits.size());
|
|
|
|
for (unsigned Bit : Bits) {
|
|
|
|
if (Bit >= NumBits)
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-07-30 03:07:00 +08:00
|
|
|
|
2016-12-05 15:00:44 +08:00
|
|
|
NewBits.push_back(VarBitInit::get(const_cast<TypedInit *>(this), Bit));
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2011-07-30 03:07:07 +08:00
|
|
|
return BitsInit::get(NewBits);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 14:41:51 +08:00
|
|
|
Init *TypedInit::convertInitListSlice(ArrayRef<unsigned> Elements) const {
|
2012-10-05 11:31:58 +08:00
|
|
|
ListRecTy *T = dyn_cast<ListRecTy>(getType());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!T) return nullptr; // Cannot subscript a non-list variable.
|
2004-07-27 09:01:21 +08:00
|
|
|
|
|
|
|
if (Elements.size() == 1)
|
2011-07-30 06:43:06 +08:00
|
|
|
return VarListElementInit::get(const_cast<TypedInit *>(this), Elements[0]);
|
2004-07-27 09:01:21 +08:00
|
|
|
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init*, 8> ListInits;
|
2004-07-27 09:01:21 +08:00
|
|
|
ListInits.reserve(Elements.size());
|
2016-12-05 15:00:44 +08:00
|
|
|
for (unsigned Element : Elements)
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInits.push_back(VarListElementInit::get(const_cast<TypedInit *>(this),
|
2016-12-05 15:00:44 +08:00
|
|
|
Element));
|
2018-02-22 23:26:45 +08:00
|
|
|
return ListInit::get(ListInits, T->getElementType());
|
2004-07-27 09:01:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-04 13:48:03 +08:00
|
|
|
VarInit *VarInit::get(StringRef VN, RecTy *T) {
|
2011-10-19 21:02:33 +08:00
|
|
|
Init *Value = StringInit::get(VN);
|
|
|
|
return VarInit::get(Value, T);
|
|
|
|
}
|
|
|
|
|
|
|
|
VarInit *VarInit::get(Init *VN, RecTy *T) {
|
2017-06-16 08:43:26 +08:00
|
|
|
using Key = std::pair<RecTy *, Init *>;
|
2016-12-04 13:48:20 +08:00
|
|
|
static DenseMap<Key, VarInit*> ThePool;
|
2011-07-30 03:07:21 +08:00
|
|
|
|
|
|
|
Key TheKey(std::make_pair(T, VN));
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
VarInit *&I = ThePool[TheKey];
|
|
|
|
if (!I)
|
|
|
|
I = new(Allocator) VarInit(VN, T);
|
|
|
|
return I;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2016-12-04 13:48:16 +08:00
|
|
|
StringRef VarInit::getName() const {
|
2015-04-29 15:13:05 +08:00
|
|
|
StringInit *NameString = cast<StringInit>(getNameInit());
|
2011-10-19 21:02:33 +08:00
|
|
|
return NameString->getValue();
|
|
|
|
}
|
|
|
|
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
Init *VarInit::getBit(unsigned Bit) const {
|
|
|
|
if (getType() == BitRecTy::get())
|
|
|
|
return const_cast<VarInit*>(this);
|
|
|
|
return VarBitInit::get(const_cast<VarInit*>(this), Bit);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *VarInit::resolveReferences(Resolver &R) const {
|
|
|
|
if (Init *Val = R.resolve(VarName))
|
|
|
|
return Val;
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<VarInit *>(this);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2005-04-22 08:00:37 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
VarBitInit *VarBitInit::get(TypedInit *T, unsigned B) {
|
2017-06-16 08:43:26 +08:00
|
|
|
using Key = std::pair<TypedInit *, unsigned>;
|
2016-12-04 13:48:20 +08:00
|
|
|
static DenseMap<Key, VarBitInit*> ThePool;
|
2011-07-30 03:07:22 +08:00
|
|
|
|
|
|
|
Key TheKey(std::make_pair(T, B));
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
VarBitInit *&I = ThePool[TheKey];
|
|
|
|
if (!I)
|
|
|
|
I = new(Allocator) VarBitInit(T, B);
|
|
|
|
return I;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *VarBitInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<BitRecTy>(Ty))
|
|
|
|
return const_cast<VarBitInit *>(this);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string VarBitInit::getAsString() const {
|
2015-05-04 09:35:39 +08:00
|
|
|
return TI->getAsString() + "{" + utostr(Bit) + "}";
|
2007-11-23 05:05:25 +08:00
|
|
|
}
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *VarBitInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *I = TI->resolveReferences(R);
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
if (TI != I)
|
|
|
|
return I->getBit(getBitNum());
|
|
|
|
|
|
|
|
return const_cast<VarBitInit*>(this);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
VarListElementInit *VarListElementInit::get(TypedInit *T,
|
|
|
|
unsigned E) {
|
2017-06-16 08:43:26 +08:00
|
|
|
using Key = std::pair<TypedInit *, unsigned>;
|
2016-12-04 13:48:20 +08:00
|
|
|
static DenseMap<Key, VarListElementInit*> ThePool;
|
2011-07-30 03:07:23 +08:00
|
|
|
|
|
|
|
Key TheKey(std::make_pair(T, E));
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
VarListElementInit *&I = ThePool[TheKey];
|
|
|
|
if (!I) I = new(Allocator) VarListElementInit(T, E);
|
|
|
|
return I;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string VarListElementInit::getAsString() const {
|
|
|
|
return TI->getAsString() + "[" + utostr(Element) + "]";
|
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *VarListElementInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *NewTI = TI->resolveReferences(R);
|
2018-02-26 04:50:04 +08:00
|
|
|
if (ListInit *List = dyn_cast<ListInit>(NewTI)) {
|
|
|
|
// Leave out-of-bounds array references as-is. This can happen without
|
|
|
|
// being an error, e.g. in the untaken "branch" of an !if expression.
|
|
|
|
if (getElementNum() < List->size())
|
|
|
|
return List->getElement(getElementNum());
|
|
|
|
}
|
|
|
|
if (NewTI != TI && isa<TypedInit>(NewTI))
|
|
|
|
return VarListElementInit::get(cast<TypedInit>(NewTI), getElementNum());
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<VarListElementInit *>(this);
|
2004-07-27 09:01:21 +08:00
|
|
|
}
|
|
|
|
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
Init *VarListElementInit::getBit(unsigned Bit) const {
|
|
|
|
if (getType() == BitRecTy::get())
|
|
|
|
return const_cast<VarListElementInit*>(this);
|
|
|
|
return VarBitInit::get(const_cast<VarListElementInit*>(this), Bit);
|
2004-07-27 09:01:21 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
DefInit *DefInit::get(Record *R) {
|
2011-07-19 01:02:57 +08:00
|
|
|
return R->getDefInit();
|
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *DefInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (auto *RRT = dyn_cast<RecordRecTy>(Ty))
|
|
|
|
if (getDef()->isSubClassOf(RRT->getRecord()))
|
|
|
|
return const_cast<DefInit *>(this);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-12-05 14:00:36 +08:00
|
|
|
RecTy *DefInit::getFieldType(StringInit *FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
if (const RecordVal *RV = Def->getValue(FieldName))
|
|
|
|
return RV->getType();
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string DefInit::getAsString() const {
|
|
|
|
return Def->getName();
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 14:00:36 +08:00
|
|
|
FieldInit *FieldInit::get(Init *R, StringInit *FN) {
|
2017-06-16 08:43:26 +08:00
|
|
|
using Key = std::pair<Init *, StringInit *>;
|
2016-12-04 13:48:20 +08:00
|
|
|
static DenseMap<Key, FieldInit*> ThePool;
|
2011-07-30 03:07:24 +08:00
|
|
|
|
|
|
|
Key TheKey(std::make_pair(R, FN));
|
|
|
|
|
2016-12-04 13:48:20 +08:00
|
|
|
FieldInit *&I = ThePool[TheKey];
|
|
|
|
if (!I) I = new(Allocator) FieldInit(R, FN);
|
|
|
|
return I;
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
Init *FieldInit::getBit(unsigned Bit) const {
|
|
|
|
if (getType() == BitRecTy::get())
|
|
|
|
return const_cast<FieldInit*>(this);
|
|
|
|
return VarBitInit::get(const_cast<FieldInit*>(this), Bit);
|
2004-07-27 09:01:21 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *FieldInit::resolveReferences(Resolver &R) const {
|
|
|
|
Init *NewRec = Rec->resolveReferences(R);
|
2005-04-19 11:36:21 +08:00
|
|
|
|
2018-02-26 04:50:11 +08:00
|
|
|
if (DefInit *DI = dyn_cast<DefInit>(NewRec)) {
|
|
|
|
Init *FieldVal = DI->getDef()->getValue(FieldName)->getValue();
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *BVR = FieldVal->resolveReferences(R);
|
2018-02-26 04:50:11 +08:00
|
|
|
if (BVR->isComplete())
|
|
|
|
return BVR;
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
2005-04-19 11:36:21 +08:00
|
|
|
|
2015-05-04 09:35:39 +08:00
|
|
|
if (NewRec != Rec)
|
2011-07-30 03:07:07 +08:00
|
|
|
return FieldInit::get(NewRec, FieldName);
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<FieldInit *>(this);
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 14:00:41 +08:00
|
|
|
static void ProfileDagInit(FoldingSetNodeID &ID, Init *V, StringInit *VN,
|
2013-02-15 20:30:38 +08:00
|
|
|
ArrayRef<Init *> ArgRange,
|
2016-12-05 14:00:46 +08:00
|
|
|
ArrayRef<StringInit *> NameRange) {
|
2011-07-30 03:07:26 +08:00
|
|
|
ID.AddPointer(V);
|
2016-12-05 14:00:41 +08:00
|
|
|
ID.AddPointer(VN);
|
2011-07-30 03:07:26 +08:00
|
|
|
|
2016-12-05 14:00:46 +08:00
|
|
|
ArrayRef<Init *>::iterator Arg = ArgRange.begin();
|
|
|
|
ArrayRef<StringInit *>::iterator Name = NameRange.begin();
|
2011-07-30 03:07:26 +08:00
|
|
|
while (Arg != ArgRange.end()) {
|
|
|
|
assert(Name != NameRange.end() && "Arg name underflow!");
|
|
|
|
ID.AddPointer(*Arg++);
|
2016-12-05 14:00:46 +08:00
|
|
|
ID.AddPointer(*Name++);
|
2011-07-30 03:07:26 +08:00
|
|
|
}
|
|
|
|
assert(Name == NameRange.end() && "Arg name overflow!");
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
DagInit *
|
2016-12-05 14:00:41 +08:00
|
|
|
DagInit::get(Init *V, StringInit *VN, ArrayRef<Init *> ArgRange,
|
2016-12-05 14:00:46 +08:00
|
|
|
ArrayRef<StringInit *> NameRange) {
|
2015-04-24 13:38:48 +08:00
|
|
|
static FoldingSet<DagInit> ThePool;
|
2011-07-30 03:07:26 +08:00
|
|
|
|
|
|
|
FoldingSetNodeID ID;
|
|
|
|
ProfileDagInit(ID, V, VN, ArgRange, NameRange);
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
void *IP = nullptr;
|
2011-07-30 06:43:06 +08:00
|
|
|
if (DagInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
|
2011-07-30 03:07:26 +08:00
|
|
|
return I;
|
|
|
|
|
2017-05-28 01:36:50 +08:00
|
|
|
void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *, StringInit *>(ArgRange.size(), NameRange.size()), alignof(BitsInit));
|
|
|
|
DagInit *I = new(Mem) DagInit(V, VN, ArgRange.size(), NameRange.size());
|
|
|
|
std::uninitialized_copy(ArgRange.begin(), ArgRange.end(),
|
|
|
|
I->getTrailingObjects<Init *>());
|
|
|
|
std::uninitialized_copy(NameRange.begin(), NameRange.end(),
|
|
|
|
I->getTrailingObjects<StringInit *>());
|
2011-07-30 03:07:26 +08:00
|
|
|
ThePool.InsertNode(I, IP);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
DagInit *
|
2016-12-05 14:00:41 +08:00
|
|
|
DagInit::get(Init *V, StringInit *VN,
|
2016-12-05 14:41:51 +08:00
|
|
|
ArrayRef<std::pair<Init*, StringInit*>> args) {
|
|
|
|
SmallVector<Init *, 8> Args;
|
|
|
|
SmallVector<StringInit *, 8> Names;
|
2011-07-30 03:07:07 +08:00
|
|
|
|
2015-04-29 15:13:14 +08:00
|
|
|
for (const auto &Arg : args) {
|
|
|
|
Args.push_back(Arg.first);
|
|
|
|
Names.push_back(Arg.second);
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return DagInit::get(V, VN, Args, Names);
|
|
|
|
}
|
|
|
|
|
2011-07-30 03:07:26 +08:00
|
|
|
void DagInit::Profile(FoldingSetNodeID &ID) const {
|
2017-05-28 01:36:50 +08:00
|
|
|
ProfileDagInit(ID, Val, ValName, makeArrayRef(getTrailingObjects<Init *>(), NumArgs), makeArrayRef(getTrailingObjects<StringInit *>(), NumArgNames));
|
2011-07-30 03:07:07 +08:00
|
|
|
}
|
|
|
|
|
2015-05-30 15:34:51 +08:00
|
|
|
Init *DagInit::convertInitializerTo(RecTy *Ty) const {
|
|
|
|
if (isa<DagRecTy>(Ty))
|
|
|
|
return const_cast<DagInit *>(this);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *DagInit::resolveReferences(Resolver &R) const {
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<Init*, 8> NewArgs;
|
2017-05-28 01:36:50 +08:00
|
|
|
NewArgs.reserve(arg_size());
|
2016-12-05 14:41:51 +08:00
|
|
|
bool ArgsChanged = false;
|
2017-05-30 05:49:34 +08:00
|
|
|
for (const Init *Arg : getArgs()) {
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *NewArg = Arg->resolveReferences(R);
|
2016-12-05 14:41:51 +08:00
|
|
|
NewArgs.push_back(NewArg);
|
|
|
|
ArgsChanged |= NewArg != Arg;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *Op = Val->resolveReferences(R);
|
2016-12-05 14:41:51 +08:00
|
|
|
if (Op != Val || ArgsChanged)
|
2017-05-28 01:36:50 +08:00
|
|
|
return DagInit::get(Op, ValName, NewArgs, getArgNames());
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
return const_cast<DagInit *>(this);
|
2006-01-31 14:02:35 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 05:05:25 +08:00
|
|
|
std::string DagInit::getAsString() const {
|
|
|
|
std::string Result = "(" + Val->getAsString();
|
2016-12-05 14:00:41 +08:00
|
|
|
if (ValName)
|
|
|
|
Result += ":" + ValName->getAsUnquotedString();
|
2017-05-28 01:36:50 +08:00
|
|
|
if (!arg_empty()) {
|
|
|
|
Result += " " + getArg(0)->getAsString();
|
|
|
|
if (getArgName(0)) Result += ":$" + getArgName(0)->getAsUnquotedString();
|
|
|
|
for (unsigned i = 1, e = getNumArgs(); i != e; ++i) {
|
|
|
|
Result += ", " + getArg(i)->getAsString();
|
|
|
|
if (getArgName(i)) Result += ":$" + getArgName(i)->getAsUnquotedString();
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
}
|
2007-11-23 05:05:25 +08:00
|
|
|
return Result + ")";
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Other implementations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-06-04 15:40:12 +08:00
|
|
|
RecordVal::RecordVal(Init *N, RecTy *T, bool P)
|
2016-12-05 13:21:13 +08:00
|
|
|
: Name(N), TyAndPrefix(T, P) {
|
|
|
|
Value = UnsetInit::get()->convertInitializerTo(T);
|
2003-10-06 03:27:59 +08:00
|
|
|
assert(Value && "Cannot create unset value for current type!");
|
|
|
|
}
|
|
|
|
|
2016-12-04 13:48:16 +08:00
|
|
|
StringRef RecordVal::getName() const {
|
2015-06-04 15:40:12 +08:00
|
|
|
return cast<StringInit>(getNameInit())->getValue();
|
2011-09-03 04:12:07 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void RecordVal::dump() const { errs() << *this; }
|
2017-01-28 10:02:38 +08:00
|
|
|
#endif
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2009-07-03 08:10:29 +08:00
|
|
|
void RecordVal::print(raw_ostream &OS, bool PrintSem) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
if (getPrefix()) OS << "field ";
|
2011-10-19 21:02:52 +08:00
|
|
|
OS << *getType() << " " << getNameInitAsString();
|
2005-04-19 11:36:21 +08:00
|
|
|
|
|
|
|
if (getValue())
|
2003-10-06 03:27:59 +08:00
|
|
|
OS << " = " << *getValue();
|
2005-04-19 11:36:21 +08:00
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
if (PrintSem) OS << ";\n";
|
|
|
|
}
|
|
|
|
|
2009-08-23 17:47:37 +08:00
|
|
|
unsigned Record::LastID = 0;
|
|
|
|
|
2011-10-19 21:02:45 +08:00
|
|
|
void Record::init() {
|
|
|
|
checkName();
|
2011-10-19 21:04:13 +08:00
|
|
|
|
|
|
|
// Every record potentially has a def at the top. This value is
|
|
|
|
// replaced with the top-level def name at instantiation time.
|
2017-06-01 14:56:16 +08:00
|
|
|
addValue(RecordVal(StringInit::get("NAME"), StringRecTy::get(), false));
|
2011-10-19 21:02:45 +08:00
|
|
|
}
|
|
|
|
|
2011-08-11 02:27:46 +08:00
|
|
|
void Record::checkName() {
|
|
|
|
// Ensure the record name has string type.
|
2015-04-29 15:13:05 +08:00
|
|
|
const TypedInit *TypedName = cast<const TypedInit>(Name);
|
2015-06-06 09:34:00 +08:00
|
|
|
if (!isa<StringRecTy>(TypedName->getType()))
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record name is not a string!");
|
2011-08-11 02:27:46 +08:00
|
|
|
}
|
|
|
|
|
2011-07-19 01:02:57 +08:00
|
|
|
DefInit *Record::getDefInit() {
|
2015-06-24 14:19:19 +08:00
|
|
|
if (!TheInit)
|
2016-12-04 13:48:20 +08:00
|
|
|
TheInit = new(Allocator) DefInit(this, new(Allocator) RecordRecTy(this));
|
|
|
|
return TheInit;
|
2011-07-19 01:02:57 +08:00
|
|
|
}
|
|
|
|
|
2011-08-11 02:27:46 +08:00
|
|
|
void Record::setName(Init *NewName) {
|
2011-10-19 21:03:25 +08:00
|
|
|
Name = NewName;
|
2011-08-11 02:27:46 +08:00
|
|
|
checkName();
|
|
|
|
// DO NOT resolve record values to the name at this point because
|
|
|
|
// there might be default values for arguments of this def. Those
|
|
|
|
// arguments might not have been resolved yet so we don't want to
|
|
|
|
// prematurely assume values for those arguments were not passed to
|
|
|
|
// this def.
|
|
|
|
//
|
|
|
|
// Nonetheless, it may be that some of this Record's values
|
|
|
|
// reference the record name. Indeed, the reason for having the
|
|
|
|
// record name be an Init is to provide this flexibility. The extra
|
|
|
|
// resolve steps after completely instantiating defs takes care of
|
|
|
|
// this. See TGParser::ParseDef and TGParser::ParseDefm.
|
|
|
|
}
|
|
|
|
|
2018-03-05 23:21:11 +08:00
|
|
|
void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
|
2016-12-05 15:00:44 +08:00
|
|
|
for (RecordVal &Value : Values) {
|
2018-03-05 23:21:11 +08:00
|
|
|
if (SkipVal == &Value) // Skip resolve the same field as the given one
|
2012-03-08 00:39:35 +08:00
|
|
|
continue;
|
2018-03-05 23:21:11 +08:00
|
|
|
if (Init *V = Value.getValue()) {
|
|
|
|
Init *VR = V->resolveReferences(R);
|
|
|
|
if (Value.setValue(VR))
|
2015-04-30 13:54:22 +08:00
|
|
|
PrintFatalError(getLoc(), "Invalid value is found when setting '" +
|
2018-03-05 23:21:11 +08:00
|
|
|
Value.getNameInitAsString() +
|
|
|
|
"' after resolving references: " +
|
|
|
|
VR->getAsUnquotedString() + "\n");
|
|
|
|
}
|
2005-04-19 11:36:21 +08:00
|
|
|
}
|
2011-10-19 21:03:30 +08:00
|
|
|
Init *OldName = getNameInit();
|
2018-03-05 23:21:11 +08:00
|
|
|
Init *NewName = Name->resolveReferences(R);
|
2011-10-19 21:03:30 +08:00
|
|
|
if (NewName != OldName) {
|
|
|
|
// Re-register with RecordKeeper.
|
|
|
|
setName(NewName);
|
|
|
|
}
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 23:21:11 +08:00
|
|
|
void Record::resolveReferences() {
|
|
|
|
RecordResolver R(*this);
|
|
|
|
resolveReferences(R);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Record::resolveReferencesTo(const RecordVal *RV) {
|
|
|
|
RecordValResolver R(*this, RV);
|
|
|
|
resolveReferences(R, RV);
|
|
|
|
}
|
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void Record::dump() const { errs() << *this; }
|
2017-01-28 10:02:38 +08:00
|
|
|
#endif
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2009-07-03 08:10:29 +08:00
|
|
|
raw_ostream &llvm::operator<<(raw_ostream &OS, const Record &R) {
|
2011-10-19 21:02:57 +08:00
|
|
|
OS << R.getNameInitAsString();
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> TArgs = R.getTemplateArgs();
|
2003-10-06 03:27:59 +08:00
|
|
|
if (!TArgs.empty()) {
|
|
|
|
OS << "<";
|
2015-06-04 15:40:14 +08:00
|
|
|
bool NeedComma = false;
|
|
|
|
for (const Init *TA : TArgs) {
|
|
|
|
if (NeedComma) OS << ", ";
|
|
|
|
NeedComma = true;
|
|
|
|
const RecordVal *RV = R.getValue(TA);
|
2003-10-06 03:27:59 +08:00
|
|
|
assert(RV && "Template argument record not found??");
|
|
|
|
RV->print(OS, false);
|
|
|
|
}
|
|
|
|
OS << ">";
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << " {";
|
2016-01-19 03:52:37 +08:00
|
|
|
ArrayRef<std::pair<Record *, SMRange>> SC = R.getSuperClasses();
|
2003-10-06 03:27:59 +08:00
|
|
|
if (!SC.empty()) {
|
|
|
|
OS << "\t//";
|
2016-01-19 03:52:37 +08:00
|
|
|
for (const auto &SuperPair : SC)
|
|
|
|
OS << " " << SuperPair.first->getNameInitAsString();
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
OS << "\n";
|
|
|
|
|
2015-06-04 15:40:14 +08:00
|
|
|
for (const RecordVal &Val : R.getValues())
|
2016-12-05 15:35:13 +08:00
|
|
|
if (Val.getPrefix() && !R.isTemplateArg(Val.getNameInit()))
|
2015-06-04 15:40:14 +08:00
|
|
|
OS << Val;
|
|
|
|
for (const RecordVal &Val : R.getValues())
|
2016-12-05 15:35:13 +08:00
|
|
|
if (!Val.getPrefix() && !R.isTemplateArg(Val.getNameInit()))
|
2015-06-04 15:40:14 +08:00
|
|
|
OS << Val;
|
2003-10-06 03:27:59 +08:00
|
|
|
|
|
|
|
return OS << "}\n";
|
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *Record::getValueInit(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
return R->getValue();
|
|
|
|
}
|
|
|
|
|
2017-06-01 03:01:11 +08:00
|
|
|
StringRef Record::getValueAsString(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (StringInit *SI = dyn_cast<StringInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return SI->getValue();
|
2016-07-06 05:22:55 +08:00
|
|
|
if (CodeInit *CI = dyn_cast<CodeInit>(R->getValue()))
|
|
|
|
return CI->getValue();
|
|
|
|
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a string initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
BitsInit *Record::getValueAsBitsInit(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (BitsInit *BI = dyn_cast<BitsInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return BI;
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a BitsInit initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInit *Record::getValueAsListInit(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (ListInit *LI = dyn_cast<ListInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return LI;
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a list initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2009-11-22 12:24:42 +08:00
|
|
|
std::vector<Record*>
|
2009-09-19 02:31:37 +08:00
|
|
|
Record::getValueAsListOfDefs(StringRef FieldName) const {
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInit *List = getValueAsListInit(FieldName);
|
2005-10-29 05:46:31 +08:00
|
|
|
std::vector<Record*> Defs;
|
2015-06-02 12:15:51 +08:00
|
|
|
for (Init *I : List->getValues()) {
|
|
|
|
if (DefInit *DI = dyn_cast<DefInit>(I))
|
2005-10-29 05:46:31 +08:00
|
|
|
Defs.push_back(DI->getDef());
|
2015-05-04 09:35:39 +08:00
|
|
|
else
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' list is not entirely DefInit!");
|
2005-10-29 05:46:31 +08:00
|
|
|
}
|
|
|
|
return Defs;
|
|
|
|
}
|
|
|
|
|
2009-09-19 02:31:37 +08:00
|
|
|
int64_t Record::getValueAsInt(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (IntInit *II = dyn_cast<IntInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return II->getValue();
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have an int initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2009-11-22 12:24:42 +08:00
|
|
|
std::vector<int64_t>
|
2009-09-19 02:31:37 +08:00
|
|
|
Record::getValueAsListOfInts(StringRef FieldName) const {
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInit *List = getValueAsListInit(FieldName);
|
2008-10-17 09:33:43 +08:00
|
|
|
std::vector<int64_t> Ints;
|
2015-06-02 12:15:51 +08:00
|
|
|
for (Init *I : List->getValues()) {
|
|
|
|
if (IntInit *II = dyn_cast<IntInit>(I))
|
2007-11-11 19:19:37 +08:00
|
|
|
Ints.push_back(II->getValue());
|
2015-05-04 09:35:39 +08:00
|
|
|
else
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a list of ints initializer!");
|
2007-11-11 19:19:37 +08:00
|
|
|
}
|
|
|
|
return Ints;
|
|
|
|
}
|
|
|
|
|
2017-06-01 03:01:11 +08:00
|
|
|
std::vector<StringRef>
|
2011-06-28 05:06:21 +08:00
|
|
|
Record::getValueAsListOfStrings(StringRef FieldName) const {
|
2011-07-30 06:43:06 +08:00
|
|
|
ListInit *List = getValueAsListInit(FieldName);
|
2017-06-01 03:01:11 +08:00
|
|
|
std::vector<StringRef> Strings;
|
2015-06-02 12:15:51 +08:00
|
|
|
for (Init *I : List->getValues()) {
|
|
|
|
if (StringInit *SI = dyn_cast<StringInit>(I))
|
|
|
|
Strings.push_back(SI->getValue());
|
2015-05-04 09:35:39 +08:00
|
|
|
else
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a list of strings initializer!");
|
2011-06-28 05:06:21 +08:00
|
|
|
}
|
|
|
|
return Strings;
|
|
|
|
}
|
|
|
|
|
2009-09-19 02:31:37 +08:00
|
|
|
Record *Record::getValueAsDef(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (DefInit *DI = dyn_cast<DefInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return DI->getDef();
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a def initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2009-09-19 02:31:37 +08:00
|
|
|
bool Record::getValueAsBit(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (BitInit *BI = dyn_cast<BitInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return BI->getValue();
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a bit initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2012-08-24 03:34:46 +08:00
|
|
|
bool Record::getValueAsBitOrUnset(StringRef FieldName, bool &Unset) const {
|
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
|
|
|
"' does not have a field named `" + FieldName.str() + "'!\n");
|
2012-08-24 03:34:46 +08:00
|
|
|
|
2015-04-22 10:09:45 +08:00
|
|
|
if (isa<UnsetInit>(R->getValue())) {
|
2012-08-24 03:34:46 +08:00
|
|
|
Unset = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Unset = false;
|
2012-10-11 04:24:43 +08:00
|
|
|
if (BitInit *BI = dyn_cast<BitInit>(R->getValue()))
|
2012-08-24 03:34:46 +08:00
|
|
|
return BI->getValue();
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a bit initializer!");
|
2012-08-24 03:34:46 +08:00
|
|
|
}
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
DagInit *Record::getValueAsDag(StringRef FieldName) const {
|
2003-10-06 03:27:59 +08:00
|
|
|
const RecordVal *R = getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!R || !R->getValue())
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() +
|
2014-03-30 01:17:15 +08:00
|
|
|
"' does not have a field named `" + FieldName + "'!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (DagInit *DI = dyn_cast<DagInit>(R->getValue()))
|
2003-10-06 03:27:59 +08:00
|
|
|
return DI;
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError(getLoc(), "Record `" + getName() + "', field `" +
|
2014-03-30 01:17:15 +08:00
|
|
|
FieldName + "' does not have a dag initializer!");
|
2003-10-06 03:27:59 +08:00
|
|
|
}
|
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void MultiClass::dump() const {
|
2009-07-03 08:10:29 +08:00
|
|
|
errs() << "Record:\n";
|
2009-04-25 00:55:41 +08:00
|
|
|
Rec.dump();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-07-03 08:10:29 +08:00
|
|
|
errs() << "Defs:\n";
|
2015-05-04 09:35:39 +08:00
|
|
|
for (const auto &Proto : DefPrototypes)
|
2015-04-29 15:13:14 +08:00
|
|
|
Proto->dump();
|
2009-04-25 00:55:41 +08:00
|
|
|
}
|
|
|
|
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void RecordKeeper::dump() const { errs() << *this; }
|
2017-01-28 10:02:38 +08:00
|
|
|
#endif
|
2003-10-06 03:27:59 +08:00
|
|
|
|
2009-07-03 08:10:29 +08:00
|
|
|
raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
|
2003-10-06 03:27:59 +08:00
|
|
|
OS << "------------- Classes -----------------\n";
|
2015-05-12 13:25:10 +08:00
|
|
|
for (const auto &C : RK.getClasses())
|
2014-08-25 03:10:49 +08:00
|
|
|
OS << "class " << *C.second;
|
2005-04-22 08:00:37 +08:00
|
|
|
|
2003-10-06 03:27:59 +08:00
|
|
|
OS << "------------- Defs -----------------\n";
|
2015-05-12 13:25:10 +08:00
|
|
|
for (const auto &D : RK.getDefs())
|
2014-08-25 03:10:49 +08:00
|
|
|
OS << "def " << *D.second;
|
2003-10-06 03:27:59 +08:00
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
2016-07-14 22:53:11 +08:00
|
|
|
std::vector<Record *>
|
2016-12-04 13:48:03 +08:00
|
|
|
RecordKeeper::getAllDerivedDefinitions(StringRef ClassName) const {
|
2010-12-13 08:20:52 +08:00
|
|
|
Record *Class = getClass(ClassName);
|
2003-10-06 03:27:59 +08:00
|
|
|
if (!Class)
|
2012-10-26 04:33:17 +08:00
|
|
|
PrintFatalError("ERROR: Couldn't find the `" + ClassName + "' class!\n");
|
2003-10-06 03:27:59 +08:00
|
|
|
|
|
|
|
std::vector<Record*> Defs;
|
2014-08-25 03:10:49 +08:00
|
|
|
for (const auto &D : getDefs())
|
|
|
|
if (D.second->isSubClassOf(Class))
|
2014-08-25 03:10:57 +08:00
|
|
|
Defs.push_back(D.second.get());
|
2003-10-06 03:27:59 +08:00
|
|
|
|
|
|
|
return Defs;
|
|
|
|
}
|
2003-11-12 06:41:34 +08:00
|
|
|
|
2016-12-05 13:21:18 +08:00
|
|
|
static Init *GetStrConcat(Init *I0, Init *I1) {
|
|
|
|
// Shortcut for the common case of concatenating two strings.
|
|
|
|
if (const StringInit *I0s = dyn_cast<StringInit>(I0))
|
|
|
|
if (const StringInit *I1s = dyn_cast<StringInit>(I1))
|
|
|
|
return ConcatStringInits(I0s, I1s);
|
|
|
|
return BinOpInit::get(BinOpInit::STRCONCAT, I0, I1, StringRecTy::get());
|
|
|
|
}
|
|
|
|
|
2011-10-19 21:02:36 +08:00
|
|
|
Init *llvm::QualifyName(Record &CurRec, MultiClass *CurMultiClass,
|
2016-12-04 13:48:03 +08:00
|
|
|
Init *Name, StringRef Scoper) {
|
2016-12-05 13:21:18 +08:00
|
|
|
Init *NewName = GetStrConcat(CurRec.getNameInit(), StringInit::get(Scoper));
|
|
|
|
NewName = GetStrConcat(NewName, Name);
|
2011-10-19 21:02:36 +08:00
|
|
|
if (CurMultiClass && Scoper != "::") {
|
2016-12-05 13:21:18 +08:00
|
|
|
Init *Prefix = GetStrConcat(CurMultiClass->Rec.getNameInit(),
|
|
|
|
StringInit::get("::"));
|
|
|
|
NewName = GetStrConcat(Prefix, NewName);
|
2011-10-19 21:02:36 +08:00
|
|
|
}
|
|
|
|
|
2016-12-05 13:21:18 +08:00
|
|
|
if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName))
|
|
|
|
NewName = BinOp->Fold(&CurRec, CurMultiClass);
|
|
|
|
return NewName;
|
2011-10-19 21:02:36 +08:00
|
|
|
}
|
2018-03-05 23:20:51 +08:00
|
|
|
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
Init *MapResolver::resolve(Init *VarName) {
|
|
|
|
auto It = Map.find(VarName);
|
|
|
|
if (It == Map.end())
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
Init *I = It->second.V;
|
|
|
|
|
|
|
|
if (!It->second.Resolved && Map.size() > 1) {
|
|
|
|
// Resolve mutual references among the mapped variables, but prevent
|
|
|
|
// infinite recursion.
|
|
|
|
Map.erase(It);
|
|
|
|
I = I->resolveReferences(*this);
|
|
|
|
Map[VarName] = {I, true};
|
|
|
|
}
|
|
|
|
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
2018-03-05 23:20:51 +08:00
|
|
|
Init *RecordResolver::resolve(Init *VarName) {
|
|
|
|
Init *Val = Cache.lookup(VarName);
|
|
|
|
if (Val)
|
|
|
|
return Val;
|
|
|
|
|
|
|
|
for (Init *S : Stack) {
|
|
|
|
if (S == VarName)
|
|
|
|
return nullptr; // prevent infinite recursion
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RecordVal *RV = getCurrentRecord()->getValue(VarName)) {
|
|
|
|
if (!isa<UnsetInit>(RV->getValue())) {
|
|
|
|
Val = RV->getValue();
|
|
|
|
Stack.push_back(VarName);
|
|
|
|
Val = Val->resolveReferences(*this);
|
|
|
|
Stack.pop_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Cache[VarName] = Val;
|
|
|
|
return Val;
|
|
|
|
}
|