25 changes: 25 additions & 0 deletions clang/test/CodeGenCXX/type-metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// Tests for the whole-program-vtables feature:
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM --check-prefix=TT-ITANIUM %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=ITANIUM-DEFAULTVIS --check-prefix=TT-ITANIUM %s
// RUN: %clang_cc1 -O2 -flto -flto-unit -triple x86_64-unknown-linux -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=ITANIUM-OPT %s
// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-pc-windows-msvc -fwhole-program-vtables -emit-llvm -o - %s | FileCheck --check-prefix=VTABLE-OPT --check-prefix=MS --check-prefix=TT-MS %s

// Tests for cfi + whole-program-vtables:
Expand Down Expand Up @@ -79,6 +80,13 @@
// ITANIUM-DIAG-SAME: !type [[ALL16]]
// ITANIUM-SAME: !type [[FAF16:![0-9]+]]

// ITANIUM: @_ZTVN5test31EE = external unnamed_addr constant
// ITANIUM-DEFAULTVIS: @_ZTVN5test31EE = external unnamed_addr constant
// ITANIUM-OPT: @_ZTVN5test31EE = available_externally unnamed_addr constant {{[^!]*}},
// ITANIUM-OPT-SAME: !type [[E16:![0-9]+]],
// ITANIUM-OPT-SAME: !type [[EF16:![0-9]+]]
// ITANIUM-OPT: @llvm.compiler.used = appending global [1 x i8*] [i8* bitcast ({ [3 x i8*] }* @_ZTVN5test31EE to i8*)]

// MS: comdat($"??_7A@@6B@"), !type [[A8:![0-9]+]]
// MS: comdat($"??_7B@@6B0@@"), !type [[B8:![0-9]+]]
// MS: comdat($"??_7B@@6BA@@@"), !type [[A8]]
Expand Down Expand Up @@ -253,6 +261,20 @@ void f(D *d) {

}

namespace test3 {
// All virtual functions are outline, so we can assume that it will
// be generated in translation unit where foo is defined.
struct E {
virtual void foo();
};

void g() {
E e;
e.foo();
}

} // Test9

// ITANIUM: [[A16]] = !{i64 16, !"_ZTS1A"}
// ITANIUM-DIAG: [[ALL16]] = !{i64 16, !"all-vtables"}
// ITANIUM: [[AF16]] = !{i64 16, !"_ZTSM1AFvvE.virtual"}
Expand Down Expand Up @@ -286,6 +308,9 @@ void f(D *d) {
// ITANIUM: [[FAF16]] = !{i64 16, [[FAF_ID:![0-9]+]]}
// ITANIUM: [[FAF_ID]] = distinct !{}

// ITANIUM-OPT: [[E16]] = !{i64 16, !"_ZTSN5test31EE"}
// ITANIUM-OPT: [[EF16]] = !{i64 16, !"_ZTSMN5test31EEFvvE.virtual"}

// MS: [[A8]] = !{i64 8, !"?AUA@@"}
// MS: [[B8]] = !{i64 8, !"?AUB@@"}
// MS: [[D8]] = !{i64 8, [[D_ID:![0-9]+]]}
Expand Down
1 change: 0 additions & 1 deletion clang/test/CodeGenCXX/union-tbaa2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ struct A {
// CHECK: tbaa ![[OCPATH:[0-9]+]]
// CHECK: store <4 x double>
// CHECK: tbaa ![[OCPATH]]
// CHECK: call
a = _mm256_setr_pd(0.0, 1.0, 2.0, 3.0);
b = _mm256_setr_pd(4.0, 5.0, 6.0, 7.0);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenObjC/disable-tail-call-escaping-block.m
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// CHECK: define internal void @[[TEST_BLOCK_INVOKE5]]({{.*}}) #[[DISABLEATTR]] {
// CHECK: define internal void @[[TEST_BLOCK_INVOKE6]]({{.*}}) #[[ENABLEATTR]] {

// CHECK: attributes #[[ENABLEATTR]] = {{{.*}}"disable-tail-calls"="false"{{.*}}}
// CHECK-NOT: attributes #[[ENABLEATTR]] = {{{.*}}"disable-tail-calls"="false"{{.*}}}
// CHECK: attributes #[[DISABLEATTR]] = {{{.*}}"disable-tail-calls"="true"{{.*}}}

typedef void (^BlockTy)(void);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGenOpenCL/amdgpu-nullptr.cl
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ typedef struct {
} StructTy3;

// CHECK-LABEL: test_memset_private
// CHECK: call void @llvm.memset.p5i8.i64(i8 addrspace(5)* align 8 {{.*}}, i8 0, i64 32, i1 false)
// CHECK: call void @llvm.memset.p5i8.i64(i8 addrspace(5)* noundef align 8 {{.*}}, i8 0, i64 32, i1 false)
// CHECK: [[GEP:%.*]] = getelementptr inbounds %struct.StructTy3, %struct.StructTy3 addrspace(5)* %ptr, i32 0, i32 4
// CHECK: store i8 addrspace(5)* addrspacecast (i8* null to i8 addrspace(5)*), i8 addrspace(5)* addrspace(5)* [[GEP]]
// CHECK: [[GEP1:%.*]] = getelementptr inbounds i8, i8 addrspace(5)* {{.*}}, i32 36
Expand Down
3 changes: 3 additions & 0 deletions clang/test/Profile/profile-prefix-map.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c ../root/nested/profile-prefix-map.c -fprofile-prefix-map=../root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\02.*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}

// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -fprofile-compilation-dir=/custom -fprofile-prefix-map=/custom=/nonsense -o - | FileCheck --check-prefix=PROFILE-COMPILATION-DIR %s
// PROFILE-COMPILATION-DIR: @__llvm_coverage_mapping = {{.*"\\02.*}}nonsense
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
// The template parameter Params is a class containing the actual parameters.
//
// Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
// Otherwise SpaceBeg=kSpaceBeg (fixed address).
// kSpaceSize is a power of two.
// At the beginning the entire space is mprotect-ed, then small parts of it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// `LocalAddressSpaceView` provides the local (i.e. target and current address
// space are the same) implementation of the `AddressSpaveView` interface which
// space are the same) implementation of the `AddressSpaceView` interface which
// provides a simple interface to load memory from another process (i.e.
// out-of-process)
//
Expand Down
3 changes: 0 additions & 3 deletions flang/include/flang/Optimizer/Dialect/FIROps.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#include "mlir/Dialect/StandardOps/IR/Ops.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"
#include "flang/Optimizer/Dialect/FIRType.h"


using namespace mlir;

Expand Down Expand Up @@ -49,5 +47,4 @@ mlir::ParseResult parseSelector(mlir::OpAsmParser &parser,
#define GET_OP_CLASSES
#include "flang/Optimizer/Dialect/FIROps.h.inc"


#endif // FORTRAN_OPTIMIZER_DIALECT_FIROPS_H
56 changes: 56 additions & 0 deletions flang/include/flang/Optimizer/Support/FIRContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===-- Optimizer/Support/FIRContext.h --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//
/// Setters and getters for associating context with an instance of a ModuleOp.
/// The context is typically set by the tool and needed in later stages to
/// determine how to correctly generate code.
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
#define FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H

#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"

namespace mlir {
class ModuleOp;
}

namespace fir {
class KindMapping;
struct NameUniquer;

/// Set the target triple for the module. `triple` must not be deallocated while
/// module `mod` is still live.
void setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple);

/// Get the Triple instance from the Module or return the default Triple.
llvm::Triple getTargetTriple(mlir::ModuleOp mod);

/// Set the kind mapping for the module. `kindMap` must not be deallocated while
/// module `mod` is still live.
void setKindMapping(mlir::ModuleOp mod, KindMapping &kindMap);

/// Get the KindMapping instance from the Module. If none was set, returns a
/// default.
KindMapping getKindMapping(mlir::ModuleOp mod);

/// Helper for determining the target from the host, etc. Tools may use this
/// function to provide a consistent interpretation of the `--target=<string>`
/// command-line option.
/// An empty string ("") or "default" will specify that the default triple
/// should be used. "native" will specify that the host machine be used to
/// construct the triple.
std::string determineTargetTriple(llvm::StringRef triple);

} // namespace fir

#endif // FORTRAN_OPTIMIZER_SUPPORT_FIRCONTEXT_H
83 changes: 44 additions & 39 deletions flang/include/flang/Optimizer/Support/InternalNames.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//

#ifndef OPTIMIZER_SUPPORT_INTERNALNAMES_H
#define OPTIMIZER_SUPPORT_INTERNALNAMES_H
#ifndef FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H
#define FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
Expand Down Expand Up @@ -59,58 +59,58 @@ struct NameUniquer {
llvm::SmallVector<std::int64_t, 4> kinds;
};

NameUniquer() = default;

/// Unique a common block name
std::string doCommonBlock(llvm::StringRef name);
static std::string doCommonBlock(llvm::StringRef name);

/// Unique a block data unit name
std::string doBlockData(llvm::StringRef name);
static std::string doBlockData(llvm::StringRef name);

/// Unique a (global) constant name
std::string doConstant(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);
static std::string doConstant(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);

/// Unique a dispatch table name
std::string doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);
static std::string doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);

/// Unique a compiler generated name
std::string doGenerated(llvm::StringRef name);
static std::string doGenerated(llvm::StringRef name);

/// Unique an intrinsic type descriptor
std::string doIntrinsicTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
IntrinsicType type, std::int64_t kind);
static std::string
doIntrinsicTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
IntrinsicType type, std::int64_t kind);

/// Unique a procedure name
std::string doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);
static std::string doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);

/// Unique a derived type name
std::string doType(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host, llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);
static std::string doType(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);

/// Unique a (derived) type descriptor name
std::string doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);
std::string doTypeDescriptor(llvm::ArrayRef<std::string> modules,
llvm::Optional<std::string> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);
static std::string doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);
static std::string doTypeDescriptor(llvm::ArrayRef<std::string> modules,
llvm::Optional<std::string> host,
llvm::StringRef name,
llvm::ArrayRef<std::int64_t> kinds);

/// Unique a (global) variable name. A variable with save attribute
/// defined inside a subprogram also needs to be handled here
std::string doVariable(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);
static std::string doVariable(llvm::ArrayRef<llvm::StringRef> modules,
llvm::Optional<llvm::StringRef> host,
llvm::StringRef name);

/// Entry point for the PROGRAM (called by the runtime)
/// Can be overridden with the `--main-entry-name=<name>` option.
Expand All @@ -121,12 +121,17 @@ struct NameUniquer {
deconstruct(llvm::StringRef uniquedName);

private:
std::string intAsString(std::int64_t i);
std::string doKind(std::int64_t kind);
std::string doKinds(llvm::ArrayRef<std::int64_t> kinds);
std::string toLower(llvm::StringRef name);
static std::string intAsString(std::int64_t i);
static std::string doKind(std::int64_t kind);
static std::string doKinds(llvm::ArrayRef<std::int64_t> kinds);
static std::string toLower(llvm::StringRef name);

NameUniquer() = delete;
NameUniquer(const NameUniquer &) = delete;
NameUniquer(NameUniquer &&) = delete;
NameUniquer &operator=(const NameUniquer &) = delete;
};

} // namespace fir

#endif // OPTIMIZER_SUPPORT_INTERNALNAMES_H
#endif // FORTRAN_OPTIMIZER_SUPPORT_INTERNALNAMES_H
39 changes: 32 additions & 7 deletions flang/include/flang/Optimizer/Support/KindMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
//
//===----------------------------------------------------------------------===//

