54 changes: 44 additions & 10 deletions clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -488,16 +488,21 @@ TEST(CallDescription, NegativeMatchQualifiedNames) {
}

TEST(CallDescription, MatchBuiltins) {
// Test CDM::CLibrary - a flag that allows matching weird builtins.
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{{"memset"}, 3}, false}, {{CDM::CLibrary, {"memset"}, 3}, true}})),
"void foo() {"
" int x;"
" __builtin___memset_chk(&x, 0, sizeof(x),"
" __builtin_object_size(&x, 0));"
"}"));

// Test the matching modes CDM::CLibrary and CDM::CLibraryMaybeHardened,
// which can recognize builtin variants of C library functions.
{
SCOPED_TRACE("hardened variants of functions");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDM::Unspecified, {"memset"}, 3}, false},
{{CDM::CLibrary, {"memset"}, 3}, false},
{{CDM::CLibraryMaybeHardened, {"memset"}, 3}, true}})),
"void foo() {"
" int x;"
" __builtin___memset_chk(&x, 0, sizeof(x),"
" __builtin_object_size(&x, 0));"
"}"));
}
{
SCOPED_TRACE("multiple similar builtins");
EXPECT_TRUE(tooling::runToolOnCode(
Expand All @@ -518,6 +523,35 @@ TEST(CallDescription, MatchBuiltins) {
__builtin_wmemcpy(x, y, sizeof(wchar_t));
})"));
}
{
SCOPED_TRACE("multiple similar builtins with hardened variant");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDM::CLibraryMaybeHardened, {"memcpy"}, 3}, false},
{{CDM::CLibraryMaybeHardened, {"wmemcpy"}, 3}, true}})),
R"(typedef __typeof(sizeof(int)) size_t;
extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
const wchar_t *__restrict __s2,
size_t __n, size_t __ns1);
void foo(wchar_t *x, wchar_t *y) {
__wmemcpy_chk(x, y, sizeof(wchar_t), 1234);
})"));
}
{
SCOPED_TRACE(
"multiple similar builtins with hardened variant reversed order");
EXPECT_TRUE(tooling::runToolOnCode(
std::unique_ptr<FrontendAction>(new CallDescriptionAction<>(
{{{CDM::CLibraryMaybeHardened, {"wmemcpy"}, 3}, true},
{{CDM::CLibraryMaybeHardened, {"memcpy"}, 3}, false}})),
R"(typedef __typeof(sizeof(int)) size_t;
extern wchar_t *__wmemcpy_chk (wchar_t *__restrict __s1,
const wchar_t *__restrict __s2,
size_t __n, size_t __ns1);
void foo(wchar_t *x, wchar_t *y) {
__wmemcpy_chk(x, y, sizeof(wchar_t), 1234);
})"));
}
{
SCOPED_TRACE("lookbehind and lookahead mismatches");
EXPECT_TRUE(tooling::runToolOnCode(
Expand Down
34 changes: 32 additions & 2 deletions clang/utils/TableGen/ClangOptionDocEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,38 @@ void emitOption(const DocumentedOption &Option, const Record *DocInfo,

// Emit the description, if we have one.
const Record *R = Option.Option;
std::string Description =
getRSTStringWithTextFallback(R, "DocBrief", "HelpText");
std::string Description;

// Prefer a program specific help string.
// This is a list of (visibilities, string) pairs.
std::vector<Record *> VisibilitiesHelp =
R->getValueAsListOfDefs("HelpTextsForVariants");
for (Record *VisibilityHelp : VisibilitiesHelp) {
// This is a list of visibilities.
ArrayRef<Init *> Visibilities =
VisibilityHelp->getValueAsListInit("Visibilities")->getValues();

// See if any of the program's visibilities are in the list.
for (StringRef DocInfoMask :
DocInfo->getValueAsListOfStrings("VisibilityMask")) {
for (Init *Visibility : Visibilities) {
if (Visibility->getAsUnquotedString() == DocInfoMask) {
// Use the first one we find.
Description = escapeRST(VisibilityHelp->getValueAsString("Text"));
break;
}
}
if (!Description.empty())
break;
}

if (!Description.empty())
break;
}

// If there's not a program specific string, use the default one.
if (Description.empty())
Description = getRSTStringWithTextFallback(R, "DocBrief", "HelpText");

if (!isa<UnsetInit>(R->getValueInit("Values"))) {
if (!Description.empty() && Description.back() != '.')
Expand Down
30 changes: 30 additions & 0 deletions flang/include/flang/Evaluate/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "flang/Evaluate/type.h"
#include "flang/Parser/message.h"
#include "flang/Semantics/attr.h"
#include "flang/Semantics/scope.h"
#include "flang/Semantics/symbol.h"
#include <array>
#include <optional>
Expand Down Expand Up @@ -1240,6 +1241,35 @@ inline bool HasCUDAAttrs(const Expr<SomeType> &expr) {
return false;
}

/// Check if the expression is a mix of host and device variables that require
/// implicit data transfer.
inline bool HasCUDAImplicitTransfer(const Expr<SomeType> &expr) {
unsigned hostSymbols{0};
unsigned deviceSymbols{0};
for (const Symbol &sym : CollectSymbols(expr)) {
if (const auto *details =
sym.GetUltimate().detailsIf<semantics::ObjectEntityDetails>()) {
if (details->cudaDataAttr()) {
++deviceSymbols;
} else {
if (sym.owner().IsDerivedType()) {
if (const auto *details =
sym.owner()
.GetSymbol()
->GetUltimate()
.detailsIf<semantics::ObjectEntityDetails>()) {
if (details->cudaDataAttr()) {
++deviceSymbols;
}
}
}
++hostSymbols;
}
}
}
return hostSymbols > 0 && deviceSymbols > 0;
}

} // namespace Fortran::evaluate

namespace Fortran::semantics {
Expand Down
8 changes: 1 addition & 7 deletions flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,7 @@ bool valueMayHaveFirAttributes(mlir::Value value,
bool anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr);

/// Unwrap integer constant from an mlir::Value.
inline std::optional<std::int64_t> getIntIfConstant(mlir::Value value) {
if (auto *definingOp = value.getDefiningOp())
if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
return intAttr.getInt();
return {};
}
std::optional<std::int64_t> getIntIfConstant(mlir::Value value);

static constexpr llvm::StringRef getAdaptToByRefAttrName() {
return "adapt.valuebyref";
Expand Down
164 changes: 82 additions & 82 deletions flang/include/flang/Runtime/io-api.h

Large diffs are not rendered by default.

99 changes: 88 additions & 11 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3710,16 +3710,18 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return false;
}

static void genCUDADataTransfer(fir::FirOpBuilder &builder,
mlir::Location loc, bool lhsIsDevice,
hlfir::Entity &lhs, bool rhsIsDevice,
hlfir::Entity &rhs) {
void genCUDADataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
const Fortran::evaluate::Assignment &assign,
hlfir::Entity &lhs, hlfir::Entity &rhs) {
bool lhsIsDevice = Fortran::evaluate::HasCUDAAttrs(assign.lhs);
bool rhsIsDevice = Fortran::evaluate::HasCUDAAttrs(assign.rhs);
if (rhs.isBoxAddressOrValue() || lhs.isBoxAddressOrValue())
TODO(loc, "CUDA data transfler with descriptors");

// device = host
if (lhsIsDevice && !rhsIsDevice) {
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::HostDevice);
// device = host
if (!rhs.isVariable()) {
auto associate = hlfir::genAssociateExpr(
loc, builder, rhs, rhs.getType(), ".cuf_host_tmp");
Expand All @@ -3732,7 +3734,73 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
return;
}
TODO(loc, "Assignement with CUDA Fortran variables");

// host = device
if (!lhsIsDevice && rhsIsDevice) {
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::DeviceHost);
if (!rhs.isVariable()) {
// evaluateRhs loads scalar. Look for the memory reference to be used in
// the transfer.
if (mlir::isa_and_nonnull<fir::LoadOp>(rhs.getDefiningOp())) {
auto loadOp = mlir::dyn_cast<fir::LoadOp>(rhs.getDefiningOp());
builder.create<fir::CUDADataTransferOp>(loc, loadOp.getMemref(), lhs,
transferKindAttr);
return;
}
} else {
builder.create<fir::CUDADataTransferOp>(loc, rhs, lhs,
transferKindAttr);
}
return;
}

if (lhsIsDevice && rhsIsDevice) {
assert(rhs.isVariable() && "CUDA Fortran assignment rhs is not legal");
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::DeviceDevice);
builder.create<fir::CUDADataTransferOp>(loc, rhs, lhs, transferKindAttr);
return;
}
llvm_unreachable("Unhandled CUDA data transfer");
}

llvm::SmallVector<mlir::Value>
genCUDAImplicitDataTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
const Fortran::evaluate::Assignment &assign) {
llvm::SmallVector<mlir::Value> temps;
localSymbols.pushScope();
auto transferKindAttr = fir::CUDADataTransferKindAttr::get(
builder.getContext(), fir::CUDADataTransferKind::DeviceHost);
unsigned nbDeviceResidentObject = 0;
for (const Fortran::semantics::Symbol &sym :
Fortran::evaluate::CollectSymbols(assign.rhs)) {
if (const auto *details =
sym.GetUltimate()
.detailsIf<Fortran::semantics::ObjectEntityDetails>()) {
if (details->cudaDataAttr()) {
if (sym.owner().IsDerivedType() && IsAllocatable(sym.GetUltimate()))
TODO(loc, "Device resident allocatable derived-type component");
// TODO: This should probably being checked in semantic and give a
// proper error.
assert(
nbDeviceResidentObject <= 1 &&
"Only one reference to the device resident object is supported");
auto addr = getSymbolAddress(sym);
hlfir::Entity entity{addr};
auto [temp, cleanup] =
hlfir::createTempFromMold(loc, builder, entity);
auto needCleanup = fir::getIntIfConstant(cleanup);
if (needCleanup && *needCleanup)
temps.push_back(temp);
addSymbol(sym, temp, /*forced=*/true);
builder.create<fir::CUDADataTransferOp>(loc, addr, temp,
transferKindAttr);
++nbDeviceResidentObject;
}
}
}
return temps;
}

void genDataAssignment(
Expand All @@ -3741,8 +3809,13 @@ class FirConverter : public Fortran::lower::AbstractConverter {
mlir::Location loc = getCurrentLocation();
fir::FirOpBuilder &builder = getFirOpBuilder();

bool lhsIsDevice = Fortran::evaluate::HasCUDAAttrs(assign.lhs);
bool rhsIsDevice = Fortran::evaluate::HasCUDAAttrs(assign.rhs);
bool isCUDATransfer = Fortran::evaluate::HasCUDAAttrs(assign.lhs) ||
Fortran::evaluate::HasCUDAAttrs(assign.rhs);
bool hasCUDAImplicitTransfer =
Fortran::evaluate::HasCUDAImplicitTransfer(assign.rhs);
llvm::SmallVector<mlir::Value> implicitTemps;
if (hasCUDAImplicitTransfer)
implicitTemps = genCUDAImplicitDataTransfer(builder, loc, assign);

// Gather some information about the assignment that will impact how it is
// lowered.
Expand Down Expand Up @@ -3800,12 +3873,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
Fortran::lower::StatementContext localStmtCtx;
hlfir::Entity rhs = evaluateRhs(localStmtCtx);
hlfir::Entity lhs = evaluateLhs(localStmtCtx);
if (lhsIsDevice || rhsIsDevice) {
genCUDADataTransfer(builder, loc, lhsIsDevice, lhs, rhsIsDevice, rhs);
} else {
if (isCUDATransfer && !hasCUDAImplicitTransfer)
genCUDADataTransfer(builder, loc, assign, lhs, rhs);
else
builder.create<hlfir::AssignOp>(loc, rhs, lhs,
isWholeAllocatableAssignment,
keepLhsLengthInAllocatableAssignment);
if (hasCUDAImplicitTransfer) {
localSymbols.popScope();
for (mlir::Value temp : implicitTemps)
builder.create<fir::FreeMemOp>(loc, temp);
}
return;
}
Expand Down
21 changes: 2 additions & 19 deletions flang/lib/Optimizer/CodeGen/CodeGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,10 @@ static mlir::Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
mlir::Region::iterator(insertBefore));
}

/// Extract constant from a value if it is a result of one of the
/// ConstantOp operations, otherwise, return std::nullopt.
static std::optional<int64_t> getIfConstantIntValue(mlir::Value val) {
if (!val || !val.dyn_cast<mlir::OpResult>())
return {};

mlir::Operation *defop = val.getDefiningOp();

if (auto constOp = mlir::dyn_cast<mlir::arith::ConstantIntOp>(defop))
return constOp.value();
if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(defop))
if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
return attr.getValue().getSExtValue();

return {};
}

/// Extract constant from a value that must be the result of one of the
/// ConstantOp operations.
static int64_t getConstantIntValue(mlir::Value val) {
if (auto constVal = getIfConstantIntValue(val))
if (auto constVal = fir::getIntIfConstant(val))
return *constVal;
fir::emitFatalError(val.getLoc(), "must be a constant");
}
Expand Down Expand Up @@ -664,7 +647,7 @@ struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
<< " -> " << toTy;

// Do folding for constant inputs.
if (auto constVal = getIfConstantIntValue(op0)) {
if (auto constVal = fir::getIntIfConstant(op0)) {
mlir::Value normVal =
genConstantIndex(loc, toTy, rewriter, *constVal ? 1 : 0);
rewriter.replaceOp(convert, normVal);
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Optimizer/Dialect/FIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3834,6 +3834,18 @@ bool fir::anyFuncArgsHaveAttr(mlir::func::FuncOp func, llvm::StringRef attr) {
return false;
}

std::optional<std::int64_t> fir::getIntIfConstant(mlir::Value value) {
if (auto *definingOp = value.getDefiningOp()) {
if (auto cst = mlir::dyn_cast<mlir::arith::ConstantOp>(definingOp))
if (auto intAttr = cst.getValue().dyn_cast<mlir::IntegerAttr>())
return intAttr.getInt();
if (auto llConstOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(definingOp))
if (auto attr = llConstOp.getValue().dyn_cast<mlir::IntegerAttr>())
return attr.getValue().getSExtValue();
}
return {};
}

mlir::Type fir::applyPathToType(mlir::Type eleTy, mlir::ValueRange path) {
for (auto i = path.begin(), end = path.end(); eleTy && i < end;) {
eleTy = llvm::TypeSwitch<mlir::Type, mlir::Type>(eleTy)
Expand Down
2 changes: 2 additions & 0 deletions flang/runtime/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static void SetEnvironmentDefaults(const EnvironmentDefaultList *envDefaults) {
}
}

RT_OFFLOAD_API_GROUP_BEGIN
Fortran::common::optional<Convert> GetConvertFromString(
const char *x, std::size_t n) {
static const char *keywords[]{
Expand All @@ -68,6 +69,7 @@ Fortran::common::optional<Convert> GetConvertFromString(
return Fortran::common::nullopt;
}
}
RT_OFFLOAD_API_GROUP_END

void ExecutionEnvironment::Configure(int ac, const char *av[],
const char *env[], const EnvironmentDefaultList *envDefaults) {
Expand Down
2 changes: 1 addition & 1 deletion flang/runtime/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RT_OFFLOAD_VAR_GROUP_END
// External unformatted I/O data conversions
enum class Convert { Unknown, Native, LittleEndian, BigEndian, Swap };

Fortran::common::optional<Convert> GetConvertFromString(
RT_API_ATTRS Fortran::common::optional<Convert> GetConvertFromString(
const char *, std::size_t);

struct ExecutionEnvironment {
Expand Down
19 changes: 19 additions & 0 deletions flang/runtime/freestanding-tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
#define STD_STRCPY_UNSUPPORTED 1
#endif

#if !defined(STD_STRCMP_UNSUPPORTED) && \
(defined(__CUDACC__) || defined(__CUDA__)) && defined(__CUDA_ARCH__)
#define STD_STRCMP_UNSUPPORTED 1
#endif

namespace Fortran::runtime {

#if STD_FILL_N_UNSUPPORTED
Expand Down Expand Up @@ -176,5 +181,19 @@ static inline RT_API_ATTRS char *strcpy(char *dest, const char *src) {
using std::strcpy;
#endif // !STD_STRCPY_UNSUPPORTED

#if STD_STRCMP_UNSUPPORTED
// Provides alternative implementation for std::strcmp(), if
// it is not supported.
static inline RT_API_ATTRS int strcmp(const char *lhs, const char *rhs) {
while (*lhs != '\0' && *lhs == *rhs) {
++lhs;
++rhs;
}
return static_cast<unsigned char>(*lhs) - static_cast<unsigned char>(*rhs);
}
#else // !STD_STRCMP_UNSUPPORTED
using std::strcmp;
#endif // !STD_STRCMP_UNSUPPORTED

} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_FREESTANDING_TOOLS_H_
204 changes: 99 additions & 105 deletions flang/runtime/io-api.cpp

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions flang/runtime/io-error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,6 @@ void IoErrorHandler::SignalPendingError() {
SignalError(error);
}

RT_OFFLOAD_API_GROUP_END

void IoErrorHandler::SignalErrno() { SignalError(errno); }

bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) {
Expand All @@ -127,7 +125,10 @@ bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) {
// in LLVM v9.0.1 with inadequate modification for Fortran,
// since rectified.
bool ok{false};
#if HAVE_STRERROR_R
#if defined(RT_DEVICE_COMPILATION)
// strerror_r is not available on device.
msg = "errno description is not available on device";
#elif HAVE_STRERROR_R
// strerror_r is thread-safe.
#if defined(__GLIBC__) && defined(_GNU_SOURCE)
// glibc defines its own incompatible version of strerror_r
Expand Down Expand Up @@ -157,4 +158,6 @@ bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) {
return false;
}
}

RT_OFFLOAD_API_GROUP_END
} // namespace Fortran::runtime::io
2 changes: 1 addition & 1 deletion flang/runtime/io-error.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class IoErrorHandler : public Terminator {
RT_API_ATTRS void SignalPendingError();

RT_API_ATTRS int GetIoStat() const { return ioStat_; }
bool GetIoMsg(char *, std::size_t);
RT_API_ATTRS bool GetIoMsg(char *, std::size_t);

private:
enum Flag : std::uint8_t {
Expand Down
46 changes: 25 additions & 21 deletions flang/runtime/namelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,20 @@

namespace Fortran::runtime::io {

RT_VAR_GROUP_BEGIN
// Max size of a group, symbol or component identifier that can appear in
// NAMELIST input, plus a byte for NUL termination.
static constexpr std::size_t nameBufferSize{201};
static constexpr RT_CONST_VAR_ATTRS std::size_t nameBufferSize{201};
RT_VAR_GROUP_END

static inline char32_t GetComma(IoStatementState &io) {
RT_OFFLOAD_API_GROUP_BEGIN

static inline RT_API_ATTRS char32_t GetComma(IoStatementState &io) {
return io.mutableModes().editingFlags & decimalComma ? char32_t{';'}
: char32_t{','};
}

bool IONAME(OutputNamelist)(Cookie cookie, const NamelistGroup &group) {
bool IODEF(OutputNamelist)(Cookie cookie, const NamelistGroup &group) {
IoStatementState &io{*cookie};
io.CheckFormattedStmtType<Direction::Output>("OutputNamelist");
io.mutableModes().inNamelist = true;
Expand All @@ -40,7 +44,8 @@ bool IONAME(OutputNamelist)(Cookie cookie, const NamelistGroup &group) {
if ((connection.NeedAdvance(prefixLen) &&
!(io.AdvanceRecord() && EmitAscii(io, " ", 1))) ||
!EmitAscii(io, prefix, prefixLen) ||
(connection.NeedAdvance(std::strlen(str) + (suffix != ' ')) &&
(connection.NeedAdvance(
Fortran::runtime::strlen(str) + (suffix != ' ')) &&
!(io.AdvanceRecord() && EmitAscii(io, " ", 1)))) {
return false;
}
Expand Down Expand Up @@ -84,20 +89,20 @@ bool IONAME(OutputNamelist)(Cookie cookie, const NamelistGroup &group) {
return EmitUpperCase("/", 1, "", ' ');
}

static constexpr bool IsLegalIdStart(char32_t ch) {
static constexpr RT_API_ATTRS bool IsLegalIdStart(char32_t ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_' ||
ch == '@';
}

static constexpr bool IsLegalIdChar(char32_t ch) {
static constexpr RT_API_ATTRS bool IsLegalIdChar(char32_t ch) {
return IsLegalIdStart(ch) || (ch >= '0' && ch <= '9');
}

static constexpr char NormalizeIdChar(char32_t ch) {
static constexpr RT_API_ATTRS char NormalizeIdChar(char32_t ch) {
return static_cast<char>(ch >= 'A' && ch <= 'Z' ? ch - 'A' + 'a' : ch);
}

static bool GetLowerCaseName(
static RT_API_ATTRS bool GetLowerCaseName(
IoStatementState &io, char buffer[], std::size_t maxLength) {
std::size_t byteLength{0};
if (auto ch{io.GetNextNonBlank(byteLength)}) {
Expand All @@ -119,7 +124,7 @@ static bool GetLowerCaseName(
return false;
}

static Fortran::common::optional<SubscriptValue> GetSubscriptValue(
static RT_API_ATTRS Fortran::common::optional<SubscriptValue> GetSubscriptValue(
IoStatementState &io) {
Fortran::common::optional<SubscriptValue> value;
std::size_t byteCount{0};
Expand Down Expand Up @@ -152,8 +157,8 @@ static Fortran::common::optional<SubscriptValue> GetSubscriptValue(
return value;
}

static bool HandleSubscripts(IoStatementState &io, Descriptor &desc,
const Descriptor &source, const char *name) {
static RT_API_ATTRS bool HandleSubscripts(IoStatementState &io,
Descriptor &desc, const Descriptor &source, const char *name) {
IoErrorHandler &handler{io.GetIoErrorHandler()};
// Allow for blanks in subscripts; they're nonstandard, but not
// ambiguous within the parentheses.
Expand Down Expand Up @@ -252,7 +257,7 @@ static bool HandleSubscripts(IoStatementState &io, Descriptor &desc,
return false;
}

static void StorageSequenceExtension(
static RT_API_ATTRS void StorageSequenceExtension(
Descriptor &desc, const Descriptor &source) {
// Support the near-universal extension of NAMELIST input into a
// designatable storage sequence identified by its initial scalar array
Expand All @@ -274,7 +279,7 @@ static void StorageSequenceExtension(
}
}

static bool HandleSubstring(
static RT_API_ATTRS bool HandleSubstring(
IoStatementState &io, Descriptor &desc, const char *name) {
IoErrorHandler &handler{io.GetIoErrorHandler()};
auto pair{desc.type().GetCategoryAndKind()};
Expand Down Expand Up @@ -335,7 +340,7 @@ static bool HandleSubstring(
return false;
}

static bool HandleComponent(IoStatementState &io, Descriptor &desc,
static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
const Descriptor &source, const char *name) {
IoErrorHandler &handler{io.GetIoErrorHandler()};
char compName[nameBufferSize];
Expand All @@ -344,7 +349,8 @@ static bool HandleComponent(IoStatementState &io, Descriptor &desc,
if (const typeInfo::DerivedType *
type{addendum ? addendum->derivedType() : nullptr}) {
if (const typeInfo::Component *
comp{type->FindDataComponent(compName, std::strlen(compName))}) {
comp{type->FindDataComponent(
compName, Fortran::runtime::strlen(compName))}) {
bool createdDesc{false};
if (comp->rank() > 0 && source.rank() > 0) {
// If base and component are both arrays, the component name
Expand Down Expand Up @@ -408,7 +414,7 @@ static bool HandleComponent(IoStatementState &io, Descriptor &desc,

// Advance to the terminal '/' of a namelist group or leading '&'/'$'
// of the next.
static void SkipNamelistGroup(IoStatementState &io) {
static RT_API_ATTRS void SkipNamelistGroup(IoStatementState &io) {
std::size_t byteCount{0};
while (auto ch{io.GetNextNonBlank(byteCount)}) {
io.HandleRelativePosition(byteCount);
Expand All @@ -431,7 +437,7 @@ static void SkipNamelistGroup(IoStatementState &io) {
}
}

bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
bool IODEF(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
IoStatementState &io{*cookie};
io.CheckFormattedStmtType<Direction::Input>("InputNamelist");
io.mutableModes().inNamelist = true;
Expand Down Expand Up @@ -470,7 +476,7 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
handler.SignalError("NAMELIST input group has no name");
return false;
}
if (std::strcmp(group.groupName, name) == 0) {
if (Fortran::runtime::strcmp(group.groupName, name) == 0) {
break; // found it
}
SkipNamelistGroup(io);
Expand All @@ -489,7 +495,7 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
}
std::size_t itemIndex{0};
for (; itemIndex < group.items; ++itemIndex) {
if (std::strcmp(name, group.item[itemIndex].name) == 0) {
if (Fortran::runtime::strcmp(name, group.item[itemIndex].name) == 0) {
break;
}
}
Expand Down Expand Up @@ -590,8 +596,6 @@ bool IONAME(InputNamelist)(Cookie cookie, const NamelistGroup &group) {
return true;
}

RT_OFFLOAD_API_GROUP_BEGIN

bool IsNamelistNameOrSlash(IoStatementState &io) {
if (auto *listInput{
io.get_if<ListDirectedStatementState<Direction::Input>>()}) {
Expand Down
2 changes: 1 addition & 1 deletion flang/test/Driver/driver-help-hidden.f90
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
! CHECK-NEXT: -fopenmp-targets=<value>
! CHECK-NEXT: Specify comma-separated list of triples OpenMP offloading targets to be supported
! CHECK-NEXT: -fopenmp-version=<value>
! CHECK-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 51 for Clang
! CHECK-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 11 for Flang
! CHECK-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
! CHECK-NEXT: -foptimization-record-file=<file>
! CHECK-NEXT: Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch <arch> options.
Expand Down
4 changes: 2 additions & 2 deletions flang/test/Driver/driver-help.f90
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
! HELP-NEXT: -fopenmp-targets=<value>
! HELP-NEXT: Specify comma-separated list of triples OpenMP offloading targets to be supported
! HELP-NEXT: -fopenmp-version=<value>
! HELP-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 51 for Clang
! HELP-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 11 for Flang
! HELP-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
! HELP-NEXT: -foptimization-record-file=<file>
! HELP-NEXT: Specify the output name of the file containing the optimization remarks. Implies -fsave-optimization-record. On Darwin platforms, this cannot be used with multiple -arch <arch> options.
Expand Down Expand Up @@ -226,7 +226,7 @@
! HELP-FC1-NEXT: Generate code only for an OpenMP target device.
! HELP-FC1-NEXT: -fopenmp-target-debug Enable debugging in the OpenMP offloading device RTL
! HELP-FC1-NEXT: -fopenmp-version=<value>
! HELP-FC1-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 51 for Clang
! HELP-FC1-NEXT: Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 11 for Flang
! HELP-FC1-NEXT: -fopenmp Parse OpenMP pragmas and generate parallel code.
! HELP-FC1-NEXT: -fpass-plugin=<dsopath> Load pass plugin from a dynamic shared object file (only with new pass manager).
! HELP-FC1-NEXT: -fppc-native-vector-element-order
Expand Down
61 changes: 61 additions & 0 deletions flang/test/Driver/fopenmp.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-NO-OPENMP
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-apple-darwin -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-apple-darwin -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-NO-OPENMP
! RUN: %flang -target x86_64-apple-darwin -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-freebsd -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-freebsd -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-NO-OPENMP
! RUN: %flang -target x86_64-freebsd -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-NO-OPENMP --check-prefix=CHECK-WARNING
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-FC1-OPENMP

! CHECK-FC1-OPENMP: "-fc1"
! CHECK-FC1-OPENMP: "-fopenmp"
!
! CHECK-WARNING: warning: The library '-fopenmp=={{.*}}' is not supported, openmp is not be enabled
! CHECK-FC1-NO-OPENMP: "-fc1"
! CHECK-FC1-NO-OPENMP-NOT: "-fopenmp"
!
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-RT
! RUN: %flang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
!
! RUN: %flang -target x86_64-darwin -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
! RUN: %flang -target x86_64-darwin -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
! RUN: %flang -target x86_64-darwin -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
!
! RUN: %flang -target x86_64-freebsd -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
! RUN: %flang -target x86_64-freebsd -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
! RUN: %flang -target x86_64-freebsd -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5
!
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP --check-prefix=CHECK-LD-GOMP-NO-RT
! RUN: %flang -target x86_64-windows-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5MD
!
! CHECK-LD-OMP: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-OMP: "-lomp"
!
! CHECK-LD-GOMP: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-GOMP: "-lgomp"
! CHECK-LD-GOMP-RT: "-lrt"
! CHECK-LD-GOMP-NO-RT-NOT: "-lrt"
!
! CHECK-LD-IOMP5: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-IOMP5: "-liomp5"
!
! CHECK-LD-IOMP5MD: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-IOMP5MD: "-liomp5md"
!
! We'd like to check that the default is sane, but until we have the ability
! to *always* semantically analyze OpenMP without always generating runtime
! calls (in the event of an unsupported runtime), we don't have a good way to
! test the CC1 invocation. Instead, just ensure we do eventually link *some*
! OpenMP runtime.
!
! CHECK-LD-ANY: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-ANY: "-l{{(omp|gomp|iomp5)}}"
!
! CHECK-LD-ANYMD: "{{.*}}ld{{(.exe)?}}"
! CHECK-LD-ANYMD: "-l{{(omp|gomp|iomp5md)}}"
9 changes: 7 additions & 2 deletions flang/test/Driver/omp-driver-offload.f90
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@
! RUN: --target=aarch64-unknown-linux-gnu \
! RUN: | FileCheck %s --check-prefix=OPENMP-OFFLOAD-ARGS
! OPENMP-OFFLOAD-ARGS: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}}.f90"
! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "amdgcn-amd-amdhsa" {{.*}} "-fopenmp" {{.*}} "-fopenmp-host-ir-file-path" "{{.*}}.bc" "-fopenmp-is-target-device" {{.*}}.f90"
! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "amdgcn-amd-amdhsa"
! OPENMP-OFFLOAD-ARGS-SAME: "-fopenmp"
! OPENMP-OFFLOAD-ARGS-SAME: "-fopenmp-host-ir-file-path" "{{.*}}.bc" "-fopenmp-is-target-device"
! OPENMP-OFFLOAD-ARGS-SAME: {{.*}}.f90"
! OPENMP-OFFLOAD-ARGS: "{{[^"]*}}clang-offload-packager{{.*}}" {{.*}} "--image=file={{.*}}.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp"
! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu" {{.*}} "-fopenmp" {{.*}} "-fembed-offload-object={{.*}}.out" {{.*}}.bc"
! OPENMP-OFFLOAD-ARGS-NEXT: "{{[^"]*}}flang-new" "-fc1" "-triple" "aarch64-unknown-linux-gnu"
! OPENMP-OFFLOAD-ARGS-SAME: "-fopenmp"
! OPENMP-OFFLOAD-ARGS-SAME: "-fembed-offload-object={{.*}}.out" {{.*}}.bc"

! Test -fopenmp with offload for RTL Flag Options
! RUN: %flang -### %s -o %t 2>&1 \
Expand Down
64 changes: 64 additions & 0 deletions flang/test/Lower/CUDA/cuda-data-transfer.cuf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

! Test CUDA Fortran data transfer using assignment statements.

module mod1
type :: t1
integer :: i
end type
end

subroutine sub1()
integer, device :: m
integer, device :: adev(10)
Expand Down Expand Up @@ -55,3 +61,61 @@ end
! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[ELEMENTAL]](%{{.*}}) {uniq_name = ".cuf_host_tmp"} : (!hlfir.expr<10xi32>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>, i1)
! CHECK: fir.cuda_data_transfer %[[ASSOC]]#0 to %[[ADEV]]#0 {transfer_kind = #fir.cuda_transfer<host_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref<!fir.array<10xi32>>, i1

subroutine sub2()
integer, device :: m
integer, device :: adev(10), bdev(10)
integer :: i, ahost(10), bhost(10)

ahost = adev

i = m

ahost(1:5) = adev(1:5)

bdev = adev

! Implicit data transfer of adev before evaluation.
bhost = ahost + adev

end

! CHECK-LABEL: func.func @_QPsub2()
! CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {cuda_attr = #fir.cuda<device>, uniq_name = "_QFsub2Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Eahost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BDEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {cuda_attr = #fir.cuda<device>, uniq_name = "_QFsub2Ebdev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Ebhost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub2Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[M:.*]]:2 = hlfir.declare %{{.*}} {cuda_attr = #fir.cuda<device>, uniq_name = "_QFsub2Em"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: fir.cuda_data_transfer %[[ADEV]]#0 to %[[AHOST]]#0 {transfer_kind = #fir.cuda_transfer<device_host>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: fir.cuda_data_transfer %[[M]]#0 to %[[I]]#0 {transfer_kind = #fir.cuda_transfer<device_host>} : !fir.ref<i32>, !fir.ref<i32>

! CHECK: %[[DES_ADEV:.*]] = hlfir.designate %[[ADEV]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: %[[DES_AHOST:.*]] = hlfir.designate %[[AHOST]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: fir.cuda_data_transfer %[[DES_ADEV]] to %[[DES_AHOST]] {transfer_kind = #fir.cuda_transfer<device_host>} : !fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>

! CHECK: fir.cuda_data_transfer %[[ADEV]]#0 to %[[BDEV]]#0 {transfer_kind = #fir.cuda_transfer<device_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>

! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<10xi32> {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[DECL_TEMP:.*]]:2 = hlfir.declare %[[TEMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>)
! CHECK: %[[ADEV_TEMP:.*]]:2 = hlfir.declare %21#0 {cuda_attr = #fir.cuda<device>, uniq_name = "_QFsub2Eadev"} : (!fir.heap<!fir.array<10xi32>>) -> (!fir.heap<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>)
! CHECK: fir.cuda_data_transfer %[[ADEV]]#1 to %[[DECL_TEMP]]#0 {transfer_kind = #fir.cuda_transfer<device_host>} : !fir.ref<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>
! CHECK: %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32>
! CHECK: hlfir.assign %[[ELEMENTAL]] to %[[BHOST]]#0 : !hlfir.expr<10xi32>, !fir.ref<!fir.array<10xi32>>
! CHECK: fir.freemem %[[DECL_TEMP]]#0 : !fir.heap<!fir.array<10xi32>>

subroutine sub3()
use mod1
type(t1), device :: t
integer :: ahost(10), bhost(10)

bhost = ahost + t%i
end

! CHECK-LABEL: func.func @_QPsub3()
! CHECK: %[[TMP:.*]] = fir.alloca !fir.type<_QMmod1Tt1{i:i32}> {bindc_name = ".tmp"}
! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub3Eahost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub3Ebhost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[T:.*]]:2 = hlfir.declare %7 {cuda_attr = #fir.cuda<device>, uniq_name = "_QFsub3Et"} : (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>) -> (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>)
! CHECK: %[[TMP_DECL:.*]]:2 = hlfir.declare %0 {uniq_name = ".tmp"} : (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>) -> (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>)
! CHECK: fir.cuda_data_transfer %[[T]]#1 to %[[TMP_DECL]]#0 {transfer_kind = #fir.cuda_transfer<device_host>} : !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>
4 changes: 4 additions & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,9 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.round
libc.src.math.roundf
libc.src.math.roundl
libc.src.math.roundeven
libc.src.math.roundevenf
libc.src.math.roundevenl
libc.src.math.scalbn
libc.src.math.scalbnf
libc.src.math.scalbnl
Expand Down Expand Up @@ -555,6 +558,7 @@ if(LIBC_TYPES_HAS_FLOAT128)
libc.src.math.nextdownf128
libc.src.math.nextupf128
libc.src.math.rintf128
libc.src.math.roundevenf128
libc.src.math.roundf128
libc.src.math.sqrtf128
libc.src.math.truncf128
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/c23.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Additions:
* pown*
* powr*
* rootn*
* roundeven*
* roundeven* |check|
* fromfp*
* ufromfp*
* fromfpx*
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ Basic Operations
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| round | |check| | |check| | |check| | | |check| | 7.12.9.6 | F.10.6.6 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| roundeven | | | | | | 7.12.9.8 | F.10.6.8 |
| roundeven | |check| | |check| | |check| | | |check| | 7.12.9.8 | F.10.6.8 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| scalbn | |check| | |check| | |check| | | | 7.12.6.19 | F.10.3.19 |
+------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
Expand Down
5 changes: 5 additions & 0 deletions libc/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,11 @@ add_math_entrypoint_object(roundf)
add_math_entrypoint_object(roundl)
add_math_entrypoint_object(roundf128)

add_math_entrypoint_object(roundeven)
add_math_entrypoint_object(roundevenf)
add_math_entrypoint_object(roundevenl)
add_math_entrypoint_object(roundevenf128)

add_math_entrypoint_object(scalbn)
add_math_entrypoint_object(scalbnf)
add_math_entrypoint_object(scalbnl)
Expand Down
49 changes: 49 additions & 0 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,55 @@ add_entrypoint_object(
libc.src.__support.FPUtil.nearest_integer_operations
)

add_entrypoint_object(
roundeven
SRCS
roundeven.cpp
HDRS
../roundeven.h
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.FPUtil.nearest_integer_operations
)

add_entrypoint_object(
roundevenf
SRCS
roundevenf.cpp
HDRS
../roundevenf.h
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.FPUtil.nearest_integer_operations
)

add_entrypoint_object(
roundevenl
SRCS
roundevenl.cpp
HDRS
../roundevenl.h
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.FPUtil.nearest_integer_operations
)

add_entrypoint_object(
roundevenf128
SRCS
roundevenf128.cpp
HDRS
../roundevenf128.h
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.macros.properties.types
libc.src.__support.FPUtil.nearest_integer_operations
)

add_entrypoint_object(
lround
SRCS
Expand Down
19 changes: 19 additions & 0 deletions libc/src/math/generic/roundeven.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Implementation of roundeven function ------------------------------===//
//
// 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 "src/math/roundeven.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(double, roundeven, (double x)) {
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
}

} // namespace LIBC_NAMESPACE
19 changes: 19 additions & 0 deletions libc/src/math/generic/roundevenf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Implementation of roundevenf function -----------------------------===//
//
// 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 "src/math/roundevenf.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(float, roundevenf, (float x)) {
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
}

} // namespace LIBC_NAMESPACE
19 changes: 19 additions & 0 deletions libc/src/math/generic/roundevenf128.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Implementation of roundevenf128 function --------------------------===//
//
// 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 "src/math/roundevenf128.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(float128, roundevenf128, (float128 x)) {
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
}

} // namespace LIBC_NAMESPACE
19 changes: 19 additions & 0 deletions libc/src/math/generic/roundevenl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===-- Implementation of roundevenl function -----------------------------===//
//
// 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 "src/math/roundevenl.h"
#include "src/__support/FPUtil/NearestIntegerOperations.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(long double, roundevenl, (long double x)) {
return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST);
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/math/roundeven.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for roundeven ---------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_MATH_ROUNDEVEN_H
#define LLVM_LIBC_SRC_MATH_ROUNDEVEN_H

namespace LIBC_NAMESPACE {

double roundeven(double x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_ROUNDEVEN_H
18 changes: 18 additions & 0 deletions libc/src/math/roundevenf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for roundevenf --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_MATH_ROUNDEVENF_H
#define LLVM_LIBC_SRC_MATH_ROUNDEVENF_H

namespace LIBC_NAMESPACE {

float roundevenf(float x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF_H
20 changes: 20 additions & 0 deletions libc/src/math/roundevenf128.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for roundevenf128 -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H
#define LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H

#include "src/__support/macros/properties/types.h"

namespace LIBC_NAMESPACE {

float128 roundevenf128(float128 x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H
18 changes: 18 additions & 0 deletions libc/src/math/roundevenl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for roundevenl --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_MATH_ROUNDEVENL_H
#define LLVM_LIBC_SRC_MATH_ROUNDEVENL_H

namespace LIBC_NAMESPACE {

long double roundevenl(long double x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENL_H
45 changes: 45 additions & 0 deletions libc/test/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,51 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundeven_test
NEED_MPFR
SUITE
libc-math-unittests
SRCS
roundeven_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundeven
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundevenf_test
NEED_MPFR
SUITE
libc-math-unittests
SRCS
roundevenf_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundevenf
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundevenl_test
NEED_MPFR
SUITE
libc-math-unittests
SRCS
roundevenl_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundevenl
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
lround_test
NEED_MPFR
Expand Down
92 changes: 92 additions & 0 deletions libc/test/src/math/RoundEvenTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//===-- Utility class to test roundeven[f|l] --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H
#define LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H

#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"

#include "include/llvm-libc-macros/math-macros.h"

namespace mpfr = LIBC_NAMESPACE::testing::mpfr;

template <typename T>
class RoundEvenTest : public LIBC_NAMESPACE::testing::Test {

DECLARE_SPECIAL_CONSTANTS(T)

public:
typedef T (*RoundEvenFunc)(T);

void testSpecialNumbers(RoundEvenFunc func) {
EXPECT_FP_EQ(zero, func(zero));
EXPECT_FP_EQ(neg_zero, func(neg_zero));

EXPECT_FP_EQ(inf, func(inf));
EXPECT_FP_EQ(neg_inf, func(neg_inf));

EXPECT_FP_EQ(aNaN, func(aNaN));
}

void testRoundedNumbers(RoundEvenFunc func) {
EXPECT_FP_EQ(T(1.0), func(T(1.0)));
EXPECT_FP_EQ(T(-1.0), func(T(-1.0)));
EXPECT_FP_EQ(T(10.0), func(T(10.0)));
EXPECT_FP_EQ(T(-10.0), func(T(-10.0)));
EXPECT_FP_EQ(T(1234.0), func(T(1234.0)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0)));
}

void testFractions(RoundEvenFunc func) {
EXPECT_FP_EQ(T(0.0), func(T(0.5)));
EXPECT_FP_EQ(T(-0.0), func(T(-0.5)));
EXPECT_FP_EQ(T(0.0), func(T(0.115)));
EXPECT_FP_EQ(T(-0.0), func(T(-0.115)));
EXPECT_FP_EQ(T(1.0), func(T(0.715)));
EXPECT_FP_EQ(T(-1.0), func(T(-0.715)));
EXPECT_FP_EQ(T(1.0), func(T(1.3)));
EXPECT_FP_EQ(T(-1.0), func(T(-1.3)));
EXPECT_FP_EQ(T(2.0), func(T(1.5)));
EXPECT_FP_EQ(T(-2.0), func(T(-1.5)));
EXPECT_FP_EQ(T(2.0), func(T(1.75)));
EXPECT_FP_EQ(T(-2.0), func(T(-1.75)));
EXPECT_FP_EQ(T(11.0), func(T(10.65)));
EXPECT_FP_EQ(T(-11.0), func(T(-10.65)));
EXPECT_FP_EQ(T(1233.0), func(T(1233.25)));
EXPECT_FP_EQ(T(1234.0), func(T(1233.50)));
EXPECT_FP_EQ(T(1234.0), func(T(1233.75)));
EXPECT_FP_EQ(T(-1233.0), func(T(-1233.25)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1233.50)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1233.75)));
EXPECT_FP_EQ(T(1234.0), func(T(1234.50)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50)));
}

void testRange(RoundEvenFunc func) {
constexpr StorageType COUNT = 100'000;
constexpr StorageType STEP = STORAGE_MAX / COUNT;
for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
T x = FPBits(v).get_val();
if (isnan(x) || isinf(x))
continue;

ASSERT_MPFR_MATCH(mpfr::Operation::RoundEven, x, func(x), 0.0);
}
}
};

#define LIST_ROUNDEVEN_TESTS(T, func) \
using LlvmLibcRoundEvenTest = RoundEvenTest<T>; \
TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \
TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \
TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); } \
TEST_F(LlvmLibcRoundEvenTest, Range) { testRange(&func); }

#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H
13 changes: 13 additions & 0 deletions libc/test/src/math/roundeven_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//===-- Unittests for roundeven -------------------------------------------===//
//
// 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 "RoundEvenTest.h"

#include "src/math/roundeven.h"

LIST_ROUNDEVEN_TESTS(double, LIBC_NAMESPACE::roundeven)
13 changes: 13 additions & 0 deletions libc/test/src/math/roundevenf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//===-- Unittests for roundevenf ------------------------------------------===//
//
// 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 "RoundEvenTest.h"

#include "src/math/roundevenf.h"

LIST_ROUNDEVEN_TESTS(float, LIBC_NAMESPACE::roundevenf)
13 changes: 13 additions & 0 deletions libc/test/src/math/roundevenl_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//===-- Unittests for roundevenl ------------------------------------------===//
//
// 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 "RoundEvenTest.h"

#include "src/math/roundevenl.h"

LIST_ROUNDEVEN_TESTS(long double, LIBC_NAMESPACE::roundevenl)
56 changes: 56 additions & 0 deletions libc/test/src/math/smoke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,62 @@ add_fp_unittest(
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundeven_test
SUITE
libc-math-smoke-tests
SRCS
roundeven_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundeven
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundevenf_test
SUITE
libc-math-smoke-tests
SRCS
roundevenf_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundevenf
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundevenl_test
SUITE
libc-math-smoke-tests
SRCS
roundevenl_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundevenl
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
roundevenf128_test
SUITE
libc-math-smoke-tests
SRCS
roundevenf128_test.cpp
HDRS
RoundEvenTest.h
DEPENDS
libc.include.math
libc.src.math.roundevenf128
libc.src.__support.FPUtil.fp_bits
)

add_fp_unittest(
lround_test
SUITE
Expand Down
72 changes: 72 additions & 0 deletions libc/test/src/math/smoke/RoundEvenTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//===-- Utility class to test roundeven[f|l] --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H
#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H

#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"

#include "include/llvm-libc-macros/math-macros.h"

template <typename T>
class RoundEvenTest : public LIBC_NAMESPACE::testing::Test {

DECLARE_SPECIAL_CONSTANTS(T)

public:
typedef T (*RoundEvenFunc)(T);

void testSpecialNumbers(RoundEvenFunc func) {
EXPECT_FP_EQ(zero, func(zero));
EXPECT_FP_EQ(neg_zero, func(neg_zero));

EXPECT_FP_EQ(inf, func(inf));
EXPECT_FP_EQ(neg_inf, func(neg_inf));

EXPECT_FP_EQ(aNaN, func(aNaN));
}

void testRoundedNumbers(RoundEvenFunc func) {
EXPECT_FP_EQ(T(1.0), func(T(1.0)));
EXPECT_FP_EQ(T(-1.0), func(T(-1.0)));
EXPECT_FP_EQ(T(10.0), func(T(10.0)));
EXPECT_FP_EQ(T(-10.0), func(T(-10.0)));
EXPECT_FP_EQ(T(1234.0), func(T(1234.0)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0)));
}

void testFractions(RoundEvenFunc func) {
EXPECT_FP_EQ(T(0.0), func(T(0.5)));
EXPECT_FP_EQ(T(-0.0), func(T(-0.5)));
EXPECT_FP_EQ(T(0.0), func(T(0.115)));
EXPECT_FP_EQ(T(-0.0), func(T(-0.115)));
EXPECT_FP_EQ(T(1.0), func(T(0.715)));
EXPECT_FP_EQ(T(-1.0), func(T(-0.715)));
EXPECT_FP_EQ(T(2.0), func(T(1.5)));
EXPECT_FP_EQ(T(-2.0), func(T(-1.5)));
EXPECT_FP_EQ(T(2.0), func(T(1.75)));
EXPECT_FP_EQ(T(-2.0), func(T(-1.75)));
EXPECT_FP_EQ(T(10.0), func(T(10.50)));
EXPECT_FP_EQ(T(-10.0), func(T(-10.50)));
EXPECT_FP_EQ(T(11.0), func(T(10.65)));
EXPECT_FP_EQ(T(-11.0), func(T(-10.65)));
EXPECT_FP_EQ(T(1234.0), func(T(1234.50)));
EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50)));
EXPECT_FP_EQ(T(1236.0), func(T(1235.50)));
EXPECT_FP_EQ(T(-1236.0), func(T(-1235.50)));
}
};

#define LIST_ROUNDEVEN_TESTS(T, func) \
using LlvmLibcRoundEvenTest = RoundEvenTest<T>; \
TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \
TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \
TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); }

#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H
12 changes: 12 additions & 0 deletions libc/test/src/math/smoke/roundeven_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittests for roundeven -------------------------------------------===//
//
// 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 "RoundEvenTest.h"
#include "src/math/roundeven.h"

LIST_ROUNDEVEN_TESTS(double, LIBC_NAMESPACE::roundeven)
12 changes: 12 additions & 0 deletions libc/test/src/math/smoke/roundevenf128_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittests for roundevenf128 ---------------------------------------===//
//
// 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 "RoundEvenTest.h"
#include "src/math/roundevenf128.h"

LIST_ROUNDEVEN_TESTS(float128, LIBC_NAMESPACE::roundevenf128)
12 changes: 12 additions & 0 deletions libc/test/src/math/smoke/roundevenf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittests for roundevenf ------------------------------------------===//
//
// 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 "RoundEvenTest.h"
#include "src/math/roundevenf.h"

LIST_ROUNDEVEN_TESTS(float, LIBC_NAMESPACE::roundevenf)
12 changes: 12 additions & 0 deletions libc/test/src/math/smoke/roundevenl_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//===-- Unittests for roundevenf ------------------------------------------===//
//
// 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 "RoundEvenTest.h"
#include "src/math/roundevenl.h"

LIST_ROUNDEVEN_TESTS(long double, LIBC_NAMESPACE::roundevenl)
12 changes: 12 additions & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,16 @@ class MPFRNumber {
return result;
}

MPFRNumber roundeven() const {
MPFRNumber result(*this);
#if MPFR_VERSION_MAJOR >= 4
mpfr_roundeven(result.value, value);
#else
mpfr_rint(result.value, value, MPFR_RNDN);
#endif
return result;
}

bool round_to_long(long &result) const {
// We first calculate the rounded value. This way, when converting
// to long using mpfr_get_si, the rounding direction of MPFR_RNDN
Expand Down Expand Up @@ -634,6 +644,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
return mpfrInput.mod_pi_over_4();
case Operation::Round:
return mpfrInput.round();
case Operation::RoundEven:
return mpfrInput.roundeven();
case Operation::Sin:
return mpfrInput.sin();
case Operation::Sinh:
Expand Down
1 change: 1 addition & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum class Operation : int {
ModPIOver2,
ModPIOver4,
Round,
RoundEven,
Sin,
Sinh,
Sqrt,
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__format/formatter_floating_point.h
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ __format_floating_point(_Tp __value, _FormatContext& __ctx, __format_spec::__par
// Let P equal the precision if nonzero, 6 if the precision is not
// specified, or 1 if the precision is 0. Then, if a conversion with
// style E would have an exponent of X:
int __p = std::max(1, (__specs.__has_precision() ? __specs.__precision_ : 6));
int __p = std::max<int>(1, (__specs.__has_precision() ? __specs.__precision_ : 6));
if (__result.__exponent == __result.__last)
// if P > X >= -4, the conversion is with style f or F and precision P - 1 - X.
// By including the radix point it calculates P - (1 + X)
Expand Down
2 changes: 1 addition & 1 deletion libcxx/include/__memory/construct_at.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr _Tp* construct_at(_Tp* __location, _Args&&... __
#endif

template <class _Tp, class... _Args, class = decltype(::new(std::declval<void*>()) _Tp(std::declval<_Args>()...))>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Tp* __construct_at(_Tp* __location, _Args&&... __args) {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* __construct_at(_Tp* __location, _Args&&... __args) {
#if _LIBCPP_STD_VER >= 20
return std::construct_at(__location, std::forward<_Args>(__args)...);
#else
Expand Down
14 changes: 7 additions & 7 deletions lld/COFF/PDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1726,15 +1726,15 @@ void PDBLinker::commit(codeview::GUID *guid) {
}
}

static uint32_t getSecrelReloc(llvm::COFF::MachineTypes machine) {
switch (machine) {
case AMD64:
static uint32_t getSecrelReloc(Triple::ArchType arch) {
switch (arch) {
case Triple::x86_64:
return COFF::IMAGE_REL_AMD64_SECREL;
case I386:
case Triple::x86:
return COFF::IMAGE_REL_I386_SECREL;
case ARMNT:
case Triple::thumb:
return COFF::IMAGE_REL_ARM_SECREL;
case ARM64:
case Triple::aarch64:
return COFF::IMAGE_REL_ARM64_SECREL;
default:
llvm_unreachable("unknown machine type");
Expand All @@ -1752,7 +1752,7 @@ static bool findLineTable(const SectionChunk *c, uint32_t addr,
DebugLinesSubsectionRef &lines,
uint32_t &offsetInLinetable) {
ExitOnError exitOnErr;
const uint32_t secrelReloc = getSecrelReloc(c->file->ctx.config.machine);
const uint32_t secrelReloc = getSecrelReloc(c->getArch());

for (SectionChunk *dbgC : c->file->getDebugChunks()) {
if (dbgC->getSectionName() != ".debug$S")
Expand Down
20 changes: 15 additions & 5 deletions lld/MachO/DriverUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,21 @@ using namespace lld::macho;
// Create table mapping all options defined in Options.td
static constexpr OptTable::Info optInfo[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, \
METAVAR, OPT_##ID, opt::Option::KIND##Class, \
PARAM, FLAGS, VISIBILITY, \
OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \
VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
VALUES) \
{PREFIX, \
NAME, \
HELPTEXT, \
HELPTEXTSFORVARIANTS, \
METAVAR, \
OPT_##ID, \
opt::Option::KIND##Class, \
PARAM, \
FLAGS, \
VISIBILITY, \
OPT_##GROUP, \
OPT_##ALIAS, \
ALIASARGS, \
VALUES},
#include "Options.inc"
#undef OPTION
Expand Down
20 changes: 15 additions & 5 deletions lld/MinGW/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,21 @@ enum {
// Create table mapping all options defined in Options.td
static constexpr opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, \
METAVAR, OPT_##ID, opt::Option::KIND##Class, \
PARAM, FLAGS, VISIBILITY, \
OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \
VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
VALUES) \
{PREFIX, \
NAME, \
HELPTEXT, \
HELPTEXTSFORVARIANTS, \
METAVAR, \
OPT_##ID, \
opt::Option::KIND##Class, \
PARAM, \
FLAGS, \
VISIBILITY, \
OPT_##GROUP, \
OPT_##ALIAS, \
ALIASARGS, \
VALUES},
#include "Options.inc"
#undef OPTION
Expand Down
59 changes: 56 additions & 3 deletions lld/test/COFF/undefined-symbol-cv.s
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s
# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s
# REQUIRES: aarch64, x86
# RUN: split-file %s %t.dir && cd %t.dir

# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o test-x86_64.obj test-x86_64.s
# RUN: llvm-mc -triple=aarch64-windows-msvc -filetype=obj -o test-aarch64.obj test-aarch64.s
# RUN: llvm-mc -triple=arm64ec-windows-msvc -filetype=obj -o test-arm64ec.obj test-aarch64.s

# RUN: not lld-link -out:test-x86_64.exe test-x86_64.obj 2>&1 | FileCheck %s
# RUN: not lld-link -out:test-aarch64.exe test-aarch64.obj 2>&1 | FileCheck %s
# RUN: not lld-link -out:test-arm64ec.exe -machine:arm64ec test-arm64ec.obj 2>&1 | FileCheck %s
# RUN: not lld-link -out:test-arm64ec2.exe -machine:arm64ec test-x86_64.obj 2>&1 | FileCheck %s

# CHECK: error: undefined symbol: int __cdecl foo(void)
# CHECK-NEXT: >>> referenced by file1.cpp:1
Expand All @@ -18,6 +26,7 @@
# CHECK-NEXT: >>> referenced by file1.cpp:5
# CHECK-NEXT: >>> {{.*}}.obj:(f2)

#--- test-x86_64.s
.cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1
.cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1

Expand Down Expand Up @@ -60,3 +69,47 @@ f2:
.long 4
.cv_filechecksums
.cv_stringtable

#--- test-aarch64.s
.cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1
.cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1

.section .text,"xr",one_only,main
.globl main
main:
.cv_func_id 0
.cv_loc 0 1 1 0 is_stmt 0
bl "?foo@@YAHXZ"
.cv_loc 0 1 2 0
bl "?foo@@YAHXZ"
.cv_loc 0 2 3 0
b "?bar@@YAHXZ"
.Lfunc_end0:

f1:
.cv_func_id 1
.cv_loc 1 1 4 0 is_stmt 0
bl "?bar@@YAHXZ"
.Lfunc_end1:

.section .text,"xr",one_only,f2
.globl f2
f2:
.cv_func_id 2
.cv_loc 2 1 5 0 is_stmt 0
bl "?baz@@YAHXZ"
.Lfunc_end2:

.section .debug$S,"dr",associative,main
.long 4
.cv_linetable 0, main, .Lfunc_end0
.cv_linetable 1, f1, .Lfunc_end1

.section .debug$S,"dr",associative,f2
.long 4
.cv_linetable 2, f2, .Lfunc_end2

.section .debug$S,"dr"
.long 4
.cv_filechecksums
.cv_stringtable
20 changes: 15 additions & 5 deletions lld/wasm/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,21 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
// Create table mapping all options defined in Options.td
static constexpr opt::OptTable::Info optInfo[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \
VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, \
METAVAR, OPT_##ID, opt::Option::KIND##Class, \
PARAM, FLAGS, VISIBILITY, \
OPT_##GROUP, OPT_##ALIAS, ALIASARGS, \
VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, \
VALUES) \
{PREFIX, \
NAME, \
HELPTEXT, \
HELPTEXTSFORVARIANTS, \
METAVAR, \
OPT_##ID, \
opt::Option::KIND##Class, \
PARAM, \
FLAGS, \
VISIBILITY, \
OPT_##GROUP, \
OPT_##ALIAS, \
ALIASARGS, \
VALUES},
#include "Options.inc"
#undef OPTION
Expand Down
26 changes: 1 addition & 25 deletions lldb/packages/Python/lldbsuite/test/make/Makefile.rules
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ LLDB_BASE_DIR := $(THIS_FILE_DIR)/../../../../../
#
# GNUWin32 uname gives "windows32" or "server version windows32" while
# some versions of MSYS uname return "MSYS_NT*", but most environments
# standardize on "Windows_NT", so we'll make it consistent here.
# standardize on "Windows_NT", so we'll make it consistent here.
# When running tests from Visual Studio, the environment variable isn't
# inherited all the way down to the process spawned for make.
#----------------------------------------------------------------------
Expand Down Expand Up @@ -210,12 +210,6 @@ else
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
DSYM = $(EXE).debug
endif

ifeq "$(MAKE_DWP)" "YES"
MAKE_DWO := YES
DWP_NAME = $(EXE).dwp
DYLIB_DWP_NAME = $(DYLIB_NAME).dwp
endif
endif

LIMIT_DEBUG_INFO_FLAGS =
Expand Down Expand Up @@ -363,7 +357,6 @@ ifneq "$(OS)" "Darwin"

OBJCOPY ?= $(call replace_cc_with,objcopy)
ARCHIVER ?= $(call replace_cc_with,ar)
DWP ?= $(call replace_cc_with,dwp)
override AR = $(ARCHIVER)
endif

Expand Down Expand Up @@ -534,10 +527,6 @@ ifneq "$(CXX)" ""
endif
endif

ifeq "$(GEN_GNU_BUILD_ID)" "YES"
LDFLAGS += -Wl,--build-id
endif

#----------------------------------------------------------------------
# DYLIB_ONLY variable can be used to skip the building of a.out.
# See the sections below regarding dSYM file as well as the building of
Expand Down Expand Up @@ -576,17 +565,10 @@ else
endif
else
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
ifeq "$(SAVE_FULL_DEBUG_BINARY)" "YES"
cp "$(EXE)" "$(EXE).unstripped"
endif
$(OBJCOPY) --only-keep-debug "$(EXE)" "$(DSYM)"
$(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DSYM)" "$(EXE)" "$(EXE)"
endif
ifeq "$(MAKE_DWP)" "YES"
$(DWP) -o "$(DWP_NAME)" $(DWOS)
endif
endif


#----------------------------------------------------------------------
# Make the dylib
Expand Down Expand Up @@ -628,15 +610,9 @@ endif
else
$(LD) $(DYLIB_OBJECTS) $(LDFLAGS) -shared -o "$(DYLIB_FILENAME)"
ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES"
ifeq "$(SAVE_FULL_DEBUG_BINARY)" "YES"
cp "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).unstripped"
endif
$(OBJCOPY) --only-keep-debug "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME).debug"
$(OBJCOPY) --strip-debug --add-gnu-debuglink="$(DYLIB_FILENAME).debug" "$(DYLIB_FILENAME)" "$(DYLIB_FILENAME)"
endif
ifeq "$(MAKE_DWP)" "YES"
$(DWP) -o $(DYLIB_DWP_FILE) $(DYLIB_DWOS)
endif
endif

#----------------------------------------------------------------------
Expand Down
38 changes: 13 additions & 25 deletions lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4378,38 +4378,26 @@ const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() {
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
ModuleSpec module_spec;
module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec();
FileSpec dwp_filespec;
for (const auto &symfile : symfiles.files()) {
module_spec.GetSymbolFileSpec() =
FileSpec(symfile.GetPath() + ".dwp", symfile.GetPathStyle());
LLDB_LOG(log, "Searching for DWP using: \"{0}\"",
module_spec.GetSymbolFileSpec());
dwp_filespec =
FileSpec dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (FileSystem::Instance().Exists(dwp_filespec)) {
break;
}
}
if (!FileSystem::Instance().Exists(dwp_filespec)) {
LLDB_LOG(log, "No DWP file found locally");
// Fill in the UUID for the module we're trying to match for, so we can
// find the correct DWP file, as the Debuginfod plugin uses *only* this
// data to correctly match the DWP file with the binary.
module_spec.GetUUID() = m_objfile_sp->GetUUID();
dwp_filespec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
}
if (FileSystem::Instance().Exists(dwp_filespec)) {
LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (dwp_obj_file) {
m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec);
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwp_filespec, 0,
FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp,
dwp_file_data_offset);
if (dwp_obj_file) {
m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>(
*this, dwp_obj_file, DIERef::k_file_index_mask);
break;
}
}
}
if (!m_dwp_symfile) {
Expand Down
7 changes: 1 addition & 6 deletions lldb/source/Plugins/SymbolLocator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# Order matters here: the first symbol locator prevents further searching.
# For DWARF binaries that are both stripped and split, the Default plugin
# will return the stripped binary when asked for the ObjectFile, which then
# prevents an unstripped binary from being requested from the Debuginfod
# provider.
add_subdirectory(Debuginfod)
add_subdirectory(Default)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
add_subdirectory(DebugSymbols)
endif()
add_subdirectory(Debuginfod)
29 changes: 2 additions & 27 deletions lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,6 @@ llvm::StringRef SymbolVendorELF::GetPluginDescriptionStatic() {
"executables.";
}

// If this is needed elsewhere, it can be exported/moved.
static bool IsDwpSymbolFile(const lldb::ModuleSP &module_sp,
const FileSpec &file_spec) {
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
// Try to create an ObjectFile from the file_spec.
ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin(
module_sp, &file_spec, 0, FileSystem::Instance().GetByteSize(file_spec),
dwp_file_data_sp, dwp_file_data_offset);
// The presence of a debug_cu_index section is the key identifying feature of
// a DWP file. Make sure we don't fill in the section list on dwp_obj_file
// (by calling GetSectionList(false)) as this function could be called before
// we may have all the symbol files collected and available.
return dwp_obj_file && ObjectFileELF::classof(dwp_obj_file.get()) &&
dwp_obj_file->GetSectionList(false)->FindSectionByType(
eSectionTypeDWARFDebugCuIndex, false);
}

// CreateInstance
//
// Platforms can register a callback to use when creating symbol vendors to
Expand Down Expand Up @@ -105,15 +87,8 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp,
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dsym_fspec =
PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (!dsym_fspec || IsDwpSymbolFile(module_sp, dsym_fspec)) {
// If we have a stripped binary or if we got a DWP file, we should prefer
// symbols in the executable acquired through a plugin.
ModuleSpec unstripped_spec =
PluginManager::LocateExecutableObjectFile(module_spec);
if (!unstripped_spec)
return nullptr;
dsym_fspec = unstripped_spec.GetFileSpec();
}
if (!dsym_fspec)
return nullptr;

DataBufferSP dsym_file_data_sp;
lldb::offset_t dsym_file_data_offset = 0;
Expand Down
19 changes: 0 additions & 19 deletions lldb/test/API/debuginfod/Normal/Makefile

This file was deleted.

183 changes: 0 additions & 183 deletions lldb/test/API/debuginfod/Normal/TestDebuginfod.py

This file was deleted.

7 changes: 0 additions & 7 deletions lldb/test/API/debuginfod/Normal/main.c

This file was deleted.

23 changes: 0 additions & 23 deletions lldb/test/API/debuginfod/SplitDWARF/Makefile

This file was deleted.

193 changes: 0 additions & 193 deletions lldb/test/API/debuginfod/SplitDWARF/TestDebuginfodDWP.py

This file was deleted.

7 changes: 0 additions & 7 deletions lldb/test/API/debuginfod/SplitDWARF/main.c

This file was deleted.

8 changes: 0 additions & 8 deletions llvm/docs/CommandGuide/llvm-objcopy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -309,14 +309,6 @@ them.
Compress DWARF debug sections in the output, using the specified format.
Supported formats are ``zlib`` and ``zstd``. Use ``zlib`` if ``<format>`` is omitted.

.. option:: --compress-sections <section>=<format>

Compress or decompress sections matched by ``<section>`` using the specified
format. Supported formats are ``zlib`` and ``zstd``. Specify ``none`` for
decompression. When a section is matched by multiple options, the last one
wins. A wildcard ``<section>`` starting with '!' is disallowed.
Sections within a segment cannot be (de)compressed.

.. option:: --decompress-debug-sections

Decompress any compressed DWARF debug sections in the output.
Expand Down
8 changes: 4 additions & 4 deletions llvm/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ Changes to the LLVM tools
* llvm-ar now allows specifying COFF archive format with ``--format`` argument
and uses it by default for COFF targets.

* llvm-ranlib now supports ``-V`` as an alias for ``--version``.
``-v`` (``--verbose`` in llvm-ar) has been removed.
(`#87661 <https://github.com/llvm/llvm-project/pull/87661>`_)

* llvm-objcopy now supports ``--set-symbol-visibility`` and
``--set-symbols-visibility`` options for ELF input to change the
visibility of symbols.
Expand All @@ -182,10 +186,6 @@ Changes to the LLVM tools
for ELF input to skip the specified symbols when executing other options
that can change a symbol's name, binding or visibility.

* llvm-objcopy now supports ``--compress-sections`` to compress or decompress
arbitrary sections not within a segment.
(`#85036 <https://github.com/llvm/llvm-project/pull/85036>`_.)

* llvm-profgen now supports COFF+DWARF binaries. This enables Sample-based PGO
on Windows using Intel VTune's SEP. For details on usage, see the `end-user
documentation for SPGO
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/ADT/STLExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -2151,15 +2151,15 @@ template <typename Container, typename UnaryFunctor, typename NullaryFunctor,
!std::is_constructible<StringRef, NullaryFunctor>::value>>
inline void interleave(const Container &c, UnaryFunctor each_fn,
NullaryFunctor between_fn) {
interleave(c.begin(), c.end(), each_fn, between_fn);
interleave(adl_begin(c), adl_end(c), each_fn, between_fn);
}

/// Overload of interleave for the common case of string separator.
template <typename Container, typename UnaryFunctor, typename StreamT,
typename T = detail::ValueOfRange<Container>>
inline void interleave(const Container &c, StreamT &os, UnaryFunctor each_fn,
const StringRef &separator) {
interleave(c.begin(), c.end(), each_fn, [&] { os << separator; });
interleave(adl_begin(c), adl_end(c), each_fn, [&] { os << separator; });
}
template <typename Container, typename StreamT,
typename T = detail::ValueOfRange<Container>>
Expand Down
5 changes: 4 additions & 1 deletion llvm/include/llvm/Analysis/TargetTransformInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,10 @@ enum class TailFoldingStyle {
/// Use predicate to control both data and control flow, but modify
/// the trip count so that a runtime overflow check can be avoided
/// and such that the scalar epilogue loop can always be removed.
DataAndControlFlowWithoutRuntimeCheck
DataAndControlFlowWithoutRuntimeCheck,
/// Use predicated EVL instructions for tail-folding.
/// Indicates that VP intrinsics should be used.
DataWithEVL,
};

struct TailFoldingInfo {
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ namespace llvm {

// Top-Level Entities
bool parseTopLevelEntities();
bool finalizeDebugInfoFormat(Module *M);
void dropUnknownMetadataReferences();
bool validateEndOfModule(bool UpgradeDebugInfo);
bool validateEndOfIndex();
Expand Down
27 changes: 15 additions & 12 deletions llvm/include/llvm/CodeGen/BasicTTIImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,28 +209,31 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
Align Alignment,
bool VariableMask,
bool IsGatherScatter,
TTI::TargetCostKind CostKind) {
TTI::TargetCostKind CostKind,
unsigned AddressSpace = 0) {
// We cannot scalarize scalable vectors, so return Invalid.
if (isa<ScalableVectorType>(DataTy))
return InstructionCost::getInvalid();

auto *VT = cast<FixedVectorType>(DataTy);
unsigned VF = VT->getNumElements();

// Assume the target does not have support for gather/scatter operations
// and provide a rough estimate.
//
// First, compute the cost of the individual memory operations.
InstructionCost AddrExtractCost =
IsGatherScatter
? getVectorInstrCost(Instruction::ExtractElement,
FixedVectorType::get(
PointerType::get(VT->getElementType(), 0),
VT->getNumElements()),
CostKind, -1, nullptr, nullptr)
? getVectorInstrCost(
Instruction::ExtractElement,
FixedVectorType::get(
PointerType::get(VT->getElementType(), 0), VF),
CostKind, -1, nullptr, nullptr)
: 0;
InstructionCost LoadCost =
VT->getNumElements() *
(AddrExtractCost +
getMemoryOpCost(Opcode, VT->getElementType(), Alignment, 0, CostKind));
VF *
(AddrExtractCost + getMemoryOpCost(Opcode, VT->getElementType(),
Alignment, AddressSpace, CostKind));

// Next, compute the cost of packing the result in a vector.
InstructionCost PackingCost =
Expand All @@ -246,11 +249,10 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
// operations accurately is quite difficult and the current solution
// provides a very rough estimate only.
ConditionalCost =
VT->getNumElements() *
VF *
(getVectorInstrCost(
Instruction::ExtractElement,
FixedVectorType::get(Type::getInt1Ty(DataTy->getContext()),
VT->getNumElements()),
FixedVectorType::get(Type::getInt1Ty(DataTy->getContext()), VF),
CostKind, -1, nullptr, nullptr) +
getCFInstrCost(Instruction::Br, CostKind) +
getCFInstrCost(Instruction::PHI, CostKind));
Expand Down Expand Up @@ -1369,6 +1371,7 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
InstructionCost getMaskedMemoryOpCost(unsigned Opcode, Type *DataTy,
Align Alignment, unsigned AddressSpace,
TTI::TargetCostKind CostKind) {
// TODO: Pass on AddressSpace when we have test coverage.
return getCommonMaskedMemoryOpCost(Opcode, DataTy, Alignment, true, false,
CostKind);
}
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/BasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
/// in the new format (\p NewFlag == true), converting to the desired format
/// if necessary.
void setIsNewDbgInfoFormat(bool NewFlag);
void setNewDbgInfoFormatFlag(bool NewFlag);

/// Record that the collection of DbgRecords in \p M "trails" after the last
/// instruction of this block. These are equivalent to dbg.value intrinsics
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/IR/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ class LLVM_EXTERNAL_VISIBILITY Function : public GlobalObject,
void convertFromNewDbgValues();

void setIsNewDbgInfoFormat(bool NewVal);
void setNewDbgInfoFormatFlag(bool NewVal);

private:
friend class TargetLibraryInfoImpl;
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ def int_dx_flattened_thread_id_in_group : Intrinsic<[llvm_i32_ty], [], [IntrNoMe
def int_dx_create_handle : ClangBuiltin<"__builtin_hlsl_create_handle">,
Intrinsic<[ llvm_ptr_ty ], [llvm_i8_ty], [IntrWillReturn]>;

def int_dx_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_dx_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_dx_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_dx_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;
def int_dx_uclamp : DefaultAttrsIntrinsic<[llvm_anyint_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;

Expand Down
Loading