| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| /*===------------- amxfp8intrin.h - AMX intrinsics -*- 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 __IMMINTRIN_H | ||
| #error "Never use <amxfp8intrin.h> directly; include <immintrin.h> instead." | ||
| #endif /* __IMMINTRIN_H */ | ||
|
|
||
| #ifndef __AMXFP8INTRIN_H | ||
| #define __AMXFP8INTRIN_H | ||
| #ifdef __x86_64__ | ||
|
|
||
| /// Peform the dot product of a BF8 value \a a by a BF8 value \a b accumulating | ||
| /// into a Single Precision (FP32) source/dest \a dst. | ||
| /// | ||
| /// \headerfile <immintrin.h> | ||
| /// | ||
| /// \code | ||
| /// void _tile_dpbf8ps (__tile dst, __tile a, __tile b) | ||
| /// \endcode | ||
| /// | ||
| /// This intrinsic corresponds to the \c TDPBF8PS instruction. | ||
| /// | ||
| /// \param dst | ||
| /// The destination tile. Max size is 1024 Bytes. | ||
| /// \param a | ||
| /// The 1st source tile. Max size is 1024 Bytes. | ||
| /// \param b | ||
| /// The 2nd source tile. Max size is 1024 Bytes. | ||
| #define _tile_dpbf8ps(dst, a, b) __builtin_ia32_tdpbf8ps((dst), (a), (b)) | ||
|
|
||
| /// Perform the dot product of a BF8 value \a a by an HF8 value \a b | ||
| /// accumulating into a Single Precision (FP32) source/dest \a dst. | ||
| /// | ||
| /// \headerfile <immintrin.h> | ||
| /// | ||
| /// \code | ||
| /// void _tile_dpbhf8ps (__tile dst, __tile a, __tile b) | ||
| /// \endcode | ||
| /// | ||
| /// This intrinsic corresponds to the \c TDPBHF8PS instruction. | ||
| /// | ||
| /// \param dst | ||
| /// The destination tile. Max size is 1024 Bytes. | ||
| /// \param a | ||
| /// The 1st source tile. Max size is 1024 Bytes. | ||
| /// \param b | ||
| /// The 2nd source tile. Max size is 1024 Bytes. | ||
| #define _tile_dpbhf8ps(dst, a, b) __builtin_ia32_tdpbhf8ps((dst), (a), (b)) | ||
|
|
||
| /// Perform the dot product of an HF8 value \a a by a BF8 value \a b | ||
| /// accumulating into a Single Precision (FP32) source/dest \a dst. | ||
| /// | ||
| /// \headerfile <immintrin.h> | ||
| /// | ||
| /// \code | ||
| /// void _tile_dphbf8ps (__tile dst, __tile a, __tile b) | ||
| /// \endcode | ||
| /// | ||
| /// This intrinsic corresponds to the \c TDPHBF8PS instruction. | ||
| /// | ||
| /// \param dst | ||
| /// The destination tile. Max size is 1024 Bytes. | ||
| /// \param a | ||
| /// The 1st source tile. Max size is 1024 Bytes. | ||
| /// \param b | ||
| /// The 2nd source tile. Max size is 1024 Bytes. | ||
| #define _tile_dphbf8ps(dst, a, b) __builtin_ia32_tdphbf8ps((dst), (a), (b)) | ||
|
|
||
| /// Perform the dot product of an HF8 value \a a by an HF8 value \a b | ||
| /// accumulating into a Single Precision (FP32) source/dest \a dst. | ||
| /// | ||
| /// \headerfile <immintrin.h> | ||
| /// | ||
| /// \code | ||
| /// void _tile_dphf8ps (__tile dst, __tile a, __tile b) | ||
| /// \endcode | ||
| /// | ||
| /// This intrinsic corresponds to the \c TDPHF8PS instruction. | ||
| /// | ||
| /// \param dst | ||
| /// The destination tile. Max size is 1024 Bytes. | ||
| /// \param a | ||
| /// The 1st source tile. Max size is 1024 Bytes. | ||
| /// \param b | ||
| /// The 2nd source tile. Max size is 1024 Bytes. | ||
| #define _tile_dphf8ps(dst, a, b) __builtin_ia32_tdphf8ps((dst), (a), (b)) | ||
|
|
||
| #endif /* __x86_64__ */ | ||
| #endif /* __AMXFP8INTRIN_H */ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-fp8 \ | ||
| // RUN: -emit-llvm -o - -Werror -pedantic | FileCheck %s | ||
| #include <immintrin.h> | ||
|
|
||
| void test_amx(void *data) { | ||
| //CHECK-LABEL: @test_amx | ||
| //CHECK: call void @llvm.x86.tdpbf8ps(i8 1, i8 2, i8 3) | ||
| _tile_dpbf8ps(1, 2, 3); | ||
| } | ||
|
|
||
| void test_amx2(void *data) { | ||
| //CHECK-LABEL: @test_amx2 | ||
| //CHECK: call void @llvm.x86.tdpbhf8ps(i8 1, i8 2, i8 3) | ||
| _tile_dpbhf8ps(1, 2, 3); | ||
| } | ||
|
|
||
| void test_amx3(void *data) { | ||
| //CHECK-LABEL: @test_amx3 | ||
| //CHECK: call void @llvm.x86.tdphbf8ps(i8 1, i8 2, i8 3) | ||
| _tile_dphbf8ps(1, 2, 3); | ||
| } | ||
|
|
||
| void test_amx4(void *data) { | ||
| //CHECK-LABEL: @test_amx4 | ||
| //CHECK: call void @llvm.x86.tdphf8ps(i8 1, i8 2, i8 3) | ||
| _tile_dphf8ps(1, 2, 3); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| // RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-tile -target-feature +amx-fp8 -verify | ||
|
|
||
| #include <immintrin.h> | ||
|
|
||
| void test_amx(void *data) { | ||
| _tile_dpbf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}} | ||
| _tile_dpbhf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}} | ||
| _tile_dphbf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}} | ||
| _tile_dphf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-fp8 -emit-llvm -o - -Wall -Werror -pedantic | FileCheck %s | ||
|
|
||
| void f_tilemul(short a) | ||
| { | ||
| //CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdpbf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"() | ||
| __asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t" | ||
| "tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t" | ||
| "tdpbf8ps %%tmm6, %%tmm0, %%tmm7 \n\t" | ||
| "tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t" | ||
| ::: "memory", "tmm0", "tmm6", "tmm7"); | ||
|
|
||
| //CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdpbhf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"() | ||
| __asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t" | ||
| "tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t" | ||
| "tdpbhf8ps %%tmm6, %%tmm0, %%tmm7 \n\t" | ||
| "tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t" | ||
| ::: "memory", "tmm0", "tmm6", "tmm7"); | ||
|
|
||
| //CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdphbf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"() | ||
| __asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t" | ||
| "tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t" | ||
| "tdphbf8ps %%tmm6, %%tmm0, %%tmm7 \n\t" | ||
| "tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t" | ||
| ::: "memory", "tmm0", "tmm6", "tmm7"); | ||
|
|
||
| //CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdphf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"() | ||
| __asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t" | ||
| "tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t" | ||
| "tdphf8ps %%tmm6, %%tmm0, %%tmm7 \n\t" | ||
| "tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t" | ||
| ::: "memory", "tmm0", "tmm6", "tmm7"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // RUN: rm -rf %t | ||
| // RUN: mkdir %t | ||
| // RUN: split-file %s %t | ||
| // | ||
| // RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm -fretain-comments-from-system-headers | ||
| // RUN: %clang_cc1 -std=c++20 %t/b.cpp -fmodule-file=a=%t/a.pcm -verify -fsyntax-only | ||
|
|
||
| //--- a.cppm | ||
| export module a; | ||
|
|
||
| //--- b.cpp | ||
| // expected-no-diagnostics | ||
| import a; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| //===- unittests/StaticAnalyzer/SValSimplifyerTest.cpp --------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "CheckerRegistration.h" | ||
| #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" | ||
| #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | ||
| #include "clang/StaticAnalyzer/Core/Checker.h" | ||
| #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" | ||
| #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" | ||
| #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" | ||
| #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" | ||
| #include "llvm/ADT/Twine.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| using namespace clang; | ||
| using namespace ento; | ||
|
|
||
| static std::string toString(SVal V) { | ||
| std::string Result; | ||
| llvm::raw_string_ostream Stream(Result); | ||
| V.dumpToStream(Stream); | ||
| return Result; | ||
| } | ||
|
|
||
| static void replace(std::string &Content, StringRef Substr, | ||
| StringRef Replacement) { | ||
| std::size_t Pos = 0; | ||
| while ((Pos = Content.find(Substr, Pos)) != std::string::npos) { | ||
| Content.replace(Pos, Substr.size(), Replacement); | ||
| Pos += Replacement.size(); | ||
| } | ||
| } | ||
|
|
||
| namespace { | ||
|
|
||
| class SimplifyChecker : public Checker<check::PreCall> { | ||
| const BugType Bug{this, "SimplifyChecker"}; | ||
| const CallDescription SimplifyCall{CDM::SimpleFunc, {"simplify"}, 1}; | ||
|
|
||
| void report(CheckerContext &C, const Expr *E, StringRef Description) const { | ||
| PathDiagnosticLocation Loc(E->getExprLoc(), C.getSourceManager()); | ||
| auto Report = std::make_unique<BasicBugReport>(Bug, Description, Loc); | ||
| C.emitReport(std::move(Report)); | ||
| } | ||
|
|
||
| public: | ||
| void checkPreCall(const CallEvent &Call, CheckerContext &C) const { | ||
| if (!SimplifyCall.matches(Call)) | ||
| return; | ||
| const Expr *Arg = Call.getArgExpr(0); | ||
| SVal Val = C.getSVal(Arg); | ||
| SVal SimplifiedVal = C.getSValBuilder().simplifySVal(C.getState(), Val); | ||
| std::string Subject = toString(Val); | ||
| std::string Simplified = toString(SimplifiedVal); | ||
| std::string Message = (llvm::Twine{Subject} + " -> " + Simplified).str(); | ||
| report(C, Arg, Message); | ||
| } | ||
| }; | ||
| } // namespace | ||
|
|
||
| static void addSimplifyChecker(AnalysisASTConsumer &AnalysisConsumer, | ||
| AnalyzerOptions &AnOpts) { | ||
| AnOpts.CheckersAndPackages = {{"SimplifyChecker", true}}; | ||
| AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { | ||
| Registry.addChecker<SimplifyChecker>("SimplifyChecker", "EmptyDescription", | ||
| "EmptyDocsUri"); | ||
| }); | ||
| } | ||
|
|
||
| static void runThisCheckerOnCode(const std::string &Code, std::string &Diags) { | ||
| ASSERT_TRUE(runCheckerOnCode<addSimplifyChecker>(Code, Diags, | ||
| /*OnlyEmitWarnings=*/true)); | ||
| ASSERT_FALSE(Diags.empty()); | ||
| ASSERT_EQ(Diags.back(), '\n'); | ||
| Diags.pop_back(); | ||
| } | ||
|
|
||
| namespace { | ||
|
|
||
| TEST(SValSimplifyerTest, LHSConstrainedNullPtrDiff) { | ||
| constexpr auto Code = R"cpp( | ||
| template <class T> void simplify(T); | ||
| void LHSConstrainedNullPtrDiff(char *p, char *q) { | ||
| int diff = p - q; | ||
| if (!p) | ||
| simplify(diff); | ||
| })cpp"; | ||
|
|
||
| std::string Diags; | ||
| runThisCheckerOnCode(Code, Diags); | ||
| replace(Diags, "(reg_$0<char * p>)", "reg_p"); | ||
| replace(Diags, "(reg_$1<char * q>)", "reg_q"); | ||
| // This should not be simplified to "Unknown". | ||
| EXPECT_EQ(Diags, "SimplifyChecker: reg_p - reg_q -> 0U - reg_q"); | ||
| } | ||
|
|
||
| } // namespace |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| ! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s | ||
|
|
||
| ! Simple tests for structured concurrent loops with loop-control. | ||
|
|
||
| pure function bar(n, m) | ||
| implicit none | ||
| integer, intent(in) :: n, m | ||
| integer :: bar | ||
| bar = n + m | ||
| end function | ||
|
|
||
| !CHECK-LABEL: sub1 | ||
| subroutine sub1(n) | ||
| implicit none | ||
| integer :: n, m, i, j, k | ||
| integer, dimension(n) :: a | ||
| !CHECK: %[[LB1:.*]] = arith.constant 1 : i32 | ||
| !CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index | ||
| !CHECK: %[[UB1:.*]] = fir.load %{{.*}}#0 : !fir.ref<i32> | ||
| !CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index | ||
|
|
||
| !CHECK: %[[LB2:.*]] = arith.constant 1 : i32 | ||
| !CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index | ||
| !CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs<pure> fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>) -> i32 | ||
| !CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index | ||
|
|
||
| !CHECK: %[[LB3:.*]] = arith.constant 5 : i32 | ||
| !CHECK: %[[LB3_CVT:.*]] = fir.convert %[[LB3]] : (i32) -> index | ||
| !CHECK: %[[UB3:.*]] = arith.constant 10 : i32 | ||
| !CHECK: %[[UB3_CVT:.*]] = fir.convert %[[UB3]] : (i32) -> index | ||
|
|
||
| !CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered | ||
| !CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered | ||
| !CHECK: fir.do_loop %{{.*}} = %[[LB3_CVT]] to %[[UB3_CVT]] step %{{.*}} unordered | ||
|
|
||
| do concurrent(i=1:n, j=1:bar(n*m, n/m), k=5:10) | ||
| a(i) = n | ||
| end do | ||
| end subroutine | ||
|
|
||
| !CHECK-LABEL: sub2 | ||
| subroutine sub2(n) | ||
| implicit none | ||
| integer :: n, m, i, j | ||
| integer, dimension(n) :: a | ||
| !CHECK: %[[LB1:.*]] = arith.constant 1 : i32 | ||
| !CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index | ||
| !CHECK: %[[UB1:.*]] = fir.load %5#0 : !fir.ref<i32> | ||
| !CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index | ||
| !CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered | ||
| !CHECK: %[[LB2:.*]] = arith.constant 1 : i32 | ||
| !CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index | ||
| !CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs<pure> fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>) -> i32 | ||
| !CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index | ||
| !CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered | ||
| do concurrent(i=1:n) | ||
| do concurrent(j=1:bar(n*m, n/m)) | ||
| a(i) = n | ||
| end do | ||
| end do | ||
| end subroutine | ||
|
|
||
|
|
||
| !CHECK-LABEL: unstructured | ||
| subroutine unstructured(inner_step) | ||
| integer(4) :: i, j, inner_step | ||
|
|
||
| !CHECK-NOT: cf.br | ||
| !CHECK-NOT: cf.cond_br | ||
| !CHECK: %[[LB1:.*]] = arith.constant 1 : i32 | ||
| !CHECK: %[[LB1_CVT:.*]] = fir.convert %c1_i32 : (i32) -> i16 | ||
| !CHECK: %[[UB1:.*]] = arith.constant 5 : i32 | ||
| !CHECK: %[[UB1_CVT:.*]] = fir.convert %c5_i32 : (i32) -> i16 | ||
| !CHECK: %[[STP1:.*]] = arith.constant 1 : i16 | ||
|
|
||
| !CHECK-NOT: cf.br | ||
| !CHECK-NOT: cf.cond_br | ||
| !CHECK: %[[LB2:.*]] = arith.constant 3 : i32 | ||
| !CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> i16 | ||
| !CHECK: %[[UB2:.*]] = arith.constant 9 : i32 | ||
| !CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> i16 | ||
| !CHECK: %[[STP2:.*]] = fir.load %{{.*}}#0 : !fir.ref<i32> | ||
| !CHECK: %[[STP2_CVT:.*]] = fir.convert %[[STP2]] : (i32) -> i16 | ||
| !CHECK: fir.store %[[STP2_CVT]] to %{{.*}} : !fir.ref<i16> | ||
| !CHECK: cf.br ^[[I_LOOP_HEADER:.*]] | ||
|
|
||
| !CHECK: ^[[I_LOOP_HEADER]]: | ||
| !CHECK-NEXT: %{{.*}} = fir.load %{{.*}} : !fir.ref<i16> | ||
| !CHECK-NEXT: %{{.*}} = arith.constant 0 : i16 | ||
| !CHECK-NEXT: %{{.*}} = arith.cmpi sgt, %{{.*}}, %{{.*}}: i16 | ||
| !CHECK-NEXT: cf.cond_br %{{.*}}, ^[[J_LOOP_HEADER:.*]], ^{{.*}} | ||
|
|
||
| !CHECK: ^[[J_LOOP_HEADER]]: | ||
| !CHECK-NEXT: %[[RANGE:.*]] = arith.subi %[[UB2_CVT]], %[[LB2_CVT]] : i16 | ||
| !CHECK-NEXT: %{{.*}} = arith.addi %[[RANGE]], %[[STP2_CVT]] : i16 | ||
| !CHECK-NEXT: %{{.*}} = arith.divsi %{{.*}}, %[[STP2_CVT]] : i16 | ||
| do concurrent (integer(2)::i=1:5, j=3:9:inner_step, i.ne.3) | ||
| goto (7, 7) i+1 | ||
| print*, 'E:', i, j | ||
| 7 continue | ||
| enddo | ||
| end subroutine unstructured |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,49 +1,56 @@ | ||
| //===-- Unittests for fstatvfs --------------------------------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "hdr/fcntl_macros.h" | ||
| #include "src/__support/macros/config.h" | ||
| #include "src/fcntl/open.h" | ||
| #include "src/sys/stat/mkdirat.h" | ||
| #include "src/sys/statvfs/fstatvfs.h" | ||
| #include "src/unistd/close.h" | ||
| #include "src/unistd/rmdir.h" | ||
| #include "test/UnitTest/ErrnoSetterMatcher.h" | ||
| #include "test/UnitTest/Test.h" | ||
|
|
||
| using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher; | ||
|
|
||
| TEST(LlvmLibcSysFStatvfsTest, FStatvfsBasic) { | ||
| struct statvfs buf; | ||
|
|
||
| int fd = LIBC_NAMESPACE::open("/", O_PATH); | ||
| ASSERT_ERRNO_SUCCESS(); | ||
| ASSERT_GT(fd, 0); | ||
|
|
||
| // The root of the file directory must always exist | ||
| ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Succeeds()); | ||
| ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); | ||
| } | ||
|
|
||
| TEST(LlvmLibcSysFStatvfsTest, FStatvfsInvalidPath) { | ||
| struct statvfs buf; | ||
|
|
||
| constexpr const char *FILENAME = "testdata/statvfs.testdir"; | ||
| auto TEST_DIR = libc_make_test_file_path(FILENAME); | ||
|
|
||
| ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU), | ||
| Succeeds(0)); | ||
|
|
||
| int fd = LIBC_NAMESPACE::open(TEST_DIR, O_PATH); | ||
| ASSERT_ERRNO_SUCCESS(); | ||
| ASSERT_GT(fd, 0); | ||
|
|
||
| // create the file, assert it exists, then delete it and assert it doesn't | ||
| // exist anymore. | ||
|
|
||
| ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Succeeds()); | ||
|
|
||
| ASSERT_THAT(LIBC_NAMESPACE::rmdir(TEST_DIR), Succeeds(0)); | ||
|
|
||
| ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Fails(ENOENT)); | ||
| ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); | ||
| ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Fails(ENOENT)); | ||
| } |