Skip to content

Commit 9e06d18

Browse files
committed
[LoongArch] Add intrinsics for CACOP instruction
The CACOP instruction is mainly used for cache initialization and cache-consistency maintenance. Depends on D140872 Reviewed By: SixWeining Differential Revision: https://reviews.llvm.org/D140527
1 parent a021db3 commit 9e06d18

18 files changed

+202
-7
lines changed

clang/include/clang/Basic/BuiltinsLoongArch.def

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
// TODO: Support more builtins.
1919
// TODO: Added feature constraints.
20+
TARGET_BUILTIN(__builtin_loongarch_cacop_d, "vLiULiLi", "nc", "64bit")
21+
TARGET_BUILTIN(__builtin_loongarch_cacop_w, "viUii", "nc", "32bit")
2022
TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "")
2123
TARGET_BUILTIN(__builtin_loongarch_ibar, "vIUi", "nc", "")
2224
TARGET_BUILTIN(__builtin_loongarch_movfcsr2gr, "UiIUi", "nc", "f")

clang/include/clang/Basic/DiagnosticSemaKinds.td

+2
Original file line numberDiff line numberDiff line change
@@ -11764,4 +11764,6 @@ def warn_unsafe_buffer_expression : Warning<
1176411764
def warn_unsafe_buffer_variable : Warning<
1176511765
"variable %0 participates in unchecked buffer operations">,
1176611766
InGroup<UnsafeBufferUsage>, DefaultIgnore;
11767+
def err_loongarch_builtin_requires_la32 : Error<
11768+
"this builtin requires target: loongarch32">;
1176711769
} // end of sema component.

clang/lib/Basic/Targets/LoongArch.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ bool LoongArchTargetInfo::initFeatureMap(
179179
const std::vector<std::string> &FeaturesVec) const {
180180
if (getTriple().getArch() == llvm::Triple::loongarch64)
181181
Features["64bit"] = true;
182+
if (getTriple().getArch() == llvm::Triple::loongarch32)
183+
Features["32bit"] = true;
182184

183185
return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec);
184186
}

clang/lib/CodeGen/CGBuiltin.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -19694,6 +19694,12 @@ Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID,
1969419694
switch (BuiltinID) {
1969519695
default:
1969619696
llvm_unreachable("unexpected builtin ID.");
19697+
case LoongArch::BI__builtin_loongarch_cacop_d:
19698+
ID = Intrinsic::loongarch_cacop_d;
19699+
break;
19700+
case LoongArch::BI__builtin_loongarch_cacop_w:
19701+
ID = Intrinsic::loongarch_cacop_w;
19702+
break;
1969719703
case LoongArch::BI__builtin_loongarch_dbar:
1969819704
ID = Intrinsic::loongarch_dbar;
1969919705
break;

clang/lib/Headers/larchintrin.h

+10
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,16 @@ extern __inline int
106106

107107
#define __break(/*ui15*/ _1) __builtin_loongarch_break((_1))
108108

109+
#if __loongarch_grlen == 32
110+
#define __cacop_w(/*uimm5*/ _1, /*unsigned int*/ _2, /*simm12*/ _3) \
111+
((void)__builtin_loongarch_cacop_w((_1), (unsigned int)(_2), (_3)))
112+
#endif
113+
114+
#if __loongarch_grlen == 64
115+
#define __cacop_d(/*uimm5*/ _1, /*unsigned long int*/ _2, /*simm12*/ _3) \
116+
((void)__builtin_loongarch_cacop_d((_1), (unsigned long int)(_2), (_3)))
117+
#endif
118+
109119
#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1))
110120

111121
#define __ibar(/*ui15*/ _1) __builtin_loongarch_ibar((_1))

clang/lib/Sema/SemaChecking.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -3705,6 +3705,23 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI,
37053705
switch (BuiltinID) {
37063706
default:
37073707
break;
3708+
case LoongArch::BI__builtin_loongarch_cacop_d:
3709+
if (!TI.hasFeature("64bit"))
3710+
return Diag(TheCall->getBeginLoc(),
3711+
diag::err_loongarch_builtin_requires_la64)
3712+
<< TheCall->getSourceRange();
3713+
LLVM_FALLTHROUGH;
3714+
case LoongArch::BI__builtin_loongarch_cacop_w: {
3715+
if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w &&
3716+
!TI.hasFeature("32bit"))
3717+
return Diag(TheCall->getBeginLoc(),
3718+
diag::err_loongarch_builtin_requires_la32)
3719+
<< TheCall->getSourceRange();
3720+
SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5));
3721+
SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12),
3722+
llvm::maxIntN(12));
3723+
break;
3724+
}
37083725
case LoongArch::BI__builtin_loongarch_crc_w_b_w:
37093726
case LoongArch::BI__builtin_loongarch_crc_w_h_w:
37103727
case LoongArch::BI__builtin_loongarch_crc_w_w_w:

