Index: clang/include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticDriverKinds.td +++ 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; Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ 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, Flags<[DriverOption]>, HelpText<"Specify types of branches to align, each element must be one of jcc, fused, jmp, call, ret, indirect">, DocBrief<[{Specify types of branches to align, each element must be one of jcc, fused, jmp, call, ret, indirect. jcc indicates conditional jumps, fused indicates fused conditional jumps, jmp indicates unconditional jumps, call indicates direct and indirect calls, ret indicates rets, indirect indicates indirect jumps.}]>; +def malign_branch_boundary_EQ : Joined<["-"], "malign-branch-boundary=">, Group, Flags<[DriverOption]>, HelpText<"Specify the boundary's size to align branches">, DocBrief<[{Control how the assembler should align branches with NOP or segment override prefix. If the boundary's size is not 0, it should be a power of 2 and no less than 32. Branches will be aligned to prevent from being across or against the boundary of specified size. The default value 0 does not align branches.}]>; +def malign_branch_prefix_size_EQ : Joined<["-"], "malign-branch-prefix-size=">, Group, Flags<[DriverOption]>, HelpText<"Specify the maximum number(no more than 5) of prefixes on an instruction to align branches">; +def mbranches_within_32B_boundaries : Flag<["-"], "mbranches-within-32B-boundaries">, Group, Flags<[DriverOption]>, HelpText<"Aligns conditional jumps, fused conditional jumps, and unconditional jumps within 32 byte boundary with up to 5 segment prefixes on an instruction. It is equivalent to -malign-branch-boundary=32 -malign-branch=fused,jcc,jmp malign-branch-prefix-size=5">; 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.">; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2012,8 +2012,71 @@ CmdArgs.push_back("-mpacked-stack"); } +static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + unsigned AlignBranchBoundary = 0, AlignBranchPrefixSize = 0; + std::string AlignBranch; + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_boundary_EQ, + options::OPT_mbranches_within_32B_boundaries)) { + if (A->getOption().matches(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(); + } else { + AlignBranchBoundary = 32; + } + } + + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_EQ, + options::OPT_mbranches_within_32B_boundaries)) { + if (A->getOption().matches(options::OPT_malign_branch_EQ)) { + 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; + } + } else { + AlignBranch = "fused+jcc+jmp"; + } + } + + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ, + options::OPT_mbranches_within_32B_boundaries)) { + if (A->getOption().matches(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(); + } else { + AlignBranchPrefixSize = 5; + } + } + + 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=" + AlignBranch)); + 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(); + 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)) @@ -2043,10 +2106,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"); } @@ -6460,6 +6523,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") { Index: clang/test/Driver/x86-malign-branch.c =================================================================== --- /dev/null +++ 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-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-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=5" +/// Test that -malign-branch* can -mbranches-within-32B-boundaries can override each other +// RUN: %clang -target x86_64 -malign-branch=jcc -mbranches-within-32B-boundaries %s -c -### 2>&1 | FileCheck %s --check-prefix=32B-TYPE1 +// 32B-TYPE1: "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=5" +// RUN: %clang -target x86_64 -mbranches-within-32B-boundaries -malign-branch=jcc %s -c -### 2>&1 | FileCheck %s --check-prefix=32B-TYPE2 +// 32B-TYPE2: "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch=jcc" "-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 Index: clang/test/Driver/x86-malign-branch.s =================================================================== --- /dev/null +++ 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-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-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=5"