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
This commit is contained in:
David Blaikie 2020-02-06 14:37:23 -08:00
parent a7e7e73c64
commit f21a88cbf6
4 changed files with 65 additions and 24 deletions

View File

@ -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**

View File

@ -1277,11 +1277,17 @@ Error IRLinker::linkModuleFlagsMetadata() {
}
// Diagnose inconsistent merge behavior types.
if (SrcBehaviorValue != DstBehaviorValue)
return stringErr("linking module flags '" + ID->getString() +
"': IDs have conflicting behaviors in '" +
SrcM->getModuleIdentifier() + "' and '" +
DstM.getModuleIdentifier() + "'");
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.

View File

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

View File

@ -0,0 +1,12 @@
; 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}