Skip to content

Commit 2a51c76

Browse files
committed
[RISCV][SelectionDAG] Lower llvm.clear_cache to __riscv_flush_icache for glibc targets
This change also must extend the generic part so a target can lower the call to a function that does not have the same signature as the generic __clear_cache.
1 parent cc184ee commit 2a51c76

File tree

5 files changed

+125
-3
lines changed

5 files changed

+125
-3
lines changed

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4764,8 +4764,15 @@ class TargetLowering : public TargetLoweringBase {
47644764
return false;
47654765
}
47664766

4767+
/// Returns true if the target needs to lower __builtin___clear_cache in a
4768+
/// specific way that is incompatible with the clear_cache
4769+
/// signature. When returning false, the lowering will invoke
4770+
/// getClearCacheBuiltinName.
4771+
virtual bool isClearCacheBuiltinTargetSpecific() const { return false; }
4772+
47674773
/// Return the builtin name for the __builtin___clear_cache intrinsic
4768-
/// Default is to invoke the clear cache library call
4774+
/// This is only used if isClearCacheBuiltinTargetSpecific returns false.
4775+
/// If nullptr is returned, the builtin is lowered to no code.
47694776
virtual const char * getClearCacheBuiltinName() const {
47704777
return "__clear_cache";
47714778
}

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7518,8 +7518,13 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
75187518
return;
75197519
case Intrinsic::clear_cache:
75207520
/// FunctionName may be null.
7521-
if (const char *FunctionName = TLI.getClearCacheBuiltinName())
7522-
lowerCallToExternalSymbol(I, FunctionName);
7521+
if (!TLI.isClearCacheBuiltinTargetSpecific()) {
7522+
if (const char *FunctionName = TLI.getClearCacheBuiltinName())
7523+
lowerCallToExternalSymbol(I, FunctionName);
7524+
} else {
7525+
// Turn this into a target intrinsic node.
7526+
visitTargetIntrinsic(I, Intrinsic);
7527+
}
75237528
return;
75247529
case Intrinsic::donothing:
75257530
case Intrinsic::seh_try_begin:

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,12 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
662662

663663
setBooleanContents(ZeroOrOneBooleanContent);
664664

665+
if (Subtarget.getTargetTriple().isOSGlibc()) {
666+
// Custom lowering of llvm.clear_cache
667+
setOperationAction({ISD::INTRINSIC_VOID, ISD::INTRINSIC_VOID}, MVT::Other,
668+
Custom);
669+
}
670+
665671
if (Subtarget.hasVInstructions()) {
666672
setBooleanVectorContents(ZeroOrOneBooleanContent);
667673

@@ -7120,6 +7126,39 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
71207126
}
71217127
}
71227128

7129+
SDValue RISCVTargetLowering::emitFlushICache(SelectionDAG &DAG, SDValue InChain,
7130+
SDValue Start, SDValue End,
7131+
SDValue Flags, SDLoc DL) const {
7132+
TargetLowering::ArgListTy Args;
7133+
TargetLowering::ArgListEntry Entry;
7134+
7135+
// start
7136+
Entry.Node = Start;
7137+
Entry.Ty = PointerType::getUnqual(*DAG.getContext());
7138+
Args.push_back(Entry);
7139+
7140+
// end
7141+
Entry.Node = End;
7142+
Entry.Ty = PointerType::getUnqual(*DAG.getContext());
7143+
Args.push_back(Entry);
7144+
7145+
// flags
7146+
Entry.Node = Flags;
7147+
Entry.Ty = Type::getIntNTy(*DAG.getContext(), Subtarget.getXLen());
7148+
Args.push_back(Entry);
7149+
7150+
TargetLowering::CallLoweringInfo CLI(DAG);
7151+
EVT Ty = getPointerTy(DAG.getDataLayout());
7152+
CLI.setDebugLoc(DL).setChain(InChain).setLibCallee(
7153+
CallingConv::C, Type::getVoidTy(*DAG.getContext()),
7154+
DAG.getExternalSymbol("__riscv_flush_icache", Ty), std::move(Args));
7155+
7156+
std::pair<SDValue, SDValue> CallResult = LowerCallTo(CLI);
7157+
7158+
// This function returns void so only the out chain matters.
7159+
return CallResult.second;
7160+
}
7161+
71237162
static SDValue getTargetNode(GlobalAddressSDNode *N, const SDLoc &DL, EVT Ty,
71247163
SelectionDAG &DAG, unsigned Flags) {
71257164
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
@@ -9497,6 +9536,15 @@ SDValue RISCVTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
94979536
return getVCIXISDNodeVOID(Op, DAG, RISCVISD::SF_VC_VVW_SE);
94989537
case Intrinsic::riscv_sf_vc_fvw_se:
94999538
return getVCIXISDNodeVOID(Op, DAG, RISCVISD::SF_VC_FVW_SE);
9539+
case Intrinsic::clear_cache: {
9540+
if (Subtarget.getTargetTriple().isOSGlibc()) {
9541+
SDLoc DL(Op);
9542+
SDValue Flags = DAG.getConstant(0, DL, Subtarget.getXLenVT());
9543+
return emitFlushICache(DAG, Op.getOperand(0), Op.getOperand(2),
9544+
Op.getOperand(3), Flags, DL);
9545+
}
9546+
break;
9547+
}
95009548
}
95019549

