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=; each element 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 @@ -2146,6 +2146,10 @@ 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 : CommaJoined<["-"], "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 : Flag<["-"], "mbranches-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 @@ -2015,8 +2015,59 @@ CmdArgs.push_back("-mpacked-stack"); } +static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-x86-branches-within-32B-boundaries"); + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + unsigned Boundary; + if (Value.getAsInteger(10, Boundary) || Boundary < 16 || + !llvm::isPowerOf2_64(Boundary)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-x86-align-branch-boundary=" + Twine(Boundary))); + } + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + std::string AlignBranch; + for (StringRef T : A->getValues()) { + 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"; + if (!AlignBranch.empty()) + AlignBranch += '+'; + AlignBranch += T; + } + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch)); + } + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { + StringRef Value = A->getValue(); + unsigned PrefixSize; + if (Value.getAsInteger(10, PrefixSize) || PrefixSize > 5) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" + + Twine(PrefixSize))); + } + } +} + void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + addX86AlignBranchArgs(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)) @@ -2046,10 +2097,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"); } @@ -6480,6 +6531,8 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + addX86AlignBranchArgs(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,39 @@ +/// Test that -malign-branch* and -mbranches-within-32B-boundaries are parsed and converted to -mllvm options. + +/// Test -malign-branch-boundary= +// RUN: %clang -target x86_64 -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= +// 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=; each element must be one of: fused, jcc, jmp, call, ret, indirect +// TYPE-ERR: invalid argument 'bar' to -malign-branch=; each element must be one of: fused, jcc, jmp, call, ret, indirect + +/// Test -malign-branch-prefix-size= +// RUN: %clang -target x86_64 -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-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 -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=32B +// 32B: "-mllvm" "-x86-branches-within-32B-boundaries" + +/// 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* and -mbranches-within-32B-boundaries are handled for assembly files. + +// RUN: %clang -target x86_64 -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=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-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-branches-within-32B-boundaries"