diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8432,6 +8432,8 @@ "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2; did you mean %3?">; +def err_typecheck_call_inst_cache_must_read_only : Error< + "instruction cache must be read only">; def err_arc_typecheck_convert_incompatible_pointer : Error< "incompatible pointer types passing retainable parameter of type %0" diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -2917,13 +2917,14 @@ /*EmittedE=*/nullptr, IsDynamic)); } case Builtin::BI__builtin_prefetch: { - Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0)); + Value *Locality, *RW, *Data, *Address = EmitScalarExpr(E->getArg(0)); // FIXME: Technically these constants should of type 'int', yes? RW = (E->getNumArgs() > 1) ? EmitScalarExpr(E->getArg(1)) : llvm::ConstantInt::get(Int32Ty, 0); Locality = (E->getNumArgs() > 2) ? EmitScalarExpr(E->getArg(2)) : llvm::ConstantInt::get(Int32Ty, 3); - Value *Data = llvm::ConstantInt::get(Int32Ty, 1); + Data = (E->getNumArgs() > 3) ? EmitScalarExpr(E->getArg(3)) : + llvm::ConstantInt::get(Int32Ty, 1); Function *F = CGM.getIntrinsic(Intrinsic::prefetch, Address->getType()); return RValue::get(Builder.CreateCall(F, {Address, RW, Locality, Data})); } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7571,17 +7571,46 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); - if (NumArgs > 3) + if (NumArgs > 4) return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most) - << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange(); + << 0 /*function call*/ << 4 << NumArgs << TheCall->getSourceRange(); + + auto SemaBuiltinConstantArgRange = + [this, TheCall](int ArgNum, int Low, int High, int &Val) -> bool { + if (isConstantEvaluated()) + return false; + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + Val = Result.getSExtValue(); + if (Val < Low || Val > High) + return Diag(TheCall->getBeginLoc(), diag::err_argument_invalid_range) + << Val << Low << High << Arg->getSourceRange(); + + return false; + }; // Argument 0 is checked for us and the remaining arguments must be // constant integers. + int Vals[3] = {0, 0, 1}; for (unsigned i = 1; i != NumArgs; ++i) - if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) + if (SemaBuiltinConstantArgRange(i, 0, i == 2 ? 3 : 1, Vals[i - 1])) return true; + if (Vals[0] == 1 && Vals[2] == 0) + return Diag(TheCall->getEndLoc(), + diag::err_typecheck_call_inst_cache_must_read_only) + << TheCall->getSourceRange(); + return false; } diff --git a/clang/test/CodeGen/builtins-arm.c b/clang/test/CodeGen/builtins-arm.c --- a/clang/test/CodeGen/builtins-arm.c +++ b/clang/test/CodeGen/builtins-arm.c @@ -97,8 +97,8 @@ __builtin_arm_prefetch(&i, 1, 1); // CHECK: call {{.*}} @llvm.prefetch.p0(ptr %{{.*}}, i32 1, i32 3, i32 1) - __builtin_arm_prefetch(&i, 1, 0); - // CHECK: call {{.*}} @llvm.prefetch.p0(ptr %{{.*}}, i32 1, i32 3, i32 0) + __builtin_arm_prefetch(&i, 0, 0); + // CHECK: call {{.*}} @llvm.prefetch.p0(ptr %{{.*}}, i32 0, i32 3, i32 0) } void ldc(const void *i) { diff --git a/clang/test/Sema/builtin-prefetch.c b/clang/test/Sema/builtin-prefetch.c --- a/clang/test/Sema/builtin-prefetch.c +++ b/clang/test/Sema/builtin-prefetch.c @@ -4,11 +4,13 @@ int a; __builtin_prefetch(&a); __builtin_prefetch(&a, 1); - __builtin_prefetch(&a, 1, 2); - __builtin_prefetch(&a, 1, 9, 3); // expected-error{{too many arguments to function}} + __builtin_prefetch(&a, 0, 2, 1); + __builtin_prefetch(&a, 1, 2, 0); // expected-error{{instruction cache must be read only}} + __builtin_prefetch(&a, 1, 9, 8, 3); // expected-error{{too many arguments to function}} __builtin_prefetch(&a, "hello", 2); // expected-error{{argument to '__builtin_prefetch' must be a constant integer}} __builtin_prefetch(&a, a, 2); // expected-error{{argument to '__builtin_prefetch' must be a constant integer}} __builtin_prefetch(&a, 2); // expected-error{{argument value 2 is outside the valid range [0, 1]}} __builtin_prefetch(&a, 0, 4); // expected-error{{argument value 4 is outside the valid range [0, 3]}} __builtin_prefetch(&a, -1, 4); // expected-error{{argument value -1 is outside the valid range [0, 1]}} + __builtin_prefetch(&a, 1, 2, 3); // expected-error{{argument value 3 is outside the valid range [0, 1]}} } diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -13163,8 +13163,9 @@ ``locality`` is a temporal locality specifier ranging from (0) - no locality, to (3) - extremely local keep in cache. The ``cache type`` specifies whether the prefetch is performed on the data (1) or -instruction (0) cache. The ``rw``, ``locality`` and ``cache type`` -arguments must be constant integers. +instruction (0) cache. When ``cache type`` is instruction, the ``rw`` +must be read. The ``rw``, ``locality`` and ``cache type`` arguments +must be constant integers. Semantics: """""""""" diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -5175,14 +5175,16 @@ "llvm.init_trampoline parameter #2 must resolve to a function.", Call); break; - case Intrinsic::prefetch: - Check(cast(Call.getArgOperand(1))->getZExtValue() < 2, - "rw argument to llvm.prefetch must be 0-1", Call); - Check(cast(Call.getArgOperand(2))->getZExtValue() < 4, - "locality argument to llvm.prefetch must be 0-4", Call); - Check(cast(Call.getArgOperand(3))->getZExtValue() < 2, - "cache type argument to llvm.prefetch must be 0-1", Call); + case Intrinsic::prefetch: { + int RW = cast(Call.getArgOperand(1))->getZExtValue(); + int Locality = cast(Call.getArgOperand(2))->getZExtValue(); + int Data = cast(Call.getArgOperand(3))->getZExtValue(); + Check(RW < 2, "rw argument to llvm.prefetch must be 0-1", Call); + Check(Locality < 4, "locality argument to llvm.prefetch must be 0-4", Call); + Check(Data < 2, "cache type argument to llvm.prefetch must be 0-1", Call); + Check(Data != 0 || RW != 1, "instruction cache must be read only", Call); break; + } case Intrinsic::stackprotector: Check(isa(Call.getArgOperand(1)->stripPointerCasts()), "llvm.stackprotector parameter #2 must resolve to an alloca.", Call); diff --git a/llvm/lib/Target/X86/X86Instr3DNow.td b/llvm/lib/Target/X86/X86Instr3DNow.td --- a/llvm/lib/Target/X86/X86Instr3DNow.td +++ b/llvm/lib/Target/X86/X86Instr3DNow.td @@ -93,7 +93,7 @@ let Predicates = [Has3DNow, NoSSEPrefetch] in def PREFETCH : I3DNow<0x0D, MRM0m, (outs), (ins i8mem:$addr), "prefetch\t$addr", - [(prefetch addr:$addr, imm, imm, (i32 1))]>, TB; + [(prefetch addr:$addr, imm, imm, (i32 imm))]>, TB; def PREFETCHW : I<0x0D, MRM1m, (outs), (ins i8mem:$addr), "prefetchw\t$addr", [(prefetch addr:$addr, (i32 1), (i32 PrefetchWLevel), (i32 1))]>, diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td --- a/llvm/lib/Target/X86/X86InstrSSE.td +++ b/llvm/lib/Target/X86/X86InstrSSE.td @@ -3201,13 +3201,13 @@ // Prefetch intrinsic. let Predicates = [HasSSEPrefetch], SchedRW = [WriteLoad] in { def PREFETCHT0 : I<0x18, MRM1m, (outs), (ins i8mem:$src), - "prefetcht0\t$src", [(prefetch addr:$src, imm, (i32 3), (i32 1))]>, TB; + "prefetcht0\t$src", [(prefetch addr:$src, imm, (i32 3), imm)]>, TB; def PREFETCHT1 : I<0x18, MRM2m, (outs), (ins i8mem:$src), - "prefetcht1\t$src", [(prefetch addr:$src, imm, (i32 2), (i32 1))]>, TB; + "prefetcht1\t$src", [(prefetch addr:$src, imm, (i32 2), imm)]>, TB; def PREFETCHT2 : I<0x18, MRM3m, (outs), (ins i8mem:$src), - "prefetcht2\t$src", [(prefetch addr:$src, imm, (i32 1), (i32 1))]>, TB; + "prefetcht2\t$src", [(prefetch addr:$src, imm, (i32 1), imm)]>, TB; def PREFETCHNTA : I<0x18, MRM0m, (outs), (ins i8mem:$src), - "prefetchnta\t$src", [(prefetch addr:$src, imm, (i32 0), (i32 1))]>, TB; + "prefetchnta\t$src", [(prefetch addr:$src, imm, (i32 0), imm)]>, TB; } // FIXME: How should flush instruction be modeled? diff --git a/llvm/test/CodeGen/SystemZ/prefetch-01.ll b/llvm/test/CodeGen/SystemZ/prefetch-01.ll --- a/llvm/test/CodeGen/SystemZ/prefetch-01.ll +++ b/llvm/test/CodeGen/SystemZ/prefetch-01.ll @@ -15,14 +15,11 @@ ret void } -; Check that instruction write prefetches are ignored. -define dso_local void @f2(ptr %ptr) { -; CHECK-LABEL: f2: -; CHECK-NOT: %r2 -; CHECK: br %r14 - call void @llvm.prefetch(ptr %ptr, i32 1, i32 0, i32 0) - ret void -} +; Instruction write prefetches are invalid. +; define dso_local void @f2(ptr %ptr) { +; call void @llvm.prefetch(ptr %ptr, i32 1, i32 0, i32 0) +; ret void +; } ; Check data read prefetches. define dso_local void @f3(ptr %ptr) { diff --git a/llvm/test/CodeGen/X86/prefetch.ll b/llvm/test/CodeGen/X86/prefetch.ll --- a/llvm/test/CodeGen/X86/prefetch.ll +++ b/llvm/test/CodeGen/X86/prefetch.ll @@ -21,7 +21,7 @@ ; rdar://10538297 -define void @t(ptr %ptr) nounwind { +define dso_local void @t(ptr %ptr) nounwind { ; SSE-LABEL: t: ; SSE: # %bb.0: # %entry ; SSE-NEXT: movl {{[0-9]+}}(%esp), %eax @@ -33,6 +33,10 @@ ; SSE-NEXT: prefetcht1 (%eax) ; SSE-NEXT: prefetcht0 (%eax) ; SSE-NEXT: prefetchnta (%eax) +; SSE-NEXT: prefetcht1 (%eax) +; SSE-NEXT: prefetcht0 (%eax) +; SSE-NEXT: prefetcht1 t +; SSE-NEXT: prefetcht0 ext ; SSE-NEXT: retl ; ; PRFCHWSSE-LABEL: t: @@ -46,6 +50,10 @@ ; PRFCHWSSE-NEXT: prefetchw (%eax) ; PRFCHWSSE-NEXT: prefetchw (%eax) ; PRFCHWSSE-NEXT: prefetchw (%eax) +; PRFCHWSSE-NEXT: prefetcht1 (%eax) +; PRFCHWSSE-NEXT: prefetcht0 (%eax) +; PRFCHWSSE-NEXT: prefetcht1 t +; PRFCHWSSE-NEXT: prefetcht0 ext ; PRFCHWSSE-NEXT: retl ; ; PREFETCHWT1-LABEL: t: @@ -59,6 +67,10 @@ ; PREFETCHWT1-NEXT: prefetchwt1 (%eax) ; PREFETCHWT1-NEXT: prefetchw (%eax) ; PREFETCHWT1-NEXT: prefetchwt1 (%eax) +; PREFETCHWT1-NEXT: prefetcht1 (%eax) +; PREFETCHWT1-NEXT: prefetcht0 (%eax) +; PREFETCHWT1-NEXT: prefetcht1 t +; PREFETCHWT1-NEXT: prefetcht0 ext ; PREFETCHWT1-NEXT: retl ; ; 3DNOW-LABEL: t: @@ -72,6 +84,10 @@ ; 3DNOW-NEXT: prefetchw (%eax) ; 3DNOW-NEXT: prefetchw (%eax) ; 3DNOW-NEXT: prefetchw (%eax) +; 3DNOW-NEXT: prefetch (%eax) +; 3DNOW-NEXT: prefetch (%eax) +; 3DNOW-NEXT: prefetch t +; 3DNOW-NEXT: prefetch ext ; 3DNOW-NEXT: retl entry: tail call void @llvm.prefetch( ptr %ptr, i32 0, i32 1, i32 1 ) @@ -82,7 +98,12 @@ tail call void @llvm.prefetch( ptr %ptr, i32 1, i32 2, i32 1 ) tail call void @llvm.prefetch( ptr %ptr, i32 1, i32 3, i32 1 ) tail call void @llvm.prefetch( ptr %ptr, i32 1, i32 0, i32 1 ) + tail call void @llvm.prefetch( ptr %ptr, i32 0, i32 2, i32 0 ) + tail call void @llvm.prefetch( ptr %ptr, i32 0, i32 3, i32 0 ) + tail call void @llvm.prefetch( ptr @t, i32 0, i32 2, i32 0 ) + tail call void @llvm.prefetch( ptr @ext, i32 0, i32 3, i32 0 ) ret void } +declare dso_local void @ext() nounwind declare void @llvm.prefetch(ptr, i32, i32, i32) nounwind