From 256422d6f40897e703eb6e73a287aac337f808c2 Mon Sep 17 00:00:00 2001 From: herengui Date: Wed, 30 Aug 2023 17:04:06 +0800 Subject: [PATCH 1000/1001] add loongarch support upstream modified Signed-off-by: herengui --- CMakeLists.txt | 1 + cmake/config-ix.cmake | 2 + cmake/config.guess | 3 + include/llvm/ADT/Triple.h | 18 ++ include/llvm/BinaryFormat/ELF.h | 24 ++ include/llvm/Demangle/ItaniumDemangle.h | 2 +- .../llvm/ExecutionEngine/Orc/OrcABISupport.h | 37 +++ .../Orc/OrcRemoteTargetClient.h | 4 +- include/llvm/IR/CMakeLists.txt | 1 + include/llvm/IR/InlineAsm.h | 1 + include/llvm/IR/Intrinsics.td | 1 + include/llvm/Object/ELFObjectFile.h | 13 + include/llvm/Support/Base64.h | 1 + include/llvm/Support/Signals.h | 1 + include/llvm/module.modulemap | 1 + lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 8 + lib/CodeGen/XRayInstrumentation.cpp | 2 + lib/ExecutionEngine/Orc/IndirectionUtils.cpp | 5 + lib/ExecutionEngine/Orc/LazyReexports.cpp | 4 + lib/ExecutionEngine/Orc/OrcABISupport.cpp | 201 ++++++++++++ .../RuntimeDyld/RuntimeDyldELF.cpp | 296 ++++++++++++++++++ .../RuntimeDyld/RuntimeDyldELF.h | 8 + lib/IR/Function.cpp | 1 + lib/Object/ELF.cpp | 7 + lib/Object/RelocationResolver.cpp | 26 ++ lib/ObjectYAML/ELFYAML.cpp | 11 + lib/Support/Host.cpp | 69 ++++ lib/Support/Triple.cpp | 23 ++ .../Instrumentation/AddressSanitizer.cpp | 8 +- .../Instrumentation/DataFlowSanitizer.cpp | 38 ++- .../Instrumentation/MemorySanitizer.cpp | 130 ++++++++ lib/XRay/InstrumentationMap.cpp | 1 + .../X86/MachO_GOTAndStubsOptimization.s | 1 + .../MCJIT/2003-01-04-ArgumentBug.ll | 2 + test/ExecutionEngine/MCJIT/lit.local.cfg | 5 +- test/ExecutionEngine/MCJIT/pr13727.ll | 2 + .../remote/test-common-symbols-remote.ll | 1 + .../MCJIT/test-common-symbols.ll | 2 + test/ExecutionEngine/frem.ll | 2 + .../DataFlowSanitizer/callback.ll | 15 +- tools/llvm-readobj/ELFDumper.cpp | 17 + tools/sancov/sancov.cpp | 2 +- utils/UpdateTestChecks/asm.py | 17 + utils/benchmark/src/cycleclock.h | 4 + utils/gn/secondary/clang/lib/Basic/BUILD.gn | 1 + utils/gn/secondary/clang/lib/Driver/BUILD.gn | 1 + .../secondary/llvm/include/llvm/IR/BUILD.gn | 11 + .../gn/secondary/llvm/lib/Target/targets.gni | 4 + 48 files changed, 1018 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ccef34..4b958a38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -296,6 +296,7 @@ set(LLVM_ALL_TARGETS BPF Hexagon Lanai + LoongArch Mips MSP430 NVPTX diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 818fafbc..023612f3 100644 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -449,6 +449,8 @@ elseif (LLVM_NATIVE_ARCH MATCHES "riscv32") set(LLVM_NATIVE_ARCH RISCV) elseif (LLVM_NATIVE_ARCH MATCHES "riscv64") set(LLVM_NATIVE_ARCH RISCV) +elseif (LLVM_NATIVE_ARCH MATCHES "loongarch") + set(LLVM_NATIVE_ARCH LoongArch) else () message(FATAL_ERROR "Unknown architecture ${LLVM_NATIVE_ARCH}") endif () diff --git a/cmake/config.guess b/cmake/config.guess index 60d3f588..255257d4 100644 --- a/cmake/config.guess +++ b/cmake/config.guess @@ -1021,6 +1021,9 @@ EOF x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; + loongarch64:Linux:*:*) + echo loongarch64-unknown-linux-gnu + exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index eed315c9..35bc8ef4 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -58,6 +58,8 @@ public: bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian) csky, // CSKY: csky hexagon, // Hexagon: hexagon + loongarch32, // LoongArch (32-bit): loongarch32 + loongarch64, // LoongArch (64-bit): loongarch64 mips, // MIPS: mips, mipsallegrex, mipsr6 mipsel, // MIPSEL: mipsel, mipsallegrexe, mipsr6el mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6 @@ -211,6 +213,7 @@ public: GNUX32, GNUILP32, CODE16, + GNUABILPX32, EABI, EABIHF, Android, @@ -750,6 +753,21 @@ public: return isMIPS32() || isMIPS64(); } + /// Tests whether the target is LoongArch 32-bit + bool isLoongArch32() const { + return getArch() == Triple::loongarch32; + } + + /// Tests whether the target is LoongArch 64-bit. + bool isLoongArch64() const { + return getArch() == Triple::loongarch64; + } + + /// Tests whether the target is LoongArch (32- or 64-bit). + bool isLoongArch() const { + return isLoongArch32() || isLoongArch64(); + } + /// Tests whether the target is PowerPC (32- or 64-bit LE or BE). bool isPPC() const { return getArch() == Triple::ppc || getArch() == Triple::ppc64 || diff --git a/include/llvm/BinaryFormat/ELF.h b/include/llvm/BinaryFormat/ELF.h index 1552303b..e27c48bb 100644 --- a/include/llvm/BinaryFormat/ELF.h +++ b/include/llvm/BinaryFormat/ELF.h @@ -317,6 +317,7 @@ enum { EM_BPF = 247, // Linux kernel bpf virtual machine EM_VE = 251, // NEC SX-Aurora VE EM_CSKY = 252, // C-SKY 32-bit processor + EM_LOONGARCH = 258, // LoongArch processor }; // Object file classes. @@ -649,6 +650,29 @@ enum { #include "ELFRelocs/RISCV.def" }; +// LoongArch Specific e_flags +enum : unsigned { + // Definitions from LoongArch ELF psABI v2.01. + // Reference: https://github.com/loongson/LoongArch-Documentation + // (commit hash 296de4def055c871809068e0816325a4ac04eb12) + + // Base ABI Modifiers + EF_LOONGARCH_ABI_SOFT_FLOAT = 0x1, + EF_LOONGARCH_ABI_SINGLE_FLOAT = 0x2, + EF_LOONGARCH_ABI_DOUBLE_FLOAT = 0x3, + EF_LOONGARCH_ABI_MODIFIER_MASK = 0x7, + + // Object file ABI versions + EF_LOONGARCH_OBJABI_V0 = 0x0, + EF_LOONGARCH_OBJABI_V1 = 0x40, + EF_LOONGARCH_OBJABI_MASK = 0xC0, +}; + +// ELF Relocation types for LoongArch +enum { +#include "ELFRelocs/LoongArch.def" +}; + // ELF Relocation types for S390/zSeries enum { #include "ELFRelocs/SystemZ.def" diff --git a/include/llvm/Demangle/ItaniumDemangle.h b/include/llvm/Demangle/ItaniumDemangle.h index e5fca98f..afdfca0f 100644 --- a/include/llvm/Demangle/ItaniumDemangle.h +++ b/include/llvm/Demangle/ItaniumDemangle.h @@ -5322,7 +5322,7 @@ template <> struct FloatData { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) + defined(__wasm__) || defined(__loongarch__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; diff --git a/include/llvm/ExecutionEngine/Orc/OrcABISupport.h b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h index 5061c15c..b6914a07 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcABISupport.h +++ b/include/llvm/ExecutionEngine/Orc/OrcABISupport.h @@ -331,6 +331,43 @@ public: JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); }; +// @brief LoongArch64 support. +class OrcLoongArch64 { +public: + static constexpr unsigned PointerSize = 8; + static constexpr unsigned TrampolineSize = 40; + static constexpr unsigned StubSize = 32; + static constexpr unsigned StubToPointerMaxDisplacement = 1 << 31; + static constexpr unsigned ResolverCodeSize = 0x120; + + /// Write the resolver code into the given memory. The user is + /// responsible for allocating the memory and setting permissions. + /// + /// ReentryFnAddr should be the address of a function whose signature matches + /// void* (*)(void *TrampolineAddr, void *ReentryCtxAddr). The ReentryCtxAddr + /// argument of writeResolverCode will be passed as the second argument to + /// the function at ReentryFnAddr. + static void writeResolverCode(char *ResolverWorkingMem, + JITTargetAddress ResolverTargetAddress, + JITTargetAddress ReentryFnAddr, + JITTargetAddress ReentryCtxAddr); + + /// Write the requested number of trampolines into the given memory, + /// which must be big enough to hold 1 pointer, plus NumTrampolines + /// trampolines. + static void writeTrampolines(char *TrampolineBlockWorkingMem, + JITTargetAddress TrampolineBlockTargetAddress, + JITTargetAddress ResolverFnAddr, + unsigned NumTrampolines); + /// Write NumStubs indirect stubs to working memory at StubsBlockWorkingMem. + /// Stubs will be written as if linked at StubsBlockTargetAddress, with the + /// Nth stub using the Nth pointer in memory starting at + /// PointersBlockTargetAddress. + static void writeIndirectStubsBlock( + char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, + JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs); +}; + } // end namespace orc } // end namespace llvm diff --git a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h index 3d139740..17d55a9a 100644 --- a/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -289,8 +289,8 @@ public: bool copyAndProtect(const std::vector &Allocs, JITTargetAddress RemoteSegmentAddr, unsigned Permissions) { - if (RemoteSegmentAddr) { - assert(!Allocs.empty() && "No sections in allocated segment"); + if (RemoteSegmentAddr && !Allocs.empty()) { + // assert(!Allocs.empty() && "No sections in allocated segment"); for (auto &Alloc : Allocs) { LLVM_DEBUG(dbgs() << " copying section: " diff --git a/include/llvm/IR/CMakeLists.txt b/include/llvm/IR/CMakeLists.txt index 0498fc26..b675a45d 100644 --- a/include/llvm/IR/CMakeLists.txt +++ b/include/llvm/IR/CMakeLists.txt @@ -9,6 +9,7 @@ tablegen(LLVM IntrinsicsAMDGPU.h -gen-intrinsic-enums -intrinsic-prefix=amdgcn) tablegen(LLVM IntrinsicsARM.h -gen-intrinsic-enums -intrinsic-prefix=arm) tablegen(LLVM IntrinsicsBPF.h -gen-intrinsic-enums -intrinsic-prefix=bpf) tablegen(LLVM IntrinsicsHexagon.h -gen-intrinsic-enums -intrinsic-prefix=hexagon) +tablegen(LLVM IntrinsicsLoongArch.h -gen-intrinsic-enums -intrinsic-prefix=loongarch) tablegen(LLVM IntrinsicsMips.h -gen-intrinsic-enums -intrinsic-prefix=mips) tablegen(LLVM IntrinsicsNVPTX.h -gen-intrinsic-enums -intrinsic-prefix=nvvm) tablegen(LLVM IntrinsicsPowerPC.h -gen-intrinsic-enums -intrinsic-prefix=ppc) diff --git a/include/llvm/IR/InlineAsm.h b/include/llvm/IR/InlineAsm.h index b6f37709..427cb3ed 100644 --- a/include/llvm/IR/InlineAsm.h +++ b/include/llvm/IR/InlineAsm.h @@ -259,6 +259,7 @@ public: Constraint_Uy, Constraint_X, Constraint_Z, + Constraint_ZB, Constraint_ZC, Constraint_Zy, Constraints_Max = Constraint_Zy, diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index 21307ed1..320e6c78 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -1664,3 +1664,4 @@ include "llvm/IR/IntrinsicsSystemZ.td" include "llvm/IR/IntrinsicsWebAssembly.td" include "llvm/IR/IntrinsicsRISCV.td" include "llvm/IR/IntrinsicsVE.td" +include "llvm/IR/IntrinsicsLoongArch.td" diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index fed53eef..dd3f6abc 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -1165,6 +1165,8 @@ StringRef ELFObjectFile::getFileFormatName() const { return "elf32-littleriscv"; case ELF::EM_CSKY: return "elf32-csky"; + case ELF::EM_LOONGARCH: + return "elf32-loongarch"; case ELF::EM_SPARC: case ELF::EM_SPARC32PLUS: return "elf32-sparc"; @@ -1189,6 +1191,8 @@ StringRef ELFObjectFile::getFileFormatName() const { return "elf64-s390"; case ELF::EM_SPARCV9: return "elf64-sparc"; + case ELF::EM_LOONGARCH: + return "elf64-loongarch"; case ELF::EM_MIPS: return "elf64-mips"; case ELF::EM_AMDGPU: @@ -1248,6 +1252,15 @@ template Triple::ArchType ELFObjectFile::getArch() const { default: report_fatal_error("Invalid ELFCLASS!"); } + case ELF::EM_LOONGARCH: + switch (EF.getHeader().e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + return Triple::loongarch32; + case ELF::ELFCLASS64: + return Triple::loongarch64; + default: + report_fatal_error("Invalid ELFCLASS!"); + } case ELF::EM_S390: return Triple::systemz; diff --git a/include/llvm/Support/Base64.h b/include/llvm/Support/Base64.h index 62064a35..da4ae168 100644 --- a/include/llvm/Support/Base64.h +++ b/include/llvm/Support/Base64.h @@ -13,6 +13,7 @@ #ifndef LLVM_SUPPORT_BASE64_H #define LLVM_SUPPORT_BASE64_H +#include #include namespace llvm { diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h index 44f5a750..937e0572 100644 --- a/include/llvm/Support/Signals.h +++ b/include/llvm/Support/Signals.h @@ -14,6 +14,7 @@ #ifndef LLVM_SUPPORT_SIGNALS_H #define LLVM_SUPPORT_SIGNALS_H +#include #include namespace llvm { diff --git a/include/llvm/module.modulemap b/include/llvm/module.modulemap index a199f7f2..6b788404 100644 --- a/include/llvm/module.modulemap +++ b/include/llvm/module.modulemap @@ -70,6 +70,7 @@ module LLVM_BinaryFormat { textual header "BinaryFormat/ELFRelocs/Hexagon.def" textual header "BinaryFormat/ELFRelocs/i386.def" textual header "BinaryFormat/ELFRelocs/Lanai.def" + textual header "BinaryFormat/ELFRelocs/LoongArch.def" textual header "BinaryFormat/ELFRelocs/Mips.def" textual header "BinaryFormat/ELFRelocs/MSP430.def" textual header "BinaryFormat/ELFRelocs/PowerPC64.def" diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index fe64b38c..4bd3a8e6 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -206,6 +206,14 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, PersonalityEncoding = dwarf::DW_EH_PE_absptr; TTypeEncoding = dwarf::DW_EH_PE_absptr; break; + case Triple::loongarch32: + case Triple::loongarch64: + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + break; case Triple::mips: case Triple::mipsel: case Triple::mips64: diff --git a/lib/CodeGen/XRayInstrumentation.cpp b/lib/CodeGen/XRayInstrumentation.cpp index 11d1b309..1655cac5 100644 --- a/lib/CodeGen/XRayInstrumentation.cpp +++ b/lib/CodeGen/XRayInstrumentation.cpp @@ -226,6 +226,8 @@ bool XRayInstrumentation::runOnMachineFunction(MachineFunction &MF) { case Triple::ArchType::arm: case Triple::ArchType::thumb: case Triple::ArchType::aarch64: + case Triple::ArchType::loongarch32: + case Triple::ArchType::loongarch64: case Triple::ArchType::mips: case Triple::ArchType::mipsel: case Triple::ArchType::mips64: diff --git a/lib/ExecutionEngine/Orc/IndirectionUtils.cpp b/lib/ExecutionEngine/Orc/IndirectionUtils.cpp index 1cfcf8ae..c3166162 100644 --- a/lib/ExecutionEngine/Orc/IndirectionUtils.cpp +++ b/lib/ExecutionEngine/Orc/IndirectionUtils.cpp @@ -147,6 +147,11 @@ createLocalCompileCallbackManager(const Triple &T, ExecutionSession &ES, return CCMgrT::Create(ES, ErrorHandlerAddress); } + case Triple::loongarch64: { + typedef orc::LocalJITCompileCallbackManager CCMgrT; + return CCMgrT::Create(ES, ErrorHandlerAddress); + } + case Triple::x86_64: { if (T.getOS() == Triple::OSType::Win32) { typedef orc::LocalJITCompileCallbackManager CCMgrT; diff --git a/lib/ExecutionEngine/Orc/LazyReexports.cpp b/lib/ExecutionEngine/Orc/LazyReexports.cpp index e1f49441..4dba00f1 100644 --- a/lib/ExecutionEngine/Orc/LazyReexports.cpp +++ b/lib/ExecutionEngine/Orc/LazyReexports.cpp @@ -131,6 +131,10 @@ createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, case Triple::mips64el: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); + case Triple::loongarch64: + return LocalLazyCallThroughManager::Create( + ES, ErrorHandlerAddr); + case Triple::x86_64: if (T.getOS() == Triple::OSType::Win32) return LocalLazyCallThroughManager::Create( diff --git a/lib/ExecutionEngine/Orc/OrcABISupport.cpp b/lib/ExecutionEngine/Orc/OrcABISupport.cpp index 18b3c5e1..440831d7 100644 --- a/lib/ExecutionEngine/Orc/OrcABISupport.cpp +++ b/lib/ExecutionEngine/Orc/OrcABISupport.cpp @@ -906,5 +906,206 @@ void OrcMips64::writeIndirectStubsBlock( Stub[8 * I + 7] = 0x00000000; // nop } } + +void OrcLoongArch64::writeResolverCode(char *ResolverWorkingMem, + JITTargetAddress ResolverTargetAddress, + JITTargetAddress ReentryFnAddr, + JITTargetAddress ReentryCtxAddr) { + + const uint32_t ResolverCode[] = { + // resolver_entry: + 0x02fc8063, // 0x0: addi.d $r3,$r3,-224(0xf20) + 0x29c00064, // 0x4: st.d $r4,$r3,0 + 0x29c02065, // 0x8: st.d $r5,$r3,8(0x8) + 0x29c04066, // 0xc: st.d $r6,$r3,16(0x10) + 0x29c06067, // 0x10: st.d $r7,$r3,24(0x18) + 0x29c08068, // 0x14: st.d $r8,$r3,32(0x20) + 0x29c0a069, // 0x18: st.d $r9,$r3,40(0x28) + 0x29c0c06a, // 0x1c: st.d $r10,$r3,48(0x30) + 0x29c0e06b, // 0x20: st.d $r11,$r3,56(0x38) + 0x29c1006c, // 0x24: st.d $r12,$r3,64(0x40) + 0x29c1206d, // 0x28: st.d $r13,$r3,72(0x48) + 0x29c1406e, // 0x2c: st.d $r14,$r3,80(0x50) + 0x29c1606f, // 0x30: st.d $r15,$r3,88(0x58) + 0x29c18070, // 0x34: st.d $r16,$r3,96(0x60) + 0x29c1a071, // 0x38: st.d $r17,$r3,104(0x68) + 0x29c1c072, // 0x3c: st.d $r18,$r3,112(0x70) + 0x29c1e073, // 0x40: st.d $r19,$r3,120(0x78) + 0x29c20074, // 0x44: st.d $r20,$r3,128(0x80) + 0x29c22076, // 0x48: st.d $r22,$r3,136(0x88) + 0x29c24077, // 0x4c: st.d $r23,$r3,144(0x90) + 0x29c26078, // 0x50: st.d $r24,$r3,152(0x98) + 0x29c28079, // 0x54: st.d $r25,$r3,160(0xa0) + 0x29c2a07a, // 0x58: st.d $r26,$r3,168(0xa8) + 0x29c2c07b, // 0x5c: st.d $r27,$r3,176(0xb0) + 0x29c2e07c, // 0x60: st.d $r28,$r3,184(0xb8) + 0x29c3007d, // 0x64: st.d $r29,$r3,192(0xc0) + 0x29c3207e, // 0x68: st.d $r30,$r3,200(0xc8) + 0x29c3407f, // 0x6c: st.d $r31,$r3,208(0xd0) + 0x29c36061, // 0x70: st.d $r1,$r3,216(0xd8) + // JIT re-entry ctx addr. + 0x00000000, // 0x74: lu12i.w $a0,hi(ctx) + 0x00000000, // 0x78: ori $a0,$a0,lo(ctx) + 0x00000000, // 0x7c: lu32i.d $a0,higher(ctx) + 0x00000000, // 0x80: lu52i.d $a0,$a0,highest(ctx) + + 0x00150025, // 0x84: move $r5,$r1 + 0x02ffa0a5, // 0x88: addi.d $r5,$r5,-24(0xfe8) + + // JIT re-entry fn addr: + 0x00000000, // 0x8c: lu12i.w $t0,hi(reentry) + 0x00000000, // 0x90: ori $t0,$t0,lo(reentry) + 0x00000000, // 0x94: lu32i.d $t0,higher(reentry) + 0x00000000, // 0x98: lu52i.d $t0,$t0,highest(reentry) + 0x4c0002a1, // 0x9c: jirl $r1,$r21,0 + 0x00150095, // 0xa0: move $r21,$r4 + 0x28c36061, // 0xa4: ld.d $r1,$r3,216(0xd8) + 0x28c3407f, // 0xa8: ld.d $r31,$r3,208(0xd0) + 0x28c3207e, // 0xac: ld.d $r30,$r3,200(0xc8) + 0x28c3007d, // 0xb0: ld.d $r29,$r3,192(0xc0) + 0x28c2e07c, // 0xb4: ld.d $r28,$r3,184(0xb8) + 0x28c2c07b, // 0xb8: ld.d $r27,$r3,176(0xb0) + 0x28c2a07a, // 0xbc: ld.d $r26,$r3,168(0xa8) + 0x28c28079, // 0xc0: ld.d $r25,$r3,160(0xa0) + 0x28c26078, // 0xc4: ld.d $r24,$r3,152(0x98) + 0x28c24077, // 0xc8: ld.d $r23,$r3,144(0x90) + 0x28c22076, // 0xcc: ld.d $r22,$r3,136(0x88) + 0x28c20074, // 0xd0: ld.d $r20,$r3,128(0x80) + 0x28c1e073, // 0xd4: ld.d $r19,$r3,120(0x78) + 0x28c1c072, // 0xd8: ld.d $r18,$r3,112(0x70) + 0x28c1a071, // 0xdc: ld.d $r17,$r3,104(0x68) + 0x28c18070, // 0xe0: ld.d $r16,$r3,96(0x60) + 0x28c1606f, // 0xe4: ld.d $r15,$r3,88(0x58) + 0x28c1406e, // 0xe8: ld.d $r14,$r3,80(0x50) + 0x28c1206d, // 0xec: ld.d $r13,$r3,72(0x48) + 0x28c1006c, // 0xf0: ld.d $r12,$r3,64(0x40) + 0x28c0e06b, // 0xf4: ld.d $r11,$r3,56(0x38) + 0x28c0c06a, // 0xf8: ld.d $r10,$r3,48(0x30) + 0x28c0a069, // 0xfc: ld.d $r9,$r3,40(0x28) + 0x28c08068, // 0x100: ld.d $r8,$r3,32(0x20) + 0x28c06067, // 0x104: ld.d $r7,$r3,24(0x18) + 0x28c04066, // 0x108: ld.d $r6,$r3,16(0x10) + 0x28c02065, // 0x10c: ld.d $r5,$r3,8(0x8) + 0x28c00064, // 0x110: ld.d $r4,$r3,0 + 0x02c38063, // 0x114: addi.d $r3,$r3,224(0xe0) + 0x00150281, // 0x118: move $r1,$r20 + 0x4c0002a0, // 0x11c: jirl $r0,$r21,0 + }; + + const unsigned ReentryFnAddrOffset = 0x8c; // JIT re-entry fn addr lu12i.w + const unsigned ReentryCtxAddrOffset = 0x74; // JIT re-entry ctx addr lu12i.w + + memcpy(ResolverWorkingMem, ResolverCode, sizeof(ResolverCode)); + + uint32_t ReentryCtxLU12i = 0x14000004 | ((ReentryCtxAddr << 32 >> 44) << 5); + uint32_t ReentryCtxORi = 0x03800084 | ((ReentryCtxAddr & 0xFFF) << 10); + uint32_t ReentryCtxLU32i = 0x16000004 | ((ReentryCtxAddr << 12 >> 44) << 5); + uint32_t ReentryCtxLU52i = 0x03000084 | ((ReentryCtxAddr >> 52) << 10); + + memcpy(ResolverWorkingMem + ReentryCtxAddrOffset, &ReentryCtxLU12i, + sizeof(ReentryCtxLU12i)); + memcpy(ResolverWorkingMem + (ReentryCtxAddrOffset + 4), &ReentryCtxORi, + sizeof(ReentryCtxORi)); + memcpy(ResolverWorkingMem + (ReentryCtxAddrOffset + 8), &ReentryCtxLU32i, + sizeof(ReentryCtxLU32i)); + memcpy(ResolverWorkingMem + (ReentryCtxAddrOffset + 12), &ReentryCtxLU52i, + sizeof(ReentryCtxLU52i)); + + uint32_t ReentryLU12i = 0x14000015 | ((ReentryFnAddr << 32 >> 44) << 5); + uint32_t ReentryORi = 0x038002b5 | ((ReentryFnAddr & 0xFFF) << 10); + uint32_t ReentryLU32i = 0x16000015 | ((ReentryFnAddr << 12 >> 44) << 5); + uint32_t ReentryLU52i = 0x030002b5 | ((ReentryFnAddr >> 52) << 10); + + memcpy(ResolverWorkingMem + ReentryFnAddrOffset, &ReentryLU12i, + sizeof(ReentryLU12i)); + memcpy(ResolverWorkingMem + (ReentryFnAddrOffset + 4), &ReentryORi, + sizeof(ReentryORi)); + memcpy(ResolverWorkingMem + (ReentryFnAddrOffset + 8), &ReentryLU32i, + sizeof(ReentryLU32i)); + memcpy(ResolverWorkingMem + (ReentryFnAddrOffset + 12), &ReentryLU52i, + sizeof(ReentryLU52i)); +} + +void OrcLoongArch64::writeTrampolines( + char *TrampolineBlockWorkingMem, + JITTargetAddress TrampolineBlockTargetAddress, + JITTargetAddress ResolverFnAddr, unsigned NumTrampolines) { + + uint32_t *Trampolines = + reinterpret_cast(TrampolineBlockWorkingMem); + + uint64_t HiBits = ((ResolverFnAddr << 32 >> 44) << 5); + uint64_t LoBits = ((ResolverFnAddr & 0xFFF) << 10); + uint64_t HigherBits = ((ResolverFnAddr << 12 >> 44) << 5); + uint64_t HighestBits = ((ResolverFnAddr >> 52) << 10); + + for (unsigned I = 0; I < NumTrampolines; ++I) { + Trampolines[10 * I + 0] = 0x00150034; // move $t8,$ra + Trampolines[10 * I + 1] = + 0x14000015 | HiBits; // lu12i.w $r21,hi(ResolveAddr) + Trampolines[10 * I + 2] = + 0x038002b5 | LoBits; // ori $r21,$r21,lo(ResolveAddr) + Trampolines[10 * I + 3] = + 0x16000015 | HigherBits; // lu32i $r21,higher(ResolveAddr) + Trampolines[10 * I + 4] = + 0x030002b5 | HighestBits; // lu52i $r21,$r21,highest(ResolveAddr) + Trampolines[10 * I + 5] = 0x4c0002a1; // jirl $ra, $r21, 0 + } +} + +void OrcLoongArch64::writeIndirectStubsBlock( + char *StubsBlockWorkingMem, JITTargetAddress StubsBlockTargetAddress, + JITTargetAddress PointersBlockTargetAddress, unsigned NumStubs) { + // Stub format is: + // + // .section __orc_stubs + // stub1: + // lu12i.w $r21, %abs(ptr1)<<32>>44 + // ori $r21, $r21, %abs(ptr1)&0xfff + // lu32i.d $r21, %abs(ptr1)<<12>>44 + // lu52i.d $r21, $r21, %abs(ptr1)>>52 + // ld.d $r21, $r21, 0 + // jirl $r0, $r21, 0 + // stub2: + // lu12i.w $r21, %abs(ptr2)<<32>>44 + // ori $r21, $r21, %abs(ptr2)&0xfff + // lu32i.d $r21, %abs(ptr2)<<12>>44 + // lu52i.d $r21, $r21, %abs(ptr2)>>52 + // ld.d $r21, $r21, 0 + // jirl $r0, $r21, 0 + // + // ... + // + // .section __orc_ptrs + // ptr1: + // .dword 0x0 + // ptr2: + // .dword 0x0 + // + // ... + + assert(stubAndPointerRangesOk( + StubsBlockTargetAddress, PointersBlockTargetAddress, NumStubs) && + "PointersBlock is out of range"); + + // Populate the stubs page stubs and mark it executable. + uint32_t *Stub = reinterpret_cast(StubsBlockWorkingMem); + uint64_t PtrAddr = PointersBlockTargetAddress; + + for (unsigned I = 0; I < NumStubs; ++I, PtrAddr += 8) { + uint64_t HiBits = ((PtrAddr << 32 >> 44) << 5); + uint64_t LoBits = ((PtrAddr & 0xFFF) << 10); + uint64_t HigherBits = ((PtrAddr << 12 >> 44) << 5); + uint64_t HighestBits = ((PtrAddr >> 52) << 10); + Stub[8 * I + 0] = 0x14000015 | HiBits; // lu12i.w $r21, hi(PtrAddr) + Stub[8 * I + 1] = 0x038002b5 | LoBits; // ori $r21, $r21, lo(PtrAddr) + Stub[8 * I + 2] = 0x16000015 | HigherBits; // lu32i.d $r21, higher(PtrAddr) + Stub[8 * I + 3] = + 0x030002b5 | HighestBits; // lu52i.d $r21, $r21, highest(PtrAddr) + Stub[8 * I + 4] = 0x28c002b5; // ld.d $r21, $r21, 0 + Stub[8 * I + 5] = 0x4c0002a0; // jirl $r0, $r21, 0 + } +} + } // End namespace orc. } // End namespace llvm. diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 28e1faab..397a10e7 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -541,6 +541,266 @@ void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, } } +void RuntimeDyldELF::resolveLoongArch64Relocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, uint32_t Type, + int64_t Addend) { + uint32_t *TargetPtr = + reinterpret_cast(Section.getAddressWithOffset(Offset)); + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + uint64_t tmp1, tmp2, tmp3; + + LLVM_DEBUG(dbgs() << "[XXX] resolveLoongArch64Relocation, LocalAddress: 0x" + << format("%llx", Section.getAddressWithOffset(Offset)) + << " FinalAddress: 0x" << format("%llx", FinalAddress) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << " Addend: 0x" + << format("%llx", Addend) << "\n"); + + switch (Type) { + case ELF::R_LARCH_SOP_PUSH_GPREL: + case ELF::R_LARCH_SOP_PUSH_TLS_TPREL: + case ELF::R_LARCH_SOP_PUSH_TLS_GOT: + case ELF::R_LARCH_SOP_PUSH_TLS_GD: + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + case ELF::R_LARCH_MARK_LA: + // mark la + MarkLA = true; + break; + case ELF::R_LARCH_SOP_PUSH_ABSOLUTE: + if (MarkLA && !Addend) + // push(value) + ValuesStack.push_back(Value); + else + // push(addend) + ValuesStack.push_back(Addend); + break; + case ELF::R_LARCH_SOP_PUSH_PLT_PCREL: + case ELF::R_LARCH_SOP_PUSH_PCREL: + MarkLA = false; + // push(value -pc + addend) + ValuesStack.push_back(Value - FinalAddress + Addend); + break; + case ELF::R_LARCH_SOP_NOT: + // pop(tmp1) + // push(!tmp1) + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(!tmp1); + break; + case ELF::R_LARCH_SOP_AND: + // pop(tmp2) + // pop(tmp1) + // push(tmp1 & tmp2) + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 & tmp2); + break; + case ELF::R_LARCH_SOP_IF_ELSE: + // pop(tmp3) + // pop(tmp2) + // pop(tmp1) + // push(tmp1 ? tmp2 : tmp3) + tmp3 = ValuesStack.pop_back_val(); + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 ? tmp2 : tmp3); + break; + case ELF::R_LARCH_SOP_ADD: + // pop(tmp2) + // pop(tmp1) + // push(tmp1 + tmp2) + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 + tmp2); + break; + case ELF::R_LARCH_SOP_SUB: + // pop(tmp2) + // pop(tmp1) + // push(tmp1 - tmp2) + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 - tmp2); + break; + case ELF::R_LARCH_SOP_SR: + // pop(tmp2) + // pop(tmp1) + // push(tmp1 >> tmp2) + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 >> tmp2); + break; + case ELF::R_LARCH_SOP_SL: + // pop(tmp2) + // pop(tmp1) + // push(tmp1 << tmp2) + tmp2 = ValuesStack.pop_back_val(); + tmp1 = ValuesStack.pop_back_val(); + ValuesStack.push_back(tmp1 << tmp2); + break; + case ELF::R_LARCH_32: + support::ulittle32_t::ref{TargetPtr} = + static_cast(Value + Addend); + break; + case ELF::R_LARCH_64: + support::ulittle64_t::ref{TargetPtr} = Value + Addend; + break; + case ELF::R_LARCH_SOP_POP_32_U_10_12: + case ELF::R_LARCH_SOP_POP_32_S_10_12: + // pop(tmp1) + // get(inst) + // inst=(inst & 0xffc003ff)|((tmp1 & 0xfff) << 10) + // write(inst) + tmp1 = ValuesStack.pop_back_val(); + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xffc003ff) | + static_cast((tmp1 & 0xfff) << 10); + break; + case ELF::R_LARCH_SOP_POP_32_S_5_20: + // pop(tmp1) + // get(inst) + // inst=(inst & 0xfe00001f)|((tmp1 & 0xfffff) << 5) + // write(inst) + tmp1 = ValuesStack.pop_back_val(); + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xfe00001f) | + static_cast((tmp1 & 0xfffff) << 5); + break; + case ELF::R_LARCH_SOP_POP_32_S_10_16_S2: + // pop(tmp1) + // tmp1 >>=2 + // get(inst) + // inst=(inst & 0xfc0003ff)|((tmp1 & 0xffff) << 10) + // write(inst) + tmp1 = ValuesStack.pop_back_val(); + tmp1 >>= 2; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xfc0003ff) | + static_cast((tmp1 & 0xffff) << 10); + break; + case ELF::R_LARCH_SOP_POP_32_S_0_5_10_16_S2: + // pop(tmp1) + // tmp1 >>= 2 + // get(inst) + // inst=(inst & 0xfc0003e0)|((tmp1 & 0xffff) << 10)|((tmp1 & 0x1f0000) >> + // 16) write(inst) + tmp1 = ValuesStack.pop_back_val(); + tmp1 >>= 2; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xfc0003e0) | + static_cast((tmp1 & 0xffff) << 10) | + static_cast((tmp1 & 0x1f0000) >> 16); + break; + case ELF::R_LARCH_SOP_POP_32_S_0_10_10_16_S2: + // pop(tmp1) + // tmp1 >>= 2 + // get(inst) + // inst=(inst & 0xfc000000)|((tmp1 & 0xffff) << 10)|((tmp1 & 0x3ff0000) >> + // 16) write(inst) + tmp1 = ValuesStack.pop_back_val(); + tmp1 >>= 2; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xfc000000) | + static_cast((tmp1 & 0xffff) << 10) | + static_cast((tmp1 & 0x3ff0000) >> 16); + break; + case ELF::R_LARCH_ADD32: + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} + + static_cast(Value + Addend)); + break; + case ELF::R_LARCH_SUB32: + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} - + static_cast(Value + Addend)); + break; + case ELF::R_LARCH_ADD64: + support::ulittle64_t::ref{TargetPtr} = + (support::ulittle64_t::ref{TargetPtr} + Value + Addend); + break; + case ELF::R_LARCH_SUB64: + support::ulittle64_t::ref{TargetPtr} = + (support::ulittle64_t::ref{TargetPtr} - Value - Addend); + break; + case ELF::R_LARCH_GOT_PC_HI20: + FinalAddress &= (~0xfff); + // Addend is G(offset in got) + Value += Addend; + if ((Value & 0xfff) > 0x7ff) + Value += 0x1000; + Value &= (~0xfff); + tmp1 = Value - FinalAddress; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x1ffffe0)) | + static_cast(((tmp1 >> 12) & 0xfffff) << 5); + break; + case ELF::R_LARCH_GOT_PC_LO12: + Value += Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x3ffc00)) | + static_cast((Value & 0xfff) << 10); + break; + case ELF::R_LARCH_PCALA_HI20: + Value += Addend; + tmp1 = Value & 0xfff; + tmp2 = FinalAddress & (~0xfff); + if (tmp1 > 0x7ff) + Value += 0x1000; + Value &= ~(0xfff); + Value -= tmp2; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x1ffffe0)) | + static_cast(((Value >> 12) & 0xfffff) << 5); + break; + case ELF::R_LARCH_PCALA_LO12: + Value += Addend; + tmp1 = Value & 0xfff; + Value = (tmp1 ^ 0x800) - 0x800; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x3ffc00)) | + static_cast((Value & 0xfff) << 10); + break; + case ELF::R_LARCH_B26: + tmp1 = Value - FinalAddress + Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x03ffffff)) | + static_cast((tmp1 >> 18) & 0x03ff) | + static_cast(((tmp1 >> 2) & 0xffff) << 10); + break; + case ELF::R_LARCH_ABS_HI20: + Value += Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x1ffffe0)) | + static_cast(((Value >> 12) & 0xfffff) << 5); + break; + case ELF::R_LARCH_ABS_LO12: + Value += Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x3ffc00)) | + static_cast((Value & 0xfff) << 10); + break; + case ELF::R_LARCH_ABS64_HI12: + Value += Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x3ffc00)) | + static_cast(((Value >> 52) & 0xfff) << 10); + break; + case ELF::R_LARCH_ABS64_LO20: + Value += Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0x1ffffe0)) | + static_cast(((Value >> 32) & 0xfffff) << 5); + break; + case ELF::R_LARCH_32_PCREL: + tmp1 = Value - FinalAddress + Addend; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & (~0xffffffff)) | + static_cast(tmp1 & 0xffffffff); + break; + } +} + void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) { if (Arch == Triple::UnknownArch || !StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) { @@ -954,6 +1214,9 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; + case Triple::loongarch64: + resolveLoongArch64Relocation(Section, Offset, Value, Type, Addend); + break; case Triple::ppc: // Fall through. case Triple::ppcle: resolvePPC32Relocation(Section, Offset, Value, Type, Addend); @@ -1266,6 +1529,34 @@ RuntimeDyldELF::processRelocationRef( } processSimpleRelocation(SectionID, Offset, RelType, Value); } + } else if (Arch == Triple::loongarch64) { + if (RelType == ELF::R_LARCH_GOT_PC_HI20) { + uint64_t GOTOffset = allocateGOTEntries(1); + + // Fill in the value of the symbol we're targeting into the GOT + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_LARCH_64); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_LARCH_GOT_PC_HI20); + } else if (RelType == ELF::R_LARCH_GOT_PC_LO12) { + uint64_t GOTOffset = allocateGOTEntries(1); + + // Fill in the value of the symbol we're targeting into the GOT + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_LARCH_64); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_LARCH_GOT_PC_LO12); + } else { + processSimpleRelocation(SectionID, Offset, RelType, Value); + } } else if (IsMipsO32ABI) { uint8_t *Placeholder = reinterpret_cast( computePlaceholderAddress(SectionID, Offset)); @@ -1779,6 +2070,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() { case Triple::x86_64: case Triple::aarch64: case Triple::aarch64_be: + case Triple::loongarch64: case Triple::ppc64: case Triple::ppc64le: case Triple::systemz: @@ -1929,6 +2221,10 @@ bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const { return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE || RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC; + if (Arch == Triple::loongarch64) + return RelTy == ELF::R_LARCH_GOT_PC_HI20 || + RelTy == ELF::R_LARCH_GOT_PC_LO12; + if (Arch == Triple::x86_64) return RelTy == ELF::R_X86_64_GOTPCREL || RelTy == ELF::R_X86_64_GOTPCRELX || diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 31892b74..5295853e 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -48,6 +48,10 @@ class RuntimeDyldELF : public RuntimeDyldImpl { void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend); + void resolveLoongArch64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend); + void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); @@ -155,6 +159,10 @@ private: // EH frame sections with the memory manager. SmallVector UnregisteredEHFrameSections; + // For loongarch evaluteRelocation + SmallVector ValuesStack; + bool MarkLA; + // Map between GOT relocation value and corresponding GOT offset std::map GOTOffsetMap; diff --git a/lib/IR/Function.cpp b/lib/IR/Function.cpp index 17247123..e74c6b6a 100644 --- a/lib/IR/Function.cpp +++ b/lib/IR/Function.cpp @@ -37,6 +37,7 @@ #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/IntrinsicsBPF.h" #include "llvm/IR/IntrinsicsHexagon.h" +#include "llvm/IR/IntrinsicsLoongArch.h" #include "llvm/IR/IntrinsicsMips.h" #include "llvm/IR/IntrinsicsNVPTX.h" #include "llvm/IR/IntrinsicsPowerPC.h" diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index 264f115d..21c820fd 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -87,6 +87,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_LOONGARCH: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" + default: + break; + } + break; case ELF::EM_PPC: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/PowerPC.def" diff --git a/lib/Object/RelocationResolver.cpp b/lib/Object/RelocationResolver.cpp index 204577af..5496db46 100644 --- a/lib/Object/RelocationResolver.cpp +++ b/lib/Object/RelocationResolver.cpp @@ -463,6 +463,28 @@ static uint64_t resolveRISCV(uint64_t Type, uint64_t Offset, uint64_t S, } } +static bool supportsLoongArch(uint64_t Type) { + switch (Type) { + case ELF::R_LARCH_32: + case ELF::R_LARCH_64: + return true; + default: + return false; + } +} + +static uint64_t resolveLoongArch(uint64_t Type, uint64_t Offset, uint64_t S, + uint64_t LocData, int64_t Addend) { + switch (Type) { + case ELF::R_LARCH_32: + return (S + Addend) & 0xFFFFFFFF; + case ELF::R_LARCH_64: + return S + Addend; + default: + llvm_unreachable("Invalid relocation type"); + } +} + static bool supportsCOFFX86(uint64_t Type) { switch (Type) { case COFF::IMAGE_REL_I386_SECREL: @@ -675,6 +697,8 @@ getRelocationResolver(const ObjectFile &Obj) { return {supportsAmdgpu, resolveAmdgpu}; case Triple::riscv64: return {supportsRISCV, resolveRISCV}; + case Triple::loongarch64: + return {supportsLoongArch, resolveLoongArch}; default: return {nullptr, nullptr}; } @@ -708,6 +732,8 @@ getRelocationResolver(const ObjectFile &Obj) { return {supportsHexagon, resolveHexagon}; case Triple::riscv32: return {supportsRISCV, resolveRISCV}; + case Triple::loongarch32: + return {supportsLoongArch, resolveLoongArch}; default: return {nullptr, nullptr}; } diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp index 05d30577..dac60766 100644 --- a/lib/ObjectYAML/ELFYAML.cpp +++ b/lib/ObjectYAML/ELFYAML.cpp @@ -234,6 +234,7 @@ void ScalarEnumerationTraits::enumeration( ECase(EM_BPF); ECase(EM_VE); ECase(EM_CSKY); + ECase(EM_LOONGARCH); #undef ECase IO.enumFallback(Value); } @@ -452,6 +453,13 @@ void ScalarBitSetTraits::bitset(IO &IO, BCase(EF_AMDGPU_XNACK); BCase(EF_AMDGPU_SRAM_ECC); break; + case ELF::EM_LOONGARCH: + BCaseMask(EF_LOONGARCH_ABI_SOFT_FLOAT, EF_LOONGARCH_ABI_MODIFIER_MASK); + BCaseMask(EF_LOONGARCH_ABI_SINGLE_FLOAT, EF_LOONGARCH_ABI_MODIFIER_MASK); + BCaseMask(EF_LOONGARCH_ABI_DOUBLE_FLOAT, EF_LOONGARCH_ABI_MODIFIER_MASK); + BCaseMask(EF_LOONGARCH_OBJABI_V0, EF_LOONGARCH_OBJABI_MASK); + BCaseMask(EF_LOONGARCH_OBJABI_V1, EF_LOONGARCH_OBJABI_MASK); + break; default: break; } @@ -691,6 +699,9 @@ void ScalarEnumerationTraits::enumeration( case ELF::EM_PPC64: #include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def" break; + case ELF::EM_LOONGARCH: +#include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" + break; default: // Nothing to do. break; diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp index 09146c47..64246c65 100644 --- a/lib/Support/Host.cpp +++ b/lib/Support/Host.cpp @@ -1219,6 +1219,45 @@ StringRef sys::getHostCPUName() { StringRef Content = P ? P->getBuffer() : ""; return detail::getHostCPUNameForS390x(Content); } +#elif defined(__linux__) && defined(__loongarch__) +// loongarch prid register +// +----------------+----------------+----------------+----------------+ +// | Company Options| Company ID | Processor ID | Revision | +// +----------------+----------------+----------------+----------------+ +// 31 24 23 16 15 8 7 0 + +#define PRID_OPT_MASK 0xff000000 +#define PRID_COMP_MASK 0xff0000 +#define PRID_COMP_LOONGSON 0x140000 +#define PRID_IMP_MASK 0xff00 + +#define PRID_IMP_LOONGSON_32 0x4200 /* Loongson 32bit */ +#define PRID_IMP_LOONGSON_64R 0x6100 /* Reduced Loongson 64bit */ +#define PRID_IMP_LOONGSON_64C 0x6300 /* Classic Loongson 64bit */ +#define PRID_IMP_LOONGSON_64G 0xc000 /* Generic Loongson 64bit */ + +StringRef sys::getHostCPUName() { + // use prid to detect cpu name + unsigned CPUCFG_NUM = 0; // prid + unsigned prid; + + __asm__("cpucfg %[prid], %[CPUCFG_NUM]\n\t" + :[prid]"=r"(prid) + :[CPUCFG_NUM]"r"(CPUCFG_NUM)); + + if ((prid & PRID_COMP_MASK) == PRID_COMP_LOONGSON) {// for Loongson + switch (prid & PRID_IMP_MASK) { + case PRID_IMP_LOONGSON_32: // not support + return "generic-la32"; + case PRID_IMP_LOONGSON_64R: + case PRID_IMP_LOONGSON_64C: + case PRID_IMP_LOONGSON_64G: + return "la464"; + } + } + + return "generic"; +} #elif defined(__APPLE__) && defined(__aarch64__) StringRef sys::getHostCPUName() { return "cyclone"; @@ -1629,6 +1668,36 @@ bool sys::getHostCPUFeatures(StringMap &Features) { return true; } +#elif defined(__linux__) && defined(__loongarch__) +bool sys::getHostCPUFeatures(StringMap &Features) { + std::unique_ptr P = getProcCpuinfoContent(); + if (!P) + return false; + + SmallVector Lines; + P->getBuffer().split(Lines, "\n"); + + SmallVector CPUFeatures; + + // Look for the CPU features. + for (unsigned I = 0, E = Lines.size(); I != E; ++I) + if (Lines[I].startswith("features")) { + Lines[I].split(CPUFeatures, ' '); + break; + } + + for (unsigned I = 0, E = CPUFeatures.size(); I != E; ++I) { + StringRef LLVMFeatureStr = StringSwitch(CPUFeatures[I]) + .Case("lsx", "lsx") + .Case("lasx", "lasx") + .Default(""); + + if (LLVMFeatureStr != "") + Features[LLVMFeatureStr] = true; + } + + return true; +} #else bool sys::getHostCPUFeatures(StringMap &Features) { return false; } #endif diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 4f483c96..de0ae535 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -44,6 +44,8 @@ StringRef Triple::getArchTypeName(ArchType Kind) { case lanai: return "lanai"; case le32: return "le32"; case le64: return "le64"; + case loongarch32: return "loongarch32"; + case loongarch64: return "loongarch64"; case mips64: return "mips64"; case mips64el: return "mips64el"; case mips: return "mips"; @@ -155,6 +157,9 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case ve: return "ve"; case csky: return "csky"; + + case loongarch32: + case loongarch64: return "loongarch"; } } @@ -241,6 +246,7 @@ StringRef Triple::getEnvironmentTypeName(EnvironmentType Kind) { case GNUEABIHF: return "gnueabihf"; case GNUX32: return "gnux32"; case GNUILP32: return "gnu_ilp32"; + case GNUABILPX32: return "gnuabilpx32"; case Itanium: return "itanium"; case MSVC: return "msvc"; case MacABI: return "macabi"; @@ -327,6 +333,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { .Case("renderscript64", renderscript64) .Case("ve", ve) .Case("csky", csky) + .Case("loongarch32", loongarch32) + .Case("loongarch64", loongarch64) .Default(UnknownArch); } @@ -459,6 +467,8 @@ static Triple::ArchType parseArch(StringRef ArchName) { .Case("wasm32", Triple::wasm32) .Case("wasm64", Triple::wasm64) .Case("csky", Triple::csky) + .Case("loongarch32", Triple::loongarch32) + .Case("loongarch64", Triple::loongarch64) .Default(Triple::UnknownArch); // Some architectures require special parsing logic just to compute the @@ -703,6 +713,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) { case Triple::lanai: case Triple::le32: case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: case Triple::mips64: case Triple::mips64el: case Triple::mips: @@ -779,6 +791,7 @@ Triple::Triple(const Twine &Str) .StartsWith("mipsisa64", Triple::GNUABI64) .StartsWith("mipsisa32", Triple::GNU) .Cases("mips", "mipsel", "mipsr6", "mipsr6el", Triple::GNU) + .Cases("loongarch32", "loongarch64", Triple::GNU) .Default(UnknownEnvironment); } } @@ -1276,6 +1289,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::kalimba: case llvm::Triple::lanai: case llvm::Triple::le32: + case llvm::Triple::loongarch32: case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::nvptx: @@ -1305,6 +1319,7 @@ static unsigned getArchPointerBitWidth(llvm::Triple::ArchType Arch) { case llvm::Triple::bpfel: case llvm::Triple::hsail64: case llvm::Triple::le64: + case llvm::Triple::loongarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::nvptx64: @@ -1360,6 +1375,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::kalimba: case Triple::lanai: case Triple::le32: + case Triple::loongarch32: case Triple::mips: case Triple::mipsel: case Triple::nvptx: @@ -1387,6 +1403,7 @@ Triple Triple::get32BitArchVariant() const { case Triple::amdil64: T.setArch(Triple::amdil); break; case Triple::hsail64: T.setArch(Triple::hsail); break; case Triple::le64: T.setArch(Triple::le32); break; + case Triple::loongarch64: T.setArch(Triple::loongarch32); break; case Triple::mips64: T.setArch(Triple::mips); break; case Triple::mips64el: T.setArch(Triple::mipsel); break; case Triple::nvptx64: T.setArch(Triple::nvptx); break; @@ -1430,6 +1447,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::bpfel: case Triple::hsail64: case Triple::le64: + case Triple::loongarch64: case Triple::mips64: case Triple::mips64el: case Triple::nvptx64: @@ -1452,6 +1470,7 @@ Triple Triple::get64BitArchVariant() const { case Triple::armeb: T.setArch(Triple::aarch64_be); break; case Triple::hsail: T.setArch(Triple::hsail64); break; case Triple::le32: T.setArch(Triple::le64); break; + case Triple::loongarch32: T.setArch(Triple::loongarch64); break; case Triple::mips: T.setArch(Triple::mips64); break; case Triple::mipsel: T.setArch(Triple::mips64el); break; case Triple::nvptx: T.setArch(Triple::nvptx64); break; @@ -1486,6 +1505,8 @@ Triple Triple::getBigEndianArchVariant() const { case Triple::kalimba: case Triple::le32: case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: case Triple::msp430: case Triple::nvptx64: case Triple::nvptx: @@ -1575,6 +1596,8 @@ bool Triple::isLittleEndian() const { case Triple::kalimba: case Triple::le32: case Triple::le64: + case Triple::loongarch32: + case Triple::loongarch64: case Triple::mips64el: case Triple::mipsel: case Triple::msp430: diff --git a/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/lib/Transforms/Instrumentation/AddressSanitizer.cpp index f4e47170..5d24fa29 100644 --- a/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -104,6 +104,7 @@ static const uint64_t kPPC64_ShadowOffset64 = 1ULL << 44; static const uint64_t kSystemZ_ShadowOffset64 = 1ULL << 52; static const uint64_t kMIPS32_ShadowOffset32 = 0x0aaa0000; static const uint64_t kMIPS64_ShadowOffset64 = 1ULL << 37; +static const uint64_t kLoongArch64_ShadowOffset64 = 1ULL << 46; static const uint64_t kAArch64_ShadowOffset64 = 1ULL << 36; static const uint64_t kRISCV64_ShadowOffset64 = 0x20000000; static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; @@ -438,6 +439,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; bool IsMIPS32 = TargetTriple.isMIPS32(); bool IsMIPS64 = TargetTriple.isMIPS64(); + bool IsLoongArch64 = TargetTriple.isLoongArch64(); bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; bool IsRISCV64 = TargetTriple.getArch() == Triple::riscv64; @@ -503,7 +505,9 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.Offset = kWindowsShadowOffset64; } else if (IsMIPS64) Mapping.Offset = kMIPS64_ShadowOffset64; - else if (IsIOS) + else if (IsLoongArch64) { + Mapping.Offset = kLoongArch64_ShadowOffset64; + } else if (IsIOS) Mapping.Offset = kDynamicShadowSentinel; else if (IsMacOS && IsAArch64) Mapping.Offset = kDynamicShadowSentinel; @@ -529,7 +533,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, // we could OR the constant in a single instruction, but it's more // efficient to load it once and use indexed addressing. Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU && - !IsRISCV64 && + !IsRISCV64 && !IsLoongArch64 && !(Mapping.Offset & (Mapping.Offset - 1)) && Mapping.Offset != kDynamicShadowSentinel; bool IsAndroidWithIfuncSupport = diff --git a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 1b14b8d5..97ebd2db 100644 --- a/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -805,6 +805,7 @@ bool DataFlowSanitizer::init(Module &M) { bool IsMIPS64 = TargetTriple.isMIPS64(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64 || TargetTriple.getArch() == Triple::aarch64_be; + bool IsLoongArch64 = TargetTriple.getArch() == Triple::loongarch64; const DataLayout &DL = M.getDataLayout(); @@ -823,6 +824,8 @@ bool DataFlowSanitizer::init(Module &M) { // AArch64 supports multiple VMAs and the shadow mask is set at runtime. else if (IsAArch64) DFSanRuntimeShadowMask = true; + else if (IsLoongArch64) + ShadowPtrMask = ConstantInt::getSigned(IntptrTy, ~0x7ffff0000000LL); else report_fatal_error("unsupported triple"); @@ -1040,14 +1043,21 @@ void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) { // Initializes event callback functions and declare them in the module void DataFlowSanitizer::initializeCallbackFunctions(Module &M) { - DFSanLoadCallbackFn = Mod->getOrInsertFunction("__dfsan_load_callback", - DFSanLoadStoreCallbackFnTy); - DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", - DFSanLoadStoreCallbackFnTy); + Triple TargetTriple(M.getTargetTriple()); + bool IsLoongArch64 = TargetTriple.isLoongArch64(); + AttributeList AL; + AL = AL.addParamAttribute(M.getContext(), 0, Attribute::ZExt); + DFSanLoadCallbackFn = Mod->getOrInsertFunction( + "__dfsan_load_callback", DFSanLoadStoreCallbackFnTy, + IsLoongArch64 ? AL : AttributeList()); + DFSanStoreCallbackFn = Mod->getOrInsertFunction( + "__dfsan_store_callback", DFSanLoadStoreCallbackFnTy, + IsLoongArch64 ? AL : AttributeList()); DFSanMemTransferCallbackFn = Mod->getOrInsertFunction( "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy); DFSanCmpCallbackFn = - Mod->getOrInsertFunction("__dfsan_cmp_callback", DFSanCmpCallbackFnTy); + Mod->getOrInsertFunction("__dfsan_cmp_callback", DFSanCmpCallbackFnTy, + IsLoongArch64 ? AL : AttributeList()); } bool DataFlowSanitizer::runImpl(Module &M) { @@ -1686,7 +1696,11 @@ void DFSanVisitor::visitLoadInst(LoadInst &LI) { if (ClEventCallbacks) { IRBuilder<> IRB(&LI); Value *Addr8 = IRB.CreateBitCast(LI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr8}); + CallInst *CallI = + IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr8}); + Triple TargetTriple(LI.getModule()->getTargetTriple()); + if (TargetTriple.getArch() == Triple::loongarch64) + CallI->addParamAttr(0, Attribute::ZExt); } } @@ -1768,7 +1782,11 @@ void DFSanVisitor::visitStoreInst(StoreInst &SI) { if (ClEventCallbacks) { IRBuilder<> IRB(&SI); Value *Addr8 = IRB.CreateBitCast(SI.getPointerOperand(), DFSF.DFS.Int8Ptr); - IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr8}); + CallInst *CallI = + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr8}); + Triple TargetTriple(SI.getModule()->getTargetTriple()); + if (TargetTriple.getArch() == Triple::loongarch64) + CallI->addParamAttr(0, Attribute::ZExt); } } @@ -1786,7 +1804,11 @@ void DFSanVisitor::visitCmpInst(CmpInst &CI) { Value *CombinedShadow = visitOperandShadowInst(CI); if (ClEventCallbacks) { IRBuilder<> IRB(&CI); - IRB.CreateCall(DFSF.DFS.DFSanCmpCallbackFn, CombinedShadow); + CallInst *CallI = + IRB.CreateCall(DFSF.DFS.DFSanCmpCallbackFn, CombinedShadow); + Triple TargetTriple(CI.getModule()->getTargetTriple()); + if (TargetTriple.getArch() == Triple::loongarch64) + CallI->addParamAttr(0, Attribute::ZExt); } } diff --git a/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 7a687458..75f2e66e 100644 --- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -384,6 +384,14 @@ static const MemoryMapParams Linux_X86_64_MemoryMapParams = { #endif }; +// loongarch64 Linux +static const MemoryMapParams Linux_LOONGARCH64_MemoryMapParams = { + 0, // AndMask (not used) + 0x500000000000, // XorMask + 0, // ShadowBase (not used) + 0x100000000000, // OriginBase +}; + // mips64 Linux static const MemoryMapParams Linux_MIPS64_MemoryMapParams = { 0, // AndMask (not used) @@ -445,6 +453,11 @@ static const PlatformMemoryMapParams Linux_X86_MemoryMapParams = { &Linux_X86_64_MemoryMapParams, }; +static const PlatformMemoryMapParams Linux_LOONGARCH_MemoryMapParams = { + nullptr, + &Linux_LOONGARCH64_MemoryMapParams, +}; + static const PlatformMemoryMapParams Linux_MIPS_MemoryMapParams = { nullptr, &Linux_MIPS64_MemoryMapParams, @@ -502,6 +515,7 @@ public: private: friend struct MemorySanitizerVisitor; friend struct VarArgAMD64Helper; + friend struct VarArgLoongArch64Helper; friend struct VarArgMIPS64Helper; friend struct VarArgAArch64Helper; friend struct VarArgPowerPC64Helper; @@ -944,6 +958,9 @@ void MemorySanitizer::initializeModule(Module &M) { case Triple::x86: MapParams = Linux_X86_MemoryMapParams.bits32; break; + case Triple::loongarch64: + MapParams = Linux_LOONGARCH_MemoryMapParams.bits64; + break; case Triple::mips64: case Triple::mips64el: MapParams = Linux_MIPS_MemoryMapParams.bits64; @@ -4397,6 +4414,117 @@ struct VarArgAMD64Helper : public VarArgHelper { } }; +/// LoongArch64-specific implementation of VarArgHelper. +struct VarArgLoongArch64Helper : public VarArgHelper { + Function &F; + MemorySanitizer &MS; + MemorySanitizerVisitor &MSV; + Value *VAArgTLSCopy = nullptr; + Value *VAArgSize = nullptr; + + SmallVector VAStartInstrumentationList; + + VarArgLoongArch64Helper(Function &F, MemorySanitizer &MS, + MemorySanitizerVisitor &MSV) : F(F), MS(MS), MSV(MSV) {} + + void visitCallBase(CallBase &CB, IRBuilder<> &IRB) override { + unsigned VAArgOffset = 0; + const DataLayout &DL = F.getParent()->getDataLayout(); + for (auto ArgIt = CB.arg_begin() + CB.getFunctionType()->getNumParams(), + End = CB.arg_end(); + ArgIt != End; ++ArgIt) { + Triple TargetTriple(F.getParent()->getTargetTriple()); + Value *A = *ArgIt; + Value *Base; + uint64_t ArgSize = DL.getTypeAllocSize(A->getType()); + Base = getShadowPtrForVAArgument(A->getType(), IRB, VAArgOffset, ArgSize); + VAArgOffset += ArgSize; + VAArgOffset = alignTo(VAArgOffset, 8); + if (!Base) + continue; + IRB.CreateAlignedStore(MSV.getShadow(A), Base, kShadowTLSAlignment); + } + + Constant *TotalVAArgSize = ConstantInt::get(IRB.getInt64Ty(), VAArgOffset); + // Here using VAArgOverflowSizeTLS as VAArgSizeTLS to avoid creation of + // a new class member i.e. it is the total size of all VarArgs. + IRB.CreateStore(TotalVAArgSize, MS.VAArgOverflowSizeTLS); + } + + /// Compute the shadow address for a given va_arg. + Value *getShadowPtrForVAArgument(Type *Ty, IRBuilder<> &IRB, + unsigned ArgOffset, unsigned ArgSize) { + // Make sure we don't overflow __msan_va_arg_tls. + if (ArgOffset + ArgSize > kParamTLSSize) + return nullptr; + Value *Base = IRB.CreatePointerCast(MS.VAArgTLS, MS.IntptrTy); + Base = IRB.CreateAdd(Base, ConstantInt::get(MS.IntptrTy, ArgOffset)); + return IRB.CreateIntToPtr(Base, PointerType::get(MSV.getShadowTy(Ty), 0), + "_msarg"); + } + + void visitVAStartInst(VAStartInst &I) override { + IRBuilder<> IRB(&I); + VAStartInstrumentationList.push_back(&I); + Value *VAListTag = I.getArgOperand(0); + Value *ShadowPtr, *OriginPtr; + const Align Alignment = Align(8); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); + IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), + /* size */ 8, Alignment, false); + } + + void visitVACopyInst(VACopyInst &I) override { + IRBuilder<> IRB(&I); + VAStartInstrumentationList.push_back(&I); + Value *VAListTag = I.getArgOperand(0); + Value *ShadowPtr, *OriginPtr; + const Align Alignment = Align(8); + std::tie(ShadowPtr, OriginPtr) = MSV.getShadowOriginPtr( + VAListTag, IRB, IRB.getInt8Ty(), Alignment, /*isStore*/ true); + IRB.CreateMemSet(ShadowPtr, Constant::getNullValue(IRB.getInt8Ty()), + /* size */ 8, Alignment, false); + } + + void finalizeInstrumentation() override { + assert(!VAArgSize && !VAArgTLSCopy && + "finalizeInstrumentation called twice"); + IRBuilder<> IRB(MSV.FnPrologueEnd); + VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); + Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), + VAArgSize); + + if (!VAStartInstrumentationList.empty()) { + // If there is a va_start in this function, make a backup copy of + // va_arg_tls somewhere in the function entry block. + VAArgTLSCopy = IRB.CreateAlloca(Type::getInt8Ty(*MS.C), CopySize); + IRB.CreateMemCpy(VAArgTLSCopy, Align(8), MS.VAArgTLS, Align(8), CopySize); + } + + // Instrument va_start. + // Copy va_list shadow from the backup copy of the TLS contents. + for (size_t i = 0, n = VAStartInstrumentationList.size(); i < n; i++) { + CallInst *OrigInst = VAStartInstrumentationList[i]; + IRBuilder<> IRB(OrigInst->getNextNode()); + Value *VAListTag = OrigInst->getArgOperand(0); + Type *RegSaveAreaPtrTy = Type::getInt64PtrTy(*MS.C); + Value *RegSaveAreaPtrPtr = + IRB.CreateIntToPtr(IRB.CreatePtrToInt(VAListTag, MS.IntptrTy), + PointerType::get(Type::getInt64PtrTy(*MS.C), 0)); + Value *RegSaveAreaPtr = + IRB.CreateLoad(RegSaveAreaPtrTy, RegSaveAreaPtrPtr); + Value *RegSaveAreaShadowPtr, *RegSaveAreaOriginPtr; + const Align Alignment = Align(8); + std::tie(RegSaveAreaShadowPtr, RegSaveAreaOriginPtr) = + MSV.getShadowOriginPtr(RegSaveAreaPtr, IRB, IRB.getInt8Ty(), + Alignment, /*isStore*/ true); + IRB.CreateMemCpy(RegSaveAreaShadowPtr, Alignment, VAArgTLSCopy, Alignment, + CopySize); + } + } +}; + /// MIPS64-specific implementation of VarArgHelper. struct VarArgMIPS64Helper : public VarArgHelper { Function &F; @@ -5296,6 +5424,8 @@ static VarArgHelper *CreateVarArgHelper(Function &Func, MemorySanitizer &Msan, return new VarArgPowerPC64Helper(Func, Msan, Visitor); else if (TargetTriple.getArch() == Triple::systemz) return new VarArgSystemZHelper(Func, Msan, Visitor); + else if (TargetTriple.getArch() == Triple::loongarch64) + return new VarArgLoongArch64Helper(Func, Msan, Visitor); else return new VarArgNoOpHelper(Func, Msan, Visitor); } diff --git a/lib/XRay/InstrumentationMap.cpp b/lib/XRay/InstrumentationMap.cpp index e6534e5a..66c07f9d 100644 --- a/lib/XRay/InstrumentationMap.cpp +++ b/lib/XRay/InstrumentationMap.cpp @@ -61,6 +61,7 @@ loadObj(StringRef Filename, object::OwningBinary &ObjFile, if ((!ObjFile.getBinary()->isELF() && !ObjFile.getBinary()->isMachO()) || !(ObjFile.getBinary()->getArch() == Triple::x86_64 || ObjFile.getBinary()->getArch() == Triple::ppc64le || + ObjFile.getBinary()->getArch() == Triple::loongarch64 || ObjFile.getBinary()->getArch() == Triple::arm || ObjFile.getBinary()->getArch() == Triple::aarch64)) return make_error( diff --git a/test/ExecutionEngine/JITLink/X86/MachO_GOTAndStubsOptimization.s b/test/ExecutionEngine/JITLink/X86/MachO_GOTAndStubsOptimization.s index 98df053c..45c078c1 100644 --- a/test/ExecutionEngine/JITLink/X86/MachO_GOTAndStubsOptimization.s +++ b/test/ExecutionEngine/JITLink/X86/MachO_GOTAndStubsOptimization.s @@ -1,3 +1,4 @@ +# UNSUPPORTED: loongarch64 # RUN: rm -rf %t && mkdir -p %t # RUN: llvm-mc -triple=x86_64-apple-macos10.9 -filetype=obj \ # RUN: -o %t/helper.o %S/Inputs/MachO_GOTAndStubsOptimizationHelper.s diff --git a/test/ExecutionEngine/MCJIT/2003-01-04-ArgumentBug.ll b/test/ExecutionEngine/MCJIT/2003-01-04-ArgumentBug.ll index 68fdefef..f7bb02b2 100644 --- a/test/ExecutionEngine/MCJIT/2003-01-04-ArgumentBug.ll +++ b/test/ExecutionEngine/MCJIT/2003-01-04-ArgumentBug.ll @@ -1,4 +1,6 @@ ; RUN: %lli %s > /dev/null +; The test needs to add the -mattr='+d' parameter to pass, set them to XFAIL for now +; XFAIL: loongarch64 define i32 @foo(i32 %X, i32 %Y, double %A) { %cond212 = fcmp une double %A, 1.000000e+00 ; [#uses=1] diff --git a/test/ExecutionEngine/MCJIT/lit.local.cfg b/test/ExecutionEngine/MCJIT/lit.local.cfg index e2535ef1..09f1a2ab 100644 --- a/test/ExecutionEngine/MCJIT/lit.local.cfg +++ b/test/ExecutionEngine/MCJIT/lit.local.cfg @@ -1,7 +1,8 @@ root = config.root targets = root.targets if ('X86' in targets) | ('AArch64' in targets) | ('ARM' in targets) | \ - ('Mips' in targets) | ('PowerPC' in targets) | ('SystemZ' in targets): + ('Mips' in targets) | ('PowerPC' in targets) | ('SystemZ' in targets) | \ + ('LoongArch' in targets) : config.unsupported = False else: config.unsupported = True @@ -9,7 +10,7 @@ else: # FIXME: autoconf and cmake produce different arch names. We should normalize # them before getting here. if root.host_arch not in ['i386', 'x86', 'x86_64', 'AMD64', - 'AArch64', 'ARM', 'Mips', + 'AArch64', 'ARM', 'Mips', 'loongarch64', 'PowerPC', 'ppc64', 'ppc64le', 'SystemZ']: config.unsupported = True diff --git a/test/ExecutionEngine/MCJIT/pr13727.ll b/test/ExecutionEngine/MCJIT/pr13727.ll index 79dd9b4c..6438756b 100644 --- a/test/ExecutionEngine/MCJIT/pr13727.ll +++ b/test/ExecutionEngine/MCJIT/pr13727.ll @@ -1,4 +1,6 @@ ; RUN: %lli -O0 -disable-lazy-compilation=false %s +; The test needs to add the -mattr='+d' parameter to pass, set them to XFAIL for now +; XFAIL: loongarch64 ; The intention of this test is to verify that symbols mapped to COMMON in ELF ; work as expected. diff --git a/test/ExecutionEngine/MCJIT/remote/test-common-symbols-remote.ll b/test/ExecutionEngine/MCJIT/remote/test-common-symbols-remote.ll index eda2c8e8..f9fc0e22 100644 --- a/test/ExecutionEngine/MCJIT/remote/test-common-symbols-remote.ll +++ b/test/ExecutionEngine/MCJIT/remote/test-common-symbols-remote.ll @@ -1,5 +1,6 @@ ; RUN: %lli -remote-mcjit -O0 -disable-lazy-compilation=false -mcjit-remote-process=lli-child-target%exeext %s ; XFAIL: windows-gnu,windows-msvc +; XFAIL: loongarch64 ; UNSUPPORTED: powerpc64-unknown-linux-gnu ; Remove UNSUPPORTED for powerpc64-unknown-linux-gnu if problem caused by r266663 is fixed diff --git a/test/ExecutionEngine/MCJIT/test-common-symbols.ll b/test/ExecutionEngine/MCJIT/test-common-symbols.ll index b63c2fea..86c09883 100644 --- a/test/ExecutionEngine/MCJIT/test-common-symbols.ll +++ b/test/ExecutionEngine/MCJIT/test-common-symbols.ll @@ -1,4 +1,6 @@ ; RUN: %lli -O0 -disable-lazy-compilation=false %s +; The test needs to add the -mattr='+d' parameter to pass, set them to XFAIL for now +; XFAIL: loongarch64 ; The intention of this test is to verify that symbols mapped to COMMON in ELF ; work as expected. diff --git a/test/ExecutionEngine/frem.ll b/test/ExecutionEngine/frem.ll index aedaae38..c6709be0 100644 --- a/test/ExecutionEngine/frem.ll +++ b/test/ExecutionEngine/frem.ll @@ -3,6 +3,8 @@ ; This unit test guards against the failure. ; ; RUN: %lli %s | FileCheck %s +; The test needs to add the -mattr='+d' parameter to pass, set them to XFAIL for now +; XFAIL: loongarch64 @flt = internal global float 12.0e+0 @str = internal constant [18 x i8] c"Double value: %f\0A\00" diff --git a/test/Instrumentation/DataFlowSanitizer/callback.ll b/test/Instrumentation/DataFlowSanitizer/callback.ll index 7194535b..8d9cf66a 100644 --- a/test/Instrumentation/DataFlowSanitizer/callback.ll +++ b/test/Instrumentation/DataFlowSanitizer/callback.ll @@ -1,10 +1,13 @@ ; RUN: opt < %s -dfsan -dfsan-event-callbacks=1 -S | FileCheck %s +; RUN: opt --mtriple=loongarch64-linux-gnu < %s -dfsan -dfsan-event-callbacks=1 -S | FileCheck %s --check-prefix=LA64 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" define i8 @load8(i8* %p) { ; CHECK: call void @__dfsan_load_callback(i16 %{{.*}}, i8* %p) ; CHECK: %a = load i8, i8* %p + ; LA64: call void @__dfsan_load_callback(i16 zeroext %{{.*}}, i8* %p) + ; LA64: %a = load i8, i8* %p %a = load i8, i8* %p ret i8 %a @@ -14,6 +17,9 @@ define void @store8(i8* %p, i8 %a) { ; CHECK: store i16 %[[l:.*]], i16* %{{.*}} ; CHECK: call void @__dfsan_store_callback(i16 %[[l]], i8* %p) ; CHECK: store i8 %a, i8* %p + ; LA64: store i16 %[[l:.*]], i16* %{{.*}} + ; LA64: call void @__dfsan_store_callback(i16 zeroext %[[l]], i8* %p) + ; LA64: store i8 %a, i8* %p store i8 %a, i8* %p ret void @@ -23,7 +29,14 @@ define i1 @cmp(i8 %a, i8 %b) { ; CHECK: call void @__dfsan_cmp_callback(i16 %[[l:.*]]) ; CHECK: %c = icmp ne i8 %a, %b ; CHECK: store i16 %[[l]], i16* bitcast ({{.*}}* @__dfsan_retval_tls to i16*) + ; LA64: call void @__dfsan_cmp_callback(i16 zeroext %[[l:.*]]) + ; LA64: %c = icmp ne i8 %a, %b + ; LA64: store i16 %[[l]], i16* bitcast ({{.*}}* @__dfsan_retval_tls to i16*) %c = icmp ne i8 %a, %b ret i1 %c -} \ No newline at end of file +} + +; LA64: declare void @__dfsan_load_callback(i16 zeroext, i8*) +; LA64: declare void @__dfsan_store_callback(i16 zeroext, i8*) +; LA64: declare void @__dfsan_cmp_callback(i16 zeroext) diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 0f508f8d..17fd17da 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -1164,6 +1164,7 @@ static const EnumEntry ElfMachineType[] = { ENUM_ENT(EM_LANAI, "EM_LANAI"), ENUM_ENT(EM_BPF, "EM_BPF"), ENUM_ENT(EM_VE, "NEC SX-Aurora Vector Engine"), + ENUM_ENT(EM_LOONGARCH, "LoongArch"), }; static const EnumEntry ElfSymbolBindings[] = { @@ -1485,6 +1486,14 @@ static const EnumEntry ElfHeaderRISCVFlags[] = { ENUM_ENT(EF_RISCV_RVE, "RVE") }; +static const EnumEntry ElfHeaderLoongArchFlags[] = { + ENUM_ENT(EF_LOONGARCH_ABI_SOFT_FLOAT, "SOFT-FLOAT"), + ENUM_ENT(EF_LOONGARCH_ABI_SINGLE_FLOAT, "SINGLE-FLOAT"), + ENUM_ENT(EF_LOONGARCH_ABI_DOUBLE_FLOAT, "DOUBLE-FLOAT"), + ENUM_ENT(EF_LOONGARCH_OBJABI_V0, "OBJ-v0"), + ENUM_ENT(EF_LOONGARCH_OBJABI_V1, "OBJ-v1"), +}; + static const EnumEntry ElfSymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL), LLVM_READOBJ_ENUM_ENT(ELF, STV_HIDDEN), @@ -3170,6 +3179,10 @@ template void GNUELFDumper::printFileHeaders() { unsigned(ELF::EF_MIPS_MACH)); else if (e.e_machine == EM_RISCV) ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderRISCVFlags)); + else if (e.e_machine == EM_LOONGARCH) + ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderLoongArchFlags), + unsigned(ELF::EF_LOONGARCH_ABI_MODIFIER_MASK), + unsigned(ELF::EF_LOONGARCH_OBJABI_MASK)); Str = "0x" + to_hexString(e.e_flags); if (!ElfFlags.empty()) Str = Str + ", " + ElfFlags; @@ -5982,6 +5995,10 @@ template void LLVMELFDumper::printFileHeaders() { unsigned(ELF::EF_AMDGPU_MACH)); else if (E.e_machine == EM_RISCV) W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderRISCVFlags)); + else if (E.e_machine == EM_LOONGARCH) + W.printFlags("Flags", E.e_flags, makeArrayRef(ElfHeaderLoongArchFlags), + unsigned(ELF::EF_LOONGARCH_ABI_MODIFIER_MASK), + unsigned(ELF::EF_LOONGARCH_OBJABI_MASK)); else W.printFlags("Flags", E.e_flags); W.printNumber("HeaderSize", E.e_ehsize); diff --git a/tools/sancov/sancov.cpp b/tools/sancov/sancov.cpp index f1d756f2..136ad502 100644 --- a/tools/sancov/sancov.cpp +++ b/tools/sancov/sancov.cpp @@ -691,7 +691,7 @@ static uint64_t getPreviousInstructionPc(uint64_t PC, Triple TheTriple) { if (TheTriple.isARM()) { return (PC - 3) & (~1); - } else if (TheTriple.isAArch64()) { + } else if (TheTriple.isAArch64() || TheTriple.isLoongArch64()) { return PC - 4; } else if (TheTriple.isMIPS()) { return PC - 8; diff --git a/utils/UpdateTestChecks/asm.py b/utils/UpdateTestChecks/asm.py index 6390ace4..3b0385cd 100644 --- a/utils/UpdateTestChecks/asm.py +++ b/utils/UpdateTestChecks/asm.py @@ -73,6 +73,12 @@ ASM_FUNCTION_AVR_RE = re.compile( r'.Lfunc_end[0-9]+:\n', flags=(re.M | re.S)) +ASM_FUNCTION_LOONGARCH_RE = re.compile( + r'^_?(?P[^:]+):[ \t]*#+[ \t]*@(?P=func)\n[^:]*?' # f: (name of func) + r'(?P^##?[ \t]+[^:]+:.*?)\s*' # (body of the function) + r'.Lfunc_end[0-9]+:\n', # .Lfunc_end[0-9]: + flags=(re.M | re.S)) + ASM_FUNCTION_PPC_RE = re.compile( r'#[ \-\t]*Begin function (?P[^.:]+)\n' r'.*?' @@ -277,6 +283,16 @@ def scrub_asm_avr(asm, args): asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) return asm +def scrub_asm_loongarch(asm, args): + # Scrub runs of whitespace out of the assembly, but leave the leading + # whitespace in place. + asm = common.SCRUB_WHITESPACE_RE.sub(r' ', asm) + # Expand the tabs used for indentation. + asm = string.expandtabs(asm, 2) + # Strip trailing whitespace. + asm = common.SCRUB_TRAILING_WHITESPACE_RE.sub(r'', asm) + return asm + def scrub_asm_riscv(asm, args): # Scrub runs of whitespace out of the assembly, but leave the leading # whitespace in place. @@ -366,6 +382,7 @@ def get_run_handler(triple): 'avr': (scrub_asm_avr, ASM_FUNCTION_AVR_RE), 'ppc32': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE), 'powerpc': (scrub_asm_powerpc, ASM_FUNCTION_PPC_RE), + 'loongarch64': (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE), 'riscv32': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 'riscv64': (scrub_asm_riscv, ASM_FUNCTION_RISCV_RE), 'lanai': (scrub_asm_lanai, ASM_FUNCTION_LANAI_RE), diff --git a/utils/benchmark/src/cycleclock.h b/utils/benchmark/src/cycleclock.h index 040ec22c..cc7c0595 100644 --- a/utils/benchmark/src/cycleclock.h +++ b/utils/benchmark/src/cycleclock.h @@ -167,6 +167,10 @@ inline BENCHMARK_ALWAYS_INLINE int64_t Now() { struct timeval tv; gettimeofday(&tv, nullptr); return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; +#elif defined(__loongarch__) + struct timeval tv; + gettimeofday(&tv, nullptr); + return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; #elif defined(__s390__) // Covers both s390 and s390x. // Return the CPU clock. uint64_t tsc; diff --git a/utils/gn/secondary/clang/lib/Basic/BUILD.gn b/utils/gn/secondary/clang/lib/Basic/BUILD.gn index d6e322f7..60eff129 100644 --- a/utils/gn/secondary/clang/lib/Basic/BUILD.gn +++ b/utils/gn/secondary/clang/lib/Basic/BUILD.gn @@ -83,6 +83,7 @@ static_library("Basic") { "Targets/Hexagon.cpp", "Targets/Lanai.cpp", "Targets/Le64.cpp", + "Targets/LoongArch.cpp", "Targets/MSP430.cpp", "Targets/Mips.cpp", "Targets/NVPTX.cpp", diff --git a/utils/gn/secondary/clang/lib/Driver/BUILD.gn b/utils/gn/secondary/clang/lib/Driver/BUILD.gn index ab29e6be..3111f03a 100644 --- a/utils/gn/secondary/clang/lib/Driver/BUILD.gn +++ b/utils/gn/secondary/clang/lib/Driver/BUILD.gn @@ -47,6 +47,7 @@ static_library("Driver") { "ToolChains/Ananas.cpp", "ToolChains/Arch/AArch64.cpp", "ToolChains/Arch/ARM.cpp", + "ToolChains/Arch/LoongArch.cpp", "ToolChains/Arch/Mips.cpp", "ToolChains/Arch/PPC.cpp", "ToolChains/Arch/RISCV.cpp", diff --git a/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn b/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn index f12d39ad..1280c748 100644 --- a/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn +++ b/utils/gn/secondary/llvm/include/llvm/IR/BUILD.gn @@ -67,6 +67,16 @@ tablegen("IntrinsicsHexagon") { td_file = "Intrinsics.td" } +tablegen("IntrinsicsLoongArch") { + visibility = [ ":public_tablegen" ] + output_name = "IntrinsicsLoongArch.h" + args = [ + "-gen-intrinsic-enums", + "-intrinsic-prefix=loongarch", + ] + td_file = "Intrinsics.td" +} + tablegen("IntrinsicsMips") { visibility = [ ":public_tablegen" ] output_name = "IntrinsicsMips.h" @@ -186,6 +196,7 @@ group("public_tablegen") { ":IntrinsicsARM", ":IntrinsicsBPF", ":IntrinsicsHexagon", + ":IntrinsicsLoongArch", ":IntrinsicsMips", ":IntrinsicsNVPTX", ":IntrinsicsPowerPC", diff --git a/utils/gn/secondary/llvm/lib/Target/targets.gni b/utils/gn/secondary/llvm/lib/Target/targets.gni index 102040c2..062526be 100644 --- a/utils/gn/secondary/llvm/lib/Target/targets.gni +++ b/utils/gn/secondary/llvm/lib/Target/targets.gni @@ -14,6 +14,7 @@ llvm_all_targets = [ "BPF", "Hexagon", "Lanai", + "LoongArch", "Mips", "NVPTX", "PowerPC", @@ -47,6 +48,7 @@ llvm_build_AArch64 = false llvm_build_AMDGPU = false llvm_build_ARM = false llvm_build_BPF = false +llvm_build_LoongArch = false llvm_build_Mips = false llvm_build_PowerPC = false llvm_build_WebAssembly = false @@ -60,6 +62,8 @@ foreach(target, llvm_targets_to_build) { llvm_build_ARM = true } else if (target == "BPF") { llvm_build_BPF = true + } else if (target == "LoongArch") { + llvm_build_LoongArch = true } else if (target == "Mips") { llvm_build_Mips = true } else if (target == "PowerPC") { -- 2.41.0