Preserve the lexical order for global variables during llvm-link merge
authorJin Lin <jinl@uber.com>
Sat, 24 Apr 2021 05:37:08 +0000 (22:37 -0700)
committerJin Lin <jinl@uber.com>
Mon, 26 Apr 2021 17:11:34 +0000 (10:11 -0700)
The order of global variables is generated in the order of recursively materializing variables if the global variable has the attribute of hasLocalLinkage or hasLinkOnceLinkage during the module merging. In practice, it is often the exact reverse of source order. This new order may cause performance regression.

The change is to preserve the original lexical order for global variables.

Reviewed By: jdoerfert, dexonsmith

Differential Revision: https://reviews.llvm.org/D94202

16 files changed:
llvm/lib/Linker/IRMover.cpp
llvm/test/Linker/Inputs/globalorder-2.ll [new file with mode: 0644]
llvm/test/Linker/comdat.ll
llvm/test/Linker/comdat14.ll
llvm/test/Linker/ctors.ll
llvm/test/Linker/ctors2.ll
llvm/test/Linker/ctors3.ll
llvm/test/Linker/globalorder.ll [new file with mode: 0644]
llvm/test/Linker/link-flags.ll
llvm/test/Linker/metadata-attach.ll
llvm/test/Linker/testlink.ll
llvm/test/ThinLTO/X86/import-constant.ll
llvm/test/ThinLTO/X86/index-const-prop.ll
llvm/test/ThinLTO/X86/index-const-prop2.ll
llvm/test/ThinLTO/X86/writeonly.ll
llvm/test/ThinLTO/X86/writeonly2.ll

index 1433d07..9489f96 100644 (file)
@@ -1509,6 +1509,20 @@ Error IRLinker::run() {
     });
   }
 
+  // Reorder the globals just added to the destination module to match their
+  // original order in the source module.
+  Module::GlobalListType &Globals = DstM.getGlobalList();
+  for (GlobalVariable &GV : SrcM->globals()) {
+    if (GV.hasAppendingLinkage())
+      continue;
+    Value *NewValue = Mapper.mapValue(GV);
+    if (NewValue) {
+      auto *NewGV = dyn_cast<GlobalVariable>(NewValue->stripPointerCasts());
+      if (NewGV)
+        Globals.splice(Globals.end(), Globals, NewGV->getIterator());
+    }
+  }
+
   // Merge the module flags into the DstM module.
   return linkModuleFlagsMetadata();
 }
diff --git a/llvm/test/Linker/Inputs/globalorder-2.ll b/llvm/test/Linker/Inputs/globalorder-2.ll
new file mode 100644 (file)
index 0000000..a984ebf
--- /dev/null
@@ -0,0 +1,14 @@
+@var5 = internal global i32 0, align 4
+@var6 = internal global i32 0, align 4
+@var7 = global i32* @var5, align 4
+@var8 = global i32* @var6, align 4
+
+define i32 @foo2() {
+entry:
+  %0 = load i32*, i32** @var7, align 4
+  %1 = load i32, i32* %0, align 4
+  %2 = load i32*, i32** @var8, align 4
+  %3 = load i32, i32* %2, align 4
+  %add = add nsw i32 %3, %1
+  ret i32 %add
+}
index 2a2ec3b..e3bb1ea 100644 (file)
@@ -23,9 +23,9 @@ $any = comdat any
 ; CHECK: $foo = comdat largest
 ; CHECK: $any = comdat any
 
+; CHECK: @foo = global i64 43, comdat{{$}}
 ; CHECK: @qux = global i64 12, comdat{{$}}
 ; CHECK: @any = global i64 6, comdat{{$}}
-; CHECK: @foo = global i64 43, comdat{{$}}
 ; CHECK-NOT: @in_unselected_group = global i32 13, comdat $qux
 
 ; CHECK: define i32 @baz() comdat($qux)
index 9c6eb7c..1a1ba47 100644 (file)
@@ -5,5 +5,5 @@ $c = comdat any
 @v = global i32 0, comdat ($c)
 
 ; CHECK: @v = global i32 0, comdat($c)
-; CHECK: @v2 = external dllexport global i32
 ; CHECK: @v3 = external global i32
+; CHECK: @v2 = external dllexport global i32
index 37dba23..f68ca3e 100644 (file)
@@ -6,12 +6,12 @@
 ; Test the bitcode writer too. It used to crash.
 ; RUN: llvm-link %s %p/Inputs/ctors.ll -o %t.bc
 
+; ALL: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @f, i8* @v }]
 @v = weak global i8 0
 ; CHECK1: @v = weak global i8 0
 ; CHECK2: @v = weak global i8 1
 
 @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @f, i8* @v }]
-; ALL: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @f, i8* @v }]
 
 define weak void @f() {
   ret void
index 9b7a70e..c02973f 100644 (file)
@@ -3,5 +3,5 @@
 $foo = comdat any
 @foo = global i8 0, comdat
 
-; CHECK: @foo = global i8 0, comdat
 ; CHECK: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer
+; CHECK: @foo = global i8 0, comdat
index e62b92d..d522df5 100644 (file)
@@ -4,5 +4,5 @@ $foo = comdat any
 %t = type { i8 }
 @foo = global %t zeroinitializer, comdat
 
-; CHECK: @foo = global %t zeroinitializer, comdat
 ; CHECK: @llvm.global_ctors = appending global [0 x { i32, void ()*, i8* }] zeroinitializer
+; CHECK: @foo = global %t zeroinitializer, comdat
diff --git a/llvm/test/Linker/globalorder.ll b/llvm/test/Linker/globalorder.ll
new file mode 100644 (file)
index 0000000..caab97a
--- /dev/null
@@ -0,0 +1,27 @@
+; Test the order of global variables during llvm-link
+
+; RUN: llvm-link %s %S/Inputs/globalorder-2.ll -o %t.bc
+; RUN: llvm-dis  -o - %t.bc | FileCheck %s
+
+@var1 = internal global i32 0, align 4
+@var2 = internal global i32 0, align 4
+@var3 = global i32* @var1, align 4
+@var4 = global i32* @var2, align 4
+
+define i32 @foo() {
+entry:
+  %0 = load i32*, i32** @var3, align 4
+  %1 = load i32, i32* %0, align 4
+  %2 = load i32*, i32** @var4, align 4
+  %3 = load i32, i32* %2, align 4
+  %add = add nsw i32 %3, %1
+  ret i32 %add
+}
+; CHECK: @var1 =
+; CHECK-NEXT: @var2 =
+; CHECK-NEXT: @var3 =
+; CHECK-NEXT: @var4 =
+; CHECK-NEXT: @var5 =
+; CHECK-NEXT: @var6 =
+; CHECK-NEXT: @var7 =
+; CHECK-NEXT: @var8 =
index 1a57e8a..4e8eaa6 100644 (file)
@@ -9,8 +9,8 @@ CI-LABEL: @X = internal global i32 5
 CU-LABEL:@U = global i32 6
 CI-LABEL:@U = internal global i32 6
 CN-NOT:@U
-DI-LABEL: @Y = global i8 42
 DI-LABEL: @llvm.used = appending global [2 x i8*] [i8* @Y, i8* bitcast (i64 ()* @foo to i8*)], section "llvm.metadata"
+DI-LABEL: @Y = global i8 42
 
 B-LABEL: define void @bar() {
 
index 368c72a..6b6c8dd 100644 (file)
@@ -6,17 +6,17 @@
 ; CHECK-LINKED1: @g1 = global i32 0, !attach !0{{$}}
 @g1 = global i32 0, !attach !0
 
-; CHECK: @g3 = weak global i32 1, !attach !0{{$}}
 ; CHECK: @g2 = external global i32, !attach !0{{$}}
+; CHECK: @g3 = weak global i32 1, !attach !0{{$}}
 ; CHECK-LINKED1: @g2 = global i32 1, !attach !1{{$}}
 @g2 = external global i32, !attach !0
 
 ; CHECK-LINKED1: @g3 = global i32 2, !attach !1{{$}}
 @g3 = weak global i32 1, !attach !0
 
-; CHECK-LINKED2: @g2 = global i32 1, !attach !0{{$}}
-; CHECK-LINKED2: @g3 = global i32 2, !attach !0{{$}}
-; CHECK-LINKED2: @g1 = global i32 0, !attach !1{{$}}
+; CHECK-LINKED2: @g1 = global i32 0, !attach !0{{$}}
+; CHECK-LINKED2: @g2 = global i32 1, !attach !1{{$}}
+; CHECK-LINKED2: @g3 = global i32 2, !attach !1{{$}}
 
 ; CHECK: define void @f1() !attach !0 {
 ; CHECK-LINKED1: define void @f1() !attach !0 {
@@ -36,14 +36,14 @@ define weak void @f3() !attach !0 {
   ret void
 }
 
-; CHECK-LINKED2: define void @f2() !attach !0 {
-; CHECK-LINKED2: define void @f3() !attach !0 {
-; CHECK-LINKED2: define void @f1() !attach !1 {
+; CHECK-LINKED2: define void @f2() !attach !1 {
+; CHECK-LINKED2: define void @f3() !attach !1 {
+; CHECK-LINKED2: define void @f1() !attach !0 {
 
 ; CHECK-LINKED1: !0 = !{i32 0}
 ; CHECK-LINKED1: !1 = !{i32 1}
 
-; CHECK-LINKED2: !0 = !{i32 1}
-; CHECK-LINKED2: !1 = !{i32 0}
+; CHECK-LINKED2: !0 = !{i32 0}
+; CHECK-LINKED2: !1 = !{i32 1}
 
 !0 = !{i32 0}
index 6a316a3..69870b5 100644 (file)
@@ -1,7 +1,7 @@
 ; RUN: llvm-link %s %S/Inputs/testlink.ll -S | FileCheck %s
 
-; CHECK: %Ty2 = type { %Ty1* }
 ; CHECK: %Ty1 = type { %Ty2* }
+; CHECK: %Ty2 = type { %Ty1* }
 %Ty1 = type opaque
 %Ty2 = type { %Ty1* }
 
index 1bc2a1c..e525494 100644 (file)
@@ -28,9 +28,9 @@
 ; PROMOTE: @_ZL3Obj.llvm.{{.*}} = hidden constant %struct.S { i32 4, i32 8, i32* @val }
 
 ; @outer is a write-only variable, so it's been converted to zeroinitializer.
-; IMPORT:      @outer = internal local_unnamed_addr global %struct.Q zeroinitializer
+; IMPORT:      @val = available_externally global i32 42
 ; IMPORT-NEXT: @_ZL3Obj.llvm.{{.*}} = available_externally hidden constant %struct.S { i32 4, i32 8, i32* @val }
-; IMPORT-NEXT: @val = available_externally global i32 42
+; IMPORT-NEXT: @outer = internal local_unnamed_addr global %struct.Q zeroinitializer
 
 ; OPT: @outer = internal unnamed_addr global %struct.Q zeroinitializer
 
@@ -39,8 +39,8 @@
 ; OPT-NEXT:   store %struct.S* null, %struct.S** getelementptr inbounds (%struct.Q, %struct.Q* @outer, i64 0, i32 0)
 ; OPT-NEXT:   ret i32 12
 
-; NOREFS:      @outer = internal local_unnamed_addr global %struct.Q zeroinitializer
-; NOREFS-NEXT: @_ZL3Obj.llvm.{{.*}} = external hidden constant %struct.S
+; NOREFS:      @_ZL3Obj.llvm.{{.*}} = external hidden constant %struct.S
+; NOREFS-NEXT: @outer = internal local_unnamed_addr global %struct.Q zeroinitializer
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"
index 9718aec..b8028d6 100644 (file)
 ; RUN: llvm-lto -thinlto-action=import -exported-symbol main -exported-symbol gBar  %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported2.bc
 ; RUN: llvm-dis %t1.imported2.bc -o - | FileCheck %s --check-prefix=IMPORT2
 
-; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4, !dbg !0
-; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4, !dbg !5
+; IMPORT:      @gBar = internal local_unnamed_addr global i32 2, align 4, !dbg !0
+; IMPORT-NEXT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4, !dbg !5
 ; IMPORT: !DICompileUnit({{.*}})
 
 ; OPTIMIZE:        define i32 @main
 ; OPTIMIZE-NEXT:     ret i32 3
 
-; IMPORT2: @gBar = available_externally local_unnamed_addr global i32 2, align 4, !dbg !5
+; IMPORT2: @gBar = available_externally local_unnamed_addr global i32 2, align 4, !dbg !0
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-pc-linux-gnu"
index 5bf40fc..68fe058 100644 (file)
 ; with corresponsing stores
 ; RUN: llvm-dis %t5.2.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN2-SRC
 
-; IMPORT:       @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
-; IMPORT-NEXT:  @gBar = internal local_unnamed_addr global i32 2, align 4
+; IMPORT:       @gBar = internal local_unnamed_addr global i32 2, align 4
+; IMPORT-NEXT:  @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
 ; IMPORT:       !DICompileUnit({{.*}})
 
 ; Write only variables are imported with a zero initializer.
-; IMPORT-WRITEONLY:  @gFoo.llvm.0 = internal unnamed_addr global i32 0
 ; IMPORT-WRITEONLY:  @gBar = internal local_unnamed_addr global i32 0
+; IMPORT-WRITEONLY:  @gFoo.llvm.0 = internal unnamed_addr global i32 0
 
 ; CODEGEN:        i32 @main()
 ; CODEGEN-NEXT:     ret i32 3
index 7616f19..65c93a7 100644 (file)
@@ -11,8 +11,8 @@
 ; RUN: llvm-dis %t1.imported.bc -o - | FileCheck %s --check-prefix=IMPORT
 ; RUN: llvm-lto -thinlto-action=optimize %t1.imported.bc -o - | llvm-dis - -o - | FileCheck %s --check-prefix=OPTIMIZE
 
-; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 0, align 4, !dbg !0
-; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 0, align 4, !dbg !5
+; IMPORT:      @gBar = internal local_unnamed_addr global i32 0, align 4, !dbg !0
+; IMPORT-NEXT: @gFoo.llvm.0 = internal unnamed_addr global i32 0, align 4, !dbg !5
 ; IMPORT: !DICompileUnit({{.*}})
 
 ; STATS:  2 module-summary-index - Number of live global variables marked write only 
@@ -29,8 +29,8 @@
 ; RUN: llvm-lto -propagate-attrs=false -thinlto-action=import -exported-symbol=main  %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported.bc -stats 2>&1 | FileCheck %s --check-prefix=STATS-NOPROP
 ; RUN: llvm-dis %t1.imported.bc -o - | FileCheck %s --check-prefix=IMPORT-NOPROP
 ; STATS-NOPROP-NOT: Number of live global variables marked write only
-; IMPORT-NOPROP: @gFoo.llvm.0 = available_externally
-; IMPORT-NOPROP-NEXT: @gBar = available_externally
+; IMPORT-NOPROP:      @gBar = available_externally
+; IMPORT-NOPROP-NEXT: @gFoo.llvm.0 = available_externally
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-pc-linux-gnu"
index 2648727..f31f9b3 100644 (file)
@@ -19,8 +19,8 @@
 ; with corresponsing stores
 ; RUN: llvm-dis %t3.2.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN-SRC
 
-; IMPORT:       @gFoo.llvm.0 = internal unnamed_addr global i32 0, align 4
-; IMPORT-NEXT:  @gBar = internal local_unnamed_addr global i32 0, align 4
+; IMPORT:       @gBar = internal local_unnamed_addr global i32 0, align 4
+; IMPORT-NEXT:  @gFoo.llvm.0 = internal unnamed_addr global i32 0, align 4
 ; IMPORT:       !DICompileUnit({{.*}})
 
 ; CODEGEN-NOT:  gFoo