diff --git a/llvm/include/llvm/CodeGen/MIRYamlMapping.h b/llvm/include/llvm/CodeGen/MIRYamlMapping.h index 678cec9838ac..c99dc40458d1 100644 --- a/llvm/include/llvm/CodeGen/MIRYamlMapping.h +++ b/llvm/include/llvm/CodeGen/MIRYamlMapping.h @@ -101,13 +101,16 @@ namespace yaml { struct VirtualRegisterDefinition { unsigned ID; StringValue Class; - // TODO: Serialize the virtual register hints. + StringValue PreferredRegister; + // TODO: Serialize the target specific register hints. }; template <> struct MappingTraits { static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) { YamlIO.mapRequired("id", Reg.ID); YamlIO.mapRequired("class", Reg.Class); + YamlIO.mapOptional("preferred-register", Reg.PreferredRegister, + StringValue()); // Don't print out when it's empty. } static const bool flow = true; diff --git a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h index 67583be616c3..2f823b44801d 100644 --- a/llvm/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/llvm/include/llvm/CodeGen/MachineRegisterInfo.h @@ -614,6 +614,12 @@ public: RegAllocHints[VReg].second = PrefReg; } + /// Specify the preferred register allocation hint for the specified virtual + /// register. + void setSimpleHint(unsigned VReg, unsigned PrefReg) { + setRegAllocationHint(VReg, /*Type=*/0, PrefReg); + } + /// getRegAllocationHint - Return the register allocation hint for the /// specified virtual register. std::pair diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp index 383fde1101a9..67c939cc562a 100644 --- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -103,11 +103,9 @@ public: const yaml::MachineBasicBlock &YamlMBB, const PerFunctionMIParsingState &PFS); - bool - initializeRegisterInfo(const MachineFunction &MF, - MachineRegisterInfo &RegInfo, - const yaml::MachineFunction &YamlMF, - DenseMap &VirtualRegisterSlots); + bool initializeRegisterInfo(MachineFunction &MF, MachineRegisterInfo &RegInfo, + const yaml::MachineFunction &YamlMF, + PerFunctionMIParsingState &PFS); bool initializeFrameInfo(const Function &F, MachineFrameInfo &MFI, const yaml::MachineFunction &YamlMF, @@ -273,8 +271,7 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice); MF.setHasInlineAsm(YamlMF.HasInlineAsm); PerFunctionMIParsingState PFS; - if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF, - PFS.VirtualRegisterSlots)) + if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF, PFS)) return true; if (initializeFrameInfo(*MF.getFunction(), *MF.getFrameInfo(), YamlMF, PFS.StackObjectSlots, PFS.FixedStackObjectSlots)) @@ -368,10 +365,10 @@ bool MIRParserImpl::initializeMachineBasicBlock( return false; } -bool MIRParserImpl::initializeRegisterInfo( - const MachineFunction &MF, MachineRegisterInfo &RegInfo, - const yaml::MachineFunction &YamlMF, - DenseMap &VirtualRegisterSlots) { +bool MIRParserImpl::initializeRegisterInfo(MachineFunction &MF, + MachineRegisterInfo &RegInfo, + const yaml::MachineFunction &YamlMF, + PerFunctionMIParsingState &PFS) { assert(RegInfo.isSSA()); if (!YamlMF.IsSSA) RegInfo.leaveSSA(); @@ -380,6 +377,7 @@ bool MIRParserImpl::initializeRegisterInfo( RegInfo.invalidateLiveness(); RegInfo.enableSubRegLiveness(YamlMF.TracksSubRegLiveness); + SMDiagnostic Error; // Parse the virtual register information. for (const auto &VReg : YamlMF.VirtualRegisters) { const auto *RC = getRegClass(MF, VReg.Class.Value); @@ -390,7 +388,15 @@ bool MIRParserImpl::initializeRegisterInfo( unsigned Reg = RegInfo.createVirtualRegister(RC); // TODO: Report an error when the same virtual register with the same ID is // redefined. - VirtualRegisterSlots.insert(std::make_pair(VReg.ID, Reg)); + PFS.VirtualRegisterSlots.insert(std::make_pair(VReg.ID, Reg)); + if (!VReg.PreferredRegister.Value.empty()) { + unsigned PreferredReg = 0; + if (parseNamedRegisterReference(PreferredReg, SM, MF, + VReg.PreferredRegister.Value, PFS, + IRSlots, Error)) + return error(Error, VReg.PreferredRegister.SourceRange); + RegInfo.setSimpleHint(Reg, PreferredReg); + } } return false; } diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index 2ae5466392fd..574a0ddee1bb 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -140,6 +140,12 @@ static void printReg(unsigned Reg, raw_ostream &OS, llvm_unreachable("Can't print this kind of register yet"); } +static void printReg(unsigned Reg, yaml::StringValue &Dest, + const TargetRegisterInfo *TRI) { + raw_string_ostream OS(Dest.Value); + printReg(Reg, OS, TRI); +} + void MIRPrinter::print(const MachineFunction &MF) { initRegisterMaskIds(MF); @@ -188,6 +194,9 @@ void MIRPrinter::convert(yaml::MachineFunction &MF, VReg.ID = I; VReg.Class = StringRef(TRI->getRegClassName(RegInfo.getRegClass(Reg))).lower(); + unsigned PreferredReg = RegInfo.getSimpleHint(Reg); + if (PreferredReg) + printReg(PreferredReg, VReg.PreferredRegister, TRI); MF.VirtualRegisters.push_back(VReg); } } diff --git a/llvm/test/CodeGen/MIR/X86/expected-named-register-in-allocation-hint.mir b/llvm/test/CodeGen/MIR/X86/expected-named-register-in-allocation-hint.mir new file mode 100644 index 000000000000..3dca9ab726b8 --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/expected-named-register-in-allocation-hint.mir @@ -0,0 +1,30 @@ +# RUN: not llc -march=x86-64 -start-after machine-scheduler -stop-after machine-scheduler -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @test(i32 %a, i32 %b) { + body: + %c = mul i32 %a, %b + ret i32 %c + } + +... +--- +name: test +tracksRegLiveness: true +registers: + - { id: 0, class: gr32 } + # CHECK: [[@LINE+1]]:48: expected a named register + - { id: 1, class: gr32, preferred-register: '%0' } + - { id: 2, class: gr32, preferred-register: '%edi' } +body: + - id: 0 + name: body + liveins: [ '%edi', '%esi' ] + instructions: + - '%1 = COPY %esi' + - '%2 = COPY %edi' + - '%2 = IMUL32rr %2, %1, implicit-def dead %eflags' + - '%eax = COPY %2' + - 'RETQ killed %eax' +... diff --git a/llvm/test/CodeGen/MIR/X86/simple-register-allocation-hints.mir b/llvm/test/CodeGen/MIR/X86/simple-register-allocation-hints.mir new file mode 100644 index 000000000000..42ed70ee3721 --- /dev/null +++ b/llvm/test/CodeGen/MIR/X86/simple-register-allocation-hints.mir @@ -0,0 +1,35 @@ +# RUN: llc -march=x86-64 -start-after machine-scheduler -stop-after machine-scheduler -o /dev/null %s | FileCheck %s +# This test ensures that the MIR parser parses simple register allocation hints +# correctly. + +--- | + + define i32 @test(i32 %a, i32 %b) { + body: + %c = mul i32 %a, %b + ret i32 %c + } + +... +--- +name: test +tracksRegLiveness: true +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr32, preferred-register: '%esi' } +# CHECK-NEXT: - { id: 2, class: gr32, preferred-register: '%edi' } +registers: + - { id: 0, class: gr32 } + - { id: 1, class: gr32, preferred-register: '%esi' } + - { id: 2, class: gr32, preferred-register: '%edi' } +body: + - id: 0 + name: body + liveins: [ '%edi', '%esi' ] + instructions: + - '%1 = COPY %esi' + - '%2 = COPY %edi' + - '%2 = IMUL32rr %2, %1, implicit-def dead %eflags' + - '%eax = COPY %2' + - 'RETQ killed %eax' +...