clang/test/CodeGen/LoongArch/intrinsic-la32-error.c

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33

44
#include <larchintrin.h>
55

6+
void cacop_d(unsigned long int a) {
7+
__builtin_loongarch_cacop_d(1, a, 1024); // expected-error {{this builtin requires target: loongarch64}}
8+
__builtin_loongarch_cacop_w(-1, a, 1024); // expected-error {{argument value -1 is outside the valid range [0, 31]}}
9+
__builtin_loongarch_cacop_w(32, a, 1024); // expected-error {{argument value 32 is outside the valid range [0, 31]}}
10+
__builtin_loongarch_cacop_w(1, a, -4096); // expected-error {{argument value -4096 is outside the valid range [-2048, 2047]}}
11+
__builtin_loongarch_cacop_w(1, a, 4096); // expected-error {{argument value 4096 is outside the valid range [-2048, 2047]}}
12+
}
13+
614
void dbar(int a) {
715
__builtin_loongarch_dbar(32768); // expected-error {{argument value 32768 is outside the valid range [0, 32767]}}
816
__builtin_loongarch_dbar(-1); // expected-error {{argument value 4294967295 is outside the valid range [0, 32767]}}

clang/test/CodeGen/LoongArch/intrinsic-la32.c

+11
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,14 @@ void loongarch_movgr2fcsr(int a) {
200200
__movgr2fcsr(1, a);
201201
__builtin_loongarch_movgr2fcsr(1, a);
202202
}
203+
204+
// CHECK-LABEL: @cacop_w(
205+
// CHECK-NEXT: entry:
206+
// CHECK-NEXT: tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A:%.*]], i32 1024)
207+
// CHECK-NEXT: tail call void @llvm.loongarch.cacop.w(i32 1, i32 [[A]], i32 1024)
208+
// CHECK-NEXT: ret void
209+
//
210+
void cacop_w(unsigned long int a) {
211+
__cacop_w(1, a, 1024);
212+
__builtin_loongarch_cacop_w(1, a, 1024);
213+
}

clang/test/CodeGen/LoongArch/intrinsic-la64.c

+11
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ int crc_w_w_w(int a, int b) {
123123
return 0;
124124
}
125125

126+
// CHECK-LABEL: @cacop_d(
127+
// CHECK-NEXT: entry:
128+
// CHECK-NEXT: tail call void @llvm.loongarch.cacop.d(i64 1, i64 [[A:%.*]], i64 1024)
129+
// CHECK-NEXT: tail call void @llvm.loongarch.cacop.d(i64 1, i64 [[A]], i64 1024)
130+
// CHECK-NEXT: ret void
131+
//
132+
void cacop_d(unsigned long int a) {
133+
__cacop_d(1, a, 1024);
134+
__builtin_loongarch_cacop_d(1, a, 1024);
135+
}
136+
126137
// CHECK-LABEL: @crc_w_d_w(
127138
// CHECK-NEXT: entry:
128139
// CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.loongarch.crc.w.d.w(i64 [[A:%.*]], i32 [[B:%.*]])

clang/test/Driver/loongarch-default-features.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %clang --target=loongarch32 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=LA32
22
// RUN: %clang --target=loongarch64 -S -emit-llvm %s -o - | FileCheck %s --check-prefix=LA64
33

4-
// LA32-NOT: "target-features"=
4+
// LA32: "target-features"="+32bit"
55
// LA64: "target-features"="+64bit,+d,+f"
66

77
int foo(void) {

llvm/include/llvm/IR/IntrinsicsLoongArch.td

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics;
5252
// LoongArch BASE
5353

5454
def int_loongarch_break : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
55+
def int_loongarch_cacop_d : Intrinsic<[], [llvm_i64_ty, llvm_i64_ty, llvm_i64_ty],
56+
[ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<2>>]>;
57+
def int_loongarch_cacop_w : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
58+
[ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<2>>]>;
5559
def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
5660
def int_loongarch_ibar : Intrinsic<[], [llvm_i32_ty], [ImmArg<ArgIndex<0>>]>;
5761
def int_loongarch_movfcsr2gr : Intrinsic<[llvm_i32_ty], [llvm_i32_ty],

llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp

+28-1
Original file line numberDiff line numberDiff line change
@@ -746,13 +746,38 @@ SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op,
746746
SDLoc DL(Op);
747747
MVT GRLenVT = Subtarget.getGRLenVT();
748748
SDValue Op0 = Op.getOperand(0);
749+
uint64_t IntrinsicEnum = Op.getConstantOperandVal(1);
749750
SDValue Op2 = Op.getOperand(2);
750751
const StringRef ErrorMsgOOR = "out of range";
751752

752-
switch (Op.getConstantOperandVal(1)) {
753+
switch (IntrinsicEnum) {
753754
default:
754755
// TODO: Add more Intrinsics.
755756
return SDValue();
757+
case Intrinsic::loongarch_cacop_d:
758+
case Intrinsic::loongarch_cacop_w: {
759+
if (IntrinsicEnum == Intrinsic::loongarch_cacop_d && !Subtarget.is64Bit()) {
760+
DAG.getContext()->emitError(
761+
"llvm.loongarch.cacop.d requires target: loongarch64");
762+
return Op.getOperand(0);
763+
}
764+
if (IntrinsicEnum == Intrinsic::loongarch_cacop_w && Subtarget.is64Bit()) {
765+
DAG.getContext()->emitError(
766+
"llvm.loongarch.cacop.w requires target: loongarch32");
767+
return Op.getOperand(0);
768+
}
769+
// call void @llvm.loongarch.cacop.[d/w](uimm5, rj, simm12)
770+
unsigned Imm1 = cast<ConstantSDNode>(Op2)->getZExtValue();
771+
if (!isUInt<5>(Imm1))
772+
return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
773+
SDValue Op4 = Op.getOperand(4);
774+
int Imm2 = cast<ConstantSDNode>(Op4)->getSExtValue();
775+
if (!isInt<12>(Imm2))
776+
return emitIntrinsicErrorMessage(Op, ErrorMsgOOR, DAG);
777+
778+
return Op;
779+
}
780+
756781
case Intrinsic::loongarch_dbar: {
757782
unsigned Imm = cast<ConstantSDNode>(Op2)->getZExtValue();
758783
if (!isUInt<15>(Imm))
@@ -1778,6 +1803,8 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
17781803
NODE_NAME_CASE(CPUCFG)
17791804
NODE_NAME_CASE(MOVGR2FCSR)
17801805
NODE_NAME_CASE(MOVFCSR2GR)
1806+
NODE_NAME_CASE(CACOP_D)
1807+
NODE_NAME_CASE(CACOP_W)
17811808
}
17821809
#undef NODE_NAME_CASE
17831810
return nullptr;

llvm/lib/Target/LoongArch/LoongArchISelLowering.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ enum NodeType : unsigned {
6161
BITREV_4B,
6262
BITREV_W,
6363

64-
// Intrinsic operations
64+
// Intrinsic operations start ============================================
6565
BREAK,
66+
CACOP_D,
67+
CACOP_W,
6668
DBAR,
6769
IBAR,
6870
SYSCALL,
@@ -93,6 +95,7 @@ enum NodeType : unsigned {
9395

9496
// Read CPU configuration information operation
9597
CPUCFG,
98+
// Intrinsic operations end =============================================
9699
};
97100
} // end namespace LoongArchISD
98101

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td

+8-4
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,10 @@ def RDTIMEL_W : RDTIME_2R<0b0000000000000000011000, "rdtimel.w">;
589589
def RDTIMEH_W : RDTIME_2R<0b0000000000000000011001, "rdtimeh.w">;
590590
def CPUCFG : ALU_2R<0b0000000000000000011011, "cpucfg">;
591591

592+
// Cache Maintenance Instructions
593+
def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12), "cacop",
594+
"$op, $rj, $imm12">;
595+
592596
/// LA64 instructions
593597

594598
let Predicates = [IsLA64] in {
@@ -1563,6 +1567,10 @@ defm : PseudoBinPat<"atomic_load_xor_32", PseudoAtomicLoadXor32>;
15631567

15641568
/// Intrinsics
15651569

1570+
def : Pat<(int_loongarch_cacop_d timm:$op, i64:$rj, timm:$imm12),
1571+
(CACOP uimm5:$op, GPR:$rj, simm12:$imm12)>;
1572+
def : Pat<(int_loongarch_cacop_w i32:$op, i32:$rj, i32:$imm12),
1573+
(CACOP uimm5:$op, GPR:$rj, simm12:$imm12)>;
15661574
def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>;
15671575
def : Pat<(loongarch_ibar uimm15:$imm15), (IBAR uimm15:$imm15)>;
15681576
def : Pat<(loongarch_break uimm15:$imm15), (BREAK uimm15:$imm15)>;
@@ -1673,10 +1681,6 @@ def IOCSRRD_D : IOCSRRD<0b0000011001001000000011, "iocsrrd.d">;
16731681
def IOCSRWR_D : IOCSRWR<0b0000011001001000000111, "iocsrwr.d">;
16741682
} // Predicates = [IsLA64]
16751683

1676-
// Cache Maintenance Instructions
1677-
def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12), "cacop",
1678-
"$op, $rj, $imm12">;
1679-
16801684
// TLB Maintenance Instructions
16811685
def TLBSRCH : FmtI32<0b00000110010010000010100000000000, "tlbsrch">;
16821686
def TLBRD : FmtI32<0b00000110010010000010110000000000, "tlbrd">;

llvm/test/CodeGen/LoongArch/intrinsic-la32-error.ll

+29
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s
22

3+
declare void @llvm.loongarch.cacop.w(i32, i32, i32)
34
declare i32 @llvm.loongarch.crc.w.b.w(i32, i32)
45
declare i32 @llvm.loongarch.crc.w.h.w(i32, i32)
56
declare i32 @llvm.loongarch.crc.w.w.w(i32, i32)
@@ -18,6 +19,34 @@ declare void @llvm.loongarch.asrtgt.d(i64, i64)
1819
declare i64 @llvm.loongarch.lddir.d(i64, i32)
1920
declare void @llvm.loongarch.ldpte.d(i64, i32)
2021

22+
define void @cacop_arg0_out_of_hi_range(i32 %a) nounwind {
23+
; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
24+
entry:
25+
call void @llvm.loongarch.cacop.w(i32 32, i32 %a, i32 1024)
26+
ret void
27+
}
28+
29+
define void @cacop_arg0_out_of_lo_range(i32 %a) nounwind {
30+
; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
31+
entry:
32+
call void @llvm.loongarch.cacop.w(i32 -1, i32 %a, i32 1024)
33+
ret void
34+
}
35+
36+
define void @cacop_arg2_out_of_hi_range(i32 %a) nounwind {
37+
; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
38+
entry:
39+
call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4096)
40+
ret void
41+
}
42+
43+
define void @cacop_arg2_out_of_lo_range(i32 %a) nounwind {
44+
; CHECK: argument to 'llvm.loongarch.cacop.w' out of range
45+
entry:
46+
call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 -4096)
47+
ret void
48+
}
49+
2150
define i32 @crc_w_b_w(i32 %a, i32 %b) nounwind {
2251
; CHECK: llvm.loongarch.crc.w.b.w requires target: loongarch64
2352
entry:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s
3+
4+
declare void @llvm.loongarch.cacop.w(i32, i32, i32)
5+
6+
define void @cacop_w(i32 %a) nounwind {
7+
; CHECK-LABEL: cacop_w:
8+
; CHECK: # %bb.0:
9+
; CHECK-NEXT: cacop 1, $a0, 4
10+
; CHECK-NEXT: ret
11+
call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4)
12+
ret void
13+
}

