[llvm] [RISCV][GlobalISel] Legalize and select G_PREFETCH (PR #215466)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 10 23:20:05 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Kane Wang (ReVe1uv)
<details>
<summary>Changes</summary>
GlobalISel aborted on `llvm.prefetch` ("unable to legalize `G_PREFETCH`") while SDAG lowers it to `prefetch.r/w/i`. Add a legalizer rule marking `G_PREFETCH` legal for p0 addresses, and a custom selector since the SDAG patterns use the `AddrRegImmLsb00000` complex pattern that the GISel pattern importer does not auto-translate. The selector picks `prefetch.r/w/i` from the rw/cache-type immediates and folds a `simm12_lsb00000` offset when present, matching SDAG.
---
Full diff: https://github.com/llvm/llvm-project/pull/215466.diff
4 Files Affected:
- (modified) llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp (+46)
- (modified) llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (+2)
- (modified) llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir (+2-2)
- (added) llvm/test/CodeGen/RISCV/GlobalISel/prefetch.ll (+116)
``````````diff
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 16af89c715861..9b830a2b6a70f 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -98,6 +98,7 @@ class RISCVInstructionSelector : public InstructionSelector {
bool selectIntrinsic(MachineInstr &I) const;
bool selectExtractSubvector(MachineInstr &MI) const;
bool selectInsertSubVector(MachineInstr &I) const;
+ bool selectPrefetch(MachineInstr &MI) const;
ComplexRendererFns selectShiftMask(MachineOperand &Root,
unsigned ShiftWidth) const;
ComplexRendererFns selectShiftMaskXLen(MachineOperand &Root) const {
@@ -1444,11 +1445,56 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
return selectExtractSubvector(MI);
case TargetOpcode::G_INSERT_SUBVECTOR:
return selectInsertSubVector(MI);
+ case TargetOpcode::G_PREFETCH:
+ return selectPrefetch(MI);
default:
return false;
}
}
+bool RISCVInstructionSelector::selectPrefetch(MachineInstr &MI) const {
+ assert(MI.getOpcode() == TargetOpcode::G_PREFETCH);
+ int64_t IsWrite = MI.getOperand(1).getImm();
+ int64_t IsData = MI.getOperand(3).getImm();
+ unsigned Opc;
+ if (!IsData)
+ Opc = RISCV::PREFETCH_I;
+ else if (!IsWrite)
+ Opc = RISCV::PREFETCH_R;
+ else
+ Opc = RISCV::PREFETCH_W;
+
+ Register AddrReg = MI.getOperand(0).getReg();
+ MachineInstr *Def = MRI->getVRegDef(AddrReg);
+
+ MachineOperand Base = MachineOperand::CreateReg(AddrReg, false);
+ int64_t Offset = 0;
+ if (Def && Def->getOpcode() == TargetOpcode::G_FRAME_INDEX) {
+ Base = Def->getOperand(1);
+ } else if (Def && isBaseWithConstantOffset(MI.getOperand(0), *MRI)) {
+ MachineOperand &BaseMO = Def->getOperand(1);
+ MachineInstr *RHSDef = MRI->getVRegDef(Def->getOperand(2).getReg());
+ int64_t C = RHSDef->getOperand(1).getCImm()->getSExtValue();
+ if (C % 32 == 0 && isInt<12>(C)) {
+ // Fold frame index + offset if the base is a G_FRAME_INDEX.
+ if (MachineInstr *BaseDef = MRI->getVRegDef(BaseMO.getReg());
+ BaseDef && BaseDef->getOpcode() == TargetOpcode::G_FRAME_INDEX)
+ Base = BaseDef->getOperand(1);
+ else
+ Base = BaseMO;
+ Offset = C;
+ }
+ }
+
+ MachineInstr *SelectedMI =
+ BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII.get(Opc))
+ .add(Base)
+ .addImm(Offset);
+ MI.eraseFromParent();
+ constrainSelectedInstRegOperands(*SelectedMI, TII, TRI, RBI);
+ return true;
+}
+
bool RISCVInstructionSelector::selectUnmergeValues(MachineInstr &MI) const {
assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index c5459d862b03f..78d96d69344e6 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -777,6 +777,8 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
.clampScalar(0, sXLen, sXLen)
.unsupported();
+ getActionDefinitionsBuilder(G_PREFETCH).legalFor({p0});
+
LegalityPredicate InsertVectorEltPred = [=](const LegalityQuery &Query) {
LLT VecTy = Query.Types[0];
LLT EltTy = Query.Types[1];
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
index 1770bc6430eb9..280ec7cd1e0f5 100644
--- a/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/legalizer-info-validation.mir
@@ -321,8 +321,8 @@
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: G_PREFETCH (opcode {{[0-9]+}}): 1 type index, 0 imm indices
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# DEBUG-NEXT: .. the first uncovered type index: 1, OK
+# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
# DEBUG-NEXT: G_BRCOND (opcode {{[0-9]+}}): 1 type index, 0 imm indices
# DEBUG-NEXT: .. the first uncovered type index: 1, OK
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/prefetch.ll b/llvm/test/CodeGen/RISCV/GlobalISel/prefetch.ll
new file mode 100644
index 0000000000000..c725b37c0812f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/prefetch.ll
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+zicbop -global-isel -global-isel-abort=1 \
+; RUN: < %s | FileCheck %s --check-prefix=RV32ZICBOP
+; RUN: llc -mtriple=riscv64 -mattr=+zicbop -global-isel -global-isel-abort=1 \
+; RUN: < %s | FileCheck %s --check-prefix=RV64ZICBOP
+; RUN: llc -mtriple=riscv64 -global-isel -global-isel-abort=1 \
+; RUN: < %s | FileCheck %s --check-prefix=RV64
+
+; prefetch hints are available even without Zicbop per the psABI, so the
+; RV64 run (no +zicbop) still emits prefetch.r/w/i.
+
+define void @prefetch_r(ptr %a) nounwind {
+; RV32ZICBOP-LABEL: prefetch_r:
+; RV32ZICBOP: # %bb.0:
+; RV32ZICBOP-NEXT: prefetch.r 0(a0)
+; RV32ZICBOP-NEXT: ret
+;
+; RV64ZICBOP-LABEL: prefetch_r:
+; RV64ZICBOP: # %bb.0:
+; RV64ZICBOP-NEXT: prefetch.r 0(a0)
+; RV64ZICBOP-NEXT: ret
+;
+; RV64-LABEL: prefetch_r:
+; RV64: # %bb.0:
+; RV64-NEXT: prefetch.r 0(a0)
+; RV64-NEXT: ret
+ call void @llvm.prefetch(ptr %a, i32 0, i32 3, i32 1)
+ ret void
+}
+
+define void @prefetch_w(ptr %a) nounwind {
+; RV32ZICBOP-LABEL: prefetch_w:
+; RV32ZICBOP: # %bb.0:
+; RV32ZICBOP-NEXT: prefetch.w 0(a0)
+; RV32ZICBOP-NEXT: ret
+;
+; RV64ZICBOP-LABEL: prefetch_w:
+; RV64ZICBOP: # %bb.0:
+; RV64ZICBOP-NEXT: prefetch.w 0(a0)
+; RV64ZICBOP-NEXT: ret
+;
+; RV64-LABEL: prefetch_w:
+; RV64: # %bb.0:
+; RV64-NEXT: prefetch.w 0(a0)
+; RV64-NEXT: ret
+ call void @llvm.prefetch(ptr %a, i32 1, i32 3, i32 1)
+ ret void
+}
+
+define void @prefetch_i(ptr %a) nounwind {
+; RV32ZICBOP-LABEL: prefetch_i:
+; RV32ZICBOP: # %bb.0:
+; RV32ZICBOP-NEXT: prefetch.i 0(a0)
+; RV32ZICBOP-NEXT: ret
+;
+; RV64ZICBOP-LABEL: prefetch_i:
+; RV64ZICBOP: # %bb.0:
+; RV64ZICBOP-NEXT: prefetch.i 0(a0)
+; RV64ZICBOP-NEXT: ret
+;
+; RV64-LABEL: prefetch_i:
+; RV64: # %bb.0:
+; RV64-NEXT: prefetch.i 0(a0)
+; RV64-NEXT: ret
+ call void @llvm.prefetch(ptr %a, i32 0, i32 3, i32 0)
+ ret void
+}
+
+; A constant offset that is a multiple of 32 (simm12_lsb00000) folds into the
+; prefetch immediate.
+define void @prefetch_r_aligned_offset(ptr %a) nounwind {
+; RV32ZICBOP-LABEL: prefetch_r_aligned_offset:
+; RV32ZICBOP: # %bb.0:
+; RV32ZICBOP-NEXT: prefetch.r 64(a0)
+; RV32ZICBOP-NEXT: ret
+;
+; RV64ZICBOP-LABEL: prefetch_r_aligned_offset:
+; RV64ZICBOP: # %bb.0:
+; RV64ZICBOP-NEXT: prefetch.r 64(a0)
+; RV64ZICBOP-NEXT: ret
+;
+; RV64-LABEL: prefetch_r_aligned_offset:
+; RV64: # %bb.0:
+; RV64-NEXT: prefetch.r 64(a0)
+; RV64-NEXT: ret
+ %q = getelementptr i8, ptr %a, i32 64
+ call void @llvm.prefetch(ptr %q, i32 0, i32 3, i32 1)
+ ret void
+}
+
+; An offset that is not a multiple of 32 cannot be encoded in simm12_lsb00000;
+; the address is materialized with an ADDI and a zero offset is used.
+define void @prefetch_r_nonaligned_offset(ptr %a) nounwind {
+; RV32ZICBOP-LABEL: prefetch_r_nonaligned_offset:
+; RV32ZICBOP: # %bb.0:
+; RV32ZICBOP-NEXT: addi a0, a0, 4
+; RV32ZICBOP-NEXT: prefetch.r 0(a0)
+; RV32ZICBOP-NEXT: ret
+;
+; RV64ZICBOP-LABEL: prefetch_r_nonaligned_offset:
+; RV64ZICBOP: # %bb.0:
+; RV64ZICBOP-NEXT: addi a0, a0, 4
+; RV64ZICBOP-NEXT: prefetch.r 0(a0)
+; RV64ZICBOP-NEXT: ret
+;
+; RV64-LABEL: prefetch_r_nonaligned_offset:
+; RV64: # %bb.0:
+; RV64-NEXT: addi a0, a0, 4
+; RV64-NEXT: prefetch.r 0(a0)
+; RV64-NEXT: ret
+ %q = getelementptr i8, ptr %a, i32 4
+ call void @llvm.prefetch(ptr %q, i32 0, i32 3, i32 1)
+ ret void
+}
+
+declare void @llvm.prefetch(ptr, i32, i32, i32)
``````````
</details>
https://github.com/llvm/llvm-project/pull/215466
More information about the llvm-commits
mailing list