From b0011ef93ba325cd0d2eae653247e842457d3108 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Tue, 23 May 2017 00:08:00 +0000 Subject: [PATCH] Support for taking the max of module flags when linking, use for PIE/PIC Summary: Add Max ModFlagBehavior, which can be used to take the max of two module flag values when merging modules. Use it for the PIE and PIC levels. This avoids an error when we try to import from a module built -fpic into a module built -fPIC, for example. For both PIE and PIC levels, this will be legal, since the code generation gets more conservative as the level is increased. Therefore we can take the max instead of somehow trying to block importing between modules compiled with different levels. Reviewers: tmsriram, pcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D33418 llvm-svn: 303590 --- include/llvm/IR/Module.h | 5 ++++- lib/IR/Module.cpp | 4 ++-- lib/IR/Verifier.cpp | 7 +++++++ lib/Linker/IRMover.cpp | 17 +++++++++++++++-- test/Linker/Inputs/module-flags-pic-2-b.ll | 5 +++-- test/Linker/module-flags-pic-2-a.ll | 13 +++++++------ test/Verifier/module-flags-1.ll | 6 +++++- 7 files changed, 43 insertions(+), 14 deletions(-) diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 3024d9e27a2..5e1f680c5b3 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -139,9 +139,12 @@ public: /// during the append operation. AppendUnique = 6, + /// Takes the max of the two values, which are required to be integers. + Max = 7, + // Markers: ModFlagBehaviorFirstVal = Error, - ModFlagBehaviorLastVal = AppendUnique + ModFlagBehaviorLastVal = Max }; /// Checks if Metadata represents a valid ModFlagBehavior, and stores the diff --git a/lib/IR/Module.cpp b/lib/IR/Module.cpp index 12c258d95f5..95673e515a5 100644 --- a/lib/IR/Module.cpp +++ b/lib/IR/Module.cpp @@ -481,7 +481,7 @@ PICLevel::Level Module::getPICLevel() const { } void Module::setPICLevel(PICLevel::Level PL) { - addModuleFlag(ModFlagBehavior::Error, "PIC Level", PL); + addModuleFlag(ModFlagBehavior::Max, "PIC Level", PL); } PIELevel::Level Module::getPIELevel() const { @@ -495,7 +495,7 @@ PIELevel::Level Module::getPIELevel() const { } void Module::setPIELevel(PIELevel::Level PL) { - addModuleFlag(ModFlagBehavior::Error, "PIE Level", PL); + addModuleFlag(ModFlagBehavior::Max, "PIE Level", PL); } void Module::setProfileSummary(Metadata *M) { diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 21e8048442b..ffb9ad27922 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -1282,6 +1282,13 @@ Verifier::visitModuleFlag(const MDNode *Op, // These behavior types accept any value. break; + case Module::Max: { + Assert(mdconst::dyn_extract_or_null(Op->getOperand(2)), + "invalid value for 'max' module flag (expected constant integer)", + Op->getOperand(2)); + break; + } + case Module::Require: { // The value should itself be an MDNode with two operands, a flag ID (an // MDString), and a value. diff --git a/lib/Linker/IRMover.cpp b/lib/Linker/IRMover.cpp index c0af21aa148..defad190498 100644 --- a/lib/Linker/IRMover.cpp +++ b/lib/Linker/IRMover.cpp @@ -1157,6 +1157,11 @@ Error IRLinker::linkModuleFlagsMetadata() { mdconst::extract(DstOp->getOperand(0)); unsigned DstBehaviorValue = DstBehavior->getZExtValue(); + auto overrideDstValue = [&]() { + DstModFlags->setOperand(DstIndex, SrcOp); + Flags[ID].first = SrcOp; + }; + // If either flag has override behavior, handle it first. if (DstBehaviorValue == Module::Override) { // Diagnose inconsistent flags which both have override behavior. @@ -1167,8 +1172,7 @@ Error IRLinker::linkModuleFlagsMetadata() { continue; } else if (SrcBehaviorValue == Module::Override) { // Update the destination flag to that of the source. - DstModFlags->setOperand(DstIndex, SrcOp); - Flags[ID].first = SrcOp; + overrideDstValue(); continue; } @@ -1204,6 +1208,15 @@ Error IRLinker::linkModuleFlagsMetadata() { } continue; } + case Module::Max: { + ConstantInt *DstValue = + mdconst::extract(DstOp->getOperand(2)); + ConstantInt *SrcValue = + mdconst::extract(SrcOp->getOperand(2)); + if (SrcValue->getZExtValue() > DstValue->getZExtValue()) + overrideDstValue(); + break; + } case Module::Append: { MDNode *DstValue = cast(DstOp->getOperand(2)); MDNode *SrcValue = cast(SrcOp->getOperand(2)); diff --git a/test/Linker/Inputs/module-flags-pic-2-b.ll b/test/Linker/Inputs/module-flags-pic-2-b.ll index 0d78cafc6a0..f652eddb384 100644 --- a/test/Linker/Inputs/module-flags-pic-2-b.ll +++ b/test/Linker/Inputs/module-flags-pic-2-b.ll @@ -1,3 +1,4 @@ -!0 = !{ i32 1, !"PIC Level", i32 2 } +!0 = !{ i32 7, !"PIC Level", i32 2 } +!1 = !{ i32 7, !"PIE Level", i32 2 } -!llvm.module.flags = !{!0} +!llvm.module.flags = !{!0, !1} diff --git a/test/Linker/module-flags-pic-2-a.ll b/test/Linker/module-flags-pic-2-a.ll index e09af6bcd12..8898d72d510 100644 --- a/test/Linker/module-flags-pic-2-a.ll +++ b/test/Linker/module-flags-pic-2-a.ll @@ -1,10 +1,11 @@ -; RUN: not llvm-link %s %p/Inputs/module-flags-pic-2-b.ll -S -o - 2> %t -; RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s +; RUN: llvm-link %s %p/Inputs/module-flags-pic-2-b.ll -S -o - | FileCheck %s -; test linking modules with two different PIC levels +; test linking modules with two different PIC and PIE levels -!0 = !{ i32 1, !"PIC Level", i32 1 } +!0 = !{ i32 7, !"PIC Level", i32 1 } +!1 = !{ i32 7, !"PIE Level", i32 1 } -!llvm.module.flags = !{!0} +!llvm.module.flags = !{!0, !1} -; CHECK-ERRORS: ERROR: linking module flags 'PIC Level': IDs have conflicting values +; CHECK: !0 = !{i32 7, !"PIC Level", i32 2} +; CHECK: !1 = !{i32 7, !"PIE Level", i32 2} diff --git a/test/Verifier/module-flags-1.ll b/test/Verifier/module-flags-1.ll index 36bcb335ffc..ff82c284523 100644 --- a/test/Verifier/module-flags-1.ll +++ b/test/Verifier/module-flags-1.ll @@ -41,6 +41,10 @@ ; CHECK-NOT: invalid value for 'append'-type module flag (expected a metadata node) !18 = !{i32 5, !"flag-4", !{i32 57}} +; Check that any 'max' module flags are valid. +; CHECK: invalid value for 'max' module flag (expected constant integer) +!19 = !{i32 7, !"max", !"max"} + ; Check that any 'require' module flags are valid. ; CHECK: invalid requirement on flag, flag is not present in module !11 = !{i32 3, !"bar", !{!"no-such-flag", i32 52}} @@ -54,4 +58,4 @@ !llvm.module.flags = !{ !0, !1, !2, !3, !4, !5, !6, !7, !8, !9, !10, !11, !12, !13, !14, !15, - !16, !17, !18 } + !16, !17, !18, !19 }