llvm.org GIT mirror llvm / 03d2823
Add support for comdats to the gold plugin. There are two parts to this. First, the plugin needs to tell gold the comdat by setting comdat_key. What gets things a bit more complicated is that gold only seems symbols. In particular, if A is an alias to B, it only sees the symbols A and B. It can then ask us to keep symbol A but drop symbol B. What we have to do instead is to create an internal version of B and make A an alias to that. At some point some of this logic should be moved to lib/Linker so that we don't map a Constant to an internal version just to have lib/Linker map that again to the destination module. The reason for implementing this in tools/gold for now is simplicity. With it in place it should be possible to update clang to use comdats for constructors and destructors on ELF without breaking the LTO bootstrap. Once that is done I intend to come back and improve the interface lib/Linker exposes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216302 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 6 years ago
4 changed file(s) with 194 addition(s) and 13 deletion(s). Raw diff Collapse all Expand all
0 $c2 = comdat any
1
2 @v1 = weak_odr global i32 41, comdat $c2
3 define weak_odr i32 @f1() comdat $c2 {
4 bb20:
5 br label %bb21
6 bb21:
7 ret i32 41
8 }
9
10 @r21 = global i32* @v1
11 @r22 = global i32()* @f1
12
13 @a21 = alias i32* @v1
14 @a22 = alias bitcast (i32* @v1 to i16*)
15
16 @a23 = alias i32()* @f1
17 @a24 = alias bitcast (i32()* @f1 to i16*)
18 @a25 = alias i16* @a24
0 ; RUN: llvm-as %s -o %t.o
1
2 ; RUN: not ld -plugin %llvmshlibdir/LLVMgold.so \
3 ; RUN: --plugin-opt=emit-llvm \
4 ; RUN: -shared %t.o -o %t2.o 2>&1 | FileCheck %s
5
6 ; CHECK: Unable to determine comdat of alias!
7
8 @g1 = global i32 1
9 @g2 = global i32 2
10
11 @a = alias inttoptr(i32 sub (i32 ptrtoint (i32* @g1 to i32),
12 i32 ptrtoint (i32* @g2 to i32)) to i32*)
0 ; RUN: llvm-as %s -o %t.o
1 ; RUN: llvm-as %p/Inputs/comdat.ll -o %t2.o
2 ; RUN: ld -shared -o %t3.o -plugin %llvmshlibdir/LLVMgold.so %t.o %t2.o \
3 ; RUN: -plugin-opt=emit-llvm
4 ; RUN: llvm-dis %t3.o -o - | FileCheck %s
5
6 $c1 = comdat any
7
8 @v1 = weak_odr global i32 42, comdat $c1
9 define weak_odr i32 @f1() comdat $c1 {
10 bb10:
11 br label %bb11
12 bb11:
13 ret i32 42
14 }
15
16 @r11 = global i32* @v1
17 @r12 = global i32 ()* @f1
18
19 @a11 = alias i32* @v1
20 @a12 = alias bitcast (i32* @v1 to i16*)
21
22 @a13 = alias i32 ()* @f1
23 @a14 = alias bitcast (i32 ()* @f1 to i16*)
24 @a15 = alias i16* @a14
25
26 ; CHECK: $c1 = comdat any
27 ; CHECK: $c2 = comdat any
28
29 ; CHECK: @v1 = weak_odr global i32 42, comdat $c1
30
31 ; CHECK: @r11 = global i32* @v1{{$}}
32 ; CHECK: @r12 = global i32 ()* @f1{{$}}
33
34 ; CHECK: @r21 = global i32* @v1{{$}}
35 ; CHECK: @r22 = global i32 ()* @f1{{$}}
36
37 ; CHECK: @v11 = internal global i32 41, comdat $c2
38
39 ; CHECK: @a11 = alias i32* @v1{{$}}
40 ; CHECK: @a12 = alias bitcast (i32* @v1 to i16*)
41
42 ; CHECK: @a13 = alias i32 ()* @f1{{$}}
43 ; CHECK: @a14 = alias bitcast (i32 ()* @f1 to i16*)
44
45 ; CHECK: @a21 = alias i32* @v11{{$}}
46 ; CHECK: @a22 = alias bitcast (i32* @v11 to i16*)
47
48 ; CHECK: @a23 = alias i32 ()* @f12{{$}}
49 ; CHECK: @a24 = alias bitcast (i32 ()* @f12 to i16*)
50
51 ; CHECK: define weak_odr i32 @f1() comdat $c1 {
52 ; CHECK-NEXT: bb10:
53 ; CHECK-NEXT: br label %bb11{{$}}
54 ; CHECK: bb11:
55 ; CHECK-NEXT: ret i32 42
56 ; CHECK-NEXT: }
57
58 ; CHECK: define internal i32 @f12() comdat $c2 {
59 ; CHECK-NEXT: bb20:
60 ; CHECK-NEXT: br label %bb21
61 ; CHECK: bb21:
62 ; CHECK-NEXT: ret i32 41
63 ; CHECK-NEXT: }
1212 //===----------------------------------------------------------------------===//
1313
1414 #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
15 #include "llvm/ADT/DenseSet.h"
1516 #include "llvm/ADT/StringSet.h"
1617 #include "llvm/Bitcode/ReaderWriter.h"
1718 #include "llvm/CodeGen/Analysis.h"
3334 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
3435 #include "llvm/Transforms/Utils/GlobalStatus.h"
3536 #include "llvm/Transforms/Utils/ModuleUtils.h"
37 #include "llvm/Transforms/Utils/ValueMapper.h"
3638 #include
3739 #include
3840 #include
254256 return LDPS_OK;
255257 }
256258
259 static const GlobalObject *getBaseObject(const GlobalValue &GV) {
260 if (auto *GA = dyn_cast(&GV))
261 return GA->getBaseObject();
262 return cast(&GV);
263 }
264
257265 /// Called by gold to see whether this file is one that our plugin can handle.
258266 /// We'll try to open it and register all the symbols with add_symbol if
259267 /// possible.
361369
362370 sym.size = 0;
363371 sym.comdat_key = nullptr;
364 if (GV && (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()))
365 sym.comdat_key = sym.name;
372 if (GV) {
373 const GlobalObject *Base = getBaseObject(*GV);
374 if (!Base)
375 message(LDPL_FATAL, "Unable to determine comdat of alias!");
376 const Comdat *C = Base->getComdat();
377 if (C)
378 sym.comdat_key = strdup(C->getName().str().c_str());
379 else if (Base->hasWeakLinkage() || Base->hasLinkOnceLinkage())
380 sym.comdat_key = strdup(sym.name);
381 }
366382
367383 sym.resolution = LDPR_UNKNOWN;
368384 }
377393 return LDPS_OK;
378394 }
379395
380 static void keepGlobalValue(GlobalValue &GV) {
396 static void keepGlobalValue(GlobalValue &GV,
397 std::vector &KeptAliases) {
381398 assert(!GV.hasLocalLinkage());
399
400 if (auto *GA = dyn_cast(&GV))
401 KeptAliases.push_back(GA);
382402
383403 switch (GV.getLinkage()) {
384404 default:
414434 static void drop(GlobalValue &GV) {
415435 if (auto *F = dyn_cast(&GV)) {
416436 F->deleteBody();
437 F->setComdat(nullptr); // Should deleteBody do this?
417438 return;
418439 }
419440
420441 if (auto *Var = dyn_cast(&GV)) {
421442 Var->setInitializer(nullptr);
422 Var->setLinkage(GlobalValue::ExternalLinkage);
443 Var->setLinkage(
444 GlobalValue::ExternalLinkage); // Should setInitializer do this?
445 Var->setComdat(nullptr); // and this?
423446 return;
424447 }
425448
459482 }
460483 }
461484
485 static GlobalObject *makeInternalReplacement(GlobalObject *GO) {
486 Module *M = GO->getParent();
487 GlobalObject *Ret;
488 if (auto *F = dyn_cast(GO)) {
489 auto *NewF = Function::Create(
490 F->getFunctionType(), GlobalValue::InternalLinkage, F->getName(), M);
491 NewF->getBasicBlockList().splice(NewF->end(), F->getBasicBlockList());
492 Ret = NewF;
493 F->deleteBody();
494 } else {
495 auto *Var = cast(GO);
496 Ret = new GlobalVariable(
497 *M, Var->getType()->getElementType(), Var->isConstant(),
498 GlobalValue::InternalLinkage, Var->getInitializer(), Var->getName(),
499 nullptr, Var->getThreadLocalMode(), Var->getType()->getAddressSpace(),
500 Var->isExternallyInitialized());
501 Var->setInitializer(nullptr);
502 }
503 Ret->copyAttributesFrom(GO);
504 Ret->setComdat(GO->getComdat());
505
506 return Ret;
507 }
508
509 namespace {
510 class LocalValueMaterializer : public ValueMaterializer {
511 DenseSet &Dropped;
512
513 public:
514 LocalValueMaterializer(DenseSet &Dropped) : Dropped(Dropped) {}
515 Value *materializeValueFor(Value *V) override;
516 };
517 }
518
519 Value *LocalValueMaterializer::materializeValueFor(Value *V) {
520 auto *GV = dyn_cast(V);
521 if (!GV)
522 return nullptr;
523 if (!Dropped.count(GV))
524 return nullptr;
525 assert(!isa(GV) && "Found alias point to weak alias.");
526 return makeInternalReplacement(cast(GV));
527 }
528
529 static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM,
530 LocalValueMaterializer *Materializer) {
531 return MapValue(C, VM, RF_IgnoreMissingEntries, nullptr, Materializer);
532 }
533
462534 static std::unique_ptr
463535 getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile,
464536 StringSet<> &Internalize, StringSet<> &Maybe) {
491563 SmallPtrSet Used;
492564 collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
493565
494 std::vector Drop;
566 DenseSet Drop;
567 std::vector KeptAliases;
495568 for (ld_plugin_symbol &Sym : F.syms) {
496569 ld_plugin_symbol_resolution Resolution =
497570 (ld_plugin_symbol_resolution)Sym.resolution;
515588 break;
516589
517590 case LDPR_PREVAILING_DEF_IRONLY: {
591 keepGlobalValue(*GV, KeptAliases);
518592 if (!Used.count(GV)) {
519593 // Since we use the regular lib/Linker, we cannot just internalize GV
520594 // now or it will not be copied to the merged module. Instead we force
521595 // it to be copied and then internalize it.
522 keepGlobalValue(*GV);
523596 Internalize.insert(Sym.name);
524597 }
525598 break;
526599 }
527600
528601 case LDPR_PREVAILING_DEF:
529 keepGlobalValue(*GV);
602 keepGlobalValue(*GV, KeptAliases);
530603 break;
531604
532605 case LDPR_PREEMPTED_REG:
533606 case LDPR_PREEMPTED_IR:
534 Drop.push_back(GV);
607 Drop.insert(GV);
535608 break;
536609
537610 case LDPR_PREVAILING_DEF_IRONLY_EXP: {
541614 // copy will be LDPR_PREEMPTED_IR.
542615 if (GV->hasLinkOnceODRLinkage())
543616 Maybe.insert(Sym.name);
544 keepGlobalValue(*GV);
617 keepGlobalValue(*GV, KeptAliases);
545618 break;
546619 }
547620 }
548621
549622 free(Sym.name);
623 free(Sym.comdat_key);
550624 Sym.name = nullptr;
551625 Sym.comdat_key = nullptr;
552626 }
553627
554 if (!Drop.empty()) {
628 if (!Drop.empty())
555629 // This is horrible. Given how lazy loading is implemented, dropping
556630 // the body while there is a materializer present doesn't work, the
557631 // linker will just read the body back.
558632 M->materializeAllPermanently();
559 for (auto *GV : Drop)
560 drop(*GV);
561 }
633
634 ValueToValueMapTy VM;
635 LocalValueMaterializer Materializer(Drop);
636 for (GlobalAlias *GA : KeptAliases) {
637 // Gold told us to keep GA. It is possible that a GV usied in the aliasee
638 // expression is being dropped. If that is the case, that GV must be copied.
639 Constant *Aliasee = GA->getAliasee();
640 Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer);
641 if (Aliasee != Replacement)
642 GA->setAliasee(Replacement);
643 }
644
645 for (auto *GV : Drop)
646 drop(*GV);
562647
563648 return M;
564649 }