| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| //===--- UseStdNumbersCheck.h - clang-tidy ----------------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H | ||
| #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H | ||
|
|
||
| #include "../ClangTidyCheck.h" | ||
| #include "../utils/IncludeInserter.h" | ||
|
|
||
| namespace clang::tidy::modernize { | ||
|
|
||
| /// Finds constants and function calls to math functions that can be replaced | ||
| /// with c++20's mathematical constants from the ``numbers`` header and | ||
| /// offers fix-it hints. | ||
| /// Does not match the use of variables with that value, and instead, | ||
| /// offers a replacement at the definition of those variables. | ||
| /// | ||
| /// For the user-facing documentation see: | ||
| /// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-numbers.html | ||
| class UseStdNumbersCheck : public ClangTidyCheck { | ||
| public: | ||
| UseStdNumbersCheck(StringRef Name, ClangTidyContext *Context); | ||
|
|
||
| bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||
| return LangOpts.CPlusPlus20; | ||
| } | ||
| void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||
| void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||
| void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, | ||
| Preprocessor *ModuleExpanderPP) override; | ||
| void storeOptions(ClangTidyOptions::OptionMap &Opts) override; | ||
| std::optional<TraversalKind> getCheckTraversalKind() const override { | ||
| return TK_IgnoreUnlessSpelledInSource; | ||
| } | ||
|
|
||
| private: | ||
| utils::IncludeInserter IncludeInserter; | ||
| StringRef DiffThresholdString; | ||
| double DiffThreshold; | ||
| }; | ||
|
|
||
| } // namespace clang::tidy::modernize | ||
|
|
||
| #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDNUMBERSCHECK_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| .. title:: clang-tidy - modernize-use-std-numbers | ||
|
|
||
| modernize-use-std-numbers | ||
| ========================= | ||
|
|
||
| Finds constants and function calls to math functions that can be replaced | ||
| with C++20's mathematical constants from the ``numbers`` header and offers | ||
| fix-it hints. | ||
| Does not match the use of variables with that value, and instead, | ||
| offers a replacement for the definition of those variables. | ||
| Function calls that match the pattern of how the constant is calculated are | ||
| matched and replaced with the ``std::numbers`` constant. | ||
| The use of macros gets replaced with the corresponding ``std::numbers`` | ||
| constant, instead of changing the macro definition. | ||
|
|
||
| The following list of constants from the ``numbers`` header are supported: | ||
|
|
||
| * ``e`` | ||
| * ``log2e`` | ||
| * ``log10e`` | ||
| * ``pi`` | ||
| * ``inv_pi`` | ||
| * ``inv_sqrtpi`` | ||
| * ``ln2`` | ||
| * ``ln10`` | ||
| * ``sqrt2`` | ||
| * ``sqrt3`` | ||
| * ``inv_sqrt3`` | ||
| * ``egamma`` | ||
| * ``phi`` | ||
|
|
||
| The list currently includes all constants as of C++20. | ||
|
|
||
| The replacements use the type of the matched constant and can remove explicit | ||
| casts, i.e., switching between ``std::numbers::e``, | ||
| ``std::numbers::e_v<float>`` and ``std::numbers::e_v<long double>`` where | ||
| appropriate. | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| double sqrt(double); | ||
| double log2(double); | ||
| void sink(auto&&) {} | ||
| void floatSink(float); | ||
|
|
||
| #define MY_PI 3.1415926 | ||
|
|
||
| void foo() { | ||
| const double Pi = 3.141592653589; // const double Pi = std::numbers::pi | ||
| const auto Use = Pi / 2; // no match for Pi | ||
| static constexpr double Euler = 2.7182818; // static constexpr double Euler = std::numbers::e; | ||
|
|
||
| log2(exp(1)); // std::numbers::log2e; | ||
| log2(Euler); // std::numbers::log2e; | ||
| 1 / sqrt(MY_PI); // std::numbers::inv_sqrtpi; | ||
| sink(MY_PI); // sink(std::numbers::pi); | ||
| floatSink(MY_PI); // floatSink(std::numbers::pi); | ||
| floatSink(static_cast<float>(MY_PI)); // floatSink(std::numbers::pi_v<float>); | ||
| } | ||
|
|
||
| Options | ||
| ------- | ||
|
|
||
| .. option:: DiffThreshold | ||
|
|
||
| A floating point value that sets the detection threshold for when literals | ||
| match a constant. A literal matches a constant if | ||
| ``abs(literal - constant) < DiffThreshold`` evaluates to ``true``. Default | ||
| is `0.001`. | ||
|
|
||
| .. option:: IncludeStyle | ||
|
|
||
| A string specifying which include-style is used, `llvm` or `google`. Default | ||
| is `llvm`. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --include-generated-funcs --version 2 | ||
| ; RUN: opt < %s -passes='lowertypetests,default<O3>' -S | FileCheck %s | ||
|
|
||
| ; This IR is based of the following C++ | ||
| ; which was compiled with: | ||
| ; clang -cc1 -fexceptions -fcxx-exceptions \ | ||
| ; -std=c++11 -internal-isystem llvm-project/build/lib/clang/17/include \ | ||
| ; -nostdsysteminc -triple x86_64-unknown-linux -fsanitize=cfi-icall \ | ||
| ; -fsanitize-cfi-cross-dso -fsanitize-trap=cfi-icall -Oz -S -emit-llvm | ||
| ; int (*catch_ptr)(int); | ||
| ; int nothrow_e (int num) noexcept { | ||
| ; if (num) return 1; | ||
| ; return 0; | ||
| ; } | ||
| ; int call_catch(int num) { | ||
| ; catch_ptr = ¬hrow_e; | ||
| ; return catch_ptr(num); | ||
| ; } | ||
|
|
||
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux" | ||
|
|
||
| @catch_ptr = local_unnamed_addr global ptr null, align 8 | ||
| @llvm.used = appending global [1 x ptr] [ptr @__cfi_check_fail], section "llvm.metadata" | ||
|
|
||
| ; Function Attrs: minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(none) | ||
| define dso_local noundef i32 @_Z9nothrow_ei(i32 noundef %num) #0 !type !4 !type !5 !type !6 { | ||
| entry: | ||
| %tobool.not = icmp ne i32 %num, 0 | ||
| %. = zext i1 %tobool.not to i32 | ||
| ret i32 %. | ||
| } | ||
|
|
||
| ; Function Attrs: minsize mustprogress nounwind optsize | ||
| define dso_local noundef i32 @_Z10call_catchi(i32 noundef %num) local_unnamed_addr #1 !type !4 !type !5 !type !6 { | ||
| entry: | ||
| store ptr @_Z9nothrow_ei, ptr @catch_ptr, align 8, !tbaa !7 | ||
| %0 = tail call i1 @llvm.type.test(ptr nonnull @_Z9nothrow_ei, metadata !"_ZTSFiiE"), !nosanitize !11 | ||
| br i1 %0, label %cfi.cont, label %cfi.slowpath, !prof !12, !nosanitize !11 | ||
|
|
||
| cfi.slowpath: ; preds = %entry | ||
| tail call void @__cfi_slowpath(i64 5174074510188755522, ptr nonnull @_Z9nothrow_ei) #5, !nosanitize !11 | ||
| br label %cfi.cont, !nosanitize !11 | ||
|
|
||
| cfi.cont: ; preds = %cfi.slowpath, %entry | ||
| %tobool.not.i = icmp ne i32 %num, 0 | ||
| %..i = zext i1 %tobool.not.i to i32 | ||
| ret i32 %..i | ||
| } | ||
|
|
||
| ; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) | ||
| declare i1 @llvm.type.test(ptr, metadata) #2 | ||
|
|
||
| declare void @__cfi_slowpath(i64, ptr) local_unnamed_addr | ||
|
|
||
| ; Function Attrs: minsize optsize | ||
| define weak_odr hidden void @__cfi_check_fail(ptr noundef %0, ptr noundef %1) #3 { | ||
| entry: | ||
| %.not = icmp eq ptr %0, null, !nosanitize !11 | ||
| br i1 %.not, label %trap, label %cont, !nosanitize !11 | ||
|
|
||
| trap: ; preds = %cont, %entry | ||
| tail call void @llvm.ubsantrap(i8 2) #6, !nosanitize !11 | ||
| unreachable, !nosanitize !11 | ||
|
|
||
| cont: ; preds = %entry | ||
| %2 = load i8, ptr %0, align 4, !nosanitize !11 | ||
| %switch = icmp ult i8 %2, 5 | ||
| br i1 %switch, label %trap, label %cont6 | ||
|
|
||
| cont6: ; preds = %cont | ||
| ret void, !nosanitize !11 | ||
| } | ||
|
|
||
| ; Function Attrs: cold noreturn nounwind | ||
| declare void @llvm.ubsantrap(i8 immarg) #4 | ||
|
|
||
| define weak void @__cfi_check(i64 %0, ptr %1, ptr %2) local_unnamed_addr { | ||
| entry: | ||
| tail call void @llvm.trap() | ||
| unreachable | ||
| } | ||
|
|
||
| ; Function Attrs: cold noreturn nounwind | ||
| declare void @llvm.trap() #4 | ||
|
|
||
| attributes #0 = { minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(none) "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } | ||
| attributes #1 = { minsize mustprogress nounwind optsize "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } | ||
| attributes #2 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } | ||
| attributes #3 = { minsize optsize "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } | ||
| attributes #4 = { cold noreturn nounwind } | ||
| attributes #5 = { nounwind } | ||
| attributes #6 = { noreturn nounwind } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2} | ||
| !llvm.ident = !{!3} | ||
|
|
||
| !0 = !{i32 1, !"wchar_size", i32 4} | ||
| !1 = !{i32 4, !"Cross-DSO CFI", i32 1} | ||
| !2 = !{i32 4, !"CFI Canonical Jump Tables", i32 0} | ||
| !3 = !{!"clang version 17.0.2"} | ||
| !4 = !{i64 0, !"_ZTSFiiE"} | ||
| !5 = !{i64 0, !"_ZTSFiiE.generalized"} | ||
| !6 = !{i64 0, i64 5174074510188755522} | ||
| !7 = !{!8, !8, i64 0} | ||
| !8 = !{!"any pointer", !9, i64 0} | ||
| !9 = !{!"omnipotent char", !10, i64 0} | ||
| !10 = !{!"Simple C++ TBAA"} | ||
| !11 = !{} | ||
| !12 = !{!"branch_weights", i32 1048575, i32 1} | ||
| ; CHECK: Function Attrs: minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(none) | ||
| ; CHECK-LABEL: define dso_local noundef i32 @_Z9nothrow_ei | ||
| ; CHECK-SAME: (i32 noundef [[NUM:%.*]]) #[[ATTR0:[0-9]+]] !type !4 !type !5 !type !6 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp ne i32 [[NUM]], 0 | ||
| ; CHECK-NEXT: [[DOT:%.*]] = zext i1 [[TOBOOL_NOT]] to i32 | ||
| ; CHECK-NEXT: ret i32 [[DOT]] | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: minsize mustprogress nofree norecurse nosync nounwind optsize willreturn memory(write, argmem: none, inaccessiblemem: none) | ||
| ; CHECK-LABEL: define dso_local noundef i32 @_Z10call_catchi | ||
| ; CHECK-SAME: (i32 noundef [[NUM:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !type !4 !type !5 !type !6 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: store ptr @_Z9nothrow_ei.cfi_jt, ptr @catch_ptr, align 8, !tbaa [[TBAA7:![0-9]+]] | ||
| ; CHECK-NEXT: [[TOBOOL_NOT_I:%.*]] = icmp ne i32 [[NUM]], 0 | ||
| ; CHECK-NEXT: [[DOT_I:%.*]] = zext i1 [[TOBOOL_NOT_I]] to i32 | ||
| ; CHECK-NEXT: ret i32 [[DOT_I]] | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: minsize optsize | ||
| ; CHECK-LABEL: define weak_odr hidden void @__cfi_check_fail | ||
| ; CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR2:[0-9]+]] { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq ptr [[TMP0]], null, !nosanitize !11 | ||
| ; CHECK-NEXT: br i1 [[DOTNOT]], label [[TRAP:%.*]], label [[CONT:%.*]], !nosanitize !11 | ||
| ; CHECK: trap: | ||
| ; CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR5:[0-9]+]], !nosanitize !11 | ||
| ; CHECK-NEXT: unreachable, !nosanitize !11 | ||
| ; CHECK: cont: | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP0]], align 4, !nosanitize !11 | ||
| ; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[TMP2]], 5 | ||
| ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRAP]], label [[CONT6:%.*]] | ||
| ; CHECK: cont6: | ||
| ; CHECK-NEXT: ret void, !nosanitize !11 | ||
| ; | ||
| ; | ||
| ; CHECK-LABEL: define weak void @__cfi_check | ||
| ; CHECK-SAME: (i64 [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) local_unnamed_addr { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: tail call void @llvm.trap() | ||
| ; CHECK-NEXT: unreachable | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: naked nocf_check noinline nounwind | ||
| ; CHECK-LABEL: define internal void @_Z9nothrow_ei.cfi_jt | ||
| ; CHECK-SAME: () #[[ATTR4:[0-9]+]] align 8 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: tail call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(ptr nonnull @_Z9nothrow_ei) #[[ATTR6:[0-9]+]] | ||
| ; CHECK-NEXT: unreachable | ||
| ; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --include-generated-funcs --version 2 | ||
| ; RUN: opt < %s -passes='lowertypetests,default<O3>' -S | FileCheck %s | ||
|
|
||
| ; This IR is based of the following C++ | ||
| ; which was compiled with: | ||
| ; clang -cc1 -fexceptions -fcxx-exceptions \ | ||
| ; -std=c++11 -internal-isystem llvm-project/build/lib/clang/17/include \ | ||
| ; -nostdsysteminc -triple x86_64-unknown-linux -fsanitize=cfi-icall \ | ||
| ; -fsanitize-cfi-cross-dso -fsanitize-trap=cfi-icall -Oz -S -emit-llvm | ||
| ; void (*catch_ptr)(int); | ||
| ; void throw_e (int num) { | ||
| ; if (num) throw 20; | ||
| ; } | ||
| ; void call_catch(int num) { | ||
| ; catch_ptr = &throw_e; | ||
| ; try{ | ||
| ; catch_ptr(num); | ||
| ; } catch (int i) { | ||
| ; } | ||
| ; } | ||
|
|
||
| target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" | ||
| target triple = "x86_64-unknown-linux" | ||
|
|
||
| @catch_ptr = local_unnamed_addr global ptr null, align 8 | ||
| @_ZTIi = external constant ptr | ||
| @llvm.used = appending global [1 x ptr] [ptr @__cfi_check_fail], section "llvm.metadata" | ||
|
|
||
| ; Function Attrs: minsize mustprogress optsize | ||
| define dso_local void @_Z7throw_ei(i32 noundef %num) #0 !type !4 !type !5 !type !6 { | ||
| entry: | ||
| %tobool.not = icmp eq i32 %num, 0 | ||
| br i1 %tobool.not, label %if.end, label %if.then | ||
|
|
||
| if.then: ; preds = %entry | ||
| %exception = tail call ptr @__cxa_allocate_exception(i64 4) #5 | ||
| store i32 20, ptr %exception, align 16, !tbaa !7 | ||
| tail call void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null) #6 | ||
| unreachable | ||
|
|
||
| if.end: ; preds = %entry | ||
| ret void | ||
| } | ||
|
|
||
| declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr | ||
|
|
||
| declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr | ||
|
|
||
| ; Function Attrs: minsize mustprogress optsize | ||
| define dso_local void @_Z10call_catchi(i32 noundef %num) local_unnamed_addr #0 personality ptr @__gxx_personality_v0 !type !4 !type !5 !type !6 { | ||
| entry: | ||
| store ptr @_Z7throw_ei, ptr @catch_ptr, align 8, !tbaa !11 | ||
| %0 = tail call i1 @llvm.type.test(ptr nonnull @_Z7throw_ei, metadata !"_ZTSFviE"), !nosanitize !13 | ||
| br i1 %0, label %cfi.cont, label %cfi.slowpath, !prof !14, !nosanitize !13 | ||
|
|
||
| cfi.slowpath: ; preds = %entry | ||
| tail call void @__cfi_slowpath(i64 -8738933900360652027, ptr nonnull @_Z7throw_ei) #5, !nosanitize !13 | ||
| br label %cfi.cont, !nosanitize !13 | ||
|
|
||
| cfi.cont: ; preds = %cfi.slowpath, %entry | ||
| invoke void @_Z7throw_ei(i32 noundef %num) #7 | ||
| to label %try.cont unwind label %lpad | ||
|
|
||
| lpad: ; preds = %cfi.cont | ||
| %1 = landingpad { ptr, i32 } | ||
| catch ptr @_ZTIi | ||
| %2 = extractvalue { ptr, i32 } %1, 1 | ||
| %3 = tail call i32 @llvm.eh.typeid.for(ptr nonnull @_ZTIi) #5 | ||
| %matches = icmp eq i32 %2, %3 | ||
| br i1 %matches, label %catch, label %eh.resume | ||
|
|
||
| catch: ; preds = %lpad | ||
| %4 = extractvalue { ptr, i32 } %1, 0 | ||
| %5 = tail call ptr @__cxa_begin_catch(ptr %4) #5 | ||
| tail call void @__cxa_end_catch() #5 | ||
| br label %try.cont | ||
|
|
||
| try.cont: ; preds = %cfi.cont, %catch | ||
| ret void | ||
|
|
||
| eh.resume: ; preds = %lpad | ||
| resume { ptr, i32 } %1 | ||
| } | ||
|
|
||
| ; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) | ||
| declare i1 @llvm.type.test(ptr, metadata) #1 | ||
|
|
||
| declare void @__cfi_slowpath(i64, ptr) local_unnamed_addr | ||
|
|
||
| declare i32 @__gxx_personality_v0(...) | ||
|
|
||
| ; Function Attrs: nofree nosync nounwind memory(none) | ||
| declare i32 @llvm.eh.typeid.for(ptr) #2 | ||
|
|
||
| declare ptr @__cxa_begin_catch(ptr) local_unnamed_addr | ||
|
|
||
| declare void @__cxa_end_catch() local_unnamed_addr | ||
|
|
||
| ; Function Attrs: minsize optsize | ||
| define weak_odr hidden void @__cfi_check_fail(ptr noundef %0, ptr noundef %1) #3 { | ||
| entry: | ||
| %.not = icmp eq ptr %0, null, !nosanitize !13 | ||
| br i1 %.not, label %trap, label %cont, !nosanitize !13 | ||
|
|
||
| trap: ; preds = %cont, %entry | ||
| tail call void @llvm.ubsantrap(i8 2) #8, !nosanitize !13 | ||
| unreachable, !nosanitize !13 | ||
|
|
||
| cont: ; preds = %entry | ||
| %2 = load i8, ptr %0, align 4, !nosanitize !13 | ||
| %switch = icmp ult i8 %2, 5 | ||
| br i1 %switch, label %trap, label %cont6 | ||
|
|
||
| cont6: ; preds = %cont | ||
| ret void, !nosanitize !13 | ||
| } | ||
|
|
||
| ; Function Attrs: cold noreturn nounwind | ||
| declare void @llvm.ubsantrap(i8 immarg) #4 | ||
|
|
||
| define weak void @__cfi_check(i64 %0, ptr %1, ptr %2) local_unnamed_addr { | ||
| entry: | ||
| tail call void @llvm.trap() | ||
| unreachable | ||
| } | ||
|
|
||
| ; Function Attrs: cold noreturn nounwind | ||
| declare void @llvm.trap() #4 | ||
|
|
||
| attributes #0 = { minsize mustprogress optsize "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } | ||
| attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } | ||
| attributes #2 = { nofree nosync nounwind memory(none) } | ||
| attributes #3 = { minsize optsize "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" } | ||
| attributes #4 = { cold noreturn nounwind } | ||
| attributes #5 = { nounwind } | ||
| attributes #6 = { noreturn } | ||
| attributes #7 = { minsize optsize } | ||
| attributes #8 = { noreturn nounwind } | ||
|
|
||
| !llvm.module.flags = !{!0, !1, !2} | ||
| !llvm.ident = !{!3} | ||
|
|
||
| !0 = !{i32 1, !"wchar_size", i32 4} | ||
| !1 = !{i32 4, !"Cross-DSO CFI", i32 1} | ||
| !2 = !{i32 4, !"CFI Canonical Jump Tables", i32 0} | ||
| !3 = !{!"clang version 17.0.2"} | ||
| !4 = !{i64 0, !"_ZTSFviE"} | ||
| !5 = !{i64 0, !"_ZTSFviE.generalized"} | ||
| !6 = !{i64 0, i64 -8738933900360652027} | ||
| !7 = !{!8, !8, i64 0} | ||
| !8 = !{!"int", !9, i64 0} | ||
| !9 = !{!"omnipotent char", !10, i64 0} | ||
| !10 = !{!"Simple C++ TBAA"} | ||
| !11 = !{!12, !12, i64 0} | ||
| !12 = !{!"any pointer", !9, i64 0} | ||
| !13 = !{} | ||
| !14 = !{!"branch_weights", i32 1048575, i32 1} | ||
| ; CHECK: Function Attrs: minsize mustprogress optsize | ||
| ; CHECK-LABEL: define dso_local void @_Z7throw_ei | ||
| ; CHECK-SAME: (i32 noundef [[NUM:%.*]]) #[[ATTR0:[0-9]+]] !type !4 !type !5 !type !6 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq i32 [[NUM]], 0 | ||
| ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[IF_END:%.*]], label [[IF_THEN:%.*]] | ||
| ; CHECK: if.then: | ||
| ; CHECK-NEXT: [[EXCEPTION:%.*]] = tail call ptr @__cxa_allocate_exception(i64 4) #[[ATTR5:[0-9]+]] | ||
| ; CHECK-NEXT: store i32 20, ptr [[EXCEPTION]], align 16, !tbaa [[TBAA7:![0-9]+]] | ||
| ; CHECK-NEXT: tail call void @__cxa_throw(ptr nonnull [[EXCEPTION]], ptr nonnull @_ZTIi, ptr null) #[[ATTR6:[0-9]+]] | ||
| ; CHECK-NEXT: unreachable | ||
| ; CHECK: if.end: | ||
| ; CHECK-NEXT: ret void | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: minsize mustprogress optsize | ||
| ; CHECK-LABEL: define dso_local void @_Z10call_catchi | ||
| ; CHECK-SAME: (i32 noundef [[NUM:%.*]]) local_unnamed_addr #[[ATTR0]] personality ptr @__gxx_personality_v0 !type !4 !type !5 !type !6 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: store ptr @_Z7throw_ei.cfi_jt, ptr @catch_ptr, align 8, !tbaa [[TBAA11:![0-9]+]] | ||
| ; CHECK-NEXT: invoke void @_Z7throw_ei.cfi_jt() #[[ATTR7:[0-9]+]] | ||
| ; CHECK-NEXT: to label [[TRY_CONT:%.*]] unwind label [[LPAD:%.*]] | ||
| ; CHECK: lpad: | ||
| ; CHECK-NEXT: [[TMP0:%.*]] = landingpad { ptr, i32 } | ||
| ; CHECK-NEXT: catch ptr @_ZTIi | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 1 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = tail call i32 @llvm.eh.typeid.for(ptr nonnull @_ZTIi) #[[ATTR5]] | ||
| ; CHECK-NEXT: [[MATCHES:%.*]] = icmp eq i32 [[TMP1]], [[TMP2]] | ||
| ; CHECK-NEXT: br i1 [[MATCHES]], label [[CATCH:%.*]], label [[EH_RESUME:%.*]] | ||
| ; CHECK: catch: | ||
| ; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { ptr, i32 } [[TMP0]], 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = tail call ptr @__cxa_begin_catch(ptr [[TMP3]]) #[[ATTR5]] | ||
| ; CHECK-NEXT: tail call void @__cxa_end_catch() #[[ATTR5]] | ||
| ; CHECK-NEXT: br label [[TRY_CONT]] | ||
| ; CHECK: try.cont: | ||
| ; CHECK-NEXT: ret void | ||
| ; CHECK: eh.resume: | ||
| ; CHECK-NEXT: resume { ptr, i32 } [[TMP0]] | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: minsize optsize | ||
| ; CHECK-LABEL: define weak_odr hidden void @__cfi_check_fail | ||
| ; CHECK-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR2:[0-9]+]] { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq ptr [[TMP0]], null, !nosanitize !13 | ||
| ; CHECK-NEXT: br i1 [[DOTNOT]], label [[TRAP:%.*]], label [[CONT:%.*]], !nosanitize !13 | ||
| ; CHECK: trap: | ||
| ; CHECK-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR8:[0-9]+]], !nosanitize !13 | ||
| ; CHECK-NEXT: unreachable, !nosanitize !13 | ||
| ; CHECK: cont: | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[TMP0]], align 4, !nosanitize !13 | ||
| ; CHECK-NEXT: [[SWITCH:%.*]] = icmp ult i8 [[TMP2]], 5 | ||
| ; CHECK-NEXT: br i1 [[SWITCH]], label [[TRAP]], label [[CONT6:%.*]] | ||
| ; CHECK: cont6: | ||
| ; CHECK-NEXT: ret void, !nosanitize !13 | ||
| ; | ||
| ; | ||
| ; CHECK-LABEL: define weak void @__cfi_check | ||
| ; CHECK-SAME: (i64 [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) local_unnamed_addr { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: tail call void @llvm.trap() | ||
| ; CHECK-NEXT: unreachable | ||
| ; | ||
| ; | ||
| ; CHECK: Function Attrs: naked nocf_check noinline | ||
| ; CHECK-LABEL: define internal void @_Z7throw_ei.cfi_jt | ||
| ; CHECK-SAME: () #[[ATTR4:[0-9]+]] align 8 { | ||
| ; CHECK-NEXT: entry: | ||
| ; CHECK-NEXT: tail call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(ptr nonnull @_Z7throw_ei) #[[ATTR5]] | ||
| ; CHECK-NEXT: unreachable | ||
| ; |