Index: include/llvm/CodeGen/MachineRegisterInfo.h =================================================================== --- include/llvm/CodeGen/MachineRegisterInfo.h +++ include/llvm/CodeGen/MachineRegisterInfo.h @@ -658,6 +658,13 @@ /// \pre Size > 0. unsigned createGenericVirtualRegister(unsigned Size); + /// Creates a new virtual register that has no register class, register bank + /// or size assigned yet. This is only allowed to be used + /// temporarily while constructing machine instructions. Most operations are + /// undefined on a preliminary register until one of setRegClass(), + /// setRegBank() or setSize() has been called for it. + unsigned createIncompleteVirtualRegister(); + /// getNumVirtRegs - Return the number of virtual registers created. /// unsigned getNumVirtRegs() const { return VRegInfo.size(); } Index: lib/CodeGen/MIRParser/MIParser.h =================================================================== --- lib/CodeGen/MIRParser/MIParser.h +++ lib/CodeGen/MIRParser/MIParser.h @@ -26,9 +26,24 @@ class MachineInstr; class MachineRegisterInfo; class MDNode; +class RegisterBank; struct SlotMapping; class SMDiagnostic; class SourceMgr; +class TargetRegisterClass; + +struct VRegInfo { + enum uint8_t { + UNKNOWN, NORMAL, GENERIC, REGBANK + } Kind = UNKNOWN; + bool Explicit = false; ///< VReg was explicitely specified in the .mir file + bool Used = false; + union { + const TargetRegisterClass *RC; + const RegisterBank *RegBank; + } D; + unsigned PreferredReg; +}; struct PerFunctionMIParsingState { MachineFunction &MF; @@ -36,16 +51,16 @@ const SlotMapping &IRSlots; DenseMap MBBSlots; - DenseMap VirtualRegisterSlots; + std::vector VRegInfos; DenseMap FixedStackObjectSlots; DenseMap StackObjectSlots; DenseMap ConstantPoolSlots; DenseMap JumpTableSlots; - /// Hold the generic virtual registers. - SmallSet GenericVRegs; PerFunctionMIParsingState(MachineFunction &MF, SourceMgr &SM, const SlotMapping &IRSlots); + + VRegInfo &getVRegInfo(unsigned VReg); }; /// Parse the machine basic block definitions, and skip the machine @@ -73,26 +88,25 @@ /// on the given source string. /// /// Return true if an error occurred. -bool parseMachineInstructions(const PerFunctionMIParsingState &PFS, - StringRef Src, SMDiagnostic &Error); +bool parseMachineInstructions(PerFunctionMIParsingState &PFS, StringRef Src, + SMDiagnostic &Error); -bool parseMBBReference(const PerFunctionMIParsingState &PFS, +bool parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, StringRef Src, SMDiagnostic &Error); -bool parseNamedRegisterReference(const PerFunctionMIParsingState &PFS, - unsigned &Reg, StringRef Src, - SMDiagnostic &Error); +bool parseNamedRegisterReference(PerFunctionMIParsingState &PFS, unsigned &Reg, + StringRef Src, SMDiagnostic &Error); -bool parseVirtualRegisterReference(const PerFunctionMIParsingState &PFS, +bool parseVirtualRegisterReference(PerFunctionMIParsingState &PFS, unsigned &Reg, StringRef Src, SMDiagnostic &Error); -bool parseStackObjectReference(const PerFunctionMIParsingState &PFS, - int &FI, StringRef Src, SMDiagnostic &Error); +bool parseStackObjectReference(PerFunctionMIParsingState &PFS, int &FI, + StringRef Src, SMDiagnostic &Error); -bool parseMDNode(const PerFunctionMIParsingState &PFS, MDNode *&Node, - StringRef Src, SMDiagnostic &Error); +bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, StringRef Src, + SMDiagnostic &Error); } // end namespace llvm Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -41,6 +41,19 @@ : MF(MF), SM(&SM), IRSlots(IRSlots) { } +VRegInfo &PerFunctionMIParsingState::getVRegInfo(unsigned VReg) { + unsigned VRegIndex = TargetRegisterInfo::virtReg2Index(VReg); + if (VRegInfos.size() <= VRegIndex) { + MachineRegisterInfo &MRI = MF.getRegInfo(); + assert(MRI.getNumVirtRegs() == VRegInfos.size() && "MRI in sync"); + + VRegInfos.resize(VRegIndex + 1); + for (unsigned I = MRI.getNumVirtRegs(); I < VRegIndex+1; ++I) + MRI.createIncompleteVirtualRegister(); + } + return VRegInfos[VRegIndex]; +} + namespace { /// A wrapper struct around the 'MachineOperand' struct that includes a source @@ -65,7 +78,7 @@ SMDiagnostic &Error; StringRef Source, CurrentSource; MIToken Token; - const PerFunctionMIParsingState &PFS; + PerFunctionMIParsingState &PFS; /// Maps from instruction names to op codes. StringMap Names2InstrOpCodes; /// Maps from register names to registers. @@ -86,7 +99,7 @@ StringMap Names2BitmaskTargetFlags; public: - MIParser(const PerFunctionMIParsingState &PFS, SMDiagnostic &Error, + MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source); /// \p SkipChar gives the number of characters to skip before looking @@ -254,7 +267,7 @@ } // end anonymous namespace -MIParser::MIParser(const PerFunctionMIParsingState &PFS, SMDiagnostic &Error, +MIParser::MIParser(PerFunctionMIParsingState &PFS, SMDiagnostic &Error, StringRef Source) : MF(PFS.MF), Error(Error), Source(Source), CurrentSource(Source), PFS(PFS) {} @@ -815,11 +828,9 @@ unsigned ID; if (getUnsigned(ID)) return true; - const auto RegInfo = PFS.VirtualRegisterSlots.find(ID); - if (RegInfo == PFS.VirtualRegisterSlots.end()) - return error(Twine("use of undefined virtual register '%") + Twine(ID) + - "'"); - Reg = RegInfo->second; + Reg = TargetRegisterInfo::index2VirtReg(ID); + VRegInfo &Info = PFS.getVRegInfo(Reg); + Info.Used = true; break; } // TODO: Parse other register kinds. @@ -982,11 +993,13 @@ MachineRegisterInfo &MRI = MF.getRegInfo(); MRI.setSize(Reg, Size); - } else if (PFS.GenericVRegs.count(Reg)) { + } else if (TargetRegisterInfo::isVirtualRegister(Reg)) { + const VRegInfo &Info = PFS.getVRegInfo(Reg); // Generic virtual registers must have a size. // If we end up here this means the size hasn't been specified and // this is bad! - return error("generic virtual registers must have a size"); + if (Info.Kind == VRegInfo::GENERIC || Info.Kind == VRegInfo::REGBANK) + return error("generic virtual registers must have a size"); } Dest = MachineOperand::CreateReg( Reg, Flags & RegState::Define, Flags & RegState::Implicit, @@ -2059,36 +2072,36 @@ return MIParser(PFS, Error, Src).parseBasicBlockDefinitions(PFS.MBBSlots); } -bool llvm::parseMachineInstructions(const PerFunctionMIParsingState &PFS, +bool llvm::parseMachineInstructions(PerFunctionMIParsingState &PFS, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseBasicBlocks(); } -bool llvm::parseMBBReference(const PerFunctionMIParsingState &PFS, +bool llvm::parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneMBB(MBB); } -bool llvm::parseNamedRegisterReference(const PerFunctionMIParsingState &PFS, +bool llvm::parseNamedRegisterReference(PerFunctionMIParsingState &PFS, unsigned &Reg, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneNamedRegister(Reg); } -bool llvm::parseVirtualRegisterReference(const PerFunctionMIParsingState &PFS, +bool llvm::parseVirtualRegisterReference(PerFunctionMIParsingState &PFS, unsigned &Reg, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneVirtualRegister(Reg); } -bool llvm::parseStackObjectReference(const PerFunctionMIParsingState &PFS, +bool llvm::parseStackObjectReference(PerFunctionMIParsingState &PFS, int &FI, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneStackObject(FI); } -bool llvm::parseMDNode(const PerFunctionMIParsingState &PFS, +bool llvm::parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, StringRef Src, SMDiagnostic &Error) { return MIParser(PFS, Error, Src).parseStandaloneMDNode(Node); } Index: lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIRParser.cpp +++ lib/CodeGen/MIRParser/MIRParser.cpp @@ -102,10 +102,10 @@ /// Return true if error occurred. bool initializeMachineFunction(MachineFunction &MF); - bool initializeRegisterInfo(PerFunctionMIParsingState &PFS, - const yaml::MachineFunction &YamlMF); + bool parseRegisterInfo(PerFunctionMIParsingState &PFS, + const yaml::MachineFunction &YamlMF); - void inferRegisterInfo(const PerFunctionMIParsingState &PFS, + bool setupRegisterInfo(const PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF); bool initializeFrameInfo(PerFunctionMIParsingState &PFS, @@ -128,10 +128,10 @@ const yaml::MachineJumpTable &YamlJTI); private: - bool parseMDNode(const PerFunctionMIParsingState &PFS, MDNode *&Node, + bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, const yaml::StringValue &Source); - bool parseMBBReference(const PerFunctionMIParsingState &PFS, + bool parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, const yaml::StringValue &Source); @@ -293,7 +293,7 @@ if (YamlMF.AllVRegsAllocated) MF.getProperties().set(MachineFunctionProperties::Property::AllVRegsAllocated); PerFunctionMIParsingState PFS(MF, SM, IRSlots); - if (initializeRegisterInfo(PFS, YamlMF)) + if (parseRegisterInfo(PFS, YamlMF)) return true; if (!YamlMF.Constants.empty()) { auto *ConstantPool = MF.getConstantPool(); @@ -343,16 +343,15 @@ } PFS.SM = &SM; - inferRegisterInfo(PFS, YamlMF); - // FIXME: This is a temporary workaround until the reserved registers can be - // serialized. - MF.getRegInfo().freezeReservedRegs(MF); + if (setupRegisterInfo(PFS, YamlMF)) + return true; + MF.verify(); return false; } -bool MIRParserImpl::initializeRegisterInfo(PerFunctionMIParsingState &PFS, - const yaml::MachineFunction &YamlMF) { +bool MIRParserImpl::parseRegisterInfo(PerFunctionMIParsingState &PFS, + const yaml::MachineFunction &YamlMF) { MachineFunction &MF = PFS.MF; MachineRegisterInfo &RegInfo = MF.getRegInfo(); assert(RegInfo.isSSA()); @@ -366,39 +365,40 @@ SMDiagnostic Error; // Parse the virtual register information. for (const auto &VReg : YamlMF.VirtualRegisters) { - unsigned Reg; + unsigned Reg = TargetRegisterInfo::index2VirtReg(VReg.ID.Value); + VRegInfo &Info = PFS.getVRegInfo(Reg); + if (Info.Explicit) + return error(VReg.ID.SourceRange.Start, + Twine("redefinition of virtual register '%") + + Twine(VReg.ID.Value) + "'"); + Info.Explicit = true; + if (StringRef(VReg.Class.Value).equals("_")) { - // This is a generic virtual register. - // The size will be set appropriately when we reach the definition. - Reg = RegInfo.createGenericVirtualRegister(/*Size*/ 1); - PFS.GenericVRegs.insert(Reg); + Info.Kind = VRegInfo::GENERIC; } else { const auto *RC = getRegClass(MF, VReg.Class.Value); if (RC) { - Reg = RegInfo.createVirtualRegister(RC); + Info.Kind = VRegInfo::NORMAL; + Info.D.RC = RC; } else { - const auto *RegBank = getRegBank(MF, VReg.Class.Value); + const RegisterBank *RegBank = getRegBank(MF, VReg.Class.Value); if (!RegBank) return error( VReg.Class.SourceRange.Start, Twine("use of undefined register class or register bank '") + VReg.Class.Value + "'"); - Reg = RegInfo.createGenericVirtualRegister(/*Size*/ 1); - RegInfo.setRegBank(Reg, *RegBank); - PFS.GenericVRegs.insert(Reg); + Info.Kind = VRegInfo::REGBANK; + Info.D.RegBank = RegBank; } } - if (!PFS.VirtualRegisterSlots.insert(std::make_pair(VReg.ID.Value, Reg)) - .second) - return error(VReg.ID.SourceRange.Start, - Twine("redefinition of virtual register '%") + - Twine(VReg.ID.Value) + "'"); + if (!VReg.PreferredRegister.Value.empty()) { - unsigned PreferredReg = 0; - if (parseNamedRegisterReference(PFS, PreferredReg, + if (Info.Kind != VRegInfo::NORMAL) + return error(VReg.Class.SourceRange.Start, + Twine("preferred register can only be set for normal vregs")); + if (parseNamedRegisterReference(PFS, Info.PreferredReg, VReg.PreferredRegister.Value, Error)) return error(Error, VReg.PreferredRegister.SourceRange); - RegInfo.setSimpleHint(Reg, PreferredReg); } } @@ -430,20 +430,55 @@ return false; } -void MIRParserImpl::inferRegisterInfo(const PerFunctionMIParsingState &PFS, +bool MIRParserImpl::setupRegisterInfo(const PerFunctionMIParsingState &PFS, const yaml::MachineFunction &YamlMF) { - if (YamlMF.CalleeSavedRegisters) - return; - MachineRegisterInfo &MRI = PFS.MF.getRegInfo(); - for (const MachineBasicBlock &MBB : PFS.MF) { - for (const MachineInstr &MI : MBB) { - for (const MachineOperand &MO : MI.operands()) { - if (!MO.isRegMask()) - continue; - MRI.addPhysRegsUsedFromRegMask(MO.getRegMask()); + MachineFunction &MF = PFS.MF; + MachineRegisterInfo &MRI = MF.getRegInfo(); + bool Error = false; + // Create VRegs + for (unsigned I = 0, E = PFS.VRegInfos.size(); I < E; ++I) { + const VRegInfo &Info = PFS.VRegInfos[I]; + unsigned Reg = TargetRegisterInfo::index2VirtReg(I); + switch (Info.Kind) { + case VRegInfo::UNKNOWN: + if (!Info.Used) + error(Twine("Unused virtual register ") + Twine(I) + + " in function '" + MF.getName() + "'"); + else + error(Twine("Cannot deduce type of virtual register ") + Twine(I) + + " in function '" + MF.getName() + "'"); + Error = true; + break; + case VRegInfo::NORMAL: + MRI.setRegClass(Reg, Info.D.RC); + if (Info.PreferredReg != 0) + MRI.setSimpleHint(Reg, Info.PreferredReg); + break; + case VRegInfo::GENERIC: + break; + case VRegInfo::REGBANK: + MRI.setRegBank(Reg, *Info.D.RegBank); + break; + } + } + + // Compute MachineRegisterInfo::UsedPhysRegMask + if (!YamlMF.CalleeSavedRegisters) { + for (const MachineBasicBlock &MBB : MF) { + for (const MachineInstr &MI : MBB) { + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isRegMask()) + continue; + MRI.addPhysRegsUsedFromRegMask(MO.getRegMask()); + } } } } + + // FIXME: This is a temporary workaround until the reserved registers can be + // serialized. + MRI.freezeReservedRegs(MF); + return Error; } bool MIRParserImpl::initializeFrameInfo(PerFunctionMIParsingState &PFS, @@ -601,7 +636,7 @@ return false; } -bool MIRParserImpl::parseMDNode(const PerFunctionMIParsingState &PFS, +bool MIRParserImpl::parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, const yaml::StringValue &Source) { if (Source.Value.empty()) return false; @@ -657,7 +692,7 @@ return false; } -bool MIRParserImpl::parseMBBReference(const PerFunctionMIParsingState &PFS, +bool MIRParserImpl::parseMBBReference(PerFunctionMIParsingState &PFS, MachineBasicBlock *&MBB, const yaml::StringValue &Source) { SMDiagnostic Error; Index: lib/CodeGen/MachineFunctionAnalysis.cpp =================================================================== --- lib/CodeGen/MachineFunctionAnalysis.cpp +++ lib/CodeGen/MachineFunctionAnalysis.cpp @@ -49,8 +49,13 @@ assert(!MF && "MachineFunctionAnalysis already initialized!"); MF = new MachineFunction(&F, TM, NextFnNum++, getAnalysis()); - if (MFInitializer) - MFInitializer->initializeMachineFunction(*MF); + if (MFInitializer) { + bool res = MFInitializer->initializeMachineFunction(*MF); + if (res) { + fprintf(stderr, "ERROR\n"); + exit(1); + } + } return false; } Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -88,6 +88,13 @@ return true; } +unsigned MachineRegisterInfo::createIncompleteVirtualRegister() { + unsigned Reg = TargetRegisterInfo::index2VirtReg(getNumVirtRegs()); + VRegInfo.grow(Reg); + RegAllocHints.grow(Reg); + return Reg; +} + /// createVirtualRegister - Create and return a new virtual register in the /// function with the specified register class. /// @@ -98,10 +105,8 @@ "Virtual register RegClass must be allocatable."); // New virtual register number. - unsigned Reg = TargetRegisterInfo::index2VirtReg(getNumVirtRegs()); - VRegInfo.grow(Reg); + unsigned Reg = createIncompleteVirtualRegister(); VRegInfo[Reg].first = RegClass; - RegAllocHints.grow(Reg); if (TheDelegate) TheDelegate->MRI_NoteNewVirtualRegister(Reg); return Reg; @@ -122,12 +127,10 @@ assert(Size && "Cannot create empty virtual register"); // New virtual register number. - unsigned Reg = TargetRegisterInfo::index2VirtReg(getNumVirtRegs()); - VRegInfo.grow(Reg); + unsigned Reg = createIncompleteVirtualRegister(); // FIXME: Should we use a dummy register class? VRegInfo[Reg].first = static_cast(nullptr); getVRegToSize()[Reg] = Size; - RegAllocHints.grow(Reg); if (TheDelegate) TheDelegate->MRI_NoteNewVirtualRegister(Reg); return Reg; Index: test/CodeGen/MIR/X86/undefined-virtual-register.mir =================================================================== --- test/CodeGen/MIR/X86/undefined-virtual-register.mir +++ test/CodeGen/MIR/X86/undefined-virtual-register.mir @@ -19,8 +19,8 @@ body: | bb.0.entry: %0 = COPY %edi - ; CHECK: [[@LINE+1]]:17: use of undefined virtual register '%10' - %eax = COPY %10 + ; CHECK: Cannot deduce type of virtual register 1 in function 'test' + %eax = COPY %1 RETQ %eax ... Index: test/CodeGen/MIR/X86/unused-virtual-register.mir =================================================================== --- test/CodeGen/MIR/X86/unused-virtual-register.mir +++ test/CodeGen/MIR/X86/unused-virtual-register.mir @@ -1,6 +1,6 @@ # RUN: not llc -march=x86-64 -start-after machine-sink -stop-after machine-sink -o /dev/null %s 2>&1 | FileCheck %s -# This test ensures that the MIR parser reports an error when parsing a -# reference to an undefined virtual register. +# Check that all virtual registers are defined. This means we cannot have +# 'holes' in the virtual register numbering. --- | @@ -11,16 +11,16 @@ ... --- +# CHECK: Unused virtual register 0 in function 'test' name: test isSSA: true tracksRegLiveness: true registers: - - { id: 0, class: gr32 } + - { id: 1, class: gr32 } body: | bb.0.entry: - %0 = COPY %edi - ; CHECK: [[@LINE+1]]:17: use of undefined virtual register '%10' - %eax = COPY %10 + %1 = COPY %edi + %eax = COPY %1 RETQ %eax ... Index: test/CodeGen/MIR/X86/virtual-registers.mir =================================================================== --- test/CodeGen/MIR/X86/virtual-registers.mir +++ test/CodeGen/MIR/X86/virtual-registers.mir @@ -16,18 +16,6 @@ ret i32 %a } - define i32 @foo(i32 %a) { - entry: - %0 = icmp sle i32 %a, 10 - br i1 %0, label %less, label %exit - - less: - ret i32 0 - - exit: - ret i32 %a - } - ... --- name: bar @@ -63,39 +51,3 @@ %eax = COPY %0 RETQ %eax ... ---- -name: foo -isSSA: true -tracksRegLiveness: true -# CHECK: name: foo -# CHECK: registers: -# CHECK-NEXT: - { id: 0, class: gr32 } -# CHECK-NEXT: - { id: 1, class: gr32 } -# CHECK-NEXT: - { id: 2, class: gr32 } -registers: - - { id: 2, class: gr32 } - - { id: 0, class: gr32 } - - { id: 10, class: gr32 } -body: | - bb.0.entry: - successors: %bb.2.exit, %bb.1.less - liveins: %edi - ; CHECK: %0 = COPY %edi - ; CHECK-NEXT: %1 = SUB32ri8 %0, 10 - %2 = COPY %edi - %0 = SUB32ri8 %2, 10, implicit-def %eflags - JG_1 %bb.2.exit, implicit %eflags - JMP_1 %bb.1.less - - bb.1.less: - ; CHECK: %2 = MOV32r0 - ; CHECK-NEXT: %eax = COPY %2 - %10 = MOV32r0 implicit-def %eflags - %eax = COPY %10 - RETQ %eax - - bb.2.exit: - ; CHECK: %eax = COPY %0 - %eax = COPY %2 - RETQ %eax -...