static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); }
};
+/// A wrapper around unsigned which contains a source range that's being set
+/// during parsing.
+struct UnsignedValue {
+ unsigned Value;
+ SMRange SourceRange;
+
+ UnsignedValue() : Value(0) {}
+ UnsignedValue(unsigned Value) : Value(Value) {}
+
+ bool operator==(const UnsignedValue &Other) const {
+ return Value == Other.Value;
+ }
+};
+
+template <> struct ScalarTraits<UnsignedValue> {
+ static void output(const UnsignedValue &Value, void *Ctx, raw_ostream &OS) {
+ return ScalarTraits<unsigned>::output(Value.Value, Ctx, OS);
+ }
+
+ static StringRef input(StringRef Scalar, void *Ctx, UnsignedValue &Value) {
+ if (const auto *Node =
+ reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
+ Value.SourceRange = Node->getSourceRange();
+ return ScalarTraits<unsigned>::input(Scalar, Ctx, Value.Value);
+ }
+
+ static bool mustQuote(StringRef Scalar) {
+ return ScalarTraits<unsigned>::mustQuote(Scalar);
+ }
+};
+
template <> struct ScalarEnumerationTraits<MachineJumpTableInfo::JTEntryKind> {
static void enumeration(yaml::IO &IO,
MachineJumpTableInfo::JTEntryKind &EntryKind) {
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue)
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue)
namespace llvm {
namespace yaml {
unsigned Alignment = 0;
bool IsLandingPad = false;
bool AddressTaken = false;
- // TODO: Serialize the successor weights.
std::vector<FlowStringValue> Successors;
+ std::vector<UnsignedValue> SuccessorWeights;
std::vector<FlowStringValue> LiveIns;
std::vector<StringValue> Instructions;
};
YamlIO.mapOptional("isLandingPad", MBB.IsLandingPad);
YamlIO.mapOptional("addressTaken", MBB.AddressTaken);
YamlIO.mapOptional("successors", MBB.Successors);
+ YamlIO.mapOptional("weights", MBB.SuccessorWeights);
YamlIO.mapOptional("liveins", MBB.LiveIns);
YamlIO.mapOptional("instructions", MBB.Instructions);
}
class BasicBlock;
class MachineFunction;
class MCSymbol;
+class MIRPrinter;
class SlotIndexes;
class StringRef;
class raw_ostream;
/// which refer to fromMBB to refer to this.
void transferSuccessorsAndUpdatePHIs(MachineBasicBlock *fromMBB);
+ /// Return true if any of the successors have weights attached to them.
+ bool hasSuccessorWeights() const { return !Weights.empty(); }
+
/// isPredecessor - Return true if the specified MBB is a predecessor of this
/// block.
bool isPredecessor(const MachineBasicBlock *MBB) const;
const_weight_iterator getWeightIterator(const_succ_iterator I) const;
friend class MachineBranchProbabilityInfo;
+ friend class MIRPrinter;
/// getSuccWeight - Return weight of the edge from this block to MBB. This
/// method should NOT be called directly, but by using getEdgeWeight method
MBB.setIsLandingPad(YamlMBB.IsLandingPad);
SMDiagnostic Error;
// Parse the successors.
+ const auto &Weights = YamlMBB.SuccessorWeights;
+ bool HasWeights = !Weights.empty();
+ if (HasWeights && Weights.size() != YamlMBB.Successors.size()) {
+ bool IsFew = Weights.size() < YamlMBB.Successors.size();
+ return error(IsFew ? Weights.back().SourceRange.End
+ : Weights[YamlMBB.Successors.size()].SourceRange.Start,
+ Twine("too ") + (IsFew ? "few" : "many") +
+ " successor weights, expected " +
+ Twine(YamlMBB.Successors.size()) + ", have " +
+ Twine(Weights.size()));
+ }
+ size_t SuccessorIndex = 0;
for (const auto &MBBSource : YamlMBB.Successors) {
MachineBasicBlock *SuccMBB = nullptr;
if (parseMBBReference(SuccMBB, MBBSource, MF, PFS))
return true;
// TODO: Report an error when adding the same successor more than once.
- MBB.addSuccessor(SuccMBB);
+ MBB.addSuccessor(SuccMBB, HasWeights ? Weights[SuccessorIndex++].Value : 0);
}
// Parse the liveins.
for (const auto &LiveInSource : YamlMBB.LiveIns) {
}
};
+} // end anonymous namespace
+
+namespace llvm {
+
/// This class prints out the machine functions using the MIR serialization
/// format.
class MIRPrinter {
void initRegisterMaskIds(const MachineFunction &MF);
};
+} // end namespace llvm
+
+namespace {
+
/// This class prints out the machine instructions using the MIR serialization
/// format.
class MIPrinter {
.printMBBReference(*SuccMBB);
YamlMBB.Successors.push_back(StrOS.str());
}
+ if (MBB.hasSuccessorWeights()) {
+ for (auto I = MBB.succ_begin(), E = MBB.succ_end(); I != E; ++I)
+ YamlMBB.SuccessorWeights.push_back(
+ yaml::UnsignedValue(MBB.getSuccWeight(I)));
+ }
// Print the live in registers.
const auto *TRI = MBB.getParent()->getSubtarget().getRegisterInfo();
assert(TRI && "Expected target register info");
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+ 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: foo
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.less', '%bb.2.exit' ]
+# CHECK: [[@LINE+1]]:23: too few successor weights, expected 2, have 1
+ weights: [ 16 ]
+ liveins: [ '%edi' ]
+ instructions:
+ - 'CMP32ri8 %edi, 10, implicit-def %eflags'
+ - 'JG_1 %bb.2.exit, implicit killed %eflags'
+ - id: 1
+ name: less
+ instructions:
+ - '%eax = MOV32r0 implicit-def dead %eflags'
+ - 'RETQ killed %eax'
+ - id: 2
+ name: exit
+ liveins: [ '%edi' ]
+ instructions:
+ - '%eax = COPY killed %edi'
+ - 'RETQ killed %eax'
+...
--- /dev/null
+# RUN: not llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s 2>&1 | FileCheck %s
+
+--- |
+
+ 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: foo
+body:
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.less', '%bb.2.exit' ]
+# CHECK: [[@LINE+1]]:28: too many successor weights, expected 2, have 3
+ weights: [ 16, 16, 16 ]
+ liveins: [ '%edi' ]
+ instructions:
+ - 'CMP32ri8 %edi, 10, implicit-def %eflags'
+ - 'JG_1 %bb.2.exit, implicit killed %eflags'
+ - id: 1
+ name: less
+ instructions:
+ - '%eax = MOV32r0 implicit-def dead %eflags'
+ - 'RETQ killed %eax'
+ - id: 2
+ name: exit
+ liveins: [ '%edi' ]
+ instructions:
+ - '%eax = COPY killed %edi'
+ - 'RETQ killed %eax'
+...
--- /dev/null
+# RUN: llc -march=x86-64 -start-after branch-folder -stop-after branch-folder -o /dev/null %s | FileCheck %s
+# This test ensures that the MIR parser parses basic block successors and
+# weights correctly.
+
+--- |
+
+ 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: foo
+body:
+ # CHECK: name: entry
+ # CHECK: successors: [ '%bb.1.less', '%bb.2.exit' ]
+ # CHECK-NEXT: weights: [ 16, 32 ]
+ # CHECK: name: less
+ - id: 0
+ name: entry
+ successors: [ '%bb.1.less', '%bb.2.exit' ]
+ weights: [ 16, 32 ]
+ liveins: [ '%edi' ]
+ instructions:
+ - 'CMP32ri8 %edi, 10, implicit-def %eflags'
+ - 'JG_1 %bb.2.exit, implicit killed %eflags'
+ - id: 1
+ name: less
+ instructions:
+ - '%eax = MOV32r0 implicit-def dead %eflags'
+ - 'RETQ killed %eax'
+ - id: 2
+ name: exit
+ liveins: [ '%edi' ]
+ instructions:
+ - '%eax = COPY killed %edi'
+ - 'RETQ killed %eax'
+...