37 changes: 22 additions & 15 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2870,19 +2870,6 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
#endif
it = FixablesForAllVars.byVar.erase(it);
} else if (Tracker.hasUnclaimedUses(it->first)) {
#ifndef NDEBUG
auto AllUnclaimed = Tracker.getUnclaimedUses(it->first);
for (auto UnclaimedDRE : AllUnclaimed) {
std::string UnclaimedUseTrace =
getDREAncestorString(UnclaimedDRE, D->getASTContext());

Handler.addDebugNoteForVar(
it->first, UnclaimedDRE->getBeginLoc(),
("failed to produce fixit for '" + it->first->getNameAsString() +
"' : has an unclaimed use\nThe unclaimed DRE trace: " +
UnclaimedUseTrace));
}
#endif
it = FixablesForAllVars.byVar.erase(it);
} else if (it->first->isInitCapture()) {
#ifndef NDEBUG
Expand All @@ -2892,10 +2879,30 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
"' : init capture"));
#endif
it = FixablesForAllVars.byVar.erase(it);
}else {
++it;
} else {
++it;
}
}

#ifndef NDEBUG
for (const auto &it : UnsafeOps.byVar) {
const VarDecl *const UnsafeVD = it.first;
auto UnclaimedDREs = Tracker.getUnclaimedUses(UnsafeVD);
if (UnclaimedDREs.empty())
continue;
const auto UnfixedVDName = UnsafeVD->getNameAsString();
for (const clang::DeclRefExpr *UnclaimedDRE : UnclaimedDREs) {
std::string UnclaimedUseTrace =
getDREAncestorString(UnclaimedDRE, D->getASTContext());

Handler.addDebugNoteForVar(
UnsafeVD, UnclaimedDRE->getBeginLoc(),
("failed to produce fixit for '" + UnfixedVDName +
"' : has an unclaimed use\nThe unclaimed DRE trace: " +
UnclaimedUseTrace));
}
}
#endif

