Index: clang/lib/Driver/ToolChains/RISCVToolchain.h =================================================================== --- clang/lib/Driver/ToolChains/RISCVToolchain.h +++ clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -25,6 +25,7 @@ void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const override; + bool HasNativeLLVMSupport() const override { return true; } RuntimeLibType GetDefaultRuntimeLibType() const override; UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override; Index: clang/lib/Driver/ToolChains/RISCVToolchain.cpp =================================================================== --- clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -144,6 +144,12 @@ std::string Linker = getToolChain().GetLinkerPath(); + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } + bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -1020,6 +1020,23 @@ GV->setLinkage(GlobalValue::InternalLinkage); } + // ThinLTO would link CombinedModule object with input file object later + // but different target abi object can not linked together + // add target-abi module flag from first input file into CombinedModule. + if (!ThinLTO.ModuleMap.empty()) { + LTOLLVMContext BackendContext(Conf); + auto &Mod = ThinLTO.ModuleMap.front(); + auto MOrErr = Mod.second.parseModule(BackendContext); + if (MOrErr) { + if (const MDString *ModuleTargetABI = dyn_cast_or_null( + (*MOrErr)->getModuleFlag("target-abi"))) { + llvm::LLVMContext &Ctx = RegularLTO.CombinedModule->getContext(); + RegularLTO.CombinedModule->addModuleFlag( + llvm::Module::Error, "target-abi", + llvm::MDString::get(Ctx, ModuleTargetABI->getString())); + } + } + } RegularLTO.CombinedModule->addModuleFlag(Module::Error, "LTOPostLink", 1); if (Conf.PostInternalizeModuleHook && Index: llvm/lib/Target/RISCV/RISCVTargetMachine.h =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.h +++ llvm/lib/Target/RISCV/RISCVTargetMachine.h @@ -42,6 +42,9 @@ return TLOF.get(); } + void setTargetOptionsWithModuleMetadata( + const Module &M LLVM_ATTRIBUTE_UNUSED) const override; + TargetTransformInfo getTargetTransformInfo(const Function &F) override; }; } Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -105,6 +105,19 @@ return I.get(); } +void RISCVTargetMachine::setTargetOptionsWithModuleMetadata( + const Module &M LLVM_ATTRIBUTE_UNUSED) const { + StringRef ABIName = Options.MCOptions.getABIName(); + if (const MDString *ModuleTargetABI = + dyn_cast_or_null(M.getModuleFlag("target-abi"))) { + StringRef ModuleABIName = ModuleTargetABI->getString(); + if (!ABIName.empty() && ModuleABIName != ABIName) + report_fatal_error("-target-abi option != target-abi module flag"); + if (ABIName.empty()) + Options.MCOptions.ABIName = ModuleABIName.str(); + } +} + TargetTransformInfo RISCVTargetMachine::getTargetTransformInfo(const Function &F) { return TargetTransformInfo(RISCVTTIImpl(this, F)); Index: llvm/test/CodeGen/RISCV/module-target-abi2.ll =================================================================== --- llvm/test/CodeGen/RISCV/module-target-abi2.ll +++ llvm/test/CodeGen/RISCV/module-target-abi2.ll @@ -8,8 +8,7 @@ ; RV32IF-ILP32: -target-abi option != target-abi module flag -; FLAGS: Flags: 0x0 -; // this should be "Flags :0x2, single-float ABI", it will be fixed later. +; FLAGS: Flags: 0x2, single-float ABI define float @foo(i32 %a) nounwind #0 { ; DEFAULT: # %bb.0: Index: llvm/test/LTO/RISCV/Inputs/foo_ilp32.ll =================================================================== --- /dev/null +++ llvm/test/LTO/RISCV/Inputs/foo_ilp32.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-unknown-elf" + +define float @foo(float %x) #0 { + %conv = fpext float %x to double + %add = fadd double %conv, 0x400921FD80C9BEFB + %conv1 = fptrunc double %add to float + ret float %conv1 +} + +attributes #0 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32"} Index: llvm/test/LTO/RISCV/Inputs/foo_ilp32f.ll =================================================================== --- /dev/null +++ llvm/test/LTO/RISCV/Inputs/foo_ilp32f.ll @@ -0,0 +1,14 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-unknown-elf" + +define float @foo(float %x) #0 { + %conv = fpext float %x to double + %add = fadd double %conv, 0x400921FD80C9BEFB + %conv1 = fptrunc double %add to float + ret float %conv1 +} + +attributes #0 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32f"} Index: llvm/test/LTO/RISCV/lit.local.cfg =================================================================== --- /dev/null +++ llvm/test/LTO/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True Index: llvm/test/LTO/RISCV/mabi-invalid.ll =================================================================== --- /dev/null +++ llvm/test/LTO/RISCV/mabi-invalid.ll @@ -0,0 +1,28 @@ +; XFAIL: * +; Check with regular LTO +; RUN: llvm-as < %s > %t1 +; RUN: llvm-as < %S/Inputs/foo_ilp32.ll > %t2 +; RUN: llvm-lto -exported-symbol=main -o %t3 %t1 %t2 2>&1 | FileCheck %s + +; Check with ThinLTO. +; RUN: opt -module-summary -o %t1.summary %s +; RUN: opt -module-summary -o %t2.summary %S/Inputs/foo_ilp32.ll +; RUN: llvm-lto2 run -r %t2.summary,foo,plx -r %t1.summary,main,plx -r %t1.summary,foo, -o %t3 %t1.summary %t2.summary 2>&1 | FileCheck %s + +; CHECK: 'target-abi': IDs have conflicting values + +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-unknown-elf" + +declare float @foo(float) #1 + +define float @main(float %x) #0 { + %retval = call float @foo(float 10.0) + ret float %retval +} + +attributes #0 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } +attributes #1 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32f"} Index: llvm/test/LTO/RISCV/mabi.ll =================================================================== --- /dev/null +++ llvm/test/LTO/RISCV/mabi.ll @@ -0,0 +1,29 @@ +; Test target-abi module flag generate correct elf flags. + +; Check with regular LTO +; RUN: llvm-as < %s >%t1 +; RUN: llvm-lto -exported-symbol=main -o %t2 %t1 +; RUN: llvm-readelf -h %t2 | FileCheck %s + +; Check with ThinLTO. +; RUN: opt -module-summary -o %t1.summary %s +; RUN: llvm-lto2 run -r %t1.summary,foo, -r %t1.summary,main,plx -o %t2 %t1.summary +; RUN: llvm-readelf -h %t2.1 | FileCheck %s + +; CHECK: Flags: 0x2, single-float ABI + +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-unknown-elf" + +declare float @foo(float) #1 + +define float @main(float %x) #0 { + %retval = call float @foo(float 10.0) + ret float %retval +} + +attributes #0 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } +attributes #1 = { nounwind "target-features"="+a,+c,+f,+m,+relax" } + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"ilp32f"}