diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3995,8 +3995,6 @@ before the function entry and N-M NOPs after the function entry. This attribute takes precedence over the command line option ``-fpatchable-function-entry=N,M``. ``M`` defaults to 0 if omitted. - -Currently, only M=0 is supported. }]; } diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -115,6 +115,7 @@ VALUE_CODEGENOPT(XRayInstructionThreshold , 32, 200) VALUE_CODEGENOPT(PatchableFunctionEntryCount , 32, 0) ///< Number of NOPs at function entry +VALUE_CODEGENOPT(PatchableFunctionEntryOffset , 32, 0) CODEGENOPT(InstrumentForProfiling , 1, 0) ///< Set when -pg is enabled. CODEGENOPT(CallFEntry , 1, 0) ///< Set when -mfentry is enabled. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -408,7 +408,7 @@ def err_drv_unknown_indirect_jump_opt : Error< "unknown '-mindirect-jump=' option '%0'">; def err_drv_unsupported_fpatchable_function_entry_argument : Error< - "the second argument of '-fpatchable-function-entry' must be 0 or omitted">; + "the second argument of '-fpatchable-function-entry' must be smaller than the first argument">; def warn_drv_unable_to_find_directory_expected : Warning< "unable to find %0 directory, expected to be in '%1'">, diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -372,6 +372,9 @@ def fsanitize_coverage_stack_depth : Flag<["-"], "fsanitize-coverage-stack-depth">, HelpText<"Enable max stack depth tracing">; +def fpatchable_function_entry_offset_EQ + : Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"">, + HelpText<"Generate M NOPs before function entry">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " "or none">, Values<"none,clang,llvm">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1714,7 +1714,7 @@ def fpascal_strings : Flag<["-"], "fpascal-strings">, Group, Flags<[CC1Option]>, HelpText<"Recognize and construct Pascal-style string literals">; def fpatchable_function_entry_EQ : Joined<["-"], "fpatchable-function-entry=">, Group, Flags<[CC1Option]>, - HelpText<"Generate N NOPs at function entry">; + MetaVarName<"">, HelpText<"Generate M NOPs before function entry and N-M NOPs after function entry">; def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group, Flags<[CC1Option]>, HelpText<"Override the default ABI to return all structs on the stack">; def fpch_preprocess : Flag<["-"], "fpch-preprocess">, Group; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -833,13 +833,18 @@ } } + unsigned Count, Offset; if (const auto *Attr = D->getAttr()) { - // Attr->getStart is currently ignored. - Fn->addFnAttr("patchable-function-entry", - std::to_string(Attr->getCount())); - } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) { - Fn->addFnAttr("patchable-function-entry", - std::to_string(Count)); + Count = Attr->getCount(); + Offset = Attr->getOffset(); + } else { + Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount; + Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset; + } + if (Count && Offset <= Count) { + Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset)); + if (Offset) + Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset)); } } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5111,20 +5111,23 @@ if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; - unsigned Size, Start = 0; + unsigned Size, Offset = 0; if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 && Triple.getArch() != llvm::Triple::x86_64) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || (!S.empty() && (!S.consume_front(",") || - S.consumeInteger(10, Start) || !S.empty()))) + S.consumeInteger(10, Offset) || !S.empty()))) D.Diag(diag::err_drv_invalid_argument_to_option) << S0 << A->getOption().getName(); - else if (Start) + else if (Size < Offset) D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); - else + else { CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); + CmdArgs.push_back(Args.MakeArgString( + "-fpatchable-function-entry-offset=" + Twine(Offset))); + } } if (TC.SupportsProfiling()) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1102,6 +1102,8 @@ Opts.PatchableFunctionEntryCount = getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags); + Opts.PatchableFunctionEntryOffset = getLastArgIntValue( + Args, OPT_fpatchable_function_entry_offset_EQ, 0, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4924,9 +4924,9 @@ Expr *Arg = AL.getArgAsExpr(1); if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) return; - if (Offset) { + if (Count < Offset) { S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) - << &AL << 0 << 0 << Arg->getBeginLoc(); + << &AL << 0 << Count << Arg->getBeginLoc(); return; } } diff --git a/clang/test/CodeGen/patchable-function-entry.c b/clang/test/CodeGen/patchable-function-entry.c --- a/clang/test/CodeGen/patchable-function-entry.c +++ b/clang/test/CodeGen/patchable-function-entry.c @@ -17,10 +17,14 @@ __attribute__((patchable_function_entry(2, 0))) void f20decl(); void f20decl() {} -// OPT: define void @f() #2 +// CHECK: define void @f52() #2 +__attribute__((patchable_function_entry(5, 2))) void f52() {} + +// OPT: define void @f() #3 void f() {} /// M in patchable_function_entry(N,M) is currently ignored. // CHECK: attributes #0 = { {{.*}} "patchable-function-entry"="0" // CHECK: attributes #1 = { {{.*}} "patchable-function-entry"="2" -// OPT: attributes #2 = { {{.*}} "patchable-function-entry"="1" +// CHECK: attributes #2 = { {{.*}} "patchable-function-entry"="3" "patchable-function-prefix"="2" +// OPT: attributes #3 = { {{.*}} "patchable-function-entry"="1" diff --git a/clang/test/Sema/patchable-function-entry-attr.c b/clang/test/Sema/patchable-function-entry-attr.c --- a/clang/test/Sema/patchable-function-entry-attr.c +++ b/clang/test/Sema/patchable-function-entry-attr.c @@ -13,5 +13,5 @@ // expected-error@+1 {{'patchable_function_entry' attribute requires parameter 0 to be an integer constant}} __attribute__((patchable_function_entry(i))) void f(); -// expected-error@+1 {{'patchable_function_entry' attribute requires integer constant between 0 and 0 inclusive}} -__attribute__((patchable_function_entry(1, 1))) void f(); +// expected-error@+1 {{'patchable_function_entry' attribute requires integer constant between 0 and 2 inclusive}} +__attribute__((patchable_function_entry(2, 3))) void f();