Index: lib/Linker/IRMover.cpp =================================================================== --- lib/Linker/IRMover.cpp +++ lib/Linker/IRMover.cpp @@ -1250,6 +1250,13 @@ return T0.getArch() == T1.getArch() && T0.getSubArch() == T1.getSubArch() && T0.getVendor() == T1.getVendor() && T0.getOS() == T1.getOS(); + // Allow linking ARM and Thumb modules together without warning, if subarch, + // vendor and OS match. + if ((T0.getArch() == Triple::thumb && T1.getArch() == Triple::arm) || + (T0.getArch() == Triple::arm && T1.getArch() == Triple::thumb)) + return T0.getSubArch() == T1.getSubArch() && + T0.getVendor() == T1.getVendor() && T0.getOS() == T1.getOS(); + return T0 == T1; } @@ -1264,6 +1271,42 @@ return DstTriple.str(); } +// Add thumb-mode to target-features if we link ARM and Thumb code together. +void maybeAddARMSubtargetFeatures(const Triple &SrcTriple, + const Triple &DstTriple, + GlobalValue *GV) { + // Only consider triples with Arm or Thumb architecture. + if (SrcTriple.getArch() == DstTriple.getArch()) + return; + if (SrcTriple.getArch() != Triple::thumb && SrcTriple.getArch() != Triple::arm) + return; + if (DstTriple.getArch() != Triple::thumb && DstTriple.getArch() != Triple::arm) + return; + + const std::string thumbMode = SrcTriple.getArch() == Triple::arm ? + "-thumb-mode" : "+thumb-mode"; + + llvm::Function *Fn = dyn_cast(GV); + if (!Fn) + return; + + Attribute targetFeatures; + if (Fn->hasFnAttribute("target-features")) { + targetFeatures = Fn->getFnAttribute("target-features"); + } + + std::string newFeatures = targetFeatures.getValueAsString(); + // Do not add thumb-mode if it is already part of the target-features. + if (newFeatures.find("thumb-mode") != std::string::npos) + return; + + if (newFeatures.size() > 0) + newFeatures += ","; + + newFeatures += thumbMode; + Fn->addFnAttr("target-features", newFeatures); +} + Error IRLinker::run() { // Ensure metadata materialized before value mapping. if (SrcM->getMaterializer()) @@ -1315,6 +1358,8 @@ GlobalValue *GV = Worklist.back(); Worklist.pop_back(); + maybeAddARMSubtargetFeatures(SrcTriple, DstTriple, GV); + // Already mapped. if (ValueMap.find(GV) != ValueMap.end() || AliasValueMap.find(GV) != AliasValueMap.end()) Index: test/LTO/ARM/Inputs/thumb.ll =================================================================== --- /dev/null +++ test/LTO/ARM/Inputs/thumb.ll @@ -0,0 +1,13 @@ +target triple = "thumbv7-apple-ios" + +define i32 @foo(i32 %a, i32 %b) { +entry: + %add = add i32 %a, %b + ret i32 %add +} + +define i32 @bar(i32 %a, i32 %b) { +entry: + %add = add i32 %a, %b + ret i32 %add +} Index: test/LTO/ARM/link-arm-and-thumb.ll =================================================================== --- /dev/null +++ test/LTO/ARM/link-arm-and-thumb.ll @@ -0,0 +1,25 @@ +; RUN: llvm-as %s -o %t1.bc +; RUN: llvm-as %p/Inputs/thumb.ll -o %t2.bc +; RUN: llvm-lto -exported-symbol main \ +; RUN: -exported-symbol bar \ +; RUN: -filetype=asm \ +; RUN: -o - \ +; RUN: %t1.bc %t2.bc | FileCheck %s + +target triple = "armv7-apple-ios" + +; CHECK: .code 32 +; CHECK-NEXT: _main +; CHECK-NEXT: mov r0, #30 + +; CHECK: .code 16 +; CHECK-NEXT: .thumb_func _bar +; CHECK-NEXT: _bar + +declare i32 @foo(i32 %a, i32 %b); + +define i32 @main() { +entry: + %add = call i32 @foo(i32 10, i32 20) + ret i32 %add +} Index: test/Linker/Inputs/thumb.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/thumb.ll @@ -0,0 +1,15 @@ +target triple = "thumbv7-apple-ios" + +define i32 @foo(i32 %a, i32 %b) #0 { +entry: + %add = add i32 %a, %b + ret i32 %add +} + +define i32 @bar(i32 %a, i32 %b) { +entry: + %add = add i32 %a, %b + ret i32 %add +} + +attributes #0 = { "target-features"="-thumb-mode" } Index: test/Linker/link-arm-and-thumb.ll =================================================================== --- /dev/null +++ test/Linker/link-arm-and-thumb.ll @@ -0,0 +1,23 @@ +; RUN: llvm-as %s -o %t1.bc +; RUN: llvm-as %p/Inputs/thumb.ll -o %t2.bc +; RUN: llvm-link %t1.bc %t2.bc -S | llc | FileCheck %s + +target triple = "armv7-apple-ios" + +declare i32 @foo(i32 %a, i32 %b); + +define i32 @main() { +entry: + %add = call i32 @foo(i32 10, i32 20) + ret i32 %add +} + +; CHECK: .code 32 +; CHECK-NEXT: _main + +; CHECK: .code 32 +; CHECK-NEXT: _foo + +; CHECK: .code 16 +; CHECK-NEXT: .thumb_func _bar +; CHECK-NEXT: _bar