// Fixpoint iteration for pointer assignments
using DepMapTy = DenseMap<const VarDecl *, llvm::SetVector<const VarDecl *>>;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/BreakableToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,11 @@ const FormatToken &BreakableComment::tokenAt(unsigned LineIndex) const {

static bool mayReflowContent(StringRef Content) {
Content = Content.trim(Blanks);
// Lines starting with '@' commonly have special meaning.
// Lines starting with '@' or '\' commonly have special meaning.
// Lines starting with '-', '-#', '+' or '*' are bulleted/numbered lists.
bool hasSpecialMeaningPrefix = false;
for (StringRef Prefix :
{"@", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
{"@", "\\", "TODO", "FIXME", "XXX", "-# ", "- ", "+ ", "* "}) {
if (Content.starts_with(Prefix)) {
hasSpecialMeaningPrefix = true;
break;
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ class VerifyDiagnosticConsumer::MarkerTracker {
}
};

static std::string DetailedErrorString(const DiagnosticsEngine &Diags) {
if (Diags.getDiagnosticOptions().VerifyPrefixes.empty())
return "expected";
return *Diags.getDiagnosticOptions().VerifyPrefixes.begin();
}

/// ParseDirective - Go through the comment and see if it indicates expected
/// diagnostics. If so, then put them in the appropriate directive list.
///
Expand Down Expand Up @@ -478,14 +484,14 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
if (NoDiag) {
if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives)
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/true;
<< DetailedErrorString(Diags) << /*IsExpectedNoDiagnostics=*/true;
else
Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics;
continue;
}
if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) {
Diags.Report(Pos, diag::err_verify_invalid_no_diags)
<< /*IsExpectedNoDiagnostics=*/false;
<< DetailedErrorString(Diags) << /*IsExpectedNoDiagnostics=*/false;
continue;
}
Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives;
Expand Down Expand Up @@ -1104,7 +1110,8 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() {
// Produce an error if no expected-* directives could be found in the
// source file(s) processed.
if (Status == HasNoDirectives) {
Diags.Report(diag::err_verify_no_directives).setForceEmit();
Diags.Report(diag::err_verify_no_directives).setForceEmit()
<< DetailedErrorString(Diags);
++NumErrors;
Status = HasNoDirectivesReported;
}
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Headers/cpuid.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
#define bit_AMXINT8 0x02000000

/* Features in %eax for leaf 7 sub-leaf 1 */
#define bit_SHA512 0x00000001
#define bit_SM3 0x00000002
#define bit_SM4 0x00000004
#define bit_RAOINT 0x00000008
#define bit_AVXVNNI 0x00000010
#define bit_AVX512BF16 0x00000020
Expand All @@ -211,7 +214,11 @@
/* Features in %edx for leaf 7 sub-leaf 1 */
#define bit_AVXVNNIINT8 0x00000010
#define bit_AVXNECONVERT 0x00000020
#define bit_AMXCOMPLEX 0x00000100
#define bit_AVXVNNIINT16 0x00000400
#define bit_PREFETCHI 0x00004000
#define bit_USERMSR 0x00008000
#define bit_AVX10 0x00080000

/* Features in %eax for leaf 13 sub-leaf 1 */
#define bit_XSAVEOPT 0x00000001
Expand Down Expand Up @@ -244,6 +251,9 @@
#define bit_RDPRU 0x00000010
#define bit_WBNOINVD 0x00000200

/* Features in %ebx for leaf 0x24 */
#define bit_AVX10_256 0x00020000
#define bit_AVX10_512 0x00040000

#if __i386__
#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21124,6 +21124,8 @@ Sema::ActOnOpenMPDependClause(const OMPDependClause::DependDataTy &Data,
ExprTy = ATy->getElementType();
else
ExprTy = BaseType->getPointeeType();
if (BaseType.isNull() || ExprTy.isNull())
return nullptr;
ExprTy = ExprTy.getNonReferenceType();
const Expr *Length = OASE->getLength();
Expr::EvalResult Result;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7722,8 +7722,8 @@ bool Sema::CheckNonDependentConversions(
unsigned Offset =
Method && Method->hasCXXExplicitFunctionObjectParameter() ? 1 : 0;

for (unsigned I = 0, N = std::min(ParamTypes.size(), Args.size()); I != N;
++I) {
for (unsigned I = 0, N = std::min(ParamTypes.size() - Offset, Args.size());
I != N; ++I) {
QualType ParamType = ParamTypes[I + Offset];
if (!ParamType->isDependentType()) {
unsigned ConvIdx;
Expand Down
13 changes: 13 additions & 0 deletions clang/test/AST/Interp/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,16 @@ namespace ffs {
char ffs6[__builtin_ffsl(0x10L) == 5 ? 1 : -1];
char ffs7[__builtin_ffsll(0x100LL) == 9 ? 1 : -1];
}

namespace EhReturnDataRegno {
void test11(int X) {
switch (X) {
case __builtin_eh_return_data_regno(0): // constant foldable.
break;
}

__builtin_eh_return_data_regno(X); // expected-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}} \
// ref-error {{argument to '__builtin_eh_return_data_regno' must be a constant integer}}

}
}
28 changes: 28 additions & 0 deletions clang/test/AST/Interp/complex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ static_assert(__imag(I3) == 0, "");
// constexpr _Complex _BitInt(8) A = 0;// = {4};


constexpr _Complex double Doubles[4] = {{1.0, 2.0}};
static_assert(__real(Doubles[0]) == 1.0, "");
static_assert(__imag(Doubles[0]) == 2.0, "");
static_assert(__real(Doubles[1]) == 0.0, "");
static_assert(__imag(Doubles[1]) == 0.0, "");
static_assert(__real(Doubles[2]) == 0.0, "");
static_assert(__imag(Doubles[2]) == 0.0, "");
static_assert(__real(Doubles[3]) == 0.0, "");
static_assert(__imag(Doubles[3]) == 0.0, "");

void func(void) {
__complex__ int arr;
_Complex int result;
Expand Down Expand Up @@ -194,3 +204,21 @@ namespace ZeroInit {

constexpr int ignored = (fcomplex(), 0);
}

namespace DeclRefCopy {
constexpr _Complex int ComplexInt = 42 + 24i;

constexpr _Complex int B = ComplexInt;
constexpr _Complex int ArrayOfComplexInt[4] = {ComplexInt, ComplexInt, ComplexInt, ComplexInt};
static_assert(__real(ArrayOfComplexInt[0]) == 42, "");
static_assert(__imag(ArrayOfComplexInt[0]) == 24, "");
static_assert(__real(ArrayOfComplexInt[3]) == 42, "");
static_assert(__imag(ArrayOfComplexInt[3]) == 24, "");

constexpr int localComplexArray() {
_Complex int A = 42 + 24i;
_Complex int ArrayOfComplexInt[4] = {A, A, A, A};
return __real(ArrayOfComplexInt[0]) + __imag(ArrayOfComplexInt[3]);
}
static_assert(localComplexArray() == (24 + 42), "");
}
2 changes: 2 additions & 0 deletions clang/test/AST/Interp/literals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ namespace PointerComparison {
}

namespace SizeOf {
static_assert(alignof(char&) == 1, "");

constexpr int soint = sizeof(int);
constexpr int souint = sizeof(unsigned int);
static_assert(soint == souint, "");
Expand Down
4 changes: 4 additions & 0 deletions clang/test/AST/Interp/records.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
// RUN: %clang_cc1 -verify=ref -std=c++20 %s
// RUN: %clang_cc1 -verify=ref -triple i686 %s

/// Used to crash.
struct Empty {};
constexpr Empty e = {Empty()};

struct BoolPair {
bool first;
bool second;
Expand Down
22 changes: 8 additions & 14 deletions clang/test/AST/Interp/switch.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %clang_cc1 -std=c++17 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -std=c++17 -verify=ref %s
// RUN: %clang_cc1 -std=c++17 -fexperimental-new-constant-interpreter -verify=expected,both %s
// RUN: %clang_cc1 -std=c++17 -verify=ref,both %s

constexpr bool isEven(int a) {
bool v = false;
Expand Down Expand Up @@ -75,20 +75,14 @@ constexpr int test(int val) {
}
static_assert(test(1) == 100, "");

constexpr int bad(int val) { return val / 0; } // expected-warning {{division by zero}} \
// ref-warning {{division by zero}}
constexpr int another_test(int val) { // expected-note {{declared here}} \
// ref-note {{declared here}}
constexpr int bad(int val) { return val / 0; } // both-warning {{division by zero}}
constexpr int another_test(int val) { // both-note {{declared here}}
switch (val) {
case bad(val): return 100; // expected-error {{case value is not a constant expression}} \
// expected-note {{cannot be used in a constant expression}} \
// ref-error {{case value is not a constant expression}} \
// ref-note {{cannot be used in a constant expression}}
case bad(val): return 100; // both-error {{case value is not a constant expression}} \
// both-note {{cannot be used in a constant expression}}
default: return -1;
}
return 0;
}
static_assert(another_test(1) == 100, ""); // expected-error {{static assertion failed}} \
// expected-note {{evaluates to}} \
// ref-error {{static assertion failed}} \
// ref-note {{evaluates to}}
static_assert(another_test(1) == 100, ""); // both-error {{static assertion failed}} \
// both-note {{evaluates to}}
5 changes: 5 additions & 0 deletions clang/test/AST/fixed-point-zero-init.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// RUN: %clang_cc1 -ffixed-point %s -verify
// expected-no-diagnostics

constexpr _Accum a[2] = {};
static_assert(a[0] == 0 && a[0] != 1);
8 changes: 8 additions & 0 deletions clang/test/Driver/linker-wrapper-image.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// RUN: -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP,OPENMP-ELF
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run -r --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP-ELF,OPENMP-REL
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=OPENMP,OPENMP-COFF

Expand All @@ -19,6 +21,8 @@
// OPENMP-COFF: @__start_omp_offloading_entries = weak_odr hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OA"
// OPENMP-COFF-NEXT: @__stop_omp_offloading_entries = weak_odr hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OZ"

// OPENMP-REL: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading.relocatable", align 8

// OPENMP: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8
// OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr inbounds ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr getelementptr inbounds ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }]
// OPENMP-NEXT: @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }
Expand All @@ -42,6 +46,8 @@
// RUN: -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-ELF
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run -r --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-ELF
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=CUDA,CUDA-COFF

Expand Down Expand Up @@ -140,6 +146,8 @@
// RUN: -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-ELF
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-linux-gnu -r \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-ELF
// RUN: clang-linker-wrapper --print-wrapped-module --dry-run --host-triple=x86_64-unknown-windows-gnu \
// RUN: --linker-path=/usr/bin/ld -- %t.o -o a.out 2>&1 | FileCheck %s --check-prefixes=HIP,HIP-COFF

Expand Down
32 changes: 29 additions & 3 deletions clang/test/Driver/linker-wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,36 @@ __attribute__((visibility("protected"), used)) int x;
// RUN: --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu \
// RUN: --image=file=%t.elf.o,kind=openmp,triple=x86_64-unknown-linux-gnu
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
// RUN: llvm-ar rcs %t.a %t.o
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld.lld -- -r --whole-archive %t.a --no-whole-archive \
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK

// RELOCATABLE-LINK-NOT: clang{{.*}} -o {{.*}}.img --target=x86_64-unknown-linux-gnu
// RELOCATABLE-LINK: clang{{.*}} -o {{.*}}.img --target=x86_64-unknown-linux-gnu
// RELOCATABLE-LINK: /usr/bin/ld.lld{{.*}}-r
// RELOCATABLE-LINK: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading

// RUN: clang-offload-packager -o %t.out \
// RUN: --image=file=%t.elf.o,kind=hip,triple=amdgcn-amd-amdhsa,arch=gfx90a \
// RUN: --image=file=%t.elf.o,kind=hip,triple=amdgcn-amd-amdhsa,arch=gfx90a
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK-HIP

// RELOCATABLE-LINK-HIP: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa
// RELOCATABLE-LINK-HIP: clang-offload-bundler{{.*}} -type=o -bundle-align=4096 -targets=host-x86_64-unknown-linux,hipv4-amdgcn-amd-amdhsa--gfx90a -input=/dev/null -input={{.*}} -output={{.*}}
// RELOCATABLE-LINK-HIP: /usr/bin/ld.lld{{.*}}-r
// RELOCATABLE-LINK-HIP: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading

// RUN: clang-offload-packager -o %t.out \
// RUN: --image=file=%t.elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_89 \
// RUN: --image=file=%t.elf.o,kind=cuda,triple=nvptx64-nvidia-cuda,arch=sm_89
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld.lld -- -r %t.o \
// RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=RELOCATABLE-LINK-CUDA

// RELOCATABLE-LINK-CUDA: clang{{.*}} -o {{.*}}.img --target=nvptx64-nvidia-cuda
// RELOCATABLE-LINK-CUDA: fatbinary{{.*}} -64 --create {{.*}}.fatbin --image=profile=sm_89,file={{.*}}.img
// RELOCATABLE-LINK-CUDA: /usr/bin/ld.lld{{.*}}-r
// RELOCATABLE-LINK-CUDA: llvm-objcopy{{.*}}a.out --remove-section .llvm.offloading
54 changes: 6 additions & 48 deletions clang/test/Driver/wasm-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,131 +2,89 @@

// CHECK: "-fvisibility=hidden"

// RUN: %clang --target=wasm32-unknown-unknown -### %s 2>&1 | FileCheck %s -check-prefix=DEFAULT
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcpu=mvp 2>&1 | FileCheck %s -check-prefix=MVP
// RUN: %clang --target=wasm32-unknown-unknown -### %s 2>&1 | FileCheck %s -check-prefix=GENERIC
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcpu=generic 2>&1 | FileCheck %s -check-prefix=GENERIC
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mcpu=bleeding-edge 2>&1 | FileCheck %s -check-prefix=BLEEDING-EDGE

// MVP: "-target-cpu" "mvp"
// GENERIC: "-target-cpu" "generic"
// BLEEDING-EDGE: "-target-cpu" "bleeding-edge"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mbulk-memory 2>&1 | FileCheck %s -check-prefix=BULK-MEMORY
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-bulk-memory 2>&1 | FileCheck %s -check-prefix=NO-BULK-MEMORY

// BULK-MEMORY: "-target-feature" "+bulk-memory"
// NO-BULK-MEMORY: "-target-feature" "-bulk-memory"
// DEFAULT-NOT: "-target-feature" "-bulk-memory"
// MVP-NOT: "-target-feature" "+bulk-memory"
// BLEEDING-EDGE-NOT: "-target-feature" "-bulk-memory"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mmutable-globals 2>&1 | FileCheck %s -check-prefix=MUTABLE-GLOBALS
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-mutable-globals 2>&1 | FileCheck %s -check-prefix=NO-MUTABLE-GLOBALS

// MUTABLE-GLOBALS: "-target-feature" "+mutable-globals"
// NO-MUTABLE-GLOBALS: "-target-feature" "-mutable-globals"
// DEFAULT-NOT: "-target-feature" "-mutable-globals"
// MVP-NOT: "-target-feature" "+mutable-globals"
// BLEEDING-EDGE-NOT: "-target-feature" "-mutable-globals"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -msign-ext 2>&1 | FileCheck %s -check-prefix=SIGN-EXT
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-sign-ext 2>&1 | FileCheck %s -check-prefix=NO-SIGN-EXT

// SIGN-EXT: "-target-feature" "+sign-ext"
// NO-SIGN-EXT: "-target-feature" "-sign-ext"
// DEFAULT-NOT: "-target-feature" "-sign-ext"
// MVP-NOT: "-target-feature" "+sign-ext"
// BLEEDING-EDGE-NOT: "-target-feature" "-sign-ext"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mnontrapping-fptoint 2>&1 | FileCheck %s -check-prefix=NONTRAPPING-FPTOINT
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-nontrapping-fptoint 2>&1 | FileCheck %s -check-prefix=NO-NONTRAPPING-FPTOINT

// NONTRAPPING-FPTOINT: "-target-feature" "+nontrapping-fptoint"
// NO-NONTRAPPING-FPTOINT: "-target-feature" "-nontrapping-fptoint"
// DEFAULT-NOT: "-target-feature" "-nontrapping-fptoint"
// MVP-NOT: "-target-feature" "+nontrapping-fptoint"
// BLEEDING-EDGE-NOT: "-target-feature" "-nontrapping-fptoint"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mmultivalue 2>&1 | FileCheck %s -check-prefix=MULTIVALUE
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-multivalue 2>&1 | FileCheck %s -check-prefix=NO-MULTIVALUE

// MULTIVALUE: "-target-feature" "+multivalue"
// NO-MULTIVALUE: "-target-feature" "-multivalue"
// DEFAULT-NOT: "-target-feature" "-multivalue"
// MVP-NOT: "-target-feature" "+multivalue"
// GENERIC-NOT: "-target-feature" "+multivalue"
// BLEEDING-EDGE-NOT: "-target-feature" "-multivalue"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mmultimemory 2>&1 | FileCheck %s -check-prefix=MULTIMEMORY
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-multimemory 2>&1 | FileCheck %s -check-prefix=NO-MULTIMEMORY

// MULTIMEMORY: "-target-feature" "+multimemory"
// NO-MULTIMEMORY: "-target-feature" "-multimemory"
// DEFAULT-NOT: "-target-feature" "-multimemory"
// MVP-NOT: "-target-feature" "+multimemory"
// BLEEDING-EDGE-NOT: "-target-feature" "-multimemory"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -matomics 2>&1 | FileCheck %s -check-prefix=ATOMICS
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-atomics 2>&1 | FileCheck %s -check-prefix=NO-ATOMICS

// ATOMICS: "-target-feature" "+atomics"
// NO-ATOMICS: "-target-feature" "-atomics"
// DEFAULT-NOT: "-target-feature" "-atomics"
// MVP-NOT: "-target-feature" "+atomics"
// GENERIC-NOT: "-target-feature" "+atomics"
// BLEEDING-EDGE-NOT: "-target-feature" "-atomics"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mtail-call 2>&1 | FileCheck %s -check-prefix=TAIL-CALL
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-tail-call 2>&1 | FileCheck %s -check-prefix=NO-TAIL-CALL

// TAIL-CALL: "-target-feature" "+tail-call"
// NO-TAIL-CALL: "-target-feature" "-tail-call"
// DEFAULT-NOT: "-target-feature" "-tail-call"
// MVP-NOT: "-target-feature" "+tail-call"
// GENERIC-NOT: "-target-feature" "+tail-call"
// BLEEDING-EDGE-NOT: "-target-feature" "-tail-call"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mreference-types 2>&1 | FileCheck %s -check-prefix=REFERENCE-TYPES
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-reference-types 2>&1 | FileCheck %s -check-prefix=NO-REFERENCE-TYPES

// REFERENCE-TYPES: "-target-feature" "+reference-types"
// NO-REFERENCE-TYPES: "-target-feature" "-reference-types"
// DEFAULT-NOT: "-target-feature" "-reference-types"
// MVP-NOT: "-target-feature" "+reference-types"
// GENERIC-NOT: "-target-feature" "+reference-types"
// BLEEDING-EDGE-NOT: "-target-feature" "-reference-types"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -msimd128 2>&1 | FileCheck %s -check-prefix=SIMD128
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-simd128 2>&1 | FileCheck %s -check-prefix=NO-SIMD128

// SIMD128: "-target-feature" "+simd128"
// NO-SIMD128: "-target-feature" "-simd128"
// DEFAULT-NOT: "-target-feature" "-simd128"
// MVP-NOT: "-target-feature" "+simd128"
// GENERIC-NOT: "-target-feature" "+simd128"
// BLEEDING-EDGE-NOT: "-target-feature" "+simd128"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-simd 2>&1 | FileCheck %s -check-prefix=RELAXED-SIMD
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-simd 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-SIMD

// RELAXED-SIMD: "-target-feature" "+relaxed-simd"
// NO-RELAXED-SIMD: "-target-feature" "-relaxed-simd"
// DEFAULT-NOT: "-target-feature" "-relaxed-simd"
// MVP-NOT: "-target-feature" "+relaxed-simd"
// GENERIC-NOT: "-target-feature" "+relaxed-simd"
// BLEEDING-EDGE-NOT: "-target-feature" "+relaxed-simd"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mexception-handling 2>&1 | FileCheck %s -check-prefix=EXCEPTION-HANDLING
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-exception-handling 2>&1 | FileCheck %s -check-prefix=NO-EXCEPTION-HANDLING

// EXCEPTION-HANDLING: "-target-feature" "+exception-handling"
// NO-EXCEPTION-HANDLING: "-target-feature" "-exception-handling"
// DEFAULT-NOT: "-target-feature" "-exception-handling"
// MVP-NOT: "-target-feature" "+exception-handling"
// GENERIC-NOT: "-target-feature" "+exception-handling"
// BLEEDING-EDGE-NOT: "-target-feature" "+exception-handling"

// RUN: %clang --target=wasm32-unknown-unknown -### %s -mextended-const 2>&1 | FileCheck %s -check-prefix=EXTENDED-CONST
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-extended-const 2>&1 | FileCheck %s -check-prefix=NO-EXTENDED-CONST

// EXTENDED-CONST: "-target-feature" "+extended-const"
// NO-EXTENDED-CONST: "-target-feature" "-extended-const"
// DEFAULT-NOT: "-target-feature" "-extended-const"
// MVP-NOT: "-target-feature" "+extended-const"
// GENERIC-NOT: "-target-feature" "+extended-const"
// BLEEDING-EDGE-NOT: "-target-feature" "+extended-const"
29 changes: 29 additions & 0 deletions clang/test/Frontend/verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,32 @@ unexpected b; // expected-error@33 1-1 {{unknown type}}
#endif

#endif

#ifdef TEST10
// RUN: not %clang_cc1 -DTEST10 -verify=foo %s 2>&1 | FileCheck -check-prefix=CHECK10 %s

// CHECK10: error: no expected directives found: consider use of 'foo-no-diagnostics'
#endif

#ifdef TEST11
// RUN: not %clang_cc1 -DTEST11 -verify=foo %s 2>&1 | FileCheck -check-prefix=CHECK11 %s

// foo-no-diagnostics
// foo-note {{}}

// CHECK11: error: 'foo-error' diagnostics seen but not expected:
// CHECK11-NEXT: Line 201: expected directive cannot follow 'foo-no-diagnostics' directive
// CHECK11-NEXT: 1 error generated.
#endif

#ifdef TEST12
// RUN: not %clang_cc1 -DTEST12 -verify=foo %s 2>&1 | FileCheck -check-prefix=CHECK12 %s

#warning X
// foo-warning@-1 {{X}}
// foo-no-diagnostics

// CHECK12: error: 'foo-error' diagnostics seen but not expected:
// CHECK12-NEXT: Line 213: 'foo-no-diagnostics' directive cannot follow other expected directives
// CHECK12-NEXT: 1 error generated.
#endif
10 changes: 10 additions & 0 deletions clang/test/OpenMP/bug69085.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 -verify -O0 -fopenmp-simd %s

int k[-1]; // expected-error {{'k' declared as an array with a negative size}}

void foo() {
#pragma omp task depend(inout: k [:])
{
k[0] = 1;
}
}
20 changes: 20 additions & 0 deletions clang/test/Preprocessor/wasm-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,26 @@
// MVP-NOT:#define __wasm_multimemory__
// MVP-NOT:#define __wasm_relaxed_simd__

// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mcpu=generic \
// RUN: | FileCheck %s -check-prefix=GENERIC
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm64-unknown-unknown -mcpu=generic \
// RUN: | FileCheck %s -check-prefix=GENERIC
//
// GENERIC-DAG:#define __wasm_sign_ext__ 1{{$}}
// GENERIC-DAG:#define __wasm_mutable_globals__ 1{{$}}
// GENERIC-NOT:#define __wasm_nontrapping_fptoint__ 1{{$}}
// GENERIC-NOT:#define __wasm_bulk_memory__ 1{{$}}
// GENERIC-NOT:#define __wasm_simd128__ 1{{$}}
// GENERIC-NOT:#define __wasm_atomics__ 1{{$}}
// GENERIC-NOT:#define __wasm_tail_call__ 1{{$}}
// GENERIC-NOT:#define __wasm_multimemory__ 1{{$}}
// GENERIC-NOT:#define __wasm_exception_handling__ 1{{$}}
// GENERIC-NOT:#define __wasm_multivalue__ 1{{$}}
// GENERIC-NOT:#define __wasm_reference_types__ 1{{$}}
// GENERIC-NOT:#define __wasm_extended_const__ 1{{$}}

// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mcpu=bleeding-edge \
// RUN: | FileCheck %s -check-prefix=BLEEDING-EDGE
Expand Down
1 change: 1 addition & 0 deletions clang/test/SemaCXX/cxx1z-copy-omission.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1z -verify -Wno-unused %s
// RUN: %clang_cc1 -std=c++1z -verify -Wno-unused %s -fexperimental-new-constant-interpreter

struct Noncopyable {
Noncopyable();
Expand Down
3 changes: 2 additions & 1 deletion clang/test/SemaCXX/cxx20-using-enum.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s -fexperimental-new-constant-interpreter

// p1099 'using enum ELABORATED-ENUM-SPECIFIER ;'

Expand Down
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/cxx2b-deducing-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,3 +636,13 @@ struct D {
}
};
}

namespace GH80971 {
struct S {
auto f(this auto self...) { }
};

int bug() {
S{}.f(0);
}
}
7 changes: 7 additions & 0 deletions clang/test/SemaCXX/warn-unsafe-buffer-usage-debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,10 @@ void test_struct_claim_use() {
x[6] = 8; // expected-warning{{unsafe buffer access}}
x++; // expected-warning{{unsafe pointer arithmetic}}
}

void use(int*);
void array2d(int idx) {
int buffer[10][5]; // expected-warning{{'buffer' is an unsafe buffer that does not perform bounds checks}}
use(buffer[idx]); // expected-note{{used in buffer access here}} \
// debug-note{{safe buffers debug: failed to produce fixit for 'buffer' : has an unclaimed use}}
}
77 changes: 70 additions & 7 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,70 @@ Expected<std::string> findProgram(StringRef Name, ArrayRef<StringRef> Paths) {
return *Path;
}

/// Returns the hashed value for a constant string.
std::string getHash(StringRef Str) {
llvm::MD5 Hasher;
llvm::MD5::MD5Result Hash;
Hasher.update(Str);
Hasher.final(Hash);
return llvm::utohexstr(Hash.low(), /*LowerCase=*/true);
}

/// Renames offloading entry sections in a relocatable link so they do not
/// conflict with a later link job.
Error relocateOffloadSection(const ArgList &Args, StringRef Output) {
llvm::Triple Triple(
Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
if (Triple.isOSWindows())
return createStringError(
inconvertibleErrorCode(),
"Relocatable linking is not supported on COFF targets");

Expected<std::string> ObjcopyPath =
findProgram("llvm-objcopy", {getMainExecutable("llvm-objcopy")});
if (!ObjcopyPath)
return ObjcopyPath.takeError();

// Use the linker output file to get a unique hash. This creates a unique
// identifier to rename the sections to that is deterministic to the contents.
auto BufferOrErr = DryRun ? MemoryBuffer::getMemBuffer("")
: MemoryBuffer::getFileOrSTDIN(Output);
if (!BufferOrErr)
return createStringError(inconvertibleErrorCode(), "Failed to open %s",
Output.str().c_str());
std::string Suffix = "_" + getHash((*BufferOrErr)->getBuffer());

SmallVector<StringRef> ObjcopyArgs = {
*ObjcopyPath,
Output,
};

// Remove the old .llvm.offloading section to prevent further linking.
ObjcopyArgs.emplace_back("--remove-section");
ObjcopyArgs.emplace_back(".llvm.offloading");
for (StringRef Prefix : {"omp", "cuda", "hip"}) {
auto Section = (Prefix + "_offloading_entries").str();
// Rename the offloading entires to make them private to this link unit.
ObjcopyArgs.emplace_back("--rename-section");
ObjcopyArgs.emplace_back(
Args.MakeArgString(Section + "=" + Section + Suffix));

// Rename the __start_ / __stop_ symbols appropriately to iterate over the
// newly renamed section containing the offloading entries.
ObjcopyArgs.emplace_back("--redefine-sym");
ObjcopyArgs.emplace_back(Args.MakeArgString("__start_" + Section + "=" +
"__start_" + Section + Suffix));
ObjcopyArgs.emplace_back("--redefine-sym");
ObjcopyArgs.emplace_back(Args.MakeArgString("__stop_" + Section + "=" +
"__stop_" + Section + Suffix));
}

if (Error Err = executeCommands(*ObjcopyPath, ObjcopyArgs))
return Err;

return Error::success();
}

/// Runs the wrapped linker job with the newly created input.
Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
llvm::TimeTraceScope TimeScope("Execute host linker");
Expand All @@ -265,6 +329,10 @@ Error runLinker(ArrayRef<StringRef> Files, const ArgList &Args) {
LinkerArgs.push_back(Arg);
if (Error Err = executeCommands(LinkerPath, LinkerArgs))
return Err;

if (Args.hasArg(OPT_relocatable))
return relocateOffloadSection(Args, ExecutableName);

return Error::success();
}

Expand Down Expand Up @@ -910,7 +978,8 @@ wrapDeviceImages(ArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
case OFK_OpenMP:
if (Error Err = offloading::wrapOpenMPBinaries(
M, BuffersToWrap,
offloading::getOffloadEntryArray(M, "omp_offloading_entries")))
offloading::getOffloadEntryArray(M, "omp_offloading_entries"),
/*Suffix=*/"", /*Relocatable=*/Args.hasArg(OPT_relocatable)))
return std::move(Err);
break;
case OFK_Cuda:
Expand Down Expand Up @@ -1356,12 +1425,6 @@ Expected<SmallVector<SmallVector<OffloadFile>>>
getDeviceInput(const ArgList &Args) {
llvm::TimeTraceScope TimeScope("ExtractDeviceCode");

// If the user is requesting a reloctable link we ignore the device code. The
// actual linker will merge the embedded device code sections so they can be
// linked when the executable is finally created.
if (Args.hasArg(OPT_relocatable))
return SmallVector<SmallVector<OffloadFile>>{};

StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
SmallVector<StringRef> LibraryPaths;
for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath))
Expand Down
5 changes: 3 additions & 2 deletions clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ def version : Flag<["--", "-"], "version">, Flags<[HelpHidden]>, Alias<v>;
def whole_archive : Flag<["--", "-"], "whole-archive">, Flags<[HelpHidden]>;
def no_whole_archive : Flag<["--", "-"], "no-whole-archive">, Flags<[HelpHidden]>;

def relocatable : Flag<["--", "-"], "relocatable">, Flags<[HelpHidden]>;
def r : Flag<["-"], "r">, Alias<relocatable>, Flags<[HelpHidden]>;
def relocatable : Flag<["--", "-"], "relocatable">,
HelpText<"Link device code to create a relocatable offloading application">;
def r : Flag<["-"], "r">, Alias<relocatable>;

// link.exe-style linker options.
def out : Joined<["/", "-", "/?", "-?"], "out:">, Flags<[HelpHidden]>;
Expand Down
8 changes: 8 additions & 0 deletions clang/unittests/Format/FormatTestComments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,14 @@ TEST_F(FormatTestComments, ReflowsComments) {
"// @param arg",
getLLVMStyleWithColumns(20)));

// Don't reflow lines starting with '\'.
verifyFormat("// long long long\n"
"// long\n"
"// \\param arg",
"// long long long long\n"
"// \\param arg",
getLLVMStyleWithColumns(20));

// Don't reflow lines starting with 'TODO'.
EXPECT_EQ("// long long long\n"
"// long\n"
Expand Down
1 change: 0 additions & 1 deletion compiler-rt/lib/asan/asan_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@

# if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
# include <ucontext.h>
extern "C" void *_DYNAMIC;
# elif SANITIZER_NETBSD
# include <link_elf.h>
# include <ucontext.h>
Expand Down
16 changes: 8 additions & 8 deletions compiler-rt/lib/memprof/memprof_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,7 @@ struct Allocator {
return ptr;
}

void CommitBack(MemprofThreadLocalMallocStorage *ms,
BufferedStackTrace *stack) {
void CommitBack(MemprofThreadLocalMallocStorage *ms) {
AllocatorCache *ac = GetAllocatorCache(ms);
allocator.SwallowCache(ac);
}
Expand Down Expand Up @@ -561,7 +560,7 @@ struct Allocator {
return reinterpret_cast<MemprofChunk *>(p - kChunkHeaderSize)->UsedSize();
}

void Purge(BufferedStackTrace *stack) { allocator.ForceReleaseToOS(); }
void Purge() { allocator.ForceReleaseToOS(); }

void PrintStats() { allocator.PrintStats(); }

Expand All @@ -583,8 +582,7 @@ static MemprofAllocator &get_allocator() { return instance.allocator; }
void InitializeAllocator() { instance.InitLinkerInitialized(); }

void MemprofThreadLocalMallocStorage::CommitBack() {
GET_STACK_TRACE_MALLOC;
instance.CommitBack(this, &stack);
instance.CommitBack(this);
}

void PrintInternalAllocatorStats() { instance.PrintStats(); }
Expand Down Expand Up @@ -699,7 +697,7 @@ static const void *memprof_malloc_begin(const void *p) {
return (const void *)m->Beg();
}

uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp) {
uptr memprof_malloc_usable_size(const void *ptr) {
if (!ptr)
return 0;
uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr));
Expand All @@ -714,15 +712,15 @@ using namespace __memprof;
uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }

int __sanitizer_get_ownership(const void *p) {
return memprof_malloc_usable_size(p, 0, 0) != 0;
return memprof_malloc_usable_size(p) != 0;
}

const void *__sanitizer_get_allocated_begin(const void *p) {
return memprof_malloc_begin(p);
}

uptr __sanitizer_get_allocated_size(const void *p) {
return memprof_malloc_usable_size(p, 0, 0);
return memprof_malloc_usable_size(p);
}

uptr __sanitizer_get_allocated_size_fast(const void *p) {
Expand All @@ -732,6 +730,8 @@ uptr __sanitizer_get_allocated_size_fast(const void *p) {
return ret;
}

void __sanitizer_purge_allocator() { instance.Purge(); }

int __memprof_profile_dump() {
instance.FinishAndWrite();
// In the future we may want to return non-zero if there are any errors
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/memprof/memprof_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void *memprof_aligned_alloc(uptr alignment, uptr size,
BufferedStackTrace *stack);
int memprof_posix_memalign(void **memptr, uptr alignment, uptr size,
BufferedStackTrace *stack);
uptr memprof_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
uptr memprof_malloc_usable_size(const void *ptr);

void PrintInternalAllocatorStats();

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/memprof/memprof_interceptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ INTERCEPTOR(int, pthread_create, void *thread, void *attr,
}

INTERCEPTOR(int, pthread_join, void *t, void **arg) {
return real_pthread_join(t, arg);
return REAL(pthread_join)(t, arg);
}

DEFINE_REAL_PTHREAD_FUNCTIONS
Expand Down
4 changes: 0 additions & 4 deletions compiler-rt/lib/memprof/memprof_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_stacktrace.h"

#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
#error "The MemProfiler run-time should not be instrumented by MemProfiler"
#endif

// Build-time configuration options.

// If set, memprof will intercept C++ exception api call(s).
Expand Down
4 changes: 1 addition & 3 deletions compiler-rt/lib/memprof/memprof_malloc_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ INTERCEPTOR(void *, aligned_alloc, uptr boundary, uptr size) {
#endif // SANITIZER_INTERCEPT_ALIGNED_ALLOC

INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
GET_CURRENT_PC_BP_SP;
(void)sp;
return memprof_malloc_usable_size(ptr, pc, bp);
return memprof_malloc_usable_size(ptr);
}

#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,8 @@ void ReExec();
#if defined(__ELF__) && !SANITIZER_FUCHSIA
extern uptr kDynamic[] asm("_DYNAMIC");
inline void DoesNotSupportStaticLinking() {
// This will fail to link with -static. However, -static-pie is not detected.
// This will fail to link with -static. However, -static-pie cannot be
// detected at link time.
[[maybe_unused]] volatile auto x = &kDynamic;
}
#else
Expand Down
4 changes: 3 additions & 1 deletion flang/include/flang/Lower/ConvertCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ namespace Fortran::lower {
/// link to internal procedures.
/// \p isElemental must be set to true if elemental call is being produced.
/// It is only used for HLFIR.
fir::ExtendedValue genCallOpAndResult(
/// The returned boolean indicates if finalization has been emitted in
/// \p stmtCtx for the result.
std::pair<fir::ExtendedValue, bool> genCallOpAndResult(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType,
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Optimizer/Builder/MutableBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::MutableBoxValue &box,
bool mayBePolymorphic = true);
bool mayBePolymorphic = true,
bool preserveLowerBounds = true);

/// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current
/// association / allocation properties. If the fir.ref<fir.box> already exists
Expand Down
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/Dialect/FIRDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ bool canLegallyInline(mlir::Operation *op, mlir::Region *reg, bool,
mlir::IRMapping &map);
bool canLegallyInline(mlir::Operation *, mlir::Operation *, bool);

// Register the FIRInlinerInterface to FIROpsDialect
void addFIRInlinerExtension(mlir::DialectRegistry &registry);

} // namespace fir

#endif // FORTRAN_OPTIMIZER_DIALECT_FIRDIALECT_H
7 changes: 7 additions & 0 deletions flang/include/flang/Optimizer/Support/InitFIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ inline void registerDialects(mlir::DialectRegistry &registry) {
registry.insert<FLANG_CODEGEN_DIALECT_LIST>();
}

// Register FIR Extensions
inline void addFIRExtensions(mlir::DialectRegistry &registry,
bool addFIRInlinerInterface = true) {
if (addFIRInlinerInterface)
addFIRInlinerExtension(registry);
}

inline void loadNonCodegenDialects(mlir::MLIRContext &context) {
mlir::DialectRegistry registry;
registerNonCodegenDialects(registry);
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ void CodeGenAction::generateLLVMIR() {
llvm::OptimizationLevel level = mapToLevel(opts);

fir::support::loadDialects(*mlirCtx);
mlir::DialectRegistry registry;
fir::support::registerNonCodegenDialects(registry);
fir::support::addFIRExtensions(registry);
mlirCtx->appendDialectRegistry(registry);
fir::support::registerLLVMTranslation(*mlirCtx);

// Set-up the MLIR pass manager
Expand Down
60 changes: 43 additions & 17 deletions flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static llvm::cl::opt<bool> useHlfirIntrinsicOps(
llvm::cl::desc("Lower via HLFIR transformational intrinsic operations such "
"as hlfir.sum"));

static constexpr char tempResultName[] = ".tmp.func_result";

/// Helper to package a Value and its properties into an ExtendedValue.
static fir::ExtendedValue toExtendedValue(mlir::Location loc, mlir::Value base,
llvm::ArrayRef<mlir::Value> extents,
Expand Down Expand Up @@ -147,7 +149,7 @@ static bool mustCastFuncOpToCopeWithImplicitInterfaceMismatch(
return false;
}

fir::ExtendedValue Fortran::lower::genCallOpAndResult(
std::pair<fir::ExtendedValue, bool> Fortran::lower::genCallOpAndResult(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType,
Expand Down Expand Up @@ -478,6 +480,7 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
[](const auto &) {});

// 7.5.6.3 point 5. Derived-type finalization for nonpointer function.
bool resultIsFinalized = false;
// Check if the derived-type is finalizable if it is a monomorphic
// derived-type.
// For polymorphic and unlimited polymorphic enities call the runtime
Expand All @@ -499,6 +502,7 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
fir::runtime::genDerivedTypeDestroy(*bldr, loc,
fir::getBase(*allocatedResult));
});
resultIsFinalized = true;
} else {
const Fortran::semantics::DerivedTypeSpec &typeSpec =
retTy->GetDerivedTypeSpec();
Expand All @@ -513,14 +517,17 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
mlir::Value box = bldr->createBox(loc, *allocatedResult);
fir::runtime::genDerivedTypeDestroy(*bldr, loc, box);
});
resultIsFinalized = true;
}
}
}
return *allocatedResult;
return {*allocatedResult, resultIsFinalized};
}

// subroutine call
if (!resultType)
return mlir::Value{}; // subroutine call
return {fir::ExtendedValue{mlir::Value{}}, /*resultIsFinalized=*/false};

// For now, Fortran return values are implemented with a single MLIR
// function return value.
assert(callNumResults == 1 && "Expected exactly one result in FUNCTION call");
Expand All @@ -533,10 +540,10 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
funcType.getResults()[0].dyn_cast<fir::CharacterType>();
mlir::Value len = builder.createIntegerConstant(
loc, builder.getCharacterLengthType(), charTy.getLen());
return fir::CharBoxValue{callResult, len};
return {fir::CharBoxValue{callResult, len}, /*resultIsFinalized=*/false};
}

return callResult;
return {callResult, /*resultIsFinalized=*/false};
}

static hlfir::EntityWithAttributes genStmtFunctionRef(
Expand Down Expand Up @@ -1389,7 +1396,7 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
// Prepare lowered arguments according to the interface
// and map the lowered values to the dummy
// arguments.
fir::ExtendedValue result = Fortran::lower::genCallOpAndResult(
auto [result, resultIsFinalized] = Fortran::lower::genCallOpAndResult(
loc, callContext.converter, callContext.symMap, callContext.stmtCtx,
caller, callSiteType, callContext.resultType,
callContext.isElementalProcWithArrayArgs());
Expand All @@ -1404,24 +1411,43 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
if (!fir::getBase(result))
return std::nullopt; // subroutine call.

hlfir::Entity resultEntity =
extendedValueToHlfirEntity(loc, builder, result, ".tmp.func_result");
if (fir::isPointerType(fir::getBase(result).getType()))
return extendedValueToHlfirEntity(loc, builder, result, tempResultName);

if (!fir::isPointerType(fir::getBase(result).getType())) {
if (!resultIsFinalized) {
hlfir::Entity resultEntity =
extendedValueToHlfirEntity(loc, builder, result, tempResultName);
resultEntity = loadTrivialScalar(loc, builder, resultEntity);

if (resultEntity.isVariable()) {
// Function result must not be freed, since it is allocated on the stack.
// Note that in non-elemental case, genCallOpAndResult()
// is responsible for establishing the clean-up that destroys
// the derived type result or deallocates its components
// without finalization.
// If the result has no finalization, it can be moved into an expression.
// In such case, the expression should not be freed after its use since
// the result is stack allocated or deallocation (for allocatable results)
// was already inserted in genCallOpAndResult.
auto asExpr = builder.create<hlfir::AsExprOp>(
loc, resultEntity, /*mustFree=*/builder.createBool(loc, false));
resultEntity = hlfir::EntityWithAttributes{asExpr.getResult()};
return hlfir::EntityWithAttributes{asExpr.getResult()};
}
return hlfir::EntityWithAttributes{resultEntity};
}
return hlfir::EntityWithAttributes{resultEntity};
// If the result has finalization, it cannot be moved because use of its
// value have been created in the statement context and may be emitted
// after the hlfir.expr destroy, so the result is kept as a variable in
// HLFIR. This may lead to copies when passing the result to an argument
// with VALUE, and this do not convey the fact that the result will not
// change, but is correct, and using hlfir.expr without the move would
// trigger a copy that may be avoided.

// Load allocatable results before emitting the hlfir.declare and drop its
// lower bounds: this is not a variable From the Fortran point of view, so
// the lower bounds are ones when inquired on the caller side.
const auto *allocatable = result.getBoxOf<fir::MutableBoxValue>();
fir::ExtendedValue loadedResult =
allocatable
? fir::factory::genMutableBoxRead(builder, loc, *allocatable,
/*mayBePolymorphic=*/true,
/*preserveLowerBounds=*/false)
: result;
return extendedValueToHlfirEntity(loc, builder, loadedResult, tempResultName);
}

/// Create an optional dummy argument value from an entity that may be
Expand Down
12 changes: 8 additions & 4 deletions flang/lib/Lower/ConvertExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2846,8 +2846,10 @@ class ScalarExprLowering {
}
}

ExtValue result = Fortran::lower::genCallOpAndResult(
loc, converter, symMap, stmtCtx, caller, callSiteType, resultType);
ExtValue result =
Fortran::lower::genCallOpAndResult(loc, converter, symMap, stmtCtx,
caller, callSiteType, resultType)
.first;

// Sync pointers and allocatables that may have been modified during the
// call.
Expand Down Expand Up @@ -4866,8 +4868,10 @@ class ArrayExprLowering {
[&](const auto &) { return fir::getBase(exv); });
caller.placeInput(argIface, arg);
}
return Fortran::lower::genCallOpAndResult(
loc, converter, symMap, getElementCtx(), caller, callSiteType, retTy);
return Fortran::lower::genCallOpAndResult(loc, converter, symMap,
getElementCtx(), caller,
callSiteType, retTy)
.first;
};
}

Expand Down
220 changes: 141 additions & 79 deletions flang/lib/Lower/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2266,31 +2266,68 @@ createAndSetPrivatizedLoopVar(Fortran::lower::AbstractConverter &converter,
return storeOp;
}

struct CreateBodyOfOpInfo {
struct OpWithBodyGenInfo {
/// A type for a code-gen callback function. This takes as argument the op for
/// which the code is being generated and returns the arguments of the op's
/// region.
using GenOMPRegionEntryCBFn =
std::function<llvm::SmallVector<const Fortran::semantics::Symbol *>(
mlir::Operation *)>;

OpWithBodyGenInfo(Fortran::lower::AbstractConverter &converter,
mlir::Location loc, Fortran::lower::pft::Evaluation &eval)
: converter(converter), loc(loc), eval(eval) {}

OpWithBodyGenInfo &setGenNested(bool value) {
genNested = value;
return *this;
}

OpWithBodyGenInfo &setOuterCombined(bool value) {
outerCombined = value;
return *this;
}

OpWithBodyGenInfo &setClauses(const Fortran::parser::OmpClauseList *value) {
clauses = value;
return *this;
}

OpWithBodyGenInfo &setDataSharingProcessor(DataSharingProcessor *value) {
dsp = value;
return *this;
}

OpWithBodyGenInfo &setGenRegionEntryCb(GenOMPRegionEntryCBFn value) {
genRegionEntryCB = value;
return *this;
}

/// [inout] converter to use for the clauses.
Fortran::lower::AbstractConverter &converter;
mlir::Location &loc;
/// [in] location in source code.
mlir::Location loc;
/// [in] current PFT node/evaluation.
Fortran::lower::pft::Evaluation &eval;
/// [in] whether to generate FIR for nested evaluations
bool genNested = true;
const Fortran::parser::OmpClauseList *clauses = nullptr;
const llvm::SmallVector<const Fortran::semantics::Symbol *> &args = {};
/// [in] is this an outer operation - prevents privatization.
bool outerCombined = false;
/// [in] list of clauses to process.
const Fortran::parser::OmpClauseList *clauses = nullptr;
/// [in] if provided, processes the construct's data-sharing attributes.
DataSharingProcessor *dsp = nullptr;
/// [in] if provided, emits the op's region entry. Otherwise, an emtpy block
/// is created in the region.
GenOMPRegionEntryCBFn genRegionEntryCB = nullptr;
};

/// Create the body (block) for an OpenMP Operation.
///
/// \param [in] op - the operation the body belongs to.
/// \param [inout] converter - converter to use for the clauses.
/// \param [in] loc - location in source code.
/// \param [in] eval - current PFT node/evaluation.
/// \param [in] genNested - whether to generate FIR for nested evaluations
/// \oaran [in] clauses - list of clauses to process.
/// \param [in] args - block arguments (induction variable[s]) for the
//// region.
/// \param [in] outerCombined - is this an outer operation - prevents
/// privatization.
/// \param [in] op - the operation the body belongs to.
/// \param [in] info - options controlling code-gen for the construction.
template <typename Op>
static void createBodyOfOp(Op &op, CreateBodyOfOpInfo info) {
static void createBodyOfOp(Op &op, OpWithBodyGenInfo &info) {
fir::FirOpBuilder &firOpBuilder = info.converter.getFirOpBuilder();

auto insertMarker = [](fir::FirOpBuilder &builder) {
Expand All @@ -2303,28 +2340,15 @@ static void createBodyOfOp(Op &op, CreateBodyOfOpInfo info) {
// argument. Also update the symbol's address with the mlir argument value.
// e.g. For loops the argument is the induction variable. And all further
// uses of the induction variable should use this mlir value.
if (info.args.size()) {
std::size_t loopVarTypeSize = 0;
for (const Fortran::semantics::Symbol *arg : info.args)
loopVarTypeSize = std::max(loopVarTypeSize, arg->GetUltimate().size());
mlir::Type loopVarType = getLoopVarType(info.converter, loopVarTypeSize);
llvm::SmallVector<mlir::Type> tiv(info.args.size(), loopVarType);
llvm::SmallVector<mlir::Location> locs(info.args.size(), info.loc);
firOpBuilder.createBlock(&op.getRegion(), {}, tiv, locs);
// The argument is not currently in memory, so make a temporary for the
// argument, and store it there, then bind that location to the argument.
mlir::Operation *storeOp = nullptr;
for (auto [argIndex, argSymbol] : llvm::enumerate(info.args)) {
mlir::Value indexVal =
fir::getBase(op.getRegion().front().getArgument(argIndex));
storeOp = createAndSetPrivatizedLoopVar(info.converter, info.loc,
indexVal, argSymbol);
auto regionArgs =
[&]() -> llvm::SmallVector<const Fortran::semantics::Symbol *> {
if (info.genRegionEntryCB != nullptr) {
return info.genRegionEntryCB(op);
}
firOpBuilder.setInsertionPointAfter(storeOp);
} else {
firOpBuilder.createBlock(&op.getRegion());
}

firOpBuilder.createBlock(&op.getRegion());
return {};
}();
// Mark the earliest insertion point.
mlir::Operation *marker = insertMarker(firOpBuilder);

Expand Down Expand Up @@ -2421,8 +2445,8 @@ static void createBodyOfOp(Op &op, CreateBodyOfOpInfo info) {
assert(tempDsp.has_value());
tempDsp->processStep2(op, isLoop);
} else {
if (isLoop && info.args.size() > 0)
info.dsp->setLoopIV(info.converter.getSymbolAddress(*info.args[0]));
if (isLoop && regionArgs.size() > 0)
info.dsp->setLoopIV(info.converter.getSymbolAddress(*regionArgs[0]));
info.dsp->processStep2(op, isLoop);
}
}
Expand Down Expand Up @@ -2497,24 +2521,11 @@ static void genBodyOfTargetDataOp(
genNestedEvaluations(converter, eval);
}

struct GenOpWithBodyInfo {
Fortran::lower::AbstractConverter &converter;
Fortran::lower::pft::Evaluation &eval;
bool genNested = false;
mlir::Location currentLocation;
bool outerCombined = false;
const Fortran::parser::OmpClauseList *clauseList = nullptr;
};

template <typename OpTy, typename... Args>
static OpTy genOpWithBody(GenOpWithBodyInfo info, Args &&...args) {
static OpTy genOpWithBody(OpWithBodyGenInfo &info, Args &&...args) {
auto op = info.converter.getFirOpBuilder().create<OpTy>(
info.currentLocation, std::forward<Args>(args)...);
createBodyOfOp<OpTy>(
op, {info.converter, info.currentLocation, info.eval, info.genNested,
info.clauseList,
/*args*/ llvm::SmallVector<const Fortran::semantics::Symbol *>{},
info.outerCombined});
info.loc, std::forward<Args>(args)...);
createBodyOfOp<OpTy>(op, info);
return op;
}

Expand All @@ -2523,7 +2534,8 @@ genMasterOp(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval, bool genNested,
mlir::Location currentLocation) {
return genOpWithBody<mlir::omp::MasterOp>(
{converter, eval, genNested, currentLocation},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested),
/*resultTypes=*/mlir::TypeRange());
}

Expand All @@ -2532,7 +2544,8 @@ genOrderedRegionOp(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval, bool genNested,
mlir::Location currentLocation) {
return genOpWithBody<mlir::omp::OrderedRegionOp>(
{converter, eval, genNested, currentLocation},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested),
/*simd=*/false);
}

Expand Down Expand Up @@ -2560,7 +2573,10 @@ genParallelOp(Fortran::lower::AbstractConverter &converter,
cp.processReduction(currentLocation, reductionVars, reductionDeclSymbols);

return genOpWithBody<mlir::omp::ParallelOp>(
{converter, eval, genNested, currentLocation, outerCombined, &clauseList},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setOuterCombined(outerCombined)
.setClauses(&clauseList),
/*resultTypes=*/mlir::TypeRange(), ifClauseOperand,
numThreadsClauseOperand, allocateOperands, allocatorOperands,
reductionVars,
Expand All @@ -2579,8 +2595,9 @@ genSectionOp(Fortran::lower::AbstractConverter &converter,
// Currently only private/firstprivate clause is handled, and
// all privatization is done within `omp.section` operations.
return genOpWithBody<mlir::omp::SectionOp>(
{converter, eval, genNested, currentLocation,
/*outerCombined=*/false, &sectionsClauseList});
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setClauses(&sectionsClauseList));
}

static mlir::omp::SingleOp
Expand All @@ -2600,8 +2617,9 @@ genSingleOp(Fortran::lower::AbstractConverter &converter,
ClauseProcessor(converter, endClauseList).processNowait(nowaitAttr);

return genOpWithBody<mlir::omp::SingleOp>(
{converter, eval, genNested, currentLocation,
/*outerCombined=*/false, &beginClauseList},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setClauses(&beginClauseList),
allocateOperands, allocatorOperands, nowaitAttr);
}

Expand Down Expand Up @@ -2633,8 +2651,9 @@ genTaskOp(Fortran::lower::AbstractConverter &converter,
currentLocation, llvm::omp::Directive::OMPD_task);

return genOpWithBody<mlir::omp::TaskOp>(
{converter, eval, genNested, currentLocation,
/*outerCombined=*/false, &clauseList},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setClauses(&clauseList),
ifClauseOperand, finalClauseOperand, untiedAttr, mergeableAttr,
/*in_reduction_vars=*/mlir::ValueRange(),
/*in_reductions=*/nullptr, priorityClauseOperand,
Expand All @@ -2656,8 +2675,9 @@ genTaskGroupOp(Fortran::lower::AbstractConverter &converter,
cp.processTODO<Fortran::parser::OmpClause::TaskReduction>(
currentLocation, llvm::omp::Directive::OMPD_taskgroup);
return genOpWithBody<mlir::omp::TaskGroupOp>(
{converter, eval, genNested, currentLocation,
/*outerCombined=*/false, &clauseList},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setClauses(&clauseList),
/*task_reduction_vars=*/mlir::ValueRange(),
/*task_reductions=*/nullptr, allocateOperands, allocatorOperands);
}
Expand Down Expand Up @@ -3040,7 +3060,10 @@ genTeamsOp(Fortran::lower::AbstractConverter &converter,
currentLocation, llvm::omp::Directive::OMPD_teams);

return genOpWithBody<mlir::omp::TeamsOp>(
{converter, eval, genNested, currentLocation, outerCombined, &clauseList},
OpWithBodyGenInfo(converter, currentLocation, eval)
.setGenNested(genNested)
.setOuterCombined(outerCombined)
.setClauses(&clauseList),
/*num_teams_lower=*/nullptr, numTeamsClauseOperand, ifClauseOperand,
threadLimitClauseOperand, allocateOperands, allocatorOperands,
reductionVars,
Expand Down Expand Up @@ -3237,6 +3260,33 @@ static void convertLoopBounds(Fortran::lower::AbstractConverter &converter,
}
}

static llvm::SmallVector<const Fortran::semantics::Symbol *>
genLoopVars(mlir::Operation *op, Fortran::lower::AbstractConverter &converter,
mlir::Location &loc,
const llvm::SmallVector<const Fortran::semantics::Symbol *> &args) {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
auto &region = op->getRegion(0);

std::size_t loopVarTypeSize = 0;
for (const Fortran::semantics::Symbol *arg : args)
loopVarTypeSize = std::max(loopVarTypeSize, arg->GetUltimate().size());
mlir::Type loopVarType = getLoopVarType(converter, loopVarTypeSize);
llvm::SmallVector<mlir::Type> tiv(args.size(), loopVarType);
llvm::SmallVector<mlir::Location> locs(args.size(), loc);
firOpBuilder.createBlock(&region, {}, tiv, locs);
// The argument is not currently in memory, so make a temporary for the
// argument, and store it there, then bind that location to the argument.
mlir::Operation *storeOp = nullptr;
for (auto [argIndex, argSymbol] : llvm::enumerate(args)) {
mlir::Value indexVal = fir::getBase(region.front().getArgument(argIndex));
storeOp =
createAndSetPrivatizedLoopVar(converter, loc, indexVal, argSymbol);
}
firOpBuilder.setInsertionPointAfter(storeOp);

return args;
}

static void
createSimdLoop(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval,
Expand Down Expand Up @@ -3284,10 +3334,16 @@ createSimdLoop(Fortran::lower::AbstractConverter &converter,

auto *nestedEval = getCollapsedLoopEval(
eval, Fortran::lower::getCollapseValue(loopOpClauseList));

auto ivCallback = [&](mlir::Operation *op) {
return genLoopVars(op, converter, loc, iv);
};

createBodyOfOp<mlir::omp::SimdLoopOp>(
simdLoopOp, {converter, loc, *nestedEval,
/*genNested=*/true, &loopOpClauseList, iv,
/*outerCombined=*/false, &dsp});
simdLoopOp, OpWithBodyGenInfo(converter, loc, *nestedEval)
.setClauses(&loopOpClauseList)
.setDataSharingProcessor(&dsp)
.setGenRegionEntryCb(ivCallback));
}

static void createWsLoop(Fortran::lower::AbstractConverter &converter,
Expand Down Expand Up @@ -3360,10 +3416,16 @@ static void createWsLoop(Fortran::lower::AbstractConverter &converter,

auto *nestedEval = getCollapsedLoopEval(
eval, Fortran::lower::getCollapseValue(beginClauseList));
createBodyOfOp<mlir::omp::WsLoopOp>(wsLoopOp,
{converter, loc, *nestedEval,
/*genNested=*/true, &beginClauseList, iv,
/*outerCombined=*/false, &dsp});

auto ivCallback = [&](mlir::Operation *op) {
return genLoopVars(op, converter, loc, iv);
};

createBodyOfOp<mlir::omp::WsLoopOp>(
wsLoopOp, OpWithBodyGenInfo(converter, loc, *nestedEval)
.setClauses(&beginClauseList)
.setDataSharingProcessor(&dsp)
.setGenRegionEntryCb(ivCallback));
}

static void createSimdWsLoop(
Expand Down Expand Up @@ -3644,8 +3706,8 @@ genOMP(Fortran::lower::AbstractConverter &converter,
currentLocation, mlir::FlatSymbolRefAttr::get(firOpBuilder.getContext(),
global.getSymName()));
}();
createBodyOfOp<mlir::omp::CriticalOp>(criticalOp,
{converter, currentLocation, eval});
auto genInfo = OpWithBodyGenInfo(converter, currentLocation, eval);
createBodyOfOp<mlir::omp::CriticalOp>(criticalOp, genInfo);
}

static void
Expand Down Expand Up @@ -3687,11 +3749,11 @@ genOMP(Fortran::lower::AbstractConverter &converter,
}

// SECTIONS construct
genOpWithBody<mlir::omp::SectionsOp>({converter, eval,
/*genNested=*/false, currentLocation},
/*reduction_vars=*/mlir::ValueRange(),
/*reductions=*/nullptr, allocateOperands,
allocatorOperands, nowaitClauseOperand);
genOpWithBody<mlir::omp::SectionsOp>(
OpWithBodyGenInfo(converter, currentLocation, eval).setGenNested(false),
/*reduction_vars=*/mlir::ValueRange(),
/*reductions=*/nullptr, allocateOperands, allocatorOperands,
nowaitClauseOperand);

const auto &sectionBlocks =
std::get<Fortran::parser::OmpSectionBlocks>(sectionsConstruct.t);
Expand Down
8 changes: 6 additions & 2 deletions flang/lib/Optimizer/Builder/MutableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,22 +406,26 @@ static bool readToBoxValue(const fir::MutableBoxValue &box,
fir::ExtendedValue
fir::factory::genMutableBoxRead(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::MutableBoxValue &box,
bool mayBePolymorphic) {
bool mayBePolymorphic,
bool preserveLowerBounds) {
if (box.hasAssumedRank())
TODO(loc, "assumed rank allocatables or pointers");
llvm::SmallVector<mlir::Value> lbounds;
llvm::SmallVector<mlir::Value> extents;
llvm::SmallVector<mlir::Value> lengths;
if (readToBoxValue(box, mayBePolymorphic)) {
auto reader = MutablePropertyReader(builder, loc, box);
reader.getLowerBounds(lbounds);
if (preserveLowerBounds)
reader.getLowerBounds(lbounds);
return fir::BoxValue{reader.getIrBox(), lbounds,
box.nonDeferredLenParams()};
}
// Contiguous intrinsic type entity: all the data can be extracted from the
// fir.box.
auto addr =
MutablePropertyReader(builder, loc, box).read(lbounds, extents, lengths);
if (!preserveLowerBounds)
lbounds.clear();
auto rank = box.rank();
if (box.isCharacter()) {
auto len = lengths.empty() ? mlir::Value{} : lengths[0];
Expand Down
9 changes: 8 additions & 1 deletion flang/lib/Optimizer/Dialect/FIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,14 @@ fir::FIROpsDialect::FIROpsDialect(mlir::MLIRContext *ctx)
#include "flang/Optimizer/Dialect/FIROps.cpp.inc"
>();
registerOpExternalInterfaces();
addInterfaces<FIRInlinerInterface>();
}

// Register the FIRInlinerInterface to FIROpsDialect
void fir::addFIRInlinerExtension(mlir::DialectRegistry &registry) {
registry.addExtension(
+[](mlir::MLIRContext *ctx, fir::FIROpsDialect *dialect) {
dialect->addInterface<FIRInlinerInterface>();
});
}

// anchor the class vtable to this compilation unit
Expand Down
30 changes: 18 additions & 12 deletions flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ createArrayTemp(mlir::Location loc, fir::FirOpBuilder &builder,
return {hlfir::Entity{declareOp.getBase()}, trueVal};
}

/// Copy \p source into a new temporary and package the temporary into a
/// <temp,cleanup> tuple. The temporary may be heap or stack allocated.
static mlir::Value copyInTempAndPackage(mlir::Location loc,
fir::FirOpBuilder &builder,
hlfir::Entity source) {
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
builder.create<hlfir::AssignOp>(loc, source, temp, temp.isAllocatable(),
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
// Dereference allocatable temporary directly to simplify processing
// of its uses.
if (temp.isAllocatable())
temp = hlfir::derefPointersAndAllocatables(loc, builder, temp);
return packageBufferizedExpr(loc, builder, temp, cleanup);
}

struct AsExprOpConversion : public mlir::OpConversionPattern<hlfir::AsExprOp> {
using mlir::OpConversionPattern<hlfir::AsExprOp>::OpConversionPattern;
explicit AsExprOpConversion(mlir::MLIRContext *ctx)
Expand All @@ -178,12 +194,7 @@ struct AsExprOpConversion : public mlir::OpConversionPattern<hlfir::AsExprOp> {
}
// Otherwise, create a copy in a new buffer.
hlfir::Entity source = hlfir::Entity{adaptor.getVar()};
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
builder.create<hlfir::AssignOp>(loc, source, temp, temp.isAllocatable(),
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
mlir::Value bufferizedExpr =
packageBufferizedExpr(loc, builder, temp, cleanup);
mlir::Value bufferizedExpr = copyInTempAndPackage(loc, builder, source);
rewriter.replaceOp(asExpr, bufferizedExpr);
return mlir::success();
}
Expand Down Expand Up @@ -542,12 +553,7 @@ struct AssociateOpConversion
// non-trivial value with more than one use. We will have to make a copy and
// use that
hlfir::Entity source = hlfir::Entity{bufferizedExpr};
auto [temp, cleanup] = hlfir::createTempFromMold(loc, builder, source);
builder.create<hlfir::AssignOp>(loc, source, temp, temp.isAllocatable(),
/*keep_lhs_length_if_realloc=*/false,
/*temporary_lhs=*/true);
mlir::Value bufferTuple =
packageBufferizedExpr(loc, builder, temp, cleanup);
mlir::Value bufferTuple = copyInTempAndPackage(loc, builder, source);
bufferizedExpr = getBufferizedExprStorage(bufferTuple);
replaceWith(bufferizedExpr, hlfir::Entity{bufferizedExpr}.getFirBase(),
getBufferizedExprMustFreeFlag(bufferTuple));
Expand Down
4 changes: 3 additions & 1 deletion flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5648,7 +5648,9 @@ void DeclarationVisitor::Post(const parser::ProcDecl &x) {
const auto &name{std::get<parser::Name>(x.t)};
const Symbol *procInterface{nullptr};
if (interfaceName_) {
procInterface = interfaceName_->symbol;
procInterface = interfaceName_->symbol->has<GenericDetails>()
? interfaceName_->symbol->get<GenericDetails>().specific()
: interfaceName_->symbol;
}
auto attrs{HandleSaveName(name.source, GetAttrs())};
DerivedTypeDetails *dtDetails{nullptr};
Expand Down
38 changes: 38 additions & 0 deletions flang/test/HLFIR/as_expr-codegen-polymorphic.fir
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Test hlfir.as_expr codegen for polymorphic expressions.

// RUN: fir-opt %s -bufferize-hlfir | FileCheck %s

!t = !fir.type<t{i:i32}>
func.func @as_expr_class(%arg0 : !fir.class<!t>, %arg1: !fir.ref<!t>) {
%0 = hlfir.as_expr %arg0 : (!fir.class<!t>) -> !hlfir.expr<!t?>
hlfir.assign %0 to %arg1 : !hlfir.expr<!t?>, !fir.ref<!t>
return
}
// CHECK-LABEL: func.func @as_expr_class(
// CHECK: %[[VAL_5:.*]] = arith.constant true
// CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = ".tmp"} : (!fir.ref<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>>) -> (!fir.ref<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>>, !fir.ref<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>>)
// ... copy ...
// CHECK: %[[VAL_11:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>>
// CHECK: %[[VAL_12:.*]] = fir.undefined tuple<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>, i1>
// CHECK: %[[VAL_13:.*]] = fir.insert_value %[[VAL_12]], %[[VAL_5]], [1 : index] : (tuple<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>, i1>, i1) -> tuple<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>, i1>
// CHECK: %[[VAL_14:.*]] = fir.insert_value %[[VAL_13]], %[[VAL_11]], [0 : index] : (tuple<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>, i1>, !fir.class<!fir.heap<!fir.type<t{i:i32}>>>) -> tuple<!fir.class<!fir.heap<!fir.type<t{i:i32}>>>, i1>
// CHECK: hlfir.assign %[[VAL_11]] to %{{.*}} : !fir.class<!fir.heap<!fir.type<t{i:i32}>>>, !fir.ref<!fir.type<t{i:i32}>>


func.func @as_expr_class_2(%arg0 : !fir.class<!fir.array<?x!t>>) {
%0 = hlfir.as_expr %arg0 : (!fir.class<!fir.array<?x!t>>) -> !hlfir.expr<?x!t?>
%c1 = arith.constant 1 : index
%1 = hlfir.apply %0, %c1 : (!hlfir.expr<?x!t?>, index) -> !hlfir.expr<!t?>
return
}
// CHECK-LABEL: func.func @as_expr_class_2(
// CHECK: %[[VAL_9:.*]] = arith.constant true
// CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = ".tmp"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>>)
// CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32
// ... copy ...
// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>>
// CHECK: %[[VAL_16:.*]] = fir.undefined tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, i1>
// CHECK: %[[VAL_17:.*]] = fir.insert_value %[[VAL_16]], %[[VAL_9]], [1 : index] : (tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, i1>, i1) -> tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, i1>
// CHECK: %[[VAL_18:.*]] = fir.insert_value %[[VAL_17]], %[[VAL_15]], [0 : index] : (tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, i1>, !fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>) -> tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, i1>
// CHECK: %[[VAL_19:.*]] = arith.constant 1 : index
// CHECK: %[[VAL_20:.*]] = hlfir.designate %[[VAL_15]] (%[[VAL_19]]) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<t{i:i32}>>>>, index) -> !fir.class<!fir.type<t{i:i32}>>
25 changes: 12 additions & 13 deletions flang/test/HLFIR/bufferize-poly-expr.fir
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ func.func @test_poly_expr_without_associate() {
// CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_4]]#1 : (!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>) -> !fir.box<none>
// CHECK: %[[VAL_12:.*]] = fir.call @_FortranAAllocatableApplyMold(%[[VAL_10]], %[[VAL_11]], %[[VAL_9]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, i32) -> none
// CHECK: hlfir.assign %[[VAL_4]]#0 to %[[VAL_8]]#0 realloc temporary_lhs : !fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>
// CHECK: %[[VAL_13:.*]] = fir.undefined tuple<!fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, i1>
// CHECK: %[[VAL_14:.*]] = fir.insert_value %[[VAL_13]], %[[VAL_7]], [1 : index] : (tuple<!fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, i1>, i1) -> tuple<!fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, i1>
// CHECK: %[[VAL_15:.*]] = fir.insert_value %[[VAL_14]], %[[VAL_8]]#0, [0 : index] : (tuple<!fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, i1>, !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>) -> tuple<!fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, i1>
// CHECK: hlfir.assign %[[VAL_8]]#0 to %[[VAL_2]]#0 realloc : !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>, !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>
// CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>
// CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_16]] : (!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>) -> !fir.heap<!fir.type<_QFtestTt{c:i32}>>
// CHECK: %[[VAL_8B:.*]] = fir.load %[[VAL_8]]#0
// CHECK: %[[VAL_13:.*]] = fir.undefined tuple<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, i1>
// CHECK: %[[VAL_14:.*]] = fir.insert_value %[[VAL_13]], %[[VAL_7]], [1 : index] : (tuple<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, i1>, i1) -> tuple<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, i1>
// CHECK: %[[VAL_15:.*]] = fir.insert_value %[[VAL_14]], %[[VAL_8B]], [0 : index] : (tuple<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, i1>, !fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>) -> tuple<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, i1>
// CHECK: hlfir.assign %[[VAL_8B]] to %[[VAL_2]]#0 realloc : !fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>, !fir.ref<!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>>
// CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_8B]] : (!fir.class<!fir.heap<!fir.type<_QFtestTt{c:i32}>>>) -> !fir.heap<!fir.type<_QFtestTt{c:i32}>>
// CHECK: fir.freemem %[[VAL_17]] : !fir.heap<!fir.type<_QFtestTt{c:i32}>>
// CHECK: return
// CHECK: }
Expand Down Expand Up @@ -81,25 +81,24 @@ func.func @test_poly_expr_with_associate(%arg1: !fir.class<!fir.array<3x!fir.typ
// CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_5]] : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>) -> !fir.box<none>
// CHECK: %[[VAL_18:.*]] = fir.call @_FortranAAllocatableApplyMold(%[[VAL_16]], %[[VAL_17]], %[[VAL_15]]) : (!fir.ref<!fir.box<none>>, !fir.box<none>, i32) -> none
// CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_14]]#0 realloc temporary_lhs : !fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>
// CHECK: %[[VAL_19:.*]] = fir.undefined tuple<!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>, i1>
// CHECK: %[[VAL_20:.*]] = fir.insert_value %[[VAL_19]], %[[VAL_13]], [1 : index] : (tuple<!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>, i1>, i1) -> tuple<!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>, i1>
// CHECK: %[[VAL_21:.*]] = fir.insert_value %[[VAL_20]], %[[VAL_14]]#0, [0 : index] : (tuple<!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>, i1>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>) -> tuple<!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>, i1>
// CHECK: %[[VAL_14B:.*]] = fir.load %[[VAL_14]]#0
// CHECK: %[[VAL_19:.*]] = fir.undefined tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, i1>
// CHECK: %[[VAL_20:.*]] = fir.insert_value %[[VAL_19]], %[[VAL_13]], [1 : index] : (tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, i1>, i1) -> tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, i1>
// CHECK: %[[VAL_21:.*]] = fir.insert_value %[[VAL_20]], %[[VAL_14B]], [0 : index] : (tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, i1>, !fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>) -> tuple<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, i1>
// CHECK: %[[VAL_22:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_23:.*]]:3 = fir.box_dims %[[VAL_5]], %[[VAL_22]] : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, index) -> (index, index, index)
// CHECK: %[[VAL_24:.*]] = fir.shape %[[VAL_23]]#1 : (index) -> !fir.shape<1>
// CHECK: %[[VAL_25:.*]] = fir.load %[[VAL_14]]#0 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>
// CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_14]]#1 : !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>
// CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>>) -> !fir.box<none>
// CHECK: %[[VAL_28:.*]] = fir.call @_FortranADestroy(%[[VAL_27]]) fastmath<contract> : (!fir.box<none>) -> none
// CHECK: %[[VAL_29:.*]] = arith.constant 3 : index
// CHECK: %[[VAL_30:.*]] = fir.shape %[[VAL_29]] : (index) -> !fir.shape<1>
// CHECK: %[[VAL_31:.*]] = arith.constant 1 : index
// CHECK: fir.do_loop %[[VAL_32:.*]] = %[[VAL_31]] to %[[VAL_29]] step %[[VAL_31]] {
// CHECK: %[[VAL_33:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_32]]) : (!fir.class<!fir.array<3x!fir.type<_QMtest_typeTt1{i:i32}>>>, index) -> !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>
// CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_25]] (%[[VAL_32]]) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, index) -> !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>
// CHECK: %[[VAL_34:.*]] = hlfir.designate %[[VAL_14B]] (%[[VAL_32]]) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>, index) -> !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>
// CHECK: fir.dispatch "assign"(%[[VAL_33]] : !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>) (%[[VAL_33]], %[[VAL_34]] : !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>, !fir.class<!fir.type<_QMtest_typeTt1{i:i32}>>) {pass_arg_pos = 0 : i32}
// CHECK: }
// CHECK: %[[VAL_35:.*]] = fir.box_addr %[[VAL_26]] : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>) -> !fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>
// CHECK: %[[VAL_35:.*]] = fir.box_addr %[[VAL_14B]] : (!fir.class<!fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>>) -> !fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>
// CHECK: fir.freemem %[[VAL_35]] : !fir.heap<!fir.array<?x!fir.type<_QMtest_typeTt1{i:i32}>>>
// CHECK: return
// CHECK: }
25 changes: 20 additions & 5 deletions flang/test/Lower/HLFIR/function-return-as-expr.f90
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,26 @@ function inner()
end function inner
end subroutine test4
! CHECK-LABEL: func.func @_QPtest4() {
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.class<!fir.heap<none>>>) -> (!fir.ref<!fir.class<!fir.heap<none>>>, !fir.ref<!fir.class<!fir.heap<none>>>)
! CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref<!fir.class<!fir.heap<none>>>
! CHECK: %[[VAL_8:.*]] = arith.constant false
! CHECK: %[[VAL_9:.*]] = hlfir.as_expr %[[VAL_7]] move %[[VAL_8]] : (!fir.class<!fir.heap<none>>, i1) -> !hlfir.expr<none?>
! CHECK: hlfir.assign %[[VAL_9]] to %{{.*}}#0 realloc : !hlfir.expr<none?>, !fir.ref<!fir.class<!fir.heap<none>>>
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_0:.*]] : !fir.ref<!fir.class<!fir.heap<none>>>
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = ".tmp.func_result"} : (!fir.class<!fir.heap<none>>) -> (!fir.class<!fir.heap<none>>, !fir.class<!fir.heap<none>>)
! CHECK: hlfir.assign %[[VAL_7]]#0 to %{{.*}}#0 realloc : !fir.class<!fir.heap<none>>, !fir.ref<!fir.class<!fir.heap<none>>>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.class<!fir.heap<none>>>) -> !fir.box<none>
! CHECK: fir.call @_FortranADestroy(%[[VAL_10]]) fastmath<contract> : (!fir.box<none>) -> none

subroutine test4b
class(*), allocatable :: p(:, :)
p = inner()
contains
function inner()
class(*), allocatable :: inner(:, :)
end function inner
end subroutine test4b
! CHECK-LABEL: func.func @_QPtest4b() {
! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_0:.*]] : !fir.ref<!fir.class<!fir.heap<!fir.array<?x?xnone>>>>
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = ".tmp.func_result"} : (!fir.class<!fir.heap<!fir.array<?x?xnone>>>) -> (!fir.class<!fir.heap<!fir.array<?x?xnone>>>, !fir.class<!fir.heap<!fir.array<?x?xnone>>>)
! CHECK: hlfir.assign %[[VAL_7]]#0 to %{{.*}}#0 realloc : !fir.class<!fir.heap<!fir.array<?x?xnone>>>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x?xnone>>>>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x?xnone>>>>) -> !fir.box<none>
! CHECK: fir.call @_FortranADestroy(%[[VAL_10]]) fastmath<contract> : (!fir.box<none>) -> none

subroutine test5
use types
Expand Down
1 change: 1 addition & 0 deletions flang/tools/bbc/bbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ static mlir::LogicalResult convertFortranSourceToMLIR(
// translate to FIR dialect of MLIR
mlir::DialectRegistry registry;
fir::support::registerNonCodegenDialects(registry);
fir::support::addFIRExtensions(registry);
mlir::MLIRContext ctx(registry);
fir::support::loadNonCodegenDialects(ctx);
auto &defKinds = semanticsContext.defaultKinds();
Expand Down
1 change: 1 addition & 0 deletions flang/tools/fir-opt/fir-opt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ int main(int argc, char **argv) {
#endif
DialectRegistry registry;
fir::support::registerDialects(registry);
fir::support::addFIRExtensions(registry);
return failed(MlirOptMain(argc, argv, "FIR modular optimizer driver\n",
registry));
}
1 change: 1 addition & 0 deletions flang/tools/tco/tco.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ compileFIR(const mlir::PassPipelineCLParser &passPipeline) {
sourceMgr.AddNewSourceBuffer(std::move(*fileOrErr), SMLoc());
mlir::DialectRegistry registry;
fir::support::registerDialects(registry);
fir::support::addFIRExtensions(registry);
mlir::MLIRContext context(registry);
fir::support::loadDialects(context);
fir::support::registerLLVMTranslation(context);
Expand Down
8 changes: 8 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,15 @@ set(TARGET_LIBM_ENTRYPOINTS
if(LIBC_COMPILER_HAS_FLOAT128)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float128 entrypoints
libc.src.math.ceilf128
libc.src.math.copysignf128
libc.src.math.fabsf128
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
libc.src.math.roundf128
libc.src.math.sqrtf128
libc.src.math.truncf128
)
endif()

Expand Down
15 changes: 15 additions & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,21 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.truncl
)

if(LIBC_COMPILER_HAS_FLOAT128)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float128 entrypoints
libc.src.math.ceilf128
libc.src.math.copysignf128
libc.src.math.fabsf128
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
libc.src.math.roundf128
libc.src.math.sqrtf128
libc.src.math.truncf128
)
endif()

if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
# compiler entrypoints (no corresponding header)
Expand Down
5 changes: 5 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdbit.stdc_trailing_zeros_ui
libc.src.stdbit.stdc_trailing_zeros_ul
libc.src.stdbit.stdc_trailing_zeros_ull
libc.src.stdbit.stdc_trailing_ones_uc
libc.src.stdbit.stdc_trailing_ones_us
libc.src.stdbit.stdc_trailing_ones_ui
libc.src.stdbit.stdc_trailing_ones_ul
libc.src.stdbit.stdc_trailing_ones_ull

# stdlib.h entrypoints
libc.src.stdlib.abs
Expand Down
16 changes: 8 additions & 8 deletions libc/docs/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,23 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ceill | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| ceilf128 | |check| | | | | | | | | | | | |
| ceilf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| copysign | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| copysignf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| copysignl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| copysignf128 | |check| | |check| | | | | | | | | | | |
| copysignf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fabs | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fabsf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fabsl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fabsf128 | |check| | |check| | | | | | | | | | | |
| fabsf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fdim | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Expand All @@ -144,21 +144,21 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| floorl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| floorf128 | |check| | | | | | | | | | | | |
| floorf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmax | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmaxf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmaxf128 | |check| | | | | | | | | | | | |
| fmaxf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmaxl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fmin | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fminf | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fminf128 | |check| | | | | | | | | | | | |
| fminf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| fminl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Expand Down Expand Up @@ -270,7 +270,7 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| roundl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| roundf128 | |check| | | | | | | | | | | | |
| roundf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| scalbn | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
Expand All @@ -284,7 +284,7 @@ Basic Operations
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| truncl | |check| | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
| truncf128 | |check| | | | | | | | | | | | |
| truncf128 | |check| | |check| | | |check| | | | | | | | | |
+--------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+


Expand Down
23 changes: 23 additions & 0 deletions libc/include/llvm-libc-macros/stdbit-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef __LLVM_LIBC_MACROS_STDBIT_MACROS_H
#define __LLVM_LIBC_MACROS_STDBIT_MACROS_H

// TODO(https://github.com/llvm/llvm-project/issues/80509): support _BitInt().
#ifdef __cplusplus
inline unsigned stdc_leading_zeros(unsigned char x) {
return stdc_leading_zeros_uc(x);
Expand Down Expand Up @@ -55,6 +56,21 @@ inline unsigned stdc_trailing_zeros(unsigned long x) {
inline unsigned stdc_trailing_zeros(unsigned long long x) {
return stdc_trailing_zeros_ull(x);
}
inline unsigned stdc_trailing_ones(unsigned char x) {
return stdc_trailing_ones_uc(x);
}
inline unsigned stdc_trailing_ones(unsigned short x) {
return stdc_trailing_ones_us(x);
}
inline unsigned stdc_trailing_ones(unsigned x) {
return stdc_trailing_ones_ui(x);
}
inline unsigned stdc_trailing_ones(unsigned long x) {
return stdc_trailing_ones_ul(x);
}
inline unsigned stdc_trailing_ones(unsigned long long x) {
return stdc_trailing_ones_ull(x);
}
#else
#define stdc_leading_zeros(x) \
_Generic((x), \
Expand All @@ -77,6 +93,13 @@ inline unsigned stdc_trailing_zeros(unsigned long long x) {
unsigned: stdc_trailing_zeros_ui, \
unsigned long: stdc_trailing_zeros_ul, \
unsigned long long: stdc_trailing_zeros_ull)(x)
#define stdc_trailing_ones(x) \
_Generic((x), \
unsigned char: stdc_trailing_ones_uc, \
unsigned short: stdc_trailing_ones_us, \
unsigned: stdc_trailing_ones_ui, \
unsigned long: stdc_trailing_ones_ul, \
unsigned long long: stdc_trailing_ones_ull)(x)
#endif // __cplusplus

#endif // __LLVM_LIBC_MACROS_STDBIT_MACROS_H
10 changes: 8 additions & 2 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,8 @@ def StdC : StandardSpec<"stdc"> {
[
Macro<"stdc_leading_zeros">,
Macro<"stdc_leading_ones">,
Macro<"stdc_trailing_zeros">
Macro<"stdc_trailing_zeros">,
Macro<"stdc_trailing_ones">
], // Macros
[], // Types
[], // Enumerations
Expand All @@ -796,7 +797,12 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"stdc_trailing_zeros_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
FunctionSpec<"stdc_trailing_zeros_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"stdc_trailing_zeros_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
FunctionSpec<"stdc_trailing_zeros_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
FunctionSpec<"stdc_trailing_zeros_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>,
FunctionSpec<"stdc_trailing_ones_uc", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedCharType>]>,
FunctionSpec<"stdc_trailing_ones_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
FunctionSpec<"stdc_trailing_ones_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"stdc_trailing_ones_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
FunctionSpec<"stdc_trailing_ones_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
] // Functions
>;

Expand Down
10 changes: 0 additions & 10 deletions libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,16 +143,6 @@ add_header_library(
libc.src.__support.uint128
)

add_header_library(
xfloat
HDRS
XFloat.h
DEPENDS
.fp_bits
.normal_float
libc.src.__support.uint
)

add_header_library(
sqrt
HDRS
Expand Down
Loading