8 changes: 8 additions & 0 deletions clang/unittests/Format/FormatTestComments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,14 @@ TEST_F(FormatTestComments, ReflowsComments) {
"// @param arg",
getLLVMStyleWithColumns(20)));

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

// Don't reflow lines starting with 'TODO'.
EXPECT_EQ("// long long long\n"
"// long\n"
Expand Down
16 changes: 8 additions & 8 deletions compiler-rt/lib/memprof/memprof_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,8 +515,7 @@ struct Allocator {
return ptr;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

void PrintInternalAllocatorStats();

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

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

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

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

// Build-time configuration options.

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

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

#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
Expand Down
4 changes: 3 additions & 1 deletion flang/include/flang/Lower/ConvertCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ namespace Fortran::lower {
/// link to internal procedures.
/// \p isElemental must be set to true if elemental call is being produced.
/// It is only used for HLFIR.
fir::ExtendedValue genCallOpAndResult(
/// The returned boolean indicates if finalization has been emitted in
/// \p stmtCtx for the result.
std::pair<fir::ExtendedValue, bool> genCallOpAndResult(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
Fortran::lower::SymMap &symMap, Fortran::lower::StatementContext &stmtCtx,
Fortran::lower::CallerInterface &caller, mlir::FunctionType callSiteType,
Expand Down
3 changes: 2 additions & 1 deletion flang/include/flang/Optimizer/Builder/MutableBox.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ void syncMutableBoxFromIRBox(fir::FirOpBuilder &builder, mlir::Location loc,
fir::ExtendedValue genMutableBoxRead(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::MutableBoxValue &box,
bool mayBePolymorphic = true);
bool mayBePolymorphic = true,
bool preserveLowerBounds = true);

/// Returns the fir.ref<fir.box<T>> of a MutableBoxValue filled with the current
/// association / allocation properties. If the fir.ref<fir.box> already exists
Expand Down
60 changes: 43 additions & 17 deletions flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ static llvm::cl::opt<bool> useHlfirIntrinsicOps(
llvm::cl::desc("Lower via HLFIR transformational intrinsic operations such "
"as hlfir.sum"));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return args;
}

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

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

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

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

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

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

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

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

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

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

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

const auto &sectionBlocks =
std::get<Fortran::parser::OmpSectionBlocks>(sectionsConstruct.t);
Expand Down
8 changes: 6 additions & 2 deletions flang/lib/Optimizer/Builder/MutableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,22 +406,26 @@ static bool readToBoxValue(const fir::MutableBoxValue &box,
fir::ExtendedValue
fir::factory::genMutableBoxRead(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::MutableBoxValue &box,
bool mayBePolymorphic) {
bool mayBePolymorphic,
bool preserveLowerBounds) {
if (box.hasAssumedRank())
TODO(loc, "assumed rank allocatables or pointers");
llvm::SmallVector<mlir::Value> lbounds;
llvm::SmallVector<mlir::Value> extents;
llvm::SmallVector<mlir::Value> lengths;
if (readToBoxValue(box, mayBePolymorphic)) {
auto reader = MutablePropertyReader(builder, loc, box);
reader.getLowerBounds(lbounds);
if (preserveLowerBounds)
reader.getLowerBounds(lbounds);
return fir::BoxValue{reader.getIrBox(), lbounds,
box.nonDeferredLenParams()};
}
// Contiguous intrinsic type entity: all the data can be extracted from the
// fir.box.
auto addr =
MutablePropertyReader(builder, loc, box).read(lbounds, extents, lengths);
if (!preserveLowerBounds)
lbounds.clear();
auto rank = box.rank();
if (box.isCharacter()) {
auto len = lengths.empty() ? mlir::Value{} : lengths[0];
Expand Down
30 changes: 18 additions & 12 deletions flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ createArrayTemp(mlir::Location loc, fir::FirOpBuilder &builder,
return {hlfir::Entity{declareOp.getBase()}, trueVal};
}

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

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

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

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


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

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

subroutine test5
use types
Expand Down
8 changes: 8 additions & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,15 @@ set(TARGET_LIBM_ENTRYPOINTS
if(LIBC_COMPILER_HAS_FLOAT128)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float128 entrypoints
libc.src.math.ceilf128
libc.src.math.copysignf128
libc.src.math.fabsf128
libc.src.math.floorf128
libc.src.math.fmaxf128
libc.src.math.fminf128
libc.src.math.roundf128
libc.src.math.sqrtf128
libc.src.math.truncf128
)
endif()

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

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

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

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


Expand Down
1 change: 1 addition & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ add_gen_header(
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.imaxdiv_t
.llvm-libc-macros.inttypes_macros
)

add_gen_header(
Expand Down
1 change: 1 addition & 0 deletions libc/include/inttypes.h.def
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_LIBC_INTTYPES_H

#include <__llvm-libc-common.h>
#include <llvm-libc-macros/inttypes-macros.h>
#include <stdint.h>

%%public_api()
Expand Down
6 changes: 6 additions & 0 deletions libc/include/llvm-libc-macros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,9 @@ add_macro_header(
HDR
wchar-macros.h
)

add_macro_header(
inttypes_macros
HDR
inttypes-macros.h
)
289 changes: 289 additions & 0 deletions libc/include/llvm-libc-macros/inttypes-macros.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,289 @@
//===-- Definition of macros from inttypes.h ------------------------------===//
//
// 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_MACROS_INTTYPES_MACROS_H
#define __LLVM_LIBC_MACROS_INTTYPES_MACROS_H

// fprintf/scanf format macros.
// POSIX.1-2008, Technical Corrigendum 1, XBD/TC1-2008/0050 [211] is applied.

// clang provides these macros, so we don't need to define them.
// TODO: ISO C23 will provide binary notations.

#ifndef __clang__
#if __UINTPTR_MAX__ == __UINT64_MAX__
#define __PRI64 "l"
#define __PRIPTR "l"
#elif __UINTPTR_MAX__ == __UINT32_MAX__
#define __PRI64 "ll"
#define __PRIPTR ""
#else
// CHERI achitecture for example, has 128-bit pointers that use special "P"
// format.
#error "Unsupported pointer format"
#endif
#define __INT8_FMTd__ "hhd"
#define __INT16_FMTd__ "hd"
#define __INT32_FMTd__ "d"
#define __INT64_FMTd__ __PRI64 "d"
#define __INT_LEAST8_FMTd__ "hhd"
#define __INT_LEAST16_FMTd__ "hd"
#define __INT_LEAST32_FMTd__ "d"
#define __INT_LEAST64_FMTd__ __PRI64 "d"
#define __INT_FAST8_FMTd__ "hhd"
#define __INT_FAST16_FMTd__ "hd"
#define __INT_FAST32_FMTd__ "d"
#define __INT_FAST64_FMTd__ __PRI64 "d"
#define __INTMAX_FMTd__ __PRI64 "d"
#define __INTPTR_FMTd__ __PRIPTR "d"

#define __INT8_FMTi__ "hhi"
#define __INT16_FMTi__ "hi"
#define __INT32_FMTi__ "i"
#define __INT64_FMTi__ __PRI64 "i"
#define __INT_LEAST8_FMTi__ "hhi"
#define __INT_LEAST16_FMTi__ "hi"
#define __INT_LEAST32_FMTi__ "i"
#define __INT_LEAST64_FMTi__ __PRI64 "i"
#define __INT_FAST8_FMTi__ "hhi"
#define __INT_FAST16_FMTi__ "hi"
#define __INT_FAST32_FMTi__ "i"
#define __INT_FAST64_FMTi__ __PRI64 "i"
#define __INTMAX_FMTi__ __PRI64 "i"
#define __INTPTR_FMTi__ __PRIPTR "i"

#define __UINT8_FMTo__ "hho"
#define __UINT16_FMTo__ "ho"
#define __UINT32_FMTo__ "o"
#define __UINT64_FMTo__ __PRI64 "o"
#define __UINT_LEAST8_FMTo__ "hho"
#define __UINT_LEAST16_FMTo__ "ho"
#define __UINT_LEAST32_FMTo__ "o"
#define __UINT_LEAST64_FMTo__ __PRI64 "o"
#define __UINT_FAST8_FMTo__ "hho"
#define __UINT_FAST16_FMTo__ "ho"
#define __UINT_FAST32_FMTo__ "o"
#define __UINT_FAST64_FMTo__ __PRI64 "o"
#define __UINTMAX_FMTo__ __PRI64 "o"
#define __UINTPTR_FMTo__ __PRIPTR "o"

#define __UINT8_FMTu__ "hhu"
#define __UINT16_FMTu__ "hu"
#define __UINT32_FMTu__ "u"
#define __UINT64_FMTu__ __PRI64 "u"
#define __UINT_LEAST8_FMTu__ "hhu"
#define __UINT_LEAST16_FMTu__ "hu"
#define __UINT_LEAST32_FMTu__ "u"
#define __UINT_LEAST64_FMTu__ __PRI64 "u"
#define __UINT_FAST8_FMTu__ "hhu"
#define __UINT_FAST16_FMTu__ "hu"
#define __UINT_FAST32_FMTu__ "u"
#define __UINT_FAST64_FMTu__ __PRI64 "u"
#define __UINTMAX_FMTu__ __PRI64 "u"
#define __UINTPTR_FMTu__ __PRIPTR "u"

#define __UINT8_FMTx__ "hhx"
#define __UINT16_FMTx__ "hx"
#define __UINT32_FMTx__ "x"
#define __UINT64_FMTx__ __PRI64 "x"
#define __UINT_LEAST8_FMTx__ "hhx"
#define __UINT_LEAST16_FMTx__ "hx"
#define __UINT_LEAST32_FMTx__ "x"
#define __UINT_LEAST64_FMTx__ __PRI64 "x"
#define __UINT_FAST8_FMTx__ "hhx"
#define __UINT_FAST16_FMTx__ "hx"
#define __UINT_FAST32_FMTx__ "x"
#define __UINT_FAST64_FMTx__ __PRI64 "x"
#define __UINTMAX_FMTx__ __PRI64 "x"
#define __UINTPTR_FMTx__ __PRIPTR "x"

#define __UINT8_FMTX__ "hhX"
#define __UINT16_FMTX__ "hX"
#define __UINT32_FMTX__ "X"
#define __UINT64_FMTX__ __PRI64 "X"
#define __UINT_LEAST8_FMTX__ "hhX"
#define __UINT_LEAST16_FMTX__ "hX"
#define __UINT_LEAST32_FMTX__ "X"
#define __UINT_LEAST64_FMTX__ __PRI64 "X"
#define __UINT_FAST8_FMTX__ "hhX"
#define __UINT_FAST16_FMTX__ "hX"
#define __UINT_FAST32_FMTX__ "X"
#define __UINT_FAST64_FMTX__ __PRI64 "X"
#define __UINTMAX_FMTX__ __PRI64 "X"
#define __UINTPTR_FMTX__ __PRIPTR "X"
#endif

// The fprintf() macros for signed integers.
#define PRId8 __INT8_FMTd__
#define PRId16 __INT16_FMTd__
#define PRId32 __INT32_FMTd__
#define PRId64 __INT64_FMTd__
#define PRIdLEAST8 __INT_LEAST8_FMTd__
#define PRIdLEAST16 __INT_LEAST16_FMTd__
#define PRIdLEAST32 __INT_LEAST32_FMTd__
#define PRIdLEAST64 __INT_LEAST64_FMTd__
#define PRIdFAST8 __INT_FAST8_FMTd__
#define PRIdFAST16 __INT_FAST16_FMTd__
#define PRIdFAST32 __INT_FAST32_FMTd__
#define PRIdFAST64 __INT_FAST64_FMTd__
#define PRIdMAX __INTMAX_FMTd__
#define PRIdPTR __INTPTR_FMTd__

#define PRIi8 __INT8_FMTi__
#define PRIi16 __INT16_FMTi__
#define PRIi32 __INT32_FMTi__
#define PRIi64 __INT64_FMTi__
#define PRIiLEAST8 __INT_LEAST8_FMTi__
#define PRIiLEAST16 __INT_LEAST16_FMTi__
#define PRIiLEAST32 __INT_LEAST32_FMTi__
#define PRIiLEAST64 __INT_LEAST64_FMTi__
#define PRIiFAST8 __INT_FAST8_FMTi__
#define PRIiFAST16 __INT_FAST16_FMTi__
#define PRIiFAST32 __INT_FAST32_FMTi__
#define PRIiFAST64 __INT_FAST64_FMTi__
#define PRIiMAX __INTMAX_FMTi__
#define PRIiPTR __INTPTR_FMTi__

// The fprintf() macros for unsigned integers.
#define PRIo8 __UINT8_FMTo__
#define PRIo16 __UINT16_FMTo__
#define PRIo32 __UINT32_FMTo__
#define PRIo64 __UINT64_FMTo__
#define PRIoLEAST8 __UINT_LEAST8_FMTo__
#define PRIoLEAST16 __UINT_LEAST16_FMTo__
#define PRIoLEAST32 __UINT_LEAST32_FMTo__
#define PRIoLEAST64 __UINT_LEAST64_FMTo__
#define PRIoFAST8 __UINT_FAST8_FMTo__
#define PRIoFAST16 __UINT_FAST16_FMTo__
#define PRIoFAST32 __UINT_FAST32_FMTo__
#define PRIoFAST64 __UINT_FAST64_FMTo__
#define PRIoMAX __UINTMAX_FMTo__
#define PRIoPTR __UINTPTR_FMTo__

#define PRIu8 __UINT8_FMTu__
#define PRIu16 __UINT16_FMTu__
#define PRIu32 __UINT32_FMTu__
#define PRIu64 __UINT64_FMTu__
#define PRIuLEAST8 __UINT_LEAST8_FMTu__
#define PRIuLEAST16 __UINT_LEAST16_FMTu__
#define PRIuLEAST32 __UINT_LEAST32_FMTu__
#define PRIuLEAST64 __UINT_LEAST64_FMTu__
#define PRIuFAST8 __UINT_FAST8_FMTu__
#define PRIuFAST16 __UINT_FAST16_FMTu__
#define PRIuFAST32 __UINT_FAST32_FMTu__
#define PRIuFAST64 __UINT_FAST64_FMTu__
#define PRIuMAX __UINTMAX_FMTu__
#define PRIuPTR __UINTPTR_FMTu__

#define PRIx8 __UINT8_FMTx__
#define PRIx16 __UINT16_FMTx__
#define PRIx32 __UINT32_FMTx__
#define PRIx64 __UINT64_FMTx__
#define PRIxLEAST8 __UINT_LEAST8_FMTx__
#define PRIxLEAST16 __UINT_LEAST16_FMTx__
#define PRIxLEAST32 __UINT_LEAST32_FMTx__
#define PRIxLEAST64 __UINT_LEAST64_FMTx__
#define PRIxFAST8 __UINT_FAST8_FMTx__
#define PRIxFAST16 __UINT_FAST16_FMTx__
#define PRIxFAST32 __UINT_FAST32_FMTx__
#define PRIxFAST64 __UINT_FAST64_FMTx__
#define PRIxMAX __UINTMAX_FMTx__
#define PRIxPTR __UINTPTR_FMTx__

#define PRIX8 __UINT8_FMTX__
#define PRIX16 __UINT16_FMTX__
#define PRIX32 __UINT32_FMTX__
#define PRIX64 __UINT64_FMTX__
#define PRIXLEAST8 __UINT_LEAST8_FMTX__
#define PRIXLEAST16 __UINT_LEAST16_FMTX__
#define PRIXLEAST32 __UINT_LEAST32_FMTX__
#define PRIXLEAST64 __UINT_LEAST64_FMTX__
#define PRIXFAST8 __UINT_FAST8_FMTX__
#define PRIXFAST16 __UINT_FAST16_FMTX__
#define PRIXFAST32 __UINT_FAST32_FMTX__
#define PRIXFAST64 __UINT_FAST64_FMTX__
#define PRIXMAX __UINTMAX_FMTX__
#define PRIXPTR __UINTPTR_FMTX__

// The fscanf() macros for signed integers.
#define SCNd8 __INT8_FMTd__
#define SCNd16 __INT16_FMTd__
#define SCNd32 __INT32_FMTd__
#define SCNd64 __INT64_FMTd__
#define SCNdLEAST8 __INT_LEAST8_FMTd__
#define SCNdLEAST16 __INT_LEAST16_FMTd__
#define SCNdLEAST32 __INT_LEAST32_FMTd__
#define SCNdLEAST64 __INT_LEAST64_FMTd__
#define SCNdFAST8 __INT_FAST8_FMTd__
#define SCNdFAST16 __INT_FAST16_FMTd__
#define SCNdFAST32 __INT_FAST32_FMTd__
#define SCNdFAST64 __INT_FAST64_FMTd__
#define SCNdMAX __INTMAX_FMTd__
#define SCNdPTR __INTPTR_FMTd__

#define SCNi8 __INT8_FMTi__
#define SCNi16 __INT16_FMTi__
#define SCNi32 __INT32_FMTi__
#define SCNi64 __INT64_FMTi__
#define SCNiLEAST8 __INT_LEAST8_FMTi__
#define SCNiLEAST16 __INT_LEAST16_FMTi__
#define SCNiLEAST32 __INT_LEAST32_FMTi__
#define SCNiLEAST64 __INT_LEAST64_FMTi__
#define SCNiFAST8 __INT_FAST8_FMTi__
#define SCNiFAST16 __INT_FAST16_FMTi__
#define SCNiFAST32 __INT_FAST32_FMTi__
#define SCNiFAST64 __INT_FAST64_FMTi__
#define SCNiMAX __INTMAX_FMTi__
#define SCNiPTR __INTPTR_FMTi__

// The fscanf() macros for unsigned integers.
#define SCNo8 __UINT8_FMTo__
#define SCNo16 __UINT16_FMTo__
#define SCNo32 __UINT32_FMTo__
#define SCNo64 __UINT64_FMTo__
#define SCNoLEAST8 __UINT_LEAST8_FMTo__
#define SCNoLEAST16 __UINT_LEAST16_FMTo__
#define SCNoLEAST32 __UINT_LEAST32_FMTo__
#define SCNoLEAST64 __UINT_LEAST64_FMTo__
#define SCNoFAST8 __UINT_FAST8_FMTo__
#define SCNoFAST16 __UINT_FAST16_FMTo__
#define SCNoFAST32 __UINT_FAST32_FMTo__
#define SCNoFAST64 __UINT_FAST64_FMTo__
#define SCNoMAX __UINTMAX_FMTo__
#define SCNoPTR __UINTPTR_FMTo__

#define SCNu8 __UINT8_FMTu__
#define SCNu16 __UINT16_FMTu__
#define SCNu32 __UINT32_FMTu__
#define SCNu64 __UINT64_FMTu__
#define SCNuLEAST8 __UINT_LEAST8_FMTu__
#define SCNuLEAST16 __UINT_LEAST16_FMTu__
#define SCNuLEAST32 __UINT_LEAST32_FMTu__
#define SCNuLEAST64 __UINT_LEAST64_FMTu__
#define SCNuFAST8 __UINT_FAST8_FMTu__
#define SCNuFAST16 __UINT_FAST16_FMTu__
#define SCNuFAST32 __UINT_FAST32_FMTu__
#define SCNuFAST64 __UINT_FAST64_FMTu__
#define SCNuMAX __UINTMAX_FMTu__
#define SCNuPTR __UINTPTR_FMTu__

#define SCNx8 __UINT8_FMTx__
#define SCNx16 __UINT16_FMTx__
#define SCNx32 __UINT32_FMTx__
#define SCNx64 __UINT64_FMTx__
#define SCNxLEAST8 __UINT_LEAST8_FMTx__
#define SCNxLEAST16 __UINT_LEAST16_FMTx__
#define SCNxLEAST32 __UINT_LEAST32_FMTx__
#define SCNxLEAST64 __UINT_LEAST64_FMTx__
#define SCNxFAST8 __UINT_FAST8_FMTx__
#define SCNxFAST16 __UINT_FAST16_FMTx__
#define SCNxFAST32 __UINT_FAST32_FMTx__
#define SCNxFAST64 __UINT_FAST64_FMTx__
#define SCNxMAX __UINTMAX_FMTx__
#define SCNxPTR __UINTPTR_FMTx__

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

// TODO(https://github.com/llvm/llvm-project/issues/80509): support _BitInt().
#ifdef __cplusplus
inline unsigned stdc_leading_zeros(unsigned char x) {
return stdc_leading_zeros_uc(x);
Expand Down Expand Up @@ -40,6 +41,36 @@ inline unsigned stdc_leading_ones(unsigned long x) {
inline unsigned stdc_leading_ones(unsigned long long x) {
return stdc_leading_ones_ull(x);
}
inline unsigned stdc_trailing_zeros(unsigned char x) {
return stdc_trailing_zeros_uc(x);
}
inline unsigned stdc_trailing_zeros(unsigned short x) {
return stdc_trailing_zeros_us(x);
}
inline unsigned stdc_trailing_zeros(unsigned x) {
return stdc_trailing_zeros_ui(x);
}
inline unsigned stdc_trailing_zeros(unsigned long x) {
return stdc_trailing_zeros_ul(x);
}
inline unsigned stdc_trailing_zeros(unsigned long long x) {
return stdc_trailing_zeros_ull(x);
}
inline unsigned stdc_trailing_ones(unsigned char x) {
return stdc_trailing_ones_uc(x);
}
inline unsigned stdc_trailing_ones(unsigned short x) {
return stdc_trailing_ones_us(x);
}
inline unsigned stdc_trailing_ones(unsigned x) {
return stdc_trailing_ones_ui(x);
}
inline unsigned stdc_trailing_ones(unsigned long x) {
return stdc_trailing_ones_ul(x);
}
inline unsigned stdc_trailing_ones(unsigned long long x) {
return stdc_trailing_ones_ull(x);
}
#else
#define stdc_leading_zeros(x) \
_Generic((x), \
Expand All @@ -55,6 +86,20 @@ inline unsigned stdc_leading_ones(unsigned long long x) {
unsigned: stdc_leading_ones_ui, \
unsigned long: stdc_leading_ones_ul, \
unsigned long long: stdc_leading_ones_ull)(x)
#define stdc_trailing_zeros(x) \
_Generic((x), \
unsigned char: stdc_trailing_zeros_uc, \
unsigned short: stdc_trailing_zeros_us, \
unsigned: stdc_trailing_zeros_ui, \
unsigned long: stdc_trailing_zeros_ul, \
unsigned long long: stdc_trailing_zeros_ull)(x)
#define stdc_trailing_ones(x) \
_Generic((x), \
unsigned char: stdc_trailing_ones_uc, \
unsigned short: stdc_trailing_ones_us, \
unsigned: stdc_trailing_ones_ui, \
unsigned long: stdc_trailing_ones_ul, \
unsigned long long: stdc_trailing_ones_ull)(x)
#endif // __cplusplus

#endif // __LLVM_LIBC_MACROS_STDBIT_MACROS_H
17 changes: 15 additions & 2 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,10 @@ def StdC : StandardSpec<"stdc"> {
HeaderSpec StdBit = HeaderSpec<
"stdbit.h",
[
Macro<"stdc_leading_zeros">
Macro<"stdc_leading_zeros">,
Macro<"stdc_leading_ones">,
Macro<"stdc_trailing_zeros">,
Macro<"stdc_trailing_ones">
], // Macros
[], // Types
[], // Enumerations
Expand All @@ -789,7 +792,17 @@ def StdC : StandardSpec<"stdc"> {
FunctionSpec<"stdc_leading_ones_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
FunctionSpec<"stdc_leading_ones_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"stdc_leading_ones_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
FunctionSpec<"stdc_leading_ones_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
FunctionSpec<"stdc_leading_ones_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>,
FunctionSpec<"stdc_trailing_zeros_uc", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedCharType>]>,
FunctionSpec<"stdc_trailing_zeros_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
FunctionSpec<"stdc_trailing_zeros_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"stdc_trailing_zeros_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
FunctionSpec<"stdc_trailing_zeros_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>,
FunctionSpec<"stdc_trailing_ones_uc", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedCharType>]>,
FunctionSpec<"stdc_trailing_ones_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
FunctionSpec<"stdc_trailing_ones_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
FunctionSpec<"stdc_trailing_ones_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
FunctionSpec<"stdc_trailing_ones_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
] // Functions
>;

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

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

add_header_library(
sqrt
HDRS
Expand Down
180 changes: 0 additions & 180 deletions libc/src/__support/FPUtil/XFloat.h

This file was deleted.

6 changes: 5 additions & 1 deletion libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,8 @@ template <> class FloatToString<long double> {
int int_block_index = 0;

static constexpr size_t BLOCK_BUFFER_LEN =
internal::div_ceil(internal::log10_pow2(FLOAT_AS_INT_WIDTH), BLOCK_SIZE);
internal::div_ceil(internal::log10_pow2(FLOAT_AS_INT_WIDTH), BLOCK_SIZE) +
1;
BlockInt block_buffer[BLOCK_BUFFER_LEN] = {0};
size_t block_buffer_valid = 0;

Expand Down Expand Up @@ -693,6 +694,7 @@ template <> class FloatToString<long double> {
int_block_index = 0;

while (float_as_int > 0) {
LIBC_ASSERT(int_block_index < static_cast<int>(BLOCK_BUFFER_LEN));
block_buffer[int_block_index] = grab_digits(float_as_int);
++int_block_index;
}
Expand Down Expand Up @@ -785,6 +787,8 @@ template <> class FloatToString<long double> {
if (block_index > static_cast<int>(block_buffer_valid) || block_index < 0)
return 0;

LIBC_ASSERT(block_index < static_cast<int>(BLOCK_BUFFER_LEN));

return block_buffer[block_index];
}

Expand Down
2 changes: 1 addition & 1 deletion libc/src/errno/libc_errno.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,5 @@ LIBC_NAMESPACE::Errno::operator int() { return errno; }

namespace LIBC_NAMESPACE {
// Define the global `libc_errno` instance.
LIBC_NAMESPACE::Errno libc_errno;
Errno libc_errno;
} // namespace LIBC_NAMESPACE
2 changes: 1 addition & 1 deletion libc/src/errno/libc_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct Errno {
operator int();
};

extern LIBC_NAMESPACE::Errno libc_errno;
extern Errno libc_errno;

} // namespace LIBC_NAMESPACE

Expand Down
119 changes: 20 additions & 99 deletions libc/src/stdbit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,99 +1,20 @@
add_entrypoint_object(
stdc_leading_zeros_uc
SRCS
stdc_leading_zeros_uc.cpp
HDRS
stdc_leading_zeros_uc.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_zeros_us
SRCS
stdc_leading_zeros_us.cpp
HDRS
stdc_leading_zeros_us.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_zeros_ui
SRCS
stdc_leading_zeros_ui.cpp
HDRS
stdc_leading_zeros_ui.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_zeros_ul
SRCS
stdc_leading_zeros_ul.cpp
HDRS
stdc_leading_zeros_ul.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_zeros_ull
SRCS
stdc_leading_zeros_ull.cpp
HDRS
stdc_leading_zeros_ull.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_ones_uc
SRCS
stdc_leading_ones_uc.cpp
HDRS
stdc_leading_ones_uc.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_ones_us
SRCS
stdc_leading_ones_us.cpp
HDRS
stdc_leading_ones_us.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_ones_ui
SRCS
stdc_leading_ones_ui.cpp
HDRS
stdc_leading_ones_ui.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_ones_ul
SRCS
stdc_leading_ones_ul.cpp
HDRS
stdc_leading_ones_ul.h
DEPENDS
libc.src.__support.CPP.bit
)

add_entrypoint_object(
stdc_leading_ones_ull
SRCS
stdc_leading_ones_ull.cpp
HDRS
stdc_leading_ones_ull.h
DEPENDS
libc.src.__support.CPP.bit
)
set(prefixes
leading_zeros
leading_ones
trailing_zeros
trailing_ones
)
set(suffixes c s i l ll)
foreach(prefix IN LISTS prefixes)
foreach(suffix IN LISTS suffixes)
add_entrypoint_object(
stdc_${prefix}_u${suffix}
SRCS
stdc_${prefix}_u${suffix}.cpp
HDRS
stdc_${prefix}_u${suffix}.h
DEPENDS
libc.src.__support.CPP.bit
)
endforeach()
endforeach()
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_uc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_uc ---------------------------===//
//
// 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/stdbit/stdc_trailing_ones_uc.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_uc, (unsigned char value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_uc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_uc --------*- 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_STDBIT_STDC_TRAILING_ONES_UC_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UC_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_uc(unsigned char value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UC_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_ui ---------------------------===//
//
// 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/stdbit/stdc_trailing_ones_ui.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ui, (unsigned value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ui --------*- 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_STDBIT_STDC_TRAILING_ONES_UI_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UI_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ui(unsigned value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UI_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ul.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_ul ---------------------------===//
//
// 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/stdbit/stdc_trailing_ones_ul.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ul, (unsigned long value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ul.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ul --------*- 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_STDBIT_STDC_TRAILING_ONES_UL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ul(unsigned long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_UL_H
21 changes: 21 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ull.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation of stdc_trailing_ones_ull --------------------------===//
//
// 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/stdbit/stdc_trailing_ones_ull.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_ull,
(unsigned long long value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_ull.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_ull --------*- 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_STDBIT_STDC_TRAILING_ONES_ULL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_ULL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_ull(unsigned long long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_ULL_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_us.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_ones_us ---------------------------===//
//
// 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/stdbit/stdc_trailing_ones_us.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_ones_us, (unsigned short value)) {
return static_cast<unsigned>(cpp::countr_one(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_ones_us.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_ones_us --------*- 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_STDBIT_STDC_TRAILING_ONES_US_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_US_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_ones_us(unsigned short value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ONES_US_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_uc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_zeros_uc --------------------------===//
//
// 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/stdbit/stdc_trailing_zeros_uc.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_zeros_uc, (unsigned char value)) {
return static_cast<unsigned>(cpp::countr_zero(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_uc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_zeros_uc --------*- 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_STDBIT_STDC_TRAILING_ZEROS_UC_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UC_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_zeros_uc(unsigned char value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UC_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_zeros_ui --------------------------===//
//
// 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/stdbit/stdc_trailing_zeros_ui.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_zeros_ui, (unsigned value)) {
return static_cast<unsigned>(cpp::countr_zero(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_zeros_ui --------*- 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_STDBIT_STDC_TRAILING_ZEROS_UI_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UI_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_zeros_ui(unsigned value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UI_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ul.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_zeros_ul --------------------------===//
//
// 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/stdbit/stdc_trailing_zeros_ul.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_zeros_ul, (unsigned long value)) {
return static_cast<unsigned>(cpp::countr_zero(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ul.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_zeros_ul --------*- 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_STDBIT_STDC_TRAILING_ZEROS_UL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_zeros_ul(unsigned long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_UL_H
21 changes: 21 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ull.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation of stdc_trailing_zeros_ull -------------------------===//
//
// 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/stdbit/stdc_trailing_zeros_ull.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_zeros_ull,
(unsigned long long value)) {
return static_cast<unsigned>(cpp::countr_zero(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_ull.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_zeros_ull -------*- 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_STDBIT_STDC_TRAILING_ZEROS_ULL_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_ULL_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_zeros_ull(unsigned long long value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_ULL_H
20 changes: 20 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_us.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation of stdc_trailing_zeros_us --------------------------===//
//
// 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/stdbit/stdc_trailing_zeros_us.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned, stdc_trailing_zeros_us, (unsigned short value)) {
return static_cast<unsigned>(cpp::countr_zero(value));
}

} // namespace LIBC_NAMESPACE
18 changes: 18 additions & 0 deletions libc/src/stdbit/stdc_trailing_zeros_us.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//===-- Implementation header for stdc_trailing_zeros_us --------*- 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_STDBIT_STDC_TRAILING_ZEROS_US_H
#define LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_US_H

namespace LIBC_NAMESPACE {

unsigned stdc_trailing_zeros_us(unsigned short value);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDBIT_STDC_TRAILING_ZEROS_US_H
2 changes: 2 additions & 0 deletions libc/src/stdio/printf_core/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ int convert(Writer *writer, const FormatSection &to_conv) {
case 'o':
case 'x':
case 'X':
case 'b':
case 'B':
return convert_int(writer, to_conv);
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
case 'f':
Expand Down
22 changes: 16 additions & 6 deletions libc/src/stdio/printf_core/int_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ using HexFmt = IntegerToString<uintmax_t, radix::Hex>;
using HexFmtUppercase = IntegerToString<uintmax_t, radix::Hex::Uppercase>;
using OctFmt = IntegerToString<uintmax_t, radix::Oct>;
using DecFmt = IntegerToString<uintmax_t>;
using BinFmt = IntegerToString<uintmax_t, radix::Bin>;

LIBC_INLINE constexpr size_t num_buf_size() {
constexpr auto max = [](size_t a, size_t b) -> size_t {
return (a < b) ? b : a;
};
return max(HexFmt::buffer_size(),
max(HexFmtUppercase::buffer_size(),
max(OctFmt::buffer_size(), DecFmt::buffer_size())));
cpp::array<size_t, 5> sizes{
HexFmt::buffer_size(), HexFmtUppercase::buffer_size(),
OctFmt::buffer_size(), DecFmt::buffer_size(), BinFmt::buffer_size()};

auto result = sizes[0];
for (size_t i = 1; i < sizes.size(); i++)
result = cpp::max(result, sizes[i]);
return result;
}

LIBC_INLINE cpp::optional<cpp::string_view>
Expand All @@ -52,6 +55,8 @@ num_to_strview(uintmax_t num, cpp::span<char> bufref, char conv_name) {
return HexFmtUppercase::format_to(bufref, num);
} else if (conv_name == 'o') {
return OctFmt::format_to(bufref, num);
} else if (to_lower(conv_name) == 'b') {
return BinFmt::format_to(bufref, num);
} else {
return DecFmt::format_to(bufref, num);
}
Expand Down Expand Up @@ -116,6 +121,11 @@ LIBC_INLINE int convert_int(Writer *writer, const FormatSection &to_conv) {
prefix_len = 2;
prefix[0] = '0';
prefix[1] = a + ('x' - 'a');
} else if ((to_lower(to_conv.conv_name) == 'b') &&
((flags & FormatFlags::ALTERNATE_FORM) != 0) && num != 0) {
prefix_len = 2;
prefix[0] = '0';
prefix[1] = a + ('b' - 'a');
} else {
prefix_len = (sign_char == 0 ? 0 : 1);
prefix[0] = sign_char;
Expand Down
4 changes: 4 additions & 0 deletions libc/src/stdio/printf_core/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
case ('b'):
case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
Expand Down Expand Up @@ -484,6 +486,8 @@ template <typename ArgProvider> class Parser {
case ('x'):
case ('X'):
case ('u'):
case ('b'):
case ('B'):
switch (lm) {
case (LengthModifier::hh):
case (LengthModifier::h):
Expand Down
2 changes: 2 additions & 0 deletions libc/src/unistd/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ add_entrypoint_object(
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.__support.macros.sanitizer
libc.src.errno.errno
)

Expand All @@ -309,6 +310,7 @@ add_entrypoint_object(
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.__support.macros.sanitizer
libc.src.errno.errno
)

Expand Down
5 changes: 4 additions & 1 deletion libc/src/unistd/linux/pread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"

#include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON
#include "src/errno/libc_errno.h"
#include <stdint.h> // For uint64_t.
#include <sys/syscall.h> // For syscall numbers.
Expand All @@ -28,6 +28,9 @@ LLVM_LIBC_FUNCTION(ssize_t, pread,
ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pread64, fd, buf,
count, offset);
#endif
// The cast is important since there is a check that dereferences the pointer
// which fails on void*.
MSAN_UNPOISON(reinterpret_cast<char *>(buf), count);
if (ret < 0) {
libc_errno = static_cast<int>(-ret);
return -1;
Expand Down
26 changes: 26 additions & 0 deletions libc/test/include/stdbit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ unsigned stdc_leading_ones_us(unsigned short) noexcept { return 0xBBU; }
unsigned stdc_leading_ones_ui(unsigned) noexcept { return 0xBCU; }
unsigned stdc_leading_ones_ul(unsigned long) noexcept { return 0xBDU; }
unsigned stdc_leading_ones_ull(unsigned long long) noexcept { return 0xBFU; }
unsigned stdc_trailing_zeros_uc(unsigned char) noexcept { return 0xCAU; }
unsigned stdc_trailing_zeros_us(unsigned short) noexcept { return 0xCBU; }
unsigned stdc_trailing_zeros_ui(unsigned) noexcept { return 0xCCU; }
unsigned stdc_trailing_zeros_ul(unsigned long) noexcept { return 0xCDU; }
unsigned stdc_trailing_zeros_ull(unsigned long long) noexcept { return 0xCFU; }
unsigned stdc_trailing_ones_uc(unsigned char) noexcept { return 0xDAU; }
unsigned stdc_trailing_ones_us(unsigned short) noexcept { return 0xDBU; }
unsigned stdc_trailing_ones_ui(unsigned) noexcept { return 0xDCU; }
unsigned stdc_trailing_ones_ul(unsigned long) noexcept { return 0xDDU; }
unsigned stdc_trailing_ones_ull(unsigned long long) noexcept { return 0xDFU; }
}

#include "include/llvm-libc-macros/stdbit-macros.h"
Expand All @@ -52,3 +62,19 @@ TEST(LlvmLibcStdbitTest, TypeGenericMacroLeadingOnes) {
EXPECT_EQ(stdc_leading_ones(0UL), 0xBDU);
EXPECT_EQ(stdc_leading_ones(0ULL), 0xBFU);
}

TEST(LlvmLibcStdbitTest, TypeGenericMacroTrailingZeros) {
EXPECT_EQ(stdc_trailing_zeros(static_cast<unsigned char>(0U)), 0xCAU);
EXPECT_EQ(stdc_trailing_zeros(static_cast<unsigned short>(0U)), 0xCBU);
EXPECT_EQ(stdc_trailing_zeros(0U), 0xCCU);
EXPECT_EQ(stdc_trailing_zeros(0UL), 0xCDU);
EXPECT_EQ(stdc_trailing_zeros(0ULL), 0xCFU);
}

TEST(LlvmLibcStdbitTest, TypeGenericMacroTrailingOnes) {
EXPECT_EQ(stdc_trailing_ones(static_cast<unsigned char>(0U)), 0xDAU);
EXPECT_EQ(stdc_trailing_ones(static_cast<unsigned short>(0U)), 0xDBU);
EXPECT_EQ(stdc_trailing_ones(0U), 0xDCU);
EXPECT_EQ(stdc_trailing_ones(0UL), 0xDDU);
EXPECT_EQ(stdc_trailing_ones(0ULL), 0xDFU);
}
Loading