Commit ba9cae58 authored by David Blaikie's avatar David Blaikie
Browse files

IR Linking: Support merging Warning+Max module metadata flags

Summary:
Debug Info Version was changed to use "Max" instead of "Warning" per the
original design intent - but this maxes old/new IR unlinkable, since
mismatched merge styles are a linking failure.

It seems possible/maybe reasonable to actually support the combination
of these two flags: Warn, but then use the maximum value rather than the
first value/earlier module's value.

Reviewers: tejohnson

Differential Revision: https://reviews.llvm.org/D74257
parent 35c63d66
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -6224,7 +6224,9 @@ The following behaviors are supported:
   * - 2
     - **Warning**
           Emits a warning if two values disagree. The result value will be the
           operand for the flag from the first module being linked.
           operand for the flag from the first module being linked, or the max
           if the other module uses **Max** (in which case the resulting flag
           will be **Max**).
   * - 3
     - **Require**
+47 −23
Original line number Diff line number Diff line
@@ -1277,11 +1277,17 @@ Error IRLinker::linkModuleFlagsMetadata() {
    }

    // Diagnose inconsistent merge behavior types.
    if (SrcBehaviorValue != DstBehaviorValue)
    if (SrcBehaviorValue != DstBehaviorValue) {
      bool MaxAndWarn = (SrcBehaviorValue == Module::Max &&
                         DstBehaviorValue == Module::Warning) ||
                        (DstBehaviorValue == Module::Max &&
                         SrcBehaviorValue == Module::Warning);
      if (!MaxAndWarn)
        return stringErr("linking module flags '" + ID->getString() +
                         "': IDs have conflicting behaviors in '" +
                         SrcM->getModuleIdentifier() + "' and '" +
                         DstM.getModuleIdentifier() + "'");
    }

    auto replaceDstValue = [&](MDNode *New) {
      Metadata *FlagOps[] = {DstOp->getOperand(0), ID, New};
@@ -1290,6 +1296,40 @@ Error IRLinker::linkModuleFlagsMetadata() {
      Flags[ID].first = Flag;
    };

    // Emit a warning if the values differ and either source or destination
    // request Warning behavior.
    if ((DstBehaviorValue == Module::Warning ||
         SrcBehaviorValue == Module::Warning) &&
        SrcOp->getOperand(2) != DstOp->getOperand(2)) {
      std::string Str;
      raw_string_ostream(Str)
          << "linking module flags '" << ID->getString()
          << "': IDs have conflicting values ('" << *SrcOp->getOperand(2)
          << "' from " << SrcM->getModuleIdentifier() << " with '"
          << *DstOp->getOperand(2) << "' from " << DstM.getModuleIdentifier()
          << ')';
      emitWarning(Str);
    }

    // Choose the maximum if either source or destination request Max behavior.
    if (DstBehaviorValue == Module::Max || SrcBehaviorValue == Module::Max) {
      ConstantInt *DstValue =
          mdconst::extract<ConstantInt>(DstOp->getOperand(2));
      ConstantInt *SrcValue =
          mdconst::extract<ConstantInt>(SrcOp->getOperand(2));

      // The resulting flag should have a Max behavior, and contain the maximum
      // value from between the source and destination values.
      Metadata *FlagOps[] = {
          (DstBehaviorValue != Module::Max ? SrcOp : DstOp)->getOperand(0), ID,
          (SrcValue->getZExtValue() > DstValue->getZExtValue() ? SrcOp : DstOp)
              ->getOperand(2)};
      MDNode *Flag = MDNode::get(DstM.getContext(), FlagOps);
      DstModFlags->setOperand(DstIndex, Flag);
      Flags[ID].first = Flag;
      continue;
    }

    // Perform the merge for standard behavior types.
    switch (SrcBehaviorValue) {
    case Module::Require:
@@ -1305,26 +1345,9 @@ Error IRLinker::linkModuleFlagsMetadata() {
      continue;
    }
    case Module::Warning: {
      // Emit a warning if the values differ.
      if (SrcOp->getOperand(2) != DstOp->getOperand(2)) {
        std::string str;
        raw_string_ostream(str)
            << "linking module flags '" << ID->getString()
            << "': IDs have conflicting values ('" << *SrcOp->getOperand(2)
            << "' from " << SrcM->getModuleIdentifier() << " with '"
            << *DstOp->getOperand(2) << "' from " << DstM.getModuleIdentifier()
            << ')';
        emitWarning(str);
      }
      continue;
      break;
    }
    case Module::Max: {
      ConstantInt *DstValue =
          mdconst::extract<ConstantInt>(DstOp->getOperand(2));
      ConstantInt *SrcValue =
          mdconst::extract<ConstantInt>(SrcOp->getOperand(2));
      if (SrcValue->getZExtValue() > DstValue->getZExtValue())
        overrideDstValue();
      break;
    }
    case Module::Append: {
@@ -1350,6 +1373,7 @@ Error IRLinker::linkModuleFlagsMetadata() {
      break;
    }
    }

  }

  // Check all of the requirements.
+3 −0
Original line number Diff line number Diff line
!llvm.module.flags = !{!0, !1}
!0 = !{i32 2, !"Combine Max and Warn", i32 4}
!1 = !{i32 7, !"Combine Warn and Max", i32 5}
+12 −0
Original line number Diff line number Diff line
; RUN: llvm-link %s %p/Inputs/module-max-warn.ll -S -o - 2>&1 | FileCheck %s

; CHECK: warning: linking module flags 'Combine Max and Warn': IDs have conflicting values ('i32 4' from {{.*}}/test/Linker/Inputs/module-max-warn.ll with 'i32 2' from llvm-link)
; CHECK: warning: linking module flags 'Combine Warn and Max': IDs have conflicting values ('i32 5' from {{.*}}/test/Linker/Inputs/module-max-warn.ll with 'i32 3' from llvm-link)


; CHECK: !0 = !{i32 7, !"Combine Max and Warn", i32 4}
; CHECK: !1 = !{i32 7, !"Combine Warn and Max", i32 5}

!llvm.module.flags = !{!0, !1}
!0 = !{i32 7, !"Combine Max and Warn", i32 2}
!1 = !{i32 2, !"Combine Warn and Max", i32 3}