diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index c99dc40458d..138882809e2 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -159,6 +159,7 @@ struct MachineStackObject { int64_t Offset = 0; uint64_t Size = 0; unsigned Alignment = 0; + StringValue CalleeSavedRegister; }; template <> struct ScalarEnumerationTraits { @@ -181,6 +182,8 @@ template <> struct MappingTraits { if (Object.Type != MachineStackObject::VariableSized) YamlIO.mapRequired("size", Object.Size); YamlIO.mapOptional("alignment", Object.Alignment); + YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister, + StringValue()); // Don't print it out when it's empty. } static const bool flow = true; @@ -197,6 +200,7 @@ struct FixedMachineStackObject { unsigned Alignment = 0; bool IsImmutable = false; bool IsAliased = false; + StringValue CalleeSavedRegister; }; template <> @@ -221,6 +225,8 @@ template <> struct MappingTraits { YamlIO.mapOptional("isImmutable", Object.IsImmutable); YamlIO.mapOptional("isAliased", Object.IsAliased); } + YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister, + StringValue()); // Don't print it out when it's empty. } static const bool flow = true; @@ -296,7 +302,6 @@ struct MachineFrameInfo { bool HasCalls = false; // TODO: Serialize StackProtectorIdx and FunctionContextIdx unsigned MaxCallFrameSize = 0; - // TODO: Serialize callee saved info. // TODO: Serialize local frame objects. bool HasOpaqueSPAdjustment = false; bool HasVAStart = false; diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp index 67c939cc562..7f226713817 100644 --- a/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/lib/CodeGen/MIRParser/MIRParser.cpp @@ -107,10 +107,15 @@ public: const yaml::MachineFunction &YamlMF, PerFunctionMIParsingState &PFS); - bool initializeFrameInfo(const Function &F, MachineFrameInfo &MFI, + bool initializeFrameInfo(MachineFunction &MF, MachineFrameInfo &MFI, const yaml::MachineFunction &YamlMF, - DenseMap &StackObjectSlots, - DenseMap &FixedStackObjectSlots); + PerFunctionMIParsingState &PFS); + + bool parseCalleeSavedRegister(MachineFunction &MF, + PerFunctionMIParsingState &PFS, + std::vector &CSIInfo, + const yaml::StringValue &RegisterSource, + int FrameIdx); bool initializeConstantPool(MachineConstantPool &ConstantPool, const yaml::MachineFunction &YamlMF, @@ -273,8 +278,7 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) { PerFunctionMIParsingState PFS; if (initializeRegisterInfo(MF, MF.getRegInfo(), YamlMF, PFS)) return true; - if (initializeFrameInfo(*MF.getFunction(), *MF.getFrameInfo(), YamlMF, - PFS.StackObjectSlots, PFS.FixedStackObjectSlots)) + if (initializeFrameInfo(MF, *MF.getFrameInfo(), YamlMF, PFS)) return true; if (!YamlMF.Constants.empty()) { auto *ConstantPool = MF.getConstantPool(); @@ -401,11 +405,11 @@ bool MIRParserImpl::initializeRegisterInfo(MachineFunction &MF, return false; } -bool MIRParserImpl::initializeFrameInfo( - const Function &F, MachineFrameInfo &MFI, - const yaml::MachineFunction &YamlMF, - DenseMap &StackObjectSlots, - DenseMap &FixedStackObjectSlots) { +bool MIRParserImpl::initializeFrameInfo(MachineFunction &MF, + MachineFrameInfo &MFI, + const yaml::MachineFunction &YamlMF, + PerFunctionMIParsingState &PFS) { + const Function &F = *MF.getFunction(); const yaml::MachineFrameInfo &YamlMFI = YamlMF.FrameInfo; MFI.setFrameAddressIsTaken(YamlMFI.IsFrameAddressTaken); MFI.setReturnAddressIsTaken(YamlMFI.IsReturnAddressTaken); @@ -422,6 +426,7 @@ bool MIRParserImpl::initializeFrameInfo( MFI.setHasVAStart(YamlMFI.HasVAStart); MFI.setHasMustTailInVarArgFunc(YamlMFI.HasMustTailInVarArgFunc); + std::vector CSIInfo; // Initialize the fixed frame objects. for (const auto &Object : YamlMF.FixedStackObjects) { int ObjectIdx; @@ -432,7 +437,10 @@ bool MIRParserImpl::initializeFrameInfo( ObjectIdx = MFI.CreateFixedSpillStackObject(Object.Size, Object.Offset); MFI.setObjectAlignment(ObjectIdx, Object.Alignment); // TODO: Report an error when objects are redefined. - FixedStackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx)); + PFS.FixedStackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx)); + if (parseCalleeSavedRegister(MF, PFS, CSIInfo, Object.CalleeSavedRegister, + ObjectIdx)) + return true; } // Initialize the ordinary frame objects. @@ -457,8 +465,29 @@ bool MIRParserImpl::initializeFrameInfo( Object.Type == yaml::MachineStackObject::SpillSlot, Alloca); MFI.setObjectOffset(ObjectIdx, Object.Offset); // TODO: Report an error when objects are redefined. - StackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx)); + PFS.StackObjectSlots.insert(std::make_pair(Object.ID, ObjectIdx)); + if (parseCalleeSavedRegister(MF, PFS, CSIInfo, Object.CalleeSavedRegister, + ObjectIdx)) + return true; } + MFI.setCalleeSavedInfo(CSIInfo); + if (!CSIInfo.empty()) + MFI.setCalleeSavedInfoValid(true); + return false; +} + +bool MIRParserImpl::parseCalleeSavedRegister( + MachineFunction &MF, PerFunctionMIParsingState &PFS, + std::vector &CSIInfo, + const yaml::StringValue &RegisterSource, int FrameIdx) { + if (RegisterSource.Value.empty()) + return false; + unsigned Reg = 0; + SMDiagnostic Error; + if (parseNamedRegisterReference(Reg, SM, MF, RegisterSource.Value, PFS, + IRSlots, Error)) + return error(Error, RegisterSource.SourceRange); + CSIInfo.push_back(CalleeSavedInfo(Reg, FrameIdx)); return false; } diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index 574a0ddee1b..2287dfd4480 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -79,7 +79,8 @@ public: void convert(ModuleSlotTracker &MST, yaml::MachineBasicBlock &YamlMBB, const MachineBasicBlock &MBB); void convertStackObjects(yaml::MachineFunction &MF, - const MachineFrameInfo &MFI); + const MachineFrameInfo &MFI, + const TargetRegisterInfo *TRI); private: void initRegisterMaskIds(const MachineFunction &MF); @@ -156,7 +157,8 @@ void MIRPrinter::print(const MachineFunction &MF) { YamlMF.HasInlineAsm = MF.hasInlineAsm(); convert(YamlMF, MF.getRegInfo(), MF.getSubtarget().getRegisterInfo()); convert(YamlMF.FrameInfo, *MF.getFrameInfo()); - convertStackObjects(YamlMF, *MF.getFrameInfo()); + convertStackObjects(YamlMF, *MF.getFrameInfo(), + MF.getSubtarget().getRegisterInfo()); if (const auto *ConstantPool = MF.getConstantPool()) convert(YamlMF, *ConstantPool); @@ -219,7 +221,8 @@ void MIRPrinter::convert(yaml::MachineFrameInfo &YamlMFI, } void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF, - const MachineFrameInfo &MFI) { + const MachineFrameInfo &MFI, + const TargetRegisterInfo *TRI) { // Process fixed stack objects. unsigned ID = 0; for (int I = MFI.getObjectIndexBegin(); I < 0; ++I) { @@ -265,6 +268,19 @@ void MIRPrinter::convertStackObjects(yaml::MachineFunction &MF, StackObjectOperandMapping.insert(std::make_pair( I, FrameIndexOperand::create(YamlObject.Name.Value, ID++))); } + + for (const auto &CSInfo : MFI.getCalleeSavedInfo()) { + yaml::StringValue Reg; + printReg(CSInfo.getReg(), Reg, TRI); + auto StackObjectInfo = StackObjectOperandMapping.find(CSInfo.getFrameIdx()); + assert(StackObjectInfo != StackObjectOperandMapping.end() && + "Invalid stack object index"); + const FrameIndexOperand &StackObject = StackObjectInfo->second; + if (StackObject.IsFixed) + MF.FixedStackObjects[StackObject.ID].CalleeSavedRegister = Reg; + else + MF.StackObjects[StackObject.ID].CalleeSavedRegister = Reg; + } } void MIRPrinter::convert(yaml::MachineFunction &MF, diff --git a/test/CodeGen/MIR/X86/callee-saved-info.mir b/test/CodeGen/MIR/X86/callee-saved-info.mir new file mode 100644 index 00000000000..4ec5b50c364 --- /dev/null +++ b/test/CodeGen/MIR/X86/callee-saved-info.mir @@ -0,0 +1,98 @@ +# RUN: llc -march=x86-64 -start-after prologepilog -stop-after prologepilog -o /dev/null %s | FileCheck %s +# This test ensures that the MIR parser parses callee saved information in the +# stack objects correctly. + +--- | + + define i32 @compute(i32 %a) { + body: + ret i32 %a + } + + define i32 @func(i32 %a) { + entry: + %b = alloca i32 + store i32 %a, i32* %b + br label %check + + check: + %comp = icmp sle i32 %a, 10 + br i1 %comp, label %loop, label %exit + + loop: + %c = load i32, i32* %b + %d = call i32 @compute(i32 %c) + %e = sub i32 %d, 1 + store i32 %e, i32* %b + br label %check + + exit: + ret i32 0 + } + +... +--- +name: compute +tracksRegLiveness: true +body: + - id: 0 + name: body + liveins: [ '%edi' ] + instructions: + - '%eax = COPY killed %edi' + - 'RETQ killed %eax' +... +--- +name: func +tracksRegLiveness: true +frameInfo: + stackSize: 24 + maxAlignment: 4 + adjustsStack: true + hasCalls: true +# CHECK: fixedStack: +# CHECK-NEXT: , callee-saved-register: '%rbx' } +fixedStack: + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '%rbx' } +# CHECK: stack: +# CHECK-NEXT: - { id: 0 +# CHECK-NEXT: , callee-saved-register: '%edi' } +stack: + - { id: 0, name: b, offset: -20, size: 4, alignment: 4 } + - { id: 1, offset: -24, size: 4, alignment: 4, callee-saved-register: '%edi' } +body: + - id: 0 + name: entry + successors: [ '%bb.1.check' ] + liveins: [ '%edi', '%rbx' ] + instructions: + - 'frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp' + - '%rsp = frame-setup SUB64ri8 %rsp, 16, implicit-def dead %eflags' + - '%ebx = COPY %edi' + - 'MOV32mr %rsp, 1, _, 12, _, %ebx' + - id: 1 + name: check + successors: [ '%bb.2.loop', '%bb.3.exit' ] + liveins: [ '%ebx' ] + instructions: + - 'CMP32ri8 %ebx, 10, implicit-def %eflags' + - 'JG_1 %bb.3.exit, implicit killed %eflags' + - 'JMP_1 %bb.2.loop' + - id: 2 + name: loop + successors: [ '%bb.1.check' ] + liveins: [ '%ebx' ] + instructions: + - '%edi = MOV32rm %rsp, 1, _, 12, _' + - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax' + - '%eax = DEC32r killed %eax, implicit-def dead %eflags' + - 'MOV32mr %rsp, 1, _, 12, _, killed %eax' + - 'JMP_1 %bb.1.check' + - id: 3 + name: exit + instructions: + - '%eax = MOV32r0 implicit-def dead %eflags' + - '%rsp = ADD64ri8 %rsp, 16, implicit-def dead %eflags' + - '%rbx = POP64r implicit-def %rsp, implicit %rsp' + - 'RETQ %eax' +... diff --git a/test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir b/test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir new file mode 100644 index 00000000000..bd9e70420b5 --- /dev/null +++ b/test/CodeGen/MIR/X86/expected-named-register-in-callee-saved-register.mir @@ -0,0 +1,91 @@ +# RUN: not llc -march=x86-64 -start-after prologepilog -stop-after prologepilog -o /dev/null %s 2>&1 | FileCheck %s + +--- | + + define i32 @compute(i32 %a) { + body: + ret i32 %a + } + + define i32 @func(i32 %a) { + entry: + %b = alloca i32 + store i32 %a, i32* %b + br label %check + + check: + %comp = icmp sle i32 %a, 10 + br i1 %comp, label %loop, label %exit + + loop: + %c = load i32, i32* %b + %d = call i32 @compute(i32 %c) + %e = sub i32 %d, 1 + store i32 %e, i32* %b + br label %check + + exit: + ret i32 0 + } + +... +--- +name: compute +tracksRegLiveness: true +body: + - id: 0 + name: body + liveins: [ '%edi' ] + instructions: + - '%eax = COPY killed %edi' + - 'RETQ killed %eax' +... +--- +name: func +tracksRegLiveness: true +frameInfo: + stackSize: 24 + maxAlignment: 4 + adjustsStack: true + hasCalls: true +fixedStack: + # CHECK: [[@LINE+1]]:93: expected a named register + - { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16, callee-saved-register: '%0' } +stack: + - { id: 0, name: b, offset: -20, size: 4, alignment: 4 } +body: + - id: 0 + name: entry + successors: [ '%bb.1.check' ] + liveins: [ '%edi', '%rbx' ] + instructions: + - 'frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp' + - '%rsp = frame-setup SUB64ri8 %rsp, 16, implicit-def dead %eflags' + - '%ebx = COPY %edi' + - 'MOV32mr %rsp, 1, _, 12, _, %ebx' + - id: 1 + name: check + successors: [ '%bb.2.loop', '%bb.3.exit' ] + liveins: [ '%ebx' ] + instructions: + - 'CMP32ri8 %ebx, 10, implicit-def %eflags' + - 'JG_1 %bb.3.exit, implicit killed %eflags' + - 'JMP_1 %bb.2.loop' + - id: 2 + name: loop + successors: [ '%bb.1.check' ] + liveins: [ '%ebx' ] + instructions: + - '%edi = MOV32rm %rsp, 1, _, 12, _' + - 'CALL64pcrel32 @compute, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, implicit-def %eax' + - '%eax = DEC32r killed %eax, implicit-def dead %eflags' + - 'MOV32mr %rsp, 1, _, 12, _, killed %eax' + - 'JMP_1 %bb.1.check' + - id: 3 + name: exit + instructions: + - '%eax = MOV32r0 implicit-def dead %eflags' + - '%rsp = ADD64ri8 %rsp, 16, implicit-def dead %eflags' + - '%rbx = POP64r implicit-def %rsp, implicit %rsp' + - 'RETQ %eax' +...