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 @@ -250,6 +250,9 @@ def err_drv_bitcode_unsupported_on_toolchain : Error< "-fembed-bitcode is not supported on versions of iOS prior to 6.0">; +def err_drv_invalid_malign_branch_EQ : Error< + "invalid argument '%0' to -malign-branch=; must be one of: %1">; + def warn_O4_is_O3 : Warning<"-O4 is equivalent to -O3">, InGroup; def warn_drv_optimization_value : Warning<"optimization level '%0' is not supported; using '%1%2' instead">, InGroup; 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 @@ -2141,6 +2141,11 @@ def malign_functions_EQ : Joined<["-"], "malign-functions=">, Group; def malign_loops_EQ : Joined<["-"], "malign-loops=">, Group; def malign_jumps_EQ : Joined<["-"], "malign-jumps=">, Group; +def malign_branch_EQ : Joined<["-"], "malign-branch=">, Group; +def malign_branch_boundary_EQ : Joined<["-"], "malign-branch-boundary=">, Group; +def malign_branch_prefix_size_EQ : Joined<["-"], "malign-branch-prefix-size=">, Group; +def mbranches_within_32B_boundaries : Joined<["-"], "mbranches-within-32B-boundaries">, Flags<[DriverOption]>, Group; +def mno_branches_within_32B_boundaries : Joined<["-"], "mno-branches-within-32B-boundaries">, Flags<[DriverOption]>, Group; def mfancy_math_387 : Flag<["-"], "mfancy-math-387">, Group; def mlong_calls : Flag<["-"], "mlong-calls">, Group, HelpText<"Generate branches with extended addressability, usually via indirect jumps.">; 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 @@ -2012,8 +2012,64 @@ CmdArgs.push_back("-mpacked-stack"); } +static void addX86AlignBranchesArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + unsigned AlignBranchBoundary = 0, AlignBranchPrefixSize = 0; + std::string AlignBranch; + if (Args.hasFlag(options::OPT_mbranches_within_32B_boundaries, + options::OPT_mno_branches_within_32B_boundaries, false)) { + AlignBranch = "fused+jcc+jmp"; + AlignBranchBoundary = 32; + AlignBranchPrefixSize = 5; + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + SmallVector BranchTypes; + AlignBranch = A->getValue(); + StringRef(AlignBranch).split(BranchTypes, '+', -1, false); + for (StringRef T : BranchTypes) + if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && + T != "ret" && T != "indirect") { + D.Diag(diag::err_drv_invalid_malign_branch_EQ) + << T << "fused, jcc, jmp, call, ret, indirect"; + AlignBranch = StringRef(); + } + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + if (Value.getAsInteger(10, AlignBranchBoundary) || + AlignBranchBoundary < 16 || !llvm::isPowerOf2_64(AlignBranchBoundary)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + AlignBranch = StringRef(); + } + } + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { + StringRef Value = A->getValue(); + if (Value.getAsInteger(10, AlignBranchPrefixSize) || + AlignBranchPrefixSize > 5) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + AlignBranch = StringRef(); + } + } + if (!AlignBranch.empty()) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch)); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-boundary=" + + Twine(AlignBranchBoundary))); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" + + Twine(AlignBranchPrefixSize))); + } +} + void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + addX86AlignBranchesArgs(D, Args, CmdArgs); + if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) @@ -2043,10 +2099,10 @@ CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } - } else if (getToolChain().getDriver().IsCLMode()) { + } else if (D.IsCLMode()) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-x86-asm-syntax=intel"); } @@ -6436,6 +6492,8 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + addX86AlignBranchesArgs(getToolChain().getDriver(), Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { StringRef Value = A->getValue(); if (Value == "intel" || Value == "att") { diff --git a/clang/test/Driver/x86-malign-branch.c b/clang/test/Driver/x86-malign-branch.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/x86-malign-branch.c @@ -0,0 +1,44 @@ +/// Test that -malign-branch* options are parsed and converted to -mllvm options. + +/// Test -malign-branch= +// RUN: %clang -target x86_64 -malign-branch=fused+jcc+jmp %s -c -### %s 2>&1 | FileCheck %s --check-prefix=TYPE0 +// TYPE0: "-mllvm" "-x86-align-branch=fused+jcc+jmp" +// RUN: %clang -target x86_64 -malign-branch=fused+jcc+jmp+ret+call+indirect %s -c -### %s 2>&1 | FileCheck %s --check-prefix=TYPE1 +// TYPE1: "-mllvm" "-x86-align-branch=fused+jcc+jmp+ret+call+indirect" + +// RUN: %clang -target x86_64 -malign-branch=fused+foo+bar %s -c -### %s 2>&1 | FileCheck %s --check-prefix=TYPE-ERR +// TYPE-ERR: invalid argument 'foo' to -malign-branch=; must be one of: fused, jcc, jmp, call, ret, indirect +// TYPE-ERR: invalid argument 'bar' to -malign-branch=; must be one of: fused, jcc, jmp, call, ret, indirect + +/// Test -malign-branch-boundary= +// RUN: %clang -target x86_64 -malign-branch=jcc -malign-branch-boundary=16 %s -c -### 2>&1 | FileCheck %s --check-prefix=BOUNDARY +// BOUNDARY: "-mllvm" "-x86-align-branch-boundary=16" + +// RUN: %clang -target x86_64 -malign-branch-boundary=8 %s -c -### 2>&1 | FileCheck %s --check-prefix=BOUNDARY-ERR +// RUN: %clang -target x86_64 -malign-branch-boundary=15 %s -c -### 2>&1 | FileCheck %s --check-prefix=BOUNDARY-ERR +// BOUNDARY-ERR: invalid argument {{.*}} to -malign-branch-boundary= + +/// Test -malign-branch-prefix-size= +// RUN: %clang -target x86_64 -malign-branch=jcc -malign-branch-prefix-size=0 %s -c -### 2>&1 | FileCheck %s --check-prefix=PREFIX-0 +// PREFIX-0: "-mllvm" "-x86-align-branch-prefix-size=0" +// RUN: %clang -target x86_64 -malign-branch=jcc -malign-branch-prefix-size=5 %s -c -### 2>&1 | FileCheck %s --check-prefix=PREFIX-5 +// PREFIX-5: "-mllvm" "-x86-align-branch-prefix-size=5" + +// RUN: %clang -target x86_64 -malign-branch-prefix-size=6 %s -c -### 2>&1 | FileCheck %s --check-prefix=PREFIX-6 +// PREFIX-6: invalid argument + +/// Test -mbranches-within-32B-boundaries +// RUN: %clang -target x86_64 -mno-branches-within-32B-boundaries -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=32B +// 32B: "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch-prefix-size=5" +// RUN: %clang -target x86_64 -mbranches-within-32B-boundaries -mno-branches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=NO32B +// NO32B-NOT: "-x86-align-branch +/// Test that -malign-branch* can override individual values of -mbranches-within-32B-boundaries +// RUN: %clang -target x86_64 -malign-branch=jcc -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=32B-TYPE +// 32B-TYPE: "-mllvm" "-x86-align-branch=jcc" "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch-prefix-size=5" + +/// Unsupported on other targets. +// RUN: %clang -target aarch64 -malign-branch=jmp %s -c -### 2>&1 | FileCheck --check-prefix=UNUSED %s +// RUN: %clang -target aarch64 -malign-branch-boundary=7 %s -c -### 2>&1 | FileCheck --check-prefix=UNUSED %s +// RUN: %clang -target aarch64 -malign-branch-prefix-size=15 %s -c -### 2>&1 | FileCheck --check-prefix=UNUSED %s +// RUN: %clang -target aarch64 -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck --check-prefix=UNUSED %s +// UNUSED: warning: argument unused diff --git a/clang/test/Driver/x86-malign-branch.s b/clang/test/Driver/x86-malign-branch.s new file mode 100644 --- /dev/null +++ b/clang/test/Driver/x86-malign-branch.s @@ -0,0 +1,13 @@ +/// Test that -malign-branch* are handled for assembly files. + +// RUN: %clang -target x86_64 -malign-branch=fused+jcc+jmp %s -c -### %s 2>&1 | FileCheck %s --check-prefix=TYPE +// TYPE: "-mllvm" "-x86-align-branch=fused+jcc+jmp" + +// RUN: %clang -target x86_64 -malign-branch=jcc -malign-branch-boundary=16 %s -c -### 2>&1 | FileCheck %s --check-prefix=BOUNDARY +// BOUNDARY: "-mllvm" "-x86-align-branch-boundary=16" + +// RUN: %clang -target x86_64 -malign-branch=jcc -malign-branch-prefix-size=5 %s -c -### 2>&1 | FileCheck %s --check-prefix=PREFIX +// PREFIX: "-mllvm" "-x86-align-branch-prefix-size=5" + +// RUN: %clang -target x86_64 -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=32B +// 32B: "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch-prefix-size=5"