pengfei created this revision. pengfei added reviewers: craig.topper, uweigand, lenary, efriedma. Herald added subscribers: StephenFan, jdoerfert, hiraditya. Herald added a project: All. pengfei requested review of this revision. Herald added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits.
LLVM backends like X86 always lowers prefetch intrinsics into similar type if the desired one is not available. For example, T2 hint -> T1 or write hint -> read. See llvm/test/CodeGen/X86/prefetch.ll However, it's not clear for backend to choose between "write data" or "read instruction" if there is no native "write instruction" instructions. As far as I know, there's no upstream target that has supported "write instruction" at the moment. So there should be no real impact by this patch. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D136145 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/lib/CodeGen/CGBuiltin.cpp clang/lib/Sema/SemaChecking.cpp clang/test/CodeGen/builtins-arm.c clang/test/Sema/builtin-prefetch.c llvm/docs/LangRef.rst llvm/lib/IR/Verifier.cpp llvm/lib/Target/X86/X86Instr3DNow.td llvm/lib/Target/X86/X86InstrSSE.td llvm/test/CodeGen/SystemZ/prefetch-01.ll llvm/test/CodeGen/X86/prefetch.ll
Index: llvm/test/CodeGen/X86/prefetch.ll =================================================================== --- llvm/test/CodeGen/X86/prefetch.ll +++ 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 Index: llvm/test/CodeGen/SystemZ/prefetch-01.ll =================================================================== --- llvm/test/CodeGen/SystemZ/prefetch-01.ll +++ 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) { Index: llvm/lib/Target/X86/X86InstrSSE.td =================================================================== --- llvm/lib/Target/X86/X86InstrSSE.td +++ 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? Index: llvm/lib/Target/X86/X86Instr3DNow.td =================================================================== --- llvm/lib/Target/X86/X86Instr3DNow.td +++ 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))]>, Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ 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<ConstantInt>(Call.getArgOperand(1))->getZExtValue() < 2, - "rw argument to llvm.prefetch must be 0-1", Call); - Check(cast<ConstantInt>(Call.getArgOperand(2))->getZExtValue() < 4, - "locality argument to llvm.prefetch must be 0-4", Call); - Check(cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue() < 2, - "cache type argument to llvm.prefetch must be 0-1", Call); + case Intrinsic::prefetch: { + int RW = cast<ConstantInt>(Call.getArgOperand(1))->getZExtValue(); + int Locality = cast<ConstantInt>(Call.getArgOperand(2))->getZExtValue(); + int Data = cast<ConstantInt>(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<AllocaInst>(Call.getArgOperand(1)->stripPointerCasts()), "llvm.stackprotector parameter #2 must resolve to an alloca.", Call); Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ 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: """""""""" Index: clang/test/Sema/builtin-prefetch.c =================================================================== --- clang/test/Sema/builtin-prefetch.c +++ 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]}} } Index: clang/test/CodeGen/builtins-arm.c =================================================================== --- clang/test/CodeGen/builtins-arm.c +++ 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) { Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ 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; } Index: clang/lib/CodeGen/CGBuiltin.cpp =================================================================== --- clang/lib/CodeGen/CGBuiltin.cpp +++ 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})); } Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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"
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits