Skip to content

Commit 13f307a

Browse files
committed
[RISCV] Initial support for EarlyCSE
This patch supports initial EarlyCSE for RISCV Note: * Add two TTI hook `getTgtMemIntrinsic` and `getOrCreateResultFromMemIntrinsic` * Add one test case intrinsics.ll in llvm/test/Transforms/EarlyCSE/RISCV/
1 parent e55172f commit 13f307a

File tree

3 files changed

+95
-1
lines changed

3 files changed

+95
-1
lines changed

llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/CodeGen/TargetLowering.h"
1616
#include "llvm/CodeGen/ValueTypes.h"
1717
#include "llvm/IR/Instructions.h"
18+
#include "llvm/IR/IntrinsicsRISCV.h"
1819
#include "llvm/IR/PatternMatch.h"
1920
#include <cmath>
2021
#include <optional>
@@ -116,6 +117,50 @@ RISCVTTIImpl::getRISCVInstructionCost(ArrayRef<unsigned> OpCodes, MVT VT,
116117
return Cost;
117118
}
118119

120+
Value *
121+
RISCVTTIImpl::getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
122+
Type *ExpectedType) const {
123+
Intrinsic::ID IID = Inst->getIntrinsicID();
124+
switch (IID) {
125+
default:
126+
return nullptr;
127+
// TODO: Add more memory intrinsic operations.
128+
case Intrinsic::riscv_vle: {
129+
if (Inst->getType() == ExpectedType)
130+
return Inst;
131+
}
132+
return nullptr;
133+
}
134+
}
135+
136+
bool RISCVTTIImpl::getTgtMemIntrinsic(IntrinsicInst *Inst,
137+
MemIntrinsicInfo &Info) const {
138+
Intrinsic::ID IID = Inst->getIntrinsicID();
139+
switch (IID) {
140+
default:
141+
return false;
142+
case Intrinsic::riscv_vle: {
143+
// Intrinsic interface:
144+
// riscv_vle(merge, ptr, vl)
145+
Info.ReadMem = true;
146+
Info.WriteMem = false;
147+
Info.PtrVal = Inst->getArgOperand(1);
148+
Info.MatchingId = VECTOR_VLE_VSE;
149+
break;
150+
}
151+
case Intrinsic::riscv_vse: {
152+
// Intrinsic interface:
153+
// riscv_vse(val, ptr, vl)
154+
Info.ReadMem = false;
155+
Info.WriteMem = true;
156+
Info.PtrVal = Inst->getArgOperand(1);
157+
Info.MatchingId = VECTOR_VLE_VSE;
158+
break;
159+
}
160+
}
161+
return true;
162+
}
163+
119164
static InstructionCost getIntImmCostImpl(const DataLayout &DL,
120165
const RISCVSubtarget *ST,
121166
const APInt &Imm, Type *Ty,

llvm/lib/Target/RISCV/RISCVTargetTransformInfo.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> {
3737
const RISCVSubtarget *getST() const { return ST; }
3838
const RISCVTargetLowering *getTLI() const { return TLI; }
3939

40+
enum MemIntrinsicType { VECTOR_VLE_VSE };
41+
4042
/// This function returns an estimate for VL to be used in VL based terms
4143
/// of the cost model. For fixed length vectors, this is simply the
4244
/// vector length. For scalable vectors, we return results consistent
@@ -156,7 +158,12 @@ class RISCVTTIImpl : public BasicTTIImplBase<RISCVTTIImpl> {
156158
void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
157159
TTI::PeelingPreferences &PP) const override;
158160

159-
unsigned getMinVectorRegisterBitWidth() const override {
161+
Value *getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst,
162+
Type *ExpectedType) const override;
163+
164+
bool getTgtMemIntrinsic(IntrinsicInst *Inst, MemIntrinsicInfo &Info) const;
165+
166+
unsigned getMinVectorRegisterBitWidth() const {
160167
return ST->useRVVForFixedLengthVectors() ? 16 : 0;
161168
}
162169

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -S -mtriple=riscv64 -mattr=+v -passes=early-cse -earlycse-debug-hash | FileCheck %s
3+
; RUN: opt < %s -S -mtriple=riscv64 -mattr=+v -aa-pipeline=basic-aa -passes='early-cse<memssa>' | FileCheck %s
4+
5+
define <vscale x 2 x i32> @test_cse(ptr noundef %base) {
6+
; CHECK-LABEL: define <vscale x 2 x i32> @test_cse(
7+
; CHECK-SAME: ptr noundef [[BASE:%.*]]) #[[ATTR0:[0-9]+]] {
8+
; CHECK-NEXT: [[ENTRY:.*:]]
9+
; CHECK-NEXT: [[TMP0:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr [[BASE]], i64 8)
10+
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> [[TMP0]], <vscale x 2 x i32> [[TMP0]], i64 8)
11+
; CHECK-NEXT: ret <vscale x 2 x i32> [[TMP1]]
12+
;
13+
entry:
14+
%0 = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr %base, i64 8)
15+
%1 = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr %base, i64 8)
16+
%2 = call <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> %0, <vscale x 2 x i32> %1, i64 8)
17+
ret <vscale x 2 x i32> %2
18+
}
19+
20+
define <vscale x 2 x i32> @test_no_cse(ptr noundef %a, ptr noundef %b) {
21+
; CHECK-LABEL: define <vscale x 2 x i32> @test_no_cse(
22+
; CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]]) #[[ATTR0]] {
23+
; CHECK-NEXT: [[ENTRY:.*:]]
24+
; CHECK-NEXT: [[TMP0:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr [[A]], i64 8)
25+
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr [[B]], i64 8)
26+
; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> [[TMP0]], <vscale x 2 x i32> [[TMP1]], i64 8)
27+
; CHECK-NEXT: ret <vscale x 2 x i32> [[TMP2]]
28+
;
29+
entry:
30+
%0 = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr %a, i64 8)
31+
%1 = call <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32> poison, ptr %b, i64 8)
32+
%2 = call <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32.nxv2i32.i64(<vscale x 2 x i32> poison, <vscale x 2 x i32> %0, <vscale x 2 x i32> %1, i64 8)
33+
ret <vscale x 2 x i32> %2
34+
}
35+
36+
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: read)
37+
declare <vscale x 2 x i32> @llvm.riscv.vle.nxv2i32.i64(<vscale x 2 x i32>, ptr captures(none), i64) #1
38+
39+
; Function Attrs: nocallback nofree nosync nounwind willreturn memory(none)
40+
declare <vscale x 2 x i32> @llvm.riscv.vadd.nxv2i32.nxv2i32.i64(<vscale x 2 x i32>, <vscale x 2 x i32>, <vscale x 2 x i32>, i64) #2
41+
42+

0 commit comments

Comments
 (0)