diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index 695ecf9da5f8..9d223c3e8516 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -50,4 +50,7 @@ BUILTIN(__builtin_arm_dmb, "vUi", "nc") BUILTIN(__builtin_arm_dsb, "vUi", "nc") BUILTIN(__builtin_arm_isb, "vUi", "nc") +// Prefetch +BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc") + #undef BUILTIN diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 092c44f5c28e..99f4b21ff7e4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3854,6 +3854,29 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID)); } + if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *RW = EmitScalarExpr(E->getArg(1)); + Value *CacheLevel = EmitScalarExpr(E->getArg(2)); + Value *RetentionPolicy = EmitScalarExpr(E->getArg(3)); + Value *IsData = EmitScalarExpr(E->getArg(4)); + + Value *Locality = nullptr; + if (cast(RetentionPolicy)->isZero()) { + // Temporal fetch, needs to convert cache level to locality. + Locality = llvm::ConstantInt::get(Int32Ty, + -cast(CacheLevel)->getValue() + 3); + } else { + // Streaming fetch. + Locality = llvm::ConstantInt::get(Int32Ty, 0); + } + + // FIXME: We need AArch64 specific LLVM intrinsic if we want to specify + // PLDL3STRM or PLDL2STRM. + Value *F = CGM.getIntrinsic(Intrinsic::prefetch); + return Builder.CreateCall4(F, Address, RW, Locality, IsData); + } + if (BuiltinID == AArch64::BI__builtin_arm_rbit) { assert((getContext().getTypeSize(E->getType()) == 32) && "rbit of unusual size!"); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index abda2d26649a..95411f568818 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -661,6 +661,13 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); } + if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) || + SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); + } + if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; diff --git a/clang/test/CodeGen/builtins-arm64.c b/clang/test/CodeGen/builtins-arm64.c index cfa118122793..cc1f54732b30 100644 --- a/clang/test/CodeGen/builtins-arm64.c +++ b/clang/test/CodeGen/builtins-arm64.c @@ -29,3 +29,17 @@ void barriers() { __builtin_arm_dsb(2); //CHECK: call {{.*}} @llvm.aarch64.dsb(i32 2) __builtin_arm_isb(3); //CHECK: call {{.*}} @llvm.aarch64.isb(i32 3) } + +void prefetch() { + __builtin_arm_prefetch(0, 1, 2, 0, 1); // pstl3keep +// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 1, i32 1, i32 1) + + __builtin_arm_prefetch(0, 0, 0, 1, 1); // pldl1keep +// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 0, i32 1) + + __builtin_arm_prefetch(0, 0, 0, 1, 1); // pldl1strm +// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 0, i32 1) + + __builtin_arm_prefetch(0, 0, 0, 0, 0); // plil1keep +// CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 3, i32 0) +} diff --git a/clang/test/Sema/builtins-arm64.c b/clang/test/Sema/builtins-arm64.c index 113f4fc302da..2779984680f4 100644 --- a/clang/test/Sema/builtins-arm64.c +++ b/clang/test/Sema/builtins-arm64.c @@ -22,3 +22,10 @@ void test_memory_barriers() { __builtin_arm_dsb(17); // expected-error {{argument should be a value from 0 to 15}} __builtin_arm_isb(18); // expected-error {{argument should be a value from 0 to 15}} } + +void test_prefetch() { + __builtin_arm_prefetch(0, 2, 0, 0, 0); // expected-error {{argument should be a value from 0 to 1}} + __builtin_arm_prefetch(0, 0, 3, 0, 0); // expected-error {{argument should be a value from 0 to 2}} + __builtin_arm_prefetch(0, 0, 0, 2, 0); // expected-error {{argument should be a value from 0 to 1}} + __builtin_arm_prefetch(0, 0, 0, 0, 2); // expected-error {{argument should be a value from 0 to 1}} +}