95029550
return lowerVectorIntrinsicScalars(Op, DAG, Subtarget);
@@ -21684,6 +21732,14 @@ SDValue RISCVTargetLowering::expandIndirectJTBranch(const SDLoc &dl,
2168421732
return TargetLowering::expandIndirectJTBranch(dl, Value, Addr, JTI, DAG);
2168521733
}
2168621734

21735+
bool RISCVTargetLowering::isClearCacheBuiltinTargetSpecific() const {
21736+
// We do a manual lowering for glibc-based targets to call
21737+
// __riscv_flush_icache instead.
21738+
if (Subtarget.getTargetTriple().isOSGlibc())
21739+
return true;
21740+
return TargetLowering::isClearCacheBuiltinTargetSpecific();
21741+
}
21742+
2168721743
namespace llvm::RISCVVIntrinsicsTable {
2168821744

2168921745
#define GET_RISCVVIntrinsicsTable_IMPL

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,8 @@ class RISCVTargetLowering : public TargetLowering {
897897
const RISCVTargetLowering &TLI,
898898
RVVArgDispatcher &RVVDispatcher);
899899

900+
bool isClearCacheBuiltinTargetSpecific() const override;
901+
900902
private:
901903
void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo,
902904
const SmallVectorImpl<ISD::InputArg> &Ins, bool IsRet,
@@ -1033,6 +1035,9 @@ class RISCVTargetLowering : public TargetLowering {
10331035
const APInt &AndMask) const override;
10341036

10351037
unsigned getMinimumJumpTableEntries() const override;
1038+
1039+
SDValue emitFlushICache(SelectionDAG &DAG, SDValue InChain, SDValue Start,
1040+
SDValue End, SDValue Flags, SDLoc DL) const;
10361041
};
10371042

10381043
/// As per the spec, the rules for passing vector arguments are as follows:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -mtriple=riscv32 < %s | FileCheck --check-prefix=RV32 %s
3+
; RUN: llc -mtriple=riscv64 < %s | FileCheck --check-prefix=RV64 %s
4+
; RUN: llc -mtriple=riscv32-unknown-linux-gnu < %s | FileCheck --check-prefix=RV32-GLIBC %s
5+
; RUN: llc -mtriple=riscv64-unknown-linux-gnu < %s | FileCheck --check-prefix=RV64-GLIBC %s
6+
7+
declare void @llvm.clear_cache(ptr, ptr)
8+
9+
define void @foo(ptr %a, ptr %b) nounwind {
10+
; RV32-LABEL: foo:
11+
; RV32: # %bb.0:
12+
; RV32-NEXT: addi sp, sp, -16
13+
; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
14+
; RV32-NEXT: call __clear_cache
15+
; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
16+
; RV32-NEXT: addi sp, sp, 16
17+
; RV32-NEXT: ret
18+
;
19+
; RV64-LABEL: foo:
20+
; RV64: # %bb.0:
21+
; RV64-NEXT: addi sp, sp, -16
22+
; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
23+
; RV64-NEXT: call __clear_cache
24+
; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
25+
; RV64-NEXT: addi sp, sp, 16
26+
; RV64-NEXT: ret
27+
;
28+
; RV32-GLIBC-LABEL: foo:
29+
; RV32-GLIBC: # %bb.0:
30+
; RV32-GLIBC-NEXT: addi sp, sp, -16
31+
; RV32-GLIBC-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
32+
; RV32-GLIBC-NEXT: li a2, 0
33+
; RV32-GLIBC-NEXT: call __riscv_flush_icache
34+
; RV32-GLIBC-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
35+
; RV32-GLIBC-NEXT: addi sp, sp, 16
36+
; RV32-GLIBC-NEXT: ret
37+
;
38+
; RV64-GLIBC-LABEL: foo:
39+
; RV64-GLIBC: # %bb.0:
40+
; RV64-GLIBC-NEXT: addi sp, sp, -16
41+
; RV64-GLIBC-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
42+
; RV64-GLIBC-NEXT: li a2, 0
43+
; RV64-GLIBC-NEXT: call __riscv_flush_icache
44+
; RV64-GLIBC-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
45+
; RV64-GLIBC-NEXT: addi sp, sp, 16
46+
; RV64-GLIBC-NEXT: ret
47+
call void @llvm.clear_cache(ptr %a, ptr %b)
48+
ret void
49+
}

0 commit comments

Comments
 (0)