diff -Nru rustc-1.41.0+dfsg1+llvm/debian/changelog rustc-1.41.0+dfsg1+llvm/debian/changelog --- rustc-1.41.0+dfsg1+llvm/debian/changelog 2020-03-02 20:22:50.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/changelog 2020-04-08 00:18:39.000000000 +0000 @@ -1,3 +1,17 @@ +rustc (1.41.0+dfsg1+llvm-0ubuntu2) focal; urgency=medium + + * Add riscv64 support: + - Add more rustc patches from Debian. + - Apply relevant llvm-toolchain-9 patches to the embedded llvm. + - debian/patches/riscv64-vendor-cc.diff: Update one last rustc lp64 ABI + reference to lp64d. + - Avoid the LDFLAGS -latomic hacks from llvm-toolchain-9: + - debian/patches/riscv64-atomic-fixes.patch: Fix libatomic detection for + riscv64. + - debian/patches/dsymutil-atomic.patch: Link dsymutil with -latomic. + + -- William Grant Wed, 08 Apr 2020 10:18:39 +1000 + rustc (1.41.0+dfsg1+llvm-0ubuntu1) focal; urgency=medium * New upstream version (LP: #1856851) diff -Nru rustc-1.41.0+dfsg1+llvm/debian/config.toml rustc-1.41.0+dfsg1+llvm/debian/config.toml --- rustc-1.41.0+dfsg1+llvm/debian/config.toml 2019-11-11 20:52:27.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/config.toml 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -[build] -submodules = false -vendor = true -locked-deps = false -verbose = 2 - -rustc = "/usr/bin/rustc" -cargo = "/usr/bin/cargo" - -build = "x86_64-unknown-linux-gnu" -host = ["x86_64-unknown-linux-gnu"] -target = ["x86_64-unknown-linux-gnu"] - -#full-bootstrap = true -# originally needed to work around #45317 but no longer necessary -# currently we have to omit it because it breaks #48319 - -# this might get changed later by override_dh_auto_configure-indep -# we do it this way to avoid spurious rebuilds -docs = false - -[install] -prefix = "/usr" - -[rust] -jemalloc = false -optimize = true -dist-src = false - -channel = "stable" - -# parallel codegen interferes with reproducibility, see -# https://github.com/rust-lang/rust/issues/34902#issuecomment-319463586 -#codegen-units = 0 -debuginfo-level = 0 -debuginfo-level-std = 2 -rpath = false - -verbose-tests = true -backtrace-on-ice = true diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-multiarch.diff rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-multiarch.diff --- rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-multiarch.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-multiarch.diff 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,34 @@ +Index: llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp +=================================================================== +--- llvm-toolchain-9_9.0.0.orig/src/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp ++++ llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Linux.cpp +@@ -151,6 +151,10 @@ static std::string getMultiarchTriple(co + if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) + return "powerpc64le-linux-gnu"; + break; ++ case llvm::Triple::riscv64: ++ if (D.getVFS().exists(SysRoot + "/lib/riscv64-linux-gnu")) ++ return "riscv64-linux-gnu"; ++ break; + case llvm::Triple::sparc: + if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) + return "sparc-linux-gnu"; +@@ -759,6 +763,8 @@ void Linux::AddClangSystemIncludeArgs(co + "/usr/include/powerpc64-linux-gnu"}; + const StringRef PPC64LEMultiarchIncludeDirs[] = { + "/usr/include/powerpc64le-linux-gnu"}; ++ const StringRef RISCV64MultiarchIncludeDirs[] = { ++ "/usr/include/riscv64-linux-gnu"}; + const StringRef SparcMultiarchIncludeDirs[] = { + "/usr/include/sparc-linux-gnu"}; + const StringRef Sparc64MultiarchIncludeDirs[] = { +@@ -834,6 +840,9 @@ void Linux::AddClangSystemIncludeArgs(co + case llvm::Triple::ppc64le: + MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; + break; ++ case llvm::Triple::riscv64: ++ MultiarchIncludeDirs = RISCV64MultiarchIncludeDirs; ++ break; + case llvm::Triple::sparc: + MultiarchIncludeDirs = SparcMultiarchIncludeDirs; + break; diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-rv64gc.diff rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-rv64gc.diff --- rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-rv64gc.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/clang-riscv64-rv64gc.diff 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,38 @@ +Index: llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +=================================================================== +--- llvm-toolchain-9_9.0.0.orig/src/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp ++++ llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +@@ -350,6 +350,13 @@ void riscv::getRISCVTargetFeatures(const + + // Handle all other types of extensions. + getExtensionFeatures(D, Args, Features, MArch, OtherExts); ++ } else { ++ // Default to imafdc aka gc ++ Features.push_back("+m"); ++ Features.push_back("+a"); ++ Features.push_back("+f"); ++ Features.push_back("+d"); ++ Features.push_back("+c"); + } + + // -mrelax is default, unless -mno-relax is specified. +@@ -375,5 +382,5 @@ StringRef riscv::getRISCVABI(const ArgLi + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + return A->getValue(); + +- return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64"; ++ return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64d"; + } +Index: llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +=================================================================== +--- llvm-toolchain-9_9.0.0.orig/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp ++++ llvm-toolchain-9_9.0.0/src/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +@@ -1862,7 +1862,7 @@ void Clang::AddRISCVTargetArgs(const Arg + else if (Triple.getArch() == llvm::Triple::riscv32) + ABIName = "ilp32"; + else if (Triple.getArch() == llvm::Triple::riscv64) +- ABIName = "lp64"; ++ ABIName = "lp64d"; + else + llvm_unreachable("Unexpected triple!"); + diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/D60657-riscv-pcrel_lo.diff rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/D60657-riscv-pcrel_lo.diff --- rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/D60657-riscv-pcrel_lo.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/D60657-riscv-pcrel_lo.diff 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,171 @@ +commit 41449c58c58e466bcf9cdc4f7415950382bad8d7 +Author: Roger Ferrer Ibanez +Date: Fri Nov 8 08:26:30 2019 +0000 + + [RISCV] Fix evaluation of %pcrel_lo + + The following testcase + + function: + .Lpcrel_label1: + auipc a0, %pcrel_hi(other_function) + addi a1, a0, %pcrel_lo(.Lpcrel_label1) + .p2align 2 # Causes a new fragment to be emitted + + .type other_function,@function + other_function: + ret + + exposes an odd behaviour in which only the %pcrel_hi relocation is + evaluated but not the %pcrel_lo. + + $ llvm-mc -triple riscv64 -filetype obj t.s | llvm-objdump -d -r - + + : file format ELF64-riscv + + Disassembly of section .text: + 0000000000000000 function: + 0: 17 05 00 00 auipc a0, 0 + 4: 93 05 05 00 mv a1, a0 + 0000000000000004: R_RISCV_PCREL_LO12_I other_function+4 + + 0000000000000008 other_function: + 8: 67 80 00 00 ret + + The reason seems to be that in RISCVAsmBackend::shouldForceRelocation we + only consider the fragment but in RISCVMCExpr::evaluatePCRelLo we + consider the section. This usually works but there are cases where the + section may still be the same but the fragment may be another one. In + that case we end forcing a %pcrel_lo relocation without any %pcrel_hi. + + This patch makes RISCVAsmBackend::shouldForceRelocation use the section, + if any, to determine if the relocation must be forced or not. + + Differential Revision: https://reviews.llvm.org/D60657 + +commit 41449c58c58e466bcf9cdc4f7415950382bad8d7 +Author: Roger Ferrer Ibanez +Date: Fri Nov 8 08:26:30 2019 +0000 + + [RISCV] Fix evaluation of %pcrel_lo + + The following testcase + + function: + .Lpcrel_label1: + auipc a0, %pcrel_hi(other_function) + addi a1, a0, %pcrel_lo(.Lpcrel_label1) + .p2align 2 # Causes a new fragment to be emitted + + .type other_function,@function + other_function: + ret + + exposes an odd behaviour in which only the %pcrel_hi relocation is + evaluated but not the %pcrel_lo. + + $ llvm-mc -triple riscv64 -filetype obj t.s | llvm-objdump -d -r - + + : file format ELF64-riscv + + Disassembly of section .text: + 0000000000000000 function: + 0: 17 05 00 00 auipc a0, 0 + 4: 93 05 05 00 mv a1, a0 + 0000000000000004: R_RISCV_PCREL_LO12_I other_function+4 + + 0000000000000008 other_function: + 8: 67 80 00 00 ret + + The reason seems to be that in RISCVAsmBackend::shouldForceRelocation we + only consider the fragment but in RISCVMCExpr::evaluatePCRelLo we + consider the section. This usually works but there are cases where the + section may still be the same but the fragment may be another one. In + that case we end forcing a %pcrel_lo relocation without any %pcrel_hi. + + This patch makes RISCVAsmBackend::shouldForceRelocation use the section, + if any, to determine if the relocation must be forced or not. + + Differential Revision: https://reviews.llvm.org/D60657 + +diff --git a/src/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/src/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +index f6b727ae37c..5881a0a86ef 100644 +--- a/src/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp ++++ b/src/llvm-project/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +@@ -64,11 +64,15 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, + case RISCV::fixup_riscv_tls_gd_hi20: + ShouldForce = true; + break; +- case RISCV::fixup_riscv_pcrel_hi20: +- ShouldForce = T->getValue()->findAssociatedFragment() != +- Fixup.getValue()->findAssociatedFragment(); ++ case RISCV::fixup_riscv_pcrel_hi20: { ++ MCFragment *TFragment = T->getValue()->findAssociatedFragment(); ++ MCFragment *FixupFragment = Fixup.getValue()->findAssociatedFragment(); ++ assert(FixupFragment && "We should have a fragment for this fixup"); ++ ShouldForce = ++ !TFragment || TFragment->getParent() != FixupFragment->getParent(); + break; + } ++ } + break; + } + +diff --git a/src/llvm-project/llvm/test/MC/RISCV/pcrel-fixups.s b/src/llvm-project/llvm/test/MC/RISCV/pcrel-fixups.s +new file mode 100644 +index 00000000000..1025988967a +--- /dev/null ++++ b/src/llvm-project/llvm/test/MC/RISCV/pcrel-fixups.s +@@ -0,0 +1,52 @@ ++# RUN: llvm-mc -triple riscv32 -mattr=-relax -filetype obj %s \ ++# RUN: | llvm-objdump -M no-aliases -d -r - \ ++# RUN: | FileCheck --check-prefix NORELAX %s ++# RUN: llvm-mc -triple riscv32 -mattr=+relax -filetype obj %s \ ++# RUN: | llvm-objdump -M no-aliases -d -r - \ ++# RUN: | FileCheck --check-prefix RELAX %s ++# RUN: llvm-mc -triple riscv64 -mattr=-relax -filetype obj %s \ ++# RUN: | llvm-objdump -M no-aliases -d -r - \ ++# RUN: | FileCheck --check-prefix NORELAX %s ++# RUN: llvm-mc -triple riscv64 -mattr=+relax -filetype obj %s \ ++# RUN: | llvm-objdump -M no-aliases -d -r - \ ++# RUN: | FileCheck --check-prefix RELAX %s ++ ++# Fixups for %pcrel_hi / %pcrel_lo can be evaluated within a section, ++# regardless of the fragment containing the target address. ++ ++function: ++.Lpcrel_label1: ++ auipc a0, %pcrel_hi(other_function) ++ addi a1, a0, %pcrel_lo(.Lpcrel_label1) ++# NORELAX: auipc a0, 0 ++# NORELAX-NOT: R_RISCV ++# NORELAX: addi a1, a0, 16 ++# NORELAX-NOT: R_RISCV ++ ++# RELAX: auipc a0, 0 ++# RELAX: R_RISCV_PCREL_HI20 other_function ++# RELAX: R_RISCV_RELAX *ABS* ++# RELAX: addi a1, a0, 0 ++# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label1 ++# RELAX: R_RISCV_RELAX *ABS* ++ ++ .p2align 2 # Cause a new fragment be emitted here ++.Lpcrel_label2: ++ auipc a0, %pcrel_hi(other_function) ++ addi a1, a0, %pcrel_lo(.Lpcrel_label2) ++# NORELAX: auipc a0, 0 ++# NORELAX-NOT: R_RISCV ++# NORELAX: addi a1, a0, 8 ++# NORELAX-NOT: R_RISCV ++ ++# RELAX: auipc a0, 0 ++# RELAX: R_RISCV_PCREL_HI20 other_function ++# RELAX: R_RISCV_RELAX *ABS* ++# RELAX: addi a1, a0, 0 ++# RELAX: R_RISCV_PCREL_LO12_I .Lpcrel_label2 ++# RELAX: R_RISCV_RELAX *ABS* ++ ++ .type other_function,@function ++other_function: ++ ret ++ diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/llvm-riscv64-fix-cffi.diff rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/llvm-riscv64-fix-cffi.diff --- rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/llvm-riscv64-fix-cffi.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/llvm/llvm-riscv64-fix-cffi.diff 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,76 @@ +commit c6b09bff5671600f8e764d3847023d0996f328d9 +Author: Luís Marques +Date: Thu Nov 14 18:27:42 2019 +0000 + + [RISCV] Fix wrong CFI directives + + Summary: Removes CFI CFA directives that could incorrectly propagate + beyond the basic block they were inteded for. Specifically it removes + the epilogue CFI directives. See the branch_and_tail_call test for an + example of the issue. Should fix the stack unwinding issues caused by + the incorrect directives. + + Reviewers: asb, lenary, shiva0217 + Reviewed By: lenary + Tags: #llvm + Differential Revision: https://reviews.llvm.org/D69723 + +--- a/src/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp ++++ b/src/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +@@ -205,7 +205,6 @@ + MachineFrameInfo &MFI = MF.getFrameInfo(); + auto *RVFI = MF.getInfo(); + DebugLoc DL = MBBI->getDebugLoc(); +- const RISCVInstrInfo *TII = STI.getInstrInfo(); + unsigned FPReg = getFPReg(STI); + unsigned SPReg = getSPReg(STI); + +@@ -225,48 +224,9 @@ + adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, + MachineInstr::FrameDestroy); + } +- +- if (hasFP(MF)) { +- // To find the instruction restoring FP from stack. +- for (auto &I = LastFrameDestroy; I != MBBI; ++I) { +- if (I->mayLoad() && I->getOperand(0).isReg()) { +- unsigned DestReg = I->getOperand(0).getReg(); +- if (DestReg == FPReg) { +- // If there is frame pointer, after restoring $fp registers, we +- // need adjust CFA to ($sp - FPOffset). +- // Emit ".cfi_def_cfa $sp, -FPOffset" +- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( +- nullptr, RI->getDwarfRegNum(SPReg, true), -FPOffset)); +- BuildMI(MBB, std::next(I), DL, +- TII->get(TargetOpcode::CFI_INSTRUCTION)) +- .addCFIIndex(CFIIndex); +- break; +- } +- } +- } +- } +- +- // Add CFI directives for callee-saved registers. +- const std::vector &CSI = MFI.getCalleeSavedInfo(); +- // Iterate over list of callee-saved registers and emit .cfi_restore +- // directives. +- for (const auto &Entry : CSI) { +- unsigned Reg = Entry.getReg(); +- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore( +- nullptr, RI->getDwarfRegNum(Reg, true))); +- BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) +- .addCFIIndex(CFIIndex); +- } + + // Deallocate stack + adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); +- +- // After restoring $sp, we need to adjust CFA to $(sp + 0) +- // Emit ".cfi_def_cfa_offset 0" +- unsigned CFIIndex = +- MF.addFrameInst(MCCFIInstruction::createDefCfaOffset(nullptr, 0)); +- BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) +- .addCFIIndex(CFIIndex); + } + + int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-atomic-detection.patch rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-atomic-detection.patch --- rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-atomic-detection.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-atomic-detection.patch 2020-04-08 00:15:47.000000000 +0000 @@ -0,0 +1,18 @@ +Description: Fix libatomic requirement detection for riscv64 + riscv64 doesn't need libatomic for 64-bit atomics, but it does for 8-bit ones. + Ensure the check tests both. +Author: William Grant + +--- rustc-1.41.0+dfsg1+llvm.orig/src/llvm-project/llvm/cmake/modules/CheckAtomic.cmake ++++ rustc-1.41.0+dfsg1+llvm/src/llvm-project/llvm/cmake/modules/CheckAtomic.cmake +@@ -12,8 +12,9 @@ function(check_working_cxx_atomics varna + CHECK_CXX_SOURCE_COMPILES(" + #include + std::atomic x; ++std::atomic y; + int main() { +- return x; ++ return x.fetch_add(1) + y.fetch_add(1); + } + " ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-dsymutil-atomic.patch rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-dsymutil-atomic.patch --- rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-dsymutil-atomic.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-dsymutil-atomic.patch 2020-04-08 00:18:39.000000000 +0000 @@ -0,0 +1,16 @@ +Description: Link dsymutil with -latomic when required + dsymutil requires -latomic on riscv64. +Author: William Grant + +Index: rustc-1.41.0+dfsg1+llvm/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt +=================================================================== +--- rustc-1.41.0+dfsg1+llvm.orig/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt ++++ rustc-1.41.0+dfsg1+llvm/src/llvm-project/llvm/tools/dsymutil/CMakeLists.txt +@@ -32,3 +32,7 @@ add_llvm_tool(dsymutil + if(APPLE) + target_link_libraries(dsymutil PRIVATE "-framework CoreFoundation") + endif(APPLE) ++ ++if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB) ++ target_link_libraries(dsymutil PRIVATE atomic) ++endif() diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-vendor-cc.diff rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-vendor-cc.diff --- rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-vendor-cc.diff 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/riscv64-vendor-cc.diff 2020-04-08 00:18:39.000000000 +0000 @@ -0,0 +1,16 @@ +Description: Fix one last ABI reference for riscv64 +Author: William Grant + +Index: rustc-1.41.0+dfsg1+llvm/vendor/cc/src/lib.rs +=================================================================== +--- rustc-1.41.0+dfsg1+llvm.orig/vendor/cc/src/lib.rs ++++ rustc-1.41.0+dfsg1+llvm/vendor/cc/src/lib.rs +@@ -1591,7 +1591,7 @@ impl Build { + // ABI is always soft-float right now, update this when this is no longer the + // case: + if arch.starts_with("64") { +- cmd.args.push("-mabi=lp64".into()); ++ cmd.args.push("-mabi=lp64d".into()); + } else { + cmd.args.push("-mabi=ilp32".into()); + } diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/series rustc-1.41.0+dfsg1+llvm/debian/patches/series --- rustc-1.41.0+dfsg1+llvm/debian/patches/series 2020-03-02 12:46:29.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/series 2020-04-08 00:18:39.000000000 +0000 @@ -42,3 +42,12 @@ # Work around for some porterboxes, keep this commented #d-host-duplicates.patch +u-riscv64-68452.patch +u-riscv64-compiletest.patch +llvm/D60657-riscv-pcrel_lo.diff +llvm/clang-riscv64-multiarch.diff +llvm/clang-riscv64-rv64gc.diff +llvm/llvm-riscv64-fix-cffi.diff +riscv64-vendor-cc.diff +riscv64-dsymutil-atomic.patch +riscv64-atomic-detection.patch diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-68452.patch rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-68452.patch --- rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-68452.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-68452.patch 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,1344 @@ +From e5901641755dfd2e758c7e855b82ee0bcd8b29c0 Mon Sep 17 00:00:00 2001 +From: msizanoen1 +Date: Tue, 21 Jan 2020 21:52:19 +0700 +Subject: [PATCH 1/2] Implement proper C ABI lowering for RISC-V + +--- + src/librustc/ty/layout.rs | 1 + + src/librustc_target/abi/call/mod.rs | 10 +- + src/librustc_target/abi/call/riscv.rs | 335 +++++++++++++++++++++++++- + 3 files changed, 331 insertions(+), 15 deletions(-) + +diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs +index bda42db40b0a..c70473b667ea 100644 +--- a/src/librustc/ty/layout.rs ++++ b/src/librustc/ty/layout.rs +@@ -2650,6 +2650,7 @@ where + .map(|(i, ty)| arg_of(ty, Some(i))) + .collect(), + c_variadic: sig.c_variadic, ++ fixed_count: inputs.len(), + conv, + }; + fn_abi.adjust_for_abi(cx, sig.abi); +diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs +index af82f9e31837..175eb93e4e55 100644 +--- a/src/librustc_target/abi/call/mod.rs ++++ b/src/librustc_target/abi/call/mod.rs +@@ -120,6 +120,7 @@ impl Reg { + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); ++ reg_ctor!(i128, Integer, 128); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +@@ -493,6 +494,12 @@ pub struct FnAbi<'a, Ty> { + + pub c_variadic: bool, + ++ /// The count of non-variadic arguments. ++ /// ++ /// Should only be different from args.len() when c_variadic is true. ++ /// This can be used to know wether an argument is variadic or not. ++ pub fixed_count: usize, ++ + pub conv: Conv, + } + +@@ -534,8 +541,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { + "nvptx" => nvptx::compute_abi_info(self), + "nvptx64" => nvptx64::compute_abi_info(self), + "hexagon" => hexagon::compute_abi_info(self), +- "riscv32" => riscv::compute_abi_info(self, 32), +- "riscv64" => riscv::compute_abi_info(self, 64), ++ "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self), + "wasm32" if cx.target_spec().target_os != "emscripten" + => wasm32_bindgen_compat::compute_abi_info(self), + "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self), +diff --git a/src/librustc_target/abi/call/riscv.rs b/src/librustc_target/abi/call/riscv.rs +index 095e5aff7442..11d6c4d81910 100644 +--- a/src/librustc_target/abi/call/riscv.rs ++++ b/src/librustc_target/abi/call/riscv.rs +@@ -1,49 +1,358 @@ + // Reference: RISC-V ELF psABI specification + // https://github.com/riscv/riscv-elf-psabi-doc ++// ++// Reference: Clang RISC-V ELF psABI lowering code ++// https://github.com/llvm/llvm-project/blob/8e780252a7284be45cf1ba224cabd884847e8e92/clang/lib/CodeGen/TargetInfo.cpp#L9311-L9773 + +-use crate::abi::call::{ArgAbi, FnAbi}; ++use crate::abi::call::{ArgAbi, ArgAttribute, CastTarget, FnAbi, PassMode, Reg, RegKind, Uniform}; ++use crate::abi::{ ++ self, Abi, FieldPlacement, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods, ++}; ++use crate::spec::HasTargetSpec; ++ ++#[derive(Copy, Clone)] ++enum RegPassKind { ++ Float(Reg), ++ Integer(Reg), ++ Unknown, ++} ++ ++#[derive(Copy, Clone)] ++enum FloatConv { ++ FloatPair(Reg, Reg), ++ Float(Reg), ++ MixedPair(Reg, Reg), ++} ++ ++#[derive(Copy, Clone)] ++struct CannotUseFpConv; ++ ++fn is_riscv_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { ++ match arg.layout.abi { ++ Abi::Vector { .. } => true, ++ _ => arg.layout.is_aggregate(), ++ } ++} ++ ++fn should_use_fp_conv_helper<'a, Ty, C>( ++ cx: &C, ++ arg_layout: &TyLayout<'a, Ty>, ++ xlen: u64, ++ flen: u64, ++ field1_kind: &mut RegPassKind, ++ field2_kind: &mut RegPassKind, ++) -> Result<(), CannotUseFpConv> ++where ++ Ty: TyLayoutMethods<'a, C> + Copy, ++ C: LayoutOf>, ++{ ++ match arg_layout.abi { ++ Abi::Scalar(ref scalar) => match scalar.value { ++ abi::Int(..) | abi::Pointer => { ++ if arg_layout.size.bits() > xlen { ++ return Err(CannotUseFpConv); ++ } ++ match (*field1_kind, *field2_kind) { ++ (RegPassKind::Unknown, _) => { ++ *field1_kind = RegPassKind::Integer(Reg { ++ kind: RegKind::Integer, ++ size: arg_layout.size, ++ }); ++ } ++ (RegPassKind::Float(_), RegPassKind::Unknown) => { ++ *field2_kind = RegPassKind::Integer(Reg { ++ kind: RegKind::Integer, ++ size: arg_layout.size, ++ }); ++ } ++ _ => return Err(CannotUseFpConv), ++ } ++ } ++ abi::F32 | abi::F64 => { ++ if arg_layout.size.bits() > flen { ++ return Err(CannotUseFpConv); ++ } ++ match (*field1_kind, *field2_kind) { ++ (RegPassKind::Unknown, _) => { ++ *field1_kind = ++ RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); ++ } ++ (_, RegPassKind::Unknown) => { ++ *field2_kind = ++ RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size }); ++ } ++ _ => return Err(CannotUseFpConv), ++ } ++ } ++ }, ++ Abi::Vector { .. } | Abi::Uninhabited => return Err(CannotUseFpConv), ++ Abi::ScalarPair(..) | Abi::Aggregate { .. } => match arg_layout.fields { ++ FieldPlacement::Union(_) => { ++ if !arg_layout.is_zst() { ++ return Err(CannotUseFpConv); ++ } ++ } ++ FieldPlacement::Array { count, .. } => { ++ for _ in 0..count { ++ let elem_layout = arg_layout.field(cx, 0); ++ should_use_fp_conv_helper( ++ cx, ++ &elem_layout, ++ xlen, ++ flen, ++ field1_kind, ++ field2_kind, ++ )?; ++ } ++ } ++ FieldPlacement::Arbitrary { .. } => { ++ match arg_layout.variants { ++ abi::Variants::Multiple { .. } => return Err(CannotUseFpConv), ++ abi::Variants::Single { .. } => (), ++ } ++ for i in arg_layout.fields.index_by_increasing_offset() { ++ let field = arg_layout.field(cx, i); ++ should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?; ++ } ++ } ++ }, ++ } ++ Ok(()) ++} ++ ++fn should_use_fp_conv<'a, Ty, C>( ++ cx: &C, ++ arg: &TyLayout<'a, Ty>, ++ xlen: u64, ++ flen: u64, ++) -> Option ++where ++ Ty: TyLayoutMethods<'a, C> + Copy, ++ C: LayoutOf>, ++{ ++ let mut field1_kind = RegPassKind::Unknown; ++ let mut field2_kind = RegPassKind::Unknown; ++ if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() { ++ return None; ++ } ++ match (field1_kind, field2_kind) { ++ (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)), ++ (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)), ++ (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)), ++ (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)), ++ _ => None, ++ } ++} ++ ++fn classify_ret<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, xlen: u64, flen: u64) -> bool ++where ++ Ty: TyLayoutMethods<'a, C> + Copy, ++ C: LayoutOf>, ++{ ++ if let Some(conv) = should_use_fp_conv(cx, &arg.layout, xlen, flen) { ++ match conv { ++ FloatConv::Float(f) => { ++ arg.cast_to(f); ++ } ++ FloatConv::FloatPair(l, r) => { ++ arg.cast_to(CastTarget::pair(l, r)); ++ } ++ FloatConv::MixedPair(l, r) => { ++ arg.cast_to(CastTarget::pair(l, r)); ++ } ++ } ++ return false; ++ } ++ ++ let total = arg.layout.size; + +-fn classify_ret(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { + // "Scalars wider than 2✕XLEN are passed by reference and are replaced in + // the argument list with the address." + // "Aggregates larger than 2✕XLEN bits are passed by reference and are + // replaced in the argument list with the address, as are C++ aggregates + // with nontrivial copy constructors, destructors, or vtables." +- if arg.layout.size.bits() > 2 * xlen { +- arg.make_indirect(); ++ if total.bits() > 2 * xlen { ++ // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN. ++ if is_riscv_aggregate(arg) { ++ arg.make_indirect(); ++ } ++ return true; ++ } ++ ++ let xlen_reg = match xlen { ++ 32 => Reg::i32(), ++ 64 => Reg::i64(), ++ _ => unreachable!("Unsupported XLEN: {}", xlen), ++ }; ++ if is_riscv_aggregate(arg) { ++ if total.bits() <= xlen { ++ arg.cast_to(xlen_reg); ++ } else { ++ arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); ++ } ++ return false; + } + + // "When passed in registers, scalars narrower than XLEN bits are widened + // according to the sign of their type up to 32 bits, then sign-extended to + // XLEN bits." +- arg.extend_integer_width_to(xlen); // this method only affects integer scalars ++ extend_integer_width(arg, xlen); ++ false + } + +-fn classify_arg(arg: &mut ArgAbi<'_, Ty>, xlen: u64) { ++fn classify_arg<'a, Ty, C>( ++ cx: &C, ++ arg: &mut ArgAbi<'a, Ty>, ++ xlen: u64, ++ flen: u64, ++ is_vararg: bool, ++ avail_gprs: &mut u64, ++ avail_fprs: &mut u64, ++) where ++ Ty: TyLayoutMethods<'a, C> + Copy, ++ C: LayoutOf>, ++{ ++ if !is_vararg { ++ match should_use_fp_conv(cx, &arg.layout, xlen, flen) { ++ Some(FloatConv::Float(f)) if *avail_fprs >= 1 => { ++ *avail_fprs -= 1; ++ arg.cast_to(f); ++ return; ++ } ++ Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => { ++ *avail_fprs -= 2; ++ arg.cast_to(CastTarget::pair(l, r)); ++ return; ++ } ++ Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => { ++ *avail_gprs -= 1; ++ *avail_fprs -= 1; ++ arg.cast_to(CastTarget::pair(l, r)); ++ return; ++ } ++ _ => (), ++ } ++ } ++ ++ let total = arg.layout.size; ++ let align = arg.layout.align.abi.bits(); ++ + // "Scalars wider than 2✕XLEN are passed by reference and are replaced in + // the argument list with the address." + // "Aggregates larger than 2✕XLEN bits are passed by reference and are + // replaced in the argument list with the address, as are C++ aggregates + // with nontrivial copy constructors, destructors, or vtables." +- if arg.layout.size.bits() > 2 * xlen { +- arg.make_indirect(); ++ if total.bits() > 2 * xlen { ++ // We rely on the LLVM backend lowering code to lower passing a scalar larger than 2*XLEN. ++ if is_riscv_aggregate(arg) { ++ arg.make_indirect(); ++ } ++ if *avail_gprs >= 1 { ++ *avail_gprs -= 1; ++ } ++ return; ++ } ++ ++ let double_xlen_reg = match xlen { ++ 32 => Reg::i64(), ++ 64 => Reg::i128(), ++ _ => unreachable!("Unsupported XLEN: {}", xlen), ++ }; ++ ++ let xlen_reg = match xlen { ++ 32 => Reg::i32(), ++ 64 => Reg::i64(), ++ _ => unreachable!("Unsupported XLEN: {}", xlen), ++ }; ++ ++ if total.bits() > xlen { ++ let align_regs = align > xlen; ++ if is_riscv_aggregate(arg) { ++ arg.cast_to(Uniform { ++ unit: if align_regs { double_xlen_reg } else { xlen_reg }, ++ total: Size::from_bits(xlen * 2), ++ }); ++ } ++ if align_regs && is_vararg { ++ *avail_gprs -= *avail_gprs % 2; ++ } ++ if *avail_gprs >= 2 { ++ *avail_gprs -= 2; ++ } else { ++ *avail_gprs = 0; ++ } ++ return; ++ } else if is_riscv_aggregate(arg) { ++ arg.cast_to(xlen_reg); ++ if *avail_gprs >= 1 { ++ *avail_gprs -= 1; ++ } ++ return; + } + + // "When passed in registers, scalars narrower than XLEN bits are widened + // according to the sign of their type up to 32 bits, then sign-extended to + // XLEN bits." +- arg.extend_integer_width_to(xlen); // this method only affects integer scalars ++ if *avail_gprs >= 1 { ++ extend_integer_width(arg, xlen); ++ *avail_gprs -= 1; ++ } + } + +-pub fn compute_abi_info(fn_abi: &mut FnAbi<'_, Ty>, xlen: u64) { ++fn extend_integer_width<'a, Ty>(arg: &mut ArgAbi<'a, Ty>, xlen: u64) { ++ match arg.layout.abi { ++ Abi::Scalar(ref scalar) => { ++ match scalar.value { ++ abi::Int(i, _) => { ++ // 32-bit integers are always sign-extended ++ if i.size().bits() == 32 && xlen > 32 { ++ if let PassMode::Direct(ref mut attrs) = arg.mode { ++ attrs.set(ArgAttribute::SExt); ++ return; ++ } ++ } ++ } ++ _ => (), ++ } ++ } ++ _ => (), ++ } ++ arg.extend_integer_width_to(xlen); ++} ++ ++pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) ++where ++ Ty: TyLayoutMethods<'a, C> + Copy, ++ C: LayoutOf> + HasDataLayout + HasTargetSpec, ++{ ++ let flen = match &cx.target_spec().options.llvm_abiname[..] { ++ "ilp32f" | "lp64f" => 32, ++ "ilp32d" | "lp64d" => 64, ++ _ => 0, ++ }; ++ let xlen = cx.data_layout().pointer_size.bits(); ++ ++ let mut avail_gprs = 8; ++ let mut avail_fprs = 8; ++ + if !fn_abi.ret.is_ignore() { +- classify_ret(&mut fn_abi.ret, xlen); ++ if classify_ret(cx, &mut fn_abi.ret, xlen, flen) { ++ avail_gprs -= 1; ++ } + } + +- for arg in &mut fn_abi.args { ++ for (i, arg) in fn_abi.args.iter_mut().enumerate() { + if arg.is_ignore() { + continue; + } +- classify_arg(arg, xlen); ++ classify_arg( ++ cx, ++ arg, ++ xlen, ++ flen, ++ i >= fn_abi.fixed_count, ++ &mut avail_gprs, ++ &mut avail_fprs, ++ ); + } + } + +From 39633874ae7d0150669004a80740ff3b0708d08d Mon Sep 17 00:00:00 2001 +From: msizanoen1 +Date: Mon, 3 Feb 2020 22:04:44 +0700 +Subject: [PATCH 2/2] Add tests for RISC-V C ABI + +--- + src/test/auxiliary/rust_test_helpers.c | 29 ++ + .../riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs | 181 +++++++++++ + .../codegen/riscv-abi/riscv64-lp64d-abi.rs | 293 ++++++++++++++++++ + .../riscv-abi/riscv64-lp64f-lp64d-abi.rs | 277 +++++++++++++++++ + src/test/ui/abi/struct-enums/struct-return.rs | 52 +++- + 5 files changed, 831 insertions(+), 1 deletion(-) + create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs + create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs + create mode 100644 src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs + +diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c +index b95b0ca1a89c..22bb54988365 100644 +--- a/src/test/auxiliary/rust_test_helpers.c ++++ b/src/test/auxiliary/rust_test_helpers.c +@@ -168,6 +168,18 @@ struct floats { + double c; + }; + ++struct char_char_double { ++ uint8_t a; ++ uint8_t b; ++ double c; ++}; ++ ++struct char_char_float { ++ uint8_t a; ++ uint8_t b; ++ float c; ++}; ++ + struct quad + rust_dbg_abi_1(struct quad q) { + struct quad qq = { q.c + 1, +@@ -185,6 +197,23 @@ rust_dbg_abi_2(struct floats f) { + return ff; + } + ++struct char_char_double ++rust_dbg_abi_3(struct char_char_double a) { ++ struct char_char_double ccd = { a.a + 1, ++ a.b - 1, ++ a.c + 1.0 }; ++ return ccd; ++} ++ ++struct char_char_float ++rust_dbg_abi_4(struct char_char_float a) { ++ struct char_char_float ccd = { a.a + 1, ++ a.b - 1, ++ a.c + 1.0 }; ++ return ccd; ++} ++ ++ + int + rust_dbg_static_mut = 3; + +diff --git a/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +new file mode 100644 +index 000000000000..f0f052fe5c55 +--- /dev/null ++++ b/src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs +@@ -0,0 +1,181 @@ ++// ignore-tidy-linelength ++// compile-flags: -C no-prepopulate-passes ++// only-riscv64 ++// only-linux ++#![crate_type = "lib"] ++#![allow(improper_ctypes)] ++ ++// CHECK: define void @f_void() ++#[no_mangle] ++pub extern "C" fn f_void() {} ++ ++// CHECK: define zeroext i1 @f_scalar_0(i1 zeroext %a) ++#[no_mangle] ++pub extern "C" fn f_scalar_0(a: bool) -> bool { ++ a ++} ++ ++// CHECK: define signext i8 @f_scalar_1(i8 signext %x) ++#[no_mangle] ++pub extern "C" fn f_scalar_1(x: i8) -> i8 { ++ x ++} ++ ++// CHECK: define zeroext i8 @f_scalar_2(i8 zeroext %x) ++#[no_mangle] ++pub extern "C" fn f_scalar_2(x: u8) -> u8 { ++ x ++} ++ ++// CHECK: define signext i32 @f_scalar_3(i32 signext %x) ++#[no_mangle] ++pub extern "C" fn f_scalar_3(x: i32) -> u32 { ++ x as u32 ++} ++ ++// CHECK: define i64 @f_scalar_4(i64 %x) ++#[no_mangle] ++pub extern "C" fn f_scalar_4(x: i64) -> i64 { ++ x ++} ++ ++// CHECK: define float @f_fp_scalar_1(float) ++#[no_mangle] ++pub extern "C" fn f_fp_scalar_1(x: f32) -> f32 { ++ x ++} ++// CHECK: define double @f_fp_scalar_2(double) ++#[no_mangle] ++pub extern "C" fn f_fp_scalar_2(x: f64) -> f64 { ++ x ++} ++ ++#[repr(C)] ++pub struct Empty {} ++ ++// CHECK: define void @f_agg_empty_struct() ++#[no_mangle] ++pub extern "C" fn f_agg_empty_struct(e: Empty) -> Empty { ++ e ++} ++ ++#[repr(C)] ++pub struct Tiny { ++ a: u16, ++ b: u16, ++ c: u16, ++ d: u16, ++} ++ ++// CHECK: define void @f_agg_tiny(i64) ++#[no_mangle] ++pub extern "C" fn f_agg_tiny(mut e: Tiny) { ++ e.a += e.b; ++ e.c += e.d; ++} ++ ++// CHECK: define i64 @f_agg_tiny_ret() ++#[no_mangle] ++pub extern "C" fn f_agg_tiny_ret() -> Tiny { ++ Tiny { a: 1, b: 2, c: 3, d: 4 } ++} ++ ++#[repr(C)] ++pub struct Small { ++ a: i64, ++ b: *mut i64, ++} ++ ++// CHECK: define void @f_agg_small([2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_agg_small(mut x: Small) { ++ x.a += unsafe { *x.b }; ++ x.b = &mut x.a; ++} ++ ++// CHECK: define [2 x i64] @f_agg_small_ret() ++#[no_mangle] ++pub extern "C" fn f_agg_small_ret() -> Small { ++ Small { a: 1, b: core::ptr::null_mut() } ++} ++ ++#[repr(C)] ++pub struct SmallAligned { ++ a: i128, ++} ++ ++// CHECK: define void @f_agg_small_aligned(i128) ++#[no_mangle] ++pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) { ++ x.a += x.a; ++} ++ ++#[repr(C)] ++pub struct Large { ++ a: i64, ++ b: i64, ++ c: i64, ++ d: i64, ++} ++ ++// CHECK: define void @f_agg_large(%Large* {{.*}}%x) ++#[no_mangle] ++pub extern "C" fn f_agg_large(mut x: Large) { ++ x.a = x.b + x.c + x.d; ++} ++ ++// CHECK: define void @f_agg_large_ret(%Large* {{.*}}sret{{.*}}, i32 signext %i, i8 signext %j) ++#[no_mangle] ++pub extern "C" fn f_agg_large_ret(i: i32, j: i8) -> Large { ++ Large { a: 1, b: 2, c: 3, d: 4 } ++} ++ ++// CHECK: define void @f_scalar_stack_1(i64, [2 x i64], i128, %Large* {{.*}}%d, i8 zeroext %e, i8 signext %f, i8 %g, i8 %h) ++#[no_mangle] ++pub extern "C" fn f_scalar_stack_1( ++ a: Tiny, ++ b: Small, ++ c: SmallAligned, ++ d: Large, ++ e: u8, ++ f: i8, ++ g: u8, ++ h: i8, ++) { ++} ++ ++// CHECK: define void @f_scalar_stack_2(%Large* {{.*}}sret{{.*}}, i64 %a, i128, i128, i64 %d, i8 zeroext %e, i8 %f, i8 %g) ++#[no_mangle] ++pub extern "C" fn f_scalar_stack_2( ++ a: u64, ++ b: SmallAligned, ++ c: SmallAligned, ++ d: u64, ++ e: u8, ++ f: i8, ++ g: u8, ++) -> Large { ++ Large { a: a as i64, b: e as i64, c: f as i64, d: g as i64 } ++} ++ ++extern "C" { ++ fn f_va_callee(_: i32, ...) -> i32; ++} ++ ++#[no_mangle] ++pub unsafe extern "C" fn f_va_caller() { ++ // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i64 3, double {{.*}}, double {{.*}}, i64 {{.*}}, [2 x i64] {{.*}}, i128 {{.*}}, %Large* {{.*}}) ++ f_va_callee( ++ 1, ++ 2i32, ++ 3i64, ++ 4.0f64, ++ 5.0f64, ++ Tiny { a: 1, b: 2, c: 3, d: 4 }, ++ Small { a: 10, b: core::ptr::null_mut() }, ++ SmallAligned { a: 11 }, ++ Large { a: 12, b: 13, c: 14, d: 15 }, ++ ); ++ // CHECK: call signext i32 (i32, ...) @f_va_callee(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i128 {{.*}}, i32 signext 6, i32 signext 7, i32 8, i32 9) ++ f_va_callee(1, 2i32, 3i32, 4i32, SmallAligned { a: 5 }, 6i32, 7i32, 8i32, 9i32); ++} +diff --git a/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs +new file mode 100644 +index 000000000000..66a3b9e4952a +--- /dev/null ++++ b/src/test/codegen/riscv-abi/riscv64-lp64d-abi.rs +@@ -0,0 +1,293 @@ ++// ignore-tidy-linelength ++// compile-flags: -C no-prepopulate-passes ++// only-riscv64 ++// only-linux ++#![crate_type = "lib"] ++ ++// CHECK: define void @f_fpr_tracking(double, double, double, double, double, double, double, double, i8 zeroext %i) ++#[no_mangle] ++pub extern "C" fn f_fpr_tracking( ++ a: f64, ++ b: f64, ++ c: f64, ++ d: f64, ++ e: f64, ++ f: f64, ++ g: f64, ++ h: f64, ++ i: u8, ++) { ++} ++ ++#[repr(C)] ++pub struct Double { ++ f: f64, ++} ++ ++#[repr(C)] ++pub struct DoubleDouble { ++ f: f64, ++ g: f64, ++} ++ ++#[repr(C)] ++pub struct DoubleFloat { ++ f: f64, ++ g: f32, ++} ++ ++// CHECK: define void @f_double_s_arg(double) ++#[no_mangle] ++pub extern "C" fn f_double_s_arg(a: Double) {} ++ ++// CHECK: define double @f_ret_double_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_s() -> Double { ++ Double { f: 1. } ++} ++ ++// CHECK: define void @f_double_double_s_arg({ double, double }) ++#[no_mangle] ++pub extern "C" fn f_double_double_s_arg(a: DoubleDouble) {} ++ ++// CHECK: define { double, double } @f_ret_double_double_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_double_s() -> DoubleDouble { ++ DoubleDouble { f: 1., g: 2. } ++} ++ ++// CHECK: define void @f_double_float_s_arg({ double, float }) ++#[no_mangle] ++pub extern "C" fn f_double_float_s_arg(a: DoubleFloat) {} ++ ++// CHECK: define { double, float } @f_ret_double_float_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_float_s() -> DoubleFloat { ++ DoubleFloat { f: 1., g: 2. } ++} ++ ++// CHECK: define void @f_double_double_s_arg_insufficient_fprs(double, double, double, double, double, double, double, [2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_double_double_s_arg_insufficient_fprs( ++ a: f64, ++ b: f64, ++ c: f64, ++ d: f64, ++ e: f64, ++ f: f64, ++ g: f64, ++ h: DoubleDouble, ++) { ++} ++ ++#[repr(C)] ++pub struct DoubleInt8 { ++ f: f64, ++ i: i8, ++} ++ ++#[repr(C)] ++pub struct DoubleUInt8 { ++ f: f64, ++ i: u8, ++} ++ ++#[repr(C)] ++pub struct DoubleInt32 { ++ f: f64, ++ i: i32, ++} ++ ++#[repr(C)] ++pub struct DoubleInt64 { ++ f: f64, ++ i: i64, ++} ++ ++// CHECK: define void @f_double_int8_s_arg({ double, i8 }) ++#[no_mangle] ++pub extern "C" fn f_double_int8_s_arg(a: DoubleInt8) {} ++ ++// CHECK: define { double, i8 } @f_ret_double_int8_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_int8_s() -> DoubleInt8 { ++ DoubleInt8 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_double_int32_s_arg({ double, i32 }) ++#[no_mangle] ++pub extern "C" fn f_double_int32_s_arg(a: DoubleInt32) {} ++ ++// CHECK: define { double, i32 } @f_ret_double_int32_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_int32_s() -> DoubleInt32 { ++ DoubleInt32 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_double_uint8_s_arg({ double, i8 }) ++#[no_mangle] ++pub extern "C" fn f_double_uint8_s_arg(a: DoubleUInt8) {} ++ ++// CHECK: define { double, i8 } @f_ret_double_uint8_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_uint8_s() -> DoubleUInt8 { ++ DoubleUInt8 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_double_int64_s_arg({ double, i64 }) ++#[no_mangle] ++pub extern "C" fn f_double_int64_s_arg(a: DoubleInt64) {} ++ ++// CHECK: define { double, i64 } @f_ret_double_int64_s() ++#[no_mangle] ++pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { ++ DoubleInt64 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( ++ a: i32, ++ b: i32, ++ c: i32, ++ d: i32, ++ e: i32, ++ f: i32, ++ g: i32, ++ h: i32, ++ i: DoubleInt8, ++) { ++} ++ ++// CHECK: define void @f_struct_double_int8_insufficient_fprs(float, double, double, double, double, double, double, double, [2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_struct_double_int8_insufficient_fprs( ++ a: f32, ++ b: f64, ++ c: f64, ++ d: f64, ++ e: f64, ++ f: f64, ++ g: f64, ++ h: f64, ++ i: DoubleInt8, ++) { ++} ++ ++#[repr(C)] ++pub struct DoubleArr1 { ++ a: [f64; 1], ++} ++ ++// CHECK: define void @f_doublearr1_s_arg(double) ++#[no_mangle] ++pub extern "C" fn f_doublearr1_s_arg(a: DoubleArr1) {} ++ ++// CHECK: define double @f_ret_doublearr1_s() ++#[no_mangle] ++pub extern "C" fn f_ret_doublearr1_s() -> DoubleArr1 { ++ DoubleArr1 { a: [1.] } ++} ++ ++#[repr(C)] ++pub struct DoubleArr2 { ++ a: [f64; 2], ++} ++ ++// CHECK: define void @f_doublearr2_s_arg({ double, double }) ++#[no_mangle] ++pub extern "C" fn f_doublearr2_s_arg(a: DoubleArr2) {} ++ ++// CHECK: define { double, double } @f_ret_doublearr2_s() ++#[no_mangle] ++pub extern "C" fn f_ret_doublearr2_s() -> DoubleArr2 { ++ DoubleArr2 { a: [1., 2.] } ++} ++ ++#[repr(C)] ++pub struct Tricky1 { ++ f: [f64; 1], ++} ++ ++#[repr(C)] ++pub struct DoubleArr2Tricky1 { ++ g: [Tricky1; 2], ++} ++ ++// CHECK: define void @f_doublearr2_tricky1_s_arg({ double, double }) ++#[no_mangle] ++pub extern "C" fn f_doublearr2_tricky1_s_arg(a: DoubleArr2Tricky1) {} ++ ++// CHECK: define { double, double } @f_ret_doublearr2_tricky1_s() ++#[no_mangle] ++pub extern "C" fn f_ret_doublearr2_tricky1_s() -> DoubleArr2Tricky1 { ++ DoubleArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } ++} ++ ++#[repr(C)] ++pub struct EmptyStruct {} ++ ++#[repr(C)] ++pub struct DoubleArr2Tricky2 { ++ s: EmptyStruct, ++ g: [Tricky1; 2], ++} ++ ++// CHECK: define void @f_doublearr2_tricky2_s_arg({ double, double }) ++#[no_mangle] ++pub extern "C" fn f_doublearr2_tricky2_s_arg(a: DoubleArr2Tricky2) {} ++ ++// CHECK: define { double, double } @f_ret_doublearr2_tricky2_s() ++#[no_mangle] ++pub extern "C" fn f_ret_doublearr2_tricky2_s() -> DoubleArr2Tricky2 { ++ DoubleArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } ++} ++ ++#[repr(C)] ++pub struct IntDoubleInt { ++ a: i32, ++ b: f64, ++ c: i32, ++} ++ ++// CHECK: define void @f_int_double_int_s_arg(%IntDoubleInt* {{.*}}%a) ++#[no_mangle] ++pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} ++ ++// CHECK: define void @f_ret_int_double_int_s(%IntDoubleInt* {{.*}}sret ++#[no_mangle] ++pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { ++ IntDoubleInt { a: 1, b: 2., c: 3 } ++} ++ ++#[repr(C)] ++pub struct CharCharDouble { ++ a: u8, ++ b: u8, ++ c: f64, ++} ++ ++// CHECK: define void @f_char_char_double_s_arg([2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_char_char_double_s_arg(a: CharCharDouble) {} ++ ++// CHECK: define [2 x i64] @f_ret_char_char_double_s() ++#[no_mangle] ++pub extern "C" fn f_ret_char_char_double_s() -> CharCharDouble { ++ CharCharDouble { a: 1, b: 2, c: 3. } ++} ++ ++#[repr(C)] ++pub union DoubleU { ++ a: f64, ++} ++ ++// CHECK: define void @f_double_u_arg(i64) ++#[no_mangle] ++pub extern "C" fn f_double_u_arg(a: DoubleU) {} ++ ++// CHECK: define i64 @f_ret_double_u() ++#[no_mangle] ++pub extern "C" fn f_ret_double_u() -> DoubleU { ++ unsafe { DoubleU { a: 1. } } ++} +diff --git a/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs +new file mode 100644 +index 000000000000..d843331f425d +--- /dev/null ++++ b/src/test/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs +@@ -0,0 +1,277 @@ ++// ignore-tidy-linelength ++// compile-flags: -C no-prepopulate-passes ++// only-riscv64 ++// only-linux ++#![crate_type = "lib"] ++ ++// CHECK: define void @f_fpr_tracking(float, float, float, float, float, float, float, float, i8 zeroext %i) ++#[no_mangle] ++pub extern "C" fn f_fpr_tracking( ++ a: f32, ++ b: f32, ++ c: f32, ++ d: f32, ++ e: f32, ++ f: f32, ++ g: f32, ++ h: f32, ++ i: u8, ++) { ++} ++ ++#[repr(C)] ++pub struct Float { ++ f: f32, ++} ++ ++#[repr(C)] ++pub struct FloatFloat { ++ f: f32, ++ g: f32, ++} ++ ++// CHECK: define void @f_float_s_arg(float) ++#[no_mangle] ++pub extern "C" fn f_float_s_arg(a: Float) {} ++ ++// CHECK: define float @f_ret_float_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_s() -> Float { ++ Float { f: 1. } ++} ++ ++// CHECK: define void @f_float_float_s_arg({ float, float }) ++#[no_mangle] ++pub extern "C" fn f_float_float_s_arg(a: FloatFloat) {} ++ ++// CHECK: define { float, float } @f_ret_float_float_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_float_s() -> FloatFloat { ++ FloatFloat { f: 1., g: 2. } ++} ++ ++// CHECK: define void @f_float_float_s_arg_insufficient_fprs(float, float, float, float, float, float, float, i64) ++#[no_mangle] ++pub extern "C" fn f_float_float_s_arg_insufficient_fprs( ++ a: f32, ++ b: f32, ++ c: f32, ++ d: f32, ++ e: f32, ++ f: f32, ++ g: f32, ++ h: FloatFloat, ++) { ++} ++ ++#[repr(C)] ++pub struct FloatInt8 { ++ f: f32, ++ i: i8, ++} ++ ++#[repr(C)] ++pub struct FloatUInt8 { ++ f: f32, ++ i: u8, ++} ++ ++#[repr(C)] ++pub struct FloatInt32 { ++ f: f32, ++ i: i32, ++} ++ ++#[repr(C)] ++pub struct FloatInt64 { ++ f: f32, ++ i: i64, ++} ++ ++// CHECK: define void @f_float_int8_s_arg({ float, i8 }) ++#[no_mangle] ++pub extern "C" fn f_float_int8_s_arg(a: FloatInt8) {} ++ ++// CHECK: define { float, i8 } @f_ret_float_int8_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_int8_s() -> FloatInt8 { ++ FloatInt8 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_float_int32_s_arg({ float, i32 }) ++#[no_mangle] ++pub extern "C" fn f_float_int32_s_arg(a: FloatInt32) {} ++ ++// CHECK: define { float, i32 } @f_ret_float_int32_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_int32_s() -> FloatInt32 { ++ FloatInt32 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_float_uint8_s_arg({ float, i8 }) ++#[no_mangle] ++pub extern "C" fn f_float_uint8_s_arg(a: FloatUInt8) {} ++ ++// CHECK: define { float, i8 } @f_ret_float_uint8_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_uint8_s() -> FloatUInt8 { ++ FloatUInt8 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_float_int64_s_arg({ float, i64 }) ++#[no_mangle] ++pub extern "C" fn f_float_int64_s_arg(a: FloatInt64) {} ++ ++// CHECK: define { float, i64 } @f_ret_float_int64_s() ++#[no_mangle] ++pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { ++ FloatInt64 { f: 1., i: 2 } ++} ++ ++// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64) ++#[no_mangle] ++pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( ++ a: i32, ++ b: i32, ++ c: i32, ++ d: i32, ++ e: i32, ++ f: i32, ++ g: i32, ++ h: i32, ++ i: FloatInt8, ++) { ++} ++ ++// CHECK: define void @f_struct_float_int8_insufficient_fprs(float, float, float, float, float, float, float, float, i64) ++#[no_mangle] ++pub extern "C" fn f_struct_float_int8_insufficient_fprs( ++ a: f32, ++ b: f32, ++ c: f32, ++ d: f32, ++ e: f32, ++ f: f32, ++ g: f32, ++ h: f32, ++ i: FloatInt8, ++) { ++} ++ ++#[repr(C)] ++pub struct FloatArr1 { ++ a: [f32; 1], ++} ++ ++// CHECK: define void @f_floatarr1_s_arg(float) ++#[no_mangle] ++pub extern "C" fn f_floatarr1_s_arg(a: FloatArr1) {} ++ ++// CHECK: define float @f_ret_floatarr1_s() ++#[no_mangle] ++pub extern "C" fn f_ret_floatarr1_s() -> FloatArr1 { ++ FloatArr1 { a: [1.] } ++} ++ ++#[repr(C)] ++pub struct FloatArr2 { ++ a: [f32; 2], ++} ++ ++// CHECK: define void @f_floatarr2_s_arg({ float, float }) ++#[no_mangle] ++pub extern "C" fn f_floatarr2_s_arg(a: FloatArr2) {} ++ ++// CHECK: define { float, float } @f_ret_floatarr2_s() ++#[no_mangle] ++pub extern "C" fn f_ret_floatarr2_s() -> FloatArr2 { ++ FloatArr2 { a: [1., 2.] } ++} ++ ++#[repr(C)] ++pub struct Tricky1 { ++ f: [f32; 1], ++} ++ ++#[repr(C)] ++pub struct FloatArr2Tricky1 { ++ g: [Tricky1; 2], ++} ++ ++// CHECK: define void @f_floatarr2_tricky1_s_arg({ float, float }) ++#[no_mangle] ++pub extern "C" fn f_floatarr2_tricky1_s_arg(a: FloatArr2Tricky1) {} ++ ++// CHECK: define { float, float } @f_ret_floatarr2_tricky1_s() ++#[no_mangle] ++pub extern "C" fn f_ret_floatarr2_tricky1_s() -> FloatArr2Tricky1 { ++ FloatArr2Tricky1 { g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } ++} ++ ++#[repr(C)] ++pub struct EmptyStruct {} ++ ++#[repr(C)] ++pub struct FloatArr2Tricky2 { ++ s: EmptyStruct, ++ g: [Tricky1; 2], ++} ++ ++// CHECK: define void @f_floatarr2_tricky2_s_arg({ float, float }) ++#[no_mangle] ++pub extern "C" fn f_floatarr2_tricky2_s_arg(a: FloatArr2Tricky2) {} ++ ++// CHECK: define { float, float } @f_ret_floatarr2_tricky2_s() ++#[no_mangle] ++pub extern "C" fn f_ret_floatarr2_tricky2_s() -> FloatArr2Tricky2 { ++ FloatArr2Tricky2 { s: EmptyStruct {}, g: [Tricky1 { f: [1.] }, Tricky1 { f: [2.] }] } ++} ++ ++#[repr(C)] ++pub struct IntFloatInt { ++ a: i32, ++ b: f32, ++ c: i32, ++} ++ ++// CHECK: define void @f_int_float_int_s_arg([2 x i64]) ++#[no_mangle] ++pub extern "C" fn f_int_float_int_s_arg(a: IntFloatInt) {} ++ ++// CHECK: define [2 x i64] @f_ret_int_float_int_s() ++#[no_mangle] ++pub extern "C" fn f_ret_int_float_int_s() -> IntFloatInt { ++ IntFloatInt { a: 1, b: 2., c: 3 } ++} ++ ++#[repr(C)] ++pub struct CharCharFloat { ++ a: u8, ++ b: u8, ++ c: f32, ++} ++ ++// CHECK: define void @f_char_char_float_s_arg(i64) ++#[no_mangle] ++pub extern "C" fn f_char_char_float_s_arg(a: CharCharFloat) {} ++ ++// CHECK: define i64 @f_ret_char_char_float_s() ++#[no_mangle] ++pub extern "C" fn f_ret_char_char_float_s() -> CharCharFloat { ++ CharCharFloat { a: 1, b: 2, c: 3. } ++} ++ ++#[repr(C)] ++pub union FloatU { ++ a: f32, ++} ++ ++// CHECK: define void @f_float_u_arg(i64) ++#[no_mangle] ++pub extern "C" fn f_float_u_arg(a: FloatU) {} ++ ++// CHECK: define i64 @f_ret_float_u() ++#[no_mangle] ++pub extern "C" fn f_ret_float_u() -> FloatU { ++ unsafe { FloatU { a: 1. } } ++} +diff --git a/src/test/ui/abi/struct-enums/struct-return.rs b/src/test/ui/abi/struct-enums/struct-return.rs +index 5930fc4acbbe..a3e70bbdb080 100644 +--- a/src/test/ui/abi/struct-enums/struct-return.rs ++++ b/src/test/ui/abi/struct-enums/struct-return.rs +@@ -10,13 +10,23 @@ pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + #[derive(Copy, Clone)] + pub struct Floats { a: f64, b: u8, c: f64 } + ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct CharCharDouble { a: u8, b: u8, c: f64 } ++ ++#[repr(C)] ++#[derive(Copy, Clone)] ++pub struct CharCharFloat { a: u8, b: u8, c: f32 } ++ + mod rustrt { +- use super::{Floats, Quad}; ++ use super::{Floats, Quad, CharCharDouble, CharCharFloat}; + + #[link(name = "rust_test_helpers", kind = "static")] + extern { + pub fn rust_dbg_abi_1(q: Quad) -> Quad; + pub fn rust_dbg_abi_2(f: Floats) -> Floats; ++ pub fn rust_dbg_abi_3(a: CharCharDouble) -> CharCharDouble; ++ pub fn rust_dbg_abi_4(a: CharCharFloat) -> CharCharFloat; + } + } + +@@ -58,7 +68,47 @@ fn test2() { + fn test2() { + } + ++#[cfg(target_pointer_width = "64")] ++fn test3() { ++ unsafe { ++ let a = CharCharDouble { ++ a: 1, ++ b: 2, ++ c: 3., ++ }; ++ let b = rustrt::rust_dbg_abi_3(a); ++ println!("a: {}", b.a); ++ println!("b: {}", b.b); ++ println!("c: {}", b.c); ++ assert_eq!(b.a, a.a + 1); ++ assert_eq!(b.b, a.b - 1); ++ assert_eq!(b.c, a.c + 1.0); ++ } ++} ++ ++#[cfg(target_pointer_width = "32")] ++fn test3() {} ++ ++fn test4() { ++ unsafe { ++ let a = CharCharFloat { ++ a: 1, ++ b: 2, ++ c: 3., ++ }; ++ let b = rustrt::rust_dbg_abi_4(a); ++ println!("a: {}", b.a); ++ println!("b: {}", b.b); ++ println!("c: {}", b.c); ++ assert_eq!(b.a, a.a + 1); ++ assert_eq!(b.b, a.b - 1); ++ assert_eq!(b.c, a.c + 1.0); ++ } ++} ++ + pub fn main() { + test1(); + test2(); ++ test3(); ++ test4(); + } diff -Nru rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-compiletest.patch rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-compiletest.patch --- rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-compiletest.patch 1970-01-01 00:00:00.000000000 +0000 +++ rustc-1.41.0+dfsg1+llvm/debian/patches/u-riscv64-compiletest.patch 2020-04-08 00:12:30.000000000 +0000 @@ -0,0 +1,10 @@ +--- a/src/tools/compiletest/src/util.rs ++++ b/src/tools/compiletest/src/util.rs +@@ -67,6 +67,7 @@ + ("powerpc", "powerpc"), + ("powerpc64", "powerpc64"), + ("powerpc64le", "powerpc64"), ++ ("riscv64gc", "riscv64"), + ("s390x", "s390x"), + ("sparc", "sparc"), + ("sparc64", "sparc64"),