From 5ef02d9963765514f094092d6635eb8b4f1f9ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Ferrer=20Ib=C3=A1=C3=B1ez?= Date: Thu, 20 Jun 2024 07:27:07 +0200 Subject: [RISCV] Lower llvm.clear_cache to __riscv_flush_icache for glibc targets (#93481) This change is a preliminary step to support trampolines on RISC-V. Trampolines are used by flang to implement obtaining the address of an internal program (i.e., a nested function in Fortran parlance). In this change we lower `llvm.clear_cache` intrinsic on glibc targets to `__riscv_flush_icache` which is what GCC is currently doing for Linux targets. --- llvm/include/llvm/IR/RuntimeLibcalls.def | 1 + llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 25 ++++++++++++++ llvm/lib/Target/RISCV/RISCVISelLowering.h | 3 ++ llvm/test/CodeGen/RISCV/clear-cache.ll | 51 +++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/clear-cache.ll diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def index e900bcd..d8eab80 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.def +++ b/llvm/include/llvm/IR/RuntimeLibcalls.def @@ -623,6 +623,7 @@ HANDLE_LIBCALL(RETURN_ADDRESS, nullptr) // Clear cache HANDLE_LIBCALL(CLEAR_CACHE, "__clear_cache") +HANDLE_LIBCALL(RISCV_FLUSH_ICACHE, "__riscv_flush_icache") HANDLE_LIBCALL(UNKNOWN_LIBCALL, nullptr) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index b1b27f0..e9c7215 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -662,6 +662,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setBooleanContents(ZeroOrOneBooleanContent); + if (getTargetMachine().getTargetTriple().isOSLinux()) { + // Custom lowering of llvm.clear_cache. + setOperationAction(ISD::CLEAR_CACHE, MVT::Other, Custom); + } + if (Subtarget.hasVInstructions()) { setBooleanVectorContents(ZeroOrOneBooleanContent); @@ -7142,9 +7147,29 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op, return lowerVPSpliceExperimental(Op, DAG); case ISD::EXPERIMENTAL_VP_REVERSE: return lowerVPReverseExperimental(Op, DAG); + case ISD::CLEAR_CACHE: { + assert(getTargetMachine().getTargetTriple().isOSLinux() && + "llvm.clear_cache only needs custom lower on Linux targets"); + SDLoc DL(Op); + SDValue Flags = DAG.getConstant(0, DL, Subtarget.getXLenVT()); + return emitFlushICache(DAG, Op.getOperand(0), Op.getOperand(1), + Op.getOperand(2), Flags, DL); + } } } +SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain, + SDValue Start, SDValue End, + SDValue Flags, SDLoc DL) const { + MakeLibCallOptions CallOptions; + std::pair CallResult = + makeLibCall(DAG, RTLIB::RISCV_FLUSH_ICACHE, MVT::isVoid, + {Start, End, Flags}, CallOptions, DL, InChain); + + // This function returns void so only the out chain matters. + return CallResult.second; +} + static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty, SelectionDAG &DAG, unsigned Flags) { return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h index 3b8eb3c..7d8bceb 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -1037,6 +1037,9 @@ private: const APInt &AndMask) const override; unsigned getMinimumJumpTableEntries() const override; + + SDValue emitFlushICache(SelectionDAG &DAG, SDValue InChain, SDValue Start, + SDValue End, SDValue Flags, SDLoc DL) const; }; /// As per the spec, the rules for passing vector arguments are as follows: diff --git a/llvm/test/CodeGen/RISCV/clear-cache.ll b/llvm/test/CodeGen/RISCV/clear-cache.ll new file mode 100644 index 0000000..d598a98 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/clear-cache.ll @@ -0,0 +1,51 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=riscv32 < %s | FileCheck --check-prefix=RV32 %s +; RUN: llc -mtriple=riscv64 < %s | FileCheck --check-prefix=RV64 %s +; RUN: llc -mtriple=riscv32-unknown-linux-gnu < %s | FileCheck --check-prefix=RV32-LINUX %s +; RUN: llc -mtriple=riscv64-unknown-linux-gnu < %s | FileCheck --check-prefix=RV64-LINUX %s +; RUN: llc -mtriple=riscv32-unknown-linux-musl < %s | FileCheck --check-prefix=RV32-LINUX %s +; RUN: llc -mtriple=riscv64-unknown-linux-musl < %s | FileCheck --check-prefix=RV64-LINUX %s + +declare void @llvm.clear_cache(ptr, ptr) + +define void @foo(ptr %a, ptr %b) nounwind { +; RV32-LABEL: foo: +; RV32: # %bb.0: +; RV32-NEXT: addi sp, sp, -16 +; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32-NEXT: call __clear_cache +; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32-NEXT: addi sp, sp, 16 +; RV32-NEXT: ret +; +; RV64-LABEL: foo: +; RV64: # %bb.0: +; RV64-NEXT: addi sp, sp, -16 +; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64-NEXT: call __clear_cache +; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64-NEXT: addi sp, sp, 16 +; RV64-NEXT: ret +; +; RV32-LINUX-LABEL: foo: +; RV32-LINUX: # %bb.0: +; RV32-LINUX-NEXT: addi sp, sp, -16 +; RV32-LINUX-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32-LINUX-NEXT: li a2, 0 +; RV32-LINUX-NEXT: call __riscv_flush_icache +; RV32-LINUX-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32-LINUX-NEXT: addi sp, sp, 16 +; RV32-LINUX-NEXT: ret +; +; RV64-LINUX-LABEL: foo: +; RV64-LINUX: # %bb.0: +; RV64-LINUX-NEXT: addi sp, sp, -16 +; RV64-LINUX-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64-LINUX-NEXT: li a2, 0 +; RV64-LINUX-NEXT: call __riscv_flush_icache +; RV64-LINUX-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64-LINUX-NEXT: addi sp, sp, 16 +; RV64-LINUX-NEXT: ret + call void @llvm.clear_cache(ptr %a, ptr %b) + ret void +} -- cgit v1.1