diff --git a/llvm/include/llvm/Target/TargetCallingConv.td b/llvm/include/llvm/Target/TargetCallingConv.td index 18b7ff4aec95f..d0533cad927a7 100644 --- a/llvm/include/llvm/Target/TargetCallingConv.td +++ b/llvm/include/llvm/Target/TargetCallingConv.td @@ -113,6 +113,13 @@ class CCAssignToReg regList> : CCAction { list RegList = regList; } +/// CCAssignToRegTuple - Same as CCAssignToReg, but with a list of registers as +/// strings. This is needed because records synthesized during tuple expansion +/// are not visible outside of the register info emitter. +class CCAssignToRegTuple regList> : CCAction { + list RegList = regList; +} + /// CCAssignToRegWithShadow - Same as CCAssignToReg, but with list of registers /// which became shadowed, when some register is used. class CCAssignToRegWithShadow regList, diff --git a/llvm/test/TableGen/cc-assign-to-reg-tuple.td b/llvm/test/TableGen/cc-assign-to-reg-tuple.td new file mode 100644 index 0000000000000..624aa1d5f5f0b --- /dev/null +++ b/llvm/test/TableGen/cc-assign-to-reg-tuple.td @@ -0,0 +1,78 @@ +// RUN: llvm-tblgen --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck %s +// RUN: not llvm-tblgen -DERROR1 --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR1 %s +// RUN: not llvm-tblgen -DERROR2 --gen-callingconv -I %p/../../include -I %p/Common %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR2 %s + +include "reg-with-subregs-common.td" + +def CC_ABI1 : CallingConv<[ + // Use singleton definitions directly. + CCIfType<[i32, f32], + CCAssignToReg<[R8, R9, R10, R11, R12, R13, R14, R15]>>, + + // Use tuple definitions indirectly as strings. + CCIfType<[i64, f64], + CCAssignToRegTuple<["R8_R9", "R10_R11", "R12_R13", "R14_R15"]>>, + + CCIfType<[i128], + CCAssignToRegTuple<["R8_R9_R10_R11", "R12_R13_R14_R15"]>>, + + CCIfType<[v8i32], + CCAssignToRegTuple<["R8_R9_R10_R11_R12_R13_R14_R15"]>>, +]>; + +// CHECK: if (LocVT == MVT::i32 || +// CHECK: LocVT == MVT::f32) { +// CHECK: static const MCPhysReg RegList1[] = { +// CHECK: R8, R9, R10, R11, R12, R13, R14, R15 +// CHECK: }; +// CHECK: if (MCRegister Reg = State.AllocateReg(RegList1)) { +// CHECK: State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); +// CHECK: return false; +// CHECK: } +// CHECK: } + +// CHECK: if (LocVT == MVT::i64 || +// CHECK: LocVT == MVT::f64) { +// CHECK: static const MCPhysReg RegList2[] = { +// CHECK: R8_R9, R10_R11, R12_R13, R14_R15 +// CHECK: }; +// CHECK: if (MCRegister Reg = State.AllocateReg(RegList2)) { +// CHECK: State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); +// CHECK: return false; +// CHECK: } +// CHECK: } + +// CHECK: if (LocVT == MVT::i128) { +// CHECK: static const MCPhysReg RegList3[] = { +// CHECK: R8_R9_R10_R11, R12_R13_R14_R15 +// CHECK: }; +// CHECK: if (MCRegister Reg = State.AllocateReg(RegList3)) { +// CHECK: State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); +// CHECK: return false; +// CHECK: } +// CHECK: } + +// CHECK: if (LocVT == MVT::v8i32) { +// CHECK: if (MCRegister Reg = State.AllocateReg(R8_R9_R10_R11_R12_R13_R14_R15)) { +// CHECK: State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); +// CHECK: return false; +// CHECK: } +// CHECK: } + +#ifdef ERROR1 +def CC_ABI2 : CallingConv<[ + // Test that referencing an undefined tuple is diagnosed as an error. + // CHECK-ERROR1: error: register not defined: "R89_R33" + CCIfType<[i64, f64], + CCAssignToRegTuple<["R89_R33", "R12_R13", "R14_R15"]>>, +]>; +#endif + +#ifdef ERROR2 +def CC_ABI3 : CallingConv<[ + // Currently an error: Use tuple definitions directly. + // CHECK-ERROR2: error: Variable not defined: 'R8_R9_R10_R11' + CCIfType<[i128], + CCAssignToRegTuple<[R8_R9_R10_R11, R12_R13_R14_R15]>>, +]>; +#endif diff --git a/llvm/utils/TableGen/CallingConvEmitter.cpp b/llvm/utils/TableGen/CallingConvEmitter.cpp index 57b1622752613..20dc1ff0ffd14 100644 --- a/llvm/utils/TableGen/CallingConvEmitter.cpp +++ b/llvm/utils/TableGen/CallingConvEmitter.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "Common/CodeGenRegisters.h" #include "Common/CodeGenTarget.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InterleavedRange.h" @@ -26,6 +27,7 @@ using namespace llvm; namespace { class CallingConvEmitter { const RecordKeeper &Records; + const CodeGenTarget Target; unsigned Counter = 0u; std::string CurrentAction; bool SwiftAction = false; @@ -35,7 +37,10 @@ class CallingConvEmitter { std::map> DelegateToMap; public: - explicit CallingConvEmitter(const RecordKeeper &R) : Records(R) {} + explicit CallingConvEmitter(const RecordKeeper &R) : Records(R), Target(R) { + for (const CodeGenRegister &Reg : Target.getRegBank().getRegisters()) + RegistersByDefName.try_emplace(Reg.getName(), &Reg); + } void run(raw_ostream &O); @@ -43,6 +48,9 @@ class CallingConvEmitter { void emitCallingConv(const Record *CC, raw_ostream &O); void emitAction(const Record *Action, indent Indent, raw_ostream &O); void emitArgRegisterLists(raw_ostream &O); + + StringMap RegistersByDefName; + std::string getQualifiedRegisterName(const Init *I); }; } // End anonymous namespace @@ -125,6 +133,20 @@ void CallingConvEmitter::emitCallingConv(const Record *CC, raw_ostream &O) { O << "}\n"; } +// Return the name of the specified Init (DefInit or StringInit), with a +// namespace qualifier if the corresponding record contains one. +std::string CallingConvEmitter::getQualifiedRegisterName(const Init *I) { + if (const auto *DI = dyn_cast(I)) + return getQualifiedName(DI->getDef()); + + const auto *SI = cast(I); + if (const CodeGenRegister *CGR = RegistersByDefName.lookup(SI->getValue())) + return getQualifiedName(CGR->TheDef); + + PrintFatalError("register not defined: " + SI->getAsString()); + return ""; +} + void CallingConvEmitter::emitAction(const Record *Action, indent Indent, raw_ostream &O) { @@ -133,7 +155,7 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent, O << Indent << " "; ListSeparator LS; for (const Init *V : RL->getValues()) - O << LS << getQualifiedName(cast(V)->getDef()); + O << LS << getQualifiedRegisterName(V); O << "\n" << Indent << "};\n"; }; @@ -142,7 +164,7 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent, SmallVector Parms; if (RegLists[0]->size() == 1) { for (const ListInit *LI : RegLists) - Parms.push_back(getQualifiedName(LI->getElementAsRecord(0))); + Parms.push_back(getQualifiedRegisterName(LI->getElement(0))); } else { for (const std::string &S : RLNames) Parms.push_back(S + utostr(++Counter)); @@ -207,10 +229,11 @@ void CallingConvEmitter::emitAction(const Record *Action, indent Indent, << Indent + 2 << "return false;\n"; DelegateToMap[CurrentAction].insert(CC->getName().str()); } else if (Action->isSubClassOf("CCAssignToReg") || + Action->isSubClassOf("CCAssignToRegTuple") || Action->isSubClassOf("CCAssignToRegAndStack")) { const ListInit *RegList = Action->getValueAsListInit("RegList"); for (unsigned I = 0, E = RegList->size(); I != E; ++I) { - std::string Name = getQualifiedName(RegList->getElementAsRecord(I)); + std::string Name = getQualifiedRegisterName(RegList->getElement(I)); if (SwiftAction) AssignedSwiftRegsMap[CurrentAction].insert(std::move(Name)); else