Index: include/llvm/CodeGen/MIRYamlMapping.h =================================================================== --- include/llvm/CodeGen/MIRYamlMapping.h +++ include/llvm/CodeGen/MIRYamlMapping.h @@ -390,6 +390,7 @@ std::vector VirtualRegisters; std::vector LiveIns; Optional> CalleeSavedRegisters; + Optional> UnusedPhysRegs; // TODO: Serialize the various register masks. // Frame information MachineFrameInfo FrameInfo; @@ -412,6 +413,7 @@ YamlIO.mapOptional("registers", MF.VirtualRegisters); YamlIO.mapOptional("liveins", MF.LiveIns); YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters); + YamlIO.mapOptional("UnusedPhysRegs", MF.UnusedPhysRegs); YamlIO.mapOptional("frameInfo", MF.FrameInfo); YamlIO.mapOptional("fixedStack", MF.FixedStackObjects); YamlIO.mapOptional("stack", MF.StackObjects); Index: include/llvm/CodeGen/MachineRegisterInfo.h =================================================================== --- include/llvm/CodeGen/MachineRegisterInfo.h +++ include/llvm/CodeGen/MachineRegisterInfo.h @@ -75,12 +75,11 @@ /// The flag is true upon \p UpdatedCSRs initialization /// and false otherwise. - bool IsUpdatedCSRsInitizialied; + bool IsUpdatedCSRsInitialized; /// Contains the updated callee saved register list. /// As opposed to the static list defined in register info, - /// all registers that were disabled (in CalleeSaveDisableRegs) - /// are removed from the list. + /// all registers that were disabled are removed from the list. SmallVector UpdatedCSRs; /// RegAllocHints - This vector records register allocation hints for virtual @@ -217,6 +216,9 @@ // Register Info //===--------------------------------------------------------------------===// + /// Returns true if the updated CSR list was initialized and false otherwise. + bool isUpdatedCSRsInitialized() const { return IsUpdatedCSRsInitialized; } + /// Disables the register from the list of CSRs. /// I.e. the register will not appear as part of the CSR mask. /// \see UpdatedCalleeSavedRegs. @@ -227,6 +229,10 @@ /// registers that are disabled from the CSR list). const MCPhysReg *getCalleeSavedRegs() const; + /// Sets the updated Callee Saved Registers list. + /// Notice that it will override ant previously disabled/saved CSRs. + void setCalleeSavedRegs(const SmallVectorImpl &CSRs); + // Strictly for use by MachineInstr.cpp. void addRegOperandToUseList(MachineOperand *MO); Index: lib/CodeGen/MIRParser/MIParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIParser.cpp +++ lib/CodeGen/MIRParser/MIParser.cpp @@ -176,6 +176,7 @@ bool parseIntrinsicOperand(MachineOperand &Dest); bool parsePredicateOperand(MachineOperand &Dest); bool parseTargetIndexOperand(MachineOperand &Dest); + bool parseCustomRegisterMaskOperand(MachineOperand &Dest); bool parseLiveoutRegisterMaskOperand(MachineOperand &Dest); bool parseMachineOperand(MachineOperand &Dest, Optional &TiedDefIdx); @@ -1670,6 +1671,35 @@ return false; } +bool MIParser::parseCustomRegisterMaskOperand(MachineOperand &Dest) { + assert(Token.stringValue() == "CustomRegMask" && "Expected a custom RegMask"); + const auto *TRI = MF.getSubtarget().getRegisterInfo(); + assert(TRI && "Expected target register info"); + lex(); + if (expectAndConsume(MIToken::lparen)) + return true; + + // Expecting a register mask as a list of hexdecimal values. + APInt Result; + uint32_t *Mask = MF.allocateRegisterMask(TRI->getNumRegs()); + unsigned int RegMaskSize = (TRI->getNumRegs() + 31) / 32; + for (unsigned I = 0, E = RegMaskSize; I < E; I++) { + assert(Token.is(MIToken::HexLiteral) && "Expecting hexdecimal number"); + if (getHexUint(Result)) + return true; + Mask[I] = Result.getLimitedValue(uint64_t(1) << 32); + lex(); + if (Token.isNot(MIToken::comma)) + break; + lex(); + } + + if (expectAndConsume(MIToken::rparen)) + return true; + Dest = MachineOperand::CreateRegMask(Mask); + return false; +} + bool MIParser::parseLiveoutRegisterMaskOperand(MachineOperand &Dest) { assert(Token.is(MIToken::kw_liveout)); const auto *TRI = MF.getSubtarget().getRegisterInfo(); @@ -1767,8 +1797,8 @@ Dest = MachineOperand::CreateRegMask(RegMask); lex(); break; - } - LLVM_FALLTHROUGH; + } else + return parseCustomRegisterMaskOperand(Dest); default: // FIXME: Parse the MCSymbol machine operand. return error("expected a machine operand"); @@ -1919,7 +1949,7 @@ return true; StringRef V = S.substr(2); APInt A(V.size()*4, V, 16); - Result = APInt(A.getActiveBits(), + Result = APInt(std::max(A.getActiveBits(), 1u), ArrayRef(A.getRawData(), A.getNumWords())); return false; } Index: lib/CodeGen/MIRParser/MIRParser.cpp =================================================================== --- lib/CodeGen/MIRParser/MIRParser.cpp +++ lib/CodeGen/MIRParser/MIRParser.cpp @@ -465,17 +465,32 @@ RegInfo.addLiveIn(Reg, VReg); } - // Parse the callee saved register mask. - BitVector CalleeSavedRegisterMask(RegInfo.getUsedPhysRegsMask().size()); - if (!YamlMF.CalleeSavedRegisters) - return false; - for (const auto &RegSource : YamlMF.CalleeSavedRegisters.getValue()) { - unsigned Reg = 0; - if (parseNamedRegisterReference(PFS, Reg, RegSource.Value, Error)) - return error(Error, RegSource.SourceRange); - CalleeSavedRegisterMask[Reg] = true; + // Parse unused physical registers (Registers that will + // not be modified by callees). + if (YamlMF.UnusedPhysRegs) { + BitVector UnusedPhysRegisterMask(RegInfo.getUsedPhysRegsMask().size()); + for (const auto &RegSource : YamlMF.UnusedPhysRegs.getValue()) { + unsigned Reg = 0; + if (parseNamedRegisterReference(PFS, Reg, RegSource.Value, Error)) + return error(Error, RegSource.SourceRange); + UnusedPhysRegisterMask[Reg] = true; + } + RegInfo.setUsedPhysRegMask(UnusedPhysRegisterMask.flip()); } - RegInfo.setUsedPhysRegMask(CalleeSavedRegisterMask.flip()); + + // Parse the callee saved registers (Registers that will + // be saved for the caller). + if (YamlMF.CalleeSavedRegisters) { + SmallVector CalleeSavedRegisters; + for (const auto &RegSource : YamlMF.CalleeSavedRegisters.getValue()) { + unsigned Reg = 0; + if (parseNamedRegisterReference(PFS, Reg, RegSource.Value, Error)) + return error(Error, RegSource.SourceRange); + CalleeSavedRegisters.push_back(Reg); + } + RegInfo.setCalleeSavedRegs(CalleeSavedRegisters); + } + return false; } @@ -508,7 +523,7 @@ } // Compute MachineRegisterInfo::UsedPhysRegMask - if (!YamlMF.CalleeSavedRegisters) { + if (!YamlMF.UnusedPhysRegs) { for (const MachineBasicBlock &MBB : MF) { for (const MachineInstr &MI : MBB) { for (const MachineOperand &MO : MI.operands()) { Index: lib/CodeGen/MIRPrinter.cpp =================================================================== --- lib/CodeGen/MIRPrinter.cpp +++ lib/CodeGen/MIRPrinter.cpp @@ -148,6 +148,21 @@ } // end namespace yaml } // end namespace llvm +static void printCustomRegMask(const uint32_t *RegMask, raw_ostream &OS, + const TargetRegisterInfo *TRI) { + assert(RegMask && "Can't print an empty register mask"); + OS << StringRef("CustomRegMask("); + + // Printing a register mask as a list of hexdecimal values. + unsigned int RegMaskSize = (TRI->getNumRegs() + 31) / 32; + for (int I = 0, E = RegMaskSize; I < E; I++) { + OS << format("0x%08" PRIx32, RegMask[I]); + if (I + 1 < E) + OS << ','; + } + OS << ')'; +} + static void printReg(unsigned Reg, raw_ostream &OS, const TargetRegisterInfo *TRI) { // TODO: Print Stack Slots. @@ -242,17 +257,29 @@ // The used physical register mask is printed as an inverted callee saved // register mask. const BitVector &UsedPhysRegMask = RegInfo.getUsedPhysRegsMask(); - if (UsedPhysRegMask.none()) - return; - std::vector CalleeSavedRegisters; - for (unsigned I = 0, E = UsedPhysRegMask.size(); I != E; ++I) { - if (!UsedPhysRegMask[I]) { + if (!UsedPhysRegMask.none()) { + std::vector UnusedPhysRegs; + for (unsigned I = 0, E = UsedPhysRegMask.size(); I != E; ++I) { + if (!UsedPhysRegMask[I]) { + yaml::FlowStringValue Reg; + printReg(I, Reg, TRI); + UnusedPhysRegs.push_back(Reg); + } + } + MF.UnusedPhysRegs = UnusedPhysRegs; + } + + // Prints the callee saved registers. + if (RegInfo.isUpdatedCSRsInitialized()) { + const MCPhysReg *CalleeSavedRegs = RegInfo.getCalleeSavedRegs(); + std::vector CalleeSavedRegisters; + for (const MCPhysReg *I = CalleeSavedRegs; *I; ++I) { yaml::FlowStringValue Reg; - printReg(I, Reg, TRI); + printReg(*I, Reg, TRI); CalleeSavedRegisters.push_back(Reg); } + MF.CalleeSavedRegisters = CalleeSavedRegisters; } - MF.CalleeSavedRegisters = CalleeSavedRegisters; } void MIRPrinter::convert(ModuleSlotTracker &MST, @@ -859,6 +886,8 @@ auto RegMaskInfo = RegisterMaskIds.find(Op.getRegMask()); if (RegMaskInfo != RegisterMaskIds.end()) OS << StringRef(TRI->getRegMaskNames()[RegMaskInfo->second]).lower(); + else if (Op.getRegMask()) + printCustomRegMask(Op.getRegMask(), OS, TRI); else llvm_unreachable("Can't print this machine register mask yet."); break; Index: lib/CodeGen/MachineRegisterInfo.cpp =================================================================== --- lib/CodeGen/MachineRegisterInfo.cpp +++ lib/CodeGen/MachineRegisterInfo.cpp @@ -44,7 +44,7 @@ MachineRegisterInfo::MachineRegisterInfo(MachineFunction *MF) : MF(MF), TracksSubRegLiveness(MF->getSubtarget().enableSubRegLiveness() && EnableSubRegLiveness), - IsUpdatedCSRsInitizialied(false) { + IsUpdatedCSRsInitialized(false) { unsigned NumRegs = getTargetRegisterInfo()->getNumRegs(); VRegInfo.reserve(256); RegAllocHints.reserve(256); @@ -564,7 +564,7 @@ assert(Reg && (Reg < TRI->getNumRegs()) && "Trying to disable an invalid register"); - if (!IsUpdatedCSRsInitizialied) { + if (!IsUpdatedCSRsInitialized) { const MCPhysReg *CSR = TRI->getCalleeSavedRegs(MF); for (const MCPhysReg *I = CSR; *I; ++I) UpdatedCSRs.push_back(*I); @@ -573,7 +573,7 @@ // (no more registers should be pushed). UpdatedCSRs.push_back(0); - IsUpdatedCSRsInitizialied = true; + IsUpdatedCSRsInitialized = true; } // Remove the register (and its aliases from the list). @@ -583,8 +583,22 @@ } const MCPhysReg *MachineRegisterInfo::getCalleeSavedRegs() const { - if (IsUpdatedCSRsInitizialied) + if (IsUpdatedCSRsInitialized) return UpdatedCSRs.data(); return getTargetRegisterInfo()->getCalleeSavedRegs(MF); } + +void MachineRegisterInfo::setCalleeSavedRegs( + const SmallVectorImpl &CSRs) { + if (IsUpdatedCSRsInitialized) + UpdatedCSRs.clear(); + + for (auto Reg : CSRs) + UpdatedCSRs.push_back(Reg); + + // Zero value represents the end of the register list + // (no more registers should be pushed). + UpdatedCSRs.push_back(0); + IsUpdatedCSRsInitialized = true; +} Index: test/CodeGen/MIR/Generic/dynamic-regmask.ll =================================================================== --- test/CodeGen/MIR/Generic/dynamic-regmask.ll +++ test/CodeGen/MIR/Generic/dynamic-regmask.ll @@ -0,0 +1,30 @@ +; RUN: llc -stop-after machine-sink %s -o %t.mir +; RUN: FileCheck %s < %t.mir +; RUN: llc %t.mir -run-pass machine-sink +; Check that callee saved registers are printed in a format that can then be parsed. + +declare x86_regcallcc i32 @callee(i32 %a0, i32 %b0, i32 %c0, i32 %d0, i32 %e0) + +define i32 @caller(i32 %a0) nounwind { + %b1 = call x86_regcallcc i32 @callee(i32 %a0, i32 %a0, i32 %a0, i32 %a0, i32 %a0) + %b2 = add i32 %b1, %a0 + ret i32 %b2 +} +; CHECK: name: caller +; CHECK: CALL64pcrel32 @callee, CustomRegMask(0x403001f0,0x00019030,0x00000000,0x003f0000,0x00003fc0,0x00000000,0x00000000,0x003f3f3f) +; CHECK: RET 0, %eax + +define x86_regcallcc {i32, i32, i32} @test_callee(i32 %a0, i32 %b0, i32 %c0, i32 %d0, i32 %e0) nounwind { + %b1 = mul i32 7, %e0 + %b2 = udiv i32 5, %e0 + %b3 = mul i32 7, %d0 + %b4 = insertvalue {i32, i32, i32} undef, i32 %b1, 0 + %b5 = insertvalue {i32, i32, i32} %b4, i32 %b2, 1 + %b6 = insertvalue {i32, i32, i32} %b5, i32 %b3, 2 + ret {i32, i32, i32} %b6 +} +; CHECK: name: test_callee +; CHECK: calleeSavedRegisters: [ '%rbx', '%rbp', '%rsp', '%r10', '%r11', '%r12', +; CHECK: '%r13', '%r14', '%r15', '%xmm8', '%xmm9', '%xmm10', +; CHECK: '%xmm11', '%xmm12', '%xmm13', '%xmm14', '%xmm15' ] +; CHECK: RET 0, %eax, %ecx, %edx Index: test/CodeGen/MIR/X86/used-physical-register-info.mir =================================================================== --- test/CodeGen/MIR/X86/used-physical-register-info.mir +++ test/CodeGen/MIR/X86/used-physical-register-info.mir @@ -53,14 +53,14 @@ liveins: - { reg: '%edi' } # CHECK: name: foo -# CHECK: calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', -# CHECK-NEXT: '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', -# CHECK-NEXT: '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', -# CHECK-NEXT: '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] -calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', - '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', - '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', - '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] +# CHECK: UnusedPhysRegs: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', +# CHECK-NEXT: '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', '%r12b', +# CHECK-NEXT: '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', '%r14d', +# CHECK-NEXT: '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] +UnusedPhysRegs: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', + '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', '%r12b', + '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', '%r14d', + '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] body: | bb.0.entry: liveins: %edi @@ -77,10 +77,10 @@ # Verify that the callee saved register can be inferred from register mask # machine operands: # CHECK: name: bar -# CHECK: calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', -# CHECK-NEXT: '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', -# CHECK-NEXT: '%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', -# CHECK-NEXT: '%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] +# CHECK: UnusedPhysRegs: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx', +# CHECK-NEXT: '%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15', '%r12b', +# CHECK-NEXT: '%r13b', '%r14b', '%r15b', '%r12d', '%r13d', '%r14d', +# CHECK-NEXT: '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ] body: | bb.0.entry: liveins: %edi @@ -96,8 +96,8 @@ - { reg: '%edi' } # Verify that the callee saved register can be empty. # CHECK: name: empty -# CHECK: calleeSavedRegisters: [ ] -calleeSavedRegisters: [ ] +# CHECK: UnusedPhysRegs: [ ] +UnusedPhysRegs: [ ] body: | bb.0.entry: liveins: %edi