diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp --- a/llvm/lib/TableGen/Record.cpp +++ b/llvm/lib/TableGen/Record.cpp @@ -1772,34 +1772,34 @@ Init *ExistsOpInit::Fold(Record *CurRec, bool IsFinal) const { if (StringInit *Name = dyn_cast(Expr)) { - if (!CurRec && !IsFinal) - return const_cast(this); - - // Self-references are allowed, but their resolution is delayed until - // the final resolve to ensure that we get the correct type for them. - auto *Anonymous = dyn_cast(CurRec->getNameInit()); - if (Name == CurRec->getNameInit() || - (Anonymous && Name == Anonymous->getNameInit())) { - if (!IsFinal) - return const_cast(this); - - // No doubt that there exists a record, so we should check if types are - // compatiable. - return IntInit::get(getRecordKeeper(), - CurRec->getType()->typeIsA(CheckType)); - } // Look up all defined records to see if we can find one. Record *D = CheckType->getRecordKeeper().getDef(Name->getValue()); - if (!D) { - if (IsFinal) - return IntInit::get(getRecordKeeper(), 0); - return const_cast(this); + if (D) { + // Check if types are compatiable. + return IntInit::get(getRecordKeeper(), + DefInit::get(D)->getType()->typeIsA(CheckType)); } - // Check if types are compatiable. - return IntInit::get(getRecordKeeper(), - DefInit::get(D)->getType()->typeIsA(CheckType)); + if (CurRec) { + // Self-references are allowed, but their resolution is delayed until + // the final resolve to ensure that we get the correct type for them. + auto *Anonymous = dyn_cast(CurRec->getNameInit()); + if (Name == CurRec->getNameInit() || + (Anonymous && Name == Anonymous->getNameInit())) { + if (!IsFinal) + return const_cast(this); + + // No doubt that there exists a record, so we should check if types are + // compatiable. + return IntInit::get(getRecordKeeper(), + CurRec->getType()->typeIsA(CheckType)); + } + } + + if (IsFinal) + return IntInit::get(getRecordKeeper(), 0); + return const_cast(this); } return const_cast(this); } diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp --- a/llvm/lib/TableGen/TGParser.cpp +++ b/llvm/lib/TableGen/TGParser.cpp @@ -384,10 +384,35 @@ bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs, bool Final, std::vector *Dest, SMLoc *Loc) { + MapResolver R; for (const auto &S : Substs) R.set(S.first, S.second); Init *List = Loop.ListValue->resolveReferences(R); + + // For if-then-else blocks, we lower to a foreach loop whose list is a + // ternary selection between lists of different length. Since we don't + // have a means to track variable length record lists, we *must* resolve + // the condition here. We want to defer final resolution of the arms + // until the resulting records are finalized. + // e.g. !if(!exists("__does_not_exist__"), [1], []) + if (auto *TI = dyn_cast(List); + TI && TI->getOpcode() == TernOpInit::IF && Final) { + Init *OldLHS = TI->getLHS(); + R.setFinal(true); + Init *LHS = OldLHS->resolveReferences(R); + if (LHS == OldLHS) { + PrintError(Loop.Loc, + Twine("unable to resolve if condition '") + + LHS->getAsString() + "' at end of containing scope"); + return true; + } + Init *MHS = TI->getMHS(); + Init *RHS = TI->getRHS(); + List = TernOpInit::get(TernOpInit::IF, LHS, MHS, RHS, TI->getType()) + ->Fold(nullptr); + } + auto LI = dyn_cast(List); if (!LI) { if (!Final) { diff --git a/llvm/lib/Target/RISCV/RISCVScheduleV.td b/llvm/lib/Target/RISCV/RISCVScheduleV.td --- a/llvm/lib/Target/RISCV/RISCVScheduleV.td +++ b/llvm/lib/Target/RISCV/RISCVScheduleV.td @@ -31,43 +31,44 @@ def name # "_" # mx : SchedRead; } } -multiclass LMULWriteResImpl MxList, - list resources> { - foreach mx = MxList in { - def : WriteRes(name # "_" # mx), resources>; +multiclass LMULWriteResImpl resources> { + foreach mx = SchedMxList in { + if !exists(name # "_" # mx) then + def : WriteRes(name # "_" # mx), resources>; } } -multiclass LMULReadAdvanceImpl MxList, int val, +multiclass LMULReadAdvanceImpl writes = []> { - foreach mx = MxList in { - def : ReadAdvance(name # "_" # mx), val, writes>; + foreach mx = SchedMxList in { + if !exists(name # "_" # mx) then + def : ReadAdvance(name # "_" # mx), val, writes>; } } multiclass LMULSchedWrites : LMULSchedWritesImpl; multiclass LMULSchedReads : LMULSchedReadsImpl; multiclass LMULWriteRes resources> - : LMULWriteResImpl; + : LMULWriteResImpl; multiclass LMULReadAdvance writes = []> - : LMULReadAdvanceImpl; + : LMULReadAdvanceImpl; multiclass LMULSchedWritesW : LMULSchedWritesImpl; multiclass LMULSchedReadsW : LMULSchedReadsImpl; multiclass LMULWriteResW resources> - : LMULWriteResImpl; + : LMULWriteResImpl; multiclass LMULReadAdvanceW writes = []> - : LMULReadAdvanceImpl; + : LMULReadAdvanceImpl; multiclass LMULSchedWritesFW : LMULSchedWritesImpl; multiclass LMULSchedReadsFW : LMULSchedReadsImpl; multiclass LMULWriteResFW resources> - : LMULWriteResImpl; + : LMULWriteResImpl; multiclass LMULReadAdvanceFW writes = []> - : LMULReadAdvanceImpl; + : LMULReadAdvanceImpl; multiclass LMULSchedWritesFWRed : LMULSchedWritesImpl; multiclass LMULWriteResFWRed resources> - : LMULWriteResImpl; + : LMULWriteResImpl; // 3.6 Vector Byte Length vlenb diff --git a/llvm/test/TableGen/exists.td b/llvm/test/TableGen/exists.td --- a/llvm/test/TableGen/exists.td +++ b/llvm/test/TableGen/exists.td @@ -37,6 +37,30 @@ def current_missing : Self_check<"current">; def current : Self_check<"current">; + +// Check that conditional definitions dependent on the resolution of an +// exists clause work as expected. +// Reminder: a0 exists, a1 does not. +class C { + int exists = 1; +} +if !exists("a0") then + def if_exists : C; +if !exists("a1") then + def if_no_exists: C; +foreach e = ["a0", "a1"] in { + if !exists(e) then + def for_exists_ # e: C; +} +multiclass mc { + foreach e = ["a0", "a1"] in { + if !exists(e) then + def _ # e: C; + } +} +defm multiclass_exists : mc<>; + + // CHECK: def a0_exists { // CHECK: int exists = 1; // CHECK: } @@ -58,6 +82,16 @@ // CHECK: int exists = 0; // CHECK: } +// CHECK: def for_exists_a0 { +// CHECK: int exists = 1; +// CHECK: } +// CHECK: def if_exists { +// CHECK: int exists = 1; +// CHECK: } +// CHECK: def multiclass_exists_a0 { +// CHECK: int exists = 1; +// CHECK: } + // CHECK: def self_reference { // CHECK: int exists = 1; // CHECK: }