diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2317,6 +2317,40 @@ +**BreakBeforeInlineASMColon** (``BreakBeforeInlineASMColonStyle``) :versionbadge:`clang-format 16` + The inline ASM colon style to use. + + Possible values: + + * ``BBIAS_Never`` (in configuration: ``Never``) + No break before inline ASM colon. + + .. code-block:: c++ + + asm volatile("string", : : val); + + * ``BBIAS_OnlyMultiline`` (in configuration: ``OnlyMultiline``) + Break before inline ASM colon if the line length is longer than column + limit. + + .. code-block:: c++ + + asm volatile("string", : : val); + asm("cmoveq %1, %2, %[result]" + : [result] "=r"(result) + : "r"(test), "r"(new), "[result]"(old)); + + * ``BBIAS_Always`` (in configuration: ``Always``) + Always break before inline ASM colon. + + .. code-block:: c++ + + asm volatile("string", + : + : val); + + + **BreakBeforeTernaryOperators** (``Boolean``) :versionbadge:`clang-format 3.7` If ``true``, ternary operators will be placed after line breaks. diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1752,6 +1752,35 @@ /// \version 12 BreakBeforeConceptDeclarationsStyle BreakBeforeConceptDeclarations; + /// Different ways to break ASM parameters. + enum BreakBeforeInlineASMColonStyle : int8_t { + /// No break before inline ASM colon. + /// \code + /// asm volatile("string", : : val); + /// \endcode + BBIAS_Never, + /// Break before inline ASM colon if the line length is longer than column + /// limit. + /// \code + /// asm volatile("string", : : val); + /// asm("cmoveq %1, %2, %[result]" + /// : [result] "=r"(result) + /// : "r"(test), "r"(new), "[result]"(old)); + /// \endcode + BBIAS_OnlyMultiline, + /// Always break before inline ASM colon. + /// \code + /// asm volatile("string", + /// : + /// : val); + /// \endcode + BBIAS_Always, + }; + + /// The inline ASM colon style to use. + /// \version 16 + BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon; + /// If ``true``, ternary operators will be placed after line breaks. /// \code /// true: @@ -4016,6 +4045,7 @@ BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators && BreakBeforeBraces == R.BreakBeforeBraces && BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations && + BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakConstructorInitializers == R.BreakConstructorInitializers && BreakInheritanceList == R.BreakInheritanceList && diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -352,8 +352,12 @@ auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack); return LambdaBodyLength > getColumnLimit(State); } - if (Current.MustBreakBefore || Current.is(TT_InlineASMColon)) + if (Current.MustBreakBefore || + (Current.is(TT_InlineASMColon) && + (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always || + Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_OnlyMultiline))) { return true; + } if (CurrentState.BreakBeforeClosingBrace && Current.closesBlockOrBlockTypeList(Style)) { return true; diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -229,6 +229,15 @@ } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, + FormatStyle::BreakBeforeInlineASMColonStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::BBIAS_Never); + IO.enumCase(Value, "OnlyMultiline", FormatStyle::BBIAS_OnlyMultiline); + IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always); + } +}; template <> struct ScalarEnumerationTraits { static void @@ -827,6 +836,8 @@ IO.mapOptional("BreakBeforeConceptDeclarations", Style.BreakBeforeConceptDeclarations); IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); + IO.mapOptional("BreakBeforeInlineASMColon", + Style.BreakBeforeInlineASMColon); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakConstructorInitializers", @@ -1263,6 +1274,7 @@ LLVMStyle.BreakArrays = true; LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; + LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false, diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4443,6 +4443,11 @@ } } + if (Line.startsWith(tok::kw_asm) && Right.is(TT_InlineASMColon) && + Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always) { + return true; + } + // If the last token before a '}', ']', or ')' is a comma or a trailing // comment, the intention is to insert a line break after it in order to make // shuffling around entries easier. Import statements, especially in diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -7259,6 +7259,59 @@ format(Input, Style)); } +TEST_F(FormatTest, BreakBeforeInlineASMColon) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeInlineASMColon = FormatStyle::BBIAS_Never; + /* Test the behaviour with long lines */ + Style.ColumnLimit = 40; + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : : val);", + Style); + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : val1 : val2);", + Style); + verifyFormat("asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" + " \"cpuid\\n\\t\"\n" + " \"xchgq\\t%%rbx %%rsi\\n\\t\",\n" + " : \"=a\" : \"a\");", + Style); + Style.ColumnLimit = 80; + verifyFormat("asm volatile(\"string\", : : val);", Style); + verifyFormat("asm volatile(\"string\", : val1 : val2);", Style); + + Style.BreakBeforeInlineASMColon = FormatStyle::BBIAS_Always; + verifyFormat("asm volatile(\"string\",\n" + " :\n" + " : val);", + Style); + verifyFormat("asm volatile(\"string\",\n" + " : val1\n" + " : val2);", + Style); + /* Test the behaviour with long lines */ + Style.ColumnLimit = 40; + verifyFormat("asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" + " \"cpuid\\n\\t\"\n" + " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n" + " : \"=a\"(*rEAX)\n" + " : \"a\"(value));", + Style); + verifyFormat("asm(\"movq\\t%%rbx, %%rsi\\n\\t\"\n" + " \"cpuid\\n\\t\"\n" + " \"xchgq\\t%%rbx, %%rsi\\n\\t\"\n" + " :\n" + " : \"a\"(value));", + Style); + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " :\n" + " : val);", + Style); + verifyFormat("asm volatile(\"loooooooooooooooooooong\",\n" + " : val1\n" + " : val2);", + Style); +} + TEST_F(FormatTest, BreakConstructorInitializersAfterColon) { FormatStyle Style = getLLVMStyle(); Style.BreakConstructorInitializers = FormatStyle::BCIS_AfterColon;