#ifndef OPTIMIZER_SUPPORT_KINDMAPPING_H
#define OPTIMIZER_SUPPORT_KINDMAPPING_H
#ifndef FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H
#define FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H

#include "mlir/IR/OpDefinition.h"
#include "llvm/ADT/DenseMap.h"
Expand Down Expand Up @@ -52,15 +52,24 @@ class KindMapping {
using LLVMTypeID = llvm::Type::TypeID;
using MatchResult = mlir::ParseResult;

/// KindMapping constructors take an optional `defs` argument to specify the
/// KindMapping constructor with both the kind map and default kinds read from
/// command-line options.
explicit KindMapping(mlir::MLIRContext *context);
/// KindMapping constructor taking a `defs` argument to specify the default
/// kinds for intrinsic types. To set the default kinds, an ArrayRef of 6
/// KindTy must be passed. The kinds must be the given in the following order:
/// CHARACTER, COMPLEX, DOUBLE PRECISION, INTEGER, LOGICAL, and REAL. The
/// kind map is read from command-line options, if given.
explicit KindMapping(mlir::MLIRContext *context, llvm::ArrayRef<KindTy> defs);
/// KindMapping constructor taking an optional `defs` argument to specify the
/// default kinds for intrinsic types. To set the default kinds, an ArrayRef
/// of 6 KindTy must be passed. The kinds must be the given in the following
/// order: CHARACTER, COMPLEX, DOUBLE PRECISION, INTEGER, LOGICAL, and REAL.
/// If `defs` is not specified, default default kinds will be used.
explicit KindMapping(mlir::MLIRContext *context,
llvm::ArrayRef<KindTy> defs = llvm::None);
explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map,
llvm::ArrayRef<KindTy> defs = llvm::None);
explicit KindMapping(mlir::MLIRContext *context, llvm::StringRef map,
llvm::StringRef defs)
: KindMapping{context, map, toDefaultKinds(defs)} {}

/// Get the size in bits of !fir.char<kind>
Bitsize getCharacterBitsize(KindTy kind) const;
Expand All @@ -85,6 +94,12 @@ class KindMapping {
/// Get the float semantics of !fir.real<kind>
const llvm::fltSemantics &getFloatSemantics(KindTy kind) const;

/// Get the default kind map as a string.
static constexpr const char *getDefaultMap() { return ""; }

/// Convert the current kind map to a string.
std::string mapToString() const;

//===--------------------------------------------------------------------===//
// Default kinds of intrinsic types
//===--------------------------------------------------------------------===//
Expand All @@ -96,6 +111,16 @@ class KindMapping {
KindTy defaultLogicalKind() const;
KindTy defaultRealKind() const;

/// Get the default kinds as a string.
static constexpr const char *getDefaultKinds() { return "a1c4d8i4l4r4"; }

/// Convert the current default kinds to a string.
std::string defaultsToString() const;

/// Translate a default kinds string into a default kind vector. This vector
/// can be passed to the KindMapping ctor.
static std::vector<KindTy> toDefaultKinds(llvm::StringRef defs);

private:
MatchResult badMapString(const llvm::Twine &ptr);
MatchResult parse(llvm::StringRef kindMap);
Expand All @@ -109,4 +134,4 @@ class KindMapping {

} // namespace fir

#endif // OPTIMIZER_SUPPORT_KINDMAPPING_H
#endif // FORTRAN_OPTIMIZER_SUPPORT_KINDMAPPING_H
1 change: 1 addition & 0 deletions flang/lib/Optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_flang_library(FIROptimizer
Dialect/FIROps.cpp
Dialect/FIRType.cpp

Support/FIRContext.cpp
Support/InternalNames.cpp
Support/KindMapping.cpp

Expand Down
62 changes: 62 additions & 0 deletions flang/lib/Optimizer/Support/FIRContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===-- FIRContext.cpp ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//

#include "flang/Optimizer/Support/FIRContext.h"
#include "flang/Optimizer/Support/KindMapping.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
#include "llvm/Support/Host.h"

static constexpr const char *tripleName = "fir.triple";

void fir::setTargetTriple(mlir::ModuleOp mod, llvm::StringRef triple) {
auto target = fir::determineTargetTriple(triple);
mod->setAttr(tripleName, mlir::StringAttr::get(mod.getContext(), target));
}

llvm::Triple fir::getTargetTriple(mlir::ModuleOp mod) {
if (auto target = mod->getAttrOfType<mlir::StringAttr>(tripleName))
return llvm::Triple(target.getValue());
return llvm::Triple(llvm::sys::getDefaultTargetTriple());
}

static constexpr const char *kindMapName = "fir.kindmap";
static constexpr const char *defKindName = "fir.defaultkind";

void fir::setKindMapping(mlir::ModuleOp mod, fir::KindMapping &kindMap) {
auto ctx = mod.getContext();
mod->setAttr(kindMapName, mlir::StringAttr::get(ctx, kindMap.mapToString()));
auto defs = kindMap.defaultsToString();
mod->setAttr(defKindName, mlir::StringAttr::get(ctx, defs));
}

fir::KindMapping fir::getKindMapping(mlir::ModuleOp mod) {
auto ctx = mod.getContext();
if (auto defs = mod->getAttrOfType<mlir::StringAttr>(defKindName)) {
auto defVals = fir::KindMapping::toDefaultKinds(defs.getValue());
if (auto maps = mod->getAttrOfType<mlir::StringAttr>(kindMapName))
return fir::KindMapping(ctx, maps.getValue(), defVals);
return fir::KindMapping(ctx, defVals);
}
return fir::KindMapping(ctx);
}

std::string fir::determineTargetTriple(llvm::StringRef triple) {
// Treat "" or "default" as stand-ins for the default machine.
if (triple.empty() || triple == "default")
return llvm::sys::getDefaultTargetTriple();
// Treat "native" as stand-in for the host machine.
if (triple == "native")
return llvm::sys::getProcessTriple();
// TODO: normalize the triple?
return triple.str();
}
4 changes: 4 additions & 0 deletions flang/lib/Optimizer/Support/InternalNames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
//
//===----------------------------------------------------------------------===//

#include "flang/Optimizer/Support/InternalNames.h"
#include "flang/Optimizer/Dialect/FIRType.h"
Expand Down
188 changes: 161 additions & 27 deletions flang/lib/Optimizer/Support/KindMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,27 @@ using KindTy = fir::KindMapping::KindTy;
using LLVMTypeID = fir::KindMapping::LLVMTypeID;
using MatchResult = fir::KindMapping::MatchResult;

static llvm::cl::opt<std::string> clKindMapping(
"kind-mapping", llvm::cl::desc("kind mapping string to set kind precision"),
llvm::cl::value_desc("kind-mapping-string"), llvm::cl::init(""));
static llvm::cl::opt<std::string>
clKindMapping("kind-mapping",
llvm::cl::desc("kind mapping string to set kind precision"),
llvm::cl::value_desc("kind-mapping-string"),
llvm::cl::init(fir::KindMapping::getDefaultMap()));

static llvm::cl::opt<std::string>
clDefaultKinds("default-kinds",
llvm::cl::desc("string to set default kind values"),
llvm::cl::value_desc("default-kind-string"),
llvm::cl::init(fir::KindMapping::getDefaultKinds()));

// Keywords for the floating point types.

static constexpr const char *kwHalf = "Half";
static constexpr const char *kwBFloat = "BFloat";
static constexpr const char *kwFloat = "Float";
static constexpr const char *kwDouble = "Double";
static constexpr const char *kwX86FP80 = "X86_FP80";
static constexpr const char *kwFP128 = "FP128";
static constexpr const char *kwPPCFP128 = "PPC_FP128";

/// Integral types default to the kind value being the size of the value in
/// bytes. The default is to scale from bytes to bits.
Expand Down Expand Up @@ -104,32 +122,50 @@ static const llvm::fltSemantics &getFloatSemanticsOfKind(KindTy kind,
}
}

static MatchResult parseCode(char &code, const char *&ptr) {
/// Parse an intrinsic type code. The codes are ('a', CHARACTER), ('c',
/// COMPLEX), ('i', INTEGER), ('l', LOGICAL), and ('r', REAL).
static MatchResult parseCode(char &code, const char *&ptr, const char *endPtr) {
if (ptr >= endPtr)
return mlir::failure();
if (*ptr != 'a' && *ptr != 'c' && *ptr != 'i' && *ptr != 'l' && *ptr != 'r')
return mlir::failure();
code = *ptr++;
return mlir::success();
}

/// Same as `parseCode` but adds the ('d', DOUBLE PRECISION) code.
static MatchResult parseDefCode(char &code, const char *&ptr,
const char *endPtr) {
if (ptr >= endPtr)
return mlir::failure();
if (*ptr == 'd') {
code = *ptr++;
return mlir::success();
}
return parseCode(code, ptr, endPtr);
}

template <char ch>
static MatchResult parseSingleChar(const char *&ptr) {
if (*ptr != ch)
static MatchResult parseSingleChar(const char *&ptr, const char *endPtr) {
if (ptr >= endPtr || *ptr != ch)
return mlir::failure();
++ptr;
return mlir::success();
}

static MatchResult parseColon(const char *&ptr) {
return parseSingleChar<':'>(ptr);
static MatchResult parseColon(const char *&ptr, const char *endPtr) {
return parseSingleChar<':'>(ptr, endPtr);
}

static MatchResult parseComma(const char *&ptr) {
return parseSingleChar<','>(ptr);
static MatchResult parseComma(const char *&ptr, const char *endPtr) {
return parseSingleChar<','>(ptr, endPtr);
}

static MatchResult parseInt(unsigned &result, const char *&ptr) {
/// Recognize and parse an unsigned integer.
static MatchResult parseInt(unsigned &result, const char *&ptr,
const char *endPtr) {
const char *beg = ptr;
while (*ptr >= '0' && *ptr <= '9')
while (ptr < endPtr && *ptr >= '0' && *ptr <= '9')
ptr++;
if (beg == ptr)
return mlir::failure();
Expand All @@ -141,42 +177,45 @@ static MatchResult parseInt(unsigned &result, const char *&ptr) {
return mlir::success();
}

static mlir::LogicalResult matchString(const char *&ptr,
static mlir::LogicalResult matchString(const char *&ptr, const char *endPtr,
llvm::StringRef literal) {
llvm::StringRef s(ptr);
llvm::StringRef s(ptr, endPtr - ptr);
if (s.startswith(literal)) {
ptr += literal.size();
return mlir::success();
}
return mlir::failure();
}

static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr) {
if (mlir::succeeded(matchString(ptr, "Half"))) {
/// Recognize and parse the various floating-point keywords. These follow the
/// LLVM naming convention.
static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr,
const char *endPtr) {
if (mlir::succeeded(matchString(ptr, endPtr, kwHalf))) {
result = LLVMTypeID::HalfTyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "BFloat"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwBFloat))) {
result = LLVMTypeID::BFloatTyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "Float"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwFloat))) {
result = LLVMTypeID::FloatTyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "Double"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwDouble))) {
result = LLVMTypeID::DoubleTyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "X86_FP80"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwX86FP80))) {
result = LLVMTypeID::X86_FP80TyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "FP128"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwFP128))) {
result = LLVMTypeID::FP128TyID;
return mlir::success();
}
if (mlir::succeeded(matchString(ptr, "PPC_FP128"))) {
if (mlir::succeeded(matchString(ptr, endPtr, kwPPCFP128))) {
result = LLVMTypeID::PPC_FP128TyID;
return mlir::success();
}
Expand All @@ -196,6 +235,9 @@ fir::KindMapping::KindMapping(mlir::MLIRContext *context,
llvm::ArrayRef<KindTy> defs)
: KindMapping{context, clKindMapping, defs} {}

fir::KindMapping::KindMapping(mlir::MLIRContext *context)
: KindMapping{context, clKindMapping, clDefaultKinds} {}

MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) {
auto unknown = mlir::UnknownLoc::get(context);
mlir::emitError(unknown, ptr);
Expand All @@ -206,28 +248,29 @@ MatchResult fir::KindMapping::parse(llvm::StringRef kindMap) {
if (kindMap.empty())
return mlir::success();
const char *srcPtr = kindMap.begin();
const char *endPtr = kindMap.end();
while (true) {
char code = '\0';
KindTy kind = 0;
if (parseCode(code, srcPtr) || parseInt(kind, srcPtr))
if (parseCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))
return badMapString(srcPtr);
if (code == 'a' || code == 'i' || code == 'l') {
Bitsize bits = 0;
if (parseColon(srcPtr) || parseInt(bits, srcPtr))
if (parseColon(srcPtr, endPtr) || parseInt(bits, srcPtr, endPtr))
return badMapString(srcPtr);
intMap[std::pair<char, KindTy>{code, kind}] = bits;
} else if (code == 'r' || code == 'c') {
LLVMTypeID id{};
if (parseColon(srcPtr) || parseTypeID(id, srcPtr))
if (parseColon(srcPtr, endPtr) || parseTypeID(id, srcPtr, endPtr))
return badMapString(srcPtr);
floatMap[std::pair<char, KindTy>{code, kind}] = id;
} else {
return badMapString(srcPtr);
}
if (parseComma(srcPtr))
if (parseComma(srcPtr, endPtr))
break;
}
if (*srcPtr)
if (srcPtr > endPtr)
return badMapString(srcPtr);
return mlir::success();
}
Expand Down Expand Up @@ -263,6 +306,51 @@ fir::KindMapping::getFloatSemantics(KindTy kind) const {
return getFloatSemanticsOfKind<'r'>(kind, floatMap);
}

