"-ftrivial-auto-var-init=zero hasn't been enabled. Enable it at your own peril for benchmarking purpose only with "
"-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">;
+def err_drv_trivial_auto_var_init_stop_after_missing_dependency : Error<
+ "-ftrivial-auto-var-init-stop-after=* is used without -ftrivial-auto-var-init=zero or -ftrivial-auto-var-init=pattern.">;
+
+def err_drv_trivial_auto_var_init_stop_after_invalid_value : Error<
+ "-ftrivial-auto-var-init-stop-after=* only accepts positive integers.">;
+
def warn_drv_msp430_hwmult_unsupported : Warning<"the given MCU does not "
"support hardware multiply, but -mhwmult is set to %0.">,
InGroup<InvalidCommandLineArgument>;
"stack protector mode")
ENUM_LANGOPT(TrivialAutoVarInit, TrivialAutoVarInitKind, 2, TrivialAutoVarInitKind::Uninitialized,
"trivial automatic variable initialization")
+VALUE_LANGOPT(TrivialAutoVarInitStopAfter, 32, 0,
+ "stop trivial automatic variable initialization after the specified number of instances. Must be greater than 0.")
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
"signed integer overflow handling")
def enable_trivial_var_init_zero : Flag<["-"], "enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">,
Flags<[CC1Option, CoreOption]>,
HelpText<"Trivial automatic variable initialization to zero is only here for benchmarks, it'll eventually be removed, and I'm OK with that because I'm only using it to benchmark">;
+def ftrivial_auto_var_init_stop_after : Joined<["-"], "ftrivial-auto-var-init-stop-after=">, Group<f_Group>,
+ Flags<[CC1Option, CoreOption]>, HelpText<"Stop initializing trivial automatic stack variables after the specified number of instances">;
def fstandalone_debug : Flag<["-"], "fstandalone-debug">, Group<f_Group>, Flags<[CoreOption]>,
HelpText<"Emit full debug info for all types used by the program">;
def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, Flags<[CoreOption]>,
break;
}
}
+ if (CGF.CGM.stopAutoInit())
+ return;
CGF.Builder.CreateMemSet(AI, Byte, Size, AlignmentInBytes);
}
case LangOptions::TrivialAutoVarInitKind::Uninitialized:
llvm_unreachable("Uninitialized handled by caller");
case LangOptions::TrivialAutoVarInitKind::Zero:
+ if (CGM.stopAutoInit())
+ return;
emitStoresForZeroInit(CGM, D, Loc, isVolatile, Builder);
break;
case LangOptions::TrivialAutoVarInitKind::Pattern:
+ if (CGM.stopAutoInit())
+ return;
emitStoresForPatternInit(CGM, D, Loc, isVolatile, Builder);
break;
}
llvm_unreachable("Uninitialized handled by caller");
case LangOptions::TrivialAutoVarInitKind::Zero:
+ if (CGM.stopAutoInit())
+ return;
if (!EltSize.isOne())
SizeVal = Builder.CreateNUWMul(SizeVal, CGM.getSize(EltSize));
Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal,
break;
case LangOptions::TrivialAutoVarInitKind::Pattern: {
+ if (CGM.stopAutoInit())
+ return;
llvm::Type *ElTy = Loc.getElementType();
llvm::Constant *Constant = constWithPadding(
CGM, IsPattern::Yes, initializationPatternFor(CGM, ElTy));
}
return Alignment;
}
+
+bool CodeGenModule::stopAutoInit() {
+ unsigned StopAfter = getContext().getLangOpts().TrivialAutoVarInitStopAfter;
+ if (StopAfter) {
+ // This number is positive only when -ftrivial-auto-var-init-stop-after=* is
+ // used
+ if (NumAutoVarInit >= StopAfter) {
+ return true;
+ }
+ if (!NumAutoVarInit) {
+ unsigned DiagID = getDiags().getCustomDiagID(
+ DiagnosticsEngine::Warning,
+ "-ftrivial-auto-var-init-stop-after=%0 has been enabled to limit the "
+ "number of times ftrivial-auto-var-init=%1 gets applied.");
+ getDiags().Report(DiagID)
+ << StopAfter
+ << (getContext().getLangOpts().getTrivialAutoVarInit() ==
+ LangOptions::TrivialAutoVarInitKind::Zero
+ ? "zero"
+ : "pattern");
+ }
+ ++NumAutoVarInit;
+ }
+ return false;
+}
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions &CodeGenOpts;
+ unsigned NumAutoVarInit = 0;
llvm::Module &TheModule;
DiagnosticsEngine &Diags;
const TargetInfo &Target;
CharUnits getNaturalPointeeTypeAlignment(QualType T,
LValueBaseInfo *BaseInfo = nullptr,
TBAAAccessInfo *TBAAInfo = nullptr);
+ bool stopAutoInit();
private:
llvm::Constant *GetOrCreateLLVMFunction(
CmdArgs.push_back(
Args.MakeArgString("-ftrivial-auto-var-init=" + TrivialAutoVarInit));
}
+
+ if (Arg *A =
+ Args.getLastArg(options::OPT_ftrivial_auto_var_init_stop_after)) {
+ if (!Args.hasArg(options::OPT_ftrivial_auto_var_init) ||
+ StringRef(
+ Args.getLastArg(options::OPT_ftrivial_auto_var_init)->getValue()) ==
+ "uninitialized")
+ D.Diag(diag::err_drv_trivial_auto_var_init_stop_after_missing_dependency);
+ A->claim();
+ StringRef Val = A->getValue();
+ if (std::stoi(Val.str()) <= 0)
+ D.Diag(diag::err_drv_trivial_auto_var_init_stop_after_invalid_value);
+ CmdArgs.push_back(
+ Args.MakeArgString("-ftrivial-auto-var-init-stop-after=" + Val));
+ }
}
static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) {
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val;
}
+ if (Arg *A = Args.getLastArg(OPT_ftrivial_auto_var_init_stop_after)) {
+ int Val = std::stoi(A->getValue());
+ Opts.TrivialAutoVarInitStopAfter = Val;
+ }
+
// Parse -fsanitize= arguments.
parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
Diags, Opts.Sanitize);
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=1 %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN-STOP-AFTER-1-SCALAR
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=2 %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN-STOP-AFTER-2-ARRAY
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=3 %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN-STOP-AFTER-3-VLA
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=4 %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN-STOP-AFTER-4-POINTER
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=5 %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN-STOP-AFTER-5-BUILTIN
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero -ftrivial-auto-var-init-stop-after=1 %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO-STOP-AFTER-1-SCALAR
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero -ftrivial-auto-var-init-stop-after=2 %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO-STOP-AFTER-2-ARRAY
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero -ftrivial-auto-var-init-stop-after=3 %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO-STOP-AFTER-3-VLA
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero -ftrivial-auto-var-init-stop-after=4 %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO-STOP-AFTER-4-POINTER
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero -ftrivial-auto-var-init-stop-after=5 %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO-STOP-AFTER-5-BUILTIN
+
+#define ARRLEN 10
+
+typedef struct {
+ int i;
+ char c;
+} S;
+
+int foo(unsigned n) {
+ // scalar variable
+ long a = 888;
+ // array
+ S arr[ARRLEN];
+ // VLA
+ S vla[n];
+ // pointer
+ void *p;
+ // builtin
+ p = __builtin_alloca(sizeof(unsigned long long) * n);
+ // PATTERN-STOP-AFTER-1-SCALAR: store i64 -6148914691236517206, i64* %a, align 8
+ // PATTERN-STOP-AFTER-1-SCALAR-NOT: call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 -86, i64 80, i1 false)
+ // PATTERN-STOP-AFTER-2-ARRAY: %0 = bitcast [10 x %struct.S]* %arr to i8*
+ // PATTERN-STOP-AFTER-2-ARRAY-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 -86, i64 80, i1 false)
+ // PATTERN-STOP-AFTER-2-ARRAY-NOT: vla-init.loop:
+ // PATTERN-STOP-AFTER-3-VLA: vla-init.loop:
+ // PATTERN-STOP-AFTER-3-VLA-NEXT: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ]
+ // PATTERN-STOP-AFTER-3-VLA-NEXT-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %vla.cur, i8* align 4 bitcast ({ i32, i8, [3 x i8] }* @__const._Z3fooj.vla to i8*), i64 8, i1 false)
+ // PATTERN-STOP-AFTER-3-VLA-NOT: store i8* inttoptr (i64 -6148914691236517206 to i8*), i8** %p, align 8
+ // PATTERN-STOP-AFTER-4-POINTER: store i8* inttoptr (i64 -6148914691236517206 to i8*), i8** %p, align 8
+ // PATTERN-STOP-AFTER-4-POINTER-NOT: call void @llvm.memset.p0i8.i64(i8* align 16 %6, i8 -86, i64 %mul, i1 false)
+ // PATTERN-STOP-AFTER-5-BUILTIN: call void @llvm.memset.p0i8.i64(i8* align 16 %6, i8 -86, i64 %mul, i1 false)
+ // PATTERN-STOP-AFTER-5-BUILTIN-MESSAGES: warning: -ftrivial-auto-var-init-stop-after=5 has been enabled to limit the number of times ftrivial-auto-var-init=pattern gets applied.
+
+ // ZERO-STOP-AFTER-1-SCALAR: store i64 0, i64* %a, align 8
+ // ZERO-STOP-AFTER-1-SCALAR-NOT: call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 0, i64 80, i1 false)
+ // ZERO-STOP-AFTER-2-ARRAY: %0 = bitcast [10 x %struct.S]* %arr to i8*
+ // ZERO-STOP-AFTER-2-ARRAY-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 0, i64 80, i1 false)
+ // ZERO-STOP-AFTER-2-ARRAY-NOT: %call void @llvm.memset.p0i8.i64(i8* align 16 %5, i8 0, i64 %4, i1 false)
+ // ZERO-STOP-AFTER-3-VLA: %5 = bitcast %struct.S* %vla to i8*
+ // ZERO-STOP-AFTER-3-VLA-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 %5, i8 0, i64 %4, i1 false)
+ // ZERO-STOP-AFTER-3-VLA-NOT: store i8* null, i8** %p, align 8
+ // ZERO-STOP-AFTER-4-POINTER: store i8* null, i8** %p, align 8
+ // ZERO-STOP-AFTER-4-POINTER-NOT: call void @llvm.memset.p0i8.i64(i8* align 16 %7, i8 0, i64 %mul, i1 false)
+ // ZERO-STOP-AFTER-5-BUILTIN: %7 = alloca i8, i64 %mul, align 16
+ // ZERO-STOP-AFTER-5-BUILTIN-NEXT: call void @llvm.memset.p0i8.i64(i8* align 16 %7, i8 0, i64 %mul, i1 false)
+ // ZERO-STOP-AFTER-5-BUILTIN-MESSAGES: warnings: -ftrivial-auto-var-init-stop-after=5 has been enabled to limit the number of times ftrivial-auto-var-init=zero gets applied.
+ return 0;
+}
// CHECK-TRIVIAL-ZERO-GOOD-NOT: hasn't been enabled
// CHECK-TRIVIAL-ZERO-BAD: hasn't been enabled
+// RUN: %clang -### -S -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=1 %s 2>&1 | FileCheck -check-prefix=CHECK-TRIVIAL-PATTERN-STOP-AFTER %s
+// RUN: %clang -### -S -ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -ftrivial-auto-var-init-stop-after=1 %s 2>&1 | FileCheck -check-prefix=CHECK-TRIVIAL-ZERO-STOP-AFTER %s
+// RUN: %clang -### -S -ftrivial-auto-var-init-stop-after=0 %s 2>&1 | FileCheck -check-prefix=CHECK-TRIVIAL-STOP-AFTER-MISSING-DEPENDENCY %s
+// RUN: %clang -### -S -ftrivial-auto-var-init=pattern -ftrivial-auto-var-init-stop-after=0 %s 2>&1 | FileCheck -check-prefix=CHECK-TRIVIAL-PATTERN-STOP-AFTER-INVALID-VALUE %s
+// RUN: %clang -### -S -ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -ftrivial-auto-var-init-stop-after=0 %s 2>&1 | FileCheck -check-prefix=CHECK-TRIVIAL-ZERO-STOP-AFTER-INVALID-VALUE %s
+// CHECK-TRIVIAL-PATTERN-STOP-AFTER-NOT: is used without -ftrivial-auto-var-init
+// CHECK-TRIVIAL-PATTERN-STOP-AFTER-NOT: only accepts positive integers
+// CHECK-TRIVIAL-ZERO-STOP-AFTER-NOT: is used without -ftrivial-auto-var-init
+// CHECK-TRIVIAL-ZERO-STOP-AFTER-NOT: only accepts positive integers
+// CHECK-TRIVIAL-STOP-AFTER-MISSING-DEPENDENCY: used without -ftrivial-auto-var-init
+// CHECK-TRIVIAL-PATTERN-STOP-AFTER-INVALID-VALUE: only accepts positive integers
+// CHECK-TRIVIAL-ZERO-STOP-AFTER-INVALID-VALUE: only accepts positive integers
+
// RUN: %clang -### -S -fno-temp-file %s 2>&1 | FileCheck -check-prefix=CHECK-NO-TEMP-FILE %s
// CHECK-NO-TEMP-FILE: "-fno-temp-file"