llvm/test/CodeGen/LoongArch/intrinsic-la64-error.ll

+36
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
22
; RUN: not llc --mtriple=loongarch64 < %s 2>&1 | FileCheck %s
33

4+
declare void @llvm.loongarch.cacop.w(i32, i32, i32)
5+
declare void @llvm.loongarch.cacop.d(i64, i64, i64)
46
declare i64 @llvm.loongarch.csrrd.d(i32 immarg)
57
declare i64 @llvm.loongarch.csrwr.d(i64, i32 immarg)
68
declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg)
@@ -46,3 +48,37 @@ entry:
4648
%0 = call i64 @llvm.loongarch.csrxchg.d(i64 %a, i64 %b, i32 -1)
4749
ret i64 %0
4850
}
51+
52+
define void @cacop_w(i32 %a) nounwind {
53+
; CHECK: llvm.loongarch.cacop.w requires target: loongarch32
54+
call void @llvm.loongarch.cacop.w(i32 1, i32 %a, i32 4)
55+
ret void
56+
}
57+
58+
define void @cacop_arg0_out_of_hi_range(i64 %a) nounwind {
59+
; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
60+
entry:
61+
call void @llvm.loongarch.cacop.d(i64 32, i64 %a, i64 1024)
62+
ret void
63+
}
64+
65+
define void @cacop_arg0_out_of_lo_range(i64 %a) nounwind {
66+
; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
67+
entry:
68+
call void @llvm.loongarch.cacop.d(i64 -1, i64 %a, i64 1024)
69+
ret void
70+
}
71+
72+
define void @cacop_arg2_out_of_hi_range(i64 %a) nounwind {
73+
; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
74+
entry:
75+
call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 4096)
76+
ret void
77+
}
78+
79+
define void @cacop_arg2_out_of_lo_range(i64 %a) nounwind {
80+
; CHECK: argument to 'llvm.loongarch.cacop.d' out of range
81+
entry:
82+
call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 -4096)
83+
ret void
84+
}

llvm/test/CodeGen/LoongArch/intrinsic-la64.ll

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
22
; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s
33

4+
declare void @llvm.loongarch.cacop.d(i64, i64, i64)
45
declare i32 @llvm.loongarch.crc.w.b.w(i32, i32)
56
declare i32 @llvm.loongarch.crc.w.h.w(i32, i32)
67
declare i32 @llvm.loongarch.crc.w.w.w(i32, i32)
@@ -46,6 +47,15 @@ define i32 @crc_w_w_w(i32 %a, i32 %b) nounwind {
4647
ret i32 %res
4748
}
4849

50+
define void @cacop_d(i64 %a) nounwind {
51+
; CHECK-LABEL: cacop_d:
52+
; CHECK: # %bb.0:
53+
; CHECK-NEXT: cacop 1, $a0, 4
54+
; CHECK-NEXT: ret
55+
call void @llvm.loongarch.cacop.d(i64 1, i64 %a, i64 4)
56+
ret void
57+
}
58+
4959
define i32 @crc_w_d_w(i64 %a, i32 %b) nounwind {
5060
; CHECK-LABEL: crc_w_d_w:
5161
; CHECK: # %bb.0:

0 commit comments

Comments
 (0)