std::string fir::KindMapping::mapToString() const {
std::string result;
bool addComma = false;
for (auto [k, v] : intMap) {
if (addComma)
result.append(",");
else
addComma = true;
result += k.first + std::to_string(k.second) + ":" + std::to_string(v);
}
for (auto [k, v] : floatMap) {
if (addComma)
result.append(",");
else
addComma = true;
result.append(k.first + std::to_string(k.second) + ":");
switch (v) {
default:
llvm_unreachable("unhandled type-id");
case LLVMTypeID::HalfTyID:
result.append(kwHalf);
break;
case LLVMTypeID::BFloatTyID:
result.append(kwBFloat);
break;
case LLVMTypeID::FloatTyID:
result.append(kwFloat);
break;
case LLVMTypeID::DoubleTyID:
result.append(kwDouble);
break;
case LLVMTypeID::X86_FP80TyID:
result.append(kwX86FP80);
break;
case LLVMTypeID::FP128TyID:
result.append(kwFP128);
break;
case LLVMTypeID::PPC_FP128TyID:
result.append(kwPPCFP128);
break;
}
}
return result;
}

mlir::LogicalResult
fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {
if (defs.empty()) {
Expand All @@ -289,6 +377,52 @@ fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {
return mlir::success();
}

std::string fir::KindMapping::defaultsToString() const {
return std::string("a") + std::to_string(defaultMap.find('a')->second) +
std::string("c") + std::to_string(defaultMap.find('c')->second) +
std::string("d") + std::to_string(defaultMap.find('d')->second) +
std::string("i") + std::to_string(defaultMap.find('i')->second) +
std::string("l") + std::to_string(defaultMap.find('l')->second) +
std::string("r") + std::to_string(defaultMap.find('r')->second);
}

/// Convert a default intrinsic code into the proper position in the array. The
/// default kinds have a precise ordering.
static int codeToIndex(char code) {
switch (code) {
case 'a':
return 0;
case 'c':
return 1;
case 'd':
return 2;
case 'i':
return 3;
case 'l':
return 4;
case 'r':
return 5;
}
llvm_unreachable("invalid default kind intrinsic code");
}

std::vector<KindTy> fir::KindMapping::toDefaultKinds(llvm::StringRef defs) {
std::vector<KindTy> result(6);
char code;
KindTy kind;
if (defs.empty())
defs = clDefaultKinds;
const char *srcPtr = defs.begin();
const char *endPtr = defs.end();
while (srcPtr < endPtr) {
if (parseDefCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))
llvm::report_fatal_error("invalid default kind code");
result[codeToIndex(code)] = kind;
}
assert(srcPtr == endPtr);
return result;
}

KindTy fir::KindMapping::defaultCharacterKind() const {
auto iter = defaultMap.find('a');
assert(iter != defaultMap.end());
Expand Down
1 change: 1 addition & 0 deletions flang/unittests/Optimizer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set(LIBS
)

add_flang_unittest(FlangOptimizerTests
FIRContextTest.cpp
InternalNamesTest.cpp
KindMappingTest.cpp
)
Expand Down
57 changes: 57 additions & 0 deletions flang/unittests/Optimizer/FIRContextTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===- FIRContextTest.cpp -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "flang/Optimizer/Support/FIRContext.h"
#include "flang/Optimizer/Support/KindMapping.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
#include "llvm/Support/Host.h"
#include "gtest/gtest.h"
#include <string>

using namespace fir;

struct StringAttributesTests : public testing::Test {
public:
void SetUp() {
kindMap = new KindMapping(&context, kindMapInit, "r42a10c14d28i40l41");
mod = mlir::ModuleOp::create(mlir::UnknownLoc::get(&context));
}

void TearDown() { delete kindMap; }

mlir::MLIRContext context;
KindMapping *kindMap{};
std::string kindMapInit =
"i10:80,l3:24,a1:8,r54:Double,r62:X86_FP80,r11:PPC_FP128";
std::string target = "powerpc64le-unknown-linux-gnu";
mlir::ModuleOp mod;
};

TEST_F(StringAttributesTests, moduleStringAttrTest) {
setTargetTriple(mod, target);
setKindMapping(mod, *kindMap);

auto triple = getTargetTriple(mod);
EXPECT_EQ(triple.getArch(), llvm::Triple::ArchType::ppc64le);
EXPECT_EQ(triple.getOS(), llvm::Triple::OSType::Linux);

auto map = getKindMapping(mod);
EXPECT_EQ(map.defaultsToString(), "a10c14d28i40l41r42");

auto mapStr = map.mapToString();
EXPECT_EQ(mapStr.size(), kindMapInit.size());
EXPECT_TRUE(mapStr.find("a1:8") != std::string::npos);
EXPECT_TRUE(mapStr.find("l3:24") != std::string::npos);
EXPECT_TRUE(mapStr.find("i10:80") != std::string::npos);
EXPECT_TRUE(mapStr.find("r11:PPC_FP128") != std::string::npos);
EXPECT_TRUE(mapStr.find("r54:Double") != std::string::npos);
EXPECT_TRUE(mapStr.find("r62:X86_FP80") != std::string::npos);
}

// main() from gtest_main
78 changes: 36 additions & 42 deletions flang/unittests/Optimizer/InternalNamesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,128 +47,123 @@ void validateDeconstructedName(
}

TEST(InternalNamesTest, doBlockDataTest) {
NameUniquer obj;
std::string actual = obj.doBlockData("blockdatatest");
std::string actualBlank = obj.doBlockData("");
std::string actual = NameUniquer::doBlockData("blockdatatest");
std::string actualBlank = NameUniquer::doBlockData("");
std::string expectedMangledName = "_QLblockdatatest";
std::string expectedMangledNameBlank = "_QL";
ASSERT_EQ(actual, expectedMangledName);
ASSERT_EQ(actualBlank, expectedMangledNameBlank);
}

TEST(InternalNamesTest, doCommonBlockTest) {
NameUniquer obj;
std::string actual = obj.doCommonBlock("hello");
std::string actualBlank = obj.doCommonBlock("");
std::string actual = NameUniquer::doCommonBlock("hello");
std::string actualBlank = NameUniquer::doCommonBlock("");
std::string expectedMangledName = "_QBhello";
std::string expectedMangledNameBlank = "_QB";
ASSERT_EQ(actual, expectedMangledName);
ASSERT_EQ(actualBlank, expectedMangledNameBlank);
}

TEST(InternalNamesTest, doGeneratedTest) {
NameUniquer obj;
std::string actual = obj.doGenerated("@MAIN");
std::string actual = NameUniquer::doGenerated("@MAIN");
std::string expectedMangledName = "_QQ@MAIN";
ASSERT_EQ(actual, expectedMangledName);

std::string actual1 = obj.doGenerated("@_ZNSt8ios_base4InitC1Ev");
std::string actual1 = NameUniquer::doGenerated("@_ZNSt8ios_base4InitC1Ev");
std::string expectedMangledName1 = "_QQ@_ZNSt8ios_base4InitC1Ev";
ASSERT_EQ(actual1, expectedMangledName1);

std::string actual2 = obj.doGenerated("_QQ@MAIN");
std::string actual2 = NameUniquer::doGenerated("_QQ@MAIN");
std::string expectedMangledName2 = "_QQ_QQ@MAIN";
ASSERT_EQ(actual2, expectedMangledName2);
}

TEST(InternalNamesTest, doConstantTest) {
NameUniquer obj;
std::string actual = obj.doConstant({"mod1", "mod2"}, {"foo"}, "Hello");
std::string actual =
NameUniquer::doConstant({"mod1", "mod2"}, {"foo"}, "Hello");
std::string expectedMangledName = "_QMmod1Smod2FfooEChello";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doProcedureTest) {
NameUniquer obj;
std::string actual = obj.doProcedure({"mod1", "mod2"}, {}, "HeLLo");
std::string actual = NameUniquer::doProcedure({"mod1", "mod2"}, {}, "HeLLo");
std::string expectedMangledName = "_QMmod1Smod2Phello";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doTypeTest) {
NameUniquer obj;
std::string actual = obj.doType({}, {}, "mytype", {4, -1});
std::string actual = NameUniquer::doType({}, {}, "mytype", {4, -1});
std::string expectedMangledName = "_QTmytypeK4KN1";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doIntrinsicTypeDescriptorTest) {
using IntrinsicType = fir::NameUniquer::IntrinsicType;
NameUniquer obj;
std::string actual =
obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, 42);
NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, 42);
std::string expectedMangledName = "_QCrealK42";
ASSERT_EQ(actual, expectedMangledName);

actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, {});
actual =
NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::REAL, {});
expectedMangledName = "_QCrealK0";
ASSERT_EQ(actual, expectedMangledName);

actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::INTEGER, 3);
actual =
NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::INTEGER, 3);
expectedMangledName = "_QCintegerK3";
ASSERT_EQ(actual, expectedMangledName);

actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::LOGICAL, 2);
actual =
NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::LOGICAL, 2);
expectedMangledName = "_QClogicalK2";
ASSERT_EQ(actual, expectedMangledName);

actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::CHARACTER, 4);
actual = NameUniquer::doIntrinsicTypeDescriptor(
{}, {}, IntrinsicType::CHARACTER, 4);
expectedMangledName = "_QCcharacterK4";
ASSERT_EQ(actual, expectedMangledName);

actual = obj.doIntrinsicTypeDescriptor({}, {}, IntrinsicType::COMPLEX, 4);
actual =
NameUniquer::doIntrinsicTypeDescriptor({}, {}, IntrinsicType::COMPLEX, 4);
expectedMangledName = "_QCcomplexK4";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doDispatchTableTest) {
NameUniquer obj;
std::string actual = obj.doDispatchTable({}, {}, "MyTYPE", {2, 8, 18});
std::string actual =
NameUniquer::doDispatchTable({}, {}, "MyTYPE", {2, 8, 18});
std::string expectedMangledName = "_QDTmytypeK2K8K18";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doTypeDescriptorTest) {
NameUniquer obj;
std::string actual = obj.doTypeDescriptor(
std::string actual = NameUniquer::doTypeDescriptor(
{StringRef("moD1")}, {StringRef("foo")}, "MyTYPE", {2, 8});
std::string expectedMangledName = "_QMmod1FfooCTmytypeK2K8";
ASSERT_EQ(actual, expectedMangledName);
}

TEST(InternalNamesTest, doVariableTest) {
NameUniquer obj;
std::string actual = obj.doVariable(
std::string actual = NameUniquer::doVariable(
{"mod1", "mod2"}, {""}, "intvar"); // Function is present and is blank.
std::string expectedMangledName = "_QMmod1Smod2FEintvar";
ASSERT_EQ(actual, expectedMangledName);

std::string actual2 = obj.doVariable(
std::string actual2 = NameUniquer::doVariable(
{"mod1", "mod2"}, {}, "intVariable"); // Function is not present.
std::string expectedMangledName2 = "_QMmod1Smod2Eintvariable";
ASSERT_EQ(actual2, expectedMangledName2);
}

TEST(InternalNamesTest, doProgramEntry) {
NameUniquer obj;
llvm::StringRef actual = obj.doProgramEntry();
llvm::StringRef actual = NameUniquer::doProgramEntry();
std::string expectedMangledName = "_QQmain";
ASSERT_EQ(actual.str(), expectedMangledName);
}

TEST(InternalNamesTest, deconstructTest) {
NameUniquer obj;
std::pair actual = obj.deconstruct("_QBhello");
std::pair actual = NameUniquer::deconstruct("_QBhello");
auto expectedNameKind = NameUniquer::NameKind::COMMON;
struct DeconstructedName expectedComponents {
{}, {}, "hello", {}
Expand All @@ -178,39 +173,38 @@ TEST(InternalNamesTest, deconstructTest) {

TEST(InternalNamesTest, complexdeconstructTest) {
using NameKind = fir::NameUniquer::NameKind;
NameUniquer obj;
std::pair actual = obj.deconstruct("_QMmodSs1modSs2modFsubPfun");
std::pair actual = NameUniquer::deconstruct("_QMmodSs1modSs2modFsubPfun");
auto expectedNameKind = NameKind::PROCEDURE;
struct DeconstructedName expectedComponents = {
{"mod", "s1mod", "s2mod"}, {"sub"}, "fun", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QPsub");
actual = NameUniquer::deconstruct("_QPsub");
expectedNameKind = NameKind::PROCEDURE;
expectedComponents = {{}, {}, "sub", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QBvariables");
actual = NameUniquer::deconstruct("_QBvariables");
expectedNameKind = NameKind::COMMON;
expectedComponents = {{}, {}, "variables", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QMmodEintvar");
actual = NameUniquer::deconstruct("_QMmodEintvar");
expectedNameKind = NameKind::VARIABLE;
expectedComponents = {{"mod"}, {}, "intvar", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QMmodECpi");
actual = NameUniquer::deconstruct("_QMmodECpi");
expectedNameKind = NameKind::CONSTANT;
expectedComponents = {{"mod"}, {}, "pi", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QTyourtypeK4KN6");
actual = NameUniquer::deconstruct("_QTyourtypeK4KN6");
expectedNameKind = NameKind::DERIVED_TYPE;
expectedComponents = {{}, {}, "yourtype", {4, -6}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);

actual = obj.deconstruct("_QDTt");
actual = NameUniquer::deconstruct("_QDTt");
expectedNameKind = NameKind::DISPATCH_TABLE;
expectedComponents = {{}, {}, "t", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);
Expand Down
26 changes: 13 additions & 13 deletions flang/unittests/Optimizer/KindMappingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,19 @@ TEST(KindMappingDeathTests, mapTest) {
}

TEST_F(KindDefaultsTests, getIntegerBitsizeTest) {
EXPECT_EQ(defaultDefaultKinds->defaultCharacterKind(), 1u);
EXPECT_EQ(defaultDefaultKinds->defaultComplexKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultDoubleKind(), 8u);
EXPECT_EQ(defaultDefaultKinds->defaultIntegerKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultLogicalKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultRealKind(), 4u);

EXPECT_EQ(overrideDefaultKinds->defaultCharacterKind(), 20u);
EXPECT_EQ(overrideDefaultKinds->defaultComplexKind(), 121u);
EXPECT_EQ(overrideDefaultKinds->defaultDoubleKind(), 32u);
EXPECT_EQ(overrideDefaultKinds->defaultIntegerKind(), 133u);
EXPECT_EQ(overrideDefaultKinds->defaultLogicalKind(), 44u);
EXPECT_EQ(overrideDefaultKinds->defaultRealKind(), 145u);
EXPECT_EQ(defaultDefaultKinds->defaultCharacterKind(), 1u);
EXPECT_EQ(defaultDefaultKinds->defaultComplexKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultDoubleKind(), 8u);
EXPECT_EQ(defaultDefaultKinds->defaultIntegerKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultLogicalKind(), 4u);
EXPECT_EQ(defaultDefaultKinds->defaultRealKind(), 4u);

EXPECT_EQ(overrideDefaultKinds->defaultCharacterKind(), 20u);
EXPECT_EQ(overrideDefaultKinds->defaultComplexKind(), 121u);
EXPECT_EQ(overrideDefaultKinds->defaultDoubleKind(), 32u);
EXPECT_EQ(overrideDefaultKinds->defaultIntegerKind(), 133u);
EXPECT_EQ(overrideDefaultKinds->defaultLogicalKind(), 44u);
EXPECT_EQ(overrideDefaultKinds->defaultRealKind(), 145u);
}

// main() from gtest_main
6 changes: 5 additions & 1 deletion libcxx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ option(LIBCXX_ENABLE_SHARED "Build libc++ as a shared library." ON)
option(LIBCXX_ENABLE_STATIC "Build libc++ as a static library." ON)
option(LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY "Build libc++experimental.a" ON)
set(ENABLE_FILESYSTEM_DEFAULT ON)
if (WIN32)
if (WIN32 AND NOT MINGW)
# Filesystem is buildable for windows, but it requires __int128 helper
# functions, that currently are provided by libgcc or compiler_rt builtins.
# These are available in MinGW environments, but not currently in MSVC
# environments.
set(ENABLE_FILESYSTEM_DEFAULT OFF)
endif()
option(LIBCXX_ENABLE_FILESYSTEM "Build filesystem as part of the main libc++ library"
Expand Down
4 changes: 2 additions & 2 deletions libcxx/docs/Cxx1zStatusIssuesStatus.csv
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@
"`2699 <https://wg21.link/LWG2699>`__","Missing restriction in [numeric.requirements]","Issaquah","|Complete|",""
"`2712 <https://wg21.link/LWG2712>`__","copy_file(from, to, ...) has a number of unspecified error conditions","Issaquah","|Complete|",""
"`2722 <https://wg21.link/LWG2722>`__","equivalent incorrectly specifies throws clause","Issaquah","|Complete|",""
"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","",""
"`2729 <https://wg21.link/LWG2729>`__","Missing SFINAE on std::pair::operator=","Issaquah","|Complete|",""
"`2732 <https://wg21.link/LWG2732>`__","Questionable specification of path::operator/= and path::append","Issaquah","|Complete|",""
"`2733 <https://wg21.link/LWG2733>`__","[fund.ts.v2] gcd / lcm and bool","Issaquah","|Complete|",""
"`2735 <https://wg21.link/LWG2735>`__","std::abs(short), std::abs(signed char) and others should return int instead of double in order to be compatible with C++98 and C","Issaquah","|Complete|",""
Expand Down Expand Up @@ -300,7 +300,7 @@
"`2872 <https://wg21.link/LWG2872>`__","Add definition for direct-non-list-initialization","Kona","|Complete|",""
"`2873 <https://wg21.link/LWG2873>`__","Add noexcept to several shared_ptr related functions","Kona","|Complete|",""
"`2874 <https://wg21.link/LWG2874>`__","Constructor ``shared_ptr::shared_ptr(Y*)``\ should be constrained","Kona","",""
"`2875 <https://wg21.link/LWG2875>`__","shared_ptr::shared_ptr(Y\*, D, [|hellip|\ ]) constructors should be constrained","Kona","",""
"`2875 <https://wg21.link/LWG2875>`__","shared_ptr::shared_ptr(Y\*, D, [|hellip|\ ]) constructors should be constrained","Kona","|Complete|",""
"`2876 <https://wg21.link/LWG2876>`__","``shared_ptr::shared_ptr(const weak_ptr<Y>&)``\ constructor should be constrained","Kona","",""
"`2878 <https://wg21.link/LWG2878>`__","Missing DefaultConstructible requirement for istream_iterator default constructor","Kona","|Complete|",""
"`2890 <https://wg21.link/LWG2890>`__","The definition of 'object state' applies only to class types","Kona","|Complete|",""
Expand Down
8 changes: 4 additions & 4 deletions libcxx/include/__config
Original file line number Diff line number Diff line change
Expand Up @@ -536,10 +536,6 @@ typedef __char32_t char32_t;
#define _LIBCPP_HAS_NO_VARIABLE_TEMPLATES
#endif

#if !defined(__cpp_concepts) || __cpp_concepts < 201907L
#define _LIBCPP_HAS_NO_CONCEPTS
#endif

#if !defined(_LIBCPP_HAS_NO_ASAN) && !defined(__SANITIZE_ADDRESS__)
#define _LIBCPP_HAS_NO_ASAN
#endif
Expand Down Expand Up @@ -836,6 +832,10 @@ typedef unsigned int char32_t;
# define _LIBCPP_CONSTEVAL consteval
#endif

#if !defined(__cpp_concepts) || __cpp_concepts < 201907L
#define _LIBCPP_HAS_NO_CONCEPTS
#endif

#ifdef _LIBCPP_CXX03_LANG
# define _LIBCPP_DEFAULT {}
#else
Expand Down
22 changes: 19 additions & 3 deletions libcxx/include/filesystem
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,12 @@ public:
#if defined(_LIBCPP_WIN32API)
_LIBCPP_INLINE_VISIBILITY _VSTD::wstring wstring() const { return __pn_; }

_VSTD::wstring generic_wstring() const { return __pn_; }
_VSTD::wstring generic_wstring() const {
_VSTD::wstring __s;
__s.resize(__pn_.size());
_VSTD::replace_copy(__pn_.begin(), __pn_.end(), __s.begin(), '\\', '/');
return __s;
}

#if !defined(_LIBCPP_HAS_NO_LOCALIZATION)
template <class _ECharT, class _Traits = char_traits<_ECharT>,
Expand Down Expand Up @@ -1230,13 +1235,24 @@ public:
class _Allocator = allocator<_ECharT> >
basic_string<_ECharT, _Traits, _Allocator>
generic_string(const _Allocator& __a = _Allocator()) const {
return string<_ECharT, _Traits, _Allocator>(__a);
using _Str = basic_string<_ECharT, _Traits, _Allocator>;
_Str __s = string<_ECharT, _Traits, _Allocator>(__a);
// Note: This (and generic_u8string below) is slightly suboptimal as
// it iterates twice over the string; once to convert it to the right
// character type, and once to replace path delimiters.
_VSTD::replace(__s.begin(), __s.end(),
static_cast<_ECharT>('\\'), static_cast<_ECharT>('/'));
return __s;
}

_VSTD::string generic_string() const { return generic_string<char>(); }
_VSTD::u16string generic_u16string() const { return generic_string<char16_t>(); }
_VSTD::u32string generic_u32string() const { return generic_string<char32_t>(); }
__u8_string generic_u8string() const { return u8string(); }
__u8_string generic_u8string() const {
__u8_string __s = u8string();
_VSTD::replace(__s.begin(), __s.end(), '\\', '/');
return __s;
}
#endif /* !_LIBCPP_HAS_NO_LOCALIZATION */
#else /* _LIBCPP_WIN32API */

Expand Down
26 changes: 22 additions & 4 deletions libcxx/include/memory
Original file line number Diff line number Diff line change
Expand Up @@ -2620,6 +2620,24 @@ struct __compatible_with
: is_convertible<_Tp*, _Up*> {};
#endif // _LIBCPP_STD_VER > 14

template <class _Dp, class _Pt,
class = decltype(_VSTD::declval<_Dp>()(_VSTD::declval<_Pt>()))>
static true_type __well_formed_deleter_test(int);

template <class, class>
static false_type __well_formed_deleter_test(...);

template <class _Dp, class _Pt>
struct __well_formed_deleter : decltype(__well_formed_deleter_test<_Dp, _Pt>(0)) {};

template<class _Dp, class _Tp, class _Yp>
struct __shared_ptr_deleter_ctor_reqs
{
static const bool value = __compatible_with<_Tp, _Yp>::value &&
is_move_constructible<_Dp>::value &&
__well_formed_deleter<_Dp, _Tp*>::value;
};

#if defined(_LIBCPP_ABI_ENABLE_SHARED_PTR_TRIVIAL_ABI)
# define _LIBCPP_SHARED_PTR_TRIVIAL_ABI __attribute__((trivial_abi))
#else
Expand Down Expand Up @@ -2652,10 +2670,10 @@ public:
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
template<class _Yp, class _Dp>
shared_ptr(_Yp* __p, _Dp __d,
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type = __nat());
template<class _Yp, class _Dp, class _Alloc>
shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type = __nat());
typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type = __nat());
template <class _Dp> shared_ptr(nullptr_t __p, _Dp __d);
template <class _Dp, class _Alloc> shared_ptr(nullptr_t __p, _Dp __d, _Alloc __a);
template<class _Yp> _LIBCPP_INLINE_VISIBILITY shared_ptr(const shared_ptr<_Yp>& __r, element_type* __p) _NOEXCEPT;
Expand Down Expand Up @@ -2921,7 +2939,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p,
template<class _Tp>
template<class _Yp, class _Dp>
shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d,
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type)
typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type)
: __ptr_(__p)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
Expand Down Expand Up @@ -2975,7 +2993,7 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t __p, _Dp __d)
template<class _Tp>
template<class _Yp, class _Dp, class _Alloc>
shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
typename enable_if<__compatible_with<_Yp, element_type>::value, __nat>::type)
typename enable_if<__shared_ptr_deleter_ctor_reqs<_Dp, _Yp, element_type>::value, __nat>::type)
: __ptr_(__p)
{
#ifndef _LIBCPP_NO_EXCEPTIONS
Expand Down
14 changes: 8 additions & 6 deletions libcxx/src/filesystem/operations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct PathParser {
}
_LIBCPP_FALLTHROUGH();
case PS_InRootName: {
PosPtr TkEnd = consumeSeparator(Start, End);
PosPtr TkEnd = consumeAllSeparators(Start, End);
if (TkEnd)
return makeState(PS_InRootDir, Start, TkEnd);
else
Expand All @@ -140,7 +140,7 @@ struct PathParser {
return makeState(PS_InFilenames, Start, consumeName(Start, End));

case PS_InFilenames: {
PosPtr SepEnd = consumeSeparator(Start, End);
PosPtr SepEnd = consumeAllSeparators(Start, End);
if (SepEnd != End) {
PosPtr TkEnd = consumeName(SepEnd, End);
if (TkEnd)
Expand All @@ -166,7 +166,7 @@ struct PathParser {
switch (State) {
case PS_AtEnd: {
// Try to consume a trailing separator or root directory first.
if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) {
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
PosPtr TkStart = consumeRootName(SepEnd, REnd);
Expand All @@ -185,7 +185,7 @@ struct PathParser {
return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
RStart + 1);
case PS_InFilenames: {
PosPtr SepEnd = consumeSeparator(RStart, REnd);
PosPtr SepEnd = consumeAllSeparators(RStart, REnd);
if (SepEnd == REnd)
return makeState(PS_InRootDir, Path.data(), RStart + 1);
PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd);
Expand Down Expand Up @@ -304,7 +304,8 @@ struct PathParser {
_LIBCPP_UNREACHABLE();
}

PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
// Consume all consecutive separators.
PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept {
if (P == nullptr || P == End || !isSeparator(*P))
return nullptr;
const int Inc = P < End ? 1 : -1;
Expand All @@ -316,7 +317,7 @@ struct PathParser {

// Consume exactly N separators, or return nullptr.
PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept {
PosPtr Ret = consumeSeparator(P, End);
PosPtr Ret = consumeAllSeparators(P, End);
if (Ret == nullptr)
return nullptr;
if (P < End) {
Expand Down Expand Up @@ -1717,6 +1718,7 @@ path path::lexically_normal() const {
if (NeedTrailingSep)
Result /= PS("");

Result.make_preferred();
return Result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,9 @@ int main(int, char**) {
SPtr<2> s2(getFn<2>(), Deleter{}); // OK
SPtr<3> s3(nullptr, Deleter{}); // OK
}
// expected-error-re@memory:* 2 {{static_assert failed{{.*}} "default_delete cannot be instantiated for function types"}}
{
SPtr<4> s4(getFn<4>()); // expected-note {{requested here}}
SPtr<5> s5(getFn<5>(), std::default_delete<FnType<5>>{}); // expected-note {{requested here}}
}

// expected-error-re@memory:* {{static_assert failed{{.*}} "default_delete cannot be instantiated for function types"}}
std::default_delete<FnType<5>> deleter{}; // expected-note {{requested here}}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,24 @@
#include "min_allocator.h"
#include "filesystem_test_helper.h"

MultiStringType longString = MKSTR("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/123456789/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
MultiStringType input = MKSTR("c:\\foo\\bar");
#ifdef _WIN32
// On windows, the generic_* accessors return a path with forward slashes
MultiStringType ref = MKSTR("c:/foo/bar");
#else
// On posix, the input string is returned as-is
MultiStringType ref = MKSTR("c:\\foo\\bar");
#endif

int main(int, char**)
{
using namespace fs;
auto const& MS = longString;
const char* value = longString;
auto const& MS = ref;
const char* value = input;
const path p(value);
{
std::string s = p.generic_string();
assert(s == value);
assert(s == (const char*)MS);
}
{
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ TEST_CASE(test_error_reporting) {
scoped_test_env env;
const path file = env.create_file("file1", 42);
const path file2 = env.create_file("file2", 55);
const path non_regular_file = env.create_fifo("non_reg");
const path dne = env.make_env_path("dne");

{ // exists(to) && equivalent(to, from)
std::error_code ec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: no-exceptions

// This test requires the dylib support introduced in D92214.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: no-exceptions

// This test requires the dylib support introduced in D92214.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ struct A

int A::count = 0;

struct bad_ty { };

struct bad_deleter
{
void operator()(bad_ty) { }
};

struct no_move_deleter
{
no_move_deleter(no_move_deleter const&) = delete;
no_move_deleter(no_move_deleter &&) = delete;
void operator()(int*) { }
};

static_assert(!std::is_move_constructible<no_move_deleter>::value, "");

struct Base { };
struct Derived : Base { };

Expand Down Expand Up @@ -65,6 +81,12 @@ int main(int, char**)
assert(test_deleter<A>::dealloc_count == 1);

{
// Make sure we can't construct with:
// a) a deleter that doesn't have an operator ()(int*)
// b) a deleter that doesn't have a move constructor.
static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter>::value, "");
static_assert(!std::is_constructible<std::shared_ptr<int>, int*, no_move_deleter>::value, "");

// Make sure that we can construct a shared_ptr where the element type and pointer type
// aren't "convertible" but are "compatible".
static_assert(!std::is_constructible<std::shared_ptr<Derived[4]>, Base[4], test_deleter<Derived[4]> >::value, "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ struct A

int A::count = 0;

struct bad_ty { };

struct bad_deleter
{
void operator()(bad_ty) { }
};

struct no_move_deleter
{
no_move_deleter(no_move_deleter const&) = delete;
no_move_deleter(no_move_deleter &&) = delete;
void operator()(int*) { }
};

static_assert(!std::is_move_constructible<no_move_deleter>::value, "");

struct Base { };
struct Derived : Base { };

Expand Down Expand Up @@ -115,6 +131,14 @@ int main(int, char**)
#endif // TEST_STD_VER >= 11

{
// Make sure we can't construct with:
// a) a deleter that doesn't have an operator ()(int*)
// b) a deleter that doesn't have a move constructor.
static_assert(!std::is_constructible<std::shared_ptr<int>, int*, bad_deleter,
test_allocator<A> >::value, "");
static_assert(!std::is_constructible<std::shared_ptr<int>, int*, no_move_deleter,
test_allocator<A> >::value, "");

// Make sure that we can construct a shared_ptr where the element type and pointer type
// aren't "convertible" but are "compatible".
static_assert(!std::is_constructible<std::shared_ptr<Derived[4]>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include <tuple>
#include <utility>
#include <memory>
#include <cassert>

#include "test_macros.h"
Expand All @@ -32,6 +33,13 @@ int main(int, char**)
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == short('a'));
}
{
// test that the implicitly generated copy assignment operator
// is properly deleted
using T = std::tuple<int, int>;
using P = std::tuple<std::unique_ptr<int>, std::unique_ptr<int>>;
static_assert(!std::is_assignable<T, const P &>::value, "");
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ struct D
explicit D(int i = 0) : B(i) {}
};

struct NonAssignable {
NonAssignable& operator=(NonAssignable const&) = delete;
NonAssignable& operator=(NonAssignable&&) = delete;
};

int main(int, char**)
{
{
Expand Down Expand Up @@ -87,6 +92,12 @@ int main(int, char**)
assert(std::get<0>(t) == 43);
assert(&std::get<0>(t) == &x);
}
{
using T = std::tuple<int, NonAssignable>;
using U = std::tuple<NonAssignable, int>;
static_assert(!std::is_assignable<T, U const&>::value, "");
static_assert(!std::is_assignable<U, T const&>::value, "");
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ struct E {
}
};

struct NonAssignable {
NonAssignable& operator=(NonAssignable const&) = delete;
NonAssignable& operator=(NonAssignable&&) = delete;
};

int main(int, char**)
{
{
Expand Down Expand Up @@ -108,6 +113,12 @@ int main(int, char**)
assert(std::get<0>(t) == 43);
assert(&std::get<0>(t) == &x);
}
{
using T = std::tuple<int, NonAssignable>;
using U = std::tuple<NonAssignable, int>;
static_assert(!std::is_assignable<T, U&&>::value, "");
static_assert(!std::is_assignable<U, T&&>::value, "");
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ struct MoveAssignable {
MoveAssignable& operator=(MoveAssignable&&) = default;
};

struct CopyAssignableInt {
CopyAssignableInt& operator=(int&) { return *this; }
};

int main(int, char**)
{
{
Expand Down Expand Up @@ -89,8 +93,8 @@ int main(int, char**)
static_assert(!std::is_copy_assignable<T>::value, "");
}
{
using T = std::tuple<int, NonAssignable>;
static_assert(!std::is_copy_assignable<T>::value, "");
using T = std::tuple<int, NonAssignable>;
static_assert(!std::is_copy_assignable<T>::value, "");
}
{
using T = std::tuple<int, CopyAssignable>;
Expand All @@ -100,6 +104,21 @@ int main(int, char**)
using T = std::tuple<int, MoveAssignable>;
static_assert(!std::is_copy_assignable<T>::value, "");
}
{
using T = std::tuple<int, int, int>;
using P = std::pair<int, int>;
static_assert(!std::is_assignable<T, P>::value, "");
}
{ // test const requirement
using T = std::tuple<CopyAssignableInt, CopyAssignableInt>;
using P = std::pair<int, int>;
static_assert(!std::is_assignable<T&, P const>::value, "");
}
{
using T = std::tuple<int, MoveAssignable>;
using P = std::pair<int, MoveAssignable>;
static_assert(!std::is_assignable<T&, P&>::value, "");
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ int main(int, char**)

}
{
using T = std::tuple<int, NonAssignable>;
static_assert(!std::is_move_assignable<T>::value, "");
using T = std::tuple<int, NonAssignable>;
static_assert(!std::is_move_assignable<T>::value, "");
}
{
using T = std::tuple<int, MoveAssignable>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ struct D
explicit D(int i) : B(i) {}
};

struct NonMoveAssignable {
NonMoveAssignable& operator=(NonMoveAssignable const&) = default;
NonMoveAssignable& operator=(NonMoveAssignable&&) = delete;
};

int main(int, char**)
{
{
Expand All @@ -48,6 +53,16 @@ int main(int, char**)
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1)->id_ == 3);
}
{
using T = std::tuple<int, NonMoveAssignable>;
using P = std::pair<int, NonMoveAssignable>;
static_assert(!std::is_assignable<T&, P&&>::value, "");
}
{
using T = std::tuple<int, int, int>;
using P = std::pair<int, int>;
static_assert(!std::is_assignable<T&, P&&>::value, "");
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
#include "archetypes.h"
#endif

struct CopyAssignableInt {
CopyAssignableInt& operator=(int&) { return *this; }
};

struct Unrelated {};

TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<int, short> P1;
Expand Down Expand Up @@ -57,6 +63,17 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(p.first == 42);
assert(p.second.value == -42);
}
{ // test const requirement
using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
using P = std::pair<int, int>;
static_assert(!std::is_assignable<T&, P const>::value, "");
}
{
using T = std::pair<int, Unrelated>;
using P = std::pair<Unrelated, int>;
static_assert(!std::is_assignable<T&, P&>::value, "");
static_assert(!std::is_assignable<P&, T&>::value, "");
}
#endif
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ TEST_CONSTEXPR_CXX20 bool test() {
using P = std::pair<int, ConstexprTestTypes::MoveAssignOnly>;
static_assert(!std::is_copy_assignable<P>::value, "");
}
{
using P = std::pair<int, std::unique_ptr<int> >;
static_assert(!std::is_copy_assignable<P>::value, "");
}
{
using P = std::pair<int, Incomplete&>;
static_assert(!std::is_copy_assignable<P>::value, "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ struct CountAssign {
}
};

struct NotAssignable {
NotAssignable& operator=(NotAssignable const&) = delete;
NotAssignable& operator=(NotAssignable&&) = delete;
};

TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<ConstexprTestTypes::MoveOnly, int> P;
Expand Down Expand Up @@ -83,6 +88,11 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(p2.first.moved == 0);
assert(p2.first.copied == 0);
}
{
using T = std::pair<int, NotAssignable>;
using P = std::pair<int, NotAssignable>;
static_assert(!std::is_assignable<T, P&&>::value, "");
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ struct CountAssign {
}
};

struct CopyAssignableInt {
CopyAssignableInt& operator=(int&) { return *this; }
};

TEST_CONSTEXPR_CXX20 bool test() {
{
typedef std::pair<Derived, short> P1;
Expand All @@ -61,6 +65,12 @@ TEST_CONSTEXPR_CXX20 bool test() {
assert(t.second.moved == 0);
assert(t.second.copied == 0);
}
{ // test const requirement
using T = std::pair<CopyAssignableInt, CopyAssignableInt>;
using P = std::pair<int, int>;
static_assert(!std::is_assignable<T, P&&>::value, "");
static_assert(!std::is_assignable<P, T&&>::value, "");
}
return true;
}

Expand Down
19 changes: 1 addition & 18 deletions lld/MachO/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,7 @@ static std::vector<ArchiveMember> getArchiveMembers(MemoryBufferRef mb) {
return v;
}

static InputFile *addFile(StringRef path, bool forceLoadArchive,
bool isBundleLoader = false) {
static InputFile *addFile(StringRef path, bool forceLoadArchive) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
return nullptr;
Expand Down Expand Up @@ -326,16 +325,6 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
case file_magic::bitcode:
newFile = make<BitcodeFile>(mbref);
break;
case file_magic::macho_executable:
case file_magic::macho_bundle:
// We only allow executable and bundle type here if it is used
// as a bundle loader.
if (!isBundleLoader)
error(path + ": unhandled file type");
if (Optional<DylibFile *> dylibFile =
loadDylib(mbref, nullptr, isBundleLoader))
newFile = *dylibFile;
break;
default:
error(path + ": unhandled file type");
}
Expand Down Expand Up @@ -758,11 +747,6 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
config->printEachFile = args.hasArg(OPT_t);
config->printWhyLoad = args.hasArg(OPT_why_load);
config->outputType = getOutputType(args);
if (const opt::Arg *arg = args.getLastArg(OPT_bundle_loader)) {
if (config->outputType != MH_BUNDLE)
error("-bundle_loader can only be used with MachO bundle output");
addFile(arg->getValue(), false, true);
}
config->ltoObjPath = args.getLastArgValue(OPT_object_path_lto);
config->ltoNewPassManager =
args.hasFlag(OPT_no_lto_legacy_pass_manager, OPT_lto_legacy_pass_manager,
Expand Down Expand Up @@ -812,7 +796,6 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
const auto &opt = arg->getOption();
warnIfDeprecatedOption(opt);
warnIfUnimplementedOption(opt);

// TODO: are any of these better handled via filtered() or getLastArg()?
switch (opt.getID()) {
case OPT_INPUT:
Expand Down
3 changes: 1 addition & 2 deletions lld/MachO/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ std::string createResponseFile(const llvm::opt::InputArgList &args);
llvm::Optional<std::string> resolveDylibPath(llvm::StringRef path);

llvm::Optional<DylibFile *> loadDylib(llvm::MemoryBufferRef mbref,
DylibFile *umbrella = nullptr,
bool isBundleLoader = false);
DylibFile *umbrella = nullptr);

llvm::Optional<InputFile *> loadArchiveMember(MemoryBufferRef, uint32_t modTime,
StringRef archiveName,
Expand Down
11 changes: 4 additions & 7 deletions lld/MachO/DriverUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,7 @@ Optional<std::string> macho::resolveDylibPath(StringRef path) {
static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs;

Optional<DylibFile *> macho::loadDylib(MemoryBufferRef mbref,
DylibFile *umbrella,
bool isBundleLoader) {
DylibFile *umbrella) {
StringRef path = mbref.getBufferIdentifier();
DylibFile *&file = loadedDylibs[CachedHashStringRef(path)];
if (file)
Expand All @@ -191,13 +190,11 @@ Optional<DylibFile *> macho::loadDylib(MemoryBufferRef mbref,
": " + toString(result.takeError()));
return {};
}
file = make<DylibFile>(**result, umbrella, isBundleLoader);
file = make<DylibFile>(**result, umbrella);
} else {
assert(magic == file_magic::macho_dynamically_linked_shared_lib ||
magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
magic == file_magic::macho_executable ||
magic == file_magic::macho_bundle);
file = make<DylibFile>(mbref, umbrella, isBundleLoader);
magic == file_magic::macho_dynamically_linked_shared_lib_stub);
file = make<DylibFile>(mbref, umbrella);
}
return file;
}
Expand Down
19 changes: 5 additions & 14 deletions lld/MachO/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,8 @@ void loadReexport(StringRef path, DylibFile *umbrella) {
inputFiles.insert(*reexport);
}

DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
bool isBundleLoader)
: InputFile(DylibKind, mb), refState(RefState::Unreferenced),
isBundleLoader(isBundleLoader) {
assert(!isBundleLoader || !umbrella);
DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella)
: InputFile(DylibKind, mb), refState(RefState::Unreferenced) {
if (umbrella == nullptr)
umbrella = this;

Expand All @@ -622,9 +619,7 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
currentVersion = read32le(&c->dylib.current_version);
compatibilityVersion = read32le(&c->dylib.compatibility_version);
dylibName = reinterpret_cast<const char *>(cmd) + read32le(&c->dylib.name);
} else if (!isBundleLoader) {
// macho_executable and macho_bundle don't have LC_ID_DYLIB,
// so it's OK.
} else {
error("dylib " + toString(this) + " missing LC_ID_DYLIB load command");
return;
}
Expand Down Expand Up @@ -663,12 +658,8 @@ DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
}
}

DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
bool isBundleLoader)
: InputFile(DylibKind, interface), refState(RefState::Unreferenced),
isBundleLoader(isBundleLoader) {
// FIXME: Add test for the missing TBD code path.

DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella)
: InputFile(DylibKind, interface), refState(RefState::Unreferenced) {
if (umbrella == nullptr)
umbrella = this;

Expand Down
14 changes: 3 additions & 11 deletions lld/MachO/InputFiles.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,28 +125,20 @@ class DylibFile : public InputFile {
// the root dylib to ensure symbols in the child library are correctly bound
// to the root. On the other hand, if a dylib is being directly loaded
// (through an -lfoo flag), then `umbrella` should be a nullptr.
explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr,
bool isBundleLoader = false);
explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella = nullptr);

explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
DylibFile *umbrella = nullptr,
bool isBundleLoader = false);
DylibFile *umbrella = nullptr);

static bool classof(const InputFile *f) { return f->kind() == DylibKind; }

StringRef dylibName;
uint32_t compatibilityVersion = 0;
uint32_t currentVersion = 0;
int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
uint64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
RefState refState;
bool reexport = false;
bool forceWeakImport = false;

// An executable can be used as a bundle loader that will load the output
// file being linked, and that contains symbols referenced, but not
// implemented in the bundle. When used like this, it is very similar
// to a Dylib, so we re-used the same class to represent it.
bool isBundleLoader;
};

// .a file
Expand Down
1 change: 1 addition & 0 deletions lld/MachO/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ def grp_bundle : OptionGroup<"bundle">, HelpText<"CREATING A BUNDLE">;
def bundle_loader : Separate<["-"], "bundle_loader">,
MetaVarName<"<executable>">,
HelpText<"Resolve undefined symbols from <executable>">,
Flags<[HelpHidden]>,
Group<grp_bundle>;

def grp_object : OptionGroup<"object">, HelpText<"CREATING AN OBJECT FILE">;
Expand Down
33 changes: 14 additions & 19 deletions lld/MachO/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ struct Binding {
OutputSegment *segment = nullptr;
uint64_t offset = 0;
int64_t addend = 0;
int16_t ordinal = 0;
uint8_t ordinal = 0;
};
} // namespace

Expand Down Expand Up @@ -262,24 +262,18 @@ static void encodeBinding(const Symbol *sym, const OutputSection *osec,
}

// Non-weak bindings need to have their dylib ordinal encoded as well.
static void encodeDylibOrdinal(const DylibSymbol *dysym, Binding *lastBinding,
static void encodeDylibOrdinal(const DylibSymbol *dysym, Binding &lastBinding,
raw_svector_ostream &os) {
using namespace llvm::MachO;
if (lastBinding == nullptr ||
lastBinding->ordinal != dysym->getFile()->ordinal) {
if (dysym->getFile()->ordinal <= 0) {
os << static_cast<uint8_t>(
BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
(dysym->getFile()->ordinal & BIND_IMMEDIATE_MASK));
} else if (dysym->getFile()->ordinal <= BIND_IMMEDIATE_MASK) {
if (lastBinding.ordinal != dysym->getFile()->ordinal) {
if (dysym->getFile()->ordinal <= BIND_IMMEDIATE_MASK) {
os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
dysym->getFile()->ordinal);
} else {
os << static_cast<uint8_t>(BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
encodeULEB128(dysym->getFile()->ordinal, os);
}
if (lastBinding != nullptr)
lastBinding->ordinal = dysym->getFile()->ordinal;
lastBinding.ordinal = dysym->getFile()->ordinal;
}
}

Expand Down Expand Up @@ -315,7 +309,7 @@ void BindingSection::finalizeContents() {
return a.target.getVA() < b.target.getVA();
});
for (const BindingEntry &b : bindings) {
encodeDylibOrdinal(b.dysym, &lastBinding, os);
encodeDylibOrdinal(b.dysym, lastBinding, os);
if (auto *isec = b.target.section.dyn_cast<const InputSection *>()) {
encodeBinding(b.dysym, isec->parent, isec->outSecOff + b.target.offset,
b.addend, /*isWeakBinding=*/false, lastBinding, os);
Expand Down Expand Up @@ -535,7 +529,13 @@ uint32_t LazyBindingSection::encode(const DylibSymbol &sym) {
uint64_t offset = in.lazyPointers->addr - dataSeg->firstSection()->addr +
sym.stubsIndex * WordSize;
encodeULEB128(offset, os);
encodeDylibOrdinal(&sym, nullptr, os);
if (sym.getFile()->ordinal <= MachO::BIND_IMMEDIATE_MASK) {
os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM |
sym.getFile()->ordinal);
} else {
os << static_cast<uint8_t>(MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB);
encodeULEB128(sym.getFile()->ordinal, os);
}

uint8_t flags = MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM;
if (sym.isWeakRef())
Expand Down Expand Up @@ -796,12 +796,7 @@ void SymtabSection::writeTo(uint8_t *buf) const {
nList->n_desc |= defined->isExternalWeakDef() ? MachO::N_WEAK_DEF : 0;
} else if (auto *dysym = dyn_cast<DylibSymbol>(entry.sym)) {
uint16_t n_desc = nList->n_desc;
if (dysym->getFile()->isBundleLoader)
MachO::SET_LIBRARY_ORDINAL(n_desc, MachO::EXECUTABLE_ORDINAL);
else
MachO::SET_LIBRARY_ORDINAL(
n_desc, static_cast<uint8_t>(dysym->getFile()->ordinal));

MachO::SET_LIBRARY_ORDINAL(n_desc, dysym->getFile()->ordinal);
nList->n_type = MachO::N_EXT;
n_desc |= dysym->isWeakRef() ? MachO::N_WEAK_REF : 0;
nList->n_desc = n_desc;
Expand Down
7 changes: 2 additions & 5 deletions lld/MachO/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,20 +497,17 @@ void Writer::createLoadCommands() {

in.header->addLoadCommand(make<LCBuildVersion>(config->platform));

int64_t dylibOrdinal = 1;
uint64_t dylibOrdinal = 1;
for (InputFile *file : inputFiles) {
if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
if (dylibFile->isBundleLoader)
dylibFile->ordinal = MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE;
else
dylibFile->ordinal = dylibOrdinal++;
LoadCommandType lcType =
dylibFile->forceWeakImport || dylibFile->refState == RefState::Weak
? LC_LOAD_WEAK_DYLIB
: LC_LOAD_DYLIB;
in.header->addLoadCommand(make<LCDylib>(lcType, dylibFile->dylibName,
dylibFile->compatibilityVersion,
dylibFile->currentVersion));
dylibFile->ordinal = dylibOrdinal++;

if (dylibFile->reexport)
in.header->addLoadCommand(
Expand Down
52 changes: 0 additions & 52 deletions lld/test/MachO/bundle-loader.s

This file was deleted.

12 changes: 6 additions & 6 deletions lldb/include/lldb/Target/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -781,10 +781,10 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// \param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// \param[in] stop_vote
/// \param[in] report_stop_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// \param[in] run_vote
/// \param[in] report_run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// \param[out] status
Expand All @@ -800,7 +800,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// plan could not be queued.
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut(
bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
bool stop_other_threads, Vote stop_vote, Vote run_vote,
bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote,
uint32_t frame_idx, Status &status,
LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate);

Expand Down Expand Up @@ -830,10 +830,10 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// \param[in] stop_other_threads
/// \b true if we will stop other threads while we single step this one.
///
/// \param[in] stop_vote
/// \param[in] report_stop_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// \param[in] run_vote
/// \param[in] report_run_vote
/// See standard meanings for the stop & run votes in ThreadPlan.h.
///
/// \param[in] frame_idx
Expand Down Expand Up @@ -864,7 +864,7 @@ class Thread : public std::enable_shared_from_this<Thread>,
/// plan could not be queued.
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(
bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
bool stop_other_threads, Vote stop_vote, Vote run_vote,
bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote,
uint32_t frame_idx, Status &status, bool continue_to_next_branch = false);

/// Gets the plan used to step through the code that steps from a function
Expand Down
15 changes: 8 additions & 7 deletions lldb/include/lldb/Target/ThreadPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ namespace lldb_private {
// One other little detail here, sometimes a plan will push another plan onto
// the plan stack to do some part of the first plan's job, and it would be
// convenient to tell that plan how it should respond to ShouldReportStop.
// You can do that by setting the stop_vote in the child plan when you create
// it.
// You can do that by setting the report_stop_vote in the child plan when you
// create it.
//
// Suppressing the initial eStateRunning event:
//
Expand All @@ -275,8 +275,9 @@ namespace lldb_private {
// eVoteNo from ShouldReportStop, to force a running event to be reported
// return eVoteYes, in general though you should return eVoteNoOpinion which
// will allow the ThreadList to figure out the right thing to do. The
// run_vote argument to the constructor works like stop_vote, and is a way for
// a plan to instruct a sub-plan on how to respond to ShouldReportStop.
// report_run_vote argument to the constructor works like report_stop_vote, and
// is a way for a plan to instruct a sub-plan on how to respond to
// ShouldReportStop.

class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
public UserID {
Expand Down Expand Up @@ -472,7 +473,7 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
protected:
// Constructors and Destructors
ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
Vote stop_vote, Vote run_vote);
Vote report_stop_vote, Vote report_run_vote);

// Classes that inherit from ThreadPlan can see and modify these

Expand Down Expand Up @@ -515,8 +516,8 @@ class ThreadPlan : public std::enable_shared_from_this<ThreadPlan>,
Status m_status;
Process &m_process;
lldb::tid_t m_tid;
Vote m_stop_vote;
Vote m_run_vote;
Vote m_report_stop_vote;
Vote m_report_run_vote;
bool m_takes_iteration_count;
bool m_could_not_resolve_hw_bp;
int32_t m_iteration_count = 1;
Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/Target/ThreadPlanStepInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace lldb_private {
class ThreadPlanStepInstruction : public ThreadPlan {
public:
ThreadPlanStepInstruction(Thread &thread, bool step_over, bool stop_others,
Vote stop_vote, Vote run_vote);
Vote report_stop_vote, Vote report_run_vote);

~ThreadPlanStepInstruction() override;

Expand Down
9 changes: 5 additions & 4 deletions lldb/include/lldb/Target/ThreadPlanStepOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace lldb_private {
class ThreadPlanStepOut : public ThreadPlan, public ThreadPlanShouldStopHere {
public:
ThreadPlanStepOut(Thread &thread, SymbolContext *addr_context,
bool first_insn, bool stop_others, Vote stop_vote,
Vote run_vote, uint32_t frame_idx,
bool first_insn, bool stop_others, Vote report_stop_vote,
Vote report_run_vote, uint32_t frame_idx,
LazyBool step_out_avoids_code_without_debug_info,
bool continue_to_next_branch = false,
bool gather_return_value = true);
Expand Down Expand Up @@ -76,8 +76,9 @@ class ThreadPlanStepOut : public ThreadPlan, public ThreadPlanShouldStopHere {

friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOut(
bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
bool stop_others, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
Status &status, LazyBool step_out_avoids_code_without_debug_info);
bool stop_others, Vote report_stop_vote, Vote report_run_vote,
uint32_t frame_idx, Status &status,
LazyBool step_out_avoids_code_without_debug_info);

void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info);
// Need an appropriate marker for the current stack so we can tell step out
Expand Down
8 changes: 4 additions & 4 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3374,14 +3374,14 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) {
should_resume = !m_thread_list.ShouldStop(event_ptr);

if (was_restarted || should_resume || m_resume_requested) {
Vote stop_vote = m_thread_list.ShouldReportStop(event_ptr);
Vote report_stop_vote = m_thread_list.ShouldReportStop(event_ptr);
LLDB_LOGF(log,
"Process::ShouldBroadcastEvent: should_resume: %i state: "
"%s was_restarted: %i stop_vote: %d.",
"%s was_restarted: %i report_stop_vote: %d.",
should_resume, StateAsCString(state), was_restarted,
stop_vote);
report_stop_vote);

switch (stop_vote) {
switch (report_stop_vote) {
case eVoteYes:
return_value = true;
break;
Expand Down
18 changes: 10 additions & 8 deletions lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1306,25 +1306,27 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange(

ThreadPlanSP Thread::QueueThreadPlanForStepOut(
bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
Status &status, LazyBool step_out_avoids_code_without_debug_info) {
bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote,
uint32_t frame_idx, Status &status,
LazyBool step_out_avoids_code_without_debug_info) {
ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut(
*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote,
frame_idx, step_out_avoids_code_without_debug_info));
*this, addr_context, first_insn, stop_other_threads, report_stop_vote,
report_run_vote, frame_idx, step_out_avoids_code_without_debug_info));

status = QueueThreadPlan(thread_plan_sp, abort_other_plans);
return thread_plan_sp;
}

ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop(
bool abort_other_plans, SymbolContext *addr_context, bool first_insn,
bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx,
Status &status, bool continue_to_next_branch) {
bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote,
uint32_t frame_idx, Status &status, bool continue_to_next_branch) {
const bool calculate_return_value =
false; // No need to calculate the return value here.
ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut(
*this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote,
frame_idx, eLazyBoolNo, continue_to_next_branch, calculate_return_value));
*this, addr_context, first_insn, stop_other_threads, report_stop_vote,
report_run_vote, frame_idx, eLazyBoolNo, continue_to_next_branch,
calculate_return_value));

ThreadPlanStepOut *new_plan =
static_cast<ThreadPlanStepOut *>(thread_plan_sp.get());
Expand Down
14 changes: 7 additions & 7 deletions lldb/source/Target/ThreadPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ using namespace lldb_private;

// ThreadPlan constructor
ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread,
Vote stop_vote, Vote run_vote)
Vote report_stop_vote, Vote report_run_vote)
: m_process(*thread.GetProcess().get()), m_tid(thread.GetID()),
m_stop_vote(stop_vote), m_run_vote(run_vote),
m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote),
m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false),
m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(),
m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false),
Expand Down Expand Up @@ -78,25 +78,25 @@ bool ThreadPlan::MischiefManaged() {
Vote ThreadPlan::ShouldReportStop(Event *event_ptr) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));

if (m_stop_vote == eVoteNoOpinion) {
if (m_report_stop_vote == eVoteNoOpinion) {
ThreadPlan *prev_plan = GetPreviousPlan();
if (prev_plan) {
Vote prev_vote = prev_plan->ShouldReportStop(event_ptr);
LLDB_LOG(log, "returning previous thread plan vote: {0}", prev_vote);
return prev_vote;
}
}
LLDB_LOG(log, "Returning vote: {0}", m_stop_vote);
return m_stop_vote;
LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote);
return m_report_stop_vote;
}

Vote ThreadPlan::ShouldReportRun(Event *event_ptr) {
if (m_run_vote == eVoteNoOpinion) {
if (m_report_run_vote == eVoteNoOpinion) {
ThreadPlan *prev_plan = GetPreviousPlan();
if (prev_plan)
return prev_plan->ShouldReportRun(event_ptr);
}
return m_run_vote;
return m_report_run_vote;
}

void ThreadPlan::ClearThreadCache() { m_thread = nullptr; }
Expand Down
28 changes: 14 additions & 14 deletions lldb/source/Target/ThreadPlanBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) {
}

bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
m_stop_vote = eVoteYes;
m_run_vote = eVoteYes;
m_report_stop_vote = eVoteYes;
m_report_run_vote = eVoteYes;

Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));

Expand All @@ -82,8 +82,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
case eStopReasonInvalid:
case eStopReasonNone:
// This
m_run_vote = eVoteNoOpinion;
m_stop_vote = eVoteNo;
m_report_run_vote = eVoteNoOpinion;
m_report_stop_vote = eVoteNo;
return false;

case eStopReasonBreakpoint:
Expand All @@ -106,11 +106,11 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
// with "restarted" so the UI will know to wait and expect the consequent
// "running".
if (stop_info_sp->ShouldNotify(event_ptr)) {
m_stop_vote = eVoteYes;
m_run_vote = eVoteYes;
m_report_stop_vote = eVoteYes;
m_report_run_vote = eVoteYes;
} else {
m_stop_vote = eVoteNo;
m_run_vote = eVoteNo;
m_report_stop_vote = eVoteNo;
m_report_run_vote = eVoteNo;
}
return false;

Expand Down Expand Up @@ -156,9 +156,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
// We're not going to stop, but while we are here, let's figure out
// whether to report this.
if (stop_info_sp->ShouldNotify(event_ptr))
m_stop_vote = eVoteYes;
m_report_stop_vote = eVoteYes;
else
m_stop_vote = eVoteNo;
m_report_stop_vote = eVoteNo;
}
return false;

Expand All @@ -167,8 +167,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) {
}

} else {
m_run_vote = eVoteNoOpinion;
m_stop_vote = eVoteNo;
m_report_run_vote = eVoteNoOpinion;
m_report_stop_vote = eVoteNo;
}

// If there's no explicit reason to stop, then we will continue.
Expand All @@ -185,8 +185,8 @@ bool ThreadPlanBase::DoWillResume(lldb::StateType resume_state,
bool current_plan) {
// Reset these to the default values so we don't set them wrong, then not get
// asked for a while, then return the wrong answer.
m_run_vote = eVoteNoOpinion;
m_stop_vote = eVoteNo;
m_report_run_vote = eVoteNoOpinion;
m_report_stop_vote = eVoteNo;
return true;
}

Expand Down
7 changes: 4 additions & 3 deletions lldb/source/Target/ThreadPlanStepInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ using namespace lldb_private;
ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread,
bool step_over,
bool stop_other_threads,
Vote stop_vote,
Vote run_vote)
Vote report_stop_vote,
Vote report_run_vote)
: ThreadPlan(ThreadPlan::eKindStepInstruction,
"Step over single instruction", thread, stop_vote, run_vote),
"Step over single instruction", thread, report_stop_vote,
report_run_vote),
m_instruction_addr(0), m_stop_other_threads(stop_other_threads),
m_step_over(step_over) {
m_takes_iteration_count = true;
Expand Down
6 changes: 3 additions & 3 deletions lldb/source/Target/ThreadPlanStepOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
// ThreadPlanStepOut: Step out of the current frame
ThreadPlanStepOut::ThreadPlanStepOut(
Thread &thread, SymbolContext *context, bool first_insn, bool stop_others,
Vote stop_vote, Vote run_vote, uint32_t frame_idx,
Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx,
LazyBool step_out_avoids_code_without_debug_info,
bool continue_to_next_branch, bool gather_return_value)
: ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote,
run_vote),
: ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, report_stop_vote,
report_run_vote),
ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS),
m_return_bp_id(LLDB_INVALID_BREAK_ID),
m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others),
Expand Down
15 changes: 15 additions & 0 deletions llvm/docs/CommandGuide/lit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,21 @@ SELECTION OPTIONS
of this option, which is especially useful in environments where the call
to ``lit`` is issued indirectly.

.. option:: --filter-out=REGEXP

Filter out those tests whose name matches the regular expression specified in
``REGEXP``. The environment variable ``LIT_FILTER_OUT`` can be also used in
place of this option, which is especially useful in environments where the
call to ``lit`` is issued indirectly.

.. option:: --xfail=LIST

Treat those tests whose name is in the semicolon separated list ``LIST`` as
``XFAIL``. This can be helpful when one does not want to modify the test
suite. The environment variable ``LIT_XFAIL`` can be also used in place of
this option, which is especially useful in environments where the call to
``lit`` is issued indirectly.

ADDITIONAL OPTIONS
------------------

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -1876,6 +1876,11 @@ class ScalarEvolution {
bool isKnownPredicateViaConstantRanges(ICmpInst::Predicate Pred,
const SCEV *LHS, const SCEV *RHS);

/// Test if the given expression is known to satisfy the condition described
/// by Pred by decomposing a subtraction.
bool isKnownPredicateViaSubIdiom(ICmpInst::Predicate Pred, const SCEV *LHS,
const SCEV *RHS);

/// Try to prove the condition described by "LHS Pred RHS" by ruling out
/// integer overflow.
///
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Analysis/ValueTracking.h
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,8 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
/// poison.
/// Formally, given I = `r = op v1 v2 .. vN`, propagatesPoison returns true
/// if, for all i, r is evaluated to poison or op raises UB if vi = poison.
/// If vi is a vector or an aggregate and r is a single value, any poison
/// element in vi should make r poison or raise UB.
/// To filter out operands that raise UB on poison, you can use
/// getGuaranteedNonPoisonOp.
bool propagatesPoison(const Operator *I);
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/CodeGen/ValueTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,11 @@ namespace llvm {
/// Return a VT for a vector type whose attributes match ourselves
/// with the exception of the element type that is chosen by the caller.
EVT changeVectorElementType(EVT EltVT) const {
if (isSimple() && EltVT.isSimple())
if (isSimple()) {
assert(EltVT.isSimple() &&
"Can't change simple vector VT to have extended element VT");
return getSimpleVT().changeVectorElementType(EltVT.getSimpleVT());
}
return changeExtendedVectorElementType(EltVT);
}

Expand Down
21 changes: 18 additions & 3 deletions llvm/include/llvm/IR/PatternMatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,10 @@ inline bind_ty<UnaryOperator> m_UnOp(UnaryOperator *&I) { return I; }
inline bind_ty<BinaryOperator> m_BinOp(BinaryOperator *&I) { return I; }
/// Match a with overflow intrinsic, capturing it if we match.
inline bind_ty<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) { return I; }
inline bind_ty<const WithOverflowInst>
m_WithOverflowInst(const WithOverflowInst *&I) {
return I;
}

/// Match a Constant, capturing the value if we match.
inline bind_ty<Constant> m_Constant(Constant *&C) { return C; }
Expand Down Expand Up @@ -2314,9 +2318,13 @@ template <int Ind, typename Opnd_t> struct ExtractValue_match {
ExtractValue_match(const Opnd_t &V) : Val(V) {}

template <typename OpTy> bool match(OpTy *V) {
if (auto *I = dyn_cast<ExtractValueInst>(V))
return I->getNumIndices() == 1 && I->getIndices()[0] == Ind &&
Val.match(I->getAggregateOperand());
if (auto *I = dyn_cast<ExtractValueInst>(V)) {
// If Ind is -1, don't inspect indices
if (Ind != -1 &&
!(I->getNumIndices() == 1 && I->getIndices()[0] == (unsigned)Ind))
return false;
return Val.match(I->getAggregateOperand());
}
return false;
}
};
Expand All @@ -2328,6 +2336,13 @@ inline ExtractValue_match<Ind, Val_t> m_ExtractValue(const Val_t &V) {
return ExtractValue_match<Ind, Val_t>(V);
}

/// Match an ExtractValue instruction with any index.
/// For example m_ExtractValue(...)
template <typename Val_t>
inline ExtractValue_match<-1, Val_t> m_ExtractValue(const Val_t &V) {
return ExtractValue_match<-1, Val_t>(V);
}

/// Matcher for a single index InsertValue instruction.
template <int Ind, typename T0, typename T1> struct InsertValue_match {
T0 Op0;
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/Analysis/IVDescriptors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,14 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurKind Kind,
if (RecurrenceType->isFloatingPointTy()) {
if (!isFloatingPointRecurrenceKind(Kind))
return false;
} else {
} else if (RecurrenceType->isIntegerTy()) {
if (!isIntegerRecurrenceKind(Kind))
return false;
if (isArithmeticRecurrenceKind(Kind))
Start = lookThroughAnd(Phi, RecurrenceType, VisitedInsts, CastInsts);
} else {
// Pointer min/max may exist, but it is not supported as a reduction op.
return false;
}

Worklist.push_back(Start);
Expand Down
Loading