From c1fa0731c3def3cacc8491c12e008eeb605f930f Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 18 Jan 2017 00:59:19 +0000 Subject: [PATCH] MIRParser: Allow regclass specification on operand You can now define the register class of a virtual register on the operand itself avoiding the need to use a "registers:" block. Example: "%0:gr64 = COPY %rax" Differential Revision: https://reviews.llvm.org/D22398 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@292321 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/MIRParser/MIParser.cpp | 71 +++++++++++++++++++++- lib/CodeGen/MIRParser/MIParser.h | 9 ++- lib/CodeGen/MIRParser/MIRParser.cpp | 11 ++-- test/CodeGen/MIR/AArch64/register-operand-bank.mir | 20 ++++++ .../MIR/X86/register-operand-class-invalid0.mir | 13 ++++ .../MIR/X86/register-operand-class-invalid1.mir | 14 +++++ test/CodeGen/MIR/X86/register-operand-class.mir | 24 ++++++++ 7 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 test/CodeGen/MIR/AArch64/register-operand-bank.mir create mode 100644 test/CodeGen/MIR/X86/register-operand-class-invalid0.mir create mode 100644 test/CodeGen/MIR/X86/register-operand-class-invalid1.mir create mode 100644 test/CodeGen/MIR/X86/register-operand-class.mir diff --git a/lib/CodeGen/MIRParser/MIParser.cpp b/lib/CodeGen/MIRParser/MIParser.cpp index c8bed0890dd..ff6d3097959 100644 --- a/lib/CodeGen/MIRParser/MIParser.cpp +++ b/lib/CodeGen/MIRParser/MIParser.cpp @@ -41,8 +41,11 @@ using namespace llvm; PerFunctionMIParsingState::PerFunctionMIParsingState(MachineFunction &MF, - SourceMgr &SM, const SlotMapping &IRSlots) - : MF(MF), SM(&SM), IRSlots(IRSlots) { + SourceMgr &SM, const SlotMapping &IRSlots, + const Name2RegClassMap &Names2RegClasses, + const Name2RegBankMap &Names2RegBanks) + : MF(MF), SM(&SM), IRSlots(IRSlots), Names2RegClasses(Names2RegClasses), + Names2RegBanks(Names2RegBanks) { } VRegInfo &PerFunctionMIParsingState::getVRegInfo(unsigned Num) { @@ -139,6 +142,7 @@ public: bool parseVirtualRegister(VRegInfo *&Info); bool parseRegister(unsigned &Reg, VRegInfo *&VRegInfo); bool parseRegisterFlag(unsigned &Flags); + bool parseRegisterClassOrBank(VRegInfo &RegInfo); bool parseSubRegisterIndex(unsigned &SubReg); bool parseRegisterTiedDefIndex(unsigned &TiedDefIdx); bool parseRegisterOperand(MachineOperand &Dest, @@ -878,6 +882,62 @@ bool MIParser::parseRegister(unsigned &Reg, VRegInfo *&Info) { } } +bool MIParser::parseRegisterClassOrBank(VRegInfo &RegInfo) { + if (Token.isNot(MIToken::Identifier)) + return error("expected a register class or register bank name"); + StringRef::iterator Loc = Token.location(); + StringRef Name = Token.stringValue(); + + // Was it a register class? + auto RCNameI = PFS.Names2RegClasses.find(Name); + if (RCNameI != PFS.Names2RegClasses.end()) { + lex(); + const TargetRegisterClass &RC = *RCNameI->getValue(); + + switch (RegInfo.Kind) { + case VRegInfo::UNKNOWN: + case VRegInfo::NORMAL: + RegInfo.Kind = VRegInfo::NORMAL; + if (RegInfo.Explicit && RegInfo.D.RC != &RC) { + const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo(); + return error(Loc, Twine("conflicting register classes, previously: ") + + Twine(TRI.getRegClassName(RegInfo.D.RC))); + } + RegInfo.D.RC = &RC; + RegInfo.Explicit = true; + return false; + + case VRegInfo::GENERIC: + case VRegInfo::REGBANK: + return error(Loc, "register class specification on generic register"); + } + llvm_unreachable("Unexpected register kind"); + } + + // Should be a register bank. + auto RBNameI = PFS.Names2RegBanks.find(Name); + lex(); + if (RBNameI == PFS.Names2RegBanks.end()) + return error(Loc, "expected a register class or register bank name"); + + const RegisterBank &RegBank = *RBNameI->getValue(); + switch (RegInfo.Kind) { + case VRegInfo::UNKNOWN: + case VRegInfo::GENERIC: + case VRegInfo::REGBANK: + RegInfo.Kind = VRegInfo::REGBANK; + if (RegInfo.Explicit && RegInfo.D.RegBank != &RegBank) + return error(Loc, "conflicting register banks"); + RegInfo.D.RegBank = &RegBank; + RegInfo.Explicit = true; + return false; + + case VRegInfo::NORMAL: + return error(Loc, "register class specification on normal register"); + } + llvm_unreachable("Unexpected register kind"); +} + bool MIParser::parseRegisterFlag(unsigned &Flags) { const unsigned OldFlags = Flags; switch (Token.kind()) { @@ -1004,6 +1064,13 @@ bool MIParser::parseRegisterOperand(MachineOperand &Dest, if (!TargetRegisterInfo::isVirtualRegister(Reg)) return error("subregister index expects a virtual register"); } + if (Token.is(MIToken::colon)) { + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + return error("register class specification expects a virtual register"); + lex(); + if (parseRegisterClassOrBank(*RegInfo)) + return true; + } MachineRegisterInfo &MRI = MF.getRegInfo(); if ((Flags & RegState::Define) == 0) { if (consumeIfPresent(MIToken::lparen)) { diff --git a/lib/CodeGen/MIRParser/MIParser.h b/lib/CodeGen/MIRParser/MIParser.h index 93a4d84ba62..9b3879cf837 100644 --- a/lib/CodeGen/MIRParser/MIParser.h +++ b/lib/CodeGen/MIRParser/MIParser.h @@ -45,11 +45,16 @@ struct VRegInfo { unsigned PreferredReg = 0; }; +typedef StringMap Name2RegClassMap; +typedef StringMap Name2RegBankMap; + struct PerFunctionMIParsingState { BumpPtrAllocator Allocator; MachineFunction &MF; SourceMgr *SM; const SlotMapping &IRSlots; + const Name2RegClassMap &Names2RegClasses; + const Name2RegBankMap &Names2RegBanks; DenseMap MBBSlots; DenseMap VRegInfos; @@ -59,7 +64,9 @@ struct PerFunctionMIParsingState { DenseMap JumpTableSlots; PerFunctionMIParsingState(MachineFunction &MF, SourceMgr &SM, - const SlotMapping &IRSlots); + const SlotMapping &IRSlots, + const Name2RegClassMap &Names2RegClasses, + const Name2RegBankMap &Names2RegBanks); VRegInfo &getVRegInfo(unsigned VReg); }; diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp index 3dff1147631..0c694c465b6 100644 --- a/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/lib/CodeGen/MIRParser/MIRParser.cpp @@ -55,9 +55,9 @@ class MIRParserImpl { StringMap> Functions; SlotMapping IRSlots; /// Maps from register class names to register classes. - StringMap Names2RegClasses; + Name2RegClassMap Names2RegClasses; /// Maps from register bank names to register banks. - StringMap Names2RegBanks; + Name2RegBankMap Names2RegBanks; public: MIRParserImpl(std::unique_ptr Contents, StringRef Filename, @@ -325,6 +325,8 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { return error(Twine("no machine function information for function '") + MF.getName() + "' in the MIR file"); // TODO: Recreate the machine function. + initNames2RegClasses(MF); + initNames2RegBanks(MF); const yaml::MachineFunction &YamlMF = *It->getValue(); if (YamlMF.Alignment) MF.setAlignment(YamlMF.Alignment); @@ -338,7 +340,8 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { if (YamlMF.Selected) MF.getProperties().set(MachineFunctionProperties::Property::Selected); - PerFunctionMIParsingState PFS(MF, SM, IRSlots); + PerFunctionMIParsingState PFS(MF, SM, IRSlots, Names2RegClasses, + Names2RegBanks); if (parseRegisterInfo(PFS, YamlMF)) return true; if (!YamlMF.Constants.empty()) { @@ -818,7 +821,6 @@ void MIRParserImpl::initNames2RegBanks(const MachineFunction &MF) { const TargetRegisterClass *MIRParserImpl::getRegClass(const MachineFunction &MF, StringRef Name) { - initNames2RegClasses(MF); auto RegClassInfo = Names2RegClasses.find(Name); if (RegClassInfo == Names2RegClasses.end()) return nullptr; @@ -827,7 +829,6 @@ const TargetRegisterClass *MIRParserImpl::getRegClass(const MachineFunction &MF, const RegisterBank *MIRParserImpl::getRegBank(const MachineFunction &MF, StringRef Name) { - initNames2RegBanks(MF); auto RegBankInfo = Names2RegBanks.find(Name); if (RegBankInfo == Names2RegBanks.end()) return nullptr; diff --git a/test/CodeGen/MIR/AArch64/register-operand-bank.mir b/test/CodeGen/MIR/AArch64/register-operand-bank.mir new file mode 100644 index 00000000000..d48495167f1 --- /dev/null +++ b/test/CodeGen/MIR/AArch64/register-operand-bank.mir @@ -0,0 +1,20 @@ +# RUN: llc -o - %s -mtriple=aarch64-- -run-pass=none | FileCheck %s +# REQUIRES: global-isel +# Test various aspects of register bank specification on machine operands. +--- | + define void @func() { ret void } +... +--- +# CHECK-LABEL: name: func +# CHECK: registers: +# CHECK: - { id: 0, class: gpr } +# CHECK: - { id: 1, class: fpr } +name: func +body: | + bb.0: + %0 : gpr(s64) = COPY %x9 + %x9 = COPY %0 + + %3 : fpr(s64) = COPY %d0 + %d1 = COPY %3 : fpr +... diff --git a/test/CodeGen/MIR/X86/register-operand-class-invalid0.mir b/test/CodeGen/MIR/X86/register-operand-class-invalid0.mir new file mode 100644 index 00000000000..10a9f2d7ceb --- /dev/null +++ b/test/CodeGen/MIR/X86/register-operand-class-invalid0.mir @@ -0,0 +1,13 @@ +# RUN: not llc -o /dev/null %s -march=x86-64 -run-pass none 2>&1 | FileCheck %s +# This test ensures that an error is reported for specifying the register class +# of a physical register. +--- | + define void @t() { ret void } +... +--- +name: t +body: | + bb.0: + ; CHECK: [[@LINE+1]]:10: register class specification expects a virtual register + %eax : gr32 = COPY %rdx +... diff --git a/test/CodeGen/MIR/X86/register-operand-class-invalid1.mir b/test/CodeGen/MIR/X86/register-operand-class-invalid1.mir new file mode 100644 index 00000000000..4be7fb38335 --- /dev/null +++ b/test/CodeGen/MIR/X86/register-operand-class-invalid1.mir @@ -0,0 +1,14 @@ +# RUN: not llc -o /dev/null %s -march=x86-64 -run-pass none 2>&1 | FileCheck %s +# This test ensures that an error is reported for specifying the register class +# of a physical register. +--- | + define void @t() { ret void } +... +--- +name: t +body: | + bb.0: + %0 : gr32 = COPY %rdx + ; CHECK: [[@LINE+1]]:24: conflicting register classes, previously: GR32 + NOOP implicit %0 : gr32_abcd +... diff --git a/test/CodeGen/MIR/X86/register-operand-class.mir b/test/CodeGen/MIR/X86/register-operand-class.mir new file mode 100644 index 00000000000..d21622b68a4 --- /dev/null +++ b/test/CodeGen/MIR/X86/register-operand-class.mir @@ -0,0 +1,24 @@ +# RUN: llc -o - %s -march=x86-64 -run-pass none | FileCheck %s +# Test various aspects of register class specification on machine operands. +--- | + define void @func() { ret void } +... +--- +# CHECK-LABEL: name: func +# CHECK: registers: +# CHECK: - { id: 0, class: gr32 } +# CHECK: - { id: 1, class: gr64 } +# CHECK: - { id: 2, class: gr32 } +# CHECK: - { id: 3, class: gr16 } +name: func +body: | + bb.0: + %0 : gr32 = COPY %rax + %1.sub_32bit : gr64 = COPY %eax + %rdx = COPY %1 + %2 = COPY %ecx + %ecx = COPY %2 : gr32 + + %3 : gr16 = COPY %bx + %bx = COPY %3 : gr16 +... -- 2.11.0