Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -2191,6 +2191,47 @@ 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 to prevent " + "from being across or against the boundary of specified size. " + "-malign-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 are combination 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_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 5.">; +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 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 @@ -2012,8 +2012,64 @@ 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(); + SmallVector BranchTypes; + Value.split(BranchTypes, '+', -1, false); + for (auto BranchType : BranchTypes) { + if (BranchType != "fused" && BranchType != "jcc" && BranchType != "jmp" && + BranchType != "call" && BranchType != "ret" && + BranchType != "indirect") + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + 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=5")); + } +} + 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)) @@ -6436,6 +6492,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,43 @@ +// 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 -mno-branches-within-32B-boundaries -mbranches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-TOTAL1 +// CHECK-TOTAL1: "-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-unknown-unknown -mbranches-within-32B-boundaries -mno-branches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-TOTAL2 +// CHECK-TOTAL2-NOT: "-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-unknown-unknown -malign-branch-boundary=7 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: %clang -target x86_64-unknown-unknown -malign-branch=jump -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: %clang -target x86_64-unknown-unknown -malign-branch-prefix-size=15 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR +// CHECK-ERROR: error: unsupported argument +// +// RUN: %clang -target aarch64-unknown-unknown -malign-branch-boundary=7 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARNING +// RUN: %clang -target aarch64-unknown-unknown -malign-branch=jump -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARNING +// RUN: %clang -target aarch64-unknown-unknown -malign-branch-prefix-size=15 -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARNING +// RUN: %clang -target aarch64-unknown-unknown -mbranches-within-32B-boundaries -### -c %s 2>&1 | FileCheck %s --check-prefix=CHECK-WARNING +// CHECK-WARNING: warning: argument unused