Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2188,6 +2188,48 @@ def mno_inline_all_stringops : Flag<["-"], "mno-inline-all-stringops">, Group; def malign_double : Flag<["-"], "malign-double">, Group, Flags<[CC1Option]>, HelpText<"Align doubles to two words in structs (x86 only)">; +def malign_branch_boundary_EQ + : Joined<["-"], "malign-branch-boundary=">, + Group, + Flags<[DriverOption, HelpHidden]>, + HelpText<"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 within the boundary of specified size. " + "-x86-align-branch-boundary=0 doesn't align branches.">; +def malign_branch_EQ + : Joined<["-"], "malign-branch=">, + Group, + Flags<[DriverOption, HelpHidden]>, + HelpText< + "Specify types of branches to align (plus separated list of " + "types). The branches's types is combination of jcc, fused, " + "jmp, call, ret, indirect." + " jcc, which aligns conditional jumps; fused, which aligns fused " + "conditional jumps; jmp, which aligns unconditional jumps; call, " + "which aligns calls; ret, which aligns rets; indirect, which " + "aligns indirect jumps.">; +def malign_branch_prefix_size_EQ + : Joined<["-"], "malign-branch-prefix-size=">, + Group, + Flags<[DriverOption, CC1Option, HelpHidden]>, + HelpText<"Specify the maximum number of prefixes on an instruction to " + "align branches. The number should be between 0 and 4.">; +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 4 segment prefixes on an " + "instruction. It is equivalent to -malign-branch-boundary=32, " + "-malign-branch=fused+jcc+jmp, -malign-branch-prefix-size=4.">; +def mno_branches_within_32B_boundaries + : Flag<["-"], "mno-branches-within-32B-boundaries">, + Group, + Flags<[DriverOption]>, + HelpText<"Opposite to -mbranches-within-32B_boundaries.">; def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group, Values<"soft,softfp,hard">; def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group; def mfpu_EQ : Joined<["-"], "mfpu=">, Group; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -2007,8 +2007,55 @@ CmdArgs.push_back("-mpacked-stack"); } +static void AlignBranchesOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + uint64_t Num; + if (!Value.getAsInteger(10, Num) && Num >= 32 && llvm::isPowerOf2_64(Num)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-x86-align-branch-boundary=" + Value)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + StringRef Value = A->getValue(); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + Value)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { + StringRef Value = A->getValue(); + uint8_t Num; + if (!Value.getAsInteger(10, Num) && Num <= 5) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-x86-align-branch-prefix-size=" + Value)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + + if (Args.hasFlag(options::OPT_mbranches_within_32B_boundaries, + options::OPT_mno_branches_within_32B_boundaries, false)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-boundary=32")); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=fused+jcc+jmp")); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=4")); + } +} + void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + AlignBranchesOptions(getToolChain().getDriver(), 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)) @@ -6434,6 +6481,7 @@ void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + AlignBranchesOptions(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/intel-align-branch.c =================================================================== --- /dev/null +++ clang/test/Driver/intel-align-branch.c @@ -0,0 +1,35 @@ +// RUN: %clang -target x86_64-unknown-unknown -malign-branch-boundary=32 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-BOUNDARY +// CHECK-BOUNDARY: "-mllvm" "-x86-align-branch-boundary=32" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=jcc -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-JCC +// CHECK-JCC: "-mllvm" "-x86-align-branch=jcc" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=fused -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-FUSED +// CHECK-FUSED: "-mllvm" "-x86-align-branch=fused" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=jmp -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-JMP +// CHECK-JMP: "-mllvm" "-x86-align-branch=jmp" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=call -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-CALL +// CHECK-CALL: "-mllvm" "-x86-align-branch=call" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=ret -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-RET +// CHECK-RET: "-mllvm" "-x86-align-branch=ret" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=indirect -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-INDIRECT +// CHECK-INDIRECT: "-mllvm" "-x86-align-branch=indirect" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=fused+jcc+jmp+ret+call+indirect -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-BRANCH +// CHECK-BRANCH: "-mllvm" "-x86-align-branch=fused+jcc+jmp+ret+call+indirect" +// +// RUN: %clang -target x86_64-unknown-unknown -malign-branch-prefix-size=4 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-PREFIX +// CHECK-PREFIX: "-mllvm" "-x86-align-branch-prefix-size=4" +// +// // RUN: %clang -target x86_64-unknown-unknown -mbranches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-TOTAL +// CHECK-TOTAL: "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=4" +// +// RUN: %clang -target x86_64-unknown-unknown -mno-branches-within-32B-boundaries -mbranches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-TOTAL2 +// CHECK-TOTAL2: "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=4" +// +// RUN: %clang -target x86_64-unknown-unknown -mbranches-within-32B-boundaries -mno-branches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-TOTAL3 +// CHECK-TOTAL3-NOT: "-mllvm" "-x86-align-branch-boundary=32" "-mllvm" "-x86-align-branch=fused+jcc+jmp" "-mllvm" "-x86-align-branch-prefix-size=4"