From 569716fc5c2c232adcd5ff840637be596c1de9b9 Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Wed, 14 Jun 2023 13:23:00 +0000 Subject: [PATCH 001/130] [flang][hlfir] Fix multiple return declaration type When the ENTRY statement is used, the same source can return different types depending on the entry point. These different return values are storage associated (share the same storage). Previously, this led to the declaration of the results to all have the largest type. This patch adds a convert between the stack allocation and the declaration so that the hlfir.decl gets the right type. I haven't managed to generate code where this convert converted a reference to an allocation for a smaller type into an allocation for a larger one, but I have added an assert just in case. This is a different solution to https://reviews.llvm.org/D152725, see discussion there. Differential Revision: https://reviews.llvm.org/D152931 --- flang/lib/Lower/Bridge.cpp | 32 ++++++++- flang/test/Lower/HLFIR/entry_return.f90 | 86 +++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 flang/test/Lower/HLFIR/entry_return.f90 diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index ee21d63c02333..f3efbfaa2dc21 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -3993,8 +3993,38 @@ class FirConverter : public Fortran::lower::AbstractConverter { Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols, stmtCtx); } else { + // catch cases where the allocation for the function result storage type + // doesn't match the type of this symbol + mlir::Value preAlloc = primaryFuncResultStorage; + mlir::Type resTy = primaryFuncResultStorage.getType(); + mlir::Type symTy = genType(altResult); + mlir::Type wrappedSymTy = fir::ReferenceType::get(symTy); + if (resTy != wrappedSymTy) { + // check size of the pointed to type so we can't overflow by writing + // double precision to a single precision allocation, etc + LLVM_ATTRIBUTE_UNUSED auto getBitWidth = [this](mlir::Type ty) { + // 15.6.2.6.3: differering result types should be integer, real, + // complex or logical + if (auto cmplx = mlir::dyn_cast_or_null(ty)) { + fir::KindTy kind = cmplx.getFKind(); + return 2 * builder->getKindMap().getRealBitsize(kind); + } + if (auto logical = mlir::dyn_cast_or_null(ty)) { + fir::KindTy kind = logical.getFKind(); + return builder->getKindMap().getLogicalBitsize(kind); + } + return ty.getIntOrFloatBitWidth(); + }; + assert(getBitWidth(fir::unwrapRefType(resTy)) >= getBitWidth(symTy)); + + // convert the storage to the symbol type so that the hlfir.declare + // gets the correct type for this symbol + preAlloc = builder->create(getCurrentLocation(), + wrappedSymTy, preAlloc); + } + Fortran::lower::mapSymbolAttributes(*this, altResult, localSymbols, - stmtCtx, primaryFuncResultStorage); + stmtCtx, preAlloc); } } diff --git a/flang/test/Lower/HLFIR/entry_return.f90 b/flang/test/Lower/HLFIR/entry_return.f90 new file mode 100644 index 0000000000000..d2fb80c8b97b7 --- /dev/null +++ b/flang/test/Lower/HLFIR/entry_return.f90 @@ -0,0 +1,86 @@ +! RUN: bbc -emit-hlfir -o - %s | FileCheck %s +! test multiple return values with different types coming from ENTRY statements + +complex function f1() + logical e1 + entry e1() + e1 = .false. +end function +! CHECK-LABEL: func.func @_QPf1() -> !fir.complex<4> { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.complex<4> {bindc_name = "f1", uniq_name = "_QFf1Ef1"} +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFf1Ef1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFf1Ee1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: cf.br ^bb1 +! CHECK: ^bb1: +! CHECK: %[[VAL_4:.*]] = arith.constant false +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i1) -> !fir.logical<4> +! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_3]]#0 : !fir.logical<4>, !fir.ref> +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref> +! CHECK: return %[[VAL_6]] : !fir.complex<4> +! CHECK: } + +! // CHECK-LABEL: func.func @_QPe1() -> !fir.logical<4> { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.complex<4> {bindc_name = "f1", uniq_name = "_QFf1Ef1"} +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFf1Ef1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFf1Ee1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: cf.br ^bb1 +! CHECK: ^bb1: +! CHECK: %[[VAL_4:.*]] = arith.constant false +! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (i1) -> !fir.logical<4> +! CHECK: hlfir.assign %[[VAL_5]] to %[[VAL_3]]#0 : !fir.logical<4>, !fir.ref> +! CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_3]]#1 : !fir.ref> +! CHECK: return %[[VAL_6]] : !fir.logical<4> +! CHECK: } + +logical function f2() + complex e2 + entry e2() + e2 = complex(1.0, 2.0) +end function +! CHECK-LABEL: func.func @_QPf2() -> !fir.logical<4> { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.complex<4> {bindc_name = "e2", uniq_name = "_QFf2Ee2"} +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFf2Ee2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFf2Ef2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: cf.br ^bb1 +! CHECK: ^bb1: +! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 +! CHECK: %[[VAL_5:.*]] = arith.constant 2.000000e+00 : f32 +! CHECK: %[[VAL_6:.*]]:3 = hlfir.associate %[[VAL_4]] {uniq_name = "adapt.valuebyref"} : (f32) -> (!fir.ref, !fir.ref, i1) +! CHECK: %[[VAL_7:.*]]:3 = hlfir.associate %[[VAL_5]] {uniq_name = "adapt.valuebyref"} : (f32) -> (!fir.ref, !fir.ref, i1) +! CHECK: %[[VAL_8:.*]] = fir.call @_QPcomplex(%[[VAL_6]]#1, %[[VAL_7]]#1) fastmath : (!fir.ref, !fir.ref) -> f32 +! CHECK: hlfir.end_associate %[[VAL_6]]#1, %[[VAL_6]]#2 : !fir.ref, i1 +! CHECK: hlfir.end_associate %[[VAL_7]]#1, %[[VAL_7]]#2 : !fir.ref, i1 +! CHECK: %[[VAL_9:.*]] = arith.constant 0.000000e+00 : f32 +! CHECK: %[[VAL_10:.*]] = fir.undefined !fir.complex<4> +! CHECK: %[[VAL_11:.*]] = fir.insert_value %[[VAL_10]], %[[VAL_8]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4> +! CHECK: %[[VAL_12:.*]] = fir.insert_value %[[VAL_11]], %[[VAL_9]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4> +! CHECK: hlfir.assign %[[VAL_12]] to %[[VAL_1]]#0 : !fir.complex<4>, !fir.ref> +! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_3]]#1 : !fir.ref> +! CHECK: return %[[VAL_13]] : !fir.logical<4> +! CHECK: } + +! CHECK-LABEL: func.func @_QPe2() -> !fir.complex<4> { +! CHECK: %[[VAL_0:.*]] = fir.alloca !fir.complex<4> {bindc_name = "e2", uniq_name = "_QFf2Ee2"} +! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFf2Ee2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#1 : (!fir.ref>) -> !fir.ref> +! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFf2Ef2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: cf.br ^bb1 +! CHECK: ^bb1: +! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 +! CHECK: %[[VAL_5:.*]] = arith.constant 2.000000e+00 : f32 +! CHECK: %[[VAL_6:.*]]:3 = hlfir.associate %[[VAL_4]] {uniq_name = "adapt.valuebyref"} : (f32) -> (!fir.ref, !fir.ref, i1) +! CHECK: %[[VAL_7:.*]]:3 = hlfir.associate %[[VAL_5]] {uniq_name = "adapt.valuebyref"} : (f32) -> (!fir.ref, !fir.ref, i1) +! CHECK: %[[VAL_8:.*]] = fir.call @_QPcomplex(%[[VAL_6]]#1, %[[VAL_7]]#1) fastmath : (!fir.ref, !fir.ref) -> f32 +! CHECK: hlfir.end_associate %[[VAL_6]]#1, %[[VAL_6]]#2 : !fir.ref, i1 +! CHECK: hlfir.end_associate %[[VAL_7]]#1, %[[VAL_7]]#2 : !fir.ref, i1 +! CHECK: %[[VAL_9:.*]] = arith.constant 0.000000e+00 : f32 +! CHECK: %[[VAL_10:.*]] = fir.undefined !fir.complex<4> +! CHECK: %[[VAL_11:.*]] = fir.insert_value %[[VAL_10]], %[[VAL_8]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4> +! CHECK: %[[VAL_12:.*]] = fir.insert_value %[[VAL_11]], %[[VAL_9]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4> +! CHECK: hlfir.assign %[[VAL_12]] to %[[VAL_1]]#0 : !fir.complex<4>, !fir.ref> +! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref> +! CHECK: return %[[VAL_13]] : !fir.complex<4> +! CHECK: } From f523b9a55a3adecf1a8373ca7525630bdd7fb5ef Mon Sep 17 00:00:00 2001 From: Tom Eccles Date: Wed, 14 Jun 2023 16:23:40 +0000 Subject: [PATCH 002/130] [flang] don't allow conversions between logical and floating point Codegen only supports conversions between logicals and integers. The verifier should reflect this. Differential Revision: https://reviews.llvm.org/D152935 --- flang/include/flang/Optimizer/Dialect/FIROps.td | 1 + flang/lib/Optimizer/Dialect/FIROps.cpp | 11 +++++++---- flang/test/Fir/invalid.fir | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index c9d68f1e1cf90..8b05c97360607 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -2606,6 +2606,7 @@ def fir_ConvertOp : fir_OneResultOp<"convert", [NoMemoryEffect]> { let hasVerifier = 1; let extraClassDeclaration = [{ + static bool isInteger(mlir::Type ty); static bool isIntegerCompatible(mlir::Type ty); static bool isFloatCompatible(mlir::Type ty); static bool isPointerCompatible(mlir::Type ty); diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index e796f2c385d95..7f899a2937987 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -928,9 +928,12 @@ mlir::OpFoldResult fir::ConvertOp::fold(FoldAdaptor adaptor) { return {}; } +bool fir::ConvertOp::isInteger(mlir::Type ty) { + return ty.isa(); +} + bool fir::ConvertOp::isIntegerCompatible(mlir::Type ty) { - return ty.isa(); + return isInteger(ty) || mlir::isa(ty); } bool fir::ConvertOp::isFloatCompatible(mlir::Type ty) { @@ -1001,8 +1004,8 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) { return true; return (isPointerCompatible(inType) && isPointerCompatible(outType)) || (isIntegerCompatible(inType) && isIntegerCompatible(outType)) || - (isIntegerCompatible(inType) && isFloatCompatible(outType)) || - (isFloatCompatible(inType) && isIntegerCompatible(outType)) || + (isInteger(inType) && isFloatCompatible(outType)) || + (isFloatCompatible(inType) && isInteger(outType)) || (isFloatCompatible(inType) && isFloatCompatible(outType)) || (isIntegerCompatible(inType) && isPointerCompatible(outType)) || (isPointerCompatible(inType) && isIntegerCompatible(outType)) || diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index c01bcc809d341..c3bfb6922deda 100644 --- a/flang/test/Fir/invalid.fir +++ b/flang/test/Fir/invalid.fir @@ -946,3 +946,19 @@ func.func @invalid_selector(%arg : !fir.box>) -> i32 { %zero = arith.constant 0 : i32 return %zero : i32 } + +// ----- + +func.func @logical_to_fp(%arg0: !fir.logical<4>) -> f32 { + // expected-error@+1{{'fir.convert' op invalid type conversion}} + %0 = fir.convert %arg0 : (!fir.logical<4>) -> f32 + return %0 : f32 +} + +// ----- + +func.func @fp_to_logical(%arg0: f32) -> !fir.logical<4> { + // expected-error@+1{{'fir.convert' op invalid type conversion}} + %0 = fir.convert %arg0 : (f32) -> !fir.logical<4> + return %0 : !fir.logical<4> +} From 3f8d8c1aac3086f603ad73f18fe2bd4fb91fa10a Mon Sep 17 00:00:00 2001 From: Jacob Crawley Date: Mon, 12 Jun 2023 12:52:47 +0000 Subject: [PATCH 003/130] [flang][hlfir] Add hlfir.count intrinsic Adds a new HLFIR operation for the COUNT intrinsic according to the design set out in flang/docs/HighLevel.md. This patch includes all the necessary changes to create a new HLFIR operation and lower it into the fir runtime call. Author was @jacob-crawley. Minor adjustments by @tblah Differential Revision: https://reviews.llvm.org/D152521 --- .../include/flang/Optimizer/HLFIR/HLFIROps.td | 23 ++- flang/lib/Lower/ConvertCall.cpp | 12 ++ flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp | 37 ++++ .../HLFIR/Transforms/LowerHLFIRIntrinsics.cpp | 37 +++- flang/test/HLFIR/count-lowering.fir | 164 ++++++++++++++++++ flang/test/HLFIR/count.fir | 83 +++++++++ flang/test/HLFIR/invalid.fir | 24 +++ flang/test/Lower/HLFIR/count.f90 | 82 +++++++++ 8 files changed, 459 insertions(+), 3 deletions(-) create mode 100644 flang/test/HLFIR/count-lowering.fir create mode 100644 flang/test/HLFIR/count.fir create mode 100644 flang/test/Lower/HLFIR/count.f90 diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td index 2dd85a2c5c181..beb50a48d86df 100644 --- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td +++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td @@ -359,6 +359,27 @@ def hlfir_AnyOp : hlfir_Op<"any", []> { let hasVerifier = 1; } +def hlfir_CountOp : hlfir_Op<"count", [AttrSizedOperandSegments]> { + let summary = "COUNT transformational intrinsic"; + let description = [{ + Takes a logical and counts the number of true values. + }]; + + let arguments = (ins + AnyFortranLogicalArrayObject:$mask, + Optional:$dim, + Optional:$kind + ); + + let results = (outs AnyFortranValue); + + let assemblyFormat = [{ + $mask (`dim` $dim^)? (`kind` $kind^)? attr-dict `:` functional-type(operands, results) + }]; + + let hasVerifier = 1; +} + def hlfir_ProductOp : hlfir_Op<"product", [AttrSizedOperandSegments, DeclareOpInterfaceMethods]> { @@ -430,7 +451,7 @@ def hlfir_SumOp : hlfir_Op<"sum", [AttrSizedOperandSegments, let hasVerifier = 1; } -def hlifr_DotProductOp : hlfir_Op<"dot_product", +def hlfir_DotProductOp : hlfir_Op<"dot_product", [DeclareOpInterfaceMethods]> { let summary = "DOT_PRODUCT transformational intrinsic"; let description = [{ diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp index 604291cdbec6d..4f4505c8b0664 100644 --- a/flang/lib/Lower/ConvertCall.cpp +++ b/flang/lib/Lower/ConvertCall.cpp @@ -1497,6 +1497,18 @@ genHLFIRIntrinsicRefCore(PreparedActualArguments &loweredActuals, return {hlfir::EntityWithAttributes{dotProductOp.getResult()}}; } + if (intrinsicName == "count") { + llvm::SmallVector operands = getOperandVector(loweredActuals); + mlir::Value array = operands[0]; + mlir::Value dim = operands[1]; + if (dim) + dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim}); + mlir::Value kind = operands[2]; + mlir::Type resultTy = computeResultType(array, *callContext.resultType); + hlfir::CountOp countOp = + builder.create(loc, resultTy, array, dim, kind); + return {hlfir::EntityWithAttributes{countOp.getResult()}}; + } // TODO add hlfir operations for other transformational intrinsics here diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp index 7a00bfae75ed1..21a44c07953b6 100644 --- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp +++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp @@ -509,6 +509,43 @@ mlir::LogicalResult hlfir::AnyOp::verify() { return verifyLogicalReductionOp(this); } +//===----------------------------------------------------------------------===// +// CountOp +//===----------------------------------------------------------------------===// + +mlir::LogicalResult hlfir::CountOp::verify() { + mlir::Operation *op = getOperation(); + + auto results = op->getResultTypes(); + assert(results.size() == 1); + mlir::Value mask = getMask(); + mlir::Value dim = getDim(); + + fir::SequenceType maskTy = + hlfir::getFortranElementOrSequenceType(mask.getType()) + .cast(); + llvm::ArrayRef maskShape = maskTy.getShape(); + + mlir::Type resultType = results[0]; + if (auto resultExpr = mlir::dyn_cast_or_null(resultType)) { + if (maskShape.size() > 1 && dim != nullptr) { + if (!resultExpr.isArray()) + return emitOpError("result must be an array"); + + llvm::ArrayRef resultShape = resultExpr.getShape(); + // Result has rank n-1 + if (resultShape.size() != (maskShape.size() - 1)) + return emitOpError("result rank must be one less than MASK"); + } else { + return emitOpError("result must be of numerical scalar type"); + } + } else if (!hlfir::isFortranScalarNumericalType(resultType)) { + return emitOpError("result must be of numerical scalar type"); + } + + return mlir::success(); +} + //===----------------------------------------------------------------------===// // ConcatOp //===----------------------------------------------------------------------===// diff --git a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp index b88b30e235a15..d3c604e249a9c 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/LowerHLFIRIntrinsics.cpp @@ -262,6 +262,39 @@ using AnyOpConversion = HlfirReductionIntrinsicConversion; using AllOpConversion = HlfirReductionIntrinsicConversion; +struct CountOpConversion : public HlfirIntrinsicConversion { + using HlfirIntrinsicConversion::HlfirIntrinsicConversion; + + mlir::LogicalResult + matchAndRewrite(hlfir::CountOp count, + mlir::PatternRewriter &rewriter) const override { + fir::KindMapping kindMapping{rewriter.getContext()}; + fir::FirOpBuilder builder{rewriter, kindMapping}; + const mlir::Location &loc = count->getLoc(); + + mlir::Type i32 = builder.getI32Type(); + mlir::Type logicalType = fir::LogicalType::get( + builder.getContext(), builder.getKindMap().defaultLogicalKind()); + + llvm::SmallVector inArgs; + inArgs.push_back({count.getMask(), logicalType}); + inArgs.push_back({count.getDim(), i32}); + inArgs.push_back({count.getKind(), i32}); + + auto *argLowering = fir::getIntrinsicArgumentLowering("count"); + llvm::SmallVector args = + lowerArguments(count, inArgs, rewriter, argLowering); + + mlir::Type scalarResultType = hlfir::getFortranElementType(count.getType()); + + auto [resultExv, mustBeFreed] = + fir::genIntrinsicCall(builder, loc, "count", scalarResultType, args); + + processReturnValue(count, resultExv, mustBeFreed, builder, rewriter); + return mlir::success(); + } +}; + struct MatmulOpConversion : public HlfirIntrinsicConversion { using HlfirIntrinsicConversion::HlfirIntrinsicConversion; @@ -405,14 +438,14 @@ class LowerHLFIRIntrinsics patterns.insert(context); + CountOpConversion, DotProductOpConversion>(context); mlir::ConversionTarget target(*context); target.addLegalDialect(); target.addIllegalOp(); + hlfir::AllOp, hlfir::DotProductOp, hlfir::CountOp>(); target.markUnknownOpDynamicallyLegal( [](mlir::Operation *) { return true; }); if (mlir::failed( diff --git a/flang/test/HLFIR/count-lowering.fir b/flang/test/HLFIR/count-lowering.fir new file mode 100644 index 0000000000000..0d9cc34a316eb --- /dev/null +++ b/flang/test/HLFIR/count-lowering.fir @@ -0,0 +1,164 @@ +// Test hlfir.count operation lowering to fir runtime call +// RUN: fir-opt %s -lower-hlfir-intrinsics | FileCheck %s + +func.func @_QPcount1(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.ref {fir.bindc_name = "s"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFcount1Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg1 {uniq_name = "_QFcount1Es"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %2 = hlfir.count %0#0 {fastmath = #arith.fastmath} : (!fir.box>>) -> i32 + hlfir.assign %2 to %1#0 : i32, !fir.ref + return +} +// CHECK-LABEL: func.func @_QPcount1( +// CHECK: %[[ARG0:.*]]: !fir.box>> +// CHECK: %[[ARG1:.*]]: !fir.ref +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 : (!fir.box>>) -> !fir.box +// CHECK: %[[RET_ARG:.*]] = fir.call @_FortranACount(%[[MASK_ARG]], %[[LOC_STR:.*]], %[[LOC_N:.*]], %[[C1:.*]]) : (!fir.box, !fir.ref, i32, i32) -> i64 +// CHECK-NEXT: %[[RET:.*]] = fir.convert %[[RET_ARG]] : (i64) -> i32 +// CHECK-NEXT: hlfir.assign %[[RET]] to %[[RES]]#0 : i32, !fir.ref +// CHECK-NEXT: return +// CHECK-NEXT: } + +func.func @_QPcount2(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.box> {fir.bindc_name = "s"}, %arg2: !fir.ref {fir.bindc_name = "d"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFcount2Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg2 {uniq_name = "_QFcount2Ed"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg1 {uniq_name = "_QFcount2Es"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %3 = fir.load %1#0 : !fir.ref + %4 = hlfir.count %0#0 dim %3 {fastmath = #arith.fastmath} : (!fir.box>>, i32) -> !hlfir.expr + hlfir.assign %4 to %2#0 : !hlfir.expr, !fir.box> + hlfir.destroy %4 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPcount2( +// CHECK: %[[ARG0:.*]]: !fir.box>> +// CHECK: %[[ARG1:.*]]: !fir.box +// CHECK: %[[ARG2:.*]]: !fir.ref +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[DIM_VAR:.*]]:2 = hlfir.declare %[[ARG2]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] + +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>> +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap> +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] + +// CHECK-DAG: %[[DIM:.*]] = fir.load %[[DIM_VAR]]#0 : !fir.ref +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 + +// CHECK: %[[NONE:.*]] = fir.call @_FortranACountDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) : (!fir.ref>, !fir.box, i32, i32, !fir.ref, i32) -> none +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>, i1) -> !hlfir.expr +// CHECK: hlfir.assign %[[EXPR]] to %[[RES]]#0 +// CHECK: hlfir.destroy %[[EXPR]] +// CHECK-NEXT: return +// CHECK-NEXT: } + +func.func @_QPcount3(%arg0: !fir.ref> {fir.bindc_name = "s"}) { + %0 = fir.address_of(@_QFcount3Ea) : !fir.ref>> + %c2 = arith.constant 2 : index + %c2_0 = arith.constant 2 : index + %1 = fir.shape %c2, %c2_0 : (index, index) -> !fir.shape<2> + %2:2 = hlfir.declare %0(%1) {uniq_name = "_QFcount3Ea"} : (!fir.ref>>, !fir.shape<2>) -> (!fir.ref>>, !fir.ref>>) + %c2_1 = arith.constant 2 : index + %3 = fir.shape %c2_1 : (index) -> !fir.shape<1> + %4:2 = hlfir.declare %arg0(%3) {uniq_name = "_QFcount3Es"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) + %c1_i32 = arith.constant 1 : i32 + %5 = hlfir.count %2#0 dim %c1_i32 {fastmath = #arith.fastmath} : (!fir.ref>>, i32) -> !hlfir.expr<2xi32> + hlfir.assign %5 to %4#0 : !hlfir.expr<2xi32>, !fir.ref> + hlfir.destroy %5 : !hlfir.expr<2xi32> + return +} +// CHECK-LABEL: func.func @_QPcount3( +// CHECK: %[[ARG0:.*]]: !fir.ref> +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>> +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap> +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG0]](%[[RES_SHAPE:.*]]) + +// CHECK-DAG: %[[MASK_ADDR:.*]] = fir.address_of +// CHECK-DAG: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ADDR]](%[[MASK_SHAPE:.*]]) +// CHECK-DAG: %[[MASK_BOX:.*]] = fir.embox %[[MASK_VAR]]#1(%[[MASK_SHAPE:.*]]) + +// CHECK-DAG: %[[DIM:.*]] = arith.constant 1 : i32 + +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK_BOX]] : (!fir.box>>) -> !fir.box +// CHECK: %[[NONE:.*]] = fir.call @_FortranACountDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>, i1) -> !hlfir.expr +// CHECK: hlfir.assign %[[EXPR]] to %[[RES]] +// CHECK: hlfir.destroy %[[EXPR]] +// CHECK-NEXT: return +// CHECK-NEXT: } + +func.func @_QPcount4(%arg0: !fir.box>> {fir.bindc_name = "a"}, %arg1: !fir.box> {fir.bindc_name = "s"}, %arg2: !fir.ref {fir.bindc_name = "d"}) { + %0:2 = hlfir.declare %arg0 {uniq_name = "_QFcount4Ea"} : (!fir.box>>) -> (!fir.box>>, !fir.box>>) + %1:2 = hlfir.declare %arg2 {uniq_name = "_QFcount4Ed"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %2:2 = hlfir.declare %arg1 {uniq_name = "_QFcount4Es"} : (!fir.box>) -> (!fir.box>, !fir.box>) + %c8_i32 = arith.constant 8 : i32 + %3 = fir.load %1#0 : !fir.ref + %4 = hlfir.count %0#0 dim %3 kind %c8_i32 {fastmath = #arith.fastmath} : (!fir.box>>, i32, i32) -> !hlfir.expr + %5 = hlfir.shape_of %4 : (!hlfir.expr) -> !fir.shape<1> + %6 = hlfir.elemental %5 : (!fir.shape<1>) -> !hlfir.expr { + ^bb0(%arg3: index): + %7 = hlfir.apply %4, %arg3 : (!hlfir.expr, index) -> i64 + %8 = fir.convert %7 : (i64) -> i32 + hlfir.yield_element %8 : i32 + } + hlfir.assign %6 to %2#0 : !hlfir.expr, !fir.box> + hlfir.destroy %6 : !hlfir.expr + hlfir.destroy %4 : !hlfir.expr + return +} +// CHECK-LABEL: func.func @_QPcount4( +// CHECK: %[[ARG0:.*]]: !fir.box>> +// CHECK: %[[ARG1:.*]]: !fir.box +// CHECK: %[[ARG2:.*]]: !fir.ref +// CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +// CHECK-DAG: %[[DIM_VAR:.*]]:2 = hlfir.declare %[[ARG2]] +// CHECK-DAG: %[[RES:.*]]:2 = hlfir.declare %[[ARG1]] + +// CHECK-DAG: %[[RET_BOX:.*]] = fir.alloca !fir.box>> +// CHECK-DAG: %[[RET_ADDR:.*]] = fir.zero_bits !fir.heap> +// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index +// CHECK-DAG: %[[RET_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1> +// CHECK-DAG: %[[RET_EMBOX:.*]] = fir.embox %[[RET_ADDR]](%[[RET_SHAPE]]) +// CHECK-DAG: fir.store %[[RET_EMBOX]] to %[[RET_BOX]] + +// CHECK-DAG: %[[DIM:.*]] = fir.load %[[DIM_VAR]]#0 : !fir.ref +// CHECK-DAG: %[[KIND:.*]] = arith.constant 8 : i32 +// CHECK-DAG: %[[RET_ARG:.*]] = fir.convert %[[RET_BOX]] +// CHECK-DAG: %[[MASK_ARG:.*]] = fir.convert %[[MASK]]#1 + +// CHECK: %[[NONE:.*]] = fir.call @_FortranACountDim(%[[RET_ARG]], %[[MASK_ARG]], %[[DIM]], %[[KIND]], %[[LOC_STR:.*]], %[[LOC_N:.*]]) : (!fir.ref>, !fir.box, i32, i32, !fir.ref, i32) -> none +// CHECK: %[[RET:.*]] = fir.load %[[RET_BOX]] +// CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[RET]] +// CHECK-NEXT: %[[ADDR:.*]] = fir.box_addr %[[RET]] +// CHECK-NEXT: %[[SHIFT:.*]] = fir.shape_shift %[[BOX_DIMS]]#0, %[[BOX_DIMS]]#1 +// CHECK-NEXT: %[[TMP:.*]]:2 = hlfir.declare %[[ADDR]](%[[SHIFT]]) {uniq_name = ".tmp.intrinsic_result"} +// CHECK: %[[TRUE:.*]] = arith.constant true +// CHECK: %[[EXPR:.*]] = hlfir.as_expr %[[TMP]]#0 move %[[TRUE]] : (!fir.box>, i1) -> !hlfir.expr +// CHECK-NEXT: %[[OUT_SHAPE:.*]] = hlfir.shape_of %[[EXPR]] +// CHECK-NEXT: %[[OUT:.*]] = hlfir.elemental %[[OUT_SHAPE]] : (!fir.shape<1>) -> !hlfir.expr +// CHECK-DAG: hlfir.assign %[[OUT]] to %[[RES]]#0 +// CHECK-NEXT: hlfir.destroy %[[OUT]] : !hlfir.expr +// CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr +// CHECK-NEXT: return +// CHECK-NEXT: } diff --git a/flang/test/HLFIR/count.fir b/flang/test/HLFIR/count.fir new file mode 100644 index 0000000000000..c25f9b94124af --- /dev/null +++ b/flang/test/HLFIR/count.fir @@ -0,0 +1,83 @@ +// Test hlfir.count operation parse, verify (no errors), and unparse + +// RUN: fir-opt %s | fir-opt | FileCheck %s + +// mask is an expression of known shape +func.func @count0(%arg0: !hlfir.expr<2x!fir.logical<4>>) { + %count = hlfir.count %arg0 : (!hlfir.expr<2x!fir.logical<4>>) -> i32 + return +} +// CHECK: func.func @count0(%[[ARRAY:.*]]: !hlfir.expr<2x!fir.logical<4>>) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] : (!hlfir.expr<2x!fir.logical<4>>) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is an expression of assumed shape +func.func @count1(%arg0: !hlfir.expr>) { + %count = hlfir.count %arg0 : (!hlfir.expr>) -> i32 + return +} +// CHECK: func.func @count1(%[[ARRAY:.*]]: !hlfir.expr>) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] : (!hlfir.expr>) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a boxed array +func.func @count2(%arg0: !fir.box>>) { + %count = hlfir.count %arg0 : (!fir.box>>) -> i32 + return +} +// CHECK: func.func @count2(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] : (!fir.box>>) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is an assumed shape boxed array +func.func @count3(%arg0: !fir.box>>) { + %count = hlfir.count %arg0 : (!fir.box>>) -> i32 + return +} +// CHECK: func.func @count3(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] : (!fir.box>>) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a 2-dimensional array +func.func @count4(%arg0: !fir.box>>){ + %count = hlfir.count %arg0 : (!fir.box>>) -> i32 + return +} +// CHECK: func.func @count4(%[[ARRAY:.*]]: !fir.box>>) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] : (!fir.box>>) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask and dim argument +func.func @count5(%arg0: !fir.box>>, %arg1: i32) { + %count = hlfir.count %arg0 dim %arg1 : (!fir.box>>, i32) -> i32 + return +} +// CHECK: func.func @count5(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[COUNT:.*]] = hlfir.count %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is a 2 dimensional array with dim +func.func @count6(%arg0: !fir.box>>, %arg1: i32) { + %count = hlfir.count %arg0 dim %arg1 : (!fir.box>>, i32) -> i32 + return +} +// CHECK: func.func @count6(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.count %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } + +// mask is of a different logical type +func.func @count7(%arg0: !fir.box>>, %arg1: i32) { + %count = hlfir.count %arg0 dim %arg1 : (!fir.box>>, i32) -> i32 + return +} +// CHECK: func.func @count7(%[[ARRAY:.*]]: !fir.box>>, %[[DIM:.*]]: i32) { +// CHECK-NEXT: %[[ANY:.*]] = hlfir.count %[[ARRAY]] dim %[[DIM]] : (!fir.box>>, i32) -> i32 +// CHECK-NEXT: return +// CHECK-NEXT: } \ No newline at end of file diff --git a/flang/test/HLFIR/invalid.fir b/flang/test/HLFIR/invalid.fir index 01bccdf80428b..6db1b79e0818f 100644 --- a/flang/test/HLFIR/invalid.fir +++ b/flang/test/HLFIR/invalid.fir @@ -368,6 +368,30 @@ func.func @bad_all6(%arg0: !hlfir.expr>) { %0 = hlfir.all %arg0 : (!hlfir.expr>) -> !hlfir.expr> } +// ----- +func.func @bad_count1(%arg0: !hlfir.expr>, %arg1: i32) { + // expected-error@+1 {{'hlfir.count' op result must be an array}} + %0 = hlfir.count %arg0 dim %arg1 : (!hlfir.expr>, i32) -> !hlfir.expr +} + +// ----- +func.func @bad_count2(%arg0: !hlfir.expr>, %arg1: i32){ + // expected-error@+1 {{'hlfir.count' op result rank must be one less than MASK}} + %0 = hlfir.count %arg0 dim %arg1 : (!hlfir.expr>, i32) -> !hlfir.expr> +} + +// ----- +func.func @bad_count3(%arg0: !hlfir.expr>, %arg1: i32) { + // expected-error@+1 {{'hlfir.count' op result must be of numerical scalar type}} + %0 = hlfir.count %arg0 dim %arg1 : (!hlfir.expr>, i32) -> !hlfir.expr +} + +// ----- +func.func @bad_count4(%arg0: !hlfir.expr>, %arg1: i32) { + // expected-error@+1 {{'hlfir.count' op result must be of numerical scalar type}} + %0 = hlfir.count %arg0 dim %arg1 : (!hlfir.expr>, i32) -> !fir.logical<4> +} + // ----- func.func @bad_product1(%arg0: !hlfir.expr, %arg1: i32, %arg2: !fir.box>) { // expected-error@+1 {{'hlfir.product' op result must have the same element type as ARRAY argument}} diff --git a/flang/test/Lower/HLFIR/count.f90 b/flang/test/Lower/HLFIR/count.f90 new file mode 100644 index 0000000000000..25c74841514e9 --- /dev/null +++ b/flang/test/Lower/HLFIR/count.f90 @@ -0,0 +1,82 @@ +! Test lowering of COUNT intrinsic to HLFIR +! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s + +! simple 1 argument COUNT +subroutine count1(a, s) + logical :: a(:) + integer :: s + s = COUNT(a) +end subroutine +! CHECK-LABEL: func.func @_QPcount1( +! CHECK: %[[ARG0:.*]]: !fir.box>> +! CHECK: %[[ARG1:.*]]: !fir.ref +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-NEXT: %[[EXPR:.*]] = hlfir.count %[[MASK]]#0 : (!fir.box>>) -> i32 +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : i32, !fir.ref +! CHECK-NEXT: return +! CHECK-NEXT: } + +! count with by-ref DIM argument +subroutine count2(a, s, d) + logical :: a(:,:) + integer :: s(:), d + s = COUNT(a, d) +end subroutine +! CHECK-LABEL: func.func @_QPcount2( +! CHECK: %[[ARG0:.*]]: !fir.box>> +! CHECK: %[[ARG1:.*]]: !fir.box> +! CHECK: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[DIM_REF:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[DIM:.*]] = fir.load %[[DIM_REF]]#0 : !fir.ref +! CHECK-DAG: %[[EXPR:.*]] = hlfir.count %[[MASK]]#0 dim %[[DIM]] : (!fir.box>>, i32) -> !hlfir.expr +! CHECK-NEXT: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !hlfir.expr, !fir.box> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr +! CHECK-NEXT: return +! CHECK-NEXT: } + +! count with DIM argument by-val, mask isn't boxed +subroutine count3(s) + integer :: s(2) + logical :: a(2,2) = reshape((/.true.,.false.,.true.,.false./), shape(a)) + s = COUNT(a, 1) +end subroutine +! CHECK-LABEL: func.func @_QPcount3( +! CHECK: %[[ARG0:.*]]: !fir.ref> +! CHECK-DAG: %[[ADDR:.*]] = fir.address_of{{.*}} : !fir.ref>> +! CHECK-DAG: %[[MASK_SHAPE:.*]] = fir.shape {{.*}} -> !fir.shape<2> +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ADDR]](%[[MASK_SHAPE]]) +! CHECK-DAG: %[[OUT_SHAPE:.*]] = fir.shape {{.*}} -> !fir.shape<1> +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG0]](%[[OUT_SHAPE]]) +! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32 +! CHECK-DAG: %[[EXPR:.*]] = hlfir.count %[[MASK]]#0 dim %[[C1]] : (!fir.ref>>, i32) -> !hlfir.expr<2xi32> +! CHECK-DAG: hlfir.assign %[[EXPR]] to %[[OUT]]#0 : !hlfir.expr<2xi32>, !fir.ref> +! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr<2xi32> +! CHECK-NEXT: return +! CHECK-NEXT: } + +! count with dim and kind arguments +subroutine count4(a, s, d) + logical :: a(:,:) + integer :: s(:), d + s = COUNT(a, d, 8) +end subroutine +! CHECK-LABEL: func.func @_QPcount4( +! CHECK: %[[ARG0:.*]]: !fir.box>> +! CHECK: %[[ARG1:.*]]: !fir.box> +! CHECK: %[[ARG2:.*]]: !fir.ref +! CHECK-DAG: %[[MASK:.*]]:2 = hlfir.declare %[[ARG0]] +! CHECK-DAG: %[[DIM_REF:.*]]:2 = hlfir.declare %[[ARG2]] +! CHECK-DAG: %[[OUT:.*]]:2 = hlfir.declare %[[ARG1]] +! CHECK-DAG: %[[C8:.*]] = arith.constant 8 : i32 +! CHECK-DAG: %[[DIM:.*]] = fir.load %[[DIM_REF]]#0 : !fir.ref +! CHECK-DAG: %[[EXPR:.*]] = hlfir.count %[[MASK]]#0 dim %[[DIM]] kind %[[C8]] : (!fir.box>>, i32, i32) -> !hlfir.expr +! CHECK-DAG: %[[RES_SHAPE:.*]] = hlfir.shape_of %[[EXPR]] +! CHECK-DAG: %[[RES:.*]] = hlfir.elemental %[[RES_SHAPE]] : (!fir.shape<1>) -> !hlfir.expr +! CHECK-DAG: hlfir.assign %[[RES]] to %[[OUT]]#0 +! CHECK-NEXT: hlfir.destroy %[[RES]] : !hlfir.expr +! CHECK-NEXT: hlfir.destroy %[[EXPR]] : !hlfir.expr +! CHECK-NEXT: return +! CHECK-NEXT: } From 4511d3c33cba90d5d53a1fd6eed89ef9a3f696e1 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 11:29:46 +0200 Subject: [PATCH 004/130] [InstSimplify] Add test for icmp of uadd.sat/usub.sat (NFC) --- .../InstSimplify/saturating-add-sub.ll | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll index b323ce0749f84..616a2060e5339 100644 --- a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll @@ -794,3 +794,157 @@ define i1 @ssub_icmp_op1_smin(i8 %a) { %c = icmp sge i8 %b, 0 ret i1 %c } + +define i1 @uadd_uge(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_uge( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp uge i8 %sat, %x + ret i1 %cmp +} + +define i1 @uadd_uge_rhs(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_uge_rhs( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[Y]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp uge i8 %sat, %y + ret i1 %cmp +} + +define i1 @uadd_uge_commuted(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_uge_commuted( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X]], [[SAT]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp ule i8 %x, %sat + ret i1 %cmp +} + +define i1 @uadd_ult(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_ult( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp ult i8 %sat, %x + ret i1 %cmp +} + +define <2 x i1> @uadd_uge_vec(<2 x i8> %x, <2 x i8> %y) { +; CHECK-LABEL: @uadd_uge_vec( +; CHECK-NEXT: [[SAT:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge <2 x i8> [[SAT]], [[X]] +; CHECK-NEXT: ret <2 x i1> [[CMP]] +; + %sat = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %x, <2 x i8> %y) + %cmp = icmp uge <2 x i8> %sat, %x + ret <2 x i1> %cmp +} + +define i1 @uadd_ugt_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_ugt_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp ugt i8 %sat, %x + ret i1 %cmp +} + +define i1 @uadd_ule_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @uadd_ule_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp ule i8 %sat, %x + ret i1 %cmp +} + +define i1 @uadd_uge_unrelated_op_fail(i8 %x, i8 %y, i8 %z) { +; CHECK-LABEL: @uadd_uge_unrelated_op_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[Z:%.*]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) + %cmp = icmp uge i8 %sat, %z + ret i1 %cmp +} + +define i1 @usub_ule(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_ule( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp ule i8 %sat, %x + ret i1 %cmp +} + +define i1 @usub_ule_rhs_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_ule_rhs_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[SAT]], [[Y]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp ule i8 %sat, %y + ret i1 %cmp +} + +define i1 @usub_ule_commuted(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_ule_commuted( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X]], [[SAT]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp uge i8 %x, %sat + ret i1 %cmp +} + +define i1 @usub_ugt(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_ugt( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp ugt i8 %sat, %x + ret i1 %cmp +} + +define i1 @usub_ult_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_ult_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp ult i8 %sat, %x + ret i1 %cmp +} + +define i1 @usub_uge_fail(i8 %x, i8 %y) { +; CHECK-LABEL: @usub_uge_fail( +; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[X]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) + %cmp = icmp uge i8 %sat, %x + ret i1 %cmp +} From f6a8775c5d9fa6cd49f404da70982f2e7b91c88c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 11:42:21 +0200 Subject: [PATCH 005/130] [InstSimplify] Fold icmp of uadd.sat/usub.sat (PR63381) Fold uadd.sat(X, Y) uge X and usub.sat(X, Y) ule X to true. Proof: https://alive2.llvm.org/ce/z/596m9X Fixes https://github.com/llvm/llvm-project/issues/63381. --- llvm/lib/Analysis/InstructionSimplify.cpp | 36 +++++++++++++++++++ .../InstSimplify/saturating-add-sub.ll | 32 +++++------------ 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 616873f87f313..48ffa83d45cee 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -3682,6 +3682,36 @@ static Value *simplifyICmpWithDominatingAssume(CmpInst::Predicate Predicate, return nullptr; } +static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred, + Value *LHS, Value *RHS) { + auto *II = dyn_cast(LHS); + if (!II) + return nullptr; + + switch (II->getIntrinsicID()) { + case Intrinsic::uadd_sat: + // uadd.sat(X, Y) uge X, uadd.sat(X, Y) uge Y + if (II->getArgOperand(0) == RHS || II->getArgOperand(1) == RHS) { + if (Pred == ICmpInst::ICMP_UGE) + return ConstantInt::getTrue(getCompareTy(II)); + if (Pred == ICmpInst::ICMP_ULT) + return ConstantInt::getFalse(getCompareTy(II)); + } + return nullptr; + case Intrinsic::usub_sat: + // usub.sat(X, Y) ule X + if (II->getArgOperand(0) == RHS) { + if (Pred == ICmpInst::ICMP_ULE) + return ConstantInt::getTrue(getCompareTy(II)); + if (Pred == ICmpInst::ICMP_UGT) + return ConstantInt::getFalse(getCompareTy(II)); + } + return nullptr; + default: + return nullptr; + } +} + /// Given operands for an ICmpInst, see if we can fold the result. /// If not, this returns null. static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, @@ -3946,6 +3976,12 @@ static Value *simplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, if (Value *V = simplifyICmpWithMinMax(Pred, LHS, RHS, Q, MaxRecurse)) return V; + if (Value *V = simplifyICmpWithIntrinsicOnLHS(Pred, LHS, RHS)) + return V; + if (Value *V = simplifyICmpWithIntrinsicOnLHS( + ICmpInst::getSwappedPredicate(Pred), RHS, LHS)) + return V; + if (Value *V = simplifyICmpWithDominatingAssume(Pred, LHS, RHS, Q)) return V; diff --git a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll index 616a2060e5339..6fb12612f2f72 100644 --- a/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll +++ b/llvm/test/Transforms/InstSimplify/saturating-add-sub.ll @@ -797,9 +797,7 @@ define i1 @ssub_icmp_op1_smin(i8 %a) { define i1 @uadd_uge(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %sat, %x @@ -808,9 +806,7 @@ define i1 @uadd_uge(i8 %x, i8 %y) { define i1 @uadd_uge_rhs(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge_rhs( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[SAT]], [[Y]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %sat, %y @@ -819,9 +815,7 @@ define i1 @uadd_uge_rhs(i8 %x, i8 %y) { define i1 @uadd_uge_commuted(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_uge_commuted( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X]], [[SAT]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp ule i8 %x, %sat @@ -830,9 +824,7 @@ define i1 @uadd_uge_commuted(i8 %x, i8 %y) { define i1 @uadd_ult(i8 %x, i8 %y) { ; CHECK-LABEL: @uadd_ult( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %sat = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %cmp = icmp ult i8 %sat, %x @@ -841,9 +833,7 @@ define i1 @uadd_ult(i8 %x, i8 %y) { define <2 x i1> @uadd_uge_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @uadd_uge_vec( -; CHECK-NEXT: [[SAT:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge <2 x i8> [[SAT]], [[X]] -; CHECK-NEXT: ret <2 x i1> [[CMP]] +; CHECK-NEXT: ret <2 x i1> ; %sat = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %x, <2 x i8> %y) %cmp = icmp uge <2 x i8> %sat, %x @@ -885,9 +875,7 @@ define i1 @uadd_uge_unrelated_op_fail(i8 %x, i8 %y, i8 %z) { define i1 @usub_ule(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ule( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp ule i8 %sat, %x @@ -907,9 +895,7 @@ define i1 @usub_ule_rhs_fail(i8 %x, i8 %y) { define i1 @usub_ule_commuted(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ule_commuted( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X]], [[SAT]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp uge i8 %x, %sat @@ -918,9 +904,7 @@ define i1 @usub_ule_commuted(i8 %x, i8 %y) { define i1 @usub_ugt(i8 %x, i8 %y) { ; CHECK-LABEL: @usub_ugt( -; CHECK-NEXT: [[SAT:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[SAT]], [[X]] -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; %sat = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %cmp = icmp ugt i8 %sat, %x From 5400257ded86b65e5b55cbb138e0438b96c9bebf Mon Sep 17 00:00:00 2001 From: Alexandros Lamprineas Date: Mon, 19 Jun 2023 10:45:42 +0100 Subject: [PATCH 006/130] [FuncSpec] Add Freeze and CallBase to the InstCostVisitor. Allows constant folding of such instructions when estimating user bonus. Differential Revision: https://reviews.llvm.org/D153036 --- .../Transforms/IPO/FunctionSpecialization.h | 2 ++ .../Transforms/IPO/FunctionSpecialization.cpp | 28 +++++++++++++++++++ .../IPO/FunctionSpecializationTest.cpp | 23 ++++++++++++--- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h index d7a2e9f871a28..e24d72fae10fb 100644 --- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h @@ -143,6 +143,8 @@ class InstCostVisitor : public InstVisitor { Cost estimateBranchInst(BranchInst &I); Constant *visitInstruction(Instruction &I) { return nullptr; } + Constant *visitFreezeInst(FreezeInst &I); + Constant *visitCallBase(CallBase &I); Constant *visitLoadInst(LoadInst &I); Constant *visitGetElementPtrInst(GetElementPtrInst &I); Constant *visitSelectInst(SelectInst &I); diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp index a970253d9b1c8..1792b24936bf8 100644 --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -222,6 +222,34 @@ Cost InstCostVisitor::estimateBranchInst(BranchInst &I) { return estimateBasicBlocks(WorkList, KnownConstants, Solver, BFI, TTI); } +Constant *InstCostVisitor::visitFreezeInst(FreezeInst &I) { + if (isGuaranteedNotToBeUndefOrPoison(LastVisited->second)) + return LastVisited->second; + return nullptr; +} + +Constant *InstCostVisitor::visitCallBase(CallBase &I) { + Function *F = I.getCalledFunction(); + if (!F || !canConstantFoldCallTo(&I, F)) + return nullptr; + + SmallVector Operands; + Operands.reserve(I.getNumOperands()); + + for (unsigned Idx = 0, E = I.getNumOperands() - 1; Idx != E; ++Idx) { + Value *V = I.getOperand(Idx); + auto *C = dyn_cast(V); + if (!C) + C = findConstantFor(V, KnownConstants); + if (!C) + return nullptr; + Operands.push_back(C); + } + + auto Ops = ArrayRef(Operands.begin(), Operands.end()); + return ConstantFoldCall(&I, F, Ops); +} + Constant *InstCostVisitor::visitLoadInst(LoadInst &I) { if (isa(LastVisited->second)) return nullptr; diff --git a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp index df44a16987721..bf65b3402f31c 100644 --- a/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp +++ b/llvm/unittests/Transforms/IPO/FunctionSpecializationTest.cpp @@ -227,13 +227,21 @@ TEST_F(FunctionSpecializationTest, Misc) { const char *ModuleString = R"( @g = constant [2 x i32] zeroinitializer, align 4 - define i32 @foo(i8 %a, i1 %cond, ptr %b) { + declare i32 @llvm.smax.i32(i32, i32) + declare i32 @bar(i32) + + define i32 @foo(i8 %a, i1 %cond, ptr %b, i32 %c) { %cmp = icmp eq i8 %a, 10 %ext = zext i1 %cmp to i32 %sel = select i1 %cond, i32 %ext, i32 1 %gep = getelementptr i32, ptr %b, i32 %sel %ld = load i32, ptr %gep - ret i32 %ld + %fr = freeze i32 %ld + %smax = call i32 @llvm.smax.i32(i32 %fr, i32 1) + %call = call i32 @bar(i32 %smax) + %fr2 = freeze i32 %c + %add = add i32 %call, %fr2 + ret i32 %add } )"; @@ -245,6 +253,7 @@ TEST_F(FunctionSpecializationTest, Misc) { GlobalVariable *GV = M.getGlobalVariable("g"); Constant *One = ConstantInt::get(IntegerType::getInt8Ty(M.getContext()), 1); Constant *True = ConstantInt::getTrue(M.getContext()); + Constant *Undef = UndefValue::get(IntegerType::getInt32Ty(M.getContext())); auto BlockIter = F->front().begin(); Instruction &Icmp = *BlockIter++; @@ -252,6 +261,8 @@ TEST_F(FunctionSpecializationTest, Misc) { Instruction &Select = *BlockIter++; Instruction &Gep = *BlockIter++; Instruction &Load = *BlockIter++; + Instruction &Freeze = *BlockIter++; + Instruction &Smax = *BlockIter++; // icmp + zext Cost Ref = getInstCost(Icmp) + getInstCost(Zext); @@ -265,9 +276,13 @@ TEST_F(FunctionSpecializationTest, Misc) { EXPECT_EQ(Bonus, Ref); EXPECT_TRUE(Bonus > 0); - // gep + load - Ref = getInstCost(Gep) + getInstCost(Load); + // gep + load + freeze + smax + Ref = getInstCost(Gep) + getInstCost(Load) + getInstCost(Freeze) + + getInstCost(Smax); Bonus = Specializer.getSpecializationBonus(F->getArg(2), GV, Visitor); EXPECT_EQ(Bonus, Ref); EXPECT_TRUE(Bonus > 0); + + Bonus = Specializer.getSpecializationBonus(F->getArg(3), Undef, Visitor); + EXPECT_TRUE(Bonus == 0); } From 6947db2778e0f4799f5311bc80fe7963aa8409c6 Mon Sep 17 00:00:00 2001 From: Russell Greene Date: Mon, 19 Jun 2023 09:59:20 +0000 Subject: [PATCH 007/130] lldb: do more than 1 kilobyte at a time to vastly increase binary sync speed https://github.com/llvm/llvm-project/issues/62750 I setup a simple test with a large .so (~100MiB) that was only present on the target machine but not present on the local machine, and ran a lldb server on the target and connectd to it. LLDB properly downloads the file from the remote, but it does so at a very slow speed, even over a hardwired 1Gbps connection! Increasing the buffer size for downloading these helps quite a bit. Test setup: ``` $ cat gen.py print('const char* hugeglobal = ') for _ in range(1000*500): print(' "' + '1234'*50 + '"') print(';') print('const char* mystring() { return hugeglobal; }') $ gen.py > huge.c $ mkdir libdir $ gcc -fPIC huge.c -Wl,-soname,libhuge.so -o libdir/libhuge.so -shared $ cat test.c #include #include extern const char* mystring(); int main() { printf("%d\n", strlen(mystring())); } $ gcc test.c -L libdir -l huge -Wl,-rpath='$ORIGIN' -o test $ rsync -a libdir remote:~/ $ ssh remote bash -c "cd ~/libdir && /llvm/buildr/bin/lldb-server platform --server --listen '*:1234'" ``` in another terminal ``` $ rm -rf ~/.lldb # clear cache $ cat connect.lldb platform select remote-linux platform connect connect://10.0.0.14:1234 file test b main r image list c q $ time /llvm/buildr/bin/lldb --source connect.lldb ``` Times with various buffer sizes: 1kiB (current): ~22s 8kiB: ~8s 16kiB: ~4s 32kiB: ~3.5s 64kiB: ~2.8s 128kiB: ~2.6s 256kiB: ~2.1s 512kiB: ~2.1s 1MiB: ~2.1s 2MiB: ~2.1s I choose 512kiB from this list as it seems to be the place where the returns start diminishing and still isn't that much memory My understanding of how this makes such a difference is ReadFile issues a request for each call, and larger buffer means less round trip times. The "ideal" situation is ReadFile() being async and being able to issue multiple of these, but that is much more work for probably little gains. NOTE: this is my first contribution, so wasn't sure who to choose as a reviewer. Greg Clayton seems to be the most appropriate of those in CODE_OWNERS.txt Reviewed By: clayborg, jasonmolenda Differential Revision: https://reviews.llvm.org/D153060 --- lldb/source/Target/Platform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 2590197c7149b..4b5d21bede121 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -1630,7 +1630,7 @@ Status Platform::DownloadModuleSlice(const FileSpec &src_file_spec, return error; } - std::vector buffer(1024); + std::vector buffer(512 * 1024); auto offset = src_offset; uint64_t total_bytes_read = 0; while (total_bytes_read < src_size) { From 664b7a4cd51d9273888e79688f64cc8bbcbdbe25 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 12:27:46 +0200 Subject: [PATCH 008/130] [SCCP] Fix conversion of range to constant for vectors (PR63380) The ConstantRange specifies the range of the scalar elements in the vector. When converting into a Constant, we need to create a vector splat with the correct type. For that purpose, pass in the expected type for the constant. Fixes https://github.com/llvm/llvm-project/issues/63380. --- .../llvm/Transforms/Utils/SCCPSolver.h | 2 +- llvm/lib/Transforms/Utils/SCCPSolver.cpp | 64 +++++++++++-------- llvm/test/Transforms/SCCP/intrinsics.ll | 14 ++++ 3 files changed, 52 insertions(+), 28 deletions(-) diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h index 3754b51f4722d..7930d95e1deaf 100644 --- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h +++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h @@ -160,7 +160,7 @@ class SCCPSolver { /// Helper to return a Constant if \p LV is either a constant or a constant /// range with a single element. - Constant *getConstant(const ValueLatticeElement &LV) const; + Constant *getConstant(const ValueLatticeElement &LV, Type *Ty) const; /// Return either a Constant or nullptr for a given Value. Constant *getConstantOrNull(Value *V) const; diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index 902651ab84f68..24d1a46cfd40f 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -394,8 +394,8 @@ class SCCPInstVisitor : public InstVisitor { LLVMContext &Ctx; private: - ConstantInt *getConstantInt(const ValueLatticeElement &IV) const { - return dyn_cast_or_null(getConstant(IV)); + ConstantInt *getConstantInt(const ValueLatticeElement &IV, Type *Ty) const { + return dyn_cast_or_null(getConstant(IV, Ty)); } // pushToWorkList - Helper for markConstant/markOverdefined @@ -778,7 +778,7 @@ class SCCPInstVisitor : public InstVisitor { bool isStructLatticeConstant(Function *F, StructType *STy); - Constant *getConstant(const ValueLatticeElement &LV) const; + Constant *getConstant(const ValueLatticeElement &LV, Type *Ty) const; Constant *getConstantOrNull(Value *V) const; @@ -881,14 +881,18 @@ bool SCCPInstVisitor::isStructLatticeConstant(Function *F, StructType *STy) { return true; } -Constant *SCCPInstVisitor::getConstant(const ValueLatticeElement &LV) const { - if (LV.isConstant()) - return LV.getConstant(); +Constant *SCCPInstVisitor::getConstant(const ValueLatticeElement &LV, + Type *Ty) const { + if (LV.isConstant()) { + Constant *C = LV.getConstant(); + assert(C->getType() == Ty && "Type mismatch"); + return C; + } if (LV.isConstantRange()) { const auto &CR = LV.getConstantRange(); if (CR.getSingleElement()) - return ConstantInt::get(Ctx, *CR.getSingleElement()); + return ConstantInt::get(Ty, *CR.getSingleElement()); } return nullptr; } @@ -904,7 +908,7 @@ Constant *SCCPInstVisitor::getConstantOrNull(Value *V) const { for (unsigned I = 0, E = ST->getNumElements(); I != E; ++I) { ValueLatticeElement LV = LVs[I]; ConstVals.push_back(SCCPSolver::isConstant(LV) - ? getConstant(LV) + ? getConstant(LV, ST->getElementType(I)) : UndefValue::get(ST->getElementType(I))); } Const = ConstantStruct::get(ST, ConstVals); @@ -912,7 +916,7 @@ Constant *SCCPInstVisitor::getConstantOrNull(Value *V) const { const ValueLatticeElement &LV = getLatticeValueFor(V); if (SCCPSolver::isOverdefined(LV)) return nullptr; - Const = SCCPSolver::isConstant(LV) ? getConstant(LV) + Const = SCCPSolver::isConstant(LV) ? getConstant(LV, V->getType()) : UndefValue::get(V->getType()); } assert(Const && "Constant is nullptr here!"); @@ -1007,7 +1011,7 @@ void SCCPInstVisitor::getFeasibleSuccessors(Instruction &TI, } ValueLatticeElement BCValue = getValueState(BI->getCondition()); - ConstantInt *CI = getConstantInt(BCValue); + ConstantInt *CI = getConstantInt(BCValue, BI->getCondition()->getType()); if (!CI) { // Overdefined condition variables, and branches on unfoldable constant // conditions, mean the branch could go either way. @@ -1033,7 +1037,8 @@ void SCCPInstVisitor::getFeasibleSuccessors(Instruction &TI, return; } const ValueLatticeElement &SCValue = getValueState(SI->getCondition()); - if (ConstantInt *CI = getConstantInt(SCValue)) { + if (ConstantInt *CI = + getConstantInt(SCValue, SI->getCondition()->getType())) { Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true; return; } @@ -1064,7 +1069,8 @@ void SCCPInstVisitor::getFeasibleSuccessors(Instruction &TI, if (auto *IBR = dyn_cast(&TI)) { // Casts are folded by visitCastInst. ValueLatticeElement IBRValue = getValueState(IBR->getAddress()); - BlockAddress *Addr = dyn_cast_or_null(getConstant(IBRValue)); + BlockAddress *Addr = dyn_cast_or_null( + getConstant(IBRValue, IBR->getAddress()->getType())); if (!Addr) { // Overdefined or unknown condition? // All destinations are executable! if (!IBRValue.isUnknownOrUndef()) @@ -1219,7 +1225,7 @@ void SCCPInstVisitor::visitCastInst(CastInst &I) { if (OpSt.isUnknownOrUndef()) return; - if (Constant *OpC = getConstant(OpSt)) { + if (Constant *OpC = getConstant(OpSt, I.getOperand(0)->getType())) { // Fold the constant as we build. Constant *C = ConstantFoldCastOperand(I.getOpcode(), OpC, I.getType(), DL); markConstant(&I, C); @@ -1354,7 +1360,8 @@ void SCCPInstVisitor::visitSelectInst(SelectInst &I) { if (CondValue.isUnknownOrUndef()) return; - if (ConstantInt *CondCB = getConstantInt(CondValue)) { + if (ConstantInt *CondCB = + getConstantInt(CondValue, I.getCondition()->getType())) { Value *OpVal = CondCB->isZero() ? I.getFalseValue() : I.getTrueValue(); mergeInValue(&I, getValueState(OpVal)); return; @@ -1387,8 +1394,8 @@ void SCCPInstVisitor::visitUnaryOperator(Instruction &I) { return; if (SCCPSolver::isConstant(V0State)) - if (Constant *C = ConstantFoldUnaryOpOperand(I.getOpcode(), - getConstant(V0State), DL)) + if (Constant *C = ConstantFoldUnaryOpOperand( + I.getOpcode(), getConstant(V0State, I.getType()), DL)) return (void)markConstant(IV, &I, C); markOverdefined(&I); @@ -1412,8 +1419,8 @@ void SCCPInstVisitor::visitFreezeInst(FreezeInst &I) { return; if (SCCPSolver::isConstant(V0State) && - isGuaranteedNotToBeUndefOrPoison(getConstant(V0State))) - return (void)markConstant(IV, &I, getConstant(V0State)); + isGuaranteedNotToBeUndefOrPoison(getConstant(V0State, I.getType()))) + return (void)markConstant(IV, &I, getConstant(V0State, I.getType())); markOverdefined(&I); } @@ -1437,10 +1444,12 @@ void SCCPInstVisitor::visitBinaryOperator(Instruction &I) { // If either of the operands is a constant, try to fold it to a constant. // TODO: Use information from notconstant better. if ((V1State.isConstant() || V2State.isConstant())) { - Value *V1 = SCCPSolver::isConstant(V1State) ? getConstant(V1State) - : I.getOperand(0); - Value *V2 = SCCPSolver::isConstant(V2State) ? getConstant(V2State) - : I.getOperand(1); + Value *V1 = SCCPSolver::isConstant(V1State) + ? getConstant(V1State, I.getOperand(0)->getType()) + : I.getOperand(0); + Value *V2 = SCCPSolver::isConstant(V2State) + ? getConstant(V2State, I.getOperand(1)->getType()) + : I.getOperand(1); Value *R = simplifyBinOp(I.getOpcode(), V1, V2, SimplifyQuery(DL)); auto *C = dyn_cast_or_null(R); if (C) { @@ -1518,7 +1527,7 @@ void SCCPInstVisitor::visitGetElementPtrInst(GetElementPtrInst &I) { if (SCCPSolver::isOverdefined(State)) return (void)markOverdefined(&I); - if (Constant *C = getConstant(State)) { + if (Constant *C = getConstant(State, I.getOperand(i)->getType())) { Operands.push_back(C); continue; } @@ -1584,7 +1593,7 @@ void SCCPInstVisitor::visitLoadInst(LoadInst &I) { ValueLatticeElement &IV = ValueState[&I]; if (SCCPSolver::isConstant(PtrVal)) { - Constant *Ptr = getConstant(PtrVal); + Constant *Ptr = getConstant(PtrVal, I.getOperand(0)->getType()); // load null is undefined. if (isa(Ptr)) { @@ -1647,7 +1656,7 @@ void SCCPInstVisitor::handleCallOverdefined(CallBase &CB) { if (SCCPSolver::isOverdefined(State)) return (void)markOverdefined(&CB); assert(SCCPSolver::isConstant(State) && "Unknown state!"); - Operands.push_back(getConstant(State)); + Operands.push_back(getConstant(State, A->getType())); } if (SCCPSolver::isOverdefined(getValueState(&CB))) @@ -2067,8 +2076,9 @@ bool SCCPSolver::isStructLatticeConstant(Function *F, StructType *STy) { return Visitor->isStructLatticeConstant(F, STy); } -Constant *SCCPSolver::getConstant(const ValueLatticeElement &LV) const { - return Visitor->getConstant(LV); +Constant *SCCPSolver::getConstant(const ValueLatticeElement &LV, + Type *Ty) const { + return Visitor->getConstant(LV, Ty); } Constant *SCCPSolver::getConstantOrNull(Value *V) const { diff --git a/llvm/test/Transforms/SCCP/intrinsics.ll b/llvm/test/Transforms/SCCP/intrinsics.ll index 3fc7637ab7327..5edb31738e685 100644 --- a/llvm/test/Transforms/SCCP/intrinsics.ll +++ b/llvm/test/Transforms/SCCP/intrinsics.ll @@ -122,3 +122,17 @@ exit: %p_umax = call i8 @llvm.umax.i8(i8 %p, i8 1) ret i8 %p_umax } + +define <4 x i32> @pr63380(<4 x i32> %input) { +; CHECK-LABEL: @pr63380( +; CHECK-NEXT: [[CTLZ_1:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> [[INPUT:%.*]], i1 false) +; CHECK-NEXT: [[CTLZ_2:%.*]] = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> [[CTLZ_1]], i1 true) +; CHECK-NEXT: ret <4 x i32> +; + %ctlz.1 = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %input, i1 false) + %ctlz.2 = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %ctlz.1, i1 true) + %ctlz.3 = call <4 x i32> @llvm.ctlz.v4i32(<4 x i32> %ctlz.2, i1 true) + ret <4 x i32> %ctlz.3 +} + +declare <4 x i32> @llvm.ctlz.v4i32(<4 x i32>, i1 immarg) From 65a2cde77195887f308d4f14be2e3ae18c5c5c0a Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Mon, 19 Jun 2023 11:23:50 +0200 Subject: [PATCH 009/130] Remove extra closing `)` from MLIR --view-op-graph GraphViz emission This was a spurious closing parenthese. --- mlir/lib/Transforms/ViewOpGraph.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/mlir/lib/Transforms/ViewOpGraph.cpp b/mlir/lib/Transforms/ViewOpGraph.cpp index def8a1443b1aa..7689aa061a09d 100644 --- a/mlir/lib/Transforms/ViewOpGraph.cpp +++ b/mlir/lib/Transforms/ViewOpGraph.cpp @@ -228,7 +228,6 @@ class PrintOpPass : public impl::ViewOpGraphBase { llvm::raw_string_ostream ss(buf); interleaveComma(op->getResultTypes(), ss); os << truncateString(ss.str()) << ")"; - os << ")"; } // Print attributes. From 9ef73f2f58ecfce21bdeb27f68b224d9be97cfe6 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Mon, 19 Jun 2023 11:58:49 +0200 Subject: [PATCH 010/130] Emit MLIR trampoline wrapper function with LLVM private linkage The wrapper, as most of compiler-generated functions, are intended to serve the IR for the current module. The safest linkage is to keep these private to avoid any possible collision with other modules. Differential Revision: https://reviews.llvm.org/D153255 --- mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp | 2 ++ ...emit-c-wrappers-for-external-functions.mlir | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp index 5867d9fa02b06..3ae997d713104 100644 --- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp +++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp @@ -208,6 +208,8 @@ static void wrapExternalFunction(OpBuilder &builder, Location loc, wrapperType, LLVM::Linkage::External, /*dsoLocal*/ false, /*cconv*/ LLVM::CConv::C, attributes); + // The wrapper that we synthetize here should only be visible in this module. + newFuncOp.setLinkage(LLVM::Linkage::Private); builder.setInsertionPointToStart(newFuncOp.addEntryBlock()); // Get a ValueRange containing arguments. diff --git a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir index 3e8841120463f..027d29b0bf079 100644 --- a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir +++ b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir @@ -1,38 +1,38 @@ // RUN: mlir-opt -llvm-request-c-wrappers -convert-func-to-llvm='use-opaque-pointers=1' %s | FileCheck %s -// CHECK: llvm.func @res_attrs_with_memref_return() -> (!llvm.struct{{.*}} {test.returnOne}) +// CHECK: llvm.func private @res_attrs_with_memref_return() -> (!llvm.struct{{.*}} {test.returnOne}) // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_memref_return // CHECK-SAME: !llvm.ptr // CHECK-NOT: test.returnOne func.func private @res_attrs_with_memref_return() -> (memref {test.returnOne}) -// CHECK: llvm.func @res_attrs_with_value_return() -> (f32 {test.returnOne = 1 : i64}) +// CHECK: llvm.func private @res_attrs_with_value_return() -> (f32 {test.returnOne = 1 : i64}) // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_value_return // CHECK-SAME: -> (f32 {test.returnOne = 1 : i64}) func.func private @res_attrs_with_value_return() -> (f32 {test.returnOne = 1}) -// CHECK: llvm.func @multiple_return() -> !llvm.struct<{{.*}}> +// CHECK: llvm.func private @multiple_return() -> !llvm.struct<{{.*}}> // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return // CHECK-NOT: test.returnOne // CHECK-NOT: test.returnTwo // CHECK-NOT: test.returnThree func.func private @multiple_return() -> (memref {test.returnOne = 1}, f32 {test.returnTwo = 2, test.returnThree = 3}) -// CHECK: llvm.func @multiple_return_missing_res_attr() -> !llvm.struct<{{.*}}> +// CHECK: llvm.func private @multiple_return_missing_res_attr() -> !llvm.struct<{{.*}}> // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return_missing_res_attr // CHECK-NOT: test.returnOne // CHECK-NOT: test.returnTwo // CHECK-NOT: test.returnThree func.func private @multiple_return_missing_res_attr() -> (memref {test.returnOne = 1}, i64, f32 {test.returnTwo = 2, test.returnThree = 3}) -// CHECK: llvm.func @one_arg_attr_no_res_attrs_with_memref_return({{.*}}) -> !llvm.struct{{.*}} +// CHECK: llvm.func private @one_arg_attr_no_res_attrs_with_memref_return({{.*}}) -> !llvm.struct{{.*}} // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_no_res_attrs_with_memref_return // CHECK-SAME: !llvm.ptr // CHECK-SAME: !llvm.ptr // CHECK-SAME: {test.argOne = 1 : i64}) func.func private @one_arg_attr_no_res_attrs_with_memref_return(%arg0: memref {test.argOne = 1}) -> memref -// CHECK: llvm.func @one_arg_attr_one_res_attr_with_memref_return({{.*}}) -> (!llvm.struct<{{.*}}> {test.returnOne = 1 : i64}) +// CHECK: llvm.func private @one_arg_attr_one_res_attr_with_memref_return({{.*}}) -> (!llvm.struct<{{.*}}> {test.returnOne = 1 : i64}) // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_memref_return // CHECK-SAME: !llvm.ptr // CHECK-NOT: test.returnOne @@ -40,14 +40,14 @@ func.func private @one_arg_attr_no_res_attrs_with_memref_return(%arg0: memref {test.argOne = 1}) -> (memref {test.returnOne = 1}) -// CHECK: llvm.func @one_arg_attr_one_res_attr_with_value_return({{.*}}) -> (f32 {test.returnOne = 1 : i64}) +// CHECK: llvm.func private @one_arg_attr_one_res_attr_with_value_return({{.*}}) -> (f32 {test.returnOne = 1 : i64}) // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_value_return // CHECK-SAME: !llvm.ptr // CHECK-SAME: {test.argOne = 1 : i64} // CHECK-SAME: -> (f32 {test.returnOne = 1 : i64}) func.func private @one_arg_attr_one_res_attr_with_value_return(%arg0: memref {test.argOne = 1}) -> (f32 {test.returnOne = 1}) -// CHECK: llvm.func @multiple_arg_attr_multiple_res_attr({{.*}}) -> !llvm.struct<{{.*}}> +// CHECK: llvm.func private @multiple_arg_attr_multiple_res_attr({{.*}}) -> !llvm.struct<{{.*}}> // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_arg_attr_multiple_res_attr // CHECK-SAME: !llvm.ptr // CHECK-NOT: test.returnOne @@ -58,7 +58,7 @@ func.func private @one_arg_attr_one_res_attr_with_value_return(%arg0: memref {test.argZero = 0}, %arg1: f32, %arg2: i32 {test.argTwo = 2}) -> (f32, memref {test.returnOne = 1}, i32 {test.returnTwo = 2}) -// CHECK: llvm.func weak @drop_linkage_attr() -> (!llvm.struct{{.*}} {test.returnOne}) +// CHECK: llvm.func private @drop_linkage_attr() -> (!llvm.struct{{.*}} {test.returnOne}) // CHECK-LABEL: llvm.func @_mlir_ciface_drop_linkage_attr // CHECK-SAME: !llvm.ptr // CHECK-NOT: llvm.linkage From 6f2e92c10cebca51f9bc98b99fa3b5583ff396c4 Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Mon, 19 Jun 2023 07:32:34 -0400 Subject: [PATCH 011/130] Re-land [LLD] Allow usage of LLD as a library This reverts commit aa495214b39d475bab24b468de7a7c676ce9e366. As discussed in https://github.com/llvm/llvm-project/issues/53475 this patch allows for using LLD-as-a-lib. It also lets clients link only the drivers that they want (see unit tests). This also adds the unit test infra as in the other LLVM projects. Among the test coverage, I've added the original issue from @krzysz00, see: https://github.com/ROCmSoftwarePlatform/D108850-lld-bug-reproduction Important note: this doesn't allow (yet) linking in parallel. This will come a bit later hopefully, in subsequent patches, for COFF at least. Differential revision: https://reviews.llvm.org/D119049 --- lld/CMakeLists.txt | 2 + lld/COFF/Driver.cpp | 2 +- lld/Common/CMakeLists.txt | 1 + lld/Common/DriverDispatcher.cpp | 203 ++++++++++++++++++++++++ lld/ELF/Driver.cpp | 11 +- lld/MachO/Driver.cpp | 9 +- lld/MinGW/Driver.cpp | 14 +- lld/docs/NewLLD.rst | 2 +- lld/docs/index.rst | 2 +- lld/include/lld/Common/Driver.h | 71 +++++---- lld/test/CMakeLists.txt | 16 +- lld/test/Unit/lit.cfg.py | 47 ++++++ lld/test/Unit/lit.site.cfg.py.in | 12 ++ lld/tools/lld/lld.cpp | 191 ++++------------------ lld/unittests/AsLibAll/AllDrivers.cpp | 35 ++++ lld/unittests/AsLibAll/CMakeLists.txt | 17 ++ lld/unittests/AsLibELF/CMakeLists.txt | 14 ++ lld/unittests/AsLibELF/Inputs/kernel1.o | Bin 0 -> 1688 bytes lld/unittests/AsLibELF/Inputs/kernel2.o | Bin 0 -> 1688 bytes lld/unittests/AsLibELF/ROCm.cpp | 74 +++++++++ lld/unittests/AsLibELF/SomeDrivers.cpp | 37 +++++ lld/unittests/CMakeLists.txt | 8 + lld/wasm/Driver.cpp | 2 +- llvm/cmake/modules/AddLLVM.cmake | 10 ++ 24 files changed, 570 insertions(+), 210 deletions(-) create mode 100644 lld/Common/DriverDispatcher.cpp create mode 100644 lld/test/Unit/lit.cfg.py create mode 100644 lld/test/Unit/lit.site.cfg.py.in create mode 100644 lld/unittests/AsLibAll/AllDrivers.cpp create mode 100644 lld/unittests/AsLibAll/CMakeLists.txt create mode 100644 lld/unittests/AsLibELF/CMakeLists.txt create mode 100644 lld/unittests/AsLibELF/Inputs/kernel1.o create mode 100644 lld/unittests/AsLibELF/Inputs/kernel2.o create mode 100644 lld/unittests/AsLibELF/ROCm.cpp create mode 100644 lld/unittests/AsLibELF/SomeDrivers.cpp create mode 100644 lld/unittests/CMakeLists.txt diff --git a/lld/CMakeLists.txt b/lld/CMakeLists.txt index 518289a6328b6..1ffcf2d9a2564 100644 --- a/lld/CMakeLists.txt +++ b/lld/CMakeLists.txt @@ -191,6 +191,8 @@ add_subdirectory(Common) add_subdirectory(tools/lld) if (LLVM_INCLUDE_TESTS) + add_custom_target(LLDUnitTests) + llvm_add_unittests(LLD_UNITTESTS_ADDED) add_subdirectory(test) endif() diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index d4115a0e85eb2..f8e2c17099c0c 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -64,7 +64,7 @@ namespace lld::coff { bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). + // This driver-specific context will be freed later by unsafeLldMain(). auto *ctx = new COFFLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); diff --git a/lld/Common/CMakeLists.txt b/lld/Common/CMakeLists.txt index 71df89c28aea0..c975da2a49b6b 100644 --- a/lld/Common/CMakeLists.txt +++ b/lld/Common/CMakeLists.txt @@ -23,6 +23,7 @@ set_source_files_properties("${version_inc}" add_lld_library(lldCommon Args.cpp CommonLinkerContext.cpp + DriverDispatcher.cpp DWARF.cpp ErrorHandler.cpp Filesystem.cpp diff --git a/lld/Common/DriverDispatcher.cpp b/lld/Common/DriverDispatcher.cpp new file mode 100644 index 0000000000000..379a4c6ddabea --- /dev/null +++ b/lld/Common/DriverDispatcher.cpp @@ -0,0 +1,203 @@ +//===- DriverDispatcher.cpp - Support using LLD as a library --------------===// +// +// 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 "lld/Common/CommonLinkerContext.h" +#include "lld/Common/Driver.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Memory.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/Triple.h" +#include + +using namespace lld; +using namespace llvm; +using namespace llvm::sys; + +static void err(const Twine &s) { llvm::errs() << s << "\n"; } + +static Flavor getFlavor(StringRef s) { + return StringSwitch(s) + .CasesLower("ld", "ld.lld", "gnu", Gnu) + .CasesLower("wasm", "ld-wasm", Wasm) + .CaseLower("link", WinLink) + .CasesLower("ld64", "ld64.lld", "darwin", Darwin) + .Default(Invalid); +} + +static cl::TokenizerCallback getDefaultQuotingStyle() { + if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) + return cl::TokenizeWindowsCommandLine; + return cl::TokenizeGNUCommandLine; +} + +static bool isPETargetName(StringRef s) { + return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe"; +} + +static std::optional isPETarget(llvm::ArrayRef args) { + for (auto it = args.begin(); it + 1 != args.end(); ++it) { + if (StringRef(*it) != "-m") + continue; + return isPETargetName(*(it + 1)); + } + + // Expand response files (arguments in the form of @) + // to allow detecting the -m argument from arguments in them. + SmallVector expandedArgs(args.data(), + args.data() + args.size()); + BumpPtrAllocator a; + StringSaver saver(a); + cl::ExpansionContext ectx(saver.getAllocator(), getDefaultQuotingStyle()); + if (Error e = ectx.expandResponseFiles(expandedArgs)) { + err(toString(std::move(e))); + return std::nullopt; + } + + for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) { + if (StringRef(*it) != "-m") + continue; + return isPETargetName(*(it + 1)); + } + +#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW + return true; +#else + return false; +#endif +} + +static Flavor parseProgname(StringRef progname) { + // Use GNU driver for "ld" by default. + if (progname == "ld") + return Gnu; + + // Progname may be something like "lld-gnu". Parse it. + SmallVector v; + progname.split(v, "-"); + for (StringRef s : v) + if (Flavor f = getFlavor(s)) + return f; + return Invalid; +} + +static Flavor +parseFlavorWithoutMinGW(llvm::SmallVectorImpl &argsV) { + // Parse -flavor option. + if (argsV.size() > 1 && argsV[1] == StringRef("-flavor")) { + if (argsV.size() <= 2) { + err("missing arg value for '-flavor'"); + return Invalid; + } + Flavor f = getFlavor(argsV[2]); + if (f == Invalid) { + err("Unknown flavor: " + StringRef(argsV[2])); + return Invalid; + } + argsV.erase(argsV.begin() + 1, argsV.begin() + 3); + return f; + } + + // Deduct the flavor from argv[0]. + StringRef arg0 = path::filename(argsV[0]); + if (arg0.ends_with_insensitive(".exe")) + arg0 = arg0.drop_back(4); + Flavor f = parseProgname(arg0); + if (f == Invalid) { + err("lld is a generic driver.\n" + "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" + " (WebAssembly) instead"); + return Invalid; + } + return f; +} + +static Flavor parseFlavor(llvm::SmallVectorImpl &argsV) { + Flavor f = parseFlavorWithoutMinGW(argsV); + if (f == Gnu) { + auto isPE = isPETarget(argsV); + if (!isPE) + return Invalid; + if (*isPE) + return MinGW; + } + return f; +} + +static Driver whichDriver(llvm::SmallVectorImpl &argsV, + llvm::ArrayRef drivers) { + Flavor f = parseFlavor(argsV); + auto it = + llvm::find_if(drivers, [=](auto &driverdef) { return driverdef.f == f; }); + if (it == drivers.end()) { + // Driver is invalid or not available in this build. + return [](llvm::ArrayRef, llvm::raw_ostream &, + llvm::raw_ostream &, bool, bool) { return false; }; + } + return it->d; +} + +namespace lld { +bool inTestOutputDisabled = false; + +/// Universal linker main(). This linker emulates the gnu, darwin, or +/// windows linker based on the argv[0] or -flavor option. +int unsafeLldMain(llvm::ArrayRef args, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, + llvm::ArrayRef drivers, bool exitEarly) { + SmallVector argsV(args); + Driver d = whichDriver(argsV, drivers); + // Run the driver. If an error occurs, false will be returned. + int r = !d(argsV, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled); + // At this point 'r' is either 1 for error, and 0 for no error. + + // Call exit() if we can to avoid calling destructors. + if (exitEarly) + exitLld(r); + + // Delete the global context and clear the global context pointer, so that it + // cannot be accessed anymore. + CommonLinkerContext::destroy(); + + return r; +} +} // namespace lld + +Result lld::lldMain(llvm::ArrayRef args, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, + llvm::ArrayRef drivers) { + int r = 0; + { + // The crash recovery is here only to be able to recover from arbitrary + // control flow when fatal() is called (through setjmp/longjmp or + // __try/__except). + llvm::CrashRecoveryContext crc; + if (!crc.RunSafely([&]() { + r = unsafeLldMain(args, stdoutOS, stderrOS, drivers, + /*exitEarly=*/false); + })) + return {crc.RetCode, /*canRunAgain=*/false}; + } + + // Cleanup memory and reset everything back in pristine condition. This path + // is only taken when LLD is in test, or when it is used as a library. + llvm::CrashRecoveryContext crc; + if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) { + // The memory is corrupted beyond any possible recovery. + return {r, /*canRunAgain=*/false}; + } + return {r, /*canRunAgain=*/true}; +} diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index db5e9bc5ab04b..4eb10fc3c91e1 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -107,10 +107,11 @@ void Ctx::reset() { needsTlsLd.store(false, std::memory_order_relaxed); } -bool elf::link(ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). +namespace lld { +namespace elf { +bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { + // This driver-specific context will be freed later by unsafeLldMain(). auto *ctx = new CommonLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); @@ -147,6 +148,8 @@ bool elf::link(ArrayRef args, llvm::raw_ostream &stdoutOS, return errorCount() == 0; } +} // namespace elf +} // namespace lld // Parses a linker -m option. static std::tuple parseEmulation(StringRef emul) { diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp index 87664b5c2ede3..8fa3ee0828797 100644 --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1367,9 +1367,10 @@ static void handleExplicitExports() { } } -bool macho::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { +namespace lld { +namespace macho { +bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { // This driver-specific context will be freed later by lldMain(). auto *ctx = new CommonLinkerContext; @@ -1968,3 +1969,5 @@ bool macho::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, return errorCount() == 0; } +} // namespace macho +} // namespace lld diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp index c5a32c3a90bb8..a5b83d2f12ca1 100644 --- a/lld/MinGW/Driver.cpp +++ b/lld/MinGW/Driver.cpp @@ -157,11 +157,17 @@ searchLibrary(StringRef name, ArrayRef searchPaths, bool bStatic) { return ""; } +namespace lld { +namespace coff { +bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); +} + +namespace mingw { // Convert Unix-ish command line arguments to Windows-ish ones and // then call coff::link. -bool mingw::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, - bool disableOutput) { +bool link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { auto *ctx = new CommonLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); @@ -482,3 +488,5 @@ bool mingw::link(ArrayRef argsArr, llvm::raw_ostream &stdoutOS, return coff::link(vec, stdoutOS, stderrOS, exitEarly, disableOutput); } +} // namespace mingw +} // namespace lld diff --git a/lld/docs/NewLLD.rst b/lld/docs/NewLLD.rst index 1b1c87067f512..18b0cc83db519 100644 --- a/lld/docs/NewLLD.rst +++ b/lld/docs/NewLLD.rst @@ -5,7 +5,7 @@ The ELF Linker as a Library --------------------------- You can embed LLD to your program by linking against it and calling the linker's -entry point function lld::elf::link. +entry point function ``lld::lldMain``. The current policy is that it is your responsibility to give trustworthy object files. The function is guaranteed to return as long as you do not pass corrupted diff --git a/lld/docs/index.rst b/lld/docs/index.rst index a50d5c0b3453d..bf7cf4846e854 100644 --- a/lld/docs/index.rst +++ b/lld/docs/index.rst @@ -36,7 +36,7 @@ Features external linkers. All you have to do is to construct object files and command line arguments just like you would do to invoke an external linker and then call the linker's main function, - ``lld::elf::link``, from your code. + ``lld::lldMain``, from your code. - It is small. We are using LLVM libObject library to read from object files, so it is not a completely fair comparison, but as of February diff --git a/lld/include/lld/Common/Driver.h b/lld/include/lld/Common/Driver.h index 19573e6e100dd..8520e6e7e257c 100644 --- a/lld/include/lld/Common/Driver.h +++ b/lld/include/lld/Common/Driver.h @@ -13,8 +13,25 @@ #include "llvm/Support/raw_ostream.h" namespace lld { -struct SafeReturn { - int ret; +enum Flavor { + Invalid, + Gnu, // -flavor gnu + MinGW, // -flavor gnu MinGW + WinLink, // -flavor link + Darwin, // -flavor darwin + Wasm, // -flavor wasm +}; + +using Driver = bool (*)(llvm::ArrayRef, llvm::raw_ostream &, + llvm::raw_ostream &, bool, bool); + +struct DriverDef { + Flavor f; + Driver d; +}; + +struct Result { + int retCode; bool canRunAgain; }; @@ -24,33 +41,29 @@ struct SafeReturn { // and re-entry would not be possible anymore. Use exitLld() in that case to // properly exit your application and avoid intermittent crashes on exit caused // by cleanup. -SafeReturn safeLldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS); - -namespace coff { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); -} - -namespace mingw { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); -} - -namespace elf { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); -} - -namespace macho { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); -} - -namespace wasm { -bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); -} +Result lldMain(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, + llvm::raw_ostream &stderrOS, llvm::ArrayRef drivers); } // namespace lld +// With this macro, library users must specify which drivers they use, provide +// that information to lldMain() in the `drivers` param, and link the +// corresponding driver library in their executable. +#define LLD_HAS_DRIVER(name) \ + namespace lld { \ + namespace name { \ + bool link(llvm::ArrayRef args, llvm::raw_ostream &stdoutOS, \ + llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); \ + } \ + } + +// An array which declares that all LLD drivers are linked in your executable. +// Must be used along with LLD_HAS_DRIVERS. See examples in LLD unittests. +#define LLD_ALL_DRIVERS \ + { \ + {lld::WinLink, &lld::coff::link}, {lld::Gnu, &lld::elf::link}, \ + {lld::MinGW, &lld::mingw::link}, {lld::Darwin, &lld::macho::link}, { \ + lld::Wasm, &lld::wasm::link \ + } \ + } + #endif diff --git a/lld/test/CMakeLists.txt b/lld/test/CMakeLists.txt index 042bfd9140b6b..f1cfacba9dd16 100644 --- a/lld/test/CMakeLists.txt +++ b/lld/test/CMakeLists.txt @@ -14,12 +14,23 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py MAIN_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py - ) +) +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.py.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py + MAIN_CONFIG + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py + PATHS + "SHLIBDIR" + "LLD_BINARY_DIR" + "LLD_SOURCE_DIR" +) set(LLD_TEST_DEPS lld) if (NOT LLD_BUILT_STANDALONE) list(APPEND LLD_TEST_DEPS FileCheck + LLDUnitTests count dsymutil llc @@ -60,6 +71,7 @@ add_lit_testsuite(check-lld "Running lld test suite" ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${LLD_TEST_DEPS} ) +set_target_properties(check-lld PROPERTIES FOLDER "lld tests") add_custom_target(lld-test-depends DEPENDS ${LLD_TEST_DEPS}) set_target_properties(lld-test-depends PROPERTIES FOLDER "lld tests") @@ -68,8 +80,6 @@ add_lit_testsuites(LLD ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${LLD_TEST_DEPS} ) -set_target_properties(check-lld PROPERTIES FOLDER "lld tests") - # Add a legacy target spelling: lld-test add_custom_target(lld-test) add_dependencies(lld-test check-lld) diff --git a/lld/test/Unit/lit.cfg.py b/lld/test/Unit/lit.cfg.py new file mode 100644 index 0000000000000..ffbbddeeed5ec --- /dev/null +++ b/lld/test/Unit/lit.cfg.py @@ -0,0 +1,47 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +import os +import subprocess + +import lit.formats + +# name: The name of this test suite. +config.name = "LLD-Unit" + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = [] + +# test_source_root: The root path where tests are located. +# test_exec_root: The root path where tests should be run. +config.test_exec_root = os.path.join(config.lld_obj_root, "unittests") +config.test_source_root = config.test_exec_root + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.GoogleTest(config.llvm_build_mode, "Tests") + +# Propagate the temp directory. Windows requires this because it uses \Windows\ +# if none of these are present. +if "TMP" in os.environ: + config.environment["TMP"] = os.environ["TMP"] +if "TEMP" in os.environ: + config.environment["TEMP"] = os.environ["TEMP"] + +# Propagate HOME as it can be used to override incorrect homedir in passwd +# that causes the tests to fail. +if "HOME" in os.environ: + config.environment["HOME"] = os.environ["HOME"] + +# Win32 seeks DLLs along %PATH%. +if sys.platform in ["win32", "cygwin"] and os.path.isdir(config.shlibdir): + config.environment["PATH"] = os.path.pathsep.join(( + config.shlibdir, config.environment["PATH"])) + +# Win32 may use %SYSTEMDRIVE% during file system shell operations, so propogate. +if sys.platform == "win32" and "SYSTEMDRIVE" in os.environ: + config.environment["SYSTEMDRIVE"] = os.environ["SYSTEMDRIVE"] + +# Expand the LLD source path so that unittests can use associated input files. +# (see AsLibELF/ROCm.cpp test) +config.environment["LLD_SRC_DIR"] = config.lld_src_dir diff --git a/lld/test/Unit/lit.site.cfg.py.in b/lld/test/Unit/lit.site.cfg.py.in new file mode 100644 index 0000000000000..204ac5f204d7b --- /dev/null +++ b/lld/test/Unit/lit.site.cfg.py.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +import sys + +config.llvm_build_mode = lit_config.substitute("@LLVM_BUILD_MODE@") +config.shlibdir = lit_config.substitute(path(r"@SHLIBDIR@")) +config.lld_obj_root = path(r"@LLD_BINARY_DIR@") +config.lld_src_dir = path(r"@LLD_SOURCE_DIR@") + +# Let the main config do the real work. +lit_config.load_config( + config, os.path.join(config.lld_src_dir, "test/Unit/lit.cfg.py")) diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index 2fc9c3a669146..2c30bc905106e 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -25,7 +25,6 @@ // //===----------------------------------------------------------------------===// -#include "lld/Common/CommonLinkerContext.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -49,161 +48,15 @@ using namespace lld; using namespace llvm; using namespace llvm::sys; -enum Flavor { - Invalid, - Gnu, // -flavor gnu - WinLink, // -flavor link - Darwin, // -flavor darwin - Wasm, // -flavor wasm -}; +namespace lld { +extern bool inTestOutputDisabled; -[[noreturn]] static void die(const Twine &s) { - llvm::errs() << s << "\n"; - exit(1); -} - -static Flavor getFlavor(StringRef s) { - return StringSwitch(s) - .CasesLower("ld", "ld.lld", "gnu", Gnu) - .CasesLower("wasm", "ld-wasm", Wasm) - .CaseLower("link", WinLink) - .CasesLower("ld64", "ld64.lld", "darwin", Darwin) - .Default(Invalid); -} - -static cl::TokenizerCallback getDefaultQuotingStyle() { - if (Triple(sys::getProcessTriple()).getOS() == Triple::Win32) - return cl::TokenizeWindowsCommandLine; - return cl::TokenizeGNUCommandLine; -} - -static bool isPETargetName(StringRef s) { - return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe"; -} - -static bool isPETarget(std::vector &v) { - for (auto it = v.begin(); it + 1 != v.end(); ++it) { - if (StringRef(*it) != "-m") - continue; - return isPETargetName(*(it + 1)); - } - // Expand response files (arguments in the form of @) - // to allow detecting the -m argument from arguments in them. - SmallVector expandedArgs(v.data(), v.data() + v.size()); - BumpPtrAllocator a; - StringSaver saver(a); - cl::ExpansionContext ECtx(saver.getAllocator(), getDefaultQuotingStyle()); - if (Error Err = ECtx.expandResponseFiles(expandedArgs)) - die(toString(std::move(Err))); - for (auto it = expandedArgs.begin(); it + 1 != expandedArgs.end(); ++it) { - if (StringRef(*it) != "-m") - continue; - return isPETargetName(*(it + 1)); - } - -#ifdef LLD_DEFAULT_LD_LLD_IS_MINGW - return true; -#else - return false; -#endif -} - -static Flavor parseProgname(StringRef progname) { - // Use GNU driver for "ld" by default. - if (progname == "ld") - return Gnu; - - // Progname may be something like "lld-gnu". Parse it. - SmallVector v; - progname.split(v, "-"); - for (StringRef s : v) - if (Flavor f = getFlavor(s)) - return f; - return Invalid; -} - -static Flavor parseFlavor(std::vector &v) { - // Parse -flavor option. - if (v.size() > 1 && v[1] == StringRef("-flavor")) { - if (v.size() <= 2) - die("missing arg value for '-flavor'"); - Flavor f = getFlavor(v[2]); - if (f == Invalid) - die("Unknown flavor: " + StringRef(v[2])); - v.erase(v.begin() + 1, v.begin() + 3); - return f; - } - - // Deduct the flavor from argv[0]. - StringRef arg0 = path::filename(v[0]); - if (arg0.ends_with_insensitive(".exe")) - arg0 = arg0.drop_back(4); - return parseProgname(arg0); -} - -bool inTestOutputDisabled = false; - -/// Universal linker main(). This linker emulates the gnu, darwin, or -/// windows linker based on the argv[0] or -flavor option. -static int lldMain(int argc, const char **argv, llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS, bool exitEarly = true) { - std::vector args(argv, argv + argc); - auto link = [&args]() { - Flavor f = parseFlavor(args); - if (f == Gnu && isPETarget(args)) - return mingw::link; - else if (f == Gnu) - return elf::link; - else if (f == WinLink) - return coff::link; - else if (f == Darwin) - return macho::link; - else if (f == Wasm) - return lld::wasm::link; - else - die("lld is a generic driver.\n" - "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld" - " (WebAssembly) instead"); - }(); - // Run the driver. If an error occurs, false will be returned. - bool r = link(args, stdoutOS, stderrOS, exitEarly, inTestOutputDisabled); - - // Call exit() if we can to avoid calling destructors. - if (exitEarly) - exitLld(!r ? 1 : 0); - - // Delete the global context and clear the global context pointer, so that it - // cannot be accessed anymore. - CommonLinkerContext::destroy(); - - return !r ? 1 : 0; -} - -// Similar to lldMain except that exceptions are caught. -SafeReturn lld::safeLldMain(int argc, const char **argv, - llvm::raw_ostream &stdoutOS, - llvm::raw_ostream &stderrOS) { - int r = 0; - { - // The crash recovery is here only to be able to recover from arbitrary - // control flow when fatal() is called (through setjmp/longjmp or - // __try/__except). - llvm::CrashRecoveryContext crc; - if (!crc.RunSafely([&]() { - r = lldMain(argc, argv, stdoutOS, stderrOS, /*exitEarly=*/false); - })) - return {crc.RetCode, /*canRunAgain=*/false}; - } - - // Cleanup memory and reset everything back in pristine condition. This path - // is only taken when LLD is in test, or when it is used as a library. - llvm::CrashRecoveryContext crc; - if (!crc.RunSafely([&]() { CommonLinkerContext::destroy(); })) { - // The memory is corrupted beyond any possible recovery. - return {r, /*canRunAgain=*/false}; - } - return {r, /*canRunAgain=*/true}; -} +// Bypass the crash recovery handler, which is only meant to be used in +// LLD-as-lib scenarios. +int unsafeLldMain(llvm::ArrayRef args, + llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, + llvm::ArrayRef drivers, bool exitEarly); +} // namespace lld // When in lit tests, tells how many times the LLD tool should re-execute the // main loop with the same inputs. When not in test, returns a value of 0 which @@ -215,6 +68,12 @@ static unsigned inTestVerbosity() { return v; } +LLD_HAS_DRIVER(coff) +LLD_HAS_DRIVER(elf) +LLD_HAS_DRIVER(mingw) +LLD_HAS_DRIVER(macho) +LLD_HAS_DRIVER(wasm) + int lld_main(int argc, char **argv, const llvm::ToolContext &) { InitLLVM x(argc, argv); sys::Process::UseANSIEscapeCodes(true); @@ -225,11 +84,16 @@ int lld_main(int argc, char **argv, const llvm::ToolContext &) { LLVM_BUILTIN_TRAP; } + ArrayRef args(argv, argv + argc); + // Not running in lit tests, just take the shortest codepath with global // exception handling and no memory cleanup on exit. - if (!inTestVerbosity()) - return lldMain(argc, const_cast(argv), llvm::outs(), - llvm::errs()); + if (!inTestVerbosity()) { + int r = + lld::unsafeLldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS, + /*exitEarly=*/true); + return r; + } std::optional mainRet; CrashRecoveryContext::Enable(); @@ -239,16 +103,15 @@ int lld_main(int argc, char **argv, const llvm::ToolContext &) { inTestOutputDisabled = (i != 1); // Execute one iteration. - auto r = safeLldMain(argc, const_cast(argv), llvm::outs(), - llvm::errs()); + auto r = lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS); if (!r.canRunAgain) - exitLld(r.ret); // Exit now, can't re-execute again. + exitLld(r.retCode); // Exit now, can't re-execute again. if (!mainRet) { - mainRet = r.ret; - } else if (r.ret != *mainRet) { + mainRet = r.retCode; + } else if (r.retCode != *mainRet) { // Exit now, to fail the tests if the result is different between runs. - return r.ret; + return r.retCode; } } return *mainRet; diff --git a/lld/unittests/AsLibAll/AllDrivers.cpp b/lld/unittests/AsLibAll/AllDrivers.cpp new file mode 100644 index 0000000000000..fef3d8ca6f016 --- /dev/null +++ b/lld/unittests/AsLibAll/AllDrivers.cpp @@ -0,0 +1,35 @@ +//===- AllDrivers.cpp -------------------------------------------*- C++ -*-===// +// +// This file is licensed 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 +// +//===----------------------------------------------------------------------===// +// This test shows a typical case where all LLD drivers are linked into the +// application binary. This is very similar to how lld.exe binary is linked, +// except that here we cleanup the internal LLD memory context after each call. +//===----------------------------------------------------------------------===// + +#include "lld/Common/Driver.h" +#include "gmock/gmock.h" + +LLD_HAS_DRIVER(coff) +LLD_HAS_DRIVER(elf) +LLD_HAS_DRIVER(mingw) +LLD_HAS_DRIVER(macho) +LLD_HAS_DRIVER(wasm) + +static bool lldInvoke(std::vector args) { + args.push_back("--version"); + lld::Result r = + lld::lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS); + return !r.retCode && r.canRunAgain; +} + +TEST(AsLib, AllDrivers) { + EXPECT_TRUE(lldInvoke({"ld.lld"})); + EXPECT_TRUE(lldInvoke({"ld64.lld"})); + EXPECT_TRUE(lldInvoke({"ld", "-m", "i386pe"})); // MinGW + EXPECT_TRUE(lldInvoke({"lld-link"})); + EXPECT_TRUE(lldInvoke({"wasm-ld"})); +} diff --git a/lld/unittests/AsLibAll/CMakeLists.txt b/lld/unittests/AsLibAll/CMakeLists.txt new file mode 100644 index 0000000000000..a88dc3eb854d4 --- /dev/null +++ b/lld/unittests/AsLibAll/CMakeLists.txt @@ -0,0 +1,17 @@ +# Test usage of LLD as a library. +# This test covers a typical case where all the LLD drivers are pulled into the +# application executable. + +add_lld_unittests(LLDAsLibAllTests + AllDrivers.cpp +) + +target_link_libraries(LLDAsLibAllTests + PRIVATE + lldCommon + lldCOFF + lldELF + lldMachO + lldMinGW + lldWasm +) diff --git a/lld/unittests/AsLibELF/CMakeLists.txt b/lld/unittests/AsLibELF/CMakeLists.txt new file mode 100644 index 0000000000000..cffd9da7006ea --- /dev/null +++ b/lld/unittests/AsLibELF/CMakeLists.txt @@ -0,0 +1,14 @@ +# Test usage of LLD as a library. +# This test covers a more singular case where only one LLD driver is used in the +# target application executable. + +add_lld_unittests(LLDAsLibELFTests + ROCm.cpp + SomeDrivers.cpp +) + +target_link_libraries(LLDAsLibELFTests + PRIVATE + lldCommon + lldELF +) diff --git a/lld/unittests/AsLibELF/Inputs/kernel1.o b/lld/unittests/AsLibELF/Inputs/kernel1.o new file mode 100644 index 0000000000000000000000000000000000000000..ba9b3056d3af37ff8512f2efb44405339adce780 GIT binary patch literal 1688 zcmd5+y>8S%5FY!EV7dTJ%1BTg#jPT$&>0C5iUiT5L$dbHYh#`Nw7Yk?OF;rj848e) zc!B7UPPr%rh=?M20p5TjkHW0Ib{uo!kZ4$GHT%tcJ3BL;@$S=&HPbL`6Y^!iB^df# z6`z_pTDbvWXGa^Xnat{~|Nm^l!i9xlz6JCC?#1D`VK!fbX+GR*Hdg`CpLs3boX^Xo zHIJa}Hk`mAo^NS<6XhBfe;MWD%_r+GwgC30G;&`FN_vdPEEMnG9TCcX@$q0vsOxej zgd@TS?1xE*hEAvNd5q8VV9oWgUp%%r zgZjBMa$BR)_1sUw&lu~<4@Fl4Ty5{0i>iLf@Mk%oaETVHACo2%4?0&98|BJkZn3(9#1e&6|#M-TR~!yOr9a~yKx(Z+SnuQ zw(kuet*jO;GhkcHN?8-lu&(lr%_BjK+(SsP=6a5ijpl`%SA15{IjVqFc8Ux z5-M2&i4)1l`tz-}khI&&ag~8}03sxpw1aXKWsoqQPit6*BoqW>Q#kvrmcB)c~R?Y_!(jqs$J8!bo@(NufC)DT9(Fz x{w`u=tFOIUoQ1uvzJ~^NzaD>a|7Fdf!z$cman~rB?NYav%18S%5FY!EV7dTJ%1BTg#jPT$&>0C5iUiT5L$dbHYh#`Nw7Yk?OF;rj848e) zc!B7UPPr%rh=?M20p5TjkHW0Ib{uo!kZ4$GHT%tcJ3BL;@$S=&HPbL`6Y^!iB^df# z6`z_pTDbvWXGa^Xnat{~|Nm^l!i9xlz6JCC?#1D`VK!fbX+GR*Hdg`CpLs3boX^Xo zHIJa}Hk`mAo^NS<6XhBfe;MWD%_r+GwgC30G;&`FN_vdPEEMnG9TCcX@$q0vsOxej zgd@TS?1xE*hEAvNd5q8VV9oWgUp%%r zgZjBMa$BR)_1sUw&lu~<4@Fl4Ty5{0i>iLf@Mk%oaETVHACo2%4?0&98|BJkZn3(9#1e&6|#M-TR~!yOr9a~yKx(Z+SnuQ zw(kuet*jO;GhkcHN?8-lu&(lr%_BjK+(SsP=6a5ijpl`%SA15{IjVqFc8Ux z5-M2&i4)1l`tz-}khI&&ag~8}03sxpw1aXKWsoqQPit6*BoqW>Q#kvrmcB)c~R?Y_!(jqs$J8!bo@(NufC)DT9(Fz x{w`u=tFOIUoQ1uvzJ~^NzaD>a|7Fdf!z$cman~rB?NYav%1 + +static std::string expand(const char *path) { + if (!llvm::StringRef(path).contains("%")) + return std::string(path); + + llvm::SmallString<256> thisPath; + thisPath.append(getenv("LLD_SRC_DIR")); + llvm::sys::path::append(thisPath, "unittests", "AsLibELF"); + + std::string expanded(path); + expanded.replace(expanded.find("%S"), 2, thisPath.data(), thisPath.size()); + return expanded; +} + +LLD_HAS_DRIVER(elf) + +static bool lldInvoke(const char *inPath, const char *outPath) { + std::vector args{"ld.lld", "-shared", inPath, "-o", outPath}; + lld::Result s = lld::lldMain(args, llvm::outs(), llvm::errs(), + {{lld::Gnu, &lld::elf::link}}); + return !s.retCode && s.canRunAgain; +} + +static bool runLinker(const char *path) { + // Create a temp file for HSA code object. + int tempHsacoFD = -1; + llvm::SmallString<128> tempHsacoFilename; + if (llvm::sys::fs::createTemporaryFile("kernel", "hsaco", tempHsacoFD, + tempHsacoFilename)) { + return false; + } + llvm::FileRemover cleanupHsaco(tempHsacoFilename); + // Invoke lld. Expect a true return value from lld. + std::string expandedPath = expand(path); + if (!lldInvoke(expandedPath.data(), tempHsacoFilename.c_str())) { + llvm::errs() << "Failed to link: " << expandedPath << "\n"; + return false; + } + return true; +} + +TEST(AsLib, ROCm) { + EXPECT_TRUE(runLinker("%S/Inputs/kernel1.o")); + EXPECT_TRUE(runLinker("%S/Inputs/kernel2.o")); + EXPECT_TRUE(runLinker("%S/Inputs/kernel1.o")); + EXPECT_TRUE(runLinker("%S/Inputs/kernel2.o")); +} +#endif diff --git a/lld/unittests/AsLibELF/SomeDrivers.cpp b/lld/unittests/AsLibELF/SomeDrivers.cpp new file mode 100644 index 0000000000000..05027541a3af0 --- /dev/null +++ b/lld/unittests/AsLibELF/SomeDrivers.cpp @@ -0,0 +1,37 @@ +//===- SomeDrivers.cpp ------------------------------------------*- C++ -*-===// +// +// This file is licensed 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 +// +//===----------------------------------------------------------------------===// +// In this test we showcase the fact that only one LLD driver can be invoked - +// the ELF driver that was linked in the test binary. Calling other drivers +// would return a failure. When using LLD as a library, any driver can be +// linked into your application. +//===----------------------------------------------------------------------===// + +#include "lld/Common/Driver.h" +#include "gmock/gmock.h" + +LLD_HAS_DRIVER(elf) + +static bool lldInvoke(const char *lldExe) { + std::vector args{lldExe, "--version"}; + lld::Result s = lld::lldMain(args, llvm::outs(), llvm::errs(), + {{lld::Gnu, &lld::elf::link}}); + return !s.retCode && s.canRunAgain; +} + +TEST(AsLib, SomeDrivers) { + // When this flag is on, we actually need the MinGW driver library, not the + // ELF one. Here our test only covers the case where the ELF driver is linked + // into the unit test binary. +#ifndef LLD_DEFAULT_LD_LLD_IS_MINGW + EXPECT_TRUE(lldInvoke("ld.lld")); // ELF +#endif + // These drivers are not linked in this unit test. + EXPECT_FALSE(lldInvoke("ld64.lld")); // Mach-O + EXPECT_FALSE(lldInvoke("lld-link")); // COFF + EXPECT_FALSE(lldInvoke("wasm-ld")); // Wasm +} diff --git a/lld/unittests/CMakeLists.txt b/lld/unittests/CMakeLists.txt new file mode 100644 index 0000000000000..ac878fa019083 --- /dev/null +++ b/lld/unittests/CMakeLists.txt @@ -0,0 +1,8 @@ +set_target_properties(LLDUnitTests PROPERTIES FOLDER "lld tests") + +function(add_lld_unittests test_dirname) + add_unittest(LLDUnitTests ${test_dirname} ${ARGN}) +endfunction() + +add_subdirectory(AsLibAll) +add_subdirectory(AsLibELF) diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index dcb76886d3a43..8e2c93772abda 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -84,7 +84,7 @@ class LinkerDriver { bool link(ArrayRef args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput) { - // This driver-specific context will be freed later by lldMain(). + // This driver-specific context will be freed later by unsafeLldMain(). auto *ctx = new CommonLinkerContext; ctx->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput); diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index bc3deef614458..926336e4a7aa8 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -2469,3 +2469,13 @@ function(setup_host_tool tool_name setting_name exe_var_name target_var_name) add_custom_target(${target_var_name} DEPENDS ${exe_name}) endif() endfunction() + +# Adds the unittests folder if gtest is available. +function(llvm_add_unittests tests_added) + if (EXISTS ${LLVM_THIRD_PARTY_DIR}/unittest/googletest/include/gtest/gtest.h) + add_subdirectory(unittests) + set(${tests_added} ON PARENT_SCOPE) + else() + message(WARNING "gtest not found, unittests will not be available") + endif() +endfunction() From 7e229217f4215b519b886e7881bae4da3742a7d2 Mon Sep 17 00:00:00 2001 From: David Spickett Date: Mon, 19 Jun 2023 11:52:06 +0100 Subject: [PATCH 012/130] [lldb][AArch64] Add thread local storage tpidr register This register is used as the pointer to the current thread local storage block and is read from NT_ARM_TLS on Linux. Though tpidr will be present on all AArch64 Linux, I am soon going to add a second register tpidr2 to this set. tpidr is only present when SME is implemented, therefore the NT_ARM_TLS set will change size. This is why I've added this as a dynamic register set to save changes later. Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D152516 --- .../NativeRegisterContextLinux_arm64.cpp | 71 ++++++++++++++++++- .../Linux/NativeRegisterContextLinux_arm64.h | 12 ++++ .../Utility/RegisterInfoPOSIX_arm64.cpp | 34 +++++++++ .../Process/Utility/RegisterInfoPOSIX_arm64.h | 6 ++ .../API/linux/aarch64/tls_register/Makefile | 3 + .../TestAArch64LinuxTLSRegister.py | 66 +++++++++++++++++ .../API/linux/aarch64/tls_register/main.c | 24 +++++++ 7 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 lldb/test/API/linux/aarch64/tls_register/Makefile create mode 100644 lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py create mode 100644 lldb/test/API/linux/aarch64/tls_register/main.c diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 0ec152f0643a4..c9384a651e81b 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -86,6 +86,8 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( if (auxv_at_hwcap2 && (*auxv_at_hwcap2 & HWCAP2_MTE)) opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE); + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS); + auto register_info_up = std::make_unique(target_arch, opt_regsets); return std::make_unique( @@ -116,6 +118,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( ::memset(&m_pac_mask, 0, sizeof(m_pac_mask)); m_mte_ctrl_reg = 0; + m_tls_tpidr_reg = 0; // 16 is just a maximum value, query hardware for actual watchpoint count m_max_hwp_supported = 16; @@ -129,6 +132,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( m_sve_header_is_valid = false; m_pac_mask_is_valid = false; m_mte_ctrl_is_valid = false; + m_tls_tpidr_is_valid = false; if (GetRegisterInfo().IsSVEEnabled()) m_sve_state = SVEState::Unknown; @@ -232,8 +236,15 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, assert(offset < GetSVEBufferSize()); src = (uint8_t *)GetSVEBuffer() + offset; } - } else if (IsSVE(reg)) { + } else if (IsTLS(reg)) { + error = ReadTLSTPIDR(); + if (error.Fail()) + return error; + offset = reg_info->byte_offset - GetRegisterInfo().GetTLSOffset(); + assert(offset < GetTLSTPIDRSize()); + src = (uint8_t *)GetTLSTPIDR() + offset; + } else if (IsSVE(reg)) { if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown) return Status("SVE disabled or not supported"); @@ -450,6 +461,17 @@ Status NativeRegisterContextLinux_arm64::WriteRegister( ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); return WriteMTEControl(); + } else if (IsTLS(reg)) { + error = ReadTLSTPIDR(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetTLSOffset(); + assert(offset < GetTLSTPIDRSize()); + dst = (uint8_t *)GetTLSTPIDR() + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + + return WriteTLSTPIDR(); } return Status("Failed to write register value"); @@ -490,6 +512,12 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( return error; } + // tpidr is always present but there will be more in future. + reg_data_byte_size += GetTLSTPIDRSize(); + error = ReadTLSTPIDR(); + if (error.Fail()) + return error; + data_sp.reset(new DataBufferHeap(reg_data_byte_size, 0)); uint8_t *dst = data_sp->GetBytes(); @@ -507,6 +535,8 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( if (GetRegisterInfo().IsMTEEnabled()) ::memcpy(dst, GetMTEControl(), GetMTEControlSize()); + ::memcpy(dst, GetTLSTPIDR(), GetTLSTPIDRSize()); + return error; } @@ -641,6 +671,10 @@ bool NativeRegisterContextLinux_arm64::IsMTE(unsigned reg) const { return GetRegisterInfo().IsMTEReg(reg); } +bool NativeRegisterContextLinux_arm64::IsTLS(unsigned reg) const { + return GetRegisterInfo().IsTLSReg(reg); +} + llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { if (!m_refresh_hwdebug_info) { return llvm::Error::success(); @@ -784,6 +818,7 @@ void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() { m_sve_header_is_valid = false; m_pac_mask_is_valid = false; m_mte_ctrl_is_valid = false; + m_tls_tpidr_is_valid = false; // Update SVE registers in case there is change in configuration. ConfigureRegisterContext(); @@ -914,6 +949,40 @@ Status NativeRegisterContextLinux_arm64::WriteMTEControl() { return WriteRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL); } +Status NativeRegisterContextLinux_arm64::ReadTLSTPIDR() { + Status error; + + if (m_tls_tpidr_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetTLSTPIDR(); + ioVec.iov_len = GetTLSTPIDRSize(); + + error = ReadRegisterSet(&ioVec, GetTLSTPIDRSize(), NT_ARM_TLS); + + if (error.Success()) + m_tls_tpidr_is_valid = true; + + return error; +} + +Status NativeRegisterContextLinux_arm64::WriteTLSTPIDR() { + Status error; + + error = ReadTLSTPIDR(); + if (error.Fail()) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetTLSTPIDR(); + ioVec.iov_len = GetTLSTPIDRSize(); + + m_tls_tpidr_is_valid = false; + + return WriteRegisterSet(&ioVec, GetTLSTPIDRSize(), NT_ARM_TLS); +} + void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() { // ConfigureRegisterContext gets called from InvalidateAllRegisters // on every stop and configures SVE vector length. diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h index 14f669a3ce98f..2b5442578cd27 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -83,6 +83,7 @@ class NativeRegisterContextLinux_arm64 bool m_fpu_is_valid; bool m_sve_buffer_is_valid; bool m_mte_ctrl_is_valid; + bool m_tls_tpidr_is_valid; bool m_sve_header_is_valid; bool m_pac_mask_is_valid; @@ -107,6 +108,8 @@ class NativeRegisterContextLinux_arm64 uint64_t m_mte_ctrl_reg; + uint64_t m_tls_tpidr_reg; + bool IsGPR(unsigned reg) const; bool IsFPR(unsigned reg) const; @@ -125,9 +128,14 @@ class NativeRegisterContextLinux_arm64 Status WriteMTEControl(); + Status ReadTLSTPIDR(); + + Status WriteTLSTPIDR(); + bool IsSVE(unsigned reg) const; bool IsPAuth(unsigned reg) const; bool IsMTE(unsigned reg) const; + bool IsTLS(unsigned reg) const; uint64_t GetSVERegVG() { return m_sve_header.vl / 8; } @@ -139,6 +147,8 @@ class NativeRegisterContextLinux_arm64 void *GetMTEControl() { return &m_mte_ctrl_reg; } + void *GetTLSTPIDR() { return &m_tls_tpidr_reg; } + void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); }; size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } @@ -149,6 +159,8 @@ class NativeRegisterContextLinux_arm64 size_t GetMTEControlSize() { return sizeof(m_mte_ctrl_reg); } + size_t GetTLSTPIDRSize() { return sizeof(m_tls_tpidr_reg); } + llvm::Error ReadHardwareDebugInfo() override; llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 497f0b4114dfb..af5bbda7bfcf5 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -78,12 +78,16 @@ static lldb_private::RegisterInfo g_register_infos_pauth[] = { static lldb_private::RegisterInfo g_register_infos_mte[] = { DEFINE_EXTENSION_REG(mte_ctrl)}; +static lldb_private::RegisterInfo g_register_infos_tls[] = { + DEFINE_EXTENSION_REG(tpidr)}; + // Number of register sets provided by this context. enum { k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, k_num_sve_registers = sve_ffr - sve_vg + 1, k_num_mte_register = 1, + k_num_tls_register = 1, k_num_pauth_register = 2, k_num_register_sets_default = 2, k_num_register_sets = 3 @@ -189,6 +193,9 @@ static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { "MTE Control Register", "mte", k_num_mte_register, nullptr}; +static const lldb_private::RegisterSet g_reg_set_tls_arm64 = { + "Thread Local Storage Registers", "tls", k_num_tls_register, nullptr}; + RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) : lldb_private::RegisterInfoAndSetInterface(target_arch), @@ -229,6 +236,10 @@ RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( if (m_opt_regsets.AllSet(eRegsetMaskMTE)) AddRegSetMTE(); + // tpidr is always present, but in future there will be others so this is + // done as a dynamic set. + AddRegSetTLS(); + m_register_info_count = m_dynamic_reg_infos.size(); m_register_info_p = m_dynamic_reg_infos.data(); m_register_set_p = m_dynamic_reg_sets.data(); @@ -312,6 +323,21 @@ void RegisterInfoPOSIX_arm64::AddRegSetMTE() { m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data(); } +void RegisterInfoPOSIX_arm64::AddRegSetTLS() { + uint32_t tls_regnum = m_dynamic_reg_infos.size(); + m_tls_regnum_collection.push_back(tls_regnum); + m_dynamic_reg_infos.push_back(g_register_infos_tls[0]); + m_dynamic_reg_infos[tls_regnum].byte_offset = + m_dynamic_reg_infos[tls_regnum - 1].byte_offset + + m_dynamic_reg_infos[tls_regnum - 1].byte_size; + m_dynamic_reg_infos[tls_regnum].kinds[lldb::eRegisterKindLLDB] = tls_regnum; + + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(tls_regnum, tls_regnum + 1); + m_dynamic_reg_sets.push_back(g_reg_set_tls_arm64); + m_dynamic_reg_sets.back().registers = m_tls_regnum_collection.data(); +} + uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLength(uint32_t sve_vq) { // sve_vq contains SVE Quad vector length in context of AArch64 SVE. // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. @@ -403,6 +429,10 @@ bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const { return llvm::is_contained(m_mte_regnum_collection, reg); } +bool RegisterInfoPOSIX_arm64::IsTLSReg(unsigned reg) const { + return llvm::is_contained(m_tls_regnum_collection, reg); +} + uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } @@ -420,3 +450,7 @@ uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const { return m_register_info_p[m_mte_regnum_collection[0]].byte_offset; } + +uint32_t RegisterInfoPOSIX_arm64::GetTLSOffset() const { + return m_register_info_p[m_tls_regnum_collection[0]].byte_offset; +} diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h index 4c52de99fde63..465d3f5b9f3bb 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -28,6 +28,7 @@ class RegisterInfoPOSIX_arm64 eRegsetMaskSVE = 1, eRegsetMaskPAuth = 2, eRegsetMaskMTE = 4, + eRegsetMaskTLS = 8, eRegsetMaskDynamic = ~1, }; @@ -102,6 +103,8 @@ class RegisterInfoPOSIX_arm64 void AddRegSetMTE(); + void AddRegSetTLS(); + uint32_t ConfigureVectorLength(uint32_t sve_vq); bool VectorSizeIsValid(uint32_t vq) { @@ -121,6 +124,7 @@ class RegisterInfoPOSIX_arm64 bool IsSVERegVG(unsigned reg) const; bool IsPAuthReg(unsigned reg) const; bool IsMTEReg(unsigned reg) const; + bool IsTLSReg(unsigned reg) const; uint32_t GetRegNumSVEZ0() const; uint32_t GetRegNumSVEFFR() const; @@ -129,6 +133,7 @@ class RegisterInfoPOSIX_arm64 uint32_t GetRegNumSVEVG() const; uint32_t GetPAuthOffset() const; uint32_t GetMTEOffset() const; + uint32_t GetTLSOffset() const; private: typedef std::map> @@ -155,6 +160,7 @@ class RegisterInfoPOSIX_arm64 std::vector pauth_regnum_collection; std::vector m_mte_regnum_collection; + std::vector m_tls_regnum_collection; }; #endif diff --git a/lldb/test/API/linux/aarch64/tls_register/Makefile b/lldb/test/API/linux/aarch64/tls_register/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/linux/aarch64/tls_register/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py b/lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py new file mode 100644 index 0000000000000..d4ab5d70cc764 --- /dev/null +++ b/lldb/test/API/linux/aarch64/tls_register/TestAArch64LinuxTLSRegister.py @@ -0,0 +1,66 @@ +""" +Test lldb's ability to read and write the AArch64 TLS register tpidr. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class AArch64LinuxTLSRegister(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessArch("aarch64") + @skipUnlessPlatform(["linux"]) + def test_tls(self): + self.build() + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, + "main.c", + line_number("main.c", "// Set break point at this line."), + num_expected_locations=1, + ) + + lldbutil.run_break_set_by_file_and_line( + self, + "main.c", + line_number("main.c", "// Set break point 2 at this line."), + num_expected_locations=1, + ) + + self.runCmd("run", RUN_SUCCEEDED) + + if self.process().GetState() == lldb.eStateExited: + self.fail("Test program failed to run.") + + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + # Since we can't predict what the value will be, the program has set + # a target value for us to find. + + regs = self.thread().GetSelectedFrame().GetRegisters() + tls_regs = regs.GetFirstValueByName("Thread Local Storage Registers") + self.assertTrue(tls_regs.IsValid(), "No TLS registers found.") + tpidr = tls_regs.GetChildMemberWithName("tpidr") + self.assertTrue(tpidr.IsValid(), "No tpidr register found.") + + self.assertEqual(tpidr.GetValueAsUnsigned(), 0x1122334455667788) + + # Set our own value for the program to find. + self.expect("register write tpidr 0x{:x}".format(0x8877665544332211)) + self.expect("continue") + + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + self.expect("p tpidr_was_set", substrs=["true"]) \ No newline at end of file diff --git a/lldb/test/API/linux/aarch64/tls_register/main.c b/lldb/test/API/linux/aarch64/tls_register/main.c new file mode 100644 index 0000000000000..7a5fd3f5fcbdf --- /dev/null +++ b/lldb/test/API/linux/aarch64/tls_register/main.c @@ -0,0 +1,24 @@ +#include +#include + +int main() { + // Save tpidr to restore later. + uint64_t tpidr = 0; + __asm__ volatile("mrs %0, tpidr_el0" : "=r"(tpidr)); + + // Set a pattern for lldb to find. + uint64_t pattern = 0x1122334455667788; + __asm__ volatile("msr tpidr_el0, %0" ::"r"(pattern)); + + // Set break point at this line. + // lldb will now set its own pattern for us to find. + + uint64_t new_tpidr = pattern; + __asm__ volatile("mrs %0, tpidr_el0" : "=r"(new_tpidr)); + volatile bool tpidr_was_set = new_tpidr == 0x8877665544332211; + + // Restore the original. + __asm__ volatile("msr tpidr_el0, %0" ::"r"(tpidr)); + + return 0; // Set break point 2 at this line. +} From a032dc139ddaf4bfccdc4d2dfe073411118cb7e0 Mon Sep 17 00:00:00 2001 From: Akash Banerjee Date: Mon, 19 Jun 2023 12:46:15 +0100 Subject: [PATCH 013/130] [MLIR][OpenMP] Refactoring createTargetData in OMPIRBuilder Key changes: - Refactor the createTargetData function to make use of the emitOffloadingArrays and emitOffloadingArraysArgument functions to generate code. - Added a new emitIfClause helper function to allow handling if clauses in a similar fashion to Clang. - Updated the MLIR side of code to account for changes to createTargetData. Depends on D149872 Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D146557 --- .../llvm/Frontend/OpenMP/OMPIRBuilder.h | 55 ++++- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 219 ++++++++++++++---- .../Frontend/OpenMPIRBuilderTest.cpp | 214 +++++++---------- .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 162 ++++++------- mlir/test/Target/LLVMIR/omptarget-llvm.mlir | 105 ++++----- 5 files changed, 419 insertions(+), 336 deletions(-) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index ea459b2d8fe37..7657ad32e1a5a 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -1478,6 +1478,25 @@ class OpenMPIRBuilder { /// Computes the size of type in bytes. Value *getSizeInBytes(Value *BasePtr); + // Emit a branch from the current block to the Target block only if + // the current block has a terminator. + void emitBranch(BasicBlock *Target); + + // If BB has no use then delete it and return. Else place BB after the current + // block, if possible, or else at the end of the function. Also add a branch + // from current block to BB if current block does not have a terminator. + void emitBlock(BasicBlock *BB, Function *CurFn, bool IsFinished = false); + + /// Emits code for OpenMP 'if' clause using specified \a BodyGenCallbackTy + /// Here is the logic: + /// if (Cond) { + /// ThenGen(); + /// } else { + /// ElseGen(); + /// } + void emitIfClause(Value *Cond, BodyGenCallbackTy ThenGen, + BodyGenCallbackTy ElseGen, InsertPointTy AllocaIP = {}); + /// Create the global variable holding the offload mappings information. GlobalVariable *createOffloadMaptypes(SmallVectorImpl &Mappings, std::string VarName); @@ -1987,29 +2006,41 @@ class OpenMPIRBuilder { StringRef EntryFnName, StringRef EntryFnIDName, int32_t NumTeams, int32_t NumThreads); + /// Type of BodyGen to use for region codegen + /// + /// Priv: If device pointer privatization is required, emit the body of the + /// region here. It will have to be duplicated: with and without + /// privatization. + /// DupNoPriv: If we need device pointer privatization, we need + /// to emit the body of the region with no privatization in the 'else' branch + /// of the conditional. + /// NoPriv: If we don't require privatization of device + /// pointers, we emit the body in between the runtime calls. This avoids + /// duplicating the body code. + enum BodyGenTy { Priv, DupNoPriv, NoPriv }; /// Generator for '#omp target data' /// /// \param Loc The location where the target data construct was encountered. + /// \param AllocaIP The insertion points to be used for alloca instructions. /// \param CodeGenIP The insertion point at which the target directive code /// should be placed. - /// \param MapTypeFlags BitVector storing the mapType flags for the - /// mapOperands. - /// \param MapNames Names for the mapOperands. - /// \param MapperAllocas Pointers to the AllocInsts for the map clause. /// \param IsBegin If true then emits begin mapper call otherwise emits /// end mapper call. /// \param DeviceID Stores the DeviceID from the device clause. /// \param IfCond Value which corresponds to the if clause condition. - /// \param ProcessMapOpCB Callback that generates code for the map clause. - /// \param BodyGenCB Callback that will generate the region code. + /// \param Info Stores all information realted to the Target Data directive. + /// \param GenMapInfoCB Callback that populates the MapInfos and returns. + /// \param BodyGenCB Optional Callback to generate the region code. OpenMPIRBuilder::InsertPointTy createTargetData( - const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP, - SmallVectorImpl &MapTypeFlags, - SmallVectorImpl &MapNames, - struct MapperAllocas &MapperAllocas, bool IsBegin, int64_t DeviceID, - Value *IfCond, BodyGenCallbackTy ProcessMapOpCB, - BodyGenCallbackTy BodyGenCB = {}); + const LocationDescription &Loc, InsertPointTy AllocaIP, + InsertPointTy CodeGenIP, Value *DeviceID, Value *IfCond, + TargetDataInfo &Info, + function_ref GenMapInfoCB, + omp::RuntimeFunction *MapperFunc = nullptr, + function_ref + BodyGenCB = nullptr); using TargetBodyGenCallbackTy = function_ref; diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index b4d5c256aa1a7..e3aa3910a4178 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -4078,73 +4078,121 @@ Constant *OpenMPIRBuilder::registerTargetRegionFunction( } OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createTargetData( - const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP, - SmallVectorImpl &MapTypeFlags, - SmallVectorImpl &MapNames, struct MapperAllocas &MapperAllocas, - bool IsBegin, int64_t DeviceID, Value *IfCond, - BodyGenCallbackTy ProcessMapOpCB, BodyGenCallbackTy BodyGenCB) { + const LocationDescription &Loc, InsertPointTy AllocaIP, + InsertPointTy CodeGenIP, Value *DeviceID, Value *IfCond, + TargetDataInfo &Info, + function_ref GenMapInfoCB, + omp::RuntimeFunction *MapperFunc, + function_ref + BodyGenCB) { if (!updateToLocation(Loc)) return InsertPointTy(); Builder.restoreIP(CodeGenIP); + bool IsStandAlone = !BodyGenCB; - // LLVM utilities like blocks with terminators. - // The UI acts as a resume point for code insertion after the BodyGen - auto *UI = Builder.CreateUnreachable(); - if (IfCond) { - auto *ThenTI = - SplitBlockAndInsertIfThen(IfCond, UI, /* Unreachable */ false); - ThenTI->getParent()->setName("omp_if.then"); - Builder.SetInsertPoint(ThenTI); - } else { - Builder.SetInsertPoint(UI); - } + // Generate the code for the opening of the data environment. Capture all the + // arguments of the runtime call by reference because they are used in the + // closing of the region. + auto BeginThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { + emitOffloadingArrays(AllocaIP, Builder.saveIP(), + GenMapInfoCB(Builder.saveIP()), Info, + /*IsNonContiguous=*/true); - ProcessMapOpCB(Builder.saveIP(), Builder.saveIP()); + TargetDataRTArgs RTArgs; + emitOffloadingArraysArgument(Builder, RTArgs, Info); - uint32_t SrcLocStrSize; - Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize); - Value *srcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize); + // Emit the number of elements in the offloading arrays. + Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs); - GlobalVariable *MapTypesGV = - createOffloadMaptypes(MapTypeFlags, ".offload_maptypes"); - Value *MapTypesArg = Builder.CreateConstInBoundsGEP2_32( - ArrayType::get(Builder.getInt64Ty(), MapTypeFlags.size()), MapTypesGV, - /*Idx0=*/0, /*Idx1=*/0); + // Source location for the ident struct + uint32_t SrcLocStrSize; + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize); + Value *SrcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize); + + Value *OffloadingArgs[] = {SrcLocInfo, DeviceID, + PointerNum, RTArgs.BasePointersArray, + RTArgs.PointersArray, RTArgs.SizesArray, + RTArgs.MapTypesArray, RTArgs.MapNamesArray, + RTArgs.MappersArray}; + + if (IsStandAlone) { + assert(MapperFunc && "MapperFunc missing for standalone target data"); + Builder.CreateCall(getOrCreateRuntimeFunctionPtr(*MapperFunc), + OffloadingArgs); + } else { + Function *BeginMapperFunc = getOrCreateRuntimeFunctionPtr( + omp::OMPRTL___tgt_target_data_begin_mapper); - GlobalVariable *MapNamesGV = - createOffloadMapnames(MapNames, ".offload_mapnames"); - Value *MapNamesArg = Builder.CreateConstInBoundsGEP2_32( - ArrayType::get(Builder.getInt8PtrTy(), MapNames.size()), MapNamesGV, - /*Idx0=*/0, /*Idx1=*/0); + Builder.CreateCall(BeginMapperFunc, OffloadingArgs); + + // If device pointer privatization is required, emit the body of the + // region here. It will have to be duplicated: with and without + // privatization. + Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::Priv)); + } + }; + + // If we need device pointer privatization, we need to emit the body of the + // region with no privatization in the 'else' branch of the conditional. + // Otherwise, we don't have to do anything. + auto BeginElseGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { + Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::DupNoPriv)); + }; + + // Generate code for the closing of the data region. + auto EndThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { + TargetDataRTArgs RTArgs; + emitOffloadingArraysArgument(Builder, RTArgs, Info, /*EmitDebug=*/false, + /*ForEndCall=*/true); + + // Emit the number of elements in the offloading arrays. + Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs); + + // Source location for the ident struct + uint32_t SrcLocStrSize; + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize); + Value *SrcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize); + + Value *OffloadingArgs[] = {SrcLocInfo, DeviceID, + PointerNum, RTArgs.BasePointersArray, + RTArgs.PointersArray, RTArgs.SizesArray, + RTArgs.MapTypesArray, RTArgs.MapNamesArray, + RTArgs.MappersArray}; + Function *EndMapperFunc = + getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_end_mapper); + + Builder.CreateCall(EndMapperFunc, OffloadingArgs); + }; - Function *beginMapperFunc = - getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_begin_mapper); - Function *endMapperFunc = - getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_end_mapper); + // We don't have to do anything to close the region if the if clause evaluates + // to false. + auto EndElseGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) {}; if (BodyGenCB) { - // Create call to start the data region. - emitMapperCall(Builder.saveIP(), beginMapperFunc, srcLocInfo, MapTypesArg, - MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size()); + if (IfCond) { + emitIfClause(IfCond, BeginThenGen, BeginElseGen, AllocaIP); + } else { + BeginThenGen(AllocaIP, Builder.saveIP()); + } - BodyGenCB(Builder.saveIP(), Builder.saveIP()); + // If we don't require privatization of device pointers, we emit the body in + // between the runtime calls. This avoids duplicating the body code. + Builder.restoreIP(BodyGenCB(Builder.saveIP(), BodyGenTy::NoPriv)); - Builder.SetInsertPoint(UI->getParent()); - // Create call to end the data region. - emitMapperCall(Builder.saveIP(), endMapperFunc, srcLocInfo, MapTypesArg, - MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size()); + if (IfCond) { + emitIfClause(IfCond, EndThenGen, EndElseGen, AllocaIP); + } else { + EndThenGen(AllocaIP, Builder.saveIP()); + } } else { - emitMapperCall(Builder.saveIP(), IsBegin ? beginMapperFunc : endMapperFunc, - srcLocInfo, MapTypesArg, MapNamesArg, MapperAllocas, - DeviceID, MapTypeFlags.size()); + if (IfCond) { + emitIfClause(IfCond, BeginThenGen, EndElseGen, AllocaIP); + } else { + BeginThenGen(AllocaIP, Builder.saveIP()); + } } - // Update the insertion point and remove the terminator we introduced. - Builder.SetInsertPoint(UI->getParent()); - if (IfCond) - UI->getParent()->setName("omp_if.end"); - UI->eraseFromParent(); return Builder.saveIP(); } @@ -4668,6 +4716,77 @@ void OpenMPIRBuilder::emitOffloadingArrays( emitNonContiguousDescriptor(AllocaIP, CodeGenIP, CombinedInfo, Info); } +void OpenMPIRBuilder::emitBranch(BasicBlock *Target) { + BasicBlock *CurBB = Builder.GetInsertBlock(); + + if (!CurBB || CurBB->getTerminator()) { + // If there is no insert point or the previous block is already + // terminated, don't touch it. + } else { + // Otherwise, create a fall-through branch. + Builder.CreateBr(Target); + } + + Builder.ClearInsertionPoint(); +} + +void OpenMPIRBuilder::emitBlock(BasicBlock *BB, Function *CurFn, + bool IsFinished) { + BasicBlock *CurBB = Builder.GetInsertBlock(); + + // Fall out of the current block (if necessary). + emitBranch(BB); + + if (IsFinished && BB->use_empty()) { + BB->eraseFromParent(); + return; + } + + // Place the block after the current block, if possible, or else at + // the end of the function. + if (CurBB && CurBB->getParent()) + CurFn->insert(std::next(CurBB->getIterator()), BB); + else + CurFn->insert(CurFn->end(), BB); + Builder.SetInsertPoint(BB); +} + +void OpenMPIRBuilder::emitIfClause(Value *Cond, BodyGenCallbackTy ThenGen, + BodyGenCallbackTy ElseGen, + InsertPointTy AllocaIP) { + // If the condition constant folds and can be elided, try to avoid emitting + // the condition and the dead arm of the if/else. + if (auto *CI = dyn_cast(Cond)) { + auto CondConstant = CI->getSExtValue(); + if (CondConstant) + ThenGen(AllocaIP, Builder.saveIP()); + else + ElseGen(AllocaIP, Builder.saveIP()); + return; + } + + Function *CurFn = Builder.GetInsertBlock()->getParent(); + + // Otherwise, the condition did not fold, or we couldn't elide it. Just + // emit the conditional branch. + BasicBlock *ThenBlock = BasicBlock::Create(M.getContext(), "omp_if.then"); + BasicBlock *ElseBlock = BasicBlock::Create(M.getContext(), "omp_if.else"); + BasicBlock *ContBlock = BasicBlock::Create(M.getContext(), "omp_if.end"); + Builder.CreateCondBr(Cond, ThenBlock, ElseBlock); + // Emit the 'then' code. + emitBlock(ThenBlock, CurFn); + ThenGen(AllocaIP, Builder.saveIP()); + emitBranch(ContBlock); + // Emit the 'else' code if present. + // There is no need to emit line number for unconditional branch. + emitBlock(ElseBlock, CurFn); + ElseGen(AllocaIP, Builder.saveIP()); + // There is no need to emit line number for unconditional branch. + emitBranch(ContBlock); + // Emit the continuation block for code after the if. + emitBlock(ContBlock, CurFn, /*IsFinished=*/true); +} + bool OpenMPIRBuilder::checkAndEmitFlushAfterAtomic( const LocationDescription &Loc, llvm::AtomicOrdering AO, AtomicKind AK) { assert(!(AO == AtomicOrdering::NotAtomic || diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp index 3897329e492d6..776b04d508dac 100644 --- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -4886,18 +4886,9 @@ TEST_F(OpenMPIRBuilderTest, TargetEnterData) { OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); - OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); - unsigned NumDataOperands = 1; int64_t DeviceID = 2; - struct OpenMPIRBuilder::MapperAllocas MapperAllocas; - SmallVector MapTypeFlagsTo = {1}; - SmallVector MapNames; - auto *I8PtrTy = Builder.getInt8PtrTy(); - auto *ArrI8PtrTy = ArrayType::get(I8PtrTy, NumDataOperands); - auto *I64Ty = Builder.getInt64Ty(); - auto *ArrI64Ty = ArrayType::get(I64Ty, NumDataOperands); AllocaInst *Val1 = Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1)); @@ -4905,44 +4896,34 @@ TEST_F(OpenMPIRBuilderTest, TargetEnterData) { IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), F->getEntryBlock().getFirstInsertionPt()); - OMPBuilder.createMapperAllocas(Builder.saveIP(), AllocaIP, NumDataOperands, - MapperAllocas); + llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo; using InsertPointTy = OpenMPIRBuilder::InsertPointTy; - auto ProcessMapOpCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { - Value *DataValue = Val1; - Value *DataPtrBase; - Value *DataPtr; - DataPtrBase = DataValue; - DataPtr = DataValue; - Builder.restoreIP(CodeGenIP); + auto GenMapInfoCB = + [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & { + // Get map clause information. + Builder.restoreIP(codeGenIP); - Value *Null = Constant::getNullValue(DataValue->getType()->getPointerTo()); - Value *SizeGep = - Builder.CreateGEP(DataValue->getType(), Null, Builder.getInt32(1)); - Value *SizePtrToInt = Builder.CreatePtrToInt(SizeGep, I64Ty); - - Value *PtrBaseGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.ArgsBase, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrBaseCast = Builder.CreateBitCast( - PtrBaseGEP, DataPtrBase->getType()->getPointerTo()); - Builder.CreateStore(DataPtrBase, PtrBaseCast); - Value *PtrGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.Args, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrCast = - Builder.CreateBitCast(PtrGEP, DataPtr->getType()->getPointerTo()); - Builder.CreateStore(DataPtr, PtrCast); - Value *SizeGEP = - Builder.CreateInBoundsGEP(ArrI64Ty, MapperAllocas.ArgSizes, - {Builder.getInt32(0), Builder.getInt32(0)}); - Builder.CreateStore(SizePtrToInt, SizeGEP); + CombinedInfo.BasePointers.emplace_back(Val1); + CombinedInfo.Pointers.emplace_back(Val1); + CombinedInfo.Sizes.emplace_back(Builder.getInt64(4)); + CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(1)); + uint32_t temp; + CombinedInfo.Names.emplace_back( + OMPBuilder.getOrCreateSrcLocStr("unknown", temp)); + return CombinedInfo; }; + llvm::OpenMPIRBuilder::TargetDataInfo Info( + /*RequiresDevicePointerInfo=*/false, + /*SeparateBeginEndCalls=*/true); + + OMPBuilder.Config.setIsTargetCodegen(true); + + llvm::omp::RuntimeFunction RTLFunc = OMPRTL___tgt_target_data_begin_mapper; Builder.restoreIP(OMPBuilder.createTargetData( - Loc, Builder.saveIP(), MapTypeFlagsTo, MapNames, MapperAllocas, - /* IsBegin= */ true, DeviceID, /* IfCond= */ nullptr, ProcessMapOpCB)); + Loc, AllocaIP, Builder.saveIP(), Builder.getInt64(DeviceID), + /* IfCond= */ nullptr, Info, GenMapInfoCB, &RTLFunc)); CallInst *TargetDataCall = dyn_cast(&BB->back()); EXPECT_NE(TargetDataCall, nullptr); @@ -4962,18 +4943,9 @@ TEST_F(OpenMPIRBuilderTest, TargetExitData) { OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); - OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); - unsigned NumDataOperands = 1; int64_t DeviceID = 2; - struct OpenMPIRBuilder::MapperAllocas MapperAllocas; - SmallVector MapTypeFlagsFrom = {2}; - SmallVector MapNames; - auto *I8PtrTy = Builder.getInt8PtrTy(); - auto *ArrI8PtrTy = ArrayType::get(I8PtrTy, NumDataOperands); - auto *I64Ty = Builder.getInt64Ty(); - auto *ArrI64Ty = ArrayType::get(I64Ty, NumDataOperands); AllocaInst *Val1 = Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1)); @@ -4981,44 +4953,34 @@ TEST_F(OpenMPIRBuilderTest, TargetExitData) { IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), F->getEntryBlock().getFirstInsertionPt()); - OMPBuilder.createMapperAllocas(Builder.saveIP(), AllocaIP, NumDataOperands, - MapperAllocas); + llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo; using InsertPointTy = OpenMPIRBuilder::InsertPointTy; - auto ProcessMapOpCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { - Value *DataValue = Val1; - Value *DataPtrBase; - Value *DataPtr; - DataPtrBase = DataValue; - DataPtr = DataValue; - Builder.restoreIP(CodeGenIP); + auto GenMapInfoCB = + [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & { + // Get map clause information. + Builder.restoreIP(codeGenIP); - Value *Null = Constant::getNullValue(DataValue->getType()->getPointerTo()); - Value *SizeGep = - Builder.CreateGEP(DataValue->getType(), Null, Builder.getInt32(1)); - Value *SizePtrToInt = Builder.CreatePtrToInt(SizeGep, I64Ty); - - Value *PtrBaseGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.ArgsBase, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrBaseCast = Builder.CreateBitCast( - PtrBaseGEP, DataPtrBase->getType()->getPointerTo()); - Builder.CreateStore(DataPtrBase, PtrBaseCast); - Value *PtrGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.Args, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrCast = - Builder.CreateBitCast(PtrGEP, DataPtr->getType()->getPointerTo()); - Builder.CreateStore(DataPtr, PtrCast); - Value *SizeGEP = - Builder.CreateInBoundsGEP(ArrI64Ty, MapperAllocas.ArgSizes, - {Builder.getInt32(0), Builder.getInt32(0)}); - Builder.CreateStore(SizePtrToInt, SizeGEP); + CombinedInfo.BasePointers.emplace_back(Val1); + CombinedInfo.Pointers.emplace_back(Val1); + CombinedInfo.Sizes.emplace_back(Builder.getInt64(4)); + CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(2)); + uint32_t temp; + CombinedInfo.Names.emplace_back( + OMPBuilder.getOrCreateSrcLocStr("unknown", temp)); + return CombinedInfo; }; + llvm::OpenMPIRBuilder::TargetDataInfo Info( + /*RequiresDevicePointerInfo=*/false, + /*SeparateBeginEndCalls=*/true); + + OMPBuilder.Config.setIsTargetCodegen(true); + + llvm::omp::RuntimeFunction RTLFunc = OMPRTL___tgt_target_data_end_mapper; Builder.restoreIP(OMPBuilder.createTargetData( - Loc, Builder.saveIP(), MapTypeFlagsFrom, MapNames, MapperAllocas, - /* IsBegin= */ false, DeviceID, /* IfCond= */ nullptr, ProcessMapOpCB)); + Loc, AllocaIP, Builder.saveIP(), Builder.getInt64(DeviceID), + /* IfCond= */ nullptr, Info, GenMapInfoCB, &RTLFunc)); CallInst *TargetDataCall = dyn_cast(&BB->back()); EXPECT_NE(TargetDataCall, nullptr); @@ -5038,18 +5000,9 @@ TEST_F(OpenMPIRBuilderTest, TargetDataRegion) { OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); - OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); - unsigned NumDataOperands = 1; int64_t DeviceID = 2; - struct OpenMPIRBuilder::MapperAllocas MapperAllocas; - SmallVector MapTypeFlagsToFrom = {3}; - SmallVector MapNames; - auto *I8PtrTy = Builder.getInt8PtrTy(); - auto *ArrI8PtrTy = ArrayType::get(I8PtrTy, NumDataOperands); - auto *I64Ty = Builder.getInt64Ty(); - auto *ArrI64Ty = ArrayType::get(I64Ty, NumDataOperands); AllocaInst *Val1 = Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1)); @@ -5057,57 +5010,52 @@ TEST_F(OpenMPIRBuilderTest, TargetDataRegion) { IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), F->getEntryBlock().getFirstInsertionPt()); - OMPBuilder.createMapperAllocas(Builder.saveIP(), AllocaIP, NumDataOperands, - MapperAllocas); + llvm::OpenMPIRBuilder::MapInfosTy CombinedInfo; using InsertPointTy = OpenMPIRBuilder::InsertPointTy; - auto ProcessMapOpCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { - Value *DataValue = Val1; - Value *DataPtrBase; - Value *DataPtr; - DataPtrBase = DataValue; - DataPtr = DataValue; - Builder.restoreIP(CodeGenIP); + auto GenMapInfoCB = + [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & { + // Get map clause information. + Builder.restoreIP(codeGenIP); - Value *Null = Constant::getNullValue(DataValue->getType()->getPointerTo()); - Value *SizeGep = - Builder.CreateGEP(DataValue->getType(), Null, Builder.getInt32(1)); - Value *SizePtrToInt = Builder.CreatePtrToInt(SizeGep, I64Ty); - - Value *PtrBaseGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.ArgsBase, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrBaseCast = Builder.CreateBitCast( - PtrBaseGEP, DataPtrBase->getType()->getPointerTo()); - Builder.CreateStore(DataPtrBase, PtrBaseCast); - Value *PtrGEP = - Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.Args, - {Builder.getInt32(0), Builder.getInt32(0)}); - Value *PtrCast = - Builder.CreateBitCast(PtrGEP, DataPtr->getType()->getPointerTo()); - Builder.CreateStore(DataPtr, PtrCast); - Value *SizeGEP = - Builder.CreateInBoundsGEP(ArrI64Ty, MapperAllocas.ArgSizes, - {Builder.getInt32(0), Builder.getInt32(0)}); - Builder.CreateStore(SizePtrToInt, SizeGEP); + CombinedInfo.BasePointers.emplace_back(Val1); + CombinedInfo.Pointers.emplace_back(Val1); + CombinedInfo.Sizes.emplace_back(Builder.getInt64(4)); + CombinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags(3)); + uint32_t temp; + CombinedInfo.Names.emplace_back( + OMPBuilder.getOrCreateSrcLocStr("unknown", temp)); + return CombinedInfo; }; - auto BodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) { - Builder.restoreIP(codeGenIP); - auto *SI = Builder.CreateStore(Builder.getInt32(99), Val1); - auto *newBB = SplitBlock(Builder.GetInsertBlock(), SI); - Builder.SetInsertPoint(newBB); - auto *UI = &Builder.GetInsertBlock()->back(); - SplitBlock(Builder.GetInsertBlock(), UI); + llvm::OpenMPIRBuilder::TargetDataInfo Info( + /*RequiresDevicePointerInfo=*/false, + /*SeparateBeginEndCalls=*/true); + + OMPBuilder.Config.setIsTargetCodegen(true); + + auto BodyCB = [&](InsertPointTy CodeGenIP, int BodyGenType) { + if (BodyGenType == 3) { + Builder.restoreIP(CodeGenIP); + CallInst *TargetDataCall = dyn_cast(&BB->back()); + EXPECT_NE(TargetDataCall, nullptr); + EXPECT_EQ(TargetDataCall->arg_size(), 9U); + EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(), + "__tgt_target_data_begin_mapper"); + EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64)); + EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32)); + EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy()); + Builder.restoreIP(CodeGenIP); + Builder.CreateStore(Builder.getInt32(99), Val1); + } + return Builder.saveIP(); }; Builder.restoreIP(OMPBuilder.createTargetData( - Loc, Builder.saveIP(), MapTypeFlagsToFrom, MapNames, MapperAllocas, - /* IsBegin= */ false, DeviceID, /* IfCond= */ nullptr, ProcessMapOpCB, - BodyCB)); + Loc, AllocaIP, Builder.saveIP(), Builder.getInt64(DeviceID), + /* IfCond= */ nullptr, Info, GenMapInfoCB, nullptr, BodyCB)); - CallInst *TargetDataCall = - dyn_cast(&Builder.GetInsertBlock()->back()); + CallInst *TargetDataCall = dyn_cast(&BB->back()); EXPECT_NE(TargetDataCall, nullptr); EXPECT_EQ(TargetDataCall->arg_size(), 9U); EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(), diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index c3ffd9903d282..a0050397a079a 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -1361,78 +1361,55 @@ convertOmpThreadprivate(Operation &opInst, llvm::IRBuilderBase &builder, return success(); } -/// Process MapOperands for Target Data directives. -static LogicalResult processMapOperand( - llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, - const SmallVector &mapOperands, const ArrayAttr &mapTypes, - SmallVector &mapTypeFlags, - SmallVectorImpl &mapNames, - struct llvm::OpenMPIRBuilder::MapperAllocas &mapperAllocas) { - auto numMapOperands = mapOperands.size(); - llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); - llvm::PointerType *i8PtrTy = builder.getInt8PtrTy(); - llvm::ArrayType *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, numMapOperands); - llvm::IntegerType *i64Ty = builder.getInt64Ty(); - llvm::ArrayType *arrI64Ty = llvm::ArrayType::get(i64Ty, numMapOperands); +int64_t getSizeInBytes(DataLayout &DL, const mlir::Type &type) { + if (isa(type)) + return DL.getTypeSize(cast(type).getElementType()); + + return 0; +} +static void genMapInfos(llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation, + DataLayout &DL, + llvm::OpenMPIRBuilder::MapInfosTy &combinedInfo, + const SmallVector &mapOperands, + const ArrayAttr &mapTypes) { + // Get map clause information. + llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); unsigned index = 0; for (const auto &mapOp : mapOperands) { - const auto &mapTypeOp = mapTypes[index]; - - llvm::Value *mapOpValue = moduleTranslation.lookupValue(mapOp); - llvm::Value *mapOpPtrBase; - llvm::Value *mapOpPtr; - llvm::Value *mapOpSize; - - if (isa(mapOp.getType())) { - mapOpPtrBase = mapOpValue; - mapOpPtr = mapOpValue; - mapOpSize = ompBuilder->getSizeInBytes(mapOpValue); - } else { - return failure(); + if (!mapOp.getType().isa()) { + // TODO: Only LLVMPointerTypes are handled. + combinedInfo.BasePointers.clear(); + combinedInfo.Pointers.clear(); + combinedInfo.Sizes.clear(); + combinedInfo.Types.clear(); + combinedInfo.Names.clear(); + return; } - // Store base pointer extracted from operand into the i-th position of - // argBase. - llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP( - arrI8PtrTy, mapperAllocas.ArgsBase, - {builder.getInt32(0), builder.getInt32(index)}); - llvm::Value *ptrBaseCast = builder.CreateBitCast( - ptrBaseGEP, mapOpPtrBase->getType()->getPointerTo()); - builder.CreateStore(mapOpPtrBase, ptrBaseCast); - - // Store pointer extracted from operand into the i-th position of args. - llvm::Value *ptrGEP = builder.CreateInBoundsGEP( - arrI8PtrTy, mapperAllocas.Args, - {builder.getInt32(0), builder.getInt32(index)}); - llvm::Value *ptrCast = - builder.CreateBitCast(ptrGEP, mapOpPtr->getType()->getPointerTo()); - builder.CreateStore(mapOpPtr, ptrCast); - - // Store size extracted from operand into the i-th position of argSizes. - llvm::Value *sizeGEP = builder.CreateInBoundsGEP( - arrI64Ty, mapperAllocas.ArgSizes, - {builder.getInt32(0), builder.getInt32(index)}); - builder.CreateStore(mapOpSize, sizeGEP); - - mapTypeFlags.push_back(dyn_cast(mapTypeOp).getInt()); - llvm::Constant *mapName = - mlir::LLVM::createMappingInformation(mapOp.getLoc(), *ompBuilder); - mapNames.push_back(mapName); - ++index; + llvm::Value *mapOpValue = moduleTranslation.lookupValue(mapOp); + combinedInfo.BasePointers.emplace_back(mapOpValue); + combinedInfo.Pointers.emplace_back(mapOpValue); + combinedInfo.Names.emplace_back( + mlir::LLVM::createMappingInformation(mapOp.getLoc(), *ompBuilder)); + combinedInfo.Types.emplace_back(llvm::omp::OpenMPOffloadMappingFlags( + mapTypes[index].dyn_cast().getInt())); + combinedInfo.Sizes.emplace_back( + builder.getInt64(getSizeInBytes(DL, mapOp.getType()))); + index++; } - - return success(); } static LogicalResult convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) { - unsigned numMapOperands; llvm::Value *ifCond = nullptr; int64_t deviceID = llvm::omp::OMP_DEVICEID_UNDEF; SmallVector mapOperands; ArrayAttr mapTypes; + llvm::omp::RuntimeFunction RTLFn; + DataLayout DL = DataLayout(op->getParentOfType()); llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); @@ -1453,7 +1430,6 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, dyn_cast(constOp.getValue())) deviceID = intAttr.getInt(); - numMapOperands = dataOp.getMapOperands().size(); mapOperands = dataOp.getMapOperands(); mapTypes = dataOp.getMapTypes(); return success(); @@ -1471,8 +1447,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, if (auto intAttr = dyn_cast(constOp.getValue())) deviceID = intAttr.getInt(); - - numMapOperands = enterDataOp.getMapOperands().size(); + RTLFn = llvm::omp::OMPRTL___tgt_target_data_begin_mapper; mapOperands = enterDataOp.getMapOperands(); mapTypes = enterDataOp.getMapTypes(); return success(); @@ -1491,7 +1466,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, dyn_cast(constOp.getValue())) deviceID = intAttr.getInt(); - numMapOperands = exitDataOp.getMapOperands().size(); + RTLFn = llvm::omp::OMPRTL___tgt_target_data_end_mapper; mapOperands = exitDataOp.getMapOperands(); mapTypes = exitDataOp.getMapTypes(); return success(); @@ -1504,46 +1479,55 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, if (failed(result)) return failure(); - llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder); - llvm::OpenMPIRBuilder::InsertPointTy allocaIP = - findAllocaInsertPoint(builder, moduleTranslation); - - struct llvm::OpenMPIRBuilder::MapperAllocas mapperAllocas; - SmallVector mapTypeFlags; - SmallVector mapNames; - ompBuilder->createMapperAllocas(builder.saveIP(), allocaIP, numMapOperands, - mapperAllocas); - using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; - LogicalResult processMapOpStatus = success(); - auto processMapOpCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) { + + // Fill up the arrays with all the mapped variables. + llvm::OpenMPIRBuilder::MapInfosTy combinedInfo; + auto genMapInfoCB = + [&](InsertPointTy codeGenIP) -> llvm::OpenMPIRBuilder::MapInfosTy & { builder.restoreIP(codeGenIP); - processMapOpStatus = - processMapOperand(builder, moduleTranslation, mapOperands, mapTypes, - mapTypeFlags, mapNames, mapperAllocas); + genMapInfos(builder, moduleTranslation, DL, combinedInfo, mapOperands, + mapTypes); + return combinedInfo; }; LogicalResult bodyGenStatus = success(); - auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) { - // DataOp has only one region associated with it. - auto ®ion = cast(op).getRegion(); - builder.restoreIP(codeGenIP); - bodyGenStatus = inlineConvertOmpRegions(region, "omp.data.region", builder, - moduleTranslation); + using BodyGenTy = llvm::OpenMPIRBuilder::BodyGenTy; + auto bodyGenCB = [&](InsertPointTy codeGenIP, BodyGenTy bodyGenType) { + switch (bodyGenType) { + case BodyGenTy::Priv: + break; + case BodyGenTy::DupNoPriv: + break; + case BodyGenTy::NoPriv: { + // DataOp has only one region associated with it. + auto ®ion = cast(op).getRegion(); + builder.restoreIP(codeGenIP); + bodyGenStatus = inlineConvertOmpRegions(region, "omp.data.region", + builder, moduleTranslation); + } + } + return builder.saveIP(); }; + llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder); + llvm::OpenMPIRBuilder::InsertPointTy allocaIP = + findAllocaInsertPoint(builder, moduleTranslation); + + // TODO: Add support for DevicePointerInfo + llvm::OpenMPIRBuilder::TargetDataInfo info( + /*RequiresDevicePointerInfo=*/false, + /*SeparateBeginEndCalls=*/true); if (isa(op)) { builder.restoreIP(ompBuilder->createTargetData( - ompLoc, builder.saveIP(), mapTypeFlags, mapNames, mapperAllocas, - /*IsBegin=*/false, deviceID, ifCond, processMapOpCB, bodyCB)); + ompLoc, allocaIP, builder.saveIP(), builder.getInt64(deviceID), ifCond, + info, genMapInfoCB, nullptr, bodyGenCB)); } else { builder.restoreIP(ompBuilder->createTargetData( - ompLoc, builder.saveIP(), mapTypeFlags, mapNames, mapperAllocas, - isa(op), deviceID, ifCond, processMapOpCB)); + ompLoc, allocaIP, builder.saveIP(), builder.getInt64(deviceID), ifCond, + info, genMapInfoCB, &RTLFn)); } - if (failed(processMapOpStatus)) - return processMapOpStatus; return bodyGenStatus; } @@ -1554,7 +1538,7 @@ LogicalResult convertFlagsAttr(Operation *op, mlir::omp::FlagsAttr attribute, LLVM::ModuleTranslation &moduleTranslation) { if (!cast(op)) return failure(); - + llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); ompBuilder->createGlobalFlag( diff --git a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir index 6d6aa11875fb5..d39741fd1160a 100644 --- a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir @@ -11,29 +11,28 @@ llvm.func @_QPopenmp_target_data() { llvm.return } +// CHECK: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 4] // CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 3] // CHECK-LABEL: define void @_QPopenmp_target_data() { // CHECK: %[[VAL_0:.*]] = alloca [1 x ptr], align 8 // CHECK: %[[VAL_1:.*]] = alloca [1 x ptr], align 8 -// CHECK: %[[VAL_2:.*]] = alloca [1 x i64], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [1 x ptr], align 8 // CHECK: %[[VAL_3:.*]] = alloca i32, i64 1, align 4 // CHECK: br label %[[VAL_4:.*]] -// CHECK: [[VAL_4]]: -// CHECK: %[[VAL_5:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 -// CHECK: store ptr %[[VAL_3]], ptr %[[VAL_5]], align 8 -// CHECK: %[[VAL_6:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: entry: ; preds = %[[VAL_5:.*]] +// CHECK: %[[VAL_6:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 // CHECK: store ptr %[[VAL_3]], ptr %[[VAL_6]], align 8 -// CHECK: %[[VAL_7:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_7]], align 4 -// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 -// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_8]], ptr %[[VAL_9]], ptr %[[VAL_10]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: %[[VAL_7:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: store ptr %[[VAL_3]], ptr %[[VAL_7]], align 8 +// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_2]], i64 0, i64 0 +// CHECK: store ptr null, ptr %[[VAL_8]], align 8 +// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_9]], ptr %[[VAL_10]], ptr @.offload_sizes, ptr @.offload_maptypes, ptr null, ptr null) // CHECK: store i32 99, ptr %[[VAL_3]], align 4 // CHECK: %[[VAL_11:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 // CHECK: %[[VAL_12:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: %[[VAL_13:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_11]], ptr %[[VAL_12]], ptr %[[VAL_13]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_11]], ptr %[[VAL_12]], ptr @.offload_sizes, ptr @.offload_maptypes, ptr null, ptr null) // CHECK: ret void // ----- @@ -51,35 +50,34 @@ llvm.func @_QPopenmp_target_data_region(%1 : !llvm.ptr>) { llvm.return } +// CHECK: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 4096] // CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 2] // CHECK-LABEL: define void @_QPopenmp_target_data_region // CHECK: (ptr %[[ARG_0:.*]]) { // CHECK: %[[VAL_0:.*]] = alloca [1 x ptr], align 8 // CHECK: %[[VAL_1:.*]] = alloca [1 x ptr], align 8 -// CHECK: %[[VAL_2:.*]] = alloca [1 x i64], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [1 x ptr], align 8 // CHECK: br label %[[VAL_3:.*]] -// CHECK: [[VAL_3]]: -// CHECK: %[[VAL_4:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 -// CHECK: store ptr %[[VAL_5:.*]], ptr %[[VAL_4]], align 8 -// CHECK: %[[VAL_6:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: store ptr %[[VAL_5]], ptr %[[VAL_6]], align 8 -// CHECK: %[[VAL_7:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_7]], align 4 -// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 -// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_8]], ptr %[[VAL_9]], ptr %[[VAL_10]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) -// CHECK: %[[VAL_11:.*]] = getelementptr [1024 x i32], ptr %[[VAL_5]], i32 0, i64 0 +// CHECK: entry: ; preds = %[[VAL_4:.*]] +// CHECK: %[[VAL_5:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: store ptr %[[VAL_6:.*]], ptr %[[VAL_5]], align 8 +// CHECK: %[[VAL_7:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: store ptr %[[VAL_6]], ptr %[[VAL_7]], align 8 +// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_2]], i64 0, i64 0 +// CHECK: store ptr null, ptr %[[VAL_8]], align 8 +// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_9]], ptr %[[VAL_10]], ptr @.offload_sizes, ptr @.offload_maptypes, ptr null, ptr null) +// CHECK: %[[VAL_11:.*]] = getelementptr [1024 x i32], ptr %[[VAL_6]], i32 0, i64 0 // CHECK: store i32 99, ptr %[[VAL_11]], align 4 // CHECK: %[[VAL_12:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 // CHECK: %[[VAL_13:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: %[[VAL_14:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_12]], ptr %[[VAL_13]], ptr %[[VAL_14]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_12]], ptr %[[VAL_13]], ptr @.offload_sizes, ptr @.offload_maptypes, ptr null, ptr null) // CHECK: ret void // ----- -llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr>, %3 : !llvm.ptr>) { +llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr>, %3 : !llvm.ptr>) { %4 = llvm.mlir.constant(1 : i64) : i64 %5 = llvm.alloca %4 x i32 {bindc_name = "dvc", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFomp_target_enter_exitEdvc"} : (i64) -> !llvm.ptr %6 = llvm.mlir.constant(1 : i64) : i64 @@ -92,25 +90,27 @@ llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr>, %3 : !llv %11 = llvm.mlir.constant(10 : i32) : i32 %12 = llvm.icmp "slt" %10, %11 : i32 %13 = llvm.load %5 : !llvm.ptr - omp.target_enter_data if(%12 : i1) device(%13 : i32) map((to -> %1 : !llvm.ptr>), (alloc -> %3 : !llvm.ptr>)) + omp.target_enter_data if(%12 : i1) device(%13 : i32) map((to -> %1 : !llvm.ptr>), (alloc -> %3 : !llvm.ptr>)) %14 = llvm.load %7 : !llvm.ptr %15 = llvm.mlir.constant(10 : i32) : i32 %16 = llvm.icmp "sgt" %14, %15 : i32 %17 = llvm.load %5 : !llvm.ptr - omp.target_exit_data if(%16 : i1) device(%17 : i32) map((from -> %1 : !llvm.ptr>), (release -> %3 : !llvm.ptr>)) + omp.target_exit_data if(%16 : i1) device(%17 : i32) map((from -> %1 : !llvm.ptr>), (release -> %3 : !llvm.ptr>)) llvm.return } +// CHECK: @.offload_sizes = private unnamed_addr constant [2 x i64] [i64 4096, i64 2048] // CHECK: @.offload_maptypes = private unnamed_addr constant [2 x i64] [i64 1, i64 0] -// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [2 x i64] [i64 2, i64 0] +// CHECK: @.offload_sizes.1 = private unnamed_addr constant [2 x i64] [i64 4096, i64 2048] +// CHECK: @.offload_maptypes.2 = private unnamed_addr constant [2 x i64] [i64 2, i64 0] // CHECK-LABEL: define void @_QPomp_target_enter_exit // CHECK: (ptr %[[ARG_0:.*]], ptr %[[ARG_1:.*]]) { // CHECK: %[[VAL_0:.*]] = alloca [2 x ptr], align 8 // CHECK: %[[VAL_1:.*]] = alloca [2 x ptr], align 8 -// CHECK: %[[VAL_2:.*]] = alloca [2 x i64], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [2 x ptr], align 8 // CHECK: %[[VAL_3:.*]] = alloca [2 x ptr], align 8 // CHECK: %[[VAL_4:.*]] = alloca [2 x ptr], align 8 -// CHECK: %[[VAL_5:.*]] = alloca [2 x i64], align 8 +// CHECK: %[[VAL_5:.*]] = alloca [2 x ptr], align 8 // CHECK: %[[VAL_6:.*]] = alloca i32, i64 1, align 4 // CHECK: %[[VAL_7:.*]] = alloca i32, i64 1, align 4 // CHECK: store i32 5, ptr %[[VAL_7]], align 4 @@ -126,44 +126,45 @@ llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr>, %3 : !llv // CHECK: store ptr %[[VAL_16:.*]], ptr %[[VAL_15]], align 8 // CHECK: %[[VAL_17:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 0 // CHECK: store ptr %[[VAL_16]], ptr %[[VAL_17]], align 8 -// CHECK: %[[VAL_18:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 0 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_18]], align 4 +// CHECK: %[[VAL_18:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_5]], i64 0, i64 0 +// CHECK: store ptr null, ptr %[[VAL_18]], align 8 // CHECK: %[[VAL_19:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_3]], i32 0, i32 1 // CHECK: store ptr %[[VAL_20:.*]], ptr %[[VAL_19]], align 8 // CHECK: %[[VAL_21:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 1 // CHECK: store ptr %[[VAL_20]], ptr %[[VAL_21]], align 8 -// CHECK: %[[VAL_22:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 1 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_22]], align 4 +// CHECK: %[[VAL_22:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_5]], i64 0, i64 1 +// CHECK: store ptr null, ptr %[[VAL_22]], align 8 // CHECK: %[[VAL_23:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_3]], i32 0, i32 0 // CHECK: %[[VAL_24:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 0 -// CHECK: %[[VAL_25:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_begin_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_23]], ptr %[[VAL_24]], ptr %[[VAL_25]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) -// CHECK: br label %[[VAL_14]] -// CHECK: omp_if.end: ; preds = %[[VAL_11]], %[[VAL_13]] +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_23]], ptr %[[VAL_24]], ptr @.offload_sizes, ptr @.offload_maptypes, ptr null, ptr null) +// CHECK: br label %[[VAL_25:.*]] +// CHECK: omp_if.else: ; preds = %[[VAL_11]] +// CHECK: br label %[[VAL_25]] +// CHECK: omp_if.end: ; preds = %[[VAL_14]], %[[VAL_13]] // CHECK: %[[VAL_26:.*]] = load i32, ptr %[[VAL_7]], align 4 // CHECK: %[[VAL_27:.*]] = icmp sgt i32 %[[VAL_26]], 10 // CHECK: %[[VAL_28:.*]] = load i32, ptr %[[VAL_6]], align 4 // CHECK: br i1 %[[VAL_27]], label %[[VAL_29:.*]], label %[[VAL_30:.*]] -// CHECK: omp_if.then4: ; preds = %[[VAL_14]] +// CHECK: omp_if.then1: ; preds = %[[VAL_25]] // CHECK: %[[VAL_31:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 0 // CHECK: store ptr %[[VAL_16]], ptr %[[VAL_31]], align 8 // CHECK: %[[VAL_32:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 0 // CHECK: store ptr %[[VAL_16]], ptr %[[VAL_32]], align 8 -// CHECK: %[[VAL_33:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_33]], align 4 +// CHECK: %[[VAL_33:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_2]], i64 0, i64 0 +// CHECK: store ptr null, ptr %[[VAL_33]], align 8 // CHECK: %[[VAL_34:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 1 // CHECK: store ptr %[[VAL_20]], ptr %[[VAL_34]], align 8 // CHECK: %[[VAL_35:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 1 // CHECK: store ptr %[[VAL_20]], ptr %[[VAL_35]], align 8 -// CHECK: %[[VAL_36:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 1 -// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_36]], align 4 +// CHECK: %[[VAL_36:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_2]], i64 0, i64 1 +// CHECK: store ptr null, ptr %[[VAL_36]], align 8 // CHECK: %[[VAL_37:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 0 // CHECK: %[[VAL_38:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 0 -// CHECK: %[[VAL_39:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 0 -// CHECK: call void @__tgt_target_data_end_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_37]], ptr %[[VAL_38]], ptr %[[VAL_39]], ptr @.offload_maptypes.1, ptr @.offload_mapnames.2, ptr null) -// CHECK: br label %[[VAL_30]] -// CHECK: omp_if.end5: ; preds = %[[VAL_14]], %[[VAL_29]] +// CHECK: call void @__tgt_target_data_end_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_37]], ptr %[[VAL_38]], ptr @.offload_sizes.1, ptr @.offload_maptypes.2, ptr null, ptr null) +// CHECK: br label %[[VAL_39:.*]] +// CHECK: omp_if.else5: ; preds = %[[VAL_25]] +// CHECK: br label %[[VAL_39]] +// CHECK: omp_if.end6: ; preds = %[[VAL_30]], %[[VAL_29]] // CHECK: ret void // ----- - From c26fe199c13871db565e14651c060616143d7a8c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 14:40:33 +0200 Subject: [PATCH 014/130] [BasicAA] Add test for PR63266 (NFC) --- llvm/test/Analysis/BasicAA/range.ll | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/llvm/test/Analysis/BasicAA/range.ll b/llvm/test/Analysis/BasicAA/range.ll index f153b58af3c88..06c8103994a8a 100644 --- a/llvm/test/Analysis/BasicAA/range.ll +++ b/llvm/test/Analysis/BasicAA/range.ll @@ -239,6 +239,26 @@ define void @benign_overflow(ptr %p, i64 %o) { ret void } +; FIXME: This is a miscompile +; CHECK-LABEL: pr63266 +; CHECK: NoAlias: i8* %gep2, i8* %offset16 +define void @pr63266(i1 %c, ptr %base) { +entry: + %offset16 = getelementptr inbounds i8, ptr %base, i64 16 + %gep1 = getelementptr i8, ptr %base, i64 -9223372036854775792 + br i1 %c, label %if, label %join + +if: + br label %join + +join: + %phi = phi i64 [ -9223372036854775808, %if ], [ 0, %entry ] + %gep2 = getelementptr i8, ptr %gep1, i64 %phi + store i8 0, ptr %gep2 + load i8, ptr %offset16 + ret void +} + declare void @llvm.assume(i1) From 85232b0ecbf817bc1d70ae602cf44cf6ea03c0e6 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Sun, 20 Nov 2022 08:49:35 -0800 Subject: [PATCH 015/130] HIP: Directly call isfinite builtins --- clang/lib/Headers/__clang_hip_math.h | 4 ++-- clang/test/Headers/__clang_hip_math.hip | 24 +++++++++--------------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/clang/lib/Headers/__clang_hip_math.h b/clang/lib/Headers/__clang_hip_math.h index c19e32bd29364..f7949f30dfbae 100644 --- a/clang/lib/Headers/__clang_hip_math.h +++ b/clang/lib/Headers/__clang_hip_math.h @@ -268,7 +268,7 @@ __DEVICE__ int ilogbf(float __x) { return __ocml_ilogb_f32(__x); } __DEVICE__ -__RETURN_TYPE __finitef(float __x) { return __ocml_isfinite_f32(__x); } +__RETURN_TYPE __finitef(float __x) { return __builtin_isfinite(__x); } __DEVICE__ __RETURN_TYPE __isinff(float __x) { return __builtin_isinf(__x); } @@ -817,7 +817,7 @@ __DEVICE__ int ilogb(double __x) { return __ocml_ilogb_f64(__x); } __DEVICE__ -__RETURN_TYPE __finite(double __x) { return __ocml_isfinite_f64(__x); } +__RETURN_TYPE __finite(double __x) { return __builtin_isfinite(__x); } __DEVICE__ __RETURN_TYPE __isinf(double __x) { return __builtin_isinf(__x); } diff --git a/clang/test/Headers/__clang_hip_math.hip b/clang/test/Headers/__clang_hip_math.hip index 7169614112d18..bb96aeaa1ab9b 100644 --- a/clang/test/Headers/__clang_hip_math.hip +++ b/clang/test/Headers/__clang_hip_math.hip @@ -1155,17 +1155,14 @@ extern "C" __device__ int test_ilogb(double x) { // DEFAULT-LABEL: @test___finitef( // DEFAULT-NEXT: entry: -// DEFAULT-NEXT: [[CALL_I:%.*]] = tail call i32 @__ocml_isfinite_f32(float noundef [[X:%.*]]) #[[ATTR14]] -// DEFAULT-NEXT: [[TOBOOL_I:%.*]] = icmp ne i32 [[CALL_I]], 0 -// DEFAULT-NEXT: [[CONV:%.*]] = zext i1 [[TOBOOL_I]] to i32 +// DEFAULT-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fabs.f32(float [[X:%.*]]) #[[ATTR17:[0-9]+]] +// DEFAULT-NEXT: [[CMPINF_I:%.*]] = fcmp contract one float [[TMP0]], 0x7FF0000000000000 +// DEFAULT-NEXT: [[CONV:%.*]] = zext i1 [[CMPINF_I]] to i32 // DEFAULT-NEXT: ret i32 [[CONV]] // // FINITEONLY-LABEL: @test___finitef( // FINITEONLY-NEXT: entry: -// FINITEONLY-NEXT: [[CALL_I:%.*]] = tail call i32 @__ocml_isfinite_f32(float noundef nofpclass(nan inf) [[X:%.*]]) #[[ATTR14]] -// FINITEONLY-NEXT: [[TOBOOL_I:%.*]] = icmp ne i32 [[CALL_I]], 0 -// FINITEONLY-NEXT: [[CONV:%.*]] = zext i1 [[TOBOOL_I]] to i32 -// FINITEONLY-NEXT: ret i32 [[CONV]] +// FINITEONLY-NEXT: ret i32 1 // extern "C" __device__ BOOL_TYPE test___finitef(float x) { return __finitef(x); @@ -1173,17 +1170,14 @@ extern "C" __device__ BOOL_TYPE test___finitef(float x) { // DEFAULT-LABEL: @test___finite( // DEFAULT-NEXT: entry: -// DEFAULT-NEXT: [[CALL_I:%.*]] = tail call i32 @__ocml_isfinite_f64(double noundef [[X:%.*]]) #[[ATTR14]] -// DEFAULT-NEXT: [[TOBOOL_I:%.*]] = icmp ne i32 [[CALL_I]], 0 -// DEFAULT-NEXT: [[CONV:%.*]] = zext i1 [[TOBOOL_I]] to i32 +// DEFAULT-NEXT: [[TMP0:%.*]] = tail call contract double @llvm.fabs.f64(double [[X:%.*]]) #[[ATTR17]] +// DEFAULT-NEXT: [[CMPINF_I:%.*]] = fcmp contract one double [[TMP0]], 0x7FF0000000000000 +// DEFAULT-NEXT: [[CONV:%.*]] = zext i1 [[CMPINF_I]] to i32 // DEFAULT-NEXT: ret i32 [[CONV]] // // FINITEONLY-LABEL: @test___finite( // FINITEONLY-NEXT: entry: -// FINITEONLY-NEXT: [[CALL_I:%.*]] = tail call i32 @__ocml_isfinite_f64(double noundef nofpclass(nan inf) [[X:%.*]]) #[[ATTR14]] -// FINITEONLY-NEXT: [[TOBOOL_I:%.*]] = icmp ne i32 [[CALL_I]], 0 -// FINITEONLY-NEXT: [[CONV:%.*]] = zext i1 [[TOBOOL_I]] to i32 -// FINITEONLY-NEXT: ret i32 [[CONV]] +// FINITEONLY-NEXT: ret i32 1 // extern "C" __device__ BOOL_TYPE test___finite(double x) { return __finite(x); @@ -1191,7 +1185,7 @@ extern "C" __device__ BOOL_TYPE test___finite(double x) { // DEFAULT-LABEL: @test___isinff( // DEFAULT-NEXT: entry: -// DEFAULT-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fabs.f32(float [[X:%.*]]) #[[ATTR17:[0-9]+]] +// DEFAULT-NEXT: [[TMP0:%.*]] = tail call contract float @llvm.fabs.f32(float [[X:%.*]]) #[[ATTR17]] // DEFAULT-NEXT: [[CMPINF_I:%.*]] = fcmp contract oeq float [[TMP0]], 0x7FF0000000000000 // DEFAULT-NEXT: [[CONV:%.*]] = zext i1 [[CMPINF_I]] to i32 // DEFAULT-NEXT: ret i32 [[CONV]] From f407a7399575a6821940973c54754d42e72dd9ce Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 22 Nov 2022 11:24:09 -0500 Subject: [PATCH 016/130] clang/HIP: Remove __llvm_amdgcn_* wrapper hacks These are leftover hacks from using asm declaratios to access intrinsics. --- .../Headers/__clang_hip_libdevice_declares.h | 32 ------------------- clang/lib/Headers/__clang_hip_math.h | 2 +- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/clang/lib/Headers/__clang_hip_libdevice_declares.h b/clang/lib/Headers/__clang_hip_libdevice_declares.h index be25f4b4a0506..2fc5e17d2f1ea 100644 --- a/clang/lib/Headers/__clang_hip_libdevice_declares.h +++ b/clang/lib/Headers/__clang_hip_libdevice_declares.h @@ -137,23 +137,6 @@ __device__ __attribute__((const)) float __ocml_fma_rte_f32(float, float, float); __device__ __attribute__((const)) float __ocml_fma_rtn_f32(float, float, float); __device__ __attribute__((const)) float __ocml_fma_rtp_f32(float, float, float); __device__ __attribute__((const)) float __ocml_fma_rtz_f32(float, float, float); - -__device__ inline __attribute__((const)) float -__llvm_amdgcn_cos_f32(float __x) { - return __builtin_amdgcn_cosf(__x); -} -__device__ inline __attribute__((const)) float -__llvm_amdgcn_rcp_f32(float __x) { - return __builtin_amdgcn_rcpf(__x); -} -__device__ inline __attribute__((const)) float -__llvm_amdgcn_rsq_f32(float __x) { - return __builtin_amdgcn_rsqf(__x); -} -__device__ inline __attribute__((const)) float -__llvm_amdgcn_sin_f32(float __x) { - return __builtin_amdgcn_sinf(__x); -} // END INTRINSICS // END FLOAT @@ -277,15 +260,6 @@ __device__ __attribute__((const)) double __ocml_fma_rtp_f64(double, double, __device__ __attribute__((const)) double __ocml_fma_rtz_f64(double, double, double); -__device__ inline __attribute__((const)) double -__llvm_amdgcn_rcp_f64(double __x) { - return __builtin_amdgcn_rcp(__x); -} -__device__ inline __attribute__((const)) double -__llvm_amdgcn_rsq_f64(double __x) { - return __builtin_amdgcn_rsq(__x); -} - __device__ __attribute__((const)) _Float16 __ocml_ceil_f16(_Float16); __device__ _Float16 __ocml_cos_f16(_Float16); __device__ __attribute__((const)) _Float16 __ocml_cvtrtn_f16_f32(float); @@ -305,7 +279,6 @@ __device__ __attribute__((const)) int __ocml_isnan_f16(_Float16); __device__ __attribute__((pure)) _Float16 __ocml_log_f16(_Float16); __device__ __attribute__((pure)) _Float16 __ocml_log10_f16(_Float16); __device__ __attribute__((pure)) _Float16 __ocml_log2_f16(_Float16); -__device__ __attribute__((const)) _Float16 __llvm_amdgcn_rcp_f16(_Float16); __device__ __attribute__((const)) _Float16 __ocml_rint_f16(_Float16); __device__ __attribute__((const)) _Float16 __ocml_rsqrt_f16(_Float16); __device__ _Float16 __ocml_sin_f16(_Float16); @@ -332,11 +305,6 @@ __device__ __attribute__((const)) __2i16 __ocml_isnan_2f16(__2f16); __device__ __attribute__((pure)) __2f16 __ocml_log_2f16(__2f16); __device__ __attribute__((pure)) __2f16 __ocml_log10_2f16(__2f16); __device__ __attribute__((pure)) __2f16 __ocml_log2_2f16(__2f16); -__device__ inline __2f16 -__llvm_amdgcn_rcp_2f16(__2f16 __x) // Not currently exposed by ROCDL. -{ - return (__2f16)(__llvm_amdgcn_rcp_f16(__x.x), __llvm_amdgcn_rcp_f16(__x.y)); -} __device__ __attribute__((const)) __2f16 __ocml_rint_2f16(__2f16); __device__ __attribute__((const)) __2f16 __ocml_rsqrt_2f16(__2f16); __device__ __2f16 __ocml_sin_2f16(__2f16); diff --git a/clang/lib/Headers/__clang_hip_math.h b/clang/lib/Headers/__clang_hip_math.h index f7949f30dfbae..2b33efcd8317a 100644 --- a/clang/lib/Headers/__clang_hip_math.h +++ b/clang/lib/Headers/__clang_hip_math.h @@ -647,7 +647,7 @@ float __frcp_rn(float __x) { return 1.0f / __x; } #endif __DEVICE__ -float __frsqrt_rn(float __x) { return __llvm_amdgcn_rsq_f32(__x); } +float __frsqrt_rn(float __x) { return __builtin_amdgcn_rsqf(__x); } #if defined OCML_BASIC_ROUNDED_OPERATIONS __DEVICE__ From d8655fb3656f289fcd8816c7b11b30dc06661a2f Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 16 Jun 2023 09:52:23 -0400 Subject: [PATCH 017/130] [libc++][NFC] Rename __lower_bound_impl to __lower_bound For consistency with other algorithms. Differential Revision: https://reviews.llvm.org/D153141 --- libcxx/include/__algorithm/equal_range.h | 2 +- libcxx/include/__algorithm/lower_bound.h | 4 ++-- libcxx/include/__algorithm/ranges_binary_search.h | 4 ++-- libcxx/include/__algorithm/ranges_lower_bound.h | 4 ++-- libcxx/include/__algorithm/ranges_upper_bound.h | 12 ++++++------ 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__algorithm/equal_range.h b/libcxx/include/__algorithm/equal_range.h index b731dcceb7886..dc1268a6ff110 100644 --- a/libcxx/include/__algorithm/equal_range.h +++ b/libcxx/include/__algorithm/equal_range.h @@ -50,7 +50,7 @@ __equal_range(_Iter __first, _Sent __last, const _Tp& __value, _Compare&& __comp } else { _Iter __mp1 = __mid; return pair<_Iter, _Iter>( - std::__lower_bound_impl<_AlgPolicy>(__first, __mid, __value, __comp, __proj), + std::__lower_bound<_AlgPolicy>(__first, __mid, __value, __comp, __proj), std::__upper_bound<_AlgPolicy>(++__mp1, __end, __value, __comp, __proj)); } } diff --git a/libcxx/include/__algorithm/lower_bound.h b/libcxx/include/__algorithm/lower_bound.h index 7a7a2995cc300..91c3bdaafd0cf 100644 --- a/libcxx/include/__algorithm/lower_bound.h +++ b/libcxx/include/__algorithm/lower_bound.h @@ -29,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 -_Iter __lower_bound_impl(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { +_Iter __lower_bound(_Iter __first, _Sent __last, const _Type& __value, _Comp& __comp, _Proj& __proj) { auto __len = _IterOps<_AlgPolicy>::distance(__first, __last); while (__len != 0) { @@ -52,7 +52,7 @@ _ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value, "The comparator has to be callable"); auto __proj = std::__identity(); - return std::__lower_bound_impl<_ClassicAlgPolicy>(__first, __last, __value, __comp, __proj); + return std::__lower_bound<_ClassicAlgPolicy>(__first, __last, __value, __comp, __proj); } template diff --git a/libcxx/include/__algorithm/ranges_binary_search.h b/libcxx/include/__algorithm/ranges_binary_search.h index d89597e1be31c..728eb8b68ef76 100644 --- a/libcxx/include/__algorithm/ranges_binary_search.h +++ b/libcxx/include/__algorithm/ranges_binary_search.h @@ -35,7 +35,7 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - auto __ret = std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + auto __ret = std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret)); } @@ -45,7 +45,7 @@ struct __fn { bool operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { auto __first = ranges::begin(__r); auto __last = ranges::end(__r); - auto __ret = std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + auto __ret = std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); return __ret != __last && !std::invoke(__comp, __value, std::invoke(__proj, *__ret)); } }; diff --git a/libcxx/include/__algorithm/ranges_lower_bound.h b/libcxx/include/__algorithm/ranges_lower_bound.h index 74356394077b1..3293886fda4db 100644 --- a/libcxx/include/__algorithm/ranges_lower_bound.h +++ b/libcxx/include/__algorithm/ranges_lower_bound.h @@ -39,7 +39,7 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - return std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); + return std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp, __proj); } template (ranges::begin(__r), ranges::end(__r), __value, __comp, __proj); + return std::__lower_bound<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), __value, __comp, __proj); } }; } // namespace __lower_bound diff --git a/libcxx/include/__algorithm/ranges_upper_bound.h b/libcxx/include/__algorithm/ranges_upper_bound.h index 43ce89b898beb..6e6f18dbc510b 100644 --- a/libcxx/include/__algorithm/ranges_upper_bound.h +++ b/libcxx/include/__algorithm/ranges_upper_bound.h @@ -40,7 +40,7 @@ struct __fn { return !std::invoke(__comp, __rhs, __lhs); }; - return std::__lower_bound_impl<_RangeAlgPolicy>(__first, __last, __value, __comp_lhs_rhs_swapped, __proj); + return std::__lower_bound<_RangeAlgPolicy>(__first, __last, __value, __comp_lhs_rhs_swapped, __proj); } template (ranges::begin(__r), - ranges::end(__r), - __value, - __comp_lhs_rhs_swapped, - __proj); + return std::__lower_bound<_RangeAlgPolicy>(ranges::begin(__r), + ranges::end(__r), + __value, + __comp_lhs_rhs_swapped, + __proj); } }; } // namespace __upper_bound From dc71a77d33620830020c939bba25ebdfdd1b6194 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 16 Jun 2023 11:11:56 -0400 Subject: [PATCH 018/130] [libc++][NFC] Move several .fail.cpp tests to .verify.cpp A few tests were also straightforward to translate to SFINAE tests instead, so in a few cases I did that and removed the .fail.cpp test entirely. Differential Revision: https://reviews.llvm.org/D153149 --- .../fstreams/filebuf/traits_mismatch.fail.cpp | 35 --------- .../filebuf/traits_mismatch.verify.cpp | 30 ++++++++ ...ch.fail.cpp => traits_mismatch.verify.cpp} | 11 +-- ...ch.fail.cpp => traits_mismatch.verify.cpp} | 13 +--- ...ch.fail.cpp => traits_mismatch.verify.cpp} | 13 +--- .../string.streams/traits_mismatch.fail.cpp | 34 --------- .../string.streams/traits_mismatch.verify.cpp | 29 ++++++++ ...> thread_safety_missing_unlock.verify.cpp} | 4 +- ..._tuple_ref_binding_diagnostics.verify.cpp} | 6 +- ...fail.cpp => pair.tuple_element.verify.cpp} | 13 ++-- .../{get.fail.cpp => get.verify.cpp} | 19 ++--- ...ment.fail.cpp => tuple_element.verify.cpp} | 15 ++-- .../views/views.span/span.cons/array.fail.cpp | 72 ------------------- .../views/views.span/span.cons/array.pass.cpp | 41 ++++++++++- .../views.span/span.cons/default.fail.cpp | 29 -------- ...othrow_t.fail.cpp => nothrow_t.verify.cpp} | 7 +- .../{types.fail.cpp => types.verify.cpp} | 7 +- ..._arg.fail.cpp => allocator_arg.verify.cpp} | 7 +- ...ail.cpp => optional_in_place_t.verify.cpp} | 12 +--- ...fail.cpp => optional_nullopt_t.verify.cpp} | 18 ++--- .../{alloc.fail.cpp => alloc.verify.cpp} | 4 -- ....fail.cpp => alloc_const_Types.verify.cpp} | 7 -- ...fail.cpp => alloc_convert_copy.verify.cpp} | 7 -- ...fail.cpp => alloc_convert_move.verify.cpp} | 7 -- ..._Types.fail.cpp => const_Types.verify.cpp} | 6 -- .../{default.fail.cpp => default.verify.cpp} | 4 -- ...st_rv.fail.cpp => get_const_rv.verify.cpp} | 7 +- ...type.fail.cpp => tuple.by.type.verify.cpp} | 5 +- ...ment.fail.cpp => tuple_element.verify.cpp} | 15 ++-- ...le_size.fail.cpp => tuple_size.verify.cpp} | 5 +- ...l.cpp => tuple_size_incomplete.verify.cpp} | 5 +- ...ize_v.fail.cpp => tuple_size_v.verify.cpp} | 5 +- .../piecewise_construct_t.verify.cpp | 2 +- .../ctor.default.explicit_LWG2510.verify.cpp | 2 +- 34 files changed, 148 insertions(+), 348 deletions(-) delete mode 100644 libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.fail.cpp create mode 100644 libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp rename libcxx/test/libcxx/input.output/file.streams/fstreams/{traits_mismatch.fail.cpp => traits_mismatch.verify.cpp} (83%) rename libcxx/test/libcxx/input.output/iostream.format/input.streams/{traits_mismatch.fail.cpp => traits_mismatch.verify.cpp} (69%) rename libcxx/test/libcxx/input.output/iostream.format/output.streams/{traits_mismatch.fail.cpp => traits_mismatch.verify.cpp} (69%) delete mode 100644 libcxx/test/libcxx/input.output/string.streams/traits_mismatch.fail.cpp create mode 100644 libcxx/test/libcxx/input.output/string.streams/traits_mismatch.verify.cpp rename libcxx/test/libcxx/thread/thread.mutex/{thread_safety_missing_unlock.fail.cpp => thread_safety_missing_unlock.verify.cpp} (95%) rename libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/{PR20855_tuple_ref_binding_diagnostics.fail.cpp => PR20855_tuple_ref_binding_diagnostics.verify.cpp} (97%) rename libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/{pair.tuple_element.fail.cpp => pair.tuple_element.verify.cpp} (58%) rename libcxx/test/std/containers/sequences/array/array.tuple/{get.fail.cpp => get.verify.cpp} (59%) rename libcxx/test/std/containers/sequences/array/array.tuple/{tuple_element.fail.cpp => tuple_element.verify.cpp} (54%) delete mode 100644 libcxx/test/std/containers/views/views.span/span.cons/array.fail.cpp delete mode 100644 libcxx/test/std/containers/views/views.span/span.cons/default.fail.cpp rename libcxx/test/std/language.support/support.dynamic/{nothrow_t.fail.cpp => nothrow_t.verify.cpp} (88%) rename libcxx/test/std/thread/thread.mutex/thread.lock/{types.fail.cpp => types.verify.cpp} (92%) rename libcxx/test/std/utilities/memory/allocator.tag/{allocator_arg.fail.cpp => allocator_arg.verify.cpp} (89%) rename libcxx/test/std/utilities/optional/optional.syn/{optional_in_place_t.fail.cpp => optional_in_place_t.verify.cpp} (78%) rename libcxx/test/std/utilities/optional/optional.syn/{optional_nullopt_t.fail.cpp => optional_nullopt_t.verify.cpp} (62%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{alloc.fail.cpp => alloc.verify.cpp} (95%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{alloc_const_Types.fail.cpp => alloc_const_Types.verify.cpp} (91%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{alloc_convert_copy.fail.cpp => alloc_convert_copy.verify.cpp} (96%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{alloc_convert_move.fail.cpp => alloc_convert_move.verify.cpp} (95%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{const_Types.fail.cpp => const_Types.verify.cpp} (96%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/{default.fail.cpp => default.verify.cpp} (98%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/{get_const_rv.fail.cpp => get_const_rv.verify.cpp} (87%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/{tuple.by.type.fail.cpp => tuple.by.type.verify.cpp} (97%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/{tuple_element.fail.cpp => tuple_element.verify.cpp} (59%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/{tuple_size.fail.cpp => tuple_size.verify.cpp} (96%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/{tuple_size_incomplete.fail.cpp => tuple_size_incomplete.verify.cpp} (97%) rename libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/{tuple_size_v.fail.cpp => tuple_size_v.verify.cpp} (96%) diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.fail.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.fail.cpp deleted file mode 100644 index 27871b0c7bea5..0000000000000 --- a/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.fail.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// - -// template> -// class basic_filebuf; -// -// The char type of the stream and the char_type of the traits have to match - -// UNSUPPORTED: no-wide-characters - -#include - -int main(int, char**) -{ - std::basic_filebuf > f; - // expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} - - return 0; -} diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp new file mode 100644 index 0000000000000..e6f651ca41d32 --- /dev/null +++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/filebuf/traits_mismatch.verify.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// template> +// class basic_filebuf; +// +// The char type of the stream and the char_type of the traits have to match + +// UNSUPPORTED: no-wide-characters + +#include + +std::basic_filebuf > f; +// expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@fstream:* {{only virtual member functions can be marked 'override'}} diff --git a/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.fail.cpp b/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp similarity index 83% rename from libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.fail.cpp rename to libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp index ce22fee618732..94299fe0af473 100644 --- a/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.fail.cpp +++ b/libcxx/test/libcxx/input.output/file.streams/fstreams/traits_mismatch.verify.cpp @@ -17,11 +17,9 @@ #include -int main(int, char**) -{ - std::basic_fstream > f; -// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +std::basic_fstream > f; +// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +// expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} // expected-error@fstream:* {{only virtual member functions can be marked 'override'}} @@ -39,6 +37,3 @@ int main(int, char**) // exception specifications for types which are already invalid for one reason or another. // For now we tolerate this diagnostic. // expected-error@ostream:* 0-1 {{exception specification of overriding function is more lax than base version}} - - return 0; -} diff --git a/libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.fail.cpp b/libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.verify.cpp similarity index 69% rename from libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.fail.cpp rename to libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.verify.cpp index 273dd0fe4c857..5789e8e2b07b1 100644 --- a/libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.fail.cpp +++ b/libcxx/test/libcxx/input.output/iostream.format/input.streams/traits_mismatch.verify.cpp @@ -16,17 +16,10 @@ // UNSUPPORTED: no-wide-characters #include -#include -#include +#include struct test_istream : public std::basic_istream > {}; - -int main(int, char**) -{ -// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error@istream:* {{only virtual member functions can be marked 'override'}} - - return 0; -} +// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +// expected-error@istream:* {{only virtual member functions can be marked 'override'}} diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.fail.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.verify.cpp similarity index 69% rename from libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.fail.cpp rename to libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.verify.cpp index 9afcde0d8c68c..6f8ba7baaa1e2 100644 --- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.fail.cpp +++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/traits_mismatch.verify.cpp @@ -16,17 +16,10 @@ // UNSUPPORTED: no-wide-characters #include -#include -#include +#include struct test_ostream : public std::basic_ostream > {}; - -int main(int, char**) -{ -// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error@ostream:* {{only virtual member functions can be marked 'override'}} - - return 0; -} +// expected-error-re@ios:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +// expected-error@ostream:* {{only virtual member functions can be marked 'override'}} diff --git a/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.fail.cpp b/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.fail.cpp deleted file mode 100644 index 23ab5f0c88a0b..0000000000000 --- a/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.fail.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// - -// - -// template, -// class Allocator = allocator> -// class basic_stringbuf; -// -// The char type of the stream and the char_type of the traits have to match - -// UNSUPPORTED: no-wide-characters - -#include - -int main(int, char**) -{ - std::basic_stringbuf > sb; -// expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} -// expected-error-re@string:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} - - // expected-error@sstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@sstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@sstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@sstream:* {{only virtual member functions can be marked 'override'}} - // expected-error@sstream:* {{only virtual member functions can be marked 'override'}} - - return 0; -} diff --git a/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.verify.cpp b/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.verify.cpp new file mode 100644 index 0000000000000..36c4b23eb2978 --- /dev/null +++ b/libcxx/test/libcxx/input.output/string.streams/traits_mismatch.verify.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// + +// template, +// class Allocator = allocator> +// class basic_stringbuf; +// +// The char type of the stream and the char_type of the traits have to match + +// UNSUPPORTED: no-wide-characters + +#include + +std::basic_stringbuf > sb; +// expected-error-re@streambuf:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} +// expected-error-re@string:* {{{{(static_assert|static assertion)}} failed{{.*}}traits_type::char_type must be the same type as CharT}} + +// expected-error@sstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@sstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@sstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@sstream:* {{only virtual member functions can be marked 'override'}} +// expected-error@sstream:* {{only virtual member functions can be marked 'override'}} diff --git a/libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp b/libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.verify.cpp similarity index 95% rename from libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp rename to libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.verify.cpp index 07a51b5db90cf..bab686e7b4ca2 100644 --- a/libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp +++ b/libcxx/test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.verify.cpp @@ -21,8 +21,6 @@ std::mutex m; -int main(int, char**) { +void f() { m.lock(); - - return 0; } // expected-error {{mutex 'm' is still held at the end of function}} diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp similarity index 97% rename from libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp rename to libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp index 2586c32ca80ec..4a6e3095c1019 100644 --- a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp +++ b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.verify.cpp @@ -10,7 +10,7 @@ // -// See llvm.org/PR20855 +// See https://llvm.org/PR20855 #include #include @@ -39,7 +39,7 @@ template void F(typename CannotDeduce>::type const&) {} -int main(int, char**) { +void f() { #if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary) // Test that we emit our diagnostic from the library. // expected-error@tuple:* 8 {{Attempted construction of reference element binds to a temporary whose lifetime has ended}} @@ -77,6 +77,4 @@ int main(int, char**) { #error force failure // expected-error@-1 {{force failure}} #endif - - return 0; } diff --git a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.fail.cpp b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.verify.cpp similarity index 58% rename from libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.fail.cpp rename to libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.verify.cpp index 40e57df508959..c21afe5caae25 100644 --- a/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.fail.cpp +++ b/libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/pair.tuple_element.verify.cpp @@ -14,13 +14,8 @@ #include -int main(int, char**) -{ - { - typedef std::pair P; - std::tuple_element<2, P>::type foo; // expected-note {{requested here}} - // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '2U[L]{0,2} < 2')?}}{{.*}}Index out of bounds in std::tuple_element>}} - } - - return 0; +void f() { + typedef std::pair P; + std::tuple_element<2, P>::type foo; // expected-note {{requested here}} + // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '2U[L]{0,2} < 2')?}}{{.*}}Index out of bounds in std::tuple_element>}} } diff --git a/libcxx/test/std/containers/sequences/array/array.tuple/get.fail.cpp b/libcxx/test/std/containers/sequences/array/array.tuple/get.verify.cpp similarity index 59% rename from libcxx/test/std/containers/sequences/array/array.tuple/get.fail.cpp rename to libcxx/test/std/containers/sequences/array/array.tuple/get.verify.cpp index 2e1071550a51c..a447a1113d4af 100644 --- a/libcxx/test/std/containers/sequences/array/array.tuple/get.fail.cpp +++ b/libcxx/test/std/containers/sequences/array/array.tuple/get.verify.cpp @@ -16,17 +16,10 @@ #include #include -#include "test_macros.h" - -int main(int, char**) -{ - { - typedef double T; - typedef std::array C; - C c = {1, 2, 3.5}; - std::get<3>(c) = 5.5; // expected-note {{requested here}} - // expected-error-re@array:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '3U[L]{0,2} < 3U[L]{0,2}')?}}{{.*}}Index out of bounds in std::get<> (std::array)}} - } - - return 0; +void f() { + typedef double T; + typedef std::array C; + C c = {1, 2, 3.5}; + std::get<3>(c) = 5.5; // expected-note {{requested here}} + // expected-error-re@array:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '3U[L]{0,2} < 3U[L]{0,2}')?}}{{.*}}Index out of bounds in std::get<> (std::array)}} } diff --git a/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.fail.cpp b/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.verify.cpp similarity index 54% rename from libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.fail.cpp rename to libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.verify.cpp index 6010c893d6995..e0ae7f10fbb2f 100644 --- a/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.fail.cpp +++ b/libcxx/test/std/containers/sequences/array/array.tuple/tuple_element.verify.cpp @@ -13,14 +13,7 @@ #include #include -int main(int, char**) -{ - { - typedef double T; - typedef std::array C; - std::tuple_element<3, C> foo; // expected-note {{requested here}} - // expected-error-re@array:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '3U[L]{0,2} < 3U[L]{0,2}')?}}{{.*}}Index out of bounds in std::tuple_element<> (std::array)}} - } - - return 0; -} +typedef double T; +typedef std::array C; +std::tuple_element<3, C> foo; // expected-note {{requested here}} +// expected-error-re@array:* {{{{(static_assert|static assertion)}} failed{{( due to requirement '3U[L]{0,2} < 3U[L]{0,2}')?}}{{.*}}Index out of bounds in std::tuple_element<> (std::array)}} diff --git a/libcxx/test/std/containers/views/views.span/span.cons/array.fail.cpp b/libcxx/test/std/containers/views/views.span/span.cons/array.fail.cpp deleted file mode 100644 index 74682167c6d27..0000000000000 --- a/libcxx/test/std/containers/views/views.span/span.cons/array.fail.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// - -// template -// constexpr span(element_type (&arr)[N]) noexcept; -// template -// constexpr span(array& arr) noexcept; -// template -// constexpr span(const array& arr) noexcept; -// -// Remarks: These constructors shall not participate in overload resolution unless: -// - extent == dynamic_extent || N == extent is true, and -// - remove_pointer_t(*)[] is convertible to ElementType(*)[]. -// - - -#include -#include -#include - -#include "test_macros.h" - - int arr[] = {1,2,3}; -const int carr[] = {4,5,6}; - volatile int varr[] = {7,8,9}; -const volatile int cvarr[] = {1,3,5}; - -int main(int, char**) -{ -// Size wrong - { - std::span s1(arr); // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// Type wrong - { - std::span s1(arr); // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s2(arr); // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (dynamically sized) - { - std::span< int> s1{ carr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s2{ varr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int> s3{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s6{ carr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int> s7{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - -// CV wrong (statically sized) - { - std::span< int,3> s1{ carr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s2{ varr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< int,3> s3{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s4{ varr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span s5{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s6{ carr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - std::span< volatile int,3> s7{cvarr}; // expected-error {{no matching constructor for initialization of 'std::span'}} - } - - return 0; -} diff --git a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp index ce03c4fa92475..8fa7692c3b637 100644 --- a/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/array.pass.cpp @@ -17,10 +17,10 @@ // - remove_pointer_t(*)[] is convertible to ElementType(*)[]. // - -#include #include +#include #include +#include #include "test_macros.h" @@ -117,5 +117,42 @@ int main(int, char**) checkCV(); + // Size wrong + { + static_assert(!std::is_constructible, int (&)[3]>::value, ""); + } + + // Type wrong + { + static_assert(!std::is_constructible, int (&)[3]>::value, ""); + static_assert(!std::is_constructible, int (&)[3]>::value, ""); + } + + // CV wrong (dynamically sized) + { + static_assert(!std::is_constructible, const int (&)[3]>::value, ""); + static_assert(!std::is_constructible, volatile int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + + static_assert(!std::is_constructible, volatile int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + + static_assert(!std::is_constructible, const int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + } + + // CV wrong (statically sized) + { + static_assert(!std::is_constructible, const int (&)[3]>::value, ""); + static_assert(!std::is_constructible, volatile int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + + static_assert(!std::is_constructible, volatile int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + + static_assert(!std::is_constructible, const int (&)[3]>::value, ""); + static_assert(!std::is_constructible, const volatile int (&)[3]>::value, ""); + } + return 0; } diff --git a/libcxx/test/std/containers/views/views.span/span.cons/default.fail.cpp b/libcxx/test/std/containers/views/views.span/span.cons/default.fail.cpp deleted file mode 100644 index 2c62278aac867..0000000000000 --- a/libcxx/test/std/containers/views/views.span/span.cons/default.fail.cpp +++ /dev/null @@ -1,29 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// - -// constexpr span() noexcept; -// -// Remarks: This constructor shall not participate in overload resolution -// unless Extent == 0 || Extent == dynamic_extent is true. - - -#include -#include -#include - -#include "test_macros.h" - -int main(int, char**) -{ - std::span s; // expected-error {{no matching constructor for initialization of 'std::span'}} - - return 0; -} diff --git a/libcxx/test/std/language.support/support.dynamic/nothrow_t.fail.cpp b/libcxx/test/std/language.support/support.dynamic/nothrow_t.verify.cpp similarity index 88% rename from libcxx/test/std/language.support/support.dynamic/nothrow_t.fail.cpp rename to libcxx/test/std/language.support/support.dynamic/nothrow_t.verify.cpp index 5ec2696a3c9c2..50dd63a6350f0 100644 --- a/libcxx/test/std/language.support/support.dynamic/nothrow_t.fail.cpp +++ b/libcxx/test/std/language.support/support.dynamic/nothrow_t.verify.cpp @@ -14,13 +14,8 @@ // }; // extern const nothrow_t nothrow; -// This test checks for LWG 2510. +// This test checks for https://wg21.link/LWG2510. #include - std::nothrow_t f() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} - -int main(int, char**) { - return 0; -} diff --git a/libcxx/test/std/thread/thread.mutex/thread.lock/types.fail.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/types.verify.cpp similarity index 92% rename from libcxx/test/std/thread/thread.mutex/thread.lock/types.fail.cpp rename to libcxx/test/std/thread/thread.mutex/thread.lock/types.verify.cpp index b4acac85b7e30..623e5c3d22e75 100644 --- a/libcxx/test/std/thread/thread.mutex/thread.lock/types.fail.cpp +++ b/libcxx/test/std/thread/thread.mutex/thread.lock/types.verify.cpp @@ -16,15 +16,10 @@ // struct try_to_lock_t { explicit try_to_lock_t() = default; }; // struct adopt_lock_t { explicit adopt_lock_t() = default; }; -// This test checks for LWG 2510. +// This test checks for https://wg21.link/LWG2510. #include - std::defer_lock_t f1() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} std::try_to_lock_t f2() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} std::adopt_lock_t f3() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} - -int main(int, char**) { - return 0; -} diff --git a/libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp b/libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.verify.cpp similarity index 89% rename from libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp rename to libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.verify.cpp index 94752af96fa27..db5a85aa752bd 100644 --- a/libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp +++ b/libcxx/test/std/utilities/memory/allocator.tag/allocator_arg.verify.cpp @@ -13,13 +13,8 @@ // struct allocator_arg_t { explicit allocator_arg_t() = default; }; // const allocator_arg_t allocator_arg = allocator_arg_t(); -// This test checks for LWG 2510. +// This test checks for https://wg21.link/LWG2510. #include - std::allocator_arg_t f() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} - -int main(int, char**) { - return 0; -} diff --git a/libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.fail.cpp b/libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.verify.cpp similarity index 78% rename from libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.fail.cpp rename to libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.verify.cpp index b95cb5606b5f2..20efef515c362 100644 --- a/libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.fail.cpp +++ b/libcxx/test/std/utilities/optional/optional.syn/optional_in_place_t.verify.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 + // // A program that necessitates the instantiation of template optional for @@ -14,14 +15,7 @@ #include -int main(int, char**) -{ - using std::optional; - using std::in_place_t; - using std::in_place; - - optional opt; // expected-note {{requested here}} +void f() { + std::optional opt; // expected-note {{requested here}} // expected-error@optional:* {{instantiation of optional with in_place_t is ill-formed}} - - return 0; } diff --git a/libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.fail.cpp b/libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.verify.cpp similarity index 62% rename from libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.fail.cpp rename to libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.verify.cpp index 044c4e66572aa..f807da7470ae9 100644 --- a/libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.fail.cpp +++ b/libcxx/test/std/utilities/optional/optional.syn/optional_nullopt_t.verify.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 + // // A program that necessitates the instantiation of template optional for @@ -14,17 +15,10 @@ #include -int main(int, char**) -{ - using std::optional; - using std::nullopt_t; - using std::nullopt; - - optional opt; // expected-note 1 {{requested here}} - optional opt1; // expected-note 1 {{requested here}} - optional opt2; // expected-note 1 {{requested here}} - optional opt3; // expected-note 1 {{requested here}} +void f() { + std::optional opt; // expected-note 1 {{requested here}} + std::optional opt1; // expected-note 1 {{requested here}} + std::optional opt2; // expected-note 1 {{requested here}} + std::optional opt3; // expected-note 1 {{requested here}} // expected-error@optional:* 4 {{instantiation of optional with nullopt_t is ill-formed}} - - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.verify.cpp similarity index 95% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.verify.cpp index 2a89996937220..0ce92da28cc42 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.verify.cpp @@ -27,7 +27,3 @@ struct ExplicitDefault { explicit ExplicitDefault() { } }; std::tuple explicit_default_test() { return {std::allocator_arg, std::allocator()}; // expected-error {{chosen constructor is explicit in copy-initialization}} } - -int main(int, char**) { - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.verify.cpp similarity index 91% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.verify.cpp index 1a1e8d2f9d54c..21ec4e07053ca 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.verify.cpp @@ -35,10 +35,3 @@ std::tuple non_const_explicity_copy_test() { return {std::allocator_arg, std::allocator{}, e}; // expected-error@-1 {{chosen constructor is explicit in copy-initialization}} } -int main(int, char**) -{ - const_explicit_copy_test(); - non_const_explicity_copy_test(); - - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.verify.cpp similarity index 96% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.verify.cpp index b5b7de75344aa..ec8490787294c 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.verify.cpp @@ -35,10 +35,3 @@ std::tuple non_const_explicit_copy_test() { return {std::allocator_arg, std::allocator{}, t1}; // expected-error@-1 {{chosen constructor is explicit in copy-initialization}} } - -int main(int, char**) -{ - - - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.verify.cpp similarity index 95% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.verify.cpp index 9202086cdae11..0fa60d54a23b0 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.verify.cpp @@ -28,10 +28,3 @@ std::tuple explicit_move_test() { return {std::allocator_arg, std::allocator{}, std::move(t1)}; // expected-error@-1 {{chosen constructor is explicit in copy-initialization}} } - -int main(int, char**) -{ - - - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.verify.cpp similarity index 96% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.verify.cpp index 7b5773e183ae0..ab35585a02993 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.verify.cpp @@ -41,9 +41,3 @@ std::tuple const_explicit_copy_no_brace() { return e; // expected-error@-1 {{no viable conversion}} } - -int main(int, char**) -{ - - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.verify.cpp similarity index 98% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.verify.cpp index ed49c739d2baf..61951d80dad26 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.verify.cpp @@ -43,7 +43,3 @@ std::tuple test12() { return {}; } // expected-err std::tuple test13() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} std::tuple test14() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} std::tuple test15() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}} - -int main(int, char**) { - return 0; -} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.verify.cpp similarity index 87% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.verify.cpp index ff1e37db8e6ad..2595ea871d5b1 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/get_const_rv.verify.cpp @@ -23,13 +23,10 @@ template void cref(T const&&) = delete; std::tuple const tup4() { return std::make_tuple(4); } -int main(int, char**) -{ +void f() { // LWG2485: tuple should not open a hole in the type system, get() should // imitate [expr.ref]'s rules for accessing data members { - cref(std::get<0>(tup4())); // expected-error {{call to deleted function 'cref'}} + cref(std::get<0>(tup4())); // expected-error {{call to deleted function 'cref'}} } - - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp similarity index 97% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp index 4fef6b99f5305..1d05eb5fe76e9 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.elem/tuple.by.type.verify.cpp @@ -33,10 +33,7 @@ void test_bad_return_type() { upint p = std::get(t); // expected-error{{deleted copy constructor}} } -int main(int, char**) -{ +void f() { test_bad_index(); test_bad_return_type(); - - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.verify.cpp similarity index 59% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.verify.cpp index 21b69683b680a..03eb8f40280a4 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_element.verify.cpp @@ -19,15 +19,8 @@ // UNSUPPORTED: c++03 #include -#include -int main(int, char**) -{ - using T = std::tuple; - using E1 = typename std::tuple_element<1, T &>::type; // expected-error{{undefined template}} - using E2 = typename std::tuple_element<3, T>::type; - using E3 = typename std::tuple_element<4, T const>::type; - // expected-error-re@*:* 2 {{{{(static_assert|static assertion)}} failed}} - - return 0; -} +using T = std::tuple; +using E1 = typename std::tuple_element<1, T &>::type; // expected-error{{undefined template}} +using E2 = typename std::tuple_element<3, T>::type; +using E3 = typename std::tuple_element<4, T const>::type; // expected-error-re@*:* 2 {{{{(static_assert|static assertion)}} failed}} diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.verify.cpp similarity index 96% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.verify.cpp index 2a4374570eced..27a821ad3bf2e 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.verify.cpp @@ -18,11 +18,8 @@ #include -int main(int, char**) -{ +void f() { (void)std::tuple_size &>::value; // expected-error {{implicit instantiation of undefined template}} (void)std::tuple_size::value; // expected-error {{implicit instantiation of undefined template}} (void)std::tuple_size*>::value; // expected-error {{implicit instantiation of undefined template}} - - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp similarity index 97% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp index a2a65e0ebb8b5..532ccd730ffc1 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.verify.cpp @@ -39,8 +39,7 @@ struct std::tuple_size { template <> struct std::tuple_size {}; -int main(int, char**) -{ +void f() { // Test that tuple_size is not incomplete when tuple_size::value // is well-formed but not a constant expression. { @@ -59,6 +58,4 @@ int main(int, char**) // expected-error@*:* 1 {{no member named 'value'}} (void)std::tuple_size::value; // expected-note {{here}} } - - return 0; } diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.verify.cpp similarity index 96% rename from libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp rename to libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.verify.cpp index 6b1ee6884b39b..7570230b4b074 100644 --- a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.fail.cpp +++ b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_v.verify.cpp @@ -16,12 +16,9 @@ #include -int main(int, char**) -{ +void f() { (void)std::tuple_size_v &>; // expected-note {{requested here}} (void)std::tuple_size_v; // expected-note {{requested here}} (void)std::tuple_size_v*>; // expected-note {{requested here}} // expected-error@tuple:* 3 {{implicit instantiation of undefined template}} - - return 0; } diff --git a/libcxx/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.verify.cpp index a72a99da4e9dd..fff5044866d91 100644 --- a/libcxx/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.verify.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.verify.cpp @@ -13,7 +13,7 @@ // struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; // constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t(); -// This test checks for LWG 2510. +// This test checks for https://wg21.link/LWG2510. #include diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.default.explicit_LWG2510.verify.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.default.explicit_LWG2510.verify.cpp index 50a4eb74800a0..18b9ab32887aa 100644 --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.default.explicit_LWG2510.verify.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.default.explicit_LWG2510.verify.cpp @@ -15,7 +15,7 @@ // explicit(see-below) constexpr pair(); // This test checks the conditional explicitness of std::pair's default -// constructor as introduced by the resolution of LWG 2510. +// constructor as introduced by the resolution of https://wg21.link/LWG2510. #include From c7d3c84449f403716a8866e50491a1860a935b30 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 12 Jun 2023 10:43:55 -0700 Subject: [PATCH 019/130] [libc++] Split sources for The operations.cpp file contained the implementation of a ton of functionality unrelated to just the filesystem operations, and filesystem_common.h contained a lot of unrelated functionality as well. Splitting this up into more files will make it possible in the future to support parts of (e.g. path) on systems where there is no notion of a filesystem. Differential Revision: https://reviews.llvm.org/D152377 --- libcxx/src/CMakeLists.txt | 10 +- libcxx/src/filesystem/directory_entry.cpp | 74 ++ libcxx/src/filesystem/directory_iterator.cpp | 12 +- libcxx/src/filesystem/error.h | 246 ++++ libcxx/src/filesystem/file_descriptor.h | 283 ++++ libcxx/src/filesystem/filesystem_clock.cpp | 54 + libcxx/src/filesystem/filesystem_error.cpp | 37 + libcxx/src/filesystem/format_string.h | 89 ++ libcxx/src/filesystem/operations.cpp | 1145 +---------------- libcxx/src/filesystem/path.cpp | 460 +++++++ libcxx/src/filesystem/path_parser.h | 379 ++++++ libcxx/src/filesystem/posix_compat.h | 50 +- .../{filesystem_common.h => time_utils.h} | 330 +---- .../last_write_time.pass.cpp | 8 +- .../filesystems/convert_file_time.pass.cpp | 4 +- libcxx/utils/data/ignore_format.txt | 9 +- 16 files changed, 1732 insertions(+), 1458 deletions(-) create mode 100644 libcxx/src/filesystem/directory_entry.cpp create mode 100644 libcxx/src/filesystem/error.h create mode 100644 libcxx/src/filesystem/file_descriptor.h create mode 100644 libcxx/src/filesystem/filesystem_clock.cpp create mode 100644 libcxx/src/filesystem/filesystem_error.cpp create mode 100644 libcxx/src/filesystem/format_string.h create mode 100644 libcxx/src/filesystem/path.cpp create mode 100644 libcxx/src/filesystem/path_parser.h rename libcxx/src/filesystem/{filesystem_common.h => time_utils.h} (55%) diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt index 358a61e4a0351..dede38652e2f9 100644 --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -110,10 +110,16 @@ endif() if (LIBCXX_ENABLE_FILESYSTEM) list(APPEND LIBCXX_SOURCES - filesystem/filesystem_common.h - filesystem/operations.cpp + filesystem/directory_entry.cpp filesystem/directory_iterator.cpp + filesystem/file_descriptor.h + filesystem/filesystem_clock.cpp + filesystem/filesystem_error.cpp + filesystem/operations.cpp + filesystem/path_parser.h + filesystem/path.cpp filesystem/posix_compat.h + filesystem/time_utils.h ) # Filesystem uses __int128_t, which requires a definition of __muloi4 when # compiled with UBSAN. This definition is not provided by libgcc_s, but is diff --git a/libcxx/src/filesystem/directory_entry.cpp b/libcxx/src/filesystem/directory_entry.cpp new file mode 100644 index 0000000000000..4910d390d1ea7 --- /dev/null +++ b/libcxx/src/filesystem/directory_entry.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__config> +#include +#include +#include + +#include "file_descriptor.h" +#include "posix_compat.h" +#include "time_utils.h" + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +error_code directory_entry::__do_refresh() noexcept { + __data_.__reset(); + error_code failure_ec; + + detail::StatT full_st; + file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); + if (!status_known(st)) { + __data_.__reset(); + return failure_ec; + } + + if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { + __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + } else { // we have a symlink + __data_.__sym_perms_ = st.permissions(); + // Get the information about the linked entity. + // Ignore errors from stat, since we don't want errors regarding symlink + // resolution to be reported to the user. + error_code ignored_ec; + st = detail::posix_stat(__p_, full_st, &ignored_ec); + + __data_.__type_ = st.type(); + __data_.__non_sym_perms_ = st.permissions(); + + // If we failed to resolve the link, then only partially populate the + // cache. + if (!status_known(st)) { + __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved; + return error_code{}; + } + // Otherwise, we resolved the link, potentially as not existing. + // That's OK. + __data_.__cache_type_ = directory_entry::_RefreshSymlink; + } + + if (_VSTD_FS::is_regular_file(st)) + __data_.__size_ = static_cast(full_st.st_size); + + if (_VSTD_FS::exists(st)) { + __data_.__nlink_ = static_cast(full_st.st_nlink); + + // Attempt to extract the mtime, and fail if it's not representable using + // file_time_type. For now we ignore the error, as we'll report it when + // the value is actually used. + error_code ignored_ec; + __data_.__write_time_ = + detail::__extract_last_write_time(__p_, full_st, &ignored_ec); + } + + return failure_ec; +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/directory_iterator.cpp b/libcxx/src/filesystem/directory_iterator.cpp index 8d069cc080d89..4a7e01b09655f 100644 --- a/libcxx/src/filesystem/directory_iterator.cpp +++ b/libcxx/src/filesystem/directory_iterator.cpp @@ -11,8 +11,18 @@ #include #include #include +#include -#include "filesystem_common.h" +#include "error.h" +#include "file_descriptor.h" + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include +#else +# include // for DIR & friends +#endif _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/error.h b/libcxx/src/filesystem/error.h new file mode 100644 index 0000000000000..72696007ce0e5 --- /dev/null +++ b/libcxx/src/filesystem/error.h @@ -0,0 +1,246 @@ +//===----------------------------------------------------------------------===//// +// +// 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 FILESYSTEM_ERROR_H +#define FILESYSTEM_ERROR_H + +#include <__assert> +#include <__config> +#include +#include +#include +#include +#include +#include +#include +#include // __libcpp_unreachable + +#include "format_string.h" + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include // ERROR_* macros +#endif + +// TODO: Check whether these functions actually need internal linkage, or if they can be made normal header functions +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +namespace detail { +namespace { + +#if defined(_LIBCPP_WIN32API) + +errc __win_err_to_errc(int err) { + constexpr struct { + DWORD win; + errc errc; + } win_error_mapping[] = { + {ERROR_ACCESS_DENIED, errc::permission_denied}, + {ERROR_ALREADY_EXISTS, errc::file_exists}, + {ERROR_BAD_NETPATH, errc::no_such_file_or_directory}, + {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory}, + {ERROR_BAD_UNIT, errc::no_such_device}, + {ERROR_BROKEN_PIPE, errc::broken_pipe}, + {ERROR_BUFFER_OVERFLOW, errc::filename_too_long}, + {ERROR_BUSY, errc::device_or_resource_busy}, + {ERROR_BUSY_DRIVE, errc::device_or_resource_busy}, + {ERROR_CANNOT_MAKE, errc::permission_denied}, + {ERROR_CANTOPEN, errc::io_error}, + {ERROR_CANTREAD, errc::io_error}, + {ERROR_CANTWRITE, errc::io_error}, + {ERROR_CURRENT_DIRECTORY, errc::permission_denied}, + {ERROR_DEV_NOT_EXIST, errc::no_such_device}, + {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy}, + {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty}, + {ERROR_DIRECTORY, errc::invalid_argument}, + {ERROR_DISK_FULL, errc::no_space_on_device}, + {ERROR_FILE_EXISTS, errc::file_exists}, + {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory}, + {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device}, + {ERROR_INVALID_ACCESS, errc::permission_denied}, + {ERROR_INVALID_DRIVE, errc::no_such_device}, + {ERROR_INVALID_FUNCTION, errc::function_not_supported}, + {ERROR_INVALID_HANDLE, errc::invalid_argument}, + {ERROR_INVALID_NAME, errc::no_such_file_or_directory}, + {ERROR_INVALID_PARAMETER, errc::invalid_argument}, + {ERROR_LOCK_VIOLATION, errc::no_lock_available}, + {ERROR_LOCKED, errc::no_lock_available}, + {ERROR_NEGATIVE_SEEK, errc::invalid_argument}, + {ERROR_NOACCESS, errc::permission_denied}, + {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory}, + {ERROR_NOT_READY, errc::resource_unavailable_try_again}, + {ERROR_NOT_SAME_DEVICE, errc::cross_device_link}, + {ERROR_NOT_SUPPORTED, errc::not_supported}, + {ERROR_OPEN_FAILED, errc::io_error}, + {ERROR_OPEN_FILES, errc::device_or_resource_busy}, + {ERROR_OPERATION_ABORTED, errc::operation_canceled}, + {ERROR_OUTOFMEMORY, errc::not_enough_memory}, + {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory}, + {ERROR_READ_FAULT, errc::io_error}, + {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument}, + {ERROR_RETRY, errc::resource_unavailable_try_again}, + {ERROR_SEEK, errc::io_error}, + {ERROR_SHARING_VIOLATION, errc::permission_denied}, + {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open}, + {ERROR_WRITE_FAULT, errc::io_error}, + {ERROR_WRITE_PROTECT, errc::permission_denied}, + }; + + for (const auto &pair : win_error_mapping) + if (pair.win == static_cast(err)) + return pair.errc; + return errc::invalid_argument; +} + +#endif // _LIBCPP_WIN32API + +error_code capture_errno() { + _LIBCPP_ASSERT(errno != 0, "Expected errno to be non-zero"); + return error_code(errno, generic_category()); +} + +#if defined(_LIBCPP_WIN32API) +error_code make_windows_error(int err) { + return make_error_code(__win_err_to_errc(err)); +} +#endif + +template +T error_value(); +template <> +_LIBCPP_CONSTEXPR_SINCE_CXX14 void error_value() {} +template <> +bool error_value() { + return false; +} +#if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ +template <> +size_t error_value() { + return size_t(-1); +} +#endif +template <> +uintmax_t error_value() { + return uintmax_t(-1); +} +template <> +_LIBCPP_CONSTEXPR_SINCE_CXX14 file_time_type error_value() { + return file_time_type::min(); +} +template <> +path error_value() { + return {}; +} + +template +struct ErrorHandler { + const char* func_name_; + error_code* ec_ = nullptr; + const path* p1_ = nullptr; + const path* p2_ = nullptr; + + ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, + const path* p2 = nullptr) + : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { + if (ec_) + ec_->clear(); + } + + T report(const error_code& ec) const { + if (ec_) { + *ec_ = ec; + return error_value(); + } + string what = string("in ") + func_name_; + switch (bool(p1_) + bool(p2_)) { + case 0: + __throw_filesystem_error(what, ec); + case 1: + __throw_filesystem_error(what, *p1_, ec); + case 2: + __throw_filesystem_error(what, *p1_, *p2_, ec); + } + __libcpp_unreachable(); + } + + _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) + void report_impl(const error_code& ec, const char* msg, va_list ap) const { + if (ec_) { + *ec_ = ec; + return; + } + string what = + string("in ") + func_name_ + ": " + detail::vformat_string(msg, ap); + switch (bool(p1_) + bool(p2_)) { + case 0: + __throw_filesystem_error(what, ec); + case 1: + __throw_filesystem_error(what, *p1_, ec); + case 2: + __throw_filesystem_error(what, *p1_, *p2_, ec); + } + __libcpp_unreachable(); + } + + _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) + T report(const error_code& ec, const char* msg, ...) const { + va_list ap; + va_start(ap, msg); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + report_impl(ec, msg, ap); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + va_end(ap); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + va_end(ap); + return error_value(); + } + + T report(errc const& err) const { + return report(make_error_code(err)); + } + + _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) + T report(errc const& err, const char* msg, ...) const { + va_list ap; + va_start(ap, msg); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + report_impl(make_error_code(err), msg, ap); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + va_end(ap); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + va_end(ap); + return error_value(); + } + +private: + ErrorHandler(ErrorHandler const&) = delete; + ErrorHandler& operator=(ErrorHandler const&) = delete; +}; + +} // end anonymous namespace +} // end namespace detail + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +#endif // FILESYSTEM_ERROR_H diff --git a/libcxx/src/filesystem/file_descriptor.h b/libcxx/src/filesystem/file_descriptor.h new file mode 100644 index 0000000000000..e9520424d301f --- /dev/null +++ b/libcxx/src/filesystem/file_descriptor.h @@ -0,0 +1,283 @@ +//===----------------------------------------------------------------------===//// +// +// 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 FILESYSTEM_FILE_DESCRIPTOR_H +#define FILESYSTEM_FILE_DESCRIPTOR_H + +#include <__config> +#include +#include +#include +#include +#include + +#include "error.h" +#include "posix_compat.h" + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include +#else +# include // for DIR & friends +# include // values for fchmodat +# include +# include +# include +#endif // defined(_LIBCPP_WIN32API) + +// TODO: Check whether these functions actually need internal linkage, or if they can be made normal header functions +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +namespace detail { +namespace { + +#if !defined(_LIBCPP_WIN32API) + +#if defined(DT_BLK) +template +static file_type get_file_type(DirEntT* ent, int) { + switch (ent->d_type) { + case DT_BLK: + return file_type::block; + case DT_CHR: + return file_type::character; + case DT_DIR: + return file_type::directory; + case DT_FIFO: + return file_type::fifo; + case DT_LNK: + return file_type::symlink; + case DT_REG: + return file_type::regular; + case DT_SOCK: + return file_type::socket; + // Unlike in lstat, hitting "unknown" here simply means that the underlying + // filesystem doesn't support d_type. Report is as 'none' so we correctly + // set the cache to empty. + case DT_UNKNOWN: + break; + } + return file_type::none; +} +#endif // defined(DT_BLK) + +template +static file_type get_file_type(DirEntT*, long) { + return file_type::none; +} + +static pair posix_readdir(DIR* dir_stream, + error_code& ec) { + struct dirent* dir_entry_ptr = nullptr; + errno = 0; // zero errno in order to detect errors + ec.clear(); + if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { + if (errno) + ec = capture_errno(); + return {}; + } else { + return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)}; + } +} + +#else // _LIBCPP_WIN32API + +static file_type get_file_type(const WIN32_FIND_DATAW& data) { + if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && + data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) + return file_type::symlink; + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return file_type::directory; + return file_type::regular; +} +static uintmax_t get_file_size(const WIN32_FIND_DATAW& data) { + return (static_cast(data.nFileSizeHigh) << 32) + data.nFileSizeLow; +} +static file_time_type get_write_time(const WIN32_FIND_DATAW& data) { + ULARGE_INTEGER tmp; + const FILETIME& time = data.ftLastWriteTime; + tmp.u.LowPart = time.dwLowDateTime; + tmp.u.HighPart = time.dwHighDateTime; + return file_time_type(file_time_type::duration(tmp.QuadPart)); +} + +#endif // !_LIBCPP_WIN32API + +// POSIX HELPERS + +using value_type = path::value_type; +using string_type = path::string_type; + +struct FileDescriptor { + const path& name; + int fd = -1; + StatT m_stat; + file_status m_status; + + template + static FileDescriptor create(const path* p, error_code& ec, Args... args) { + ec.clear(); + int fd; + if ((fd = detail::open(p->c_str(), args...)) == -1) { + ec = capture_errno(); + return FileDescriptor{p}; + } + return FileDescriptor(p, fd); + } + + template + static FileDescriptor create_with_status(const path* p, error_code& ec, + Args... args) { + FileDescriptor fd = create(p, ec, args...); + if (!ec) + fd.refresh_status(ec); + + return fd; + } + + file_status get_status() const { return m_status; } + StatT const& get_stat() const { return m_stat; } + + bool status_known() const { return _VSTD_FS::status_known(m_status); } + + file_status refresh_status(error_code& ec); + + void close() noexcept { + if (fd != -1) + detail::close(fd); + fd = -1; + } + + FileDescriptor(FileDescriptor&& other) + : name(other.name), fd(other.fd), m_stat(other.m_stat), + m_status(other.m_status) { + other.fd = -1; + other.m_status = file_status{}; + } + + ~FileDescriptor() { close(); } + + FileDescriptor(FileDescriptor const&) = delete; + FileDescriptor& operator=(FileDescriptor const&) = delete; + +private: + explicit FileDescriptor(const path* p, int descriptor = -1) : name(*p), fd(descriptor) {} +}; + +perms posix_get_perms(const StatT& st) noexcept { + return static_cast(st.st_mode) & perms::mask; +} + +file_status create_file_status(error_code& m_ec, path const& p, + const StatT& path_stat, error_code* ec) { + if (ec) + *ec = m_ec; + if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { + return file_status(file_type::not_found); + } else if (m_ec) { + ErrorHandler err("posix_stat", ec, &p); + err.report(m_ec, "failed to determine attributes for the specified path"); + return file_status(file_type::none); + } + // else + + file_status fs_tmp; + auto const mode = path_stat.st_mode; + if (S_ISLNK(mode)) + fs_tmp.type(file_type::symlink); + else if (S_ISREG(mode)) + fs_tmp.type(file_type::regular); + else if (S_ISDIR(mode)) + fs_tmp.type(file_type::directory); + else if (S_ISBLK(mode)) + fs_tmp.type(file_type::block); + else if (S_ISCHR(mode)) + fs_tmp.type(file_type::character); + else if (S_ISFIFO(mode)) + fs_tmp.type(file_type::fifo); + else if (S_ISSOCK(mode)) + fs_tmp.type(file_type::socket); + else + fs_tmp.type(file_type::unknown); + + fs_tmp.permissions(detail::posix_get_perms(path_stat)); + return fs_tmp; +} + +file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { + error_code m_ec; + if (detail::stat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_stat(path const& p, error_code* ec) { + StatT path_stat; + return posix_stat(p, path_stat, ec); +} + +file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { + error_code m_ec; + if (detail::lstat(p.c_str(), &path_stat) == -1) + m_ec = detail::capture_errno(); + return create_file_status(m_ec, p, path_stat, ec); +} + +file_status posix_lstat(path const& p, error_code* ec) { + StatT path_stat; + return posix_lstat(p, path_stat, ec); +} + +// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html +bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) { + if (detail::ftruncate(fd.fd, to_size) == -1) { + ec = capture_errno(); + return true; + } + ec.clear(); + return false; +} + +bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) { + if (detail::fchmod(fd.fd, st.st_mode) == -1) { + ec = capture_errno(); + return true; + } + ec.clear(); + return false; +} + +bool stat_equivalent(const StatT& st1, const StatT& st2) { + return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); +} + +file_status FileDescriptor::refresh_status(error_code& ec) { + // FD must be open and good. + m_status = file_status{}; + m_stat = {}; + error_code m_ec; + if (detail::fstat(fd, &m_stat) == -1) + m_ec = capture_errno(); + m_status = create_file_status(m_ec, name, m_stat, &ec); + return m_status; +} + +} // namespace +} // end namespace detail + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +_LIBCPP_DIAGNOSTIC_POP + +#endif // FILESYSTEM_FILE_DESCRIPTOR_H diff --git a/libcxx/src/filesystem/filesystem_clock.cpp b/libcxx/src/filesystem/filesystem_clock.cpp new file mode 100644 index 0000000000000..c6b3c893ff8f7 --- /dev/null +++ b/libcxx/src/filesystem/filesystem_clock.cpp @@ -0,0 +1,54 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__config> +#include +#include +#include + +#include "posix_compat.h" // TimeSpec + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include +#endif + +#if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API) +# include // for gettimeofday and timeval +#endif + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +const bool _FilesystemClock::is_steady; + +_FilesystemClock::time_point _FilesystemClock::now() noexcept { + typedef chrono::duration __secs; +#if defined(_LIBCPP_WIN32API) + typedef chrono::duration __nsecs; + FILETIME time; + GetSystemTimeAsFileTime(&time); + detail::TimeSpec tp = detail::filetime_to_timespec(time); + return time_point(__secs(tp.tv_sec) + + chrono::duration_cast(__nsecs(tp.tv_nsec))); +#elif defined(CLOCK_REALTIME) + typedef chrono::duration __nsecs; + struct timespec tp; + if (0 != clock_gettime(CLOCK_REALTIME, &tp)) + __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); + return time_point(__secs(tp.tv_sec) + + chrono::duration_cast(__nsecs(tp.tv_nsec))); +#else + typedef chrono::duration __microsecs; + timeval tv; + gettimeofday(&tv, 0); + return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec)); +#endif // CLOCK_REALTIME +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/filesystem_error.cpp b/libcxx/src/filesystem/filesystem_error.cpp new file mode 100644 index 0000000000000..5faed3b89efa6 --- /dev/null +++ b/libcxx/src/filesystem/filesystem_error.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__config> +#include <__utility/unreachable.h> +#include +#include + +#include "format_string.h" + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +filesystem_error::~filesystem_error() {} + +void filesystem_error::__create_what(int __num_paths) { + const char* derived_what = system_error::what(); + __storage_->__what_ = [&]() -> string { + switch (__num_paths) { + case 0: + return detail::format_string("filesystem error: %s", derived_what); + case 1: + return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "]", + derived_what, path1().c_str()); + case 2: + return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "] [" PATH_CSTR_FMT "]", + derived_what, path1().c_str(), path2().c_str()); + } + __libcpp_unreachable(); + }(); +} + +_LIBCPP_END_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/format_string.h b/libcxx/src/filesystem/format_string.h new file mode 100644 index 0000000000000..d95d9bd3f55ec --- /dev/null +++ b/libcxx/src/filesystem/format_string.h @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===//// +// +// 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 FILESYSTEM_FORMAT_STRING_H +#define FILESYSTEM_FORMAT_STRING_H + +#include <__assert> +#include <__config> +#include +#include +#include +#include +#include + +#if defined(_LIBCPP_WIN32API) +# define PATHSTR(x) (L##x) +# define PATH_CSTR_FMT "\"%ls\"" +#else +# define PATHSTR(x) (x) +# define PATH_CSTR_FMT "\"%s\"" +#endif + +// TODO: Check whether these functions actually need internal linkage, or if they can be made normal header functions +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +namespace detail { +namespace { + +_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) +string vformat_string(const char* msg, va_list ap) { + array buf; + + va_list apcopy; + va_copy(apcopy, ap); + int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); + va_end(apcopy); + + string result; + if (static_cast(ret) < buf.size()) { + result.assign(buf.data(), static_cast(ret)); + } else { + // we did not provide a long enough buffer on our first attempt. The + // return value is the number of bytes (excluding the null byte) that are + // needed for formatting. + size_t size_with_null = static_cast(ret) + 1; + result.__resize_default_init(size_with_null - 1); + ret = ::vsnprintf(&result[0], size_with_null, msg, ap); + _LIBCPP_ASSERT(static_cast(ret) == (size_with_null - 1), "TODO"); + } + return result; +} + +_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) +string format_string(const char* msg, ...) { + string ret; + va_list ap; + va_start(ap, msg); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + try { +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + ret = detail::vformat_string(msg, ap); +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + } catch (...) { + va_end(ap); + throw; + } +#endif // _LIBCPP_HAS_NO_EXCEPTIONS + va_end(ap); + return ret; +} + +} // end anonymous namespace +} // end namespace detail + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +_LIBCPP_DIAGNOSTIC_POP + +#endif // FILESYSTEM_FORMAT_STRING_H diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp index af31fe049b3e4..f6c3ff13080dd 100644 --- a/libcxx/src/filesystem/operations.cpp +++ b/libcxx/src/filesystem/operations.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include <__assert> +#include <__config> #include <__utility/unreachable.h> #include #include @@ -17,9 +18,11 @@ #include #include -#include "filesystem_common.h" - +#include "error.h" +#include "file_descriptor.h" +#include "path_parser.h" #include "posix_compat.h" +#include "time_utils.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN @@ -45,595 +48,12 @@ # define _LIBCPP_FILESYSTEM_USE_FSTREAM #endif -#if !defined(CLOCK_REALTIME) && !defined(_LIBCPP_WIN32API) -# include // for gettimeofday and timeval -#endif - #if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB) # pragma comment(lib, "rt") #endif _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM -namespace { - -bool isSeparator(path::value_type C) { - if (C == '/') - return true; -#if defined(_LIBCPP_WIN32API) - if (C == '\\') - return true; -#endif - return false; -} - -bool isDriveLetter(path::value_type C) { - return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z'); -} - -namespace parser { - -using string_view_t = path::__string_view; -using string_view_pair = pair; -using PosPtr = path::value_type const*; - -struct PathParser { - enum ParserState : unsigned char { - // Zero is a special sentinel value used by default constructed iterators. - PS_BeforeBegin = path::iterator::_BeforeBegin, - PS_InRootName = path::iterator::_InRootName, - PS_InRootDir = path::iterator::_InRootDir, - PS_InFilenames = path::iterator::_InFilenames, - PS_InTrailingSep = path::iterator::_InTrailingSep, - PS_AtEnd = path::iterator::_AtEnd - }; - - const string_view_t Path; - string_view_t RawEntry; - ParserState State; - -private: - PathParser(string_view_t P, ParserState State) noexcept : Path(P), - State(State) {} - -public: - PathParser(string_view_t P, string_view_t E, unsigned char S) - : Path(P), RawEntry(E), State(static_cast(S)) { - // S cannot be '0' or PS_BeforeBegin. - } - - static PathParser CreateBegin(string_view_t P) noexcept { - PathParser PP(P, PS_BeforeBegin); - PP.increment(); - return PP; - } - - static PathParser CreateEnd(string_view_t P) noexcept { - PathParser PP(P, PS_AtEnd); - return PP; - } - - PosPtr peek() const noexcept { - auto TkEnd = getNextTokenStartPos(); - auto End = getAfterBack(); - return TkEnd == End ? nullptr : TkEnd; - } - - void increment() noexcept { - const PosPtr End = getAfterBack(); - const PosPtr Start = getNextTokenStartPos(); - if (Start == End) - return makeState(PS_AtEnd); - - switch (State) { - case PS_BeforeBegin: { - PosPtr TkEnd = consumeRootName(Start, End); - if (TkEnd) - return makeState(PS_InRootName, Start, TkEnd); - } - _LIBCPP_FALLTHROUGH(); - case PS_InRootName: { - PosPtr TkEnd = consumeAllSeparators(Start, End); - if (TkEnd) - return makeState(PS_InRootDir, Start, TkEnd); - else - return makeState(PS_InFilenames, Start, consumeName(Start, End)); - } - case PS_InRootDir: - return makeState(PS_InFilenames, Start, consumeName(Start, End)); - - case PS_InFilenames: { - PosPtr SepEnd = consumeAllSeparators(Start, End); - if (SepEnd != End) { - PosPtr TkEnd = consumeName(SepEnd, End); - if (TkEnd) - return makeState(PS_InFilenames, SepEnd, TkEnd); - } - return makeState(PS_InTrailingSep, Start, SepEnd); - } - - case PS_InTrailingSep: - return makeState(PS_AtEnd); - - case PS_AtEnd: - __libcpp_unreachable(); - } - } - - void decrement() noexcept { - const PosPtr REnd = getBeforeFront(); - const PosPtr RStart = getCurrentTokenStartPos() - 1; - if (RStart == REnd) // we're decrementing the begin - return makeState(PS_BeforeBegin); - - switch (State) { - case PS_AtEnd: { - // Try to consume a trailing separator or root directory first. - if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) { - if (SepEnd == REnd) - return makeState(PS_InRootDir, Path.data(), RStart + 1); - PosPtr TkStart = consumeRootName(SepEnd, REnd); - if (TkStart == REnd) - return makeState(PS_InRootDir, RStart, RStart + 1); - return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1); - } else { - PosPtr TkStart = consumeRootName(RStart, REnd); - if (TkStart == REnd) - return makeState(PS_InRootName, TkStart + 1, RStart + 1); - TkStart = consumeName(RStart, REnd); - return makeState(PS_InFilenames, TkStart + 1, RStart + 1); - } - } - case PS_InTrailingSep: - return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, - RStart + 1); - case PS_InFilenames: { - PosPtr SepEnd = consumeAllSeparators(RStart, REnd); - if (SepEnd == REnd) - return makeState(PS_InRootDir, Path.data(), RStart + 1); - PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd); - if (TkStart == REnd) { - if (SepEnd) - return makeState(PS_InRootDir, SepEnd + 1, RStart + 1); - return makeState(PS_InRootName, TkStart + 1, RStart + 1); - } - TkStart = consumeName(SepEnd, REnd); - return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1); - } - case PS_InRootDir: - return makeState(PS_InRootName, Path.data(), RStart + 1); - case PS_InRootName: - case PS_BeforeBegin: - __libcpp_unreachable(); - } - } - - /// \brief Return a view with the "preferred representation" of the current - /// element. For example trailing separators are represented as a '.' - string_view_t operator*() const noexcept { - switch (State) { - case PS_BeforeBegin: - case PS_AtEnd: - return PATHSTR(""); - case PS_InRootDir: - if (RawEntry[0] == '\\') - return PATHSTR("\\"); - else - return PATHSTR("/"); - case PS_InTrailingSep: - return PATHSTR(""); - case PS_InRootName: - case PS_InFilenames: - return RawEntry; - } - __libcpp_unreachable(); - } - - explicit operator bool() const noexcept { - return State != PS_BeforeBegin && State != PS_AtEnd; - } - - PathParser& operator++() noexcept { - increment(); - return *this; - } - - PathParser& operator--() noexcept { - decrement(); - return *this; - } - - bool atEnd() const noexcept { - return State == PS_AtEnd; - } - - bool inRootDir() const noexcept { - return State == PS_InRootDir; - } - - bool inRootName() const noexcept { - return State == PS_InRootName; - } - - bool inRootPath() const noexcept { - return inRootName() || inRootDir(); - } - -private: - void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept { - State = NewState; - RawEntry = string_view_t(Start, End - Start); - } - void makeState(ParserState NewState) noexcept { - State = NewState; - RawEntry = {}; - } - - PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); } - - PosPtr getBeforeFront() const noexcept { return Path.data() - 1; } - - /// \brief Return a pointer to the first character after the currently - /// lexed element. - PosPtr getNextTokenStartPos() const noexcept { - switch (State) { - case PS_BeforeBegin: - return Path.data(); - case PS_InRootName: - case PS_InRootDir: - case PS_InFilenames: - return &RawEntry.back() + 1; - case PS_InTrailingSep: - case PS_AtEnd: - return getAfterBack(); - } - __libcpp_unreachable(); - } - - /// \brief Return a pointer to the first character in the currently lexed - /// element. - PosPtr getCurrentTokenStartPos() const noexcept { - switch (State) { - case PS_BeforeBegin: - case PS_InRootName: - return &Path.front(); - case PS_InRootDir: - case PS_InFilenames: - case PS_InTrailingSep: - return &RawEntry.front(); - case PS_AtEnd: - return &Path.back() + 1; - } - __libcpp_unreachable(); - } - - // Consume all consecutive separators. - PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept { - if (P == nullptr || P == End || !isSeparator(*P)) - return nullptr; - const int Inc = P < End ? 1 : -1; - P += Inc; - while (P != End && isSeparator(*P)) - P += Inc; - return P; - } - - // Consume exactly N separators, or return nullptr. - PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept { - PosPtr Ret = consumeAllSeparators(P, End); - if (Ret == nullptr) - return nullptr; - if (P < End) { - if (Ret == P + N) - return Ret; - } else { - if (Ret == P - N) - return Ret; - } - return nullptr; - } - - PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { - PosPtr Start = P; - if (P == nullptr || P == End || isSeparator(*P)) - return nullptr; - const int Inc = P < End ? 1 : -1; - P += Inc; - while (P != End && !isSeparator(*P)) - P += Inc; - if (P == End && Inc < 0) { - // Iterating backwards and consumed all the rest of the input. - // Check if the start of the string would have been considered - // a root name. - PosPtr RootEnd = consumeRootName(End + 1, Start); - if (RootEnd) - return RootEnd - 1; - } - return P; - } - - PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept { - if (P == End) - return nullptr; - if (P < End) { - if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':') - return nullptr; - return P + 2; - } else { - if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':') - return nullptr; - return P - 2; - } - } - - PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept { - if (P == End) - return nullptr; - if (P < End) - return consumeName(consumeNSeparators(P, End, 2), End); - else - return consumeNSeparators(consumeName(P, End), End, 2); - } - - PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept { -#if defined(_LIBCPP_WIN32API) - if (PosPtr Ret = consumeDriveLetter(P, End)) - return Ret; - if (PosPtr Ret = consumeNetworkRoot(P, End)) - return Ret; -#endif - return nullptr; - } -}; - -string_view_pair separate_filename(string_view_t const& s) { - if (s == PATHSTR(".") || s == PATHSTR("..") || s.empty()) - return string_view_pair{s, PATHSTR("")}; - auto pos = s.find_last_of('.'); - if (pos == string_view_t::npos || pos == 0) - return string_view_pair{s, string_view_t{}}; - return string_view_pair{s.substr(0, pos), s.substr(pos)}; -} - -string_view_t createView(PosPtr S, PosPtr E) noexcept { - return {S, static_cast(E - S) + 1}; -} - -} // namespace parser -} // namespace - -// POSIX HELPERS - -#if defined(_LIBCPP_WIN32API) -namespace detail { - -errc __win_err_to_errc(int err) { - constexpr struct { - DWORD win; - errc errc; - } win_error_mapping[] = { - {ERROR_ACCESS_DENIED, errc::permission_denied}, - {ERROR_ALREADY_EXISTS, errc::file_exists}, - {ERROR_BAD_NETPATH, errc::no_such_file_or_directory}, - {ERROR_BAD_PATHNAME, errc::no_such_file_or_directory}, - {ERROR_BAD_UNIT, errc::no_such_device}, - {ERROR_BROKEN_PIPE, errc::broken_pipe}, - {ERROR_BUFFER_OVERFLOW, errc::filename_too_long}, - {ERROR_BUSY, errc::device_or_resource_busy}, - {ERROR_BUSY_DRIVE, errc::device_or_resource_busy}, - {ERROR_CANNOT_MAKE, errc::permission_denied}, - {ERROR_CANTOPEN, errc::io_error}, - {ERROR_CANTREAD, errc::io_error}, - {ERROR_CANTWRITE, errc::io_error}, - {ERROR_CURRENT_DIRECTORY, errc::permission_denied}, - {ERROR_DEV_NOT_EXIST, errc::no_such_device}, - {ERROR_DEVICE_IN_USE, errc::device_or_resource_busy}, - {ERROR_DIR_NOT_EMPTY, errc::directory_not_empty}, - {ERROR_DIRECTORY, errc::invalid_argument}, - {ERROR_DISK_FULL, errc::no_space_on_device}, - {ERROR_FILE_EXISTS, errc::file_exists}, - {ERROR_FILE_NOT_FOUND, errc::no_such_file_or_directory}, - {ERROR_HANDLE_DISK_FULL, errc::no_space_on_device}, - {ERROR_INVALID_ACCESS, errc::permission_denied}, - {ERROR_INVALID_DRIVE, errc::no_such_device}, - {ERROR_INVALID_FUNCTION, errc::function_not_supported}, - {ERROR_INVALID_HANDLE, errc::invalid_argument}, - {ERROR_INVALID_NAME, errc::no_such_file_or_directory}, - {ERROR_INVALID_PARAMETER, errc::invalid_argument}, - {ERROR_LOCK_VIOLATION, errc::no_lock_available}, - {ERROR_LOCKED, errc::no_lock_available}, - {ERROR_NEGATIVE_SEEK, errc::invalid_argument}, - {ERROR_NOACCESS, errc::permission_denied}, - {ERROR_NOT_ENOUGH_MEMORY, errc::not_enough_memory}, - {ERROR_NOT_READY, errc::resource_unavailable_try_again}, - {ERROR_NOT_SAME_DEVICE, errc::cross_device_link}, - {ERROR_NOT_SUPPORTED, errc::not_supported}, - {ERROR_OPEN_FAILED, errc::io_error}, - {ERROR_OPEN_FILES, errc::device_or_resource_busy}, - {ERROR_OPERATION_ABORTED, errc::operation_canceled}, - {ERROR_OUTOFMEMORY, errc::not_enough_memory}, - {ERROR_PATH_NOT_FOUND, errc::no_such_file_or_directory}, - {ERROR_READ_FAULT, errc::io_error}, - {ERROR_REPARSE_TAG_INVALID, errc::invalid_argument}, - {ERROR_RETRY, errc::resource_unavailable_try_again}, - {ERROR_SEEK, errc::io_error}, - {ERROR_SHARING_VIOLATION, errc::permission_denied}, - {ERROR_TOO_MANY_OPEN_FILES, errc::too_many_files_open}, - {ERROR_WRITE_FAULT, errc::io_error}, - {ERROR_WRITE_PROTECT, errc::permission_denied}, - }; - - for (const auto &pair : win_error_mapping) - if (pair.win == static_cast(err)) - return pair.errc; - return errc::invalid_argument; -} - -} // namespace detail -#endif - -namespace detail { -namespace { - -using value_type = path::value_type; -using string_type = path::string_type; - -struct FileDescriptor { - const path& name; - int fd = -1; - StatT m_stat; - file_status m_status; - - template - static FileDescriptor create(const path* p, error_code& ec, Args... args) { - ec.clear(); - int fd; - if ((fd = detail::open(p->c_str(), args...)) == -1) { - ec = capture_errno(); - return FileDescriptor{p}; - } - return FileDescriptor(p, fd); - } - - template - static FileDescriptor create_with_status(const path* p, error_code& ec, - Args... args) { - FileDescriptor fd = create(p, ec, args...); - if (!ec) - fd.refresh_status(ec); - - return fd; - } - - file_status get_status() const { return m_status; } - StatT const& get_stat() const { return m_stat; } - - bool status_known() const { return _VSTD_FS::status_known(m_status); } - - file_status refresh_status(error_code& ec); - - void close() noexcept { - if (fd != -1) - detail::close(fd); - fd = -1; - } - - FileDescriptor(FileDescriptor&& other) - : name(other.name), fd(other.fd), m_stat(other.m_stat), - m_status(other.m_status) { - other.fd = -1; - other.m_status = file_status{}; - } - - ~FileDescriptor() { close(); } - - FileDescriptor(FileDescriptor const&) = delete; - FileDescriptor& operator=(FileDescriptor const&) = delete; - -private: - explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {} -}; - -perms posix_get_perms(const StatT& st) noexcept { - return static_cast(st.st_mode) & perms::mask; -} - -file_status create_file_status(error_code& m_ec, path const& p, - const StatT& path_stat, error_code* ec) { - if (ec) - *ec = m_ec; - if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) { - return file_status(file_type::not_found); - } else if (m_ec) { - ErrorHandler err("posix_stat", ec, &p); - err.report(m_ec, "failed to determine attributes for the specified path"); - return file_status(file_type::none); - } - // else - - file_status fs_tmp; - auto const mode = path_stat.st_mode; - if (S_ISLNK(mode)) - fs_tmp.type(file_type::symlink); - else if (S_ISREG(mode)) - fs_tmp.type(file_type::regular); - else if (S_ISDIR(mode)) - fs_tmp.type(file_type::directory); - else if (S_ISBLK(mode)) - fs_tmp.type(file_type::block); - else if (S_ISCHR(mode)) - fs_tmp.type(file_type::character); - else if (S_ISFIFO(mode)) - fs_tmp.type(file_type::fifo); - else if (S_ISSOCK(mode)) - fs_tmp.type(file_type::socket); - else - fs_tmp.type(file_type::unknown); - - fs_tmp.permissions(detail::posix_get_perms(path_stat)); - return fs_tmp; -} - -file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) { - error_code m_ec; - if (detail::stat(p.c_str(), &path_stat) == -1) - m_ec = detail::capture_errno(); - return create_file_status(m_ec, p, path_stat, ec); -} - -file_status posix_stat(path const& p, error_code* ec) { - StatT path_stat; - return posix_stat(p, path_stat, ec); -} - -file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) { - error_code m_ec; - if (detail::lstat(p.c_str(), &path_stat) == -1) - m_ec = detail::capture_errno(); - return create_file_status(m_ec, p, path_stat, ec); -} - -file_status posix_lstat(path const& p, error_code* ec) { - StatT path_stat; - return posix_lstat(p, path_stat, ec); -} - -// http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html -bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) { - if (detail::ftruncate(fd.fd, to_size) == -1) { - ec = capture_errno(); - return true; - } - ec.clear(); - return false; -} - -bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) { - if (detail::fchmod(fd.fd, st.st_mode) == -1) { - ec = capture_errno(); - return true; - } - ec.clear(); - return false; -} - -bool stat_equivalent(const StatT& st1, const StatT& st2) { - return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino); -} - -file_status FileDescriptor::refresh_status(error_code& ec) { - // FD must be open and good. - m_status = file_status{}; - m_stat = {}; - error_code m_ec; - if (detail::fstat(fd, &m_stat) == -1) - m_ec = capture_errno(); - m_status = create_file_status(m_ec, name, m_stat, &ec); - return m_status; -} -} // namespace -} // end namespace detail - using detail::capture_errno; using detail::ErrorHandler; using detail::StatT; @@ -642,51 +62,6 @@ using parser::createView; using parser::PathParser; using parser::string_view_t; -const bool _FilesystemClock::is_steady; - -_FilesystemClock::time_point _FilesystemClock::now() noexcept { - typedef chrono::duration __secs; -#if defined(_LIBCPP_WIN32API) - typedef chrono::duration __nsecs; - FILETIME time; - GetSystemTimeAsFileTime(&time); - TimeSpec tp = detail::filetime_to_timespec(time); - return time_point(__secs(tp.tv_sec) + - chrono::duration_cast(__nsecs(tp.tv_nsec))); -#elif defined(CLOCK_REALTIME) - typedef chrono::duration __nsecs; - struct timespec tp; - if (0 != clock_gettime(CLOCK_REALTIME, &tp)) - __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed"); - return time_point(__secs(tp.tv_sec) + - chrono::duration_cast(__nsecs(tp.tv_nsec))); -#else - typedef chrono::duration __microsecs; - timeval tv; - gettimeofday(&tv, 0); - return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec)); -#endif // CLOCK_REALTIME -} - -filesystem_error::~filesystem_error() {} - -void filesystem_error::__create_what(int __num_paths) { - const char* derived_what = system_error::what(); - __storage_->__what_ = [&]() -> string { - switch (__num_paths) { - case 0: - return detail::format_string("filesystem error: %s", derived_what); - case 1: - return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "]", - derived_what, path1().c_str()); - case 2: - return detail::format_string("filesystem error: %s [" PATH_CSTR_FMT "] [" PATH_CSTR_FMT "]", - derived_what, path1().c_str(), path2().c_str()); - } - __libcpp_unreachable(); - }(); -} - static path __do_absolute(const path& p, path* cwd, error_code* ec) { if (ec) ec->clear(); @@ -1193,18 +568,6 @@ bool __fs_is_empty(const path& p, error_code* ec) { __libcpp_unreachable(); } -static file_time_type __extract_last_write_time(const path& p, const StatT& st, - error_code* ec) { - using detail::fs_time; - ErrorHandler err("last_write_time", ec, &p); - - auto ts = detail::extract_mtime(st); - if (!fs_time::is_representable(ts)) - return err.report(errc::value_too_large); - - return fs_time::convert_from_timespec(ts); -} - file_time_type __last_write_time(const path& p, error_code* ec) { using namespace chrono; ErrorHandler err("last_write_time", ec, &p); @@ -1214,7 +577,7 @@ file_time_type __last_write_time(const path& p, error_code* ec) { detail::posix_stat(p, st, &m_ec); if (m_ec) return err.report(m_ec); - return __extract_last_write_time(p, st, ec); + return detail::__extract_last_write_time(p, st, ec); } void __last_write_time(const path& p, file_time_type new_time, error_code* ec) { @@ -1609,500 +972,4 @@ path __weakly_canonical(const path& p, error_code* ec) { return result.lexically_normal(); } -/////////////////////////////////////////////////////////////////////////////// -// path definitions -/////////////////////////////////////////////////////////////////////////////// - -constexpr path::value_type path::preferred_separator; - -path& path::replace_extension(path const& replacement) { - path p = extension(); - if (not p.empty()) { - __pn_.erase(__pn_.size() - p.native().size()); - } - if (!replacement.empty()) { - if (replacement.native()[0] != '.') { - __pn_ += PATHSTR("."); - } - __pn_.append(replacement.__pn_); - } - return *this; -} - -/////////////////////////////////////////////////////////////////////////////// -// path.decompose - -string_view_t path::__root_name() const { - auto PP = PathParser::CreateBegin(__pn_); - if (PP.State == PathParser::PS_InRootName) - return *PP; - return {}; -} - -string_view_t path::__root_directory() const { - auto PP = PathParser::CreateBegin(__pn_); - if (PP.State == PathParser::PS_InRootName) - ++PP; - if (PP.State == PathParser::PS_InRootDir) - return *PP; - return {}; -} - -string_view_t path::__root_path_raw() const { - auto PP = PathParser::CreateBegin(__pn_); - if (PP.State == PathParser::PS_InRootName) { - auto NextCh = PP.peek(); - if (NextCh && isSeparator(*NextCh)) { - ++PP; - return createView(__pn_.data(), &PP.RawEntry.back()); - } - return PP.RawEntry; - } - if (PP.State == PathParser::PS_InRootDir) - return *PP; - return {}; -} - -static bool ConsumeRootName(PathParser *PP) { - static_assert(PathParser::PS_BeforeBegin == 1 && - PathParser::PS_InRootName == 2, - "Values for enums are incorrect"); - while (PP->State <= PathParser::PS_InRootName) - ++(*PP); - return PP->State == PathParser::PS_AtEnd; -} - -static bool ConsumeRootDir(PathParser* PP) { - static_assert(PathParser::PS_BeforeBegin == 1 && - PathParser::PS_InRootName == 2 && - PathParser::PS_InRootDir == 3, "Values for enums are incorrect"); - while (PP->State <= PathParser::PS_InRootDir) - ++(*PP); - return PP->State == PathParser::PS_AtEnd; -} - -string_view_t path::__relative_path() const { - auto PP = PathParser::CreateBegin(__pn_); - if (ConsumeRootDir(&PP)) - return {}; - return createView(PP.RawEntry.data(), &__pn_.back()); -} - -string_view_t path::__parent_path() const { - if (empty()) - return {}; - // Determine if we have a root path but not a relative path. In that case - // return *this. - { - auto PP = PathParser::CreateBegin(__pn_); - if (ConsumeRootDir(&PP)) - return __pn_; - } - // Otherwise remove a single element from the end of the path, and return - // a string representing that path - { - auto PP = PathParser::CreateEnd(__pn_); - --PP; - if (PP.RawEntry.data() == __pn_.data()) - return {}; - --PP; - return createView(__pn_.data(), &PP.RawEntry.back()); - } -} - -string_view_t path::__filename() const { - if (empty()) - return {}; - { - PathParser PP = PathParser::CreateBegin(__pn_); - if (ConsumeRootDir(&PP)) - return {}; - } - return *(--PathParser::CreateEnd(__pn_)); -} - -string_view_t path::__stem() const { - return parser::separate_filename(__filename()).first; -} - -string_view_t path::__extension() const { - return parser::separate_filename(__filename()).second; -} - -//////////////////////////////////////////////////////////////////////////// -// path.gen - -enum PathPartKind : unsigned char { - PK_None, - PK_RootSep, - PK_Filename, - PK_Dot, - PK_DotDot, - PK_TrailingSep -}; - -static PathPartKind ClassifyPathPart(string_view_t Part) { - if (Part.empty()) - return PK_TrailingSep; - if (Part == PATHSTR(".")) - return PK_Dot; - if (Part == PATHSTR("..")) - return PK_DotDot; - if (Part == PATHSTR("/")) - return PK_RootSep; -#if defined(_LIBCPP_WIN32API) - if (Part == PATHSTR("\\")) - return PK_RootSep; -#endif - return PK_Filename; -} - -path path::lexically_normal() const { - if (__pn_.empty()) - return *this; - - using PartKindPair = pair; - vector Parts; - // Guess as to how many elements the path has to avoid reallocating. - Parts.reserve(32); - - // Track the total size of the parts as we collect them. This allows the - // resulting path to reserve the correct amount of memory. - size_t NewPathSize = 0; - auto AddPart = [&](PathPartKind K, string_view_t P) { - NewPathSize += P.size(); - Parts.emplace_back(P, K); - }; - auto LastPartKind = [&]() { - if (Parts.empty()) - return PK_None; - return Parts.back().second; - }; - - bool MaybeNeedTrailingSep = false; - // Build a stack containing the remaining elements of the path, popping off - // elements which occur before a '..' entry. - for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) { - auto Part = *PP; - PathPartKind Kind = ClassifyPathPart(Part); - switch (Kind) { - case PK_Filename: - case PK_RootSep: { - // Add all non-dot and non-dot-dot elements to the stack of elements. - AddPart(Kind, Part); - MaybeNeedTrailingSep = false; - break; - } - case PK_DotDot: { - // Only push a ".." element if there are no elements preceding the "..", - // or if the preceding element is itself "..". - auto LastKind = LastPartKind(); - if (LastKind == PK_Filename) { - NewPathSize -= Parts.back().first.size(); - Parts.pop_back(); - } else if (LastKind != PK_RootSep) - AddPart(PK_DotDot, PATHSTR("..")); - MaybeNeedTrailingSep = LastKind == PK_Filename; - break; - } - case PK_Dot: - case PK_TrailingSep: { - MaybeNeedTrailingSep = true; - break; - } - case PK_None: - __libcpp_unreachable(); - } - } - // [fs.path.generic]p6.8: If the path is empty, add a dot. - if (Parts.empty()) - return PATHSTR("."); - - // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any - // trailing directory-separator. - bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename; - - path Result; - Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep); - for (auto& PK : Parts) - Result /= PK.first; - - if (NeedTrailingSep) - Result /= PATHSTR(""); - - Result.make_preferred(); - return Result; -} - -static int DetermineLexicalElementCount(PathParser PP) { - int Count = 0; - for (; PP; ++PP) { - auto Elem = *PP; - if (Elem == PATHSTR("..")) - --Count; - else if (Elem != PATHSTR(".") && Elem != PATHSTR("")) - ++Count; - } - return Count; -} - -path path::lexically_relative(const path& base) const { - { // perform root-name/root-directory mismatch checks - auto PP = PathParser::CreateBegin(__pn_); - auto PPBase = PathParser::CreateBegin(base.__pn_); - auto CheckIterMismatchAtBase = [&]() { - return PP.State != PPBase.State && - (PP.inRootPath() || PPBase.inRootPath()); - }; - if (PP.inRootName() && PPBase.inRootName()) { - if (*PP != *PPBase) - return {}; - } else if (CheckIterMismatchAtBase()) - return {}; - - if (PP.inRootPath()) - ++PP; - if (PPBase.inRootPath()) - ++PPBase; - if (CheckIterMismatchAtBase()) - return {}; - } - - // Find the first mismatching element - auto PP = PathParser::CreateBegin(__pn_); - auto PPBase = PathParser::CreateBegin(base.__pn_); - while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) { - ++PP; - ++PPBase; - } - - // If there is no mismatch, return ".". - if (!PP && !PPBase) - return "."; - - // Otherwise, determine the number of elements, 'n', which are not dot or - // dot-dot minus the number of dot-dot elements. - int ElemCount = DetermineLexicalElementCount(PPBase); - if (ElemCount < 0) - return {}; - - // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise - if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR(""))) - return PATHSTR("."); - - // return a path constructed with 'n' dot-dot elements, followed by the - // elements of '*this' after the mismatch. - path Result; - // FIXME: Reserve enough room in Result that it won't have to re-allocate. - while (ElemCount--) - Result /= PATHSTR(".."); - for (; PP; ++PP) - Result /= *PP; - return Result; -} - -//////////////////////////////////////////////////////////////////////////// -// path.comparisons -static int CompareRootName(PathParser *LHS, PathParser *RHS) { - if (!LHS->inRootName() && !RHS->inRootName()) - return 0; - - auto GetRootName = [](PathParser *Parser) -> string_view_t { - return Parser->inRootName() ? **Parser : PATHSTR(""); - }; - int res = GetRootName(LHS).compare(GetRootName(RHS)); - ConsumeRootName(LHS); - ConsumeRootName(RHS); - return res; -} - -static int CompareRootDir(PathParser *LHS, PathParser *RHS) { - if (!LHS->inRootDir() && RHS->inRootDir()) - return -1; - else if (LHS->inRootDir() && !RHS->inRootDir()) - return 1; - else { - ConsumeRootDir(LHS); - ConsumeRootDir(RHS); - return 0; - } -} - -static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) { - auto &LHS = *LHSPtr; - auto &RHS = *RHSPtr; - - int res; - while (LHS && RHS) { - if ((res = (*LHS).compare(*RHS)) != 0) - return res; - ++LHS; - ++RHS; - } - return 0; -} - -static int CompareEndState(PathParser *LHS, PathParser *RHS) { - if (LHS->atEnd() && !RHS->atEnd()) - return -1; - else if (!LHS->atEnd() && RHS->atEnd()) - return 1; - return 0; -} - -int path::__compare(string_view_t __s) const { - auto LHS = PathParser::CreateBegin(__pn_); - auto RHS = PathParser::CreateBegin(__s); - int res; - - if ((res = CompareRootName(&LHS, &RHS)) != 0) - return res; - - if ((res = CompareRootDir(&LHS, &RHS)) != 0) - return res; - - if ((res = CompareRelative(&LHS, &RHS)) != 0) - return res; - - return CompareEndState(&LHS, &RHS); -} - -//////////////////////////////////////////////////////////////////////////// -// path.nonmembers -size_t hash_value(const path& __p) noexcept { - auto PP = PathParser::CreateBegin(__p.native()); - size_t hash_value = 0; - hash hasher; - while (PP) { - hash_value = __hash_combine(hash_value, hasher(*PP)); - ++PP; - } - return hash_value; -} - -//////////////////////////////////////////////////////////////////////////// -// path.itr -path::iterator path::begin() const { - auto PP = PathParser::CreateBegin(__pn_); - iterator it; - it.__path_ptr_ = this; - it.__state_ = static_cast(PP.State); - it.__entry_ = PP.RawEntry; - it.__stashed_elem_.__assign_view(*PP); - return it; -} - -path::iterator path::end() const { - iterator it{}; - it.__state_ = path::iterator::_AtEnd; - it.__path_ptr_ = this; - return it; -} - -path::iterator& path::iterator::__increment() { - PathParser PP(__path_ptr_->native(), __entry_, __state_); - ++PP; - __state_ = static_cast<_ParserState>(PP.State); - __entry_ = PP.RawEntry; - __stashed_elem_.__assign_view(*PP); - return *this; -} - -path::iterator& path::iterator::__decrement() { - PathParser PP(__path_ptr_->native(), __entry_, __state_); - --PP; - __state_ = static_cast<_ParserState>(PP.State); - __entry_ = PP.RawEntry; - __stashed_elem_.__assign_view(*PP); - return *this; -} - -#if defined(_LIBCPP_WIN32API) -//////////////////////////////////////////////////////////////////////////// -// Windows path conversions -size_t __wide_to_char(const wstring &str, char *out, size_t outlen) { - if (str.empty()) - return 0; - ErrorHandler err("__wide_to_char", nullptr); - UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - BOOL used_default = FALSE; - int ret = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, - outlen, nullptr, &used_default); - if (ret <= 0 || used_default) - return err.report(errc::illegal_byte_sequence); - return ret; -} - -size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) { - if (str.empty()) - return 0; - ErrorHandler err("__char_to_wide", nullptr); - UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - int ret = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), - str.size(), out, outlen); - if (ret <= 0) - return err.report(errc::illegal_byte_sequence); - return ret; -} -#endif - - -/////////////////////////////////////////////////////////////////////////////// -// directory entry definitions -/////////////////////////////////////////////////////////////////////////////// - -error_code directory_entry::__do_refresh() noexcept { - __data_.__reset(); - error_code failure_ec; - - StatT full_st; - file_status st = detail::posix_lstat(__p_, full_st, &failure_ec); - if (!status_known(st)) { - __data_.__reset(); - return failure_ec; - } - - if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) { - __data_.__cache_type_ = directory_entry::_RefreshNonSymlink; - __data_.__type_ = st.type(); - __data_.__non_sym_perms_ = st.permissions(); - } else { // we have a symlink - __data_.__sym_perms_ = st.permissions(); - // Get the information about the linked entity. - // Ignore errors from stat, since we don't want errors regarding symlink - // resolution to be reported to the user. - error_code ignored_ec; - st = detail::posix_stat(__p_, full_st, &ignored_ec); - - __data_.__type_ = st.type(); - __data_.__non_sym_perms_ = st.permissions(); - - // If we failed to resolve the link, then only partially populate the - // cache. - if (!status_known(st)) { - __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved; - return error_code{}; - } - // Otherwise, we resolved the link, potentially as not existing. - // That's OK. - __data_.__cache_type_ = directory_entry::_RefreshSymlink; - } - - if (_VSTD_FS::is_regular_file(st)) - __data_.__size_ = static_cast(full_st.st_size); - - if (_VSTD_FS::exists(st)) { - __data_.__nlink_ = static_cast(full_st.st_nlink); - - // Attempt to extract the mtime, and fail if it's not representable using - // file_time_type. For now we ignore the error, as we'll report it when - // the value is actually used. - error_code ignored_ec; - __data_.__write_time_ = - __extract_last_write_time(__p_, full_st, &ignored_ec); - } - - return failure_ec; -} - _LIBCPP_END_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/path.cpp b/libcxx/src/filesystem/path.cpp new file mode 100644 index 0000000000000..82f1ba7ba69da --- /dev/null +++ b/libcxx/src/filesystem/path.cpp @@ -0,0 +1,460 @@ +//===----------------------------------------------------------------------===// +// +// 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 <__config> +#include +#include + +#include "error.h" +#include "path_parser.h" + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +using detail::ErrorHandler; +using parser::createView; +using parser::PathParser; +using parser::string_view_t; + +/////////////////////////////////////////////////////////////////////////////// +// path definitions +/////////////////////////////////////////////////////////////////////////////// + +constexpr path::value_type path::preferred_separator; + +path& path::replace_extension(path const& replacement) { + path p = extension(); + if (not p.empty()) { + __pn_.erase(__pn_.size() - p.native().size()); + } + if (!replacement.empty()) { + if (replacement.native()[0] != '.') { + __pn_ += PATHSTR("."); + } + __pn_.append(replacement.__pn_); + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// +// path.decompose + +string_view_t path::__root_name() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + return *PP; + return {}; +} + +string_view_t path::__root_directory() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) + ++PP; + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; +} + +string_view_t path::__root_path_raw() const { + auto PP = PathParser::CreateBegin(__pn_); + if (PP.State == PathParser::PS_InRootName) { + auto NextCh = PP.peek(); + if (NextCh && isSeparator(*NextCh)) { + ++PP; + return createView(__pn_.data(), &PP.RawEntry.back()); + } + return PP.RawEntry; + } + if (PP.State == PathParser::PS_InRootDir) + return *PP; + return {}; +} + +static bool ConsumeRootName(PathParser *PP) { + static_assert(PathParser::PS_BeforeBegin == 1 && + PathParser::PS_InRootName == 2, + "Values for enums are incorrect"); + while (PP->State <= PathParser::PS_InRootName) + ++(*PP); + return PP->State == PathParser::PS_AtEnd; +} + +static bool ConsumeRootDir(PathParser* PP) { + static_assert(PathParser::PS_BeforeBegin == 1 && + PathParser::PS_InRootName == 2 && + PathParser::PS_InRootDir == 3, "Values for enums are incorrect"); + while (PP->State <= PathParser::PS_InRootDir) + ++(*PP); + return PP->State == PathParser::PS_AtEnd; +} + +string_view_t path::__relative_path() const { + auto PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return {}; + return createView(PP.RawEntry.data(), &__pn_.back()); +} + +string_view_t path::__parent_path() const { + if (empty()) + return {}; + // Determine if we have a root path but not a relative path. In that case + // return *this. + { + auto PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return __pn_; + } + // Otherwise remove a single element from the end of the path, and return + // a string representing that path + { + auto PP = PathParser::CreateEnd(__pn_); + --PP; + if (PP.RawEntry.data() == __pn_.data()) + return {}; + --PP; + return createView(__pn_.data(), &PP.RawEntry.back()); + } +} + +string_view_t path::__filename() const { + if (empty()) + return {}; + { + PathParser PP = PathParser::CreateBegin(__pn_); + if (ConsumeRootDir(&PP)) + return {}; + } + return *(--PathParser::CreateEnd(__pn_)); +} + +string_view_t path::__stem() const { + return parser::separate_filename(__filename()).first; +} + +string_view_t path::__extension() const { + return parser::separate_filename(__filename()).second; +} + +//////////////////////////////////////////////////////////////////////////// +// path.gen + +enum PathPartKind : unsigned char { + PK_None, + PK_RootSep, + PK_Filename, + PK_Dot, + PK_DotDot, + PK_TrailingSep +}; + +static PathPartKind ClassifyPathPart(string_view_t Part) { + if (Part.empty()) + return PK_TrailingSep; + if (Part == PATHSTR(".")) + return PK_Dot; + if (Part == PATHSTR("..")) + return PK_DotDot; + if (Part == PATHSTR("/")) + return PK_RootSep; +#if defined(_LIBCPP_WIN32API) + if (Part == PATHSTR("\\")) + return PK_RootSep; +#endif + return PK_Filename; +} + +path path::lexically_normal() const { + if (__pn_.empty()) + return *this; + + using PartKindPair = pair; + vector Parts; + // Guess as to how many elements the path has to avoid reallocating. + Parts.reserve(32); + + // Track the total size of the parts as we collect them. This allows the + // resulting path to reserve the correct amount of memory. + size_t NewPathSize = 0; + auto AddPart = [&](PathPartKind K, string_view_t P) { + NewPathSize += P.size(); + Parts.emplace_back(P, K); + }; + auto LastPartKind = [&]() { + if (Parts.empty()) + return PK_None; + return Parts.back().second; + }; + + bool MaybeNeedTrailingSep = false; + // Build a stack containing the remaining elements of the path, popping off + // elements which occur before a '..' entry. + for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) { + auto Part = *PP; + PathPartKind Kind = ClassifyPathPart(Part); + switch (Kind) { + case PK_Filename: + case PK_RootSep: { + // Add all non-dot and non-dot-dot elements to the stack of elements. + AddPart(Kind, Part); + MaybeNeedTrailingSep = false; + break; + } + case PK_DotDot: { + // Only push a ".." element if there are no elements preceding the "..", + // or if the preceding element is itself "..". + auto LastKind = LastPartKind(); + if (LastKind == PK_Filename) { + NewPathSize -= Parts.back().first.size(); + Parts.pop_back(); + } else if (LastKind != PK_RootSep) + AddPart(PK_DotDot, PATHSTR("..")); + MaybeNeedTrailingSep = LastKind == PK_Filename; + break; + } + case PK_Dot: + case PK_TrailingSep: { + MaybeNeedTrailingSep = true; + break; + } + case PK_None: + __libcpp_unreachable(); + } + } + // [fs.path.generic]p6.8: If the path is empty, add a dot. + if (Parts.empty()) + return PATHSTR("."); + + // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any + // trailing directory-separator. + bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename; + + path Result; + Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep); + for (auto& PK : Parts) + Result /= PK.first; + + if (NeedTrailingSep) + Result /= PATHSTR(""); + + Result.make_preferred(); + return Result; +} + +static int DetermineLexicalElementCount(PathParser PP) { + int Count = 0; + for (; PP; ++PP) { + auto Elem = *PP; + if (Elem == PATHSTR("..")) + --Count; + else if (Elem != PATHSTR(".") && Elem != PATHSTR("")) + ++Count; + } + return Count; +} + +path path::lexically_relative(const path& base) const { + { // perform root-name/root-directory mismatch checks + auto PP = PathParser::CreateBegin(__pn_); + auto PPBase = PathParser::CreateBegin(base.__pn_); + auto CheckIterMismatchAtBase = [&]() { + return PP.State != PPBase.State && + (PP.inRootPath() || PPBase.inRootPath()); + }; + if (PP.inRootName() && PPBase.inRootName()) { + if (*PP != *PPBase) + return {}; + } else if (CheckIterMismatchAtBase()) + return {}; + + if (PP.inRootPath()) + ++PP; + if (PPBase.inRootPath()) + ++PPBase; + if (CheckIterMismatchAtBase()) + return {}; + } + + // Find the first mismatching element + auto PP = PathParser::CreateBegin(__pn_); + auto PPBase = PathParser::CreateBegin(base.__pn_); + while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) { + ++PP; + ++PPBase; + } + + // If there is no mismatch, return ".". + if (!PP && !PPBase) + return "."; + + // Otherwise, determine the number of elements, 'n', which are not dot or + // dot-dot minus the number of dot-dot elements. + int ElemCount = DetermineLexicalElementCount(PPBase); + if (ElemCount < 0) + return {}; + + // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise + if (ElemCount == 0 && (PP.atEnd() || *PP == PATHSTR(""))) + return PATHSTR("."); + + // return a path constructed with 'n' dot-dot elements, followed by the + // elements of '*this' after the mismatch. + path Result; + // FIXME: Reserve enough room in Result that it won't have to re-allocate. + while (ElemCount--) + Result /= PATHSTR(".."); + for (; PP; ++PP) + Result /= *PP; + return Result; +} + +//////////////////////////////////////////////////////////////////////////// +// path.comparisons +static int CompareRootName(PathParser *LHS, PathParser *RHS) { + if (!LHS->inRootName() && !RHS->inRootName()) + return 0; + + auto GetRootName = [](PathParser *Parser) -> string_view_t { + return Parser->inRootName() ? **Parser : PATHSTR(""); + }; + int res = GetRootName(LHS).compare(GetRootName(RHS)); + ConsumeRootName(LHS); + ConsumeRootName(RHS); + return res; +} + +static int CompareRootDir(PathParser *LHS, PathParser *RHS) { + if (!LHS->inRootDir() && RHS->inRootDir()) + return -1; + else if (LHS->inRootDir() && !RHS->inRootDir()) + return 1; + else { + ConsumeRootDir(LHS); + ConsumeRootDir(RHS); + return 0; + } +} + +static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) { + auto &LHS = *LHSPtr; + auto &RHS = *RHSPtr; + + int res; + while (LHS && RHS) { + if ((res = (*LHS).compare(*RHS)) != 0) + return res; + ++LHS; + ++RHS; + } + return 0; +} + +static int CompareEndState(PathParser *LHS, PathParser *RHS) { + if (LHS->atEnd() && !RHS->atEnd()) + return -1; + else if (!LHS->atEnd() && RHS->atEnd()) + return 1; + return 0; +} + +int path::__compare(string_view_t __s) const { + auto LHS = PathParser::CreateBegin(__pn_); + auto RHS = PathParser::CreateBegin(__s); + int res; + + if ((res = CompareRootName(&LHS, &RHS)) != 0) + return res; + + if ((res = CompareRootDir(&LHS, &RHS)) != 0) + return res; + + if ((res = CompareRelative(&LHS, &RHS)) != 0) + return res; + + return CompareEndState(&LHS, &RHS); +} + +//////////////////////////////////////////////////////////////////////////// +// path.nonmembers +size_t hash_value(const path& __p) noexcept { + auto PP = PathParser::CreateBegin(__p.native()); + size_t hash_value = 0; + hash hasher; + while (PP) { + hash_value = __hash_combine(hash_value, hasher(*PP)); + ++PP; + } + return hash_value; +} + +//////////////////////////////////////////////////////////////////////////// +// path.itr +path::iterator path::begin() const { + auto PP = PathParser::CreateBegin(__pn_); + iterator it; + it.__path_ptr_ = this; + it.__state_ = static_cast(PP.State); + it.__entry_ = PP.RawEntry; + it.__stashed_elem_.__assign_view(*PP); + return it; +} + +path::iterator path::end() const { + iterator it{}; + it.__state_ = path::iterator::_AtEnd; + it.__path_ptr_ = this; + return it; +} + +path::iterator& path::iterator::__increment() { + PathParser PP(__path_ptr_->native(), __entry_, __state_); + ++PP; + __state_ = static_cast<_ParserState>(PP.State); + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); + return *this; +} + +path::iterator& path::iterator::__decrement() { + PathParser PP(__path_ptr_->native(), __entry_, __state_); + --PP; + __state_ = static_cast<_ParserState>(PP.State); + __entry_ = PP.RawEntry; + __stashed_elem_.__assign_view(*PP); + return *this; +} + +#if defined(_LIBCPP_WIN32API) +//////////////////////////////////////////////////////////////////////////// +// Windows path conversions +size_t __wide_to_char(const wstring &str, char *out, size_t outlen) { + if (str.empty()) + return 0; + ErrorHandler err("__wide_to_char", nullptr); + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + BOOL used_default = FALSE; + int ret = WideCharToMultiByte(codepage, 0, str.data(), str.size(), out, + outlen, nullptr, &used_default); + if (ret <= 0 || used_default) + return err.report(errc::illegal_byte_sequence); + return ret; +} + +size_t __char_to_wide(const string &str, wchar_t *out, size_t outlen) { + if (str.empty()) + return 0; + ErrorHandler err("__char_to_wide", nullptr); + UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; + int ret = MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, str.data(), + str.size(), out, outlen); + if (ret <= 0) + return err.report(errc::illegal_byte_sequence); + return ret; +} +#endif + +_LIBCPP_END_NAMESPACE_FILESYSTEM diff --git a/libcxx/src/filesystem/path_parser.h b/libcxx/src/filesystem/path_parser.h new file mode 100644 index 0000000000000..4cc75a50b9640 --- /dev/null +++ b/libcxx/src/filesystem/path_parser.h @@ -0,0 +1,379 @@ +//===----------------------------------------------------------------------===// +// +// 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 PATH_PARSER_H +#define PATH_PARSER_H + +#include <__config> +#include <__utility/unreachable.h> +#include +#include +#include + +#include "format_string.h" + +// TODO: Check whether these functions actually need internal linkage, or if they can be made normal header functions +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") + +_LIBCPP_BEGIN_NAMESPACE_FILESYSTEM + +namespace { + +bool isSeparator(path::value_type C) { + if (C == '/') + return true; +#if defined(_LIBCPP_WIN32API) + if (C == '\\') + return true; +#endif + return false; +} + +bool isDriveLetter(path::value_type C) { + return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z'); +} + +namespace parser { + +using string_view_t = path::__string_view; +using string_view_pair = pair; +using PosPtr = path::value_type const*; + +struct PathParser { + enum ParserState : unsigned char { + // Zero is a special sentinel value used by default constructed iterators. + PS_BeforeBegin = path::iterator::_BeforeBegin, + PS_InRootName = path::iterator::_InRootName, + PS_InRootDir = path::iterator::_InRootDir, + PS_InFilenames = path::iterator::_InFilenames, + PS_InTrailingSep = path::iterator::_InTrailingSep, + PS_AtEnd = path::iterator::_AtEnd + }; + + const string_view_t Path; + string_view_t RawEntry; + ParserState State; + +private: + PathParser(string_view_t P, ParserState State) noexcept : Path(P), + State(State) {} + +public: + PathParser(string_view_t P, string_view_t E, unsigned char S) + : Path(P), RawEntry(E), State(static_cast(S)) { + // S cannot be '0' or PS_BeforeBegin. + } + + static PathParser CreateBegin(string_view_t P) noexcept { + PathParser PP(P, PS_BeforeBegin); + PP.increment(); + return PP; + } + + static PathParser CreateEnd(string_view_t P) noexcept { + PathParser PP(P, PS_AtEnd); + return PP; + } + + PosPtr peek() const noexcept { + auto TkEnd = getNextTokenStartPos(); + auto End = getAfterBack(); + return TkEnd == End ? nullptr : TkEnd; + } + + void increment() noexcept { + const PosPtr End = getAfterBack(); + const PosPtr Start = getNextTokenStartPos(); + if (Start == End) + return makeState(PS_AtEnd); + + switch (State) { + case PS_BeforeBegin: { + PosPtr TkEnd = consumeRootName(Start, End); + if (TkEnd) + return makeState(PS_InRootName, Start, TkEnd); + } + _LIBCPP_FALLTHROUGH(); + case PS_InRootName: { + PosPtr TkEnd = consumeAllSeparators(Start, End); + if (TkEnd) + return makeState(PS_InRootDir, Start, TkEnd); + else + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + } + case PS_InRootDir: + return makeState(PS_InFilenames, Start, consumeName(Start, End)); + + case PS_InFilenames: { + PosPtr SepEnd = consumeAllSeparators(Start, End); + if (SepEnd != End) { + PosPtr TkEnd = consumeName(SepEnd, End); + if (TkEnd) + return makeState(PS_InFilenames, SepEnd, TkEnd); + } + return makeState(PS_InTrailingSep, Start, SepEnd); + } + + case PS_InTrailingSep: + return makeState(PS_AtEnd); + + case PS_AtEnd: + __libcpp_unreachable(); + } + } + + void decrement() noexcept { + const PosPtr REnd = getBeforeFront(); + const PosPtr RStart = getCurrentTokenStartPos() - 1; + if (RStart == REnd) // we're decrementing the begin + return makeState(PS_BeforeBegin); + + switch (State) { + case PS_AtEnd: { + // Try to consume a trailing separator or root directory first. + if (PosPtr SepEnd = consumeAllSeparators(RStart, REnd)) { + if (SepEnd == REnd) + return makeState(PS_InRootDir, Path.data(), RStart + 1); + PosPtr TkStart = consumeRootName(SepEnd, REnd); + if (TkStart == REnd) + return makeState(PS_InRootDir, RStart, RStart + 1); + return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1); + } else { + PosPtr TkStart = consumeRootName(RStart, REnd); + if (TkStart == REnd) + return makeState(PS_InRootName, TkStart + 1, RStart + 1); + TkStart = consumeName(RStart, REnd); + return makeState(PS_InFilenames, TkStart + 1, RStart + 1); + } + } + case PS_InTrailingSep: + return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1, + RStart + 1); + case PS_InFilenames: { + PosPtr SepEnd = consumeAllSeparators(RStart, REnd); + if (SepEnd == REnd) + return makeState(PS_InRootDir, Path.data(), RStart + 1); + PosPtr TkStart = consumeRootName(SepEnd ? SepEnd : RStart, REnd); + if (TkStart == REnd) { + if (SepEnd) + return makeState(PS_InRootDir, SepEnd + 1, RStart + 1); + return makeState(PS_InRootName, TkStart + 1, RStart + 1); + } + TkStart = consumeName(SepEnd, REnd); + return makeState(PS_InFilenames, TkStart + 1, SepEnd + 1); + } + case PS_InRootDir: + return makeState(PS_InRootName, Path.data(), RStart + 1); + case PS_InRootName: + case PS_BeforeBegin: + __libcpp_unreachable(); + } + } + + /// \brief Return a view with the "preferred representation" of the current + /// element. For example trailing separators are represented as a '.' + string_view_t operator*() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_AtEnd: + return PATHSTR(""); + case PS_InRootDir: + if (RawEntry[0] == '\\') + return PATHSTR("\\"); + else + return PATHSTR("/"); + case PS_InTrailingSep: + return PATHSTR(""); + case PS_InRootName: + case PS_InFilenames: + return RawEntry; + } + __libcpp_unreachable(); + } + + explicit operator bool() const noexcept { + return State != PS_BeforeBegin && State != PS_AtEnd; + } + + PathParser& operator++() noexcept { + increment(); + return *this; + } + + PathParser& operator--() noexcept { + decrement(); + return *this; + } + + bool atEnd() const noexcept { + return State == PS_AtEnd; + } + + bool inRootDir() const noexcept { + return State == PS_InRootDir; + } + + bool inRootName() const noexcept { + return State == PS_InRootName; + } + + bool inRootPath() const noexcept { + return inRootName() || inRootDir(); + } + +private: + void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept { + State = NewState; + RawEntry = string_view_t(Start, End - Start); + } + void makeState(ParserState NewState) noexcept { + State = NewState; + RawEntry = {}; + } + + PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); } + + PosPtr getBeforeFront() const noexcept { return Path.data() - 1; } + + /// \brief Return a pointer to the first character after the currently + /// lexed element. + PosPtr getNextTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + return Path.data(); + case PS_InRootName: + case PS_InRootDir: + case PS_InFilenames: + return &RawEntry.back() + 1; + case PS_InTrailingSep: + case PS_AtEnd: + return getAfterBack(); + } + __libcpp_unreachable(); + } + + /// \brief Return a pointer to the first character in the currently lexed + /// element. + PosPtr getCurrentTokenStartPos() const noexcept { + switch (State) { + case PS_BeforeBegin: + case PS_InRootName: + return &Path.front(); + case PS_InRootDir: + case PS_InFilenames: + case PS_InTrailingSep: + return &RawEntry.front(); + case PS_AtEnd: + return &Path.back() + 1; + } + __libcpp_unreachable(); + } + + // Consume all consecutive separators. + PosPtr consumeAllSeparators(PosPtr P, PosPtr End) const noexcept { + if (P == nullptr || P == End || !isSeparator(*P)) + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && isSeparator(*P)) + P += Inc; + return P; + } + + // Consume exactly N separators, or return nullptr. + PosPtr consumeNSeparators(PosPtr P, PosPtr End, int N) const noexcept { + PosPtr Ret = consumeAllSeparators(P, End); + if (Ret == nullptr) + return nullptr; + if (P < End) { + if (Ret == P + N) + return Ret; + } else { + if (Ret == P - N) + return Ret; + } + return nullptr; + } + + PosPtr consumeName(PosPtr P, PosPtr End) const noexcept { + PosPtr Start = P; + if (P == nullptr || P == End || isSeparator(*P)) + return nullptr; + const int Inc = P < End ? 1 : -1; + P += Inc; + while (P != End && !isSeparator(*P)) + P += Inc; + if (P == End && Inc < 0) { + // Iterating backwards and consumed all the rest of the input. + // Check if the start of the string would have been considered + // a root name. + PosPtr RootEnd = consumeRootName(End + 1, Start); + if (RootEnd) + return RootEnd - 1; + } + return P; + } + + PosPtr consumeDriveLetter(PosPtr P, PosPtr End) const noexcept { + if (P == End) + return nullptr; + if (P < End) { + if (P + 1 == End || !isDriveLetter(P[0]) || P[1] != ':') + return nullptr; + return P + 2; + } else { + if (P - 1 == End || !isDriveLetter(P[-1]) || P[0] != ':') + return nullptr; + return P - 2; + } + } + + PosPtr consumeNetworkRoot(PosPtr P, PosPtr End) const noexcept { + if (P == End) + return nullptr; + if (P < End) + return consumeName(consumeNSeparators(P, End, 2), End); + else + return consumeNSeparators(consumeName(P, End), End, 2); + } + + PosPtr consumeRootName(PosPtr P, PosPtr End) const noexcept { +#if defined(_LIBCPP_WIN32API) + if (PosPtr Ret = consumeDriveLetter(P, End)) + return Ret; + if (PosPtr Ret = consumeNetworkRoot(P, End)) + return Ret; +#endif + return nullptr; + } +}; + +string_view_pair separate_filename(string_view_t const& s) { + if (s == PATHSTR(".") || s == PATHSTR("..") || s.empty()) + return string_view_pair{s, PATHSTR("")}; + auto pos = s.find_last_of('.'); + if (pos == string_view_t::npos || pos == 0) + return string_view_pair{s, string_view_t{}}; + return string_view_pair{s.substr(0, pos), s.substr(pos)}; +} + +string_view_t createView(PosPtr S, PosPtr E) noexcept { + return {S, static_cast(E - S) + 1}; +} + +} // namespace parser +} // namespace + +_LIBCPP_END_NAMESPACE_FILESYSTEM + +_LIBCPP_DIAGNOSTIC_POP + +#endif // PATH_PARSER_H diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h index 36116ec5a3952..bddead75960d8 100644 --- a/libcxx/src/filesystem/posix_compat.h +++ b/libcxx/src/filesystem/posix_compat.h @@ -24,9 +24,10 @@ #define POSIX_COMPAT_H #include <__assert> +#include <__config> #include -#include "filesystem_common.h" +#include "error.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN @@ -35,10 +36,12 @@ # include # include #else +# include # include # include # include #endif +#include #include #if defined(_LIBCPP_WIN32API) @@ -71,11 +74,52 @@ struct LIBCPP_REPARSE_DATA_BUFFER { }; #endif +// TODO: Check whether these functions actually need internal linkage, or if they can be made normal header functions +_LIBCPP_DIAGNOSTIC_PUSH +_LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") +_LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") + _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM namespace detail { namespace { +#if defined(_LIBCPP_WIN32API) +// Various C runtime versions (UCRT, or the legacy msvcrt.dll used by +// some mingw toolchains) provide different stat function implementations, +// with a number of limitations with respect to what we want from the +// stat function. Instead provide our own which does exactly what we want, +// along with our own stat structure and flag macros. + +struct TimeSpec { + int64_t tv_sec; + int64_t tv_nsec; +}; +struct StatT { + unsigned st_mode; + TimeSpec st_atim; + TimeSpec st_mtim; + uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber + struct FileIdStruct { + unsigned char id[16]; // FILE_ID_INFO::FileId + bool operator==(const FileIdStruct &other) const { + for (int i = 0; i < 16; i++) + if (id[i] != other.id[i]) + return false; + return true; + } + } st_ino; + uint32_t st_nlink; + uintmax_t st_size; +}; + +#else +using TimeSpec = struct timespec; +using TimeVal = struct timeval; +using StatT = struct stat; +#endif + #if defined(_LIBCPP_WIN32API) // Various C runtime header sets provide more or less of these. As we @@ -400,7 +444,7 @@ int fchmod_handle(HANDLE h, int perms) { return 0; } -int fchmodat(int fd, const wchar_t *path, int perms, int flag) { +int fchmodat(int /*fd*/, const wchar_t *path, int perms, int flag) { DWORD attributes = GetFileAttributesW(path); if (attributes == INVALID_FILE_ATTRIBUTES) return set_errno(); @@ -519,4 +563,6 @@ using SSizeT = ::ssize_t; _LIBCPP_END_NAMESPACE_FILESYSTEM +_LIBCPP_DIAGNOSTIC_POP + #endif // POSIX_COMPAT_H diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/time_utils.h similarity index 55% rename from libcxx/src/filesystem/filesystem_common.h rename to libcxx/src/filesystem/time_utils.h index a1756cf5ef83e..2e299b85a46f1 100644 --- a/libcxx/src/filesystem/filesystem_common.h +++ b/libcxx/src/filesystem/time_utils.h @@ -6,34 +6,30 @@ // //===----------------------------------------------------------------------===//// -#ifndef FILESYSTEM_COMMON_H -#define FILESYSTEM_COMMON_H +#ifndef FILESYSTEM_TIME_UTILS_H +#define FILESYSTEM_TIME_UTILS_H -#include <__assert> #include <__config> #include -#include #include -#include -#include -#include #include +#include #include -#include #include +#include +#include + +#include "error.h" +#include "format_string.h" +#include "posix_compat.h" #if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include #else -# include // for DIR & friends -# include /* values for fchmodat */ -# include -# include # include // for ::utimes as used in __last_write_time -# include -#endif // defined(_LIBCPP_WIN32API) +#endif // We can use the presence of UTIME_OMIT to detect platforms that provide utimensat. #if defined(UTIME_OMIT) @@ -46,240 +42,14 @@ _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wunused-function") _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-function") _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wunused-template") -#if defined(_LIBCPP_WIN32API) -# define PATHSTR(x) (L##x) -# define PATH_CSTR_FMT "\"%ls\"" -#else -# define PATHSTR(x) (x) -# define PATH_CSTR_FMT "\"%s\"" -#endif - _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM namespace detail { - -#if defined(_LIBCPP_WIN32API) -// Non anonymous, to allow access from two translation units. -errc __win_err_to_errc(int err); -#endif - namespace { -static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string -format_string_impl(const char* msg, va_list ap) { - array buf; - - va_list apcopy; - va_copy(apcopy, ap); - int ret = ::vsnprintf(buf.data(), buf.size(), msg, apcopy); - va_end(apcopy); - - string result; - if (static_cast(ret) < buf.size()) { - result.assign(buf.data(), static_cast(ret)); - } else { - // we did not provide a long enough buffer on our first attempt. The - // return value is the number of bytes (excluding the null byte) that are - // needed for formatting. - size_t size_with_null = static_cast(ret) + 1; - result.__resize_default_init(size_with_null - 1); - ret = ::vsnprintf(&result[0], size_with_null, msg, ap); - _LIBCPP_ASSERT(static_cast(ret) == (size_with_null - 1), "TODO"); - } - return result; -} - -static _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) string -format_string(const char* msg, ...) { - string ret; - va_list ap; - va_start(ap, msg); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - ret = format_string_impl(msg, ap); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - va_end(ap); - return ret; -} - -error_code capture_errno() { - _LIBCPP_ASSERT(errno != 0, "Expected errno to be non-zero"); - return error_code(errno, generic_category()); -} - -#if defined(_LIBCPP_WIN32API) -error_code make_windows_error(int err) { - return make_error_code(__win_err_to_errc(err)); -} -#endif - -template -T error_value(); -template <> -_LIBCPP_CONSTEXPR_SINCE_CXX14 void error_value() {} -template <> -bool error_value() { - return false; -} -#if __SIZEOF_SIZE_T__ != __SIZEOF_LONG_LONG__ -template <> -size_t error_value() { - return size_t(-1); -} -#endif -template <> -uintmax_t error_value() { - return uintmax_t(-1); -} -template <> -_LIBCPP_CONSTEXPR_SINCE_CXX14 file_time_type error_value() { - return file_time_type::min(); -} -template <> -path error_value() { - return {}; -} - -template -struct ErrorHandler { - const char* func_name_; - error_code* ec_ = nullptr; - const path* p1_ = nullptr; - const path* p2_ = nullptr; - - ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr, - const path* p2 = nullptr) - : func_name_(fname), ec_(ec), p1_(p1), p2_(p2) { - if (ec_) - ec_->clear(); - } - - T report(const error_code& ec) const { - if (ec_) { - *ec_ = ec; - return error_value(); - } - string what = string("in ") + func_name_; - switch (bool(p1_) + bool(p2_)) { - case 0: - __throw_filesystem_error(what, ec); - case 1: - __throw_filesystem_error(what, *p1_, ec); - case 2: - __throw_filesystem_error(what, *p1_, *p2_, ec); - } - __libcpp_unreachable(); - } - - _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 0) - void report_impl(const error_code& ec, const char* msg, va_list ap) const { - if (ec_) { - *ec_ = ec; - return; - } - string what = - string("in ") + func_name_ + ": " + format_string_impl(msg, ap); - switch (bool(p1_) + bool(p2_)) { - case 0: - __throw_filesystem_error(what, ec); - case 1: - __throw_filesystem_error(what, *p1_, ec); - case 2: - __throw_filesystem_error(what, *p1_, *p2_, ec); - } - __libcpp_unreachable(); - } - - _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) - T report(const error_code& ec, const char* msg, ...) const { - va_list ap; - va_start(ap, msg); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - report_impl(ec, msg, ap); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - va_end(ap); - return error_value(); - } - - T report(errc const& err) const { - return report(make_error_code(err)); - } - - _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) - T report(errc const& err, const char* msg, ...) const { - va_list ap; - va_start(ap, msg); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - try { -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - report_impl(make_error_code(err), msg, ap); -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - } catch (...) { - va_end(ap); - throw; - } -#endif // _LIBCPP_HAS_NO_EXCEPTIONS - va_end(ap); - return error_value(); - } - -private: - ErrorHandler(ErrorHandler const&) = delete; - ErrorHandler& operator=(ErrorHandler const&) = delete; -}; - using chrono::duration; using chrono::duration_cast; -#if defined(_LIBCPP_WIN32API) -// Various C runtime versions (UCRT, or the legacy msvcrt.dll used by -// some mingw toolchains) provide different stat function implementations, -// with a number of limitations with respect to what we want from the -// stat function. Instead provide our own (in the anonymous detail namespace -// in posix_compat.h) which does exactly what we want, along with our own -// stat structure and flag macros. - -struct TimeSpec { - int64_t tv_sec; - int64_t tv_nsec; -}; -struct StatT { - unsigned st_mode; - TimeSpec st_atim; - TimeSpec st_mtim; - uint64_t st_dev; // FILE_ID_INFO::VolumeSerialNumber - struct FileIdStruct { - unsigned char id[16]; // FILE_ID_INFO::FileId - bool operator==(const FileIdStruct &other) const { - for (int i = 0; i < 16; i++) - if (id[i] != other.id[i]) - return false; - return true; - } - } st_ino; - uint32_t st_nlink; - uintmax_t st_size; -}; - -#else -using TimeSpec = struct timespec; -using TimeVal = struct timeval; -using StatT = struct stat; -#endif - template ::value> struct time_util_base { @@ -307,7 +77,7 @@ struct time_util_base { .count(); private: - static _LIBCPP_CONSTEXPR_SINCE_CXX14 fs_duration get_min_nsecs() { + static _LIBCPP_CONSTEXPR fs_duration get_min_nsecs() { return duration_cast( fs_nanoseconds(min_nsec_timespec) - duration_cast(fs_seconds(1))); @@ -327,7 +97,9 @@ struct time_util_base { return max_seconds >= numeric_limits::max() && min_seconds <= numeric_limits::min(); } +#if _LIBCPP_STD_VER >= 14 static_assert(check_range(), "the representable range is unacceptable small"); +#endif }; template @@ -531,75 +303,19 @@ bool set_file_times(const path& p, std::array const& TS, #endif } -#if defined(DT_BLK) -template -static file_type get_file_type(DirEntT* ent, int) { - switch (ent->d_type) { - case DT_BLK: - return file_type::block; - case DT_CHR: - return file_type::character; - case DT_DIR: - return file_type::directory; - case DT_FIFO: - return file_type::fifo; - case DT_LNK: - return file_type::symlink; - case DT_REG: - return file_type::regular; - case DT_SOCK: - return file_type::socket; - // Unlike in lstat, hitting "unknown" here simply means that the underlying - // filesystem doesn't support d_type. Report is as 'none' so we correctly - // set the cache to empty. - case DT_UNKNOWN: - break; - } - return file_type::none; -} -#endif // defined(DT_BLK) - -template -static file_type get_file_type(DirEntT*, long) { - return file_type::none; -} +#endif // !_LIBCPP_WIN32API -static pair posix_readdir(DIR* dir_stream, - error_code& ec) { - struct dirent* dir_entry_ptr = nullptr; - errno = 0; // zero errno in order to detect errors - ec.clear(); - if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) { - if (errno) - ec = capture_errno(); - return {}; - } else { - return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)}; - } -} +file_time_type __extract_last_write_time(const path& p, const StatT& st, + error_code* ec) { + using detail::fs_time; + ErrorHandler err("last_write_time", ec, &p); -#else // _LIBCPP_WIN32API + auto ts = detail::extract_mtime(st); + if (!fs_time::is_representable(ts)) + return err.report(errc::value_too_large); -static file_type get_file_type(const WIN32_FIND_DATAW& data) { - if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && - data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) - return file_type::symlink; - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return file_type::directory; - return file_type::regular; + return fs_time::convert_from_timespec(ts); } -static uintmax_t get_file_size(const WIN32_FIND_DATAW& data) { - return (static_cast(data.nFileSizeHigh) << 32) + data.nFileSizeLow; -} -static file_time_type get_write_time(const WIN32_FIND_DATAW& data) { - ULARGE_INTEGER tmp; - const FILETIME& time = data.ftLastWriteTime; - tmp.u.LowPart = time.dwLowDateTime; - tmp.u.HighPart = time.dwHighDateTime; - return file_time_type(file_time_type::duration(tmp.QuadPart)); -} - -#endif // !_LIBCPP_WIN32API } // namespace } // end namespace detail @@ -608,4 +324,4 @@ _LIBCPP_END_NAMESPACE_FILESYSTEM _LIBCPP_DIAGNOSTIC_POP -#endif // FILESYSTEM_COMMON_H +#endif // FILESYSTEM_TIME_UTILS_H diff --git a/libcxx/test/libcxx/input.output/filesystems/class.directory_entry/directory_entry.mods/last_write_time.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/class.directory_entry/directory_entry.mods/last_write_time.pass.cpp index 4c6ac405282ef..e581963d7a33b 100644 --- a/libcxx/test/libcxx/input.output/filesystems/class.directory_entry/directory_entry.mods/last_write_time.pass.cpp +++ b/libcxx/test/libcxx/input.output/filesystems/class.directory_entry/directory_entry.mods/last_write_time.pass.cpp @@ -7,10 +7,10 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03 -// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../../../src/filesystem +// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../../../src -// This test relies on calling functions from the libcxx internal header -// filesystem_common.h; the Windows implementation uses different +// This test relies on calling functions from the libcxx internal headers +// of ; the Windows implementation uses different // internals and doesn't provide the same set_file_times function as for // other platforms. // UNSUPPORTED: windows @@ -30,7 +30,7 @@ #include "test_macros.h" #include "filesystem_test_helper.h" -#include "filesystem_common.h" +#include "filesystem/time_utils.h" using namespace fs::detail; diff --git a/libcxx/test/libcxx/input.output/filesystems/convert_file_time.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/convert_file_time.pass.cpp index b86282ccbedb5..2d057cbf265a6 100644 --- a/libcxx/test/libcxx/input.output/filesystems/convert_file_time.pass.cpp +++ b/libcxx/test/libcxx/input.output/filesystems/convert_file_time.pass.cpp @@ -12,7 +12,7 @@ // typedef TrivialClock file_time_type; -// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../src/filesystem -Wno-macro-redefined +// ADDITIONAL_COMPILE_FLAGS: -I %S/../../../../src -Wno-macro-redefined #include #include @@ -22,7 +22,7 @@ #include #include -#include "filesystem_common.h" +#include "filesystem/time_utils.h" #ifndef __SIZEOF_INT128__ #define TEST_HAS_NO_INT128_T diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt index 2281cc22c0aba..dfe30a2c3f4c1 100644 --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -790,11 +790,18 @@ libcxx/src/condition_variable_destructor.cpp libcxx/src/debug.cpp libcxx/src/exception.cpp libcxx/src/experimental/memory_resource.cpp +libcxx/src/filesystem/directory_entry.cpp libcxx/src/filesystem/directory_iterator.cpp -libcxx/src/filesystem/filesystem_common.h +libcxx/src/filesystem/error.h +libcxx/src/filesystem/file_descriptor.h +libcxx/src/filesystem/filesystem_clock.cpp +libcxx/src/filesystem/filesystem_error.cpp libcxx/src/filesystem/int128_builtins.cpp libcxx/src/filesystem/operations.cpp +libcxx/src/filesystem/path.cpp +libcxx/src/filesystem/path_parser.h libcxx/src/filesystem/posix_compat.h +libcxx/src/filesystem/time_utils.h libcxx/src/functional.cpp libcxx/src/future.cpp libcxx/src/hash.cpp From c5a412dad5b89996cdd1661075c63dbf884f8e5c Mon Sep 17 00:00:00 2001 From: melonedo Date: Wed, 14 Jun 2023 21:42:57 +0800 Subject: [PATCH 020/130] [RISCV] Add support for XCVbitmanip extension in CV32E40P Implement XCVbitmanip intrinsics for CV32E40P according to the specification. This commit is part of a patch-set to upstream the 7 vendor specific extensions of CV32E40P. Contributors: @CharKeaney, @jeremybennett, @lewis-revill, @liaolucy, @simoncook, @xmj. Spec: https://github.com/openhwgroup/cv32e40p/blob/62bec66b36182215e18c9cf10f723567e23878e9/docs/source/instruction_set_extensions.rst Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D152915 --- llvm/docs/RISCVUsage.rst | 3 + .../RISCV/Disassembler/RISCVDisassembler.cpp | 3 + llvm/lib/Target/RISCV/RISCVFeatures.td | 8 + llvm/lib/Target/RISCV/RISCVInstrInfo.td | 1 + llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td | 68 +++++ .../test/MC/RISCV/corev/XCVbitmanip-invalid.s | 267 ++++++++++++++++++ llvm/test/MC/RISCV/corev/XCVbitmanip.s | 248 ++++++++++++++++ 7 files changed, 598 insertions(+) create mode 100644 llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td create mode 100644 llvm/test/MC/RISCV/corev/XCVbitmanip-invalid.s create mode 100644 llvm/test/MC/RISCV/corev/XCVbitmanip.s diff --git a/llvm/docs/RISCVUsage.rst b/llvm/docs/RISCVUsage.rst index 7ea7dba043605..017e5c2aba782 100644 --- a/llvm/docs/RISCVUsage.rst +++ b/llvm/docs/RISCVUsage.rst @@ -279,3 +279,6 @@ The current vendor extensions supported are: ``XSfvcp`` LLVM implements `version 1.0.0 of the SiFive Vector Coprocessor Interface (VCIX) Software Specification `_ by SiFive. All instructions are prefixed with `sf.vc.` as described in the specification, and the riscv-toolchain-convention document linked above. + +``XCVbitmanip`` + LLVM implements `version 1.3.1 of the Core-V bit manipulation custom instructions specification `_ by Core-V. All instructions are prefixed with `cv.` as described in the specification. diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp index e10fb7d4b039c..202bfb4792550 100644 --- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp +++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp @@ -558,6 +558,9 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size, "XTHeadVdot custom opcode table"); TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXSfvcp, DecoderTableXSfvcp32, "SiFive VCIX custom opcode table"); + TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXCVbitmanip, + DecoderTableXCVbitmanip32, + "CORE-V Bit Manipulation custom opcode table"); TRY_TO_DECODE(true, DecoderTable32, "RISCV32 table"); return MCDisassembler::Fail; diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td index 63ddc87f60742..8243b34fb23c8 100644 --- a/llvm/lib/Target/RISCV/RISCVFeatures.td +++ b/llvm/lib/Target/RISCV/RISCVFeatures.td @@ -752,6 +752,14 @@ def HasVendorXSfvcp : Predicate<"Subtarget->hasVendorXSfvcp()">, AssemblerPredicate<(all_of FeatureVendorXSfvcp), "'XSfvcp' (SiFive Custom Vector Coprocessor Interface Instructions)">; + +def FeatureVendorXCVbitmanip + : SubtargetFeature<"xcvbitmanip", "HasVendorXCVbitmanip", "true", + "'XCVbitmanip' (Bit Manipulation)">; +def HasVendorXCVbitmanip : Predicate<"Subtarget->hasVendorXCVbitmanip()">, + AssemblerPredicate<(all_of FeatureVendorXCVbitmanip), + "'XCVbitmanip' (Bit Manipulation)">; + //===----------------------------------------------------------------------===// // LLVM specific features and extensions //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index ed3b1d9cdb8fb..eb675d9581571 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1923,3 +1923,4 @@ include "RISCVInstrInfoZicond.td" include "RISCVInstrInfoXVentana.td" include "RISCVInstrInfoXTHead.td" include "RISCVInstrInfoXSf.td" +include "RISCVInstrInfoXCV.td" diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td new file mode 100644 index 0000000000000..3a69993ee96b0 --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXCV.td @@ -0,0 +1,68 @@ +//===-- RISCVInstrInfoXCV.td - CORE-V instructions ---------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file describes the vendor extensions defined by Core-V extensions. +// +//===----------------------------------------------------------------------===// + +let DecoderNamespace = "XCVbitmanip" in { + class RVInstBitManipRII funct2, bits<3> funct3, dag outs, dag ins, + string opcodestr, string argstr> + : RVInstI { + bits<5> is3; + bits<5> is2; + let imm12 = {funct2, is3, is2}; + } + + class CVBitManipRII funct2, bits<3> funct3, string opcodestr, + Operand i3type = uimm5> + : RVInstBitManipRII; + + class CVBitManipRR funct7, string opcodestr> + : RVInstR; + + class CVBitManipR funct7, string opcodestr> + : RVInstR { + let rs2 = 0b00000; + } +} + +let Predicates = [HasVendorXCVbitmanip, IsRV32], + hasSideEffects = 0, mayLoad = 0, mayStore = 0 in { + def CV_EXTRACT : CVBitManipRII<0b00, 0b000, "cv.extract">; + def CV_EXTRACTU : CVBitManipRII<0b01, 0b000, "cv.extractu">; + + def CV_BCLR : CVBitManipRII<0b00, 0b001, "cv.bclr">; + def CV_BSET : CVBitManipRII<0b01, 0b001, "cv.bset">; + def CV_BITREV : CVBitManipRII<0b11, 0b001, "cv.bitrev", uimm2>; + + def CV_EXTRACTR : CVBitManipRR<0b0011000, "cv.extractr">; + def CV_EXTRACTUR : CVBitManipRR<0b0011001, "cv.extractur">; + + let Constraints = "$rd = $rd_wb" in { + def CV_INSERT : RVInstBitManipRII<0b10, 0b000, (outs GPR:$rd_wb), + (ins GPR:$rd, GPR:$rs1, uimm5:$is3, uimm5:$is2), + "cv.insert", "$rd, $rs1, $is3, $is2">; + def CV_INSERTR : RVInstR<0b0011010, 0b011, OPC_CUSTOM_1, (outs GPR:$rd_wb), + (ins GPR:$rd, GPR:$rs1, GPR:$rs2), + "cv.insertr", "$rd, $rs1, $rs2">; + } + + def CV_BCLRR : CVBitManipRR<0b0011100, "cv.bclrr">; + def CV_BSETR : CVBitManipRR<0b0011101, "cv.bsetr">; + + def CV_ROR : CVBitManipRR<0b0100000, "cv.ror">; + def CV_FF1 : CVBitManipR<0b0100001, "cv.ff1">; + def CV_FL1 : CVBitManipR<0b0100010, "cv.fl1">; + def CV_CLB : CVBitManipR<0b0100011, "cv.clb">; + def CV_CNT : CVBitManipR<0b0100100, "cv.cnt">; +} diff --git a/llvm/test/MC/RISCV/corev/XCVbitmanip-invalid.s b/llvm/test/MC/RISCV/corev/XCVbitmanip-invalid.s new file mode 100644 index 0000000000000..684b3f220a994 --- /dev/null +++ b/llvm/test/MC/RISCV/corev/XCVbitmanip-invalid.s @@ -0,0 +1,267 @@ +# RUN: not llvm-mc -triple=riscv32 --mattr=+xcvbitmanip %s 2>&1 \ +# RUN: | FileCheck %s --check-prefixes=CHECK-ERROR + +cv.extract t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.extract t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.extract t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extract t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extract t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extract t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extract t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extract t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.extractu t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.extractu t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.extractu t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.insert t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.insert t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.insert t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.bclr t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.bclr t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bclr t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.bset t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.bset t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bset t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bitrev t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.bitrev t0, t1, 0 +# CHECK-ERROR: too few operands for instruction + +cv.bitrev t0, t1, t2 +# CHECK-ERROR: immediate must be an integer in the range [0, 3] + +cv.bitrev t0, t1, t2, t3 +# CHECK-ERROR: immediate must be an integer in the range [0, 3] + +cv.bitrev t0, t1, 0, 32 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bitrev t0, t1, 0, -1 +# CHECK-ERROR: immediate must be an integer in the range [0, 31] + +cv.bitrev t0, t1, 32, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 3] + +cv.bitrev t0, t1, -1, 0 +# CHECK-ERROR: immediate must be an integer in the range [0, 3] + +cv.extractr t0 +# CHECK-ERROR: too few operands for instruction + +cv.extractr t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.extractr t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.extractr t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.extractur t0 +# CHECK-ERROR: too few operands for instruction + +cv.extractur t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.extractur t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.extractur t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.insertr t0 +# CHECK-ERROR: too few operands for instruction + +cv.insertr t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.insertr t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.insertr t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.bclrr t0 +# CHECK-ERROR: too few operands for instruction + +cv.bclrr t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.bclrr t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.bclrr t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.bsetr t0 +# CHECK-ERROR: too few operands for instruction + +cv.bsetr t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.bsetr t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.bsetr t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.ror t0 +# CHECK-ERROR: too few operands for instruction + +cv.ror t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.ror t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.ror t0, t1 +# CHECK-ERROR: too few operands for instruction + +cv.ff1 t0 +# CHECK-ERROR: too few operands for instruction + +cv.ff1 t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.ff1 t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.ff1 t0, t1, t2 +# CHECK-ERROR: invalid operand for instruction + +cv.fl1 t0 +# CHECK-ERROR: too few operands for instruction + +cv.fl1 t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.fl1 t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.fl1 t0, t1, t2 +# CHECK-ERROR: invalid operand for instruction + +cv.clb t0 +# CHECK-ERROR: too few operands for instruction + +cv.clb t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.clb t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.clb t0, t1, t2 +# CHECK-ERROR: invalid operand for instruction + +cv.cnt t0 +# CHECK-ERROR: too few operands for instruction + +cv.cnt t0, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.cnt t0, t1, 0 +# CHECK-ERROR: invalid operand for instruction + +cv.cnt t0, t1, t2 +# CHECK-ERROR: invalid operand for instruction + diff --git a/llvm/test/MC/RISCV/corev/XCVbitmanip.s b/llvm/test/MC/RISCV/corev/XCVbitmanip.s new file mode 100644 index 0000000000000..dab8395c93f01 --- /dev/null +++ b/llvm/test/MC/RISCV/corev/XCVbitmanip.s @@ -0,0 +1,248 @@ +# RUN: llvm-mc -triple=riscv32 --mattr=+xcvbitmanip -show-encoding %s \ +# RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INSTR +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+xcvbitmanip < %s \ +# RUN: | llvm-objdump --mattr=+xcvbitmanip -M no-aliases -d -r - \ +# RUN: | FileCheck --check-prefix=CHECK-INSTR %s +# RUN: not llvm-mc -triple riscv32 %s 2>&1 \ +# RUN: | FileCheck -check-prefix=CHECK-NO-EXT %s + +cv.extract t0, t1, 0, 1 +# CHECK-INSTR: cv.extract t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x02,0x13,0x00] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extract a0, a1, 17, 18 +# CHECK-INSTR: cv.extract a0, a1, 17, 18 +# CHECK-ENCODING: [0x5b,0x85,0x25,0x23] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extract s0, s1, 30, 31 +# CHECK-INSTR: cv.extract s0, s1, 30, 31 +# CHECK-ENCODING: [0x5b,0x84,0xf4,0x3d] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractu t0, t1, 0, 1 +# CHECK-INSTR: cv.extractu t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x02,0x13,0x40] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractu a0, a1, 17, 18 +# CHECK-INSTR: cv.extractu a0, a1, 17, 18 +# CHECK-ENCODING: [0x5b,0x85,0x25,0x63] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractu s0, s1, 30, 31 +# CHECK-INSTR: cv.extractu s0, s1, 30, 31 +# CHECK-ENCODING: [0x5b,0x84,0xf4,0x7d] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insert t0, t1, 0, 1 +# CHECK-INSTR: cv.insert t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x02,0x13,0x80] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insert a0, a1, 17, 18 +# CHECK-INSTR: cv.insert a0, a1, 17, 18 +# CHECK-ENCODING: [0x5b,0x85,0x25,0xa3] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insert s0, s1, 30, 31 +# CHECK-INSTR: cv.insert s0, s1, 30, 31 +# CHECK-ENCODING: [0x5b,0x84,0xf4,0xbd] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclr t0, t1, 0, 1 +# CHECK-INSTR: cv.bclr t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x12,0x13,0x00] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclr a0, a1, 17, 18 +# CHECK-INSTR: cv.bclr a0, a1, 17, 18 +# CHECK-ENCODING: [0x5b,0x95,0x25,0x23] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclr s0, s1, 30, 31 +# CHECK-INSTR: cv.bclr s0, s1, 30, 31 +# CHECK-ENCODING: [0x5b,0x94,0xf4,0x3d] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bset t0, t1, 0, 1 +# CHECK-INSTR: cv.bset t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x12,0x13,0x40] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bset a0, a1, 17, 18 +# CHECK-INSTR: cv.bset a0, a1, 17, 18 +# CHECK-ENCODING: [0x5b,0x95,0x25,0x63] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bset s0, s1, 30, 31 +# CHECK-INSTR: cv.bset s0, s1, 30, 31 +# CHECK-ENCODING: [0x5b,0x94,0xf4,0x7d] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bitrev t0, t1, 0, 1 +# CHECK-INSTR: cv.bitrev t0, t1, 0, 1 +# CHECK-ENCODING: [0xdb,0x12,0x13,0xc0] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bitrev a0, a1, 1, 18 +# CHECK-INSTR: cv.bitrev a0, a1, 1, 18 +# CHECK-ENCODING: [0x5b,0x95,0x25,0xc3] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bitrev s0, s1, 2, 31 +# CHECK-INSTR: cv.bitrev s0, s1, 2, 31 +# CHECK-ENCODING: [0x5b,0x94,0xf4,0xc5] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractr t0, t1, t2 +# CHECK-INSTR: cv.extractr t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x30] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractr a0, a1, a2 +# CHECK-INSTR: cv.extractr a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x30] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractr s0, s1, s2 +# CHECK-INSTR: cv.extractr s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x31] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractur t0, t1, t2 +# CHECK-INSTR: cv.extractur t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x32] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractur a0, a1, a2 +# CHECK-INSTR: cv.extractur a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x32] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.extractur s0, s1, s2 +# CHECK-INSTR: cv.extractur s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x33] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insertr t0, t1, t2 +# CHECK-INSTR: cv.insertr t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x34] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insertr a0, a1, a2 +# CHECK-INSTR: cv.insertr a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x34] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.insertr s0, s1, s2 +# CHECK-INSTR: cv.insertr s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x35] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclrr t0, t1, t2 +# CHECK-INSTR: cv.bclrr t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x38] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclrr a0, a1, a2 +# CHECK-INSTR: cv.bclrr a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x38] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bclrr s0, s1, s2 +# CHECK-INSTR: cv.bclrr s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x39] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bsetr t0, t1, t2 +# CHECK-INSTR: cv.bsetr t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x3a] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bsetr a0, a1, a2 +# CHECK-INSTR: cv.bsetr a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x3a] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.bsetr s0, s1, s2 +# CHECK-INSTR: cv.bsetr s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x3b] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ror t0, t1, t2 +# CHECK-INSTR: cv.ror t0, t1, t2 +# CHECK-ENCODING: [0xab,0x32,0x73,0x40] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ror a0, a1, a2 +# CHECK-INSTR: cv.ror a0, a1, a2 +# CHECK-ENCODING: [0x2b,0xb5,0xc5,0x40] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ror s0, s1, s2 +# CHECK-INSTR: cv.ror s0, s1, s2 +# CHECK-ENCODING: [0x2b,0xb4,0x24,0x41] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ff1 t0, t1 +# CHECK-INSTR: cv.ff1 t0, t1 +# CHECK-ENCODING: [0xab,0x32,0x03,0x42] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ff1 a0, a1 +# CHECK-INSTR: cv.ff1 a0, a1 +# CHECK-ENCODING: [0x2b,0xb5,0x05,0x42] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.ff1 s0, s1 +# CHECK-INSTR: cv.ff1 s0, s1 +# CHECK-ENCODING: [0x2b,0xb4,0x04,0x42] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.fl1 t0, t1 +# CHECK-INSTR: cv.fl1 t0, t1 +# CHECK-ENCODING: [0xab,0x32,0x03,0x44] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.fl1 a0, a1 +# CHECK-INSTR: cv.fl1 a0, a1 +# CHECK-ENCODING: [0x2b,0xb5,0x05,0x44] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.fl1 s0, s1 +# CHECK-INSTR: cv.fl1 s0, s1 +# CHECK-ENCODING: [0x2b,0xb4,0x04,0x44] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.clb t0, t1 +# CHECK-INSTR: cv.clb t0, t1 +# CHECK-ENCODING: [0xab,0x32,0x03,0x46] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.clb a0, a1 +# CHECK-INSTR: cv.clb a0, a1 +# CHECK-ENCODING: [0x2b,0xb5,0x05,0x46] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.clb s0, s1 +# CHECK-INSTR: cv.clb s0, s1 +# CHECK-ENCODING: [0x2b,0xb4,0x04,0x46] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.cnt t0, t1 +# CHECK-INSTR: cv.cnt t0, t1 +# CHECK-ENCODING: [0xab,0x32,0x03,0x48] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.cnt a0, a1 +# CHECK-INSTR: cv.cnt a0, a1 +# CHECK-ENCODING: [0x2b,0xb5,0x05,0x48] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + +cv.cnt s0, s1 +# CHECK-INSTR: cv.cnt s0, s1 +# CHECK-ENCODING: [0x2b,0xb4,0x04,0x48] +# CHECK-NO-EXT: instruction requires the following: 'XCVbitmanip' (Bit Manipulation){{$}} + From 9d4c1be8b0793ee94e0906e4ff40d1ff325470de Mon Sep 17 00:00:00 2001 From: David Truby Date: Fri, 16 Jun 2023 12:45:54 +0100 Subject: [PATCH 021/130] [mlir] Add support for LLVMIR comdat operation The LLVM comdat operation specifies how to deduplicate globals with the same key in two different object files. This is necessary on Windows where e.g. two object files with linkonce globals will not link unless a comdat for those globals is specified. It is also supported in the ELF format. Differential Revision: https://reviews.llvm.org/D150796 --- .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td | 9 +++ mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td | 25 +++++++++ mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 51 +++++++++++++++++ .../include/mlir/Target/LLVMIR/ModuleImport.h | 10 ++++ .../mlir/Target/LLVMIR/ModuleTranslation.h | 1 + mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 55 ++++++++++++++++++- mlir/lib/Target/LLVMIR/ModuleImport.cpp | 46 ++++++++++++++++ mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 30 +++++++++- mlir/test/Dialect/LLVMIR/comdat.mlir | 16 ++++++ mlir/test/Dialect/LLVMIR/global.mlir | 8 +++ mlir/test/Dialect/LLVMIR/invalid.mlir | 13 +++++ mlir/test/Target/LLVMIR/Import/comdat.ll | 20 +++++++ mlir/test/Target/LLVMIR/llvmir-invalid.mlir | 11 ++++ mlir/test/Target/LLVMIR/llvmir.mlir | 30 ++++++++++ 14 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 mlir/test/Dialect/LLVMIR/comdat.mlir create mode 100644 mlir/test/Target/LLVMIR/Import/comdat.ll diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 05ee0832360dc..62eca517c828c 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -29,6 +29,15 @@ def CConvAttr : LLVM_Attr<"CConv", "cconv"> { let assemblyFormat = "`<` $CallingConv `>`"; } +//===----------------------------------------------------------------------===// +// ComdatAttr +//===----------------------------------------------------------------------===// + +def ComdatAttr : LLVM_Attr<"Comdat", "comdat"> { + let parameters = (ins "comdat::Comdat":$comdat); + let assemblyFormat = "$comdat"; +} + //===----------------------------------------------------------------------===// // LinkageAttr //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td index 8d8494924e2a9..9eb012a971efb 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td @@ -589,6 +589,31 @@ def Linkage : DialectAttr< "::mlir::LLVM::LinkageAttr::get($_builder.getContext(), $0)"; } + +//===----------------------------------------------------------------------===// +// Comdat +//===----------------------------------------------------------------------===// + +def ComdatAny + : LLVM_EnumAttrCase<"Any", "any", "Any", 0>; +def ComdatExactMatch + : LLVM_EnumAttrCase<"ExactMatch", "exactmatch", "ExactMatch", 1>; +def ComdatLargest + : LLVM_EnumAttrCase<"Largest", "largest", "Largest", 2>; +def ComdatNoDeduplicate + : LLVM_EnumAttrCase<"NoDeduplicate", "nodeduplicate", "NoDeduplicate", 3>; +def ComdatSameSize + : LLVM_EnumAttrCase<"SameSize", "samesize", "SameSize", 4>; + +def Comdat : LLVM_EnumAttr< + "Comdat", + "::llvm::Comdat::SelectionKind", + "LLVM Comdat Types", + [ComdatAny, ComdatExactMatch, ComdatLargest, + ComdatNoDeduplicate, ComdatSameSize]> { + let cppNamespace = "::mlir::LLVM::comdat"; +} + //===----------------------------------------------------------------------===// // UnnamedAddr //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 53418cfec0735..b4081091a579d 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1321,6 +1321,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global", DefaultValuedAttr, "0">:$addr_space, OptionalAttr:$unnamed_addr, OptionalAttr:$section, + OptionalAttr:$comdat, DefaultValuedAttr:$visibility_ ); let summary = "LLVM dialect global."; @@ -1429,6 +1430,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global", CArg<"unsigned", "0">:$addrSpace, CArg<"bool", "false">:$dsoLocal, CArg<"bool", "false">:$thread_local_, + CArg<"SymbolRefAttr", "{}">:$comdat, CArg<"ArrayRef", "{}">:$attrs)> ]; @@ -1520,6 +1522,55 @@ def LLVM_GlobalDtorsOp : LLVM_Op<"mlir.global_dtors", [ let hasVerifier = 1; } +def LLVM_ComdatSelectorOp : LLVM_Op<"comdat_selector", [Symbol]> { + let arguments = (ins + SymbolNameAttr:$sym_name, + Comdat:$comdat + ); + + let summary = "LLVM dialect comdat selector declaration"; + + let description = [{ + Provides access to object file COMDAT section/group functionality. + + Examples: + ```mlir + llvm.comdat @__llvm_comdat { + llvm.comdat_selector @any any + } + llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64 + ``` + }]; + let assemblyFormat = "$sym_name $comdat attr-dict"; +} + +def LLVM_ComdatOp : LLVM_Op<"comdat", [NoTerminator, NoRegionArguments, SymbolTable, Symbol]> { + let arguments = (ins + SymbolNameAttr:$sym_name + ); + let summary = "LLVM dialect comdat region"; + + let description = [{ + Provides access to object file COMDAT section/group functionality. + + Examples: + ```mlir + llvm.comdat @__llvm_comdat { + llvm.comdat_selector @any any + } + llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64 + ``` + }]; + let regions = (region SizedRegion<1>:$body); + + + let skipDefaultBuilders = 1; + let builders = [OpBuilder<(ins "StringRef":$symName)>]; + + let assemblyFormat = "$sym_name $body attr-dict"; + let hasRegionVerifier = 1; +} + def LLVM_LLVMFuncOp : LLVM_Op<"func", [ AutomaticAllocationScope, IsolatedFromAbove, FunctionOpInterface, CallableOpInterface diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h index ce622f7cabab3..b9d7463d34c63 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h @@ -56,6 +56,10 @@ class ModuleImport { /// Converts all functions of the LLVM module to MLIR functions. LogicalResult convertFunctions(); + /// Converts all comdat selectors of the LLVM module to MLIR comdat + /// operations. + LogicalResult convertComdats(); + /// Converts all global variables of the LLVM module to MLIR global variables. LogicalResult convertGlobals(); @@ -284,6 +288,10 @@ class ModuleImport { /// metadata that converts to MLIR operations. Creates the global metadata /// operation on the first invocation. MetadataOp getGlobalMetadataOp(); + /// Returns a global comdat operation that serves as a container for LLVM + /// comdat selectors. Creates the global comdat operation on the first + /// invocation. + ComdatOp getGlobalComdatOp(); /// Performs conversion of LLVM TBAA metadata starting from /// `node`. On exit from this function all nodes reachable /// from `node` are converted, and tbaaMapping map is updated @@ -312,6 +320,8 @@ class ModuleImport { Operation *globalInsertionOp = nullptr; /// Operation to insert metadata operations into. MetadataOp globalMetadataOp = nullptr; + /// Operation to insert comdat selector operations into. + ComdatOp globalComdatOp = nullptr; /// The current context. MLIRContext *context; /// The MLIR module being created. diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 949a0c705066f..960416d4913f7 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -274,6 +274,7 @@ class ModuleTranslation { LogicalResult convertOperation(Operation &op, llvm::IRBuilderBase &builder); LogicalResult convertFunctionSignatures(); LogicalResult convertFunctions(); + LogicalResult convertComdats(); LogicalResult convertGlobals(); LogicalResult convertOneFunction(LLVMFuncOp func); diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index c44c60a0bc176..a97632c222287 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1609,6 +1609,28 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) { return success(); } +//===----------------------------------------------------------------------===// +// Verifier for LLVM::ComdatOp. +//===----------------------------------------------------------------------===// + +void ComdatOp::build(OpBuilder &builder, OperationState &result, + StringRef symName) { + result.addAttribute(getSymNameAttrName(result.name), + builder.getStringAttr(symName)); + Region *body = result.addRegion(); + body->emplaceBlock(); +} + +LogicalResult ComdatOp::verifyRegions() { + Region &body = getBody(); + for (Operation &op : body.getOps()) + if (!isa(op)) + return op.emitError( + "only comdat selector symbols can appear in a comdat region"); + + return success(); +} + //===----------------------------------------------------------------------===// // Builder, printer and verifier for LLVM::GlobalOp. //===----------------------------------------------------------------------===// @@ -1616,7 +1638,7 @@ AddressOfOp::verifySymbolUses(SymbolTableCollection &symbolTable) { void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type, bool isConstant, Linkage linkage, StringRef name, Attribute value, uint64_t alignment, unsigned addrSpace, - bool dsoLocal, bool threadLocal, + bool dsoLocal, bool threadLocal, SymbolRefAttr comdat, ArrayRef attrs) { result.addAttribute(getSymNameAttrName(result.name), builder.getStringAttr(name)); @@ -1632,6 +1654,8 @@ void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type, if (threadLocal) result.addAttribute(getThreadLocal_AttrName(result.name), builder.getUnitAttr()); + if (comdat) + result.addAttribute(getComdatAttrName(result.name), comdat); // Only add an alignment attribute if the "alignment" input // is different from 0. The value must also be a power of two, but @@ -1668,6 +1692,9 @@ void GlobalOp::print(OpAsmPrinter &p) { if (auto value = getValueOrNull()) p.printAttribute(value); p << ')'; + if (auto comdat = getComdat()) + p << " comdat(" << *comdat << ')'; + // Note that the alignment attribute is printed using the // default syntax here, even though it is an inherent attribute // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes) @@ -1676,7 +1703,7 @@ void GlobalOp::print(OpAsmPrinter &p) { getGlobalTypeAttrName(), getConstantAttrName(), getValueAttrName(), getLinkageAttrName(), getUnnamedAddrAttrName(), getThreadLocal_AttrName(), - getVisibility_AttrName()}); + getVisibility_AttrName(), getComdatAttrName()}); // Print the trailing type unless it's a string global. if (llvm::dyn_cast_or_null(getValueOrNull())) @@ -1736,6 +1763,18 @@ static RetTy parseOptionalLLVMKeyword(OpAsmParser &parser, return static_cast(index); } +static LogicalResult verifyComdat(Operation *op, + std::optional attr) { + if (!attr) + return success(); + + auto *comdatSelector = SymbolTable::lookupNearestSymbolFrom(op, *attr); + if (!isa_and_nonnull(comdatSelector)) + return op->emitError() << "expected comdat symbol"; + + return success(); +} + // operation ::= `llvm.mlir.global` linkage? `constant`? `@` identifier // `(` attribute? `)` align? attribute-list? (`:` type)? region? // align ::= `align` `=` UINT64 @@ -1784,6 +1823,15 @@ ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) { return failure(); } + if (succeeded(parser.parseOptionalKeyword("comdat"))) { + SymbolRefAttr comdat; + if (parser.parseLParen() || parser.parseAttribute(comdat) || + parser.parseRParen()) + return failure(); + + result.addAttribute(getComdatAttrName(result.name), comdat); + } + SmallVector types; if (parser.parseOptionalAttrDict(result.attributes) || parser.parseOptionalColonTypeList(types)) @@ -1882,6 +1930,9 @@ LogicalResult GlobalOp::verify() { } } + if (failed(verifyComdat(*this, getComdat()))) + return failure(); + std::optional alignAttr = getAlignment(); if (alignAttr.has_value()) { uint64_t value = alignAttr.value(); diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 5f9eb1835cd2d..fbb20bed6e8ff 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringSet.h" +#include "llvm/IR/Comdat.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" @@ -81,6 +82,12 @@ static constexpr StringRef getGlobalMetadataOpName() { return "__llvm_global_metadata"; } +/// Returns the symbol name for the module-level comdat operation. It must not +/// conflict with the user namespace. +static constexpr StringRef getGlobalComdatOpName() { + return "__llvm_global_comdat"; +} + /// Converts the sync scope identifier of `inst` to the string representation /// necessary to build an atomic LLVM dialect operation. Returns the empty /// string if the operation has either no sync scope or the default system-level @@ -167,6 +174,16 @@ MetadataOp ModuleImport::getGlobalMetadataOp() { mlirModule.getLoc(), getGlobalMetadataOpName()); } +ComdatOp ModuleImport::getGlobalComdatOp() { + if (globalComdatOp) + return globalComdatOp; + + OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToStart(mlirModule.getBody()); + return globalComdatOp = builder.create(mlirModule.getLoc(), + getGlobalComdatOpName()); +} + LogicalResult ModuleImport::processTBAAMetadata(const llvm::MDNode *node) { Location loc = mlirModule.getLoc(); SmallVector workList; @@ -540,6 +557,20 @@ LogicalResult ModuleImport::convertMetadata() { return success(); } +LogicalResult ModuleImport::convertComdats() { + ComdatOp comdat = getGlobalComdatOp(); + OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToEnd(&comdat.getBody().back()); + for (auto &kv : llvmModule->getComdatSymbolTable()) { + StringRef name = kv.getKey(); + llvm::Comdat::SelectionKind selector = kv.getValue().getSelectionKind(); + builder.create(mlirModule.getLoc(), name, + convertComdatFromLLVM(selector)); + } + + return success(); +} + LogicalResult ModuleImport::convertGlobals() { for (llvm::GlobalVariable &globalVar : llvmModule->globals()) { if (globalVar.getName() == getGlobalCtorsVarName() || @@ -857,6 +888,19 @@ LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) { globalOp.setVisibility_( convertVisibilityFromLLVM(globalVar->getVisibility())); + if (globalVar->hasComdat()) { + llvm::Comdat *llvmComdat = globalVar->getComdat(); + ComdatOp comdat = getGlobalComdatOp(); + if (ComdatSelectorOp selector = dyn_cast( + comdat.lookupSymbol(llvmComdat->getName()))) { + auto symbolRef = + SymbolRefAttr::get(builder.getContext(), getGlobalComdatOpName(), + FlatSymbolRefAttr::get(selector.getSymNameAttr())); + globalOp.setComdatAttr(symbolRef); + } else + return failure(); + } + return success(); } @@ -1780,6 +1824,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr llvmModule, return {}; if (failed(moduleImport.convertMetadata())) return {}; + if (failed(moduleImport.convertComdats())) + return {}; if (failed(moduleImport.convertGlobals())) return {}; if (failed(moduleImport.convertFunctions())) diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index ee176a43c6ff9..9f072191804e0 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -27,6 +27,7 @@ #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/RegionGraphTraits.h" #include "mlir/Support/LLVM.h" +#include "mlir/Support/LogicalResult.h" #include "mlir/Target/LLVMIR/LLVMTranslationInterface.h" #include "mlir/Target/LLVMIR/TypeToLLVM.h" @@ -724,6 +725,14 @@ LogicalResult ModuleTranslation::convertGlobals() { : llvm::GlobalValue::NotThreadLocal, addrSpace); + if (std::optional comdat = op.getComdat()) { + StringRef name = comdat->getLeafReference().getValue(); + if (!llvmModule->getComdatSymbolTable().contains(name)) + return emitError(op.getLoc(), "global references non-existant comdat"); + llvm::Comdat *llvmComdat = llvmModule->getOrInsertComdat(name); + var->setComdat(llvmComdat); + } + if (op.getUnnamedAddr().has_value()) var->setUnnamedAddr(convertUnnamedAddrToLLVM(*op.getUnnamedAddr())); @@ -1037,6 +1046,23 @@ LogicalResult ModuleTranslation::convertFunctions() { return success(); } +LogicalResult ModuleTranslation::convertComdats() { + for (ComdatOp comdat : getModuleBody(mlirModule).getOps()) { + for (ComdatSelectorOp selector : comdat.getOps()) { + StringRef name = selector.getName(); + llvm::Module *module = getLLVMModule(); + if (module->getComdatSymbolTable().contains(name)) { + return emitError(selector.getLoc()) + << "comdat selection symbols must be unique even in different " + "comdat regions"; + } + llvm::Comdat *comdat = module->getOrInsertComdat(name); + comdat->setSelectionKind(convertComdatToLLVM(selector.getComdat())); + } + } + return success(); +} + LogicalResult ModuleTranslation::createAccessGroupMetadata() { return loopAnnotationTranslation->createAccessGroupMetadata(); } @@ -1372,6 +1398,8 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, ModuleTranslation translator(module, std::move(llvmModule)); if (failed(translator.convertFunctionSignatures())) return nullptr; + if (failed(translator.convertComdats())) + return nullptr; if (failed(translator.convertGlobals())) return nullptr; if (failed(translator.createAccessGroupMetadata())) @@ -1387,7 +1415,7 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext, llvm::IRBuilder<> llvmBuilder(llvmContext); for (Operation &o : getModuleBody(module).getOperations()) { if (!isa(&o) && + LLVM::GlobalDtorsOp, LLVM::MetadataOp, LLVM::ComdatOp>(&o) && !o.hasTrait() && failed(translator.convertOperation(o, llvmBuilder))) { return nullptr; diff --git a/mlir/test/Dialect/LLVMIR/comdat.mlir b/mlir/test/Dialect/LLVMIR/comdat.mlir new file mode 100644 index 0000000000000..e8eaaa15160a0 --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/comdat.mlir @@ -0,0 +1,16 @@ +// RUN: mlir-opt -split-input-file -verify-diagnostics %s | FileCheck %s + +// CHECK: llvm.comdat @__llvm_comdat +llvm.comdat @__llvm_comdat { + // CHECK: llvm.comdat_selector @any_comdat any + llvm.comdat_selector @any_comdat any + // CHECK: llvm.comdat_selector @exactmatch_comdat exactmatch + llvm.comdat_selector @exactmatch_comdat exactmatch + // CHECK: llvm.comdat_selector @largest_comdat largest + llvm.comdat_selector @largest_comdat largest + // CHECK: llvm.comdat_selector @nodeduplicate_comdat nodeduplicate + llvm.comdat_selector @nodeduplicate_comdat nodeduplicate + // CHECK: llvm.comdat_selector @samesize_comdat samesize + llvm.comdat_selector @samesize_comdat samesize +} + diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir index 00b73f0549fab..c9a28e0a9eb93 100644 --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -64,6 +64,14 @@ llvm.mlir.global external @has_dso_local(42 : i64) {dso_local} : i64 // CHECK: llvm.mlir.global external @has_addr_space(32 : i64) {addr_space = 3 : i32} : i64 llvm.mlir.global external @has_addr_space(32 : i64) {addr_space = 3: i32} : i64 +// CHECK: llvm.comdat @__llvm_comdat +llvm.comdat @__llvm_comdat { + // CHECK: llvm.comdat_selector @any any + llvm.comdat_selector @any any +} +// CHECK: llvm.mlir.global external @any() comdat(@__llvm_comdat::@any) {addr_space = 0 : i32} : i64 +llvm.mlir.global @any() comdat(@__llvm_comdat::@any) : i64 + // CHECK-LABEL: references func.func @references() { // CHECK: llvm.mlir.addressof @".string" : !llvm.ptr diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir index b88619b1e388d..db8b304182805 100644 --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -1423,3 +1423,16 @@ func.func @invalid_target_ext_constant() { // expected-error@+1 {{only zero-initializer allowed for target extension types}} %0 = llvm.mlir.constant(42 : index) : !llvm.target<"spirv.Event"> } + +// ----- + +llvm.comdat @__llvm_comdat { + // expected-error@+1 {{only comdat selector symbols can appear in a comdat region}} + llvm.return +} + +// ----- + +llvm.mlir.global @not_comdat(0 : i32) : i32 +// expected-error@+1 {{expected comdat symbol}} +llvm.mlir.global @invalid_comdat_use(0 : i32) comdat(@not_comdat) : i32 diff --git a/mlir/test/Target/LLVMIR/Import/comdat.ll b/mlir/test/Target/LLVMIR/Import/comdat.ll new file mode 100644 index 0000000000000..8ef38eb8728a1 --- /dev/null +++ b/mlir/test/Target/LLVMIR/Import/comdat.ll @@ -0,0 +1,20 @@ +; RUN: mlir-translate -import-llvm %s | FileCheck %s + +; CHECK: llvm.mlir.global external @foo(42 : i64) comdat(@__llvm_global_comdat::@foo) {addr_space = 0 : i32} : i64 +@foo = global i64 42, comdat +; CHECK: llvm.mlir.global external @bar(42 : i64) comdat(@__llvm_global_comdat::@foo) {addr_space = 0 : i32} : i64 +@bar = global i64 42, comdat($foo) + +; CHECK: llvm.comdat @__llvm_global_comdat { +; CHECK-DAG: llvm.comdat_selector @foo any +$foo = comdat any +; CHECK-DAG: llvm.comdat_selector @exact exactmatch +$exact = comdat exactmatch +; CHECK-DAG: llvm.comdat_selector @largest largest +$largest = comdat largest +; CHECK-DAG: llvm.comdat_selector @nodedup nodeduplicate +$nodedup = comdat nodeduplicate +; CHECK-DAG: llvm.comdat_selector @same samesize +$same = comdat samesize + +; CHECK: } diff --git a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir index 0522a8a14f525..2d6ccff2d436f 100644 --- a/mlir/test/Target/LLVMIR/llvmir-invalid.mlir +++ b/mlir/test/Target/LLVMIR/llvmir-invalid.mlir @@ -242,3 +242,14 @@ llvm.func @stepvector_intr_wrong_type() -> vector<7xf32> { %0 = llvm.intr.experimental.stepvector : vector<7xf32> llvm.return %0 : vector<7xf32> } + +// ----- + +llvm.comdat @__llvm_comdat { + llvm.comdat_selector @foo any +} + +llvm.comdat @__llvm_comdat_1 { + // expected-error @below{{comdat selection symbols must be unique even in different comdat regions}} + llvm.comdat_selector @foo any +} diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 5a56862817ac5..d23b6a7c289cc 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -1,5 +1,21 @@ // RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s + +// Comdat sections +llvm.comdat @__llvm_comdat { + // CHECK: $any = comdat any + llvm.comdat_selector @any any + // CHECK: $exactmatch = comdat exactmatch + llvm.comdat_selector @exactmatch exactmatch + // CHECK: $largest = comdat largest + llvm.comdat_selector @largest largest + // CHECK: $nodeduplicate = comdat nodeduplicate + llvm.comdat_selector @nodeduplicate nodeduplicate + // CHECK: $samesize = comdat samesize + llvm.comdat_selector @samesize samesize +} + + // CHECK: @global_aligned32 = private global i64 42, align 32 "llvm.mlir.global"() ({}) {sym_name = "global_aligned32", global_type = i64, value = 42 : i64, linkage = #llvm.linkage, alignment = 32} : () -> () @@ -153,6 +169,20 @@ llvm.mlir.global thread_local @has_thr_local(42 : i64) : i64 // CHECK: @sectionvar = internal constant [10 x i8] c"teststring", section ".mysection" llvm.mlir.global internal constant @sectionvar("teststring") {section = ".mysection"}: !llvm.array<10 x i8> +// +// Comdat attribute. +// +// CHECK: @has_any_comdat = internal constant i64 1, comdat($any) +llvm.mlir.global internal constant @has_any_comdat(1 : i64) comdat(@__llvm_comdat::@any) : i64 +// CHECK: @has_exactmatch_comdat = internal constant i64 1, comdat($exactmatch) +llvm.mlir.global internal constant @has_exactmatch_comdat(1 : i64) comdat(@__llvm_comdat::@exactmatch) : i64 +// CHECK: @has_largest_comdat = internal constant i64 1, comdat($largest) +llvm.mlir.global internal constant @has_largest_comdat(1 : i64) comdat(@__llvm_comdat::@largest) : i64 +// CHECK: @has_nodeduplicate_comdat = internal constant i64 1, comdat($nodeduplicate) +llvm.mlir.global internal constant @has_nodeduplicate_comdat(1 : i64) comdat(@__llvm_comdat::@nodeduplicate) : i64 +// CHECK: @has_samesize_comdat = internal constant i64 1, comdat($samesize) +llvm.mlir.global internal constant @has_samesize_comdat(1 : i64) comdat(@__llvm_comdat::@samesize) : i64 + // // Declarations of the allocation functions to be linked against. These are // inserted before other functions in the module. From d46d9689f7c3fe16010cd07761858a6392239b3f Mon Sep 17 00:00:00 2001 From: Dmitry Makogon Date: Thu, 8 Jun 2023 18:56:18 +0700 Subject: [PATCH 022/130] [BBUtils] Don't add 'then' block to a loop if it's terminated with unreachable SplitBlockAndInsertIfThen utility creates two new blocks, they're called ThenBlock and Tail (true and false destinations of a conditional branch correspondingly). The function has a bool parameter Unreachable, and if it's set, then ThenBlock is terminated with an unreachable. At the end of the function the new blocks are added to the loop of the split block. However, in case ThenBlock is terminated with an unreachable, it cannot belong to any loop. Differential Revision: https://reviews.llvm.org/D152434 --- llvm/lib/Transforms/Utils/BasicBlockUtils.cpp | 4 +++- llvm/test/Transforms/SimpleLoopUnswitch/guards.ll | 3 --- .../nontrivial-unswitch-skip-selects-in-guards.ll | 3 --- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index 4b93b624c2eb0..68ff16f70a5d5 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -1518,7 +1518,9 @@ Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, if (LI) { if (Loop *L = LI->getLoopFor(Head)) { - L->addBasicBlockToLoop(ThenBlock, *LI); + // unreachable-terminated blocks cannot belong to any loop. + if (!Unreachable) + L->addBasicBlockToLoop(ThenBlock, *LI); L->addBasicBlockToLoop(Tail, *LI); } } diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/guards.ll b/llvm/test/Transforms/SimpleLoopUnswitch/guards.ll index 52580382d1d55..07668616ff86d 100644 --- a/llvm/test/Transforms/SimpleLoopUnswitch/guards.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/guards.ll @@ -2,9 +2,6 @@ ; RUN: opt -passes='simple-loop-unswitch' -simple-loop-unswitch-guards -S < %s | FileCheck %s ; RUN: opt -passes='loop-mssa(simple-loop-unswitch),verify' -simple-loop-unswitch-guards -verify-memoryssa -verify-loop-info -S < %s | FileCheck %s -; XFAIL: * -; REQUIRES: asserts - declare void @llvm.experimental.guard(i1, ...) define void @test_simple_case(i1 %cond, i32 %N) { diff --git a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-skip-selects-in-guards.ll b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-skip-selects-in-guards.ll index e7bf39dd74e42..543ee092e810c 100644 --- a/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-skip-selects-in-guards.ll +++ b/llvm/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch-skip-selects-in-guards.ll @@ -7,9 +7,6 @@ declare ptr @pluto() declare void @llvm.experimental.guard(i1, ...) declare void @widget() -; XFAIL: * -; REQUIRES: asserts - define void @foo(ptr addrspace(1) %arg, i64 %arg1) personality ptr @pluto { ; CHECK-LABEL: @foo( ; CHECK-NEXT: bb: From 028cf8c016b21961bd229f24ddffcad1cb95aa7a Mon Sep 17 00:00:00 2001 From: Adrian Munera Date: Thu, 15 Jun 2023 14:27:01 -0500 Subject: [PATCH 023/130] [OpenMP] Implement printing TDGs to dot files This patch implements the "__kmp_print_tdg_dot" function, that prints a task dependency graph into a dot file containing the tasks and their dependencies. It is activated through a new environment variable "KMP_TDG_DOT" Reviewed By: tianshilei1992 Differential Revision: https://reviews.llvm.org/D150962 --- openmp/runtime/src/kmp.h | 1 + openmp/runtime/src/kmp_global.cpp | 1 + openmp/runtime/src/kmp_settings.cpp | 11 +++ openmp/runtime/src/kmp_tasking.cpp | 36 +++++++++ .../tasking/omp_record_replay_print_dot.cpp | 80 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp diff --git a/openmp/runtime/src/kmp.h b/openmp/runtime/src/kmp.h index 251a5f0ce76fd..f50fb01f793f0 100644 --- a/openmp/runtime/src/kmp.h +++ b/openmp/runtime/src/kmp.h @@ -2535,6 +2535,7 @@ typedef struct kmp_tdg_info { kmp_int32 rec_num_taskred; } kmp_tdg_info_t; +extern int __kmp_tdg_dot; extern kmp_int32 __kmp_max_tdgs; extern kmp_tdg_info_t **__kmp_global_tdgs; extern kmp_int32 __kmp_curr_tdg_idx; diff --git a/openmp/runtime/src/kmp_global.cpp b/openmp/runtime/src/kmp_global.cpp index 9557c519f835a..4ce0691abf8d6 100644 --- a/openmp/runtime/src/kmp_global.cpp +++ b/openmp/runtime/src/kmp_global.cpp @@ -559,6 +559,7 @@ int *__kmp_nesting_nth_level; #if OMPX_TASKGRAPH // TDG record & replay +int __kmp_tdg_dot = 0; kmp_int32 __kmp_max_tdgs = 100; kmp_tdg_info_t **__kmp_global_tdgs = NULL; kmp_int32 __kmp_curr_tdg_idx = diff --git a/openmp/runtime/src/kmp_settings.cpp b/openmp/runtime/src/kmp_settings.cpp index 7092d6eb9104c..181db20a5f58d 100644 --- a/openmp/runtime/src/kmp_settings.cpp +++ b/openmp/runtime/src/kmp_settings.cpp @@ -1267,6 +1267,16 @@ static void __kmp_std_print_max_tdgs(kmp_str_buf_t *buffer, char const *name, void *data) { __kmp_stg_print_int(buffer, name, __kmp_max_tdgs); } // __kmp_std_print_max_tdgs + +static void __kmp_stg_parse_tdg_dot(char const *name, char const *value, + void *data) { + __kmp_stg_parse_bool(name, value, &__kmp_tdg_dot); +} // __kmp_stg_parse_tdg_dot + +static void __kmp_stg_print_tdg_dot(kmp_str_buf_t *buffer, char const *name, + void *data) { + __kmp_stg_print_bool(buffer, name, __kmp_tdg_dot); +} // __kmp_stg_print_tdg_dot #endif static void __kmp_stg_parse_num_hidden_helper_threads(char const *name, @@ -5624,6 +5634,7 @@ static kmp_setting_t __kmp_stg_table[] = { #if OMPX_TASKGRAPH {"KMP_MAX_TDGS", __kmp_stg_parse_max_tdgs, __kmp_std_print_max_tdgs, NULL, 0, 0}, + {"KMP_TDG_DOT", __kmp_stg_parse_tdg_dot, __kmp_stg_print_tdg_dot, NULL, 0, 0}, #endif #if OMPT_SUPPORT diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp index ee452440176bf..fefa609927e89 100644 --- a/openmp/runtime/src/kmp_tasking.cpp +++ b/openmp/runtime/src/kmp_tasking.cpp @@ -5467,6 +5467,39 @@ static kmp_tdg_info_t *__kmp_find_tdg(kmp_int32 tdg_id) { return res; } +// __kmp_print_tdg_dot: prints the TDG to a dot file +// tdg: ID of the TDG +void __kmp_print_tdg_dot(kmp_tdg_info_t *tdg) { + kmp_int32 tdg_id = tdg->tdg_id; + KA_TRACE(10, ("__kmp_print_tdg_dot(enter): T#%d tdg_id=%d \n", gtid, tdg_id)); + + char file_name[20]; + sprintf(file_name, "tdg_%d.dot", tdg_id); + kmp_safe_raii_file_t tdg_file(file_name, "w"); + + kmp_int32 num_tasks = KMP_ATOMIC_LD_RLX(&tdg->num_tasks); + fprintf(tdg_file, + "digraph TDG {\n" + " compound=true\n" + " subgraph cluster {\n" + " label=TDG_%d\n", + tdg_id); + for (kmp_int32 i = 0; i < num_tasks; i++) { + fprintf(tdg_file, " %d[style=bold]\n", i); + } + fprintf(tdg_file, " }\n"); + for (kmp_int32 i = 0; i < num_tasks; i++) { + kmp_int32 nsuccessors = tdg->record_map[i].nsuccessors; + kmp_int32 *successors = tdg->record_map[i].successors; + if (nsuccessors > 0) { + for (kmp_int32 j = 0; j < nsuccessors; j++) + fprintf(tdg_file, " %d -> %d \n", i, successors[j]); + } + } + fprintf(tdg_file, "}"); + KA_TRACE(10, ("__kmp_print_tdg_dot(exit): T#%d tdg_id=%d \n", gtid, tdg_id)); +} + // __kmp_start_record: launch the execution of a previous // recorded TDG // gtid: Global Thread ID @@ -5636,6 +5669,9 @@ void __kmp_end_record(kmp_int32 gtid, kmp_tdg_info_t *tdg) { this_record_map[i].npredecessors); } KMP_ATOMIC_ST_RLX(&__kmp_tdg_task_id, 0); + + if (__kmp_tdg_dot) + __kmp_print_tdg_dot(tdg); } // __kmpc_end_record_task: wrapper around __kmp_end_record to mark diff --git a/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp new file mode 100644 index 0000000000000..2fe55f0815429 --- /dev/null +++ b/openmp/runtime/test/tasking/omp_record_replay_print_dot.cpp @@ -0,0 +1,80 @@ +// REQUIRES: ompx_taskgraph +// RUN: %libomp-cxx-compile-and-run +#include +#include +#include +#include + +// Compiler-generated code (emulation) +typedef struct ident { + void* dummy; +} ident_t; + +#ifdef __cplusplus +extern "C" { + int __kmpc_global_thread_num(ident_t *); + int __kmpc_start_record_task(ident_t *, int, int, int); + void __kmpc_end_record_task(ident_t *, int, int , int); +} +#endif + +void func(int *num_exec) { + #pragma omp atomic + (*num_exec)++; +} + +std::string tdg_string= "digraph TDG {\n" +" compound=true\n" +" subgraph cluster {\n" +" label=TDG_0\n" +" 0[style=bold]\n" +" 1[style=bold]\n" +" 2[style=bold]\n" +" 3[style=bold]\n" +" }\n" +" 0 -> 1 \n" +" 1 -> 2 \n" +" 1 -> 3 \n" +"}"; + +int main() { + int num_exec = 0; + int x, y; + + setenv("KMP_TDG_DOT","TRUE",1); + remove("tdg_0.dot"); + + #pragma omp parallel + #pragma omp single + { + int gtid = __kmpc_global_thread_num(nullptr); + int res = __kmpc_start_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0); + if (res) { + #pragma omp task depend(out : x) + func(&num_exec); + #pragma omp task depend(in : x) depend(out : y) + func(&num_exec); + #pragma omp task depend(in : y) + func(&num_exec); + #pragma omp task depend(in : y) + func(&num_exec); + } + + __kmpc_end_record_task(nullptr, gtid, /* kmp_tdg_flags */ 0, /* tdg_id */ 0); + } + + assert(num_exec == 4); + + std::ifstream tdg_file("tdg_0.dot"); + assert(tdg_file.is_open()); + + std::stringstream tdg_file_stream; + tdg_file_stream << tdg_file.rdbuf(); + int equal = tdg_string.compare(tdg_file_stream.str()); + + assert(equal == 0); + + std::cout << "Passed" << std::endl; + return 0; +} +// CHECK: Passed From ce9d3f09b4b2a2ae229c3e1f56f27cd31bc4660c Mon Sep 17 00:00:00 2001 From: Alexandros Lamprineas Date: Mon, 19 Jun 2023 11:08:03 +0100 Subject: [PATCH 024/130] [FuncSpec] Promote stack values before specialization. After each iteration of the function specializer, constant stack values are promoted to constant globals in order to enable recursive function specialization. This should also be done once before running the specializer. Enables specialization of _QMbrute_forcePdigits_2 from SPEC2017:548.exchange2_r. Differential Revision: https://reviews.llvm.org/D152799 --- .../Transforms/IPO/FunctionSpecialization.h | 13 +- .../Transforms/IPO/FunctionSpecialization.cpp | 128 ++++++++---------- .../function-specialization-recursive.ll | 59 -------- .../promoteContantStackValues.ll | 95 +++++++++++++ 4 files changed, 152 insertions(+), 143 deletions(-) delete mode 100644 llvm/test/Transforms/FunctionSpecialization/function-specialization-recursive.ll create mode 100644 llvm/test/Transforms/FunctionSpecialization/promoteContantStackValues.ll diff --git a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h index e24d72fae10fb..f780385f7f67d 100644 --- a/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h +++ b/llvm/include/llvm/Transforms/IPO/FunctionSpecialization.h @@ -206,10 +206,9 @@ class FunctionSpecializer { /// is a function argument. Constant *getConstantStackValue(CallInst *Call, Value *Val); - /// Iterate over the argument tracked functions see if there - /// are any new constant values for the call instruction via - /// stack variables. - void promoteConstantStackValues(); + /// See if there are any new constant values for the callers of \p F via + /// stack variables and promote them to global variables. + void promoteConstantStackValues(Function *F); /// Clean up fully specialized functions. void removeDeadFunctions(); @@ -217,9 +216,6 @@ class FunctionSpecializer { /// Remove any ssa_copy intrinsics that may have been introduced. void cleanUpSSA(); - // Compute the code metrics for function \p F. - CodeMetrics &analyzeFunction(Function *F); - /// @brief Find potential specialization opportunities. /// @param F Function to specialize /// @param SpecCost Cost of specializing a function. Final score is benefit @@ -238,9 +234,6 @@ class FunctionSpecializer { /// @return The new, cloned function Function *createSpecialization(Function *F, const SpecSig &S); - /// Compute and return the cost of specializing function \p F. - Cost getSpecializationCost(Function *F); - /// Determine if it is possible to specialise the function for constant values /// of the formal parameter \p A. bool isArgumentInteresting(Argument *A); diff --git a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp index 1792b24936bf8..93d2eaaddf310 100644 --- a/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp +++ b/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp @@ -397,49 +397,37 @@ Constant *FunctionSpecializer::getConstantStackValue(CallInst *Call, // ret void // } // -void FunctionSpecializer::promoteConstantStackValues() { - // Iterate over the argument tracked functions see if there - // are any new constant values for the call instruction via - // stack variables. - for (Function &F : M) { - if (!Solver.isArgumentTrackedFunction(&F)) +// See if there are any new constant values for the callers of \p F via +// stack variables and promote them to global variables. +void FunctionSpecializer::promoteConstantStackValues(Function *F) { + for (User *U : F->users()) { + + auto *Call = dyn_cast(U); + if (!Call) continue; - for (auto *User : F.users()) { + if (!Solver.isBlockExecutable(Call->getParent())) + continue; - auto *Call = dyn_cast(User); - if (!Call) - continue; + for (const Use &U : Call->args()) { + unsigned Idx = Call->getArgOperandNo(&U); + Value *ArgOp = Call->getArgOperand(Idx); + Type *ArgOpType = ArgOp->getType(); - if (!Solver.isBlockExecutable(Call->getParent())) + if (!Call->onlyReadsMemory(Idx) || !ArgOpType->isPointerTy()) continue; - bool Changed = false; - for (const Use &U : Call->args()) { - unsigned Idx = Call->getArgOperandNo(&U); - Value *ArgOp = Call->getArgOperand(Idx); - Type *ArgOpType = ArgOp->getType(); - - if (!Call->onlyReadsMemory(Idx) || !ArgOpType->isPointerTy()) - continue; - - auto *ConstVal = getConstantStackValue(Call, ArgOp); - if (!ConstVal) - continue; - - Value *GV = new GlobalVariable(M, ConstVal->getType(), true, - GlobalValue::InternalLinkage, ConstVal, - "funcspec.arg"); - if (ArgOpType != ConstVal->getType()) - GV = ConstantExpr::getBitCast(cast(GV), ArgOpType); + auto *ConstVal = getConstantStackValue(Call, ArgOp); + if (!ConstVal) + continue; - Call->setArgOperand(Idx, GV); - Changed = true; - } + Value *GV = new GlobalVariable(M, ConstVal->getType(), true, + GlobalValue::InternalLinkage, ConstVal, + "funcspec.arg"); + if (ArgOpType != ConstVal->getType()) + GV = ConstantExpr::getBitCast(cast(GV), ArgOpType); - // Add the changed CallInst to Solver Worklist - if (Changed) - Solver.visitCall(*Call); + Call->setArgOperand(Idx, GV); } } } @@ -504,17 +492,37 @@ bool FunctionSpecializer::run() { if (!isCandidateFunction(&F)) continue; - Cost SpecCost = getSpecializationCost(&F); - if (!SpecCost.isValid()) { - LLVM_DEBUG(dbgs() << "FnSpecialization: Invalid specialization cost for " - << F.getName() << "\n"); - continue; + auto [It, Inserted] = FunctionMetrics.try_emplace(&F); + CodeMetrics &Metrics = It->second; + //Analyze the function. + if (Inserted) { + SmallPtrSet EphValues; + CodeMetrics::collectEphemeralValues(&F, &GetAC(F), EphValues); + for (BasicBlock &BB : F) + Metrics.analyzeBasicBlock(&BB, GetTTI(F), EphValues); } + // If the code metrics reveal that we shouldn't duplicate the function, + // or if the code size implies that this function is easy to get inlined, + // then we shouldn't specialize it. + if (Metrics.notDuplicatable || !Metrics.NumInsts.isValid() || + (!ForceSpecialization && !F.hasFnAttribute(Attribute::NoInline) && + Metrics.NumInsts < MinFunctionSize)) + continue; + + // TODO: For now only consider recursive functions when running multiple + // times. This should change if specialization on literal constants gets + // enabled. + if (!Inserted && !Metrics.isRecursive && !SpecializeLiteralConstant) + continue; + LLVM_DEBUG(dbgs() << "FnSpecialization: Specialization cost for " - << F.getName() << " is " << SpecCost << "\n"); + << F.getName() << " is " << Metrics.NumInsts << "\n"); + + if (Inserted && Metrics.isRecursive) + promoteConstantStackValues(&F); - if (!findSpecializations(&F, SpecCost, AllSpecs, SM)) { + if (!findSpecializations(&F, Metrics.NumInsts, AllSpecs, SM)) { LLVM_DEBUG( dbgs() << "FnSpecialization: No possible specializations found for " << F.getName() << "\n"); @@ -622,7 +630,10 @@ bool FunctionSpecializer::run() { // Rerun the solver to notify the users of the modified callsites. Solver.solveWhileResolvedUndefs(); - promoteConstantStackValues(); + for (Function *F : OriginalFuncs) + if (FunctionMetrics[F].isRecursive) + promoteConstantStackValues(F); + return true; } @@ -637,20 +648,6 @@ void FunctionSpecializer::removeDeadFunctions() { FullySpecialized.clear(); } -// Compute the code metrics for function \p F. -CodeMetrics &FunctionSpecializer::analyzeFunction(Function *F) { - auto I = FunctionMetrics.insert({F, CodeMetrics()}); - CodeMetrics &Metrics = I.first->second; - if (I.second) { - // The code metrics were not cached. - SmallPtrSet EphValues; - CodeMetrics::collectEphemeralValues(F, &(GetAC)(*F), EphValues); - for (BasicBlock &BB : *F) - Metrics.analyzeBasicBlock(&BB, (GetTTI)(*F), EphValues); - } - return Metrics; -} - /// Clone the function \p F and remove the ssa_copy intrinsics added by /// the SCCPSolver in the cloned version. static Function *cloneCandidateFunction(Function *F) { @@ -802,23 +799,6 @@ Function *FunctionSpecializer::createSpecialization(Function *F, return Clone; } -/// Compute and return the cost of specializing function \p F. -Cost FunctionSpecializer::getSpecializationCost(Function *F) { - CodeMetrics &Metrics = analyzeFunction(F); - // If the code metrics reveal that we shouldn't duplicate the function, we - // shouldn't specialize it. Set the specialization cost to Invalid. - // Or if the lines of codes implies that this function is easy to get - // inlined so that we shouldn't specialize it. - if (Metrics.notDuplicatable || !Metrics.NumInsts.isValid() || - (!ForceSpecialization && !F->hasFnAttribute(Attribute::NoInline) && - Metrics.NumInsts < MinFunctionSize)) - return InstructionCost::getInvalid(); - - // Otherwise, set the specialization cost to be the cost of all the - // instructions in the function. - return Metrics.NumInsts; -} - /// Compute a bonus for replacing argument \p A with constant \p C. Cost FunctionSpecializer::getSpecializationBonus(Argument *A, Constant *C, InstCostVisitor &Visitor) { diff --git a/llvm/test/Transforms/FunctionSpecialization/function-specialization-recursive.ll b/llvm/test/Transforms/FunctionSpecialization/function-specialization-recursive.ll deleted file mode 100644 index 2cee26a911a47..0000000000000 --- a/llvm/test/Transforms/FunctionSpecialization/function-specialization-recursive.ll +++ /dev/null @@ -1,59 +0,0 @@ -; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=2 -S < %s | FileCheck %s --check-prefix=ITERS2 -; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=3 -S < %s | FileCheck %s --check-prefix=ITERS3 -; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=4 -S < %s | FileCheck %s --check-prefix=ITERS4 - -@low = internal constant i32 0, align 4 -@high = internal constant i32 6, align 4 - -define internal void @recursiveFunc(ptr nocapture readonly %lo, i32 %step, ptr nocapture readonly %hi) { - %lo.temp = alloca i32, align 4 - %hi.temp = alloca i32, align 4 - %lo.load = load i32, ptr %lo, align 4 - %hi.load = load i32, ptr %hi, align 4 - %cmp = icmp ne i32 %lo.load, %hi.load - br i1 %cmp, label %block6, label %ret.block - -block6: - call void @print_val(i32 %lo.load, i32 %hi.load) - %add = add nsw i32 %lo.load, %step - %sub = sub nsw i32 %hi.load, %step - store i32 %add, ptr %lo.temp, align 4 - store i32 %sub, ptr %hi.temp, align 4 - call void @recursiveFunc(ptr nonnull %lo.temp, i32 %step, ptr nonnull %hi.temp) - br label %ret.block - -ret.block: - ret void -} - -; ITERS2: @funcspec.arg.4 = internal constant i32 2 -; ITERS2: @funcspec.arg.5 = internal constant i32 4 - -; ITERS3: @funcspec.arg.7 = internal constant i32 3 -; ITERS3: @funcspec.arg.8 = internal constant i32 3 - -define i32 @main() { -; ITERS2-LABEL: @main( -; ITERS2-NEXT: call void @print_val(i32 0, i32 6) -; ITERS2-NEXT: call void @print_val(i32 1, i32 5) -; ITERS2-NEXT: call void @recursiveFunc(ptr nonnull @funcspec.arg.4, i32 1, ptr nonnull @funcspec.arg.5) -; ITERS2-NEXT: ret i32 0 -; -; ITERS3-LABEL: @main( -; ITERS3-NEXT: call void @print_val(i32 0, i32 6) -; ITERS3-NEXT: call void @print_val(i32 1, i32 5) -; ITERS3-NEXT: call void @print_val(i32 2, i32 4) -; ITERS3-NEXT: call void @recursiveFunc(ptr nonnull @funcspec.arg.7, i32 1, ptr nonnull @funcspec.arg.8) -; ITERS3-NEXT: ret i32 0 -; -; ITERS4-LABEL: @main( -; ITERS4-NEXT: call void @print_val(i32 0, i32 6) -; ITERS4-NEXT: call void @print_val(i32 1, i32 5) -; ITERS4-NEXT: call void @print_val(i32 2, i32 4) -; ITERS4-NEXT: ret i32 0 -; - call void @recursiveFunc(ptr nonnull @low, i32 1, ptr nonnull @high) - ret i32 0 -} - -declare dso_local void @print_val(i32, i32) diff --git a/llvm/test/Transforms/FunctionSpecialization/promoteContantStackValues.ll b/llvm/test/Transforms/FunctionSpecialization/promoteContantStackValues.ll new file mode 100644 index 0000000000000..256cbebae0620 --- /dev/null +++ b/llvm/test/Transforms/FunctionSpecialization/promoteContantStackValues.ll @@ -0,0 +1,95 @@ +; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=1 -S < %s | FileCheck %s --check-prefix=ITERS1 +; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=2 -S < %s | FileCheck %s --check-prefix=ITERS2 +; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=3 -S < %s | FileCheck %s --check-prefix=ITERS3 +; RUN: opt -passes="ipsccp,inline,instcombine" -force-specialization -funcspec-max-iters=4 -S < %s | FileCheck %s --check-prefix=ITERS4 + +@low = internal constant i32 0, align 4 +@high = internal constant i32 6, align 4 + +define internal void @recursiveFunc(ptr nocapture readonly %lo, i32 %step, ptr nocapture readonly %hi) { + %lo.temp = alloca i32, align 4 + %hi.temp = alloca i32, align 4 + %lo.load = load i32, ptr %lo, align 4 + %hi.load = load i32, ptr %hi, align 4 + %cmp = icmp ne i32 %lo.load, %hi.load + br i1 %cmp, label %block6, label %ret.block + +block6: + call void @print_val(i32 %lo.load, i32 %hi.load) + %add = add nsw i32 %lo.load, %step + %sub = sub nsw i32 %hi.load, %step + store i32 %add, ptr %lo.temp, align 4 + store i32 %sub, ptr %hi.temp, align 4 + call void @recursiveFunc(ptr nonnull %lo.temp, i32 %step, ptr nonnull %hi.temp) + br label %ret.block + +ret.block: + ret void +} + +; ITERS1: @funcspec.arg = internal constant i32 0 +; ITERS1: @funcspec.arg.1 = internal constant i32 6 +; ITERS1: @funcspec.arg.3 = internal constant i32 1 +; ITERS1: @funcspec.arg.4 = internal constant i32 5 + +; ITERS2: @funcspec.arg = internal constant i32 0 +; ITERS2: @funcspec.arg.1 = internal constant i32 6 +; ITERS2: @funcspec.arg.3 = internal constant i32 1 +; ITERS2: @funcspec.arg.4 = internal constant i32 5 +; ITERS2: @funcspec.arg.6 = internal constant i32 2 +; ITERS2: @funcspec.arg.7 = internal constant i32 4 + +; ITERS3: @funcspec.arg = internal constant i32 0 +; ITERS3: @funcspec.arg.1 = internal constant i32 6 +; ITERS3: @funcspec.arg.3 = internal constant i32 1 +; ITERS3: @funcspec.arg.4 = internal constant i32 5 +; ITERS3: @funcspec.arg.6 = internal constant i32 2 +; ITERS3: @funcspec.arg.7 = internal constant i32 4 +; ITERS3: @funcspec.arg.9 = internal constant i32 3 +; ITERS3: @funcspec.arg.10 = internal constant i32 3 + +; ITERS4: @funcspec.arg = internal constant i32 0 +; ITERS4: @funcspec.arg.1 = internal constant i32 6 +; ITERS4: @funcspec.arg.3 = internal constant i32 1 +; ITERS4: @funcspec.arg.4 = internal constant i32 5 +; ITERS4: @funcspec.arg.6 = internal constant i32 2 +; ITERS4: @funcspec.arg.7 = internal constant i32 4 +; ITERS4: @funcspec.arg.9 = internal constant i32 3 +; ITERS4: @funcspec.arg.10 = internal constant i32 3 + +define i32 @main() { +; ITERS1-LABEL: @main( +; ITERS1-NEXT: call void @print_val(i32 0, i32 6) +; ITERS1-NEXT: call void @recursiveFunc(ptr nonnull @funcspec.arg.3, i32 1, ptr nonnull @funcspec.arg.4) +; ITERS1-NEXT: ret i32 0 +; +; ITERS2-LABEL: @main( +; ITERS2-NEXT: call void @print_val(i32 0, i32 6) +; ITERS2-NEXT: call void @print_val(i32 1, i32 5) +; ITERS2-NEXT: call void @recursiveFunc(ptr nonnull @funcspec.arg.6, i32 1, ptr nonnull @funcspec.arg.7) +; ITERS2-NEXT: ret i32 0 +; +; ITERS3-LABEL: @main( +; ITERS3-NEXT: call void @print_val(i32 0, i32 6) +; ITERS3-NEXT: call void @print_val(i32 1, i32 5) +; ITERS3-NEXT: call void @print_val(i32 2, i32 4) +; ITERS3-NEXT: call void @recursiveFunc(ptr nonnull @funcspec.arg.9, i32 1, ptr nonnull @funcspec.arg.10) +; ITERS3-NEXT: ret i32 0 +; +; ITERS4-LABEL: @main( +; ITERS4-NEXT: call void @print_val(i32 0, i32 6) +; ITERS4-NEXT: call void @print_val(i32 1, i32 5) +; ITERS4-NEXT: call void @print_val(i32 2, i32 4) +; ITERS4-NEXT: ret i32 0 +; + %lo.temp = alloca i32, align 4 + %hi.temp = alloca i32, align 4 + %lo.load = load i32, ptr @low, align 4 + %hi.load = load i32, ptr @high, align 4 + store i32 %lo.load, ptr %lo.temp, align 4 + store i32 %hi.load, ptr %hi.temp, align 4 + call void @recursiveFunc(ptr nonnull %lo.temp, i32 1, ptr nonnull %hi.temp) + ret i32 0 +} + +declare dso_local void @print_val(i32, i32) From cbd9585ba2c9c50160075bdc9de20ccead286d60 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 15:38:35 +0200 Subject: [PATCH 025/130] [CVP] Add test for PR63330 (NFC) --- .../urem-expansion.ll | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll index 620cd5e0651ca..cc4644d83aaf5 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll @@ -326,3 +326,21 @@ define i8 @large.divisor.with.overflow.v2.unbound.x(i8 %x) { %rem = urem i8 %x, 128 ret i8 %rem } + +define i1 @icmp_after_expansion(i8 noundef %x) { +; CHECK-LABEL: @icmp_after_expansion( +; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 6 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) +; CHECK-NEXT: [[X_FROZEN:%.*]] = freeze i8 [[X]] +; CHECK-NEXT: [[REM_UREM:%.*]] = sub nuw i8 [[X_FROZEN]], 3 +; CHECK-NEXT: [[REM_CMP:%.*]] = icmp ult i8 [[X_FROZEN]], 3 +; CHECK-NEXT: [[REM:%.*]] = select i1 [[REM_CMP]], i8 [[X_FROZEN]], i8 [[REM_UREM]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[REM]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; + %cmp.x.upper = icmp ult i8 %x, 6 + call void @llvm.assume(i1 %cmp.x.upper) + %rem = urem i8 %x, 3 + %cmp = icmp eq i8 %rem, 3 + ret i1 %cmp +} From 90b55f2bba365c1e83c3be60583b449e07f846f3 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 15:41:39 +0200 Subject: [PATCH 026/130] [CVP] Don't freeze value if guaranteed non-undef Avoid inserting the freeze if not necessary, as this allows LVI to continue reasoning about the expression. --- .../Transforms/Scalar/CorrelatedValuePropagation.cpp | 4 +++- .../CorrelatedValuePropagation/cond-at-use.ll | 7 +++---- .../CorrelatedValuePropagation/urem-expansion.ll | 10 ++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 9f503fb43bc35..488297110d6fa 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -766,7 +766,9 @@ static bool expandUDivOrURem(BinaryOperator *Instr, const ConstantRange &XCR, if (IsRem) { // NOTE: this transformation introduces two uses of X, // but it may be undef so we must freeze it first. - Value *FrozenX = B.CreateFreeze(X, X->getName() + ".frozen"); + Value *FrozenX = X; + if (!isGuaranteedNotToBeUndefOrPoison(X)) + FrozenX = B.CreateFreeze(X, X->getName() + ".frozen"); auto *AdjX = B.CreateNUWSub(FrozenX, Y, Instr->getName() + ".urem"); auto *Cmp = B.CreateICmp(ICmpInst::ICMP_ULT, FrozenX, Y, Instr->getName() + ".cmp"); diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll index dbb63203cc945..8e5ec878bb894 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll @@ -346,10 +346,9 @@ define i16 @urem_elide(i16 noundef %x) { define i16 @urem_expand(i16 noundef %x) { ; CHECK-LABEL: @urem_expand( -; CHECK-NEXT: [[X_FROZEN:%.*]] = freeze i16 [[X:%.*]] -; CHECK-NEXT: [[UREM_UREM:%.*]] = sub nuw i16 [[X_FROZEN]], 42 -; CHECK-NEXT: [[UREM_CMP:%.*]] = icmp ult i16 [[X_FROZEN]], 42 -; CHECK-NEXT: [[UREM:%.*]] = select i1 [[UREM_CMP]], i16 [[X_FROZEN]], i16 [[UREM_UREM]] +; CHECK-NEXT: [[UREM_UREM:%.*]] = sub nuw i16 [[X:%.*]], 42 +; CHECK-NEXT: [[UREM_CMP:%.*]] = icmp ult i16 [[X]], 42 +; CHECK-NEXT: [[UREM:%.*]] = select i1 [[UREM_CMP]], i16 [[X]], i16 [[UREM_UREM]] ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i16 [[X]], 84 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i16 [[UREM]], i16 24 ; CHECK-NEXT: ret i16 [[SEL]] diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll index cc4644d83aaf5..2f1ca2483f67d 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll @@ -331,12 +331,10 @@ define i1 @icmp_after_expansion(i8 noundef %x) { ; CHECK-LABEL: @icmp_after_expansion( ; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 6 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) -; CHECK-NEXT: [[X_FROZEN:%.*]] = freeze i8 [[X]] -; CHECK-NEXT: [[REM_UREM:%.*]] = sub nuw i8 [[X_FROZEN]], 3 -; CHECK-NEXT: [[REM_CMP:%.*]] = icmp ult i8 [[X_FROZEN]], 3 -; CHECK-NEXT: [[REM:%.*]] = select i1 [[REM_CMP]], i8 [[X_FROZEN]], i8 [[REM_UREM]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[REM]], 3 -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: [[REM_UREM:%.*]] = sub nuw i8 [[X]], 3 +; CHECK-NEXT: [[REM_CMP:%.*]] = icmp ult i8 [[X]], 3 +; CHECK-NEXT: [[REM:%.*]] = select i1 [[REM_CMP]], i8 [[X]], i8 [[REM_UREM]] +; CHECK-NEXT: ret i1 false ; %cmp.x.upper = icmp ult i8 %x, 6 call void @llvm.assume(i1 %cmp.x.upper) From 3956a34e4fc6994021e8f3cbcb81a02161ce15e0 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 14 Jun 2023 15:36:37 -0700 Subject: [PATCH 027/130] [libc++] Move non operator new definitions outside of new.cpp This makes it such that new.cpp contains only the definitions of operator new and operator delete, like its libc++abi counterpart. Differential Revision: https://reviews.llvm.org/D153136 --- libcxx/src/CMakeLists.txt | 1 + libcxx/src/new.cpp | 23 ----------------------- libcxx/src/new_helpers.cpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 23 deletions(-) create mode 100644 libcxx/src/new_helpers.cpp diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt index dede38652e2f9..5280436108e7f 100644 --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -36,6 +36,7 @@ set(LIBCXX_SOURCES mutex_destructor.cpp new.cpp new_handler.cpp + new_helpers.cpp optional.cpp random_shuffle.cpp ryu/d2fixed.cpp diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index b8d24e73f0812..a9920ba09849b 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -10,29 +10,6 @@ #include #include -namespace std -{ - -#ifndef __GLIBCXX__ -const nothrow_t nothrow{}; -#endif - -#ifndef LIBSTDCXX - -void -__throw_bad_alloc() -{ -#ifndef _LIBCPP_HAS_NO_EXCEPTIONS - throw bad_alloc(); -#else - _VSTD::abort(); -#endif -} - -#endif // !LIBSTDCXX - -} // std - #if !defined(__GLIBCXX__) && \ !defined(_LIBCPP_ABI_VCRUNTIME) && \ !defined(_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS) diff --git a/libcxx/src/new_helpers.cpp b/libcxx/src/new_helpers.cpp new file mode 100644 index 0000000000000..45a0a661db0e4 --- /dev/null +++ b/libcxx/src/new_helpers.cpp @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +namespace std { // purposefully not versioned + +#ifndef __GLIBCXX__ +const nothrow_t nothrow{}; +#endif + +#ifndef LIBSTDCXX + +void __throw_bad_alloc() { +# ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw bad_alloc(); +# else + std::abort(); +# endif +} + +#endif // !LIBSTDCXX + +} // namespace std From aabea3d320c87561fe98b56c9f53cca1c6d18869 Mon Sep 17 00:00:00 2001 From: Nicolas Vasilache Date: Mon, 19 Jun 2023 13:26:00 +0000 Subject: [PATCH 028/130] [mlir][Vector] Let VectorToLLVM operate on non-ModuleOp Restriction to ModuleOp is ancient and unnecessarily restrictive. --- mlir/include/mlir/Conversion/Passes.td | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index ac53af4709098..1e16d7b1dbdf8 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -361,10 +361,6 @@ def GpuToLLVMConversionPass : Pass<"gpu-to-llvm", "ModuleOp"> { }]; let options = [ - Option<"hostBarePtrCallConv", "use-bare-pointers-for-host", "bool", - /*default=*/"false", - "Use bare pointers to pass memref arguments to host functions. " - "All memrefs must have static shape.">, Option<"kernelBarePtrCallConv", "use-bare-pointers-for-kernels", "bool", /*default=*/"false", "Use bare pointers to pass memref arguments to kernels. " @@ -426,10 +422,6 @@ def ConvertGpuOpsToNVVMOps : Pass<"convert-gpu-to-nvvm", "gpu::GPUModuleOp"> { "Bitwidth of the index type, 0 to use size of machine word">, Option<"hasRedux", "has-redux", "bool", /*default=*/"false", "Target gpu supports redux">, - Option<"useBarePtrCallConv", "use-bare-ptr-memref-call-conv", "bool", - /*default=*/"false", - "Replace memref arguments in GPU functions with bare pointers. " - "All memrefs must have static shape.">, Option<"useOpaquePointers", "use-opaque-pointers", "bool", /*default=*/"true", "Generate LLVM IR using opaque pointers " "instead of typed pointers">, @@ -1065,7 +1057,7 @@ def ConvertVectorToSCF : Pass<"convert-vector-to-scf"> { // VectorToLLVM //===----------------------------------------------------------------------===// -def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm", "ModuleOp"> { +def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm"> { let summary = "Lower the operations from the vector dialect into the LLVM " "dialect"; let description = [{ @@ -1100,10 +1092,6 @@ def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm", "ModuleOp"> { "bool", /*default=*/"false", "Enables the use of ArmSVE dialect while lowering the vector " "dialect.">, - Option<"armSME", "enable-arm-sme", - "bool", /*default=*/"false", - "Enables the use of ArmSME dialect while lowering the vector " - "dialect.">, Option<"x86Vector", "enable-x86vector", "bool", /*default=*/"false", "Enables the use of X86Vector dialect while lowering the vector " From 8c80d01a95ba0d75c29191de0ea38cce48c9978f Mon Sep 17 00:00:00 2001 From: Nicolas Vasilache Date: Mon, 19 Jun 2023 13:33:30 +0000 Subject: [PATCH 029/130] [mlir][NVGPU] NFC - Add a more convenient C++ builder for nvgpu::MmaSyncOp --- mlir/include/mlir/Dialect/NVGPU/IR/NVGPU.td | 10 +++++++--- mlir/lib/Dialect/NVGPU/IR/NVGPUDialect.cpp | 9 +++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mlir/include/mlir/Dialect/NVGPU/IR/NVGPU.td b/mlir/include/mlir/Dialect/NVGPU/IR/NVGPU.td index 5bb02b082575a..e595e9dffbe0b 100644 --- a/mlir/include/mlir/Dialect/NVGPU/IR/NVGPU.td +++ b/mlir/include/mlir/Dialect/NVGPU/IR/NVGPU.td @@ -158,8 +158,7 @@ def NVGPU_MmaSyncOp : NVGPU_MmaSyncOp<"mma.sync"> { AnyVector:$matrixB, AnyVector:$matrixC, I64ArrayAttr:$mmaShape, - OptionalAttr:$tf32Enabled - ); + OptionalAttr:$tf32Enabled); let results = (outs AnyVector:$res); @@ -167,7 +166,12 @@ def NVGPU_MmaSyncOp : NVGPU_MmaSyncOp<"mma.sync"> { OpBuilder<(ins "Value":$matrixA, "Value":$matrixB, "Value":$matrixC, - "ArrayAttr":$mmaShape)> + "ArrayAttr":$mmaShape)>, + OpBuilder<(ins "Value":$matrixA, + "Value":$matrixB, + "Value":$matrixC, + "ArrayRef":$mmaShape, + CArg<"bool", "false">:$tf32Enabled)> ]; let assemblyFormat = [{ diff --git a/mlir/lib/Dialect/NVGPU/IR/NVGPUDialect.cpp b/mlir/lib/Dialect/NVGPU/IR/NVGPUDialect.cpp index 77c853a2c35f4..0472d27906ead 100644 --- a/mlir/lib/Dialect/NVGPU/IR/NVGPUDialect.cpp +++ b/mlir/lib/Dialect/NVGPU/IR/NVGPUDialect.cpp @@ -96,6 +96,15 @@ void MmaSyncOp::build(::mlir::OpBuilder &odsBuilder, mmaShape, UnitAttr()); } +void MmaSyncOp::build(::mlir::OpBuilder &odsBuilder, + ::mlir::OperationState &odsState, Value matrixA, + Value matrixB, Value matrixC, ArrayRef mmaShape, + bool tf32Enabled) { + build(odsBuilder, odsState, matrixC.getType(), matrixA, matrixB, matrixC, + odsBuilder.getI64ArrayAttr(mmaShape), + tf32Enabled ? odsBuilder.getUnitAttr() : UnitAttr()); +} + /// Performs verification for MmaSyncOp and MmaSparseSyncOp. static LogicalResult verifyMmaSyncOp(Operation *op, TypedValue matrixA, From 798b6419bc8446ba4d30c61e182ec628ea44ce40 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 19 Jun 2023 15:35:48 +0100 Subject: [PATCH 030/130] [LSR] Add test for for issue leading to revert of abfeda5af329b5. Add unit test triggering an assertion with abfeda5af329b5. --- ...ostinc-with-fixups-with-different-loops.ll | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 llvm/test/Transforms/LoopStrengthReduce/AArch64/postinc-with-fixups-with-different-loops.ll diff --git a/llvm/test/Transforms/LoopStrengthReduce/AArch64/postinc-with-fixups-with-different-loops.ll b/llvm/test/Transforms/LoopStrengthReduce/AArch64/postinc-with-fixups-with-different-loops.ll new file mode 100644 index 0000000000000..60d5588dfea11 --- /dev/null +++ b/llvm/test/Transforms/LoopStrengthReduce/AArch64/postinc-with-fixups-with-different-loops.ll @@ -0,0 +1,53 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt -loop-reduce -S %s | FileCheck %s + +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "arm64-apple-macosx13.0.0" + +declare void @use(i32) + +define i32 @test() { +; CHECK-LABEL: define i32 @test() { +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[LOOP_1:%.*]] +; CHECK: loop.1: +; CHECK-NEXT: [[LSR_IV1:%.*]] = phi i32 [ [[LSR_IV_NEXT2:%.*]], [[LOOP_1]] ], [ -1, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[LSR_IV_NEXT2]] = add i32 [[LSR_IV1]], 1 +; CHECK-NEXT: br i1 false, label [[LOOP_2_PH:%.*]], label [[LOOP_1]] +; CHECK: loop.2.ph: +; CHECK-NEXT: [[LSR_IV_NEXT2_LCSSA:%.*]] = phi i32 [ [[LSR_IV_NEXT2]], [[LOOP_1]] ] +; CHECK-NEXT: br label [[LOOP_2:%.*]] +; CHECK: loop.2: +; CHECK-NEXT: [[LSR_IV:%.*]] = phi i64 [ [[LSR_IV_NEXT:%.*]], [[LOOP_2]] ], [ 1, [[LOOP_2_PH]] ] +; CHECK-NEXT: [[IV_2:%.*]] = phi i32 [ [[LSR_IV_NEXT2_LCSSA]], [[LOOP_2_PH]] ], [ [[IV_2_NEXT:%.*]], [[LOOP_2]] ] +; CHECK-NEXT: call void @use(i32 [[IV_2]]) +; CHECK-NEXT: [[IV_2_NEXT]] = add i32 [[IV_2]], 1 +; CHECK-NEXT: [[LSR_IV_NEXT]] = add nsw i64 [[LSR_IV]], -1 +; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[LSR_IV_NEXT]], 0 +; CHECK-NEXT: br i1 [[EC]], label [[EXIT:%.*]], label [[LOOP_2]] +; CHECK: exit: +; CHECK-NEXT: ret i32 [[IV_2_NEXT]] +; +entry: + br label %loop.1 + +loop.1: + %iv.1 = phi i32 [ 0, %entry ], [ %iv.1.next, %loop.1 ] + %iv.1.next = add i32 %iv.1, 1 + br i1 false, label %loop.2.ph, label %loop.1 + +loop.2.ph: + br label %loop.2 + +loop.2: + %iv.2 = phi i32 [ %iv.1, %loop.2.ph ], [ %iv.2.next, %loop.2 ] + %iv.3 = phi i64 [ 0, %loop.2.ph ], [ %iv.3.next, %loop.2 ] + call void @use(i32 %iv.2) + %iv.2.next = add i32 %iv.2, 1 + %iv.3.next = add i64 %iv.3, 1 + %ec = icmp eq i64 %iv.3, 0 + br i1 %ec, label %exit, label %loop.2 + +exit: + ret i32 %iv.2.next +} From fa45f81ff7ea9fc2a2a40fea8dd7626ecc3a8dbb Mon Sep 17 00:00:00 2001 From: Roger Ferrer Ibanez Date: Mon, 19 Jun 2023 14:37:46 +0000 Subject: [PATCH 031/130] [clang][Serialization][RISCV] Increase the number of reserved predefined type IDs In D152070 we added many new intrinsic types required for the RISC-V Vector Extension. This was crashing when loading the AST as those types are intrinsically added to the AST (they don't come from the disk). The total number required now by clang exceeds 400 so increasing the value to 500 solves the problem. This value was already increased in D92715 but I assume this has some impact on the on-disk format. Also add a static assert to avoid this happening again in the future. Differential Revision: https://reviews.llvm.org/D153111 --- clang/include/clang/Serialization/ASTBitCodes.h | 10 +++++++++- clang/lib/Serialization/ASTReader.cpp | 4 ++++ clang/test/Modules/embed-files-compressed.cpp | 4 ++-- clang/test/Modules/empty.modulemap | 4 ++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index a93eb3d38a480..7019bc5922ebc 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1099,6 +1099,8 @@ enum PredefinedTypeIDs { // \brief WebAssembly reference types with auto numeration #define WASM_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/WebAssemblyReferenceTypes.def" + // Sentinel value. Considered a predefined type but not useable as one. + PREDEF_TYPE_LAST_ID }; /// The number of predefined type IDs that are reserved for @@ -1106,7 +1108,13 @@ enum PredefinedTypeIDs { /// /// Type IDs for non-predefined types will start at /// NUM_PREDEF_TYPE_IDs. -const unsigned NUM_PREDEF_TYPE_IDS = 300; +const unsigned NUM_PREDEF_TYPE_IDS = 500; + +// Ensure we do not overrun the predefined types we reserved +// in the enum PredefinedTypeIDs above. +static_assert(PREDEF_TYPE_LAST_ID < NUM_PREDEF_TYPE_IDS, + "Too many enumerators in PredefinedTypeIDs. Review the value of " + "NUM_PREDEF_TYPE_IDS"); /// Record codes for each kind of type. /// diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index a0ccc5aa4a741..cba6791783e8b 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6983,6 +6983,10 @@ QualType ASTReader::GetType(TypeID ID) { if (Index < NUM_PREDEF_TYPE_IDS) { QualType T; switch ((PredefinedTypeIDs)Index) { + case PREDEF_TYPE_LAST_ID: + // We should never use this one. + llvm_unreachable("Invalid predefined type"); + break; case PREDEF_TYPE_NULL_ID: return QualType(); case PREDEF_TYPE_VOID_ID: diff --git a/clang/test/Modules/embed-files-compressed.cpp b/clang/test/Modules/embed-files-compressed.cpp index ae016bc1f9630..873b3082a2fdf 100644 --- a/clang/test/Modules/embed-files-compressed.cpp +++ b/clang/test/Modules/embed-files-compressed.cpp @@ -17,7 +17,7 @@ // RUN: %clang_cc1 -fmodules -I%t -fmodules-cache-path=%t -fmodule-name=a -emit-module %t/modulemap -fmodules-embed-all-files -o %t/a.pcm // // The above embeds ~4.5MB of highly-predictable /s and \ns into the pcm file. -// Check that the resulting file is under 40KB: +// Check that the resulting file is under 60KB: // // RUN: wc -c %t/a.pcm | FileCheck --check-prefix=CHECK-SIZE %s -// CHECK-SIZE: {{(^|[^0-9])[123][0-9][0-9][0-9][0-9]($|[^0-9])}} +// CHECK-SIZE: {{(^|[^0-9])[1-5][0-9][0-9][0-9][0-9]($|[^0-9])}} diff --git a/clang/test/Modules/empty.modulemap b/clang/test/Modules/empty.modulemap index 3225d88829ae0..f2d37c19d77bc 100644 --- a/clang/test/Modules/empty.modulemap +++ b/clang/test/Modules/empty.modulemap @@ -13,8 +13,8 @@ // The module file should be identical each time we produce it. // RUN: diff %t/base.pcm %t/check.pcm // -// We expect an empty module to be less than 40KB (and at least 10K, for now). +// We expect an empty module to be less than 60KB (and at least 10K, for now). // RUN: wc -c %t/base.pcm | FileCheck --check-prefix=CHECK-SIZE %s -// CHECK-SIZE: {{(^|[^0-9])[123][0-9][0-9][0-9][0-9]($|[^0-9])}} +// CHECK-SIZE: {{(^|[^0-9])[1-5][0-9][0-9][0-9][0-9]($|[^0-9])}} module empty { header "Inputs/empty.h" export * } From 66511b401042f28c74d2ded3aac76d19a53bd7c4 Mon Sep 17 00:00:00 2001 From: Vladislav Dzhidzhoev Date: Mon, 19 Jun 2023 16:42:05 +0200 Subject: [PATCH 032/130] [DebugMetadata][DwarfDebug] Support function-local types in lexical block scopes (4/7) RFC https://discourse.llvm.org/t/rfc-dwarfdebug-fix-and-improve-handling-imported-entities-types-and-static-local-in-subprogram-and-lexical-block-scopes/68544 Similar to imported declarations, the patch tracks function-local types in DISubprogram's 'retainedNodes' field. DwarfDebug is adjusted in accordance with the aforementioned metadata change and provided a support of function-local types scoped within a lexical block. The patch assumes that DICompileUnit's 'enums field' no longer tracks local types and DwarfDebug would assert if any locally-scoped types get placed there. Authored-by: Kristina Bessonova Differential Revision: https://reviews.llvm.org/D144006 Depends on D144005 --- .../CodeGen/debug-info-codeview-unnamed.c | 16 +- clang/test/CodeGen/debug-info-unused-types.c | 14 +- .../test/CodeGen/debug-info-unused-types.cpp | 12 +- clang/test/CodeGenCXX/debug-info-access.cpp | 2 +- .../CodeGenCXX/debug-info-anon-union-vars.cpp | 12 +- .../debug-info-codeview-unnamed.cpp | 110 +++-- .../debug-info-gline-tables-only-codeview.cpp | 4 +- clang/test/CodeGenCXX/debug-lambda-this.cpp | 4 +- llvm/include/llvm/IR/DIBuilder.h | 6 +- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 87 ++-- .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 60 ++- .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 16 +- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 13 +- llvm/lib/IR/DIBuilder.cpp | 34 +- llvm/lib/IR/Verifier.cpp | 6 +- llvm/test/Bitcode/upgrade-cu-locals.ll | 68 +-- llvm/test/Bitcode/upgrade-cu-locals.ll.bc | Bin 2688 -> 2780 bytes .../DebugInfo/Generic/inlined-local-type.ll | 128 ++++++ .../Generic/lexical-block-retained-types.ll | 55 +++ .../DebugInfo/Generic/lexical-block-types.ll | 425 ++++++++++++++++++ .../local-type-as-template-parameter.ll | 160 +++++++ .../Generic/verifier-invalid-disubprogram.ll | 2 +- llvm/test/DebugInfo/X86/set.ll | 4 +- 23 files changed, 1051 insertions(+), 187 deletions(-) create mode 100644 llvm/test/DebugInfo/Generic/inlined-local-type.ll create mode 100644 llvm/test/DebugInfo/Generic/lexical-block-retained-types.ll create mode 100644 llvm/test/DebugInfo/Generic/lexical-block-types.ll create mode 100644 llvm/test/DebugInfo/Generic/local-type-as-template-parameter.ll diff --git a/clang/test/CodeGen/debug-info-codeview-unnamed.c b/clang/test/CodeGen/debug-info-codeview-unnamed.c index bd2a7543e56b2..16ffb3682236f 100644 --- a/clang/test/CodeGen/debug-info-codeview-unnamed.c +++ b/clang/test/CodeGen/debug-info-codeview-unnamed.c @@ -8,23 +8,23 @@ int main(int argc, char* argv[], char* arge[]) { // struct { int bar; } one = {42}; // - // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "one" - // LINUX-SAME: type: [[TYPE_OF_ONE:![0-9]+]] - // LINUX-SAME: ) - // LINUX: [[TYPE_OF_ONE]] = distinct !DICompositeType( + // LINUX: [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType( // LINUX-SAME: tag: DW_TAG_structure_type // LINUX-NOT: name: // LINUX-NOT: identifier: // LINUX-SAME: ) + // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "one" + // LINUX-SAME: type: [[TYPE_OF_ONE]] + // LINUX-SAME: ) // - // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "one" - // MSVC-SAME: type: [[TYPE_OF_ONE:![0-9]+]] - // MSVC-SAME: ) - // MSVC: [[TYPE_OF_ONE]] = distinct !DICompositeType + // MSVC: [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType // MSVC-SAME: tag: DW_TAG_structure_type // MSVC-NOT: name: // MSVC-NOT: identifier: // MSVC-SAME: ) + // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "one" + // MSVC-SAME: type: [[TYPE_OF_ONE]] + // MSVC-SAME: ) return 0; } diff --git a/clang/test/CodeGen/debug-info-unused-types.c b/clang/test/CodeGen/debug-info-unused-types.c index 3e9f7b07658e3..5bcc71f710a5c 100644 --- a/clang/test/CodeGen/debug-info-unused-types.c +++ b/clang/test/CodeGen/debug-info-unused-types.c @@ -18,13 +18,13 @@ void quux(void) { // CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]] // CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "bar" // CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAR" -// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z" -// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z" -// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], [[TYPE6:![0-9]+]], {{![0-9]+}}, [[TYPE7:![0-9]+]], [[TYPE2]], [[TYPE8:![0-9]+]]} -// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "my_int" -// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo" -// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "baz" -// CHECK: [[TYPE7]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "y" +// CHECK: [[RETTYPES]] = !{[[TYPE2:![0-9]+]], [[TYPE3:![0-9]+]], [[TYPE0]], [[TYPE4:![0-9]+]], {{![0-9]+}}, [[TYPE5:![0-9]+]], [[TYPE6:![0-9]+]], [[TYPE8:![0-9]+]]} +// CHECK: [[TYPE2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "my_int" +// CHECK: [[TYPE3]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "foo" +// CHECK: [[TYPE4]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "baz" +// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "y" +// CHECK: [[TYPE6]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z" +// CHECK: [[TYPE7:![0-9]+]] = !DIEnumerator(name: "Z" // CHECK: [[TYPE8]] = distinct !DICompositeType(tag: DW_TAG_union_type, name: "w" // Check that debug info is not emitted for the typedef, struct, enum, and diff --git a/clang/test/CodeGen/debug-info-unused-types.cpp b/clang/test/CodeGen/debug-info-unused-types.cpp index 023cac159faa4..715fada47eab8 100644 --- a/clang/test/CodeGen/debug-info-unused-types.cpp +++ b/clang/test/CodeGen/debug-info-unused-types.cpp @@ -13,12 +13,12 @@ void quux() { // CHECK: !DICompileUnit{{.+}}retainedTypes: [[RETTYPES:![0-9]+]] // CHECK: [[TYPE0:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "baz" // CHECK: [[TYPE1:![0-9]+]] = !DIEnumerator(name: "BAZ" -// CHECK: [[TYPE2:![0-9]+]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z" -// CHECK: [[TYPE3:![0-9]+]] = !DIEnumerator(name: "Z" -// CHECK: [[RETTYPES]] = !{[[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]], [[TYPE0]], {{![0-9]+}}, [[TYPE6:![0-9]+]], [[TYPE2]]} -// CHECK: [[TYPE4]] = !DIDerivedType(tag: DW_TAG_typedef, name: "foo" -// CHECK: [[TYPE5]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "bar" -// CHECK: [[TYPE6]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y" +// CHECK: [[RETTYPES]] = !{[[TYPE2:![0-9]+]], [[TYPE3:![0-9]+]], [[TYPE0]], {{![0-9]+}}, [[TYPE4:![0-9]+]], [[TYPE5:![0-9]+]]} +// CHECK: [[TYPE2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "foo" +// CHECK: [[TYPE3]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "bar" +// CHECK: [[TYPE4]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y" +// CHECK: [[TYPE5]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "z" +// CHECK: [[TYPE6:![0-9]+]] = !DIEnumerator(name: "Z" // NODBG-NOT: !DI{{CompositeType|Enumerator|DerivedType}} diff --git a/clang/test/CodeGenCXX/debug-info-access.cpp b/clang/test/CodeGenCXX/debug-info-access.cpp index 9f2c044843d0f..7c0bf8ccb0384 100644 --- a/clang/test/CodeGenCXX/debug-info-access.cpp +++ b/clang/test/CodeGenCXX/debug-info-access.cpp @@ -18,9 +18,9 @@ class B : public A { static int public_static; protected: + // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_using",{{.*}} line: [[@LINE+3]],{{.*}} flags: DIFlagProtected) // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_typedef",{{.*}} line: [[@LINE+1]],{{.*}} flags: DIFlagProtected) typedef int prot_typedef; - // CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "prot_using",{{.*}} line: [[@LINE+1]],{{.*}} flags: DIFlagProtected) using prot_using = prot_typedef; prot_using prot_member; diff --git a/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp index 61b3c7c0526c8..c91cf83c0405f 100644 --- a/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp +++ b/clang/test/CodeGenCXX/debug-info-anon-union-vars.cpp @@ -51,13 +51,13 @@ void instantiate(int x) { // CHECK: !DIGlobalVariable(name: "b",{{.*}} file: [[FILE]], line: 6,{{.*}} isLocal: true, isDefinition: true // CHECK: !DIGlobalVariable(name: "result", {{.*}} isLocal: false, isDefinition: true // CHECK: !DIGlobalVariable(name: "value", {{.*}} isLocal: false, isDefinition: true -// CHECK: !DILocalVariable(name: "i", {{.*}}, flags: DIFlagArtificial -// CHECK: !DILocalVariable(name: "c", {{.*}}, flags: DIFlagArtificial -// CHECK: !DILocalVariable( -// CHECK-NOT: name: -// CHECK: type: ![[UNION:[0-9]+]] -// CHECK: ![[UNION]] = distinct !DICompositeType(tag: DW_TAG_union_type, +// CHECK: ![[UNION:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_union_type, // CHECK-NOT: name: // CHECK: elements // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "i", scope: ![[UNION]], // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "c", scope: ![[UNION]], +// CHECK: !DILocalVariable(name: "i", {{.*}}, flags: DIFlagArtificial +// CHECK: !DILocalVariable(name: "c", {{.*}}, flags: DIFlagArtificial +// CHECK: !DILocalVariable( +// CHECK-NOT: name: +// CHECK: type: ![[UNION]] diff --git a/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp b/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp index b4c79936ab33e..9602ac1b02497 100644 --- a/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp +++ b/clang/test/CodeGenCXX/debug-info-codeview-unnamed.cpp @@ -3,6 +3,60 @@ int main(int argc, char* argv[], char* arge[]) { // + // LINUX: [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType( + // LINUX-SAME: tag: DW_TAG_structure_type + // LINUX-NOT: name: + // LINUX-NOT: identifier: + // LINUX-SAME: ) + // + // MSVC: [[TYPE_OF_ONE:![0-9]+]] = distinct !DICompositeType + // MSVC-SAME: tag: DW_TAG_structure_type + // MSVC-SAME: name: "" + // MSVC-SAME: identifier: ".?AU@?1??main@@9@" + // MSVC-SAME: ) + + + // + // LINUX: [[TYPE_OF_TWO:![0-9]+]] = distinct !DICompositeType( + // LINUX-SAME: tag: DW_TAG_structure_type + // LINUX-NOT: name: + // LINUX-NOT: identifier: + // LINUX-SAME: ) + // + // MSVC: [[TYPE_OF_TWO:![0-9]+]] = distinct !DICompositeType + // MSVC-SAME: tag: DW_TAG_structure_type + // MSVC-SAME: name: "" + // MSVC-SAME: identifier: ".?AU@?2??main@@9@" + // MSVC-SAME: ) + + + // + // LINUX: [[TYPE_OF_THREE:![0-9]+]] = distinct !DICompositeType( + // LINUX-SAME: tag: DW_TAG_structure_type + // LINUX-SAME: name: "named" + // LINUX-NOT: identifier: + // LINUX-SAME: ) + // + // MSVC: [[TYPE_OF_THREE:![0-9]+]] = distinct !DICompositeType + // MSVC-SAME: tag: DW_TAG_structure_type + // MSVC-SAME: name: "named" + // MSVC-SAME: identifier: ".?AUnamed@?1??main@@9@" + // MSVC-SAME: ) + + // + // LINUX: [[TYPE_OF_FOUR:![0-9]+]] = distinct !DICompositeType( + // LINUX-SAME: tag: DW_TAG_class_type + // LINUX-NOT: name: + // LINUX-NOT: identifier: + // LINUX-SAME: ) + // + // MSVC: [[TYPE_OF_FOUR:![0-9]+]] = distinct !DICompositeType + // MSVC-SAME: tag: DW_TAG_class_type + // MSVC-SAME: name: "" + // MSVC-SAME: identifier: ".?AV@?0??main@@9@" + // MSVC-SAME: ) + + // In CodeView, the LF_MFUNCTION entry for "bar()" refers to the forward // reference of the unnamed struct. Visual Studio requires a unique // identifier to match the LF_STRUCTURE forward reference to the definition. @@ -10,21 +64,11 @@ int main(int argc, char* argv[], char* arge[]) { struct { void bar() {} } one; // // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "one" - // LINUX-SAME: type: [[TYPE_OF_ONE:![0-9]+]] - // LINUX-SAME: ) - // LINUX: [[TYPE_OF_ONE]] = distinct !DICompositeType( - // LINUX-SAME: tag: DW_TAG_structure_type - // LINUX-NOT: name: - // LINUX-NOT: identifier: + // LINUX-SAME: type: [[TYPE_OF_ONE]] // LINUX-SAME: ) // // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "one" - // MSVC-SAME: type: [[TYPE_OF_ONE:![0-9]+]] - // MSVC-SAME: ) - // MSVC: [[TYPE_OF_ONE]] = distinct !DICompositeType - // MSVC-SAME: tag: DW_TAG_structure_type - // MSVC-SAME: name: "" - // MSVC-SAME: identifier: ".?AU@?1??main@@9@" + // MSVC-SAME: type: [[TYPE_OF_ONE]] // MSVC-SAME: ) @@ -36,21 +80,11 @@ int main(int argc, char* argv[], char* arge[]) { int decltype(two)::*ptr2unnamed = &decltype(two)::bar; // // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "two" - // LINUX-SAME: type: [[TYPE_OF_TWO:![0-9]+]] - // LINUX-SAME: ) - // LINUX: [[TYPE_OF_TWO]] = distinct !DICompositeType( - // LINUX-SAME: tag: DW_TAG_structure_type - // LINUX-NOT: name: - // LINUX-NOT: identifier: + // LINUX-SAME: type: [[TYPE_OF_TWO]] // LINUX-SAME: ) // // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "two" - // MSVC-SAME: type: [[TYPE_OF_TWO:![0-9]+]] - // MSVC-SAME: ) - // MSVC: [[TYPE_OF_TWO]] = distinct !DICompositeType - // MSVC-SAME: tag: DW_TAG_structure_type - // MSVC-SAME: name: "" - // MSVC-SAME: identifier: ".?AU@?2??main@@9@" + // MSVC-SAME: type: [[TYPE_OF_TWO]] // MSVC-SAME: ) @@ -61,21 +95,11 @@ int main(int argc, char* argv[], char* arge[]) { struct named { int bar; int named::* p2mem; } three = { 42, &named::bar }; // // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "three" - // LINUX-SAME: type: [[TYPE_OF_THREE:![0-9]+]] - // LINUX-SAME: ) - // LINUX: [[TYPE_OF_THREE]] = distinct !DICompositeType( - // LINUX-SAME: tag: DW_TAG_structure_type - // LINUX-SAME: name: "named" - // LINUX-NOT: identifier: + // LINUX-SAME: type: [[TYPE_OF_THREE]] // LINUX-SAME: ) // // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "three" - // MSVC-SAME: type: [[TYPE_OF_THREE:![0-9]+]] - // MSVC-SAME: ) - // MSVC: [[TYPE_OF_THREE]] = distinct !DICompositeType - // MSVC-SAME: tag: DW_TAG_structure_type - // MSVC-SAME: name: "named" - // MSVC-SAME: identifier: ".?AUnamed@?1??main@@9@" + // MSVC-SAME: type: [[TYPE_OF_THREE]] // MSVC-SAME: ) @@ -87,21 +111,11 @@ int main(int argc, char* argv[], char* arge[]) { auto four = [argc](int i) -> int { return argc == i ? 1 : 0; }; // // LINUX: !{{[0-9]+}} = !DILocalVariable(name: "four" - // LINUX-SAME: type: [[TYPE_OF_FOUR:![0-9]+]] - // LINUX-SAME: ) - // LINUX: [[TYPE_OF_FOUR]] = distinct !DICompositeType( - // LINUX-SAME: tag: DW_TAG_class_type - // LINUX-NOT: name: - // LINUX-NOT: identifier: + // LINUX-SAME: type: [[TYPE_OF_FOUR]] // LINUX-SAME: ) // // MSVC: !{{[0-9]+}} = !DILocalVariable(name: "four" - // MSVC-SAME: type: [[TYPE_OF_FOUR:![0-9]+]] - // MSVC-SAME: ) - // MSVC: [[TYPE_OF_FOUR]] = distinct !DICompositeType - // MSVC-SAME: tag: DW_TAG_class_type - // MSVC-SAME: name: "" - // MSVC-SAME: identifier: ".?AV@?0??main@@9@" + // MSVC-SAME: type: [[TYPE_OF_FOUR]] // MSVC-SAME: ) return 0; diff --git a/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp b/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp index 6b9c9a243decd..122e4aa62ea7d 100644 --- a/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp +++ b/clang/test/CodeGenCXX/debug-info-gline-tables-only-codeview.cpp @@ -51,9 +51,9 @@ void test() { // CHECK-SAME: name: "", c.lambda_params(); - // CHECK: !DISubprogram(name: "operator()", scope: ![[LAMBDA1:[0-9]+]], - // CHECK: ![[LAMBDA1]] = !DICompositeType(tag: DW_TAG_class_type, + // CHECK: ![[LAMBDA1:[0-9]+]] = !DICompositeType(tag: DW_TAG_class_type, // CHECK-SAME: name: "", // CHECK-SAME: flags: DIFlagFwdDecl + // CHECK: !DISubprogram(name: "operator()", scope: ![[LAMBDA1]], c.lambda2(); } diff --git a/clang/test/CodeGenCXX/debug-lambda-this.cpp b/clang/test/CodeGenCXX/debug-lambda-this.cpp index eecbac6520ac9..3d659e7bfd004 100644 --- a/clang/test/CodeGenCXX/debug-lambda-this.cpp +++ b/clang/test/CodeGenCXX/debug-lambda-this.cpp @@ -13,10 +13,10 @@ int D::d(int x) { } // CHECK: ![[D:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "D", -// CHECK: ![[POINTER:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[D]], size: 64) // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "this", // CHECK-SAME: line: 11 -// CHECK-SAME: baseType: ![[POINTER]] +// CHECK-SAME: baseType: ![[POINTER:[0-9]+]] // CHECK-SAME: size: 64 // CHECK-NOT: offset: 0 // CHECK-SAME: ){{$}} +// CHECK: ![[POINTER]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[D]], size: 64) diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index ecd6dd7b0a4f8..0aa180aec6d8a 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -49,7 +49,7 @@ namespace llvm { Function *LabelFn; ///< llvm.dbg.label Function *AssignFn; ///< llvm.dbg.assign - SmallVector AllEnumTypes; + SmallVector EnumTypes; /// Track the RetainTypes, since they can be updated later on. SmallVector AllRetainTypes; SmallVector AllSubprograms; @@ -64,8 +64,8 @@ namespace llvm { SmallVector UnresolvedNodes; bool AllowUnresolvedNodes; - /// Each subprogram's preserved local variables, labels and imported - /// entities. + /// Each subprogram's preserved local variables, labels, imported entities, + /// and types. /// /// Do not use a std::vector. Some versions of libc++ apparently copy /// instead of move on grow operations, and TrackingMDRef is expensive to diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 0a9a80688a419..321eae6fcb3b5 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -548,6 +548,8 @@ class MetadataLoader::MetadataLoaderImpl { /// Move local imports from DICompileUnit's 'imports' field to /// DISubprogram's retainedNodes. + /// Move fucntion-local enums from DICompileUnit's enums + /// to DISubprogram's retainedNodes. void upgradeCULocals() { if (NamedMDNode *CUNodes = TheModule.getNamedMetadata("llvm.dbg.cu")) { for (unsigned I = 0, E = CUNodes->getNumOperands(); I != E; ++I) { @@ -555,48 +557,71 @@ class MetadataLoader::MetadataLoaderImpl { if (!CU) continue; - if (auto *RawImported = CU->getRawImportedEntities()) { - // Collect a set of imported entities to be moved. - SetVector EntitiesToRemove; + SetVector MetadataToRemove; + // Collect imported entities to be moved. + if (CU->getRawImportedEntities()) { for (Metadata *Op : CU->getImportedEntities()->operands()) { auto *IE = cast(Op); - if (auto *S = dyn_cast_or_null(IE->getScope())) { - EntitiesToRemove.insert(IE); + if (dyn_cast_or_null(IE->getScope())) { + MetadataToRemove.insert(IE); } } + } + // Collect enums to be moved. + if (CU->getRawEnumTypes()) { + for (Metadata *Op : CU->getEnumTypes()->operands()) { + auto *Enum = cast(Op); + if (dyn_cast_or_null(Enum->getScope())) { + MetadataToRemove.insert(Enum); + } + } + } - if (!EntitiesToRemove.empty()) { - // Make a new list of CU's 'imports'. - SmallVector NewImports; - for (Metadata *Op : CU->getImportedEntities()->operands()) { - if (!EntitiesToRemove.contains(cast(Op))) { + if (!MetadataToRemove.empty()) { + // Make a new list of CU's 'imports'. + SmallVector NewImports; + if (CU->getRawImportedEntities()) + for (Metadata *Op : CU->getImportedEntities()->operands()) + if (!MetadataToRemove.contains(Op)) NewImports.push_back(Op); - } - } - // Find DISubprogram corresponding to each entity. - std::map> SPToEntities; - for (auto *I : EntitiesToRemove) { - auto *Entity = cast(I); - if (auto *SP = findEnclosingSubprogram( - cast(Entity->getScope()))) { - SPToEntities[SP].push_back(Entity); - } + // Make a new list of CU's 'enums'. + SmallVector NewEnums; + if (CU->getRawEnumTypes()) + for (Metadata *Op : CU->getEnumTypes()->operands()) + if (!MetadataToRemove.contains(Op)) + NewEnums.push_back(Op); + + // Find DISubprogram corresponding to each entity. + std::map> SPToEntities; + for (auto *I : MetadataToRemove) { + DILocalScope *Scope = nullptr; + if (auto *Entity = dyn_cast(I)) + Scope = cast(Entity->getScope()); + else if (auto *Enum = dyn_cast(I)) + Scope = cast(Enum->getScope()); + + if (auto *SP = findEnclosingSubprogram(Scope)) { + SPToEntities[SP].push_back(I); } + } - // Update DISubprograms' retainedNodes. - for (auto I = SPToEntities.begin(); I != SPToEntities.end(); ++I) { - auto *SP = I->first; - auto RetainedNodes = SP->getRetainedNodes(); - SmallVector MDs(RetainedNodes.begin(), - RetainedNodes.end()); - MDs.append(I->second); - SP->replaceRetainedNodes(MDNode::get(Context, MDs)); - } + // Update DISubprograms' retainedNodes. + for (auto I = SPToEntities.begin(); I != SPToEntities.end(); ++I) { + auto *SP = I->first; + auto RetainedNodes = SP->getRetainedNodes(); + SmallVector MDs(RetainedNodes.begin(), + RetainedNodes.end()); + MDs.append(I->second); + SP->replaceRetainedNodes(MDNode::get(Context, MDs)); + } - // Remove entities with local scope from CU. + // Remove entities with local scope from CU. + if (CU->getRawImportedEntities()) CU->replaceImportedEntities(MDTuple::get(Context, NewImports)); - } + // Remove enums with local scope from CU. + if (CU->getRawEnumTypes()) + CU->replaceEnumTypes(MDTuple::get(Context, NewEnums)); } } } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 58ed21379d29b..bf8bdbb7da49f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -598,10 +598,9 @@ void DwarfCompileUnit::constructScopeDIE(LexicalScope *Scope, return; // Emit lexical blocks. - DIE *ScopeDIE = constructLexicalScopeDIE(Scope); + DIE *ScopeDIE = getOrCreateLexicalBlockDIE(Scope, ParentScopeDIE); assert(ScopeDIE && "Scope DIE should not be null."); - ParentScopeDIE.addChild(ScopeDIE); createAndAddScopeChildren(Scope, *ScopeDIE); } @@ -721,24 +720,39 @@ DIE *DwarfCompileUnit::constructInlinedScopeDIE(LexicalScope *Scope, return ScopeDIE; } -// Construct new DW_TAG_lexical_block for this scope and attach -// DW_AT_low_pc/DW_AT_high_pc labels. -DIE *DwarfCompileUnit::constructLexicalScopeDIE(LexicalScope *Scope) { +DIE *DwarfCompileUnit::getOrCreateLexicalBlockDIE(LexicalScope *Scope, + DIE &ParentScopeDIE) { if (DD->isLexicalScopeDIENull(Scope)) return nullptr; const auto *DS = Scope->getScopeNode(); - - auto ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_lexical_block); - if (Scope->isAbstractScope()) { - assert(!getAbstractScopeDIEs().count(DS) && - "Abstract DIE for this scope exists!"); - getAbstractScopeDIEs()[DS] = ScopeDIE; - return ScopeDIE; + DIE *ScopeDIE = nullptr; + + // FIXME: We may have a concrete DIE for this scope already created. + // This may happen when we emit local variables for an abstract tree of + // an inlined function: if a local variable has a templated type with + // a function-local type as a template parameter. See PR55680 for details + // (see also llvm/test/DebugInfo/Generic/local-type-as-template-parameter.ll). + if (!Scope->isAbstractScope() && !Scope->getInlinedAt()) { + if (auto It = LexicalBlockDIEs.find(DS); It != LexicalBlockDIEs.end()) { + ScopeDIE = It->second; + assert(!ScopeDIE->findAttribute(dwarf::DW_AT_low_pc) && + !ScopeDIE->findAttribute(dwarf::DW_AT_ranges)); + assert(ScopeDIE->getParent() == &ParentScopeDIE); + } } - if (!Scope->getInlinedAt()) { - assert(!LexicalBlockDIEs.count(DS) && - "Concrete out-of-line DIE for this scope exists!"); - LexicalBlockDIEs[DS] = ScopeDIE; + if (!ScopeDIE) { + ScopeDIE = DIE::get(DIEValueAllocator, dwarf::DW_TAG_lexical_block); + ParentScopeDIE.addChild(ScopeDIE); + + if (Scope->isAbstractScope()) { + assert(!getAbstractScopeDIEs().count(DS) && + "Abstract DIE for this scope exists!"); + getAbstractScopeDIEs()[DS] = ScopeDIE; + return ScopeDIE; + } + + if (!Scope->getInlinedAt()) + LexicalBlockDIEs[DS] = ScopeDIE; } attachRangesOrLowHighPC(*ScopeDIE, Scope->getRanges()); @@ -1681,15 +1695,21 @@ void DwarfCompileUnit::createBaseTypeDIEs() { } } -DIE *DwarfCompileUnit::getLexicalBlockDIE(const DILexicalBlock *LB) { +DIE *DwarfCompileUnit::getLocalContextDIE(const DILexicalBlock *LB) { // Assume if there is an abstract tree all the DIEs are already emitted. bool isAbstract = getAbstractScopeDIEs().count(LB->getSubprogram()); if (isAbstract && getAbstractScopeDIEs().count(LB)) return getAbstractScopeDIEs()[LB]; assert(!isAbstract && "Missed lexical block DIE in abstract tree!"); - // Return a concrete DIE if it exists or nullptr otherwise. - return LexicalBlockDIEs.lookup(LB); + // Check if we have a concrete DIE. + if (auto It = LexicalBlockDIEs.find(LB); It != LexicalBlockDIEs.end()) + return It->second; + + // If nothing available found, we cannot just create a new lexical block, + // because it isn't known where to put it into the DIE tree. + // So, we may only try to find the most close avaiable parent DIE. + return getOrCreateContextDIE(LB->getScope()->getNonLexicalBlockFileScope()); } DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) { @@ -1697,7 +1717,7 @@ DIE *DwarfCompileUnit::getOrCreateContextDIE(const DIScope *Context) { if (auto *LFScope = dyn_cast(Context)) Context = LFScope->getNonLexicalBlockFileScope(); if (auto *LScope = dyn_cast(Context)) - return getLexicalBlockDIE(LScope); + return getLocalContextDIE(LScope); // Otherwise the context must be a DISubprogram. auto *SPScope = cast(Context); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 6ef73ebd4f7f2..5662087bec322 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -210,14 +210,9 @@ class DwarfCompileUnit final : public DwarfUnit { /// DIE to represent this concrete inlined copy of the function. DIE *constructInlinedScopeDIE(LexicalScope *Scope, DIE &ParentScopeDIE); - /// Construct new DW_TAG_lexical_block for this scope and - /// attach DW_AT_low_pc/DW_AT_high_pc labels. - DIE *constructLexicalScopeDIE(LexicalScope *Scope); - - /// Get a DIE for the given DILexicalBlock. - /// Note that this function assumes that the DIE has been already created - /// and it's an error, if it hasn't. - DIE *getLexicalBlockDIE(const DILexicalBlock *LB); + /// Get if available or create a new DW_TAG_lexical_block for the given + /// LexicalScope and attach DW_AT_low_pc/DW_AT_high_pc labels. + DIE *getOrCreateLexicalBlockDIE(LexicalScope *Scope, DIE &ParentDIE); /// constructVariableDIE - Construct a DIE for the given DbgVariable. DIE *constructVariableDIE(DbgVariable &DV, bool Abstract = false); @@ -234,6 +229,11 @@ class DwarfCompileUnit final : public DwarfUnit { /// This instance of 'getOrCreateContextDIE()' can handle DILocalScope. DIE *getOrCreateContextDIE(const DIScope *Ty) override; + /// Get DW_TAG_lexical_block for the given DILexicalBlock if available, + /// or the most close parent DIE, if no correspoding DW_TAG_lexical_block + /// exists. + DIE *getLocalContextDIE(const DILexicalBlock *LB); + /// Construct a DIE for this subprogram scope. DIE &constructSubprogramScopeDIE(const DISubprogram *Sub, LexicalScope *Scope); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index b8502b455f587..557291c97265f 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1229,12 +1229,13 @@ void DwarfDebug::beginModule(Module *M) { CU.getOrCreateGlobalVariableDIE(GV, sortGlobalExprs(GVMap[GV])); } - for (auto *Ty : CUNode->getEnumTypes()) + for (auto *Ty : CUNode->getEnumTypes()) { + assert(!isa_and_nonnull(Ty->getScope()) && + "Unexpected function-local entity in 'enums' CU field."); CU.getOrCreateTypeDIE(cast(Ty)); + } for (auto *Ty : CUNode->getRetainedTypes()) { - // The retained types array by design contains pointers to - // MDNodes rather than DIRefs. Unique them here. if (DIType *RT = dyn_cast(Ty)) // There is no point in force-emitting a forward declaration. CU.getOrCreateTypeDIE(RT); @@ -1428,9 +1429,13 @@ void DwarfDebug::endModule() { "Unexpected function-local entity in 'imports' CU field."); CU->getOrCreateImportedEntityDIE(IE); } + + // Emit function-local entities. for (const auto *D : CU->getDeferredLocalDecls()) { if (auto *IE = dyn_cast(D)) CU->getOrCreateImportedEntityDIE(IE); + else if (auto *Ty = dyn_cast(D)) + CU->getOrCreateTypeDIE(Ty); else llvm_unreachable("Unexpected local retained node!"); } @@ -1528,6 +1533,8 @@ static const DILocalScope *getRetainedNodeScope(const MDNode *N) { S = L->getScope(); else if (const auto *IE = dyn_cast(N)) S = IE->getScope(); + else if (const auto *T = dyn_cast(N)) + S = T->getScope(); else llvm_unreachable("Unexpected retained node!"); diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index ae1a1a37d7c74..242ca44794262 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -29,7 +29,7 @@ DIBuilder::DIBuilder(Module &m, bool AllowUnresolvedNodes, DICompileUnit *CU) AllowUnresolvedNodes(AllowUnresolvedNodes) { if (CUNode) { if (const auto &ETs = CUNode->getEnumTypes()) - AllEnumTypes.assign(ETs.begin(), ETs.end()); + EnumTypes.assign(ETs.begin(), ETs.end()); if (const auto &RTs = CUNode->getRetainedTypes()) AllRetainTypes.assign(RTs.begin(), RTs.end()); if (const auto &GVs = CUNode->getGlobalVariables()) @@ -66,10 +66,10 @@ void DIBuilder::finalize() { return; } - if (!AllEnumTypes.empty()) + if (!EnumTypes.empty()) CUNode->replaceEnumTypes(MDTuple::get( - VMContext, SmallVector(AllEnumTypes.begin(), - AllEnumTypes.end()))); + VMContext, SmallVector(EnumTypes.begin(), + EnumTypes.end()))); SmallVector RetainValues; // Declarations and definitions of the same type may be retained. Some @@ -334,10 +334,13 @@ DIDerivedType *DIBuilder::createTypedef(DIType *Ty, StringRef Name, DIScope *Context, uint32_t AlignInBits, DINode::DIFlags Flags, DINodeArray Annotations) { - return DIDerivedType::get(VMContext, dwarf::DW_TAG_typedef, Name, File, - LineNo, getNonCompileUnitScope(Context), Ty, 0, - AlignInBits, 0, std::nullopt, Flags, nullptr, - Annotations); + auto *T = + DIDerivedType::get(VMContext, dwarf::DW_TAG_typedef, Name, File, LineNo, + getNonCompileUnitScope(Context), Ty, 0, AlignInBits, 0, + std::nullopt, Flags, nullptr, Annotations); + if (isa_and_nonnull(Context)) + getSubprogramNodesTrackingVector(Context).emplace_back(T); + return T; } DIDerivedType *DIBuilder::createFriend(DIType *Ty, DIType *FriendTy) { @@ -485,6 +488,8 @@ DICompositeType *DIBuilder::createClassType( OffsetInBits, Flags, Elements, 0, VTableHolder, cast_or_null(TemplateParams), UniqueIdentifier); trackIfUnresolved(R); + if (isa_and_nonnull(Context)) + getSubprogramNodesTrackingVector(Context).emplace_back(R); return R; } @@ -498,6 +503,8 @@ DICompositeType *DIBuilder::createStructType( getNonCompileUnitScope(Context), DerivedFrom, SizeInBits, AlignInBits, 0, Flags, Elements, RunTimeLang, VTableHolder, nullptr, UniqueIdentifier); trackIfUnresolved(R); + if (isa_and_nonnull(Context)) + getSubprogramNodesTrackingVector(Context).emplace_back(R); return R; } @@ -510,6 +517,8 @@ DICompositeType *DIBuilder::createUnionType( getNonCompileUnitScope(Scope), nullptr, SizeInBits, AlignInBits, 0, Flags, Elements, RunTimeLang, nullptr, nullptr, UniqueIdentifier); trackIfUnresolved(R); + if (isa_and_nonnull(Scope)) + getSubprogramNodesTrackingVector(Scope).emplace_back(R); return R; } @@ -542,7 +551,10 @@ DICompositeType *DIBuilder::createEnumerationType( getNonCompileUnitScope(Scope), UnderlyingType, SizeInBits, AlignInBits, 0, IsScoped ? DINode::FlagEnumClass : DINode::FlagZero, Elements, 0, nullptr, nullptr, UniqueIdentifier); - AllEnumTypes.emplace_back(CTy); + if (isa_and_nonnull(Scope)) + getSubprogramNodesTrackingVector(Scope).emplace_back(CTy); + else + EnumTypes.emplace_back(CTy); trackIfUnresolved(CTy); return CTy; } @@ -640,6 +652,8 @@ DIBuilder::createForwardDecl(unsigned Tag, StringRef Name, DIScope *Scope, SizeInBits, AlignInBits, 0, DINode::FlagFwdDecl, nullptr, RuntimeLang, nullptr, nullptr, UniqueIdentifier); trackIfUnresolved(RetTy); + if (isa_and_nonnull(Scope)) + getSubprogramNodesTrackingVector(Scope).emplace_back(RetTy); return RetTy; } @@ -656,6 +670,8 @@ DICompositeType *DIBuilder::createReplaceableCompositeType( nullptr, Annotations) .release(); trackIfUnresolved(RetTy); + if (isa_and_nonnull(Scope)) + getSubprogramNodesTrackingVector(Scope).emplace_back(RetTy); return RetTy; } diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 293d443d754a4..8f929dc7f48ab 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1384,9 +1384,9 @@ void Verifier::visitDISubprogram(const DISubprogram &N) { CheckDI(Node, "invalid retained nodes list", &N, RawNode); for (Metadata *Op : Node->operands()) { CheckDI(Op && (isa(Op) || isa(Op) || - isa(Op)), - "invalid retained nodes, expected DILocalVariable, DILabel or " - "DIImportedEntity", + isa(Op) || isa(Op)), + "invalid retained nodes, expected DILocalVariable, DILabel, " + "DIImportedEntity or DIType", &N, Node, Op); } } diff --git a/llvm/test/Bitcode/upgrade-cu-locals.ll b/llvm/test/Bitcode/upgrade-cu-locals.ll index 9a590f0fc0774..7052ab379bea4 100644 --- a/llvm/test/Bitcode/upgrade-cu-locals.ll +++ b/llvm/test/Bitcode/upgrade-cu-locals.ll @@ -1,4 +1,4 @@ -; Test moving of local imports from DICompileUnit's 'imports' to DISubprogram's 'retainedNodes' +; Test moving of local imports/enums from DICompileUnit to DISubprogram's 'retainedNodes' ; ; RUN: llvm-dis -o - %s.bc | FileCheck %s @@ -31,31 +31,36 @@ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memo ; CHECK: !4 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t4" ; CHECK: !5 = !{} -; CHECK: !6 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !7, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !5, nameTableKind: GNU) - -; CHECK: !14 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 2, type: !15, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !18) -; CHECK: !18 = !{!19} -; CHECK: !19 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !20, entity: !23, -; CHECK: !20 = !DILexicalBlock(scope: !21, file: !7, line: 7, column: 35) -; CHECK: !21 = !DILexicalBlock(scope: !22, file: !7, line: 7, column: 35) -; CHECK: !22 = !DILexicalBlock(scope: !14, file: !7, line: 7, column: 35) -; CHECK: !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t5", scope: !20, - -; CHECK: !25 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !26, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !28) -; CHECK: !28 = !{!29, !32, !34} -; CHECK: !29 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !30, -; CHECK: !30 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", -; CHECK: !32 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !33, -; CHECK: !33 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", -; CHECK: !34 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !25, entity: !35, -; CHECK: !35 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t3", - -; CHECK: !40 = distinct !DISubprogram(name: "main2", scope: !7, file: !7, line: 10, type: !15, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !41) -; CHECK: !41 = !{!42, !44} -; CHECK: !42 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !40, entity: !43, -; CHECK: !43 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t6" -; CHECK: !44 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !40, entity: !45, -; CHECK: !45 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t7", +; CHECK: !6 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !7, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !8, imports: !5, nameTableKind: GNU) +; CHECK: !7 = !DIFile(filename: "b.cpp" +; CHECK: !8 = !{!9} +; CHECK: !9 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum2", scope: !6, file: !7, line: 4, size: 8, align: 8, elements: !5) + +; CHECK: !16 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 2, type: !17, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !20) +; CHECK: !20 = !{!21} +; CHECK: !21 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !22, entity: !25, +; CHECK: !22 = !DILexicalBlock(scope: !23, file: !7, line: 7, column: 35) +; CHECK: !23 = !DILexicalBlock(scope: !24, file: !7, line: 7, column: 35) +; CHECK: !24 = !DILexicalBlock(scope: !16, file: !7, line: 7, column: 35) +; CHECK: !25 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t5", scope: !22, + +; CHECK: !27 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 3, type: !28, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !30) +; CHECK: !30 = !{!31, !34, !36} +; CHECK: !31 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !27, entity: !32, +; CHECK: !32 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1", +; CHECK: !34 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !27, entity: !35, +; CHECK: !35 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t2", +; CHECK: !36 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !27, entity: !37, +; CHECK: !37 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t3", + +; CHECK: !42 = distinct !DISubprogram(name: "main2", scope: !7, file: !7, line: 10, type: !17, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !43) +; CHECK: !43 = !{!44, !46, !48, !49} +; CHECK: !44 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !42, entity: !45, +; CHECK: !45 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t6" +; CHECK: !46 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !42, entity: !47, +; CHECK: !47 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t7", +; CHECK: !48 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !42, file: !7, line: 3, size: 8, align: 8, elements: !5) +; CHECK: !49 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum3", scope: !42, file: !7, line: 5, size: 8, align: 8, elements: !5) !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !2, nameTableKind: GNU) @@ -82,7 +87,7 @@ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memo ; Leave t4 in CU !14 = !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !0, entity: !15, file: !1, line: 3) !15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t4", scope: !0, file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTSN2ns2t4E") -!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !17, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !18, nameTableKind: GNU) +!16 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !17, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, imports: !18, enums: !50, nameTableKind: GNU) !17 = !DIFile(filename: "b.cpp", directory: "/") !18 = !{!19, !28, !31} @@ -116,3 +121,12 @@ attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memo !41 = distinct !DILocation(line: 3, column: 3, scope: !23) !42 = !DILocation(line: 3, column: 41, scope: !4, inlinedAt: !41) !43 = !DILocation(line: 4, column: 1, scope: !23) + +!50 = !{!51, !52, !53} +; Move to main2 +!51 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !29, file: !17, line: 3, size: 8, align: 8, elements: !7) +; Leave in b.cpp's CU +!52 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum2", scope: !16, file: !17, line: 4, size: 8, align: 8, elements: !7) +; Move to main2 +!53 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum3", scope: !29, file: !17, line: 5, size: 8, align: 8, elements: !7) + diff --git a/llvm/test/Bitcode/upgrade-cu-locals.ll.bc b/llvm/test/Bitcode/upgrade-cu-locals.ll.bc index 9d0ea8fd9a3704ea1fb3a92250500addc75f0587..f73d05668af5b16f9ee03e400e2877faab339a0d 100644 GIT binary patch delta 1080 zcmYk5e`p(J7{{NxT<^v2T79^Yj3eX zCa4ST^$4!hY-CFq`$I=`D*iELuKy_e=R!ISm`cGRL56hTA0ibxhWMA%_q{6H%X`oB z-1ohE-p}*!zJ}+nr}PA4Tzv8e=ETMO&yU}{_3PDJt*yNt=um-!|A&k}H9J|6zN*x) zz`pltPnw1RR8~Q?N^cBEwg8N+ilr9PDjEQ4=T<*p+z#fi@<&_{iTssC`dw0W77=EH z*c_9SV-gA2gRx8VvGQFm-JQ(6b&5U_YNDso)49lW?sWONHl>_yJF*18yXh_f*wo~p zm<*emHz?jF4h4_b4>b}uctVLpliLG87yzu1pRs>l{*5sRvWb=j0!DRwX=wDE!o5S^ zOf<4d(z>W#%y#_LCnWZe`V1s?y-g$s)sK#yRhD8G6zL2mOMNo{bO~2Hg=K}-PyV<3 zq#>kxqe*`rGx=)KWD%^aF+h`3j$?WG#v>f#G%w}o32^!&9A2suj-yWr%l!{I44%|a zL4<$~0r4859CHsjn1Ia@0;sw`ra%slionW?#uo{nWGL`pFMPtkj$s~}XJN(nVGSA# z4zOq@#XFE-No&eR!r!V%R>}e1C})ip;CBXV%(E=PadK-*f}AheRU;84oDiwJ=Y7|E^bU zPf#aaZ~liW_I^`?Z3Zt9R(*qaScJ9SUwv_3QfX~?T-W%k-X<>8UgL=j zd}ekQW|i;f7Vq_tsi(X3-JsT;L+v-o1XsyBp4;T7(%n-D;dAR-CSw{Q6hxpZ$6M`h_o> zw~J42>AA|JXZ&N&#J$xHv5k3on>Xg(ukv3b;h>Lna+U<_nRGCQVoQRnT!plNqI)a{8Ff@)_sAV5(!c!vJ$=_ozlX z<-P*D&c#bd?4=WAs{s;qIV!309p_*u{7g7Dd~zy26wOR#W081lI2)ci5Q#<(#PJXw bjz`1MY<74kUf$B@aE3>`OdxH z`DW%Ebf_IG{nX^@Bi~TU>Tgesr^SEYyYtha=j~yWY!HBg<7MPOE-e79rviCYP}RO~ z{gy^qhXoMu+C9!tM`Yd7K=*rCbF3X;nZdEU$I902B_4N`Kn>%1fgo0Y`Gqk@ou2o|DYupHkvUM?9G>Oq(ubP_5n(a4sm= zSie0NwAk3VXnE9Y+cR78YGZ0=kSKu|xb4S$DwriFb<1z>Yhhyjpv9A9-m_myaT zL(g*3@Li&q)A9VPEq8uL*&bj)mDsk61ggK}NN7uR?PWy%O-xFsCjs;lE_N)IMV>_D zKJvPZ8&dgmG{g!t_+n1JiKi&Q4*X8vq zpX}VuKUzy9i#hYNWpjYqoMKH>Ktt-x;^$Xi)Hp1+A%zQVaK+&J4", directory: "/") +!2 = !{!3, !10} +!3 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Y", scope: !5, file: !4, line: 2, size: 8, flags: DIFlagTypePassByValue, elements: !8) +!4 = !DIFile(filename: "test.cpp", directory: "/") +!5 = distinct !DISubprogram(name: "test_unused", linkageName: "_Z11test_unusedv", scope: !4, file: !4, line: 1, type: !6, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !9) +!6 = !DISubroutineType(types: !7) +!7 = !{null} +!8 = !{} +!9 = !{!3, !10} +!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", scope: !11, file: !4, line: 4, size: 8, flags: DIFlagTypePassByValue, elements: !8) +!11 = distinct !DILexicalBlock(scope: !5, file: !4, line: 3, column: 3) +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 15.0.0"} +!16 = !DILocation(line: 6, column: 1, scope: !5) diff --git a/llvm/test/DebugInfo/Generic/lexical-block-types.ll b/llvm/test/DebugInfo/Generic/lexical-block-types.ll new file mode 100644 index 0000000000000..aef59984351a7 --- /dev/null +++ b/llvm/test/DebugInfo/Generic/lexical-block-types.ll @@ -0,0 +1,425 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s | llvm-dwarfdump -debug-info - | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s +; REQUIRES: object-emission + +; inline __attribute__((always_inline)) +; void removed() { +; struct A1 { int i; }; +; typedef int Int1; +; { +; struct I1 { Int1 j; }; +; struct C1 { typedef char Char1; Char1 c; }; +; A1 a1; a1.i++; +; { +; I1 i1; i1.j++; +; C1 c1; c1.c++; +; } +; } +; } +; +; __attribute__((always_inline)) +; void not_removed() { +; struct A2 { int i; }; +; typedef int Int2; +; { +; struct I2 { Int2 j; }; +; struct C2 { typedef char Char2; Char2 c; }; +; A2 a2; a2.i++; +; { +; I2 i2; i2.j++; +; C2 c2; c2.c++; +; } +; } +; } +; +; void foo() { +; struct A3 { int i; }; +; typedef int Int3; +; { +; struct I3 { Int3 j; }; +; { +; struct C3 { typedef char Char3; Char3 c; }; +; A3 a3; a3.i++; +; { +; I3 i3; i3.j++; +; C3 c3; c3.c++; +; } +; } +; } +; removed(); +; not_removed(); +; } +; +; CHECK: DW_TAG_compile_unit + +; Out-of-line definition of `not_removed()` shouldn't contain any debug info for types. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "a2" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "i2" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "c2" +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; Abstract definition of `removed()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("removed") +; CHECK: DW_AT_inline (DW_INL_inlined) + +; I1 and C1 defined in the first lexical block, typedef Char1 is a child of C1. +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a1") +; CHECK: DW_AT_type {{.*}} "A1" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type {{.*}} "I1" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_type {{.*}} "C1" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I1") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int1" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C1") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Char1" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char1") +; CHECK: NULL +; CHECK: NULL + +; A1 and typedef Int1 defined in the subprogram scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A1") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int1") +; CHECK: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_TAG_base_type + +; Abstract definition of `not_removed()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("not_removed") +; CHECK: DW_AT_inline (DW_INL_inlined) + +; I2 and C2 defined in the first lexical block, typedef Char2 is a child of C2. +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a2") +; CHECK: DW_AT_type {{.*}} "A2" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("i2") +; CHECK: DW_AT_type {{.*}} "I2" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("c2") +; CHECK: DW_AT_type {{.*}} "C2" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I2") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int2" +; CHECK: NULL +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C2") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Char2" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char2") +; CHECK: NULL +; CHECK: NULL + +; A2 and typedef Int2 defined in subprogram scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A2") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int2") +; CHECK: NULL + +; Definition of `foo()`. +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") + +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("a3") +; CHECK: DW_AT_type {{.*}} "A3" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("i3") +; CHECK: DW_AT_type {{.*}} "I3" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("c3") +; CHECK: DW_AT_type {{.*}} "C3" +; CHECK: NULL + +; C3 has the inner lexical block scope, typedef Char3 is a child of C3. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("C3") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Char3" +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Char3") +; CHECK: NULL +; CHECK: NULL + +; I3 has the outer lexical block scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("I3") +; CHECK: DW_TAG_member +; CHECK: DW_AT_type {{.*}} "Int3" +; CHECK: NULL +; CHECK: NULL + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z7removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z11not_removedv" +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_lexical_block +; CHECK: DW_TAG_variable +; CHECK: DW_TAG_variable +; CHECK: NULL +; CHECK: NULL +; CHECK: NULL + +; A3 and Int3 defined within the subprogam scope. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("A3") +; CHECK: DW_TAG_member +; CHECK: NULL +; CHECK: DW_TAG_typedef +; CHECK: DW_AT_name ("Int3") +; CHECK: NULL +; CHECK: NULL + +%struct.A2 = type { i32 } +%struct.I2 = type { i32 } +%struct.C2 = type { i8 } +%struct.A1 = type { i32 } +%struct.I1 = type { i32 } +%struct.C1 = type { i8 } +%struct.A3 = type { i32 } +%struct.I3 = type { i32 } +%struct.C3 = type { i8 } + +define dso_local void @_Z11not_removedv() !dbg !8 { +entry: + %a2 = alloca %struct.A2, align 4 + %i2 = alloca %struct.I2, align 4 + %c2 = alloca %struct.C2, align 1 + call void @llvm.dbg.declare(metadata %struct.A2* %a2, metadata !12, metadata !DIExpression()), !dbg !18 + %i = getelementptr inbounds %struct.A2, %struct.A2* %a2, i32 0, i32 0, !dbg !19 + %0 = load i32, i32* %i, align 4, !dbg !20 + %inc = add nsw i32 %0, 1, !dbg !20 + store i32 %inc, i32* %i, align 4, !dbg !20 + call void @llvm.dbg.declare(metadata %struct.I2* %i2, metadata !21, metadata !DIExpression()), !dbg !27 + %j = getelementptr inbounds %struct.I2, %struct.I2* %i2, i32 0, i32 0, !dbg !28 + %1 = load i32, i32* %j, align 4, !dbg !29 + %inc1 = add nsw i32 %1, 1, !dbg !29 + store i32 %inc1, i32* %j, align 4, !dbg !29 + call void @llvm.dbg.declare(metadata %struct.C2* %c2, metadata !30, metadata !DIExpression()), !dbg !36 + %c = getelementptr inbounds %struct.C2, %struct.C2* %c2, i32 0, i32 0, !dbg !37 + %2 = load i8, i8* %c, align 1, !dbg !38 + %inc2 = add i8 %2, 1, !dbg !38 + store i8 %inc2, i8* %c, align 1, !dbg !38 + ret void, !dbg !39 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +define dso_local void @_Z3foov() !dbg !40 { +entry: + %a1.i = alloca %struct.A1, align 4 + %i1.i = alloca %struct.I1, align 4 + %c1.i = alloca %struct.C1, align 1 + %a2.i = alloca %struct.A2, align 4 + %i2.i = alloca %struct.I2, align 4 + %c2.i = alloca %struct.C2, align 1 + %a3 = alloca %struct.A3, align 4 + %i3 = alloca %struct.I3, align 4 + %c3 = alloca %struct.C3, align 1 + call void @llvm.dbg.declare(metadata %struct.A3* %a3, metadata !41, metadata !DIExpression()), !dbg !47 + %i = getelementptr inbounds %struct.A3, %struct.A3* %a3, i32 0, i32 0, !dbg !48 + %0 = load i32, i32* %i, align 4, !dbg !49 + %inc = add nsw i32 %0, 1, !dbg !49 + store i32 %inc, i32* %i, align 4, !dbg !49 + call void @llvm.dbg.declare(metadata %struct.I3* %i3, metadata !50, metadata !DIExpression()), !dbg !56 + %j = getelementptr inbounds %struct.I3, %struct.I3* %i3, i32 0, i32 0, !dbg !57 + %1 = load i32, i32* %j, align 4, !dbg !58 + %inc1 = add nsw i32 %1, 1, !dbg !58 + store i32 %inc1, i32* %j, align 4, !dbg !58 + call void @llvm.dbg.declare(metadata %struct.C3* %c3, metadata !59, metadata !DIExpression()), !dbg !64 + %c = getelementptr inbounds %struct.C3, %struct.C3* %c3, i32 0, i32 0, !dbg !65 + %2 = load i8, i8* %c, align 1, !dbg !66 + %inc2 = add i8 %2, 1, !dbg !66 + store i8 %inc2, i8* %c, align 1, !dbg !66 + call void @llvm.dbg.declare(metadata %struct.A1* %a1.i, metadata !67, metadata !DIExpression()), !dbg !73 + %i.i3 = getelementptr inbounds %struct.A1, %struct.A1* %a1.i, i32 0, i32 0, !dbg !75 + %3 = load i32, i32* %i.i3, align 4, !dbg !76 + %inc.i4 = add nsw i32 %3, 1, !dbg !76 + store i32 %inc.i4, i32* %i.i3, align 4, !dbg !76 + call void @llvm.dbg.declare(metadata %struct.I1* %i1.i, metadata !77, metadata !DIExpression()), !dbg !83 + %j.i5 = getelementptr inbounds %struct.I1, %struct.I1* %i1.i, i32 0, i32 0, !dbg !84 + %4 = load i32, i32* %j.i5, align 4, !dbg !85 + %inc1.i6 = add nsw i32 %4, 1, !dbg !85 + store i32 %inc1.i6, i32* %j.i5, align 4, !dbg !85 + call void @llvm.dbg.declare(metadata %struct.C1* %c1.i, metadata !86, metadata !DIExpression()), !dbg !91 + %c.i7 = getelementptr inbounds %struct.C1, %struct.C1* %c1.i, i32 0, i32 0, !dbg !92 + %5 = load i8, i8* %c.i7, align 1, !dbg !93 + %inc2.i8 = add i8 %5, 1, !dbg !93 + store i8 %inc2.i8, i8* %c.i7, align 1, !dbg !93 + call void @llvm.dbg.declare(metadata %struct.A2* %a2.i, metadata !12, metadata !DIExpression()), !dbg !94 + %i.i = getelementptr inbounds %struct.A2, %struct.A2* %a2.i, i32 0, i32 0, !dbg !96 + %6 = load i32, i32* %i.i, align 4, !dbg !97 + %inc.i = add nsw i32 %6, 1, !dbg !97 + store i32 %inc.i, i32* %i.i, align 4, !dbg !97 + call void @llvm.dbg.declare(metadata %struct.I2* %i2.i, metadata !21, metadata !DIExpression()), !dbg !98 + %j.i = getelementptr inbounds %struct.I2, %struct.I2* %i2.i, i32 0, i32 0, !dbg !99 + %7 = load i32, i32* %j.i, align 4, !dbg !100 + %inc1.i = add nsw i32 %7, 1, !dbg !100 + store i32 %inc1.i, i32* %j.i, align 4, !dbg !100 + call void @llvm.dbg.declare(metadata %struct.C2* %c2.i, metadata !30, metadata !DIExpression()), !dbg !101 + %c.i = getelementptr inbounds %struct.C2, %struct.C2* %c2.i, i32 0, i32 0, !dbg !102 + %8 = load i8, i8* %c.i, align 1, !dbg !103 + %inc2.i = add i8 %8, 1, !dbg !103 + store i8 %inc2.i, i8* %c.i, align 1, !dbg !103 + ret void, !dbg !104 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5, !6} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/") +!2 = !{i32 7, !"Dwarf Version", i32 4} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{i32 7, !"frame-pointer", i32 2} +!7 = !{!"clang version 14.0.0"} +!8 = distinct !DISubprogram(name: "not_removed", linkageName: "_Z11not_removedv", scope: !1, file: !1, line: 17, type: !9, scopeLine: 17, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !105) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !{} +!12 = !DILocalVariable(name: "a2", scope: !13, file: !1, line: 23, type: !14) +!13 = distinct !DILexicalBlock(scope: !8, file: !1, line: 20, column: 3) +!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A2", scope: !8, file: !1, line: 18, size: 32, flags: DIFlagTypePassByValue, elements: !15) +!15 = !{!16} +!16 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !14, file: !1, line: 18, baseType: !17, size: 32) +!17 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!18 = !DILocation(line: 23, column: 8, scope: !13) +!19 = !DILocation(line: 23, column: 15, scope: !13) +!20 = !DILocation(line: 23, column: 16, scope: !13) +!21 = !DILocalVariable(name: "i2", scope: !22, file: !1, line: 25, type: !23) +!22 = distinct !DILexicalBlock(scope: !13, file: !1, line: 24, column: 5) +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I2", scope: !13, file: !1, line: 21, size: 32, flags: DIFlagTypePassByValue, elements: !24) +!24 = !{!25} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !23, file: !1, line: 21, baseType: !26, size: 32) +!26 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int2", scope: !8, file: !1, line: 19, baseType: !17) +!27 = !DILocation(line: 25, column: 10, scope: !22) +!28 = !DILocation(line: 25, column: 17, scope: !22) +!29 = !DILocation(line: 25, column: 18, scope: !22) +!30 = !DILocalVariable(name: "c2", scope: !22, file: !1, line: 26, type: !31) +!31 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C2", scope: !13, file: !1, line: 22, size: 8, flags: DIFlagTypePassByValue, elements: !32) +!32 = !{!33} +!33 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !31, file: !1, line: 22, baseType: !34, size: 8) +!34 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char2", scope: !31, file: !1, line: 22, baseType: !35) +!35 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!36 = !DILocation(line: 26, column: 10, scope: !22) +!37 = !DILocation(line: 26, column: 17, scope: !22) +!38 = !DILocation(line: 26, column: 18, scope: !22) +!39 = !DILocation(line: 29, column: 1, scope: !8) +!40 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 31, type: !9, scopeLine: 31, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !107) +!41 = !DILocalVariable(name: "a3", scope: !42, file: !1, line: 38, type: !44) +!42 = distinct !DILexicalBlock(scope: !43, file: !1, line: 36, column: 5) +!43 = distinct !DILexicalBlock(scope: !40, file: !1, line: 34, column: 3) +!44 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A3", scope: !40, file: !1, line: 32, size: 32, flags: DIFlagTypePassByValue, elements: !45) +!45 = !{!46} +!46 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !44, file: !1, line: 32, baseType: !17, size: 32) +!47 = !DILocation(line: 38, column: 10, scope: !42) +!48 = !DILocation(line: 38, column: 17, scope: !42) +!49 = !DILocation(line: 38, column: 18, scope: !42) +!50 = !DILocalVariable(name: "i3", scope: !51, file: !1, line: 40, type: !52) +!51 = distinct !DILexicalBlock(scope: !42, file: !1, line: 39, column: 7) +!52 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I3", scope: !43, file: !1, line: 35, size: 32, flags: DIFlagTypePassByValue, elements: !53) +!53 = !{!54} +!54 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !52, file: !1, line: 35, baseType: !55, size: 32) +!55 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int3", scope: !40, file: !1, line: 33, baseType: !17) +!56 = !DILocation(line: 40, column: 12, scope: !51) +!57 = !DILocation(line: 40, column: 19, scope: !51) +!58 = !DILocation(line: 40, column: 20, scope: !51) +!59 = !DILocalVariable(name: "c3", scope: !51, file: !1, line: 41, type: !60) +!60 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C3", scope: !42, file: !1, line: 37, size: 8, flags: DIFlagTypePassByValue, elements: !61) +!61 = !{!62} +!62 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !60, file: !1, line: 37, baseType: !63, size: 8) +!63 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char3", scope: !60, file: !1, line: 37, baseType: !35) +!64 = !DILocation(line: 41, column: 12, scope: !51) +!65 = !DILocation(line: 41, column: 19, scope: !51) +!66 = !DILocation(line: 41, column: 20, scope: !51) +!67 = !DILocalVariable(name: "a1", scope: !68, file: !1, line: 8, type: !70) +!68 = distinct !DILexicalBlock(scope: !69, file: !1, line: 5, column: 3) +!69 = distinct !DISubprogram(name: "removed", linkageName: "_Z7removedv", scope: !1, file: !1, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !110) +!70 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A1", scope: !69, file: !1, line: 3, size: 32, flags: DIFlagTypePassByValue, elements: !71, identifier: "_ZTSZ7removedvE2A1") +!71 = !{!72} +!72 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !70, file: !1, line: 3, baseType: !17, size: 32) +!73 = !DILocation(line: 8, column: 8, scope: !68, inlinedAt: !74) +!74 = distinct !DILocation(line: 45, column: 3, scope: !40) +!75 = !DILocation(line: 8, column: 15, scope: !68, inlinedAt: !74) +!76 = !DILocation(line: 8, column: 16, scope: !68, inlinedAt: !74) +!77 = !DILocalVariable(name: "i1", scope: !78, file: !1, line: 10, type: !79) +!78 = distinct !DILexicalBlock(scope: !68, file: !1, line: 9, column: 5) +!79 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "I1", scope: !68, file: !1, line: 6, size: 32, flags: DIFlagTypePassByValue, elements: !80, identifier: "_ZTSZ7removedvE2I1") +!80 = !{!81} +!81 = !DIDerivedType(tag: DW_TAG_member, name: "j", scope: !79, file: !1, line: 6, baseType: !82, size: 32) +!82 = !DIDerivedType(tag: DW_TAG_typedef, name: "Int1", scope: !69, file: !1, line: 4, baseType: !17) +!83 = !DILocation(line: 10, column: 10, scope: !78, inlinedAt: !74) +!84 = !DILocation(line: 10, column: 17, scope: !78, inlinedAt: !74) +!85 = !DILocation(line: 10, column: 18, scope: !78, inlinedAt: !74) +!86 = !DILocalVariable(name: "c1", scope: !78, file: !1, line: 11, type: !87) +!87 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C1", scope: !68, file: !1, line: 7, size: 8, flags: DIFlagTypePassByValue, elements: !88, identifier: "_ZTSZ7removedvE2C1") +!88 = !{!89} +!89 = !DIDerivedType(tag: DW_TAG_member, name: "c", scope: !87, file: !1, line: 7, baseType: !90, size: 8) +!90 = !DIDerivedType(tag: DW_TAG_typedef, name: "Char1", scope: !87, file: !1, line: 7, baseType: !35) +!91 = !DILocation(line: 11, column: 10, scope: !78, inlinedAt: !74) +!92 = !DILocation(line: 11, column: 17, scope: !78, inlinedAt: !74) +!93 = !DILocation(line: 11, column: 18, scope: !78, inlinedAt: !74) +!94 = !DILocation(line: 23, column: 8, scope: !13, inlinedAt: !95) +!95 = distinct !DILocation(line: 46, column: 3, scope: !40) +!96 = !DILocation(line: 23, column: 15, scope: !13, inlinedAt: !95) +!97 = !DILocation(line: 23, column: 16, scope: !13, inlinedAt: !95) +!98 = !DILocation(line: 25, column: 10, scope: !22, inlinedAt: !95) +!99 = !DILocation(line: 25, column: 17, scope: !22, inlinedAt: !95) +!100 = !DILocation(line: 25, column: 18, scope: !22, inlinedAt: !95) +!101 = !DILocation(line: 26, column: 10, scope: !22, inlinedAt: !95) +!102 = !DILocation(line: 26, column: 17, scope: !22, inlinedAt: !95) +!103 = !DILocation(line: 26, column: 18, scope: !22, inlinedAt: !95) +!104 = !DILocation(line: 47, column: 1, scope: !40) +!105 = !{!14, !23, !26, !31} +!107 = !{!44, !52, !55, !60} +!110 = !{!70, !79, !82, !87} diff --git a/llvm/test/DebugInfo/Generic/local-type-as-template-parameter.ll b/llvm/test/DebugInfo/Generic/local-type-as-template-parameter.ll new file mode 100644 index 0000000000000..7999e434d139e --- /dev/null +++ b/llvm/test/DebugInfo/Generic/local-type-as-template-parameter.ll @@ -0,0 +1,160 @@ +; RUN: %llc_dwarf -O0 -filetype=obj < %s \ +; RUN: | llvm-dwarfdump --show-children --name=foo - \ +; RUN: | FileCheck --implicit-check-not "{{DW_TAG|NULL}}" %s + +; The test ensures that AsmPrinter doesn't crashed compiling this. +; It also demostrates misplacement for a local type (see PR55680 for details). + +; The test compiled from: + +; template +; struct A { +; A(T &in) : a(in) {} +; T a; +; }; +; +; __attribute__((always_inline)) +; void foo() { +; struct B { int i; }; +; B objB; +; A objA(objB); +; } +; +; int main() { +; foo(); +; } + +; Concrete out-of-line tree of foo(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_abstract_origin {{.*}} "_Z3foov" + +; FIXME: 'struct B' should be in the abstract tree below, not here. +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("B") +; CHECK: DW_TAG_member +; CHECK: NULL +; +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "objB" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "objA" + +; CHECK: NULL + +; Abstract tree of foo(). +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name ("foo") +; CHECK: DW_AT_inline (DW_INL_inlined) + +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("objB") +; CHECK: DW_TAG_variable +; CHECK: DW_AT_name ("objA") + +; CHECK: NULL + +; CHECK: DW_TAG_inlined_subroutine +; CHECK: DW_AT_abstract_origin {{.*}} "_Z3foov" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "objB" +; CHECK: DW_TAG_variable +; CHECK: DW_AT_abstract_origin {{.*}} "objA" +; CHECK: NULL + +%struct.B = type { i32 } +%struct.A = type { %struct.B } + +define dso_local void @_Z3foov() !dbg !7 { +entry: + %objB = alloca %struct.B, align 4 + %objA = alloca %struct.A, align 4 + call void @llvm.dbg.declare(metadata ptr %objB, metadata !30, metadata !DIExpression()), !dbg !31 + call void @llvm.dbg.declare(metadata ptr %objA, metadata !32, metadata !DIExpression()), !dbg !33 + call void @_ZN1AIZ3foovE1BEC2ERS0_(ptr noundef nonnull align 4 dereferenceable(4) %objA, ptr noundef nonnull align 4 dereferenceable(4) %objB), !dbg !33 + ret void, !dbg !34 +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +define internal void @_ZN1AIZ3foovE1BEC2ERS0_(ptr noundef nonnull align 4 dereferenceable(4) %this, ptr noundef nonnull align 4 dereferenceable(4) %in) unnamed_addr align 2 !dbg !35 { +entry: + %this.addr = alloca ptr, align 8 + %in.addr = alloca ptr, align 8 + store ptr %this, ptr %this.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %this.addr, metadata !36, metadata !DIExpression()), !dbg !38 + store ptr %in, ptr %in.addr, align 8 + call void @llvm.dbg.declare(metadata ptr %in.addr, metadata !39, metadata !DIExpression()), !dbg !40 + %this1 = load ptr, ptr %this.addr, align 8 + %a = getelementptr inbounds %struct.A, ptr %this1, i32 0, i32 0, !dbg !41 + %0 = load ptr, ptr %in.addr, align 8, !dbg !42 + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 %0, i64 4, i1 false), !dbg !41 + ret void, !dbg !43 +} + +define dso_local noundef i32 @main() !dbg !44 { +entry: + %objB.i = alloca %struct.B, align 4 + %objA.i = alloca %struct.A, align 4 + call void @llvm.dbg.declare(metadata ptr %objB.i, metadata !30, metadata !DIExpression()), !dbg !47 + call void @llvm.dbg.declare(metadata ptr %objA.i, metadata !32, metadata !DIExpression()), !dbg !49 + call void @_ZN1AIZ3foovE1BEC2ERS0_(ptr noundef nonnull align 4 dereferenceable(4) %objA.i, ptr noundef nonnull align 4 dereferenceable(4) %objB.i), !dbg !49 + ret i32 0, !dbg !50 +} + +declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!22, !23, !24, !25, !26, !27, !28} +!llvm.ident = !{!29} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 15.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.cpp", directory: "/", checksumkind: CSK_MD5, checksum: "aec7fd397e86f8655ef7f4bb4233b849") +!2 = !{!3} +!3 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 2, size: 32, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !4, templateParams: !20) +!4 = !{!5, !15} +!5 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !3, file: !1, line: 4, baseType: !6, size: 32) +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "B", scope: !7, file: !1, line: 9, size: 32, flags: DIFlagTypePassByValue, elements: !12) +!7 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 8, type: !8, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{null} +!10 = !{} +!11 = !{!6} +!12 = !{!13} +!13 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !6, file: !1, line: 9, baseType: !14, size: 32) +!14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!15 = !DISubprogram(name: "A", scope: !3, file: !1, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit) +!16 = !DISubroutineType(types: !17) +!17 = !{null, !18, !19} +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!19 = !DIDerivedType(tag: DW_TAG_reference_type, baseType: !6, size: 64) +!20 = !{!21} +!21 = !DITemplateTypeParameter(name: "T", type: !6) +!22 = !{i32 7, !"Dwarf Version", i32 5} +!23 = !{i32 2, !"Debug Info Version", i32 3} +!24 = !{i32 1, !"wchar_size", i32 4} +!25 = !{i32 7, !"PIC Level", i32 2} +!26 = !{i32 7, !"PIE Level", i32 2} +!27 = !{i32 7, !"uwtable", i32 2} +!28 = !{i32 7, !"frame-pointer", i32 2} +!29 = !{!"clang version 15.0.0"} +!30 = !DILocalVariable(name: "objB", scope: !7, file: !1, line: 10, type: !6) +!31 = !DILocation(line: 10, column: 5, scope: !7) +!32 = !DILocalVariable(name: "objA", scope: !7, file: !1, line: 11, type: !3) +!33 = !DILocation(line: 11, column: 8, scope: !7) +!34 = !DILocation(line: 12, column: 1, scope: !7) +!35 = distinct !DISubprogram(name: "A", linkageName: "_ZN1AIZ3foovE1BEC2ERS0_", scope: !3, file: !1, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !0, declaration: !15, retainedNodes: !10) +!36 = !DILocalVariable(name: "this", arg: 1, scope: !35, type: !37, flags: DIFlagArtificial | DIFlagObjectPointer) +!37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !3, size: 64) +!38 = !DILocation(line: 0, scope: !35) +!39 = !DILocalVariable(name: "in", arg: 2, scope: !35, file: !1, line: 3, type: !19) +!40 = !DILocation(line: 3, column: 8, scope: !35) +!41 = !DILocation(line: 3, column: 14, scope: !35) +!42 = !DILocation(line: 3, column: 16, scope: !35) +!43 = !DILocation(line: 3, column: 21, scope: !35) +!44 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 14, type: !45, scopeLine: 14, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !10) +!45 = !DISubroutineType(types: !46) +!46 = !{!14} +!47 = !DILocation(line: 10, column: 5, scope: !7, inlinedAt: !48) +!48 = distinct !DILocation(line: 15, column: 3, scope: !44) +!49 = !DILocation(line: 11, column: 8, scope: !7, inlinedAt: !48) +!50 = !DILocation(line: 16, column: 1, scope: !44) diff --git a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll index 6d4d0e93d38f9..54ce1c56c6b30 100644 --- a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll +++ b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll @@ -38,7 +38,7 @@ define void @invalid_subprogram_declaration() !dbg !9 { ret void } define void @invalid_retained_nodes_list() !dbg !10 { ret void } !10 = distinct !DISubprogram(retainedNodes: !0) -; CHECK: invalid retained nodes, expected DILocalVariable, DILabel or DIImportedEntity +; CHECK: invalid retained nodes, expected DILocalVariable, DILabel, DIImportedEntity or DIType define void @invalid_retained_nodes_expected() !dbg !11 { ret void } !11 = distinct !DISubprogram(retainedNodes: !{!0}) diff --git a/llvm/test/DebugInfo/X86/set.ll b/llvm/test/DebugInfo/X86/set.ll index 292c7c6e4a577..7dbec4520ed6c 100644 --- a/llvm/test/DebugInfo/X86/set.ll +++ b/llvm/test/DebugInfo/X86/set.ll @@ -68,11 +68,11 @@ attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } !llvm.module.flags = !{!18, !19, !20} !0 = !{!"versions- cm3: d5.10.0 llvm: 9.0"} -!1 = distinct !DICompileUnit(language: DW_LANG_Modula3, file: !2, producer: "cm3", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3) +!1 = distinct !DICompileUnit(language: DW_LANG_Modula3, file: !2, producer: "cm3", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug) !2 = !DIFile(filename: "Main.m3", directory: "/home/cm3/settest/src") !3 = !{!4} !4 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum", scope: !5, file: !2, line: 11, size: 8, align: 8, elements: !9) -!5 = distinct !DISubprogram(name: "Test", linkageName: "Main__Test", scope: !2, file: !2, line: 11, type: !6, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !8) +!5 = distinct !DISubprogram(name: "Test", linkageName: "Main__Test", scope: !2, file: !2, line: 11, type: !6, scopeLine: 11, spFlags: DISPFlagDefinition, unit: !1, retainedNodes: !3) !6 = !DISubroutineType(types: !7) !7 = !{null} !8 = !{} From ab927a998397c30fd3426d9aa1e071206fa554b2 Mon Sep 17 00:00:00 2001 From: Joe Nash Date: Mon, 12 Jun 2023 17:21:29 -0400 Subject: [PATCH 033/130] [AMDGPU] Fix operand class of v_ldexp_f16 src1 Patch eece6ba283bd changed the src1 type of v_ldexp_f16 from i32 to i16. Though semantically src1 is an i16, the hardware reads this operand as an f16 type, which primarily enables floating point inline constants. Therefore this patch changes the operand type to f16. It maintains the current behavior where floating point source modifiers are not allowed on src1. SDWA sext modifier continues to be allowed. The test asm and disasm test changes in eece6ba283bd are reverted, because the floating point inline constants are allowed. Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D153169 --- llvm/lib/Target/AMDGPU/VOP2Instructions.td | 34 ++++++++++++++++--- llvm/test/MC/AMDGPU/gfx10_asm_vop2.s | 6 ++-- .../test/MC/AMDGPU/gfx11_asm_vop3_from_vop2.s | 2 +- llvm/test/MC/AMDGPU/gfx8_asm_vop3.s | 7 ++-- llvm/test/MC/AMDGPU/gfx9_asm_vop3.s | 7 ++-- .../MC/Disassembler/AMDGPU/gfx10_vop3.txt | 4 +-- .../AMDGPU/gfx11_dasm_vop3_from_vop2.txt | 2 +- .../test/MC/Disassembler/AMDGPU/gfx8_vop3.txt | 4 +-- .../test/MC/Disassembler/AMDGPU/gfx9_vop3.txt | 4 +-- 9 files changed, 46 insertions(+), 24 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/llvm/lib/Target/AMDGPU/VOP2Instructions.td index 35429a44c93e3..ea7ab163992ea 100644 --- a/llvm/lib/Target/AMDGPU/VOP2Instructions.td +++ b/llvm/lib/Target/AMDGPU/VOP2Instructions.td @@ -863,9 +863,18 @@ def : divergent_i64_BinOp ; // 16-Bit Operand Instructions //===----------------------------------------------------------------------===// -def LDEXP_F16_VOPProfile_True16 : VOPProfile_True16 { - // The ldexp.f16 intrinsic expects a i32 src1 operand, though the hardware - // encoding treats src1 as an f16 +// The ldexp.f16 intrinsic expects a integer src1 operand, though the hardware +// encoding treats src1 as an f16 +def LDEXP_F16_VOPProfile : VOPProfile <[f16, f16, f16, untyped]> { + let Src1Mod = Int32InputMods; + let Src1ModDPP = IntVRegInputMods; + let Src1ModVOP3DPP = IntVRegInputMods; + // SDWA sext is the only modifier allowed. + let HasSrc1IntMods = 1; + let HasSrc1FloatMods = 0; + let Src1ModSDWA = Int16SDWAInputMods; +} +def LDEXP_F16_VOPProfile_True16 : VOPProfile_True16 { let Src1RC32 = RegisterOperand; let Src1DPP = VGPR_32_Lo128; let Src1ModDPP = IntT16VRegInputMods; @@ -874,9 +883,9 @@ def LDEXP_F16_VOPProfile_True16 : VOPProfile_True16 { let isReMaterializable = 1 in { let FPDPRounding = 1 in { let SubtargetPredicate = NotHasTrue16BitInsts, OtherPredicates = [Has16BitInsts] in - defm V_LDEXP_F16 : VOP2Inst <"v_ldexp_f16", VOP_F16_F16_I16, any_fldexp>; + defm V_LDEXP_F16 : VOP2Inst <"v_ldexp_f16", LDEXP_F16_VOPProfile>; let SubtargetPredicate = HasTrue16BitInsts in - defm V_LDEXP_F16_t16 : VOP2Inst <"v_ldexp_f16_t16", LDEXP_F16_VOPProfile_True16, any_fldexp>; + defm V_LDEXP_F16_t16 : VOP2Inst <"v_ldexp_f16_t16", LDEXP_F16_VOPProfile_True16>; } // End FPDPRounding = 1 // FIXME VOP3 Only instructions. NFC using VOPProfile_True16 for these until a planned change to use a new register class for VOP3 encoded True16 instuctions defm V_LSHLREV_B16 : VOP2Inst_e64_t16 <"v_lshlrev_b16", VOP_I16_I16_I16, clshl_rev_16>; @@ -899,6 +908,21 @@ defm V_MIN_I16 : VOP2Inst_e64_t16 <"v_min_i16", VOP_I16_I16_I16, smin>; } // End isCommutable = 1 } // End isReMaterializable = 1 +class LDEXP_F16_Pat : GCNPat < + (P.DstVT (op (P.Src0VT (VOP3Mods0 P.Src0VT:$src0, i32:$src0_modifiers, i1:$clamp, i32:$omod)), + (i16 (VOP3Mods0 P.Src1VT:$src1, i32:$src1_modifiers)))), + (inst $src0_modifiers, $src0, + $src1_modifiers, $src1, + $clamp, /* clamp */ + $omod /* omod */) +>; + +let OtherPredicates = [NotHasTrue16BitInsts] in +def : LDEXP_F16_Pat; + +let OtherPredicates = [HasTrue16BitInsts] in +def : LDEXP_F16_Pat; + let SubtargetPredicate = isGFX11Plus in { let isCommutable = 1 in { defm V_AND_B16_t16 : VOP2Inst_e64 <"v_and_b16_t16", VOPProfile_True16, and>; diff --git a/llvm/test/MC/AMDGPU/gfx10_asm_vop2.s b/llvm/test/MC/AMDGPU/gfx10_asm_vop2.s index 6ea135c95d1f0..b1b54005bee28 100644 --- a/llvm/test/MC/AMDGPU/gfx10_asm_vop2.s +++ b/llvm/test/MC/AMDGPU/gfx10_asm_vop2.s @@ -12931,11 +12931,11 @@ v_ldexp_f16_e64 v5, v1, 0 v_ldexp_f16_e64 v5, v1, -1 // GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0x83,0x01,0x00] -v_ldexp_f16_e64 v5, v1, 0x3800 -// GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0xff,0x01,0x00,0x00,0x38,0x00,0x00] +v_ldexp_f16_e64 v5, v1, 0.5 +// GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0xe1,0x01,0x00] v_ldexp_f16_e64 v5, v1, -4.0 -// GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0xff,0x01,0x00,0x00,0xc4,0x00,0x00] +// GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0xef,0x01,0x00] v_ldexp_f16_e64 v5, -v1, v2 // GFX10: encoding: [0x05,0x00,0x3b,0xd5,0x01,0x05,0x02,0x20] diff --git a/llvm/test/MC/AMDGPU/gfx11_asm_vop3_from_vop2.s b/llvm/test/MC/AMDGPU/gfx11_asm_vop3_from_vop2.s index ffb83100c08ce..43c71617bb385 100644 --- a/llvm/test/MC/AMDGPU/gfx11_asm_vop3_from_vop2.s +++ b/llvm/test/MC/AMDGPU/gfx11_asm_vop3_from_vop2.s @@ -734,7 +734,7 @@ v_ldexp_f16_e64 v5, ttmp15, src_scc // GFX11: encoding: [0x05,0x00,0x3b,0xd5,0x7b,0xfa,0x01,0x00] v_ldexp_f16_e64 v5, m0, 0.5 -// GFX11: encoding: [0x05,0x00,0x3b,0xd5,0x7d,0xfe,0x01,0x00,0x00,0x38,0x00,0x00] +// GFX11: encoding: [0x05,0x00,0x3b,0xd5,0x7d,0xe0,0x01,0x00] v_ldexp_f16_e64 v5, exec_lo, -1 // GFX11: encoding: [0x05,0x00,0x3b,0xd5,0x7e,0x82,0x01,0x00] diff --git a/llvm/test/MC/AMDGPU/gfx8_asm_vop3.s b/llvm/test/MC/AMDGPU/gfx8_asm_vop3.s index d46a97f1cbd58..d4c31f14d3bfc 100644 --- a/llvm/test/MC/AMDGPU/gfx8_asm_vop3.s +++ b/llvm/test/MC/AMDGPU/gfx8_asm_vop3.s @@ -1,5 +1,4 @@ -// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s | FileCheck %s -// RUN: not llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding -filetype=null 2>&1 %s | FileCheck -check-prefix=ERR --implicit-check-not=error %s +// RUN: llvm-mc -arch=amdgcn -mcpu=tonga -show-encoding %s | FileCheck %s v_interp_p1_f32_e64 v5, v2, attr0.x // CHECK: [0x05,0x00,0x70,0xd2,0x00,0x04,0x02,0x00] @@ -12827,10 +12826,10 @@ v_ldexp_f16_e64 v5, v1, -1 // CHECK: [0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00] v_ldexp_f16_e64 v5, v1, 0.5 -// ERR: [[@LINE-1]]:25: error: literal operands are not supported +// CHECK: [0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00] v_ldexp_f16_e64 v5, v1, -4.0 -// ERR: [[@LINE-1]]:25: error: literal operands are not supported +// CHECK: [0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00] v_ldexp_f16_e64 v5, v1, src_vccz // CHECK: [0x05,0x00,0x33,0xd1,0x01,0xf7,0x01,0x00] diff --git a/llvm/test/MC/AMDGPU/gfx9_asm_vop3.s b/llvm/test/MC/AMDGPU/gfx9_asm_vop3.s index 34d0d77c07f36..8781a01f1eb8e 100644 --- a/llvm/test/MC/AMDGPU/gfx9_asm_vop3.s +++ b/llvm/test/MC/AMDGPU/gfx9_asm_vop3.s @@ -1,5 +1,4 @@ -// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding %s | FileCheck %s -// RUN: not llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding 2>&1 %s | FileCheck -check-prefix=ERR --implicit-check-not=error %s +// RUN: llvm-mc -arch=amdgcn -mcpu=gfx900 -show-encoding %s | FileCheck %s v_interp_p1_f32_e64 v5, v2, attr0.x // CHECK: [0x05,0x00,0x70,0xd2,0x00,0x04,0x02,0x00] @@ -11240,10 +11239,10 @@ v_ldexp_f16_e64 v5, v1, -1 // CHECK: [0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00] v_ldexp_f16_e64 v5, v1, 0.5 -// ERR: [[@LINE-1]]:25: error: literal operands are not supported +// CHECK: [0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00] v_ldexp_f16_e64 v5, v1, -4.0 -// ERR: [[@LINE-1]]:25: error: literal operands are not supported +// CHECK: [0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00] v_ldexp_f16_e64 v5, v1, src_vccz // CHECK: [0x05,0x00,0x33,0xd1,0x01,0xf7,0x01,0x00] diff --git a/llvm/test/MC/Disassembler/AMDGPU/gfx10_vop3.txt b/llvm/test/MC/Disassembler/AMDGPU/gfx10_vop3.txt index c5cd6f6c4dcea..0785ba2ea2eb6 100644 --- a/llvm/test/MC/Disassembler/AMDGPU/gfx10_vop3.txt +++ b/llvm/test/MC/Disassembler/AMDGPU/gfx10_vop3.txt @@ -7520,13 +7520,13 @@ # GFX10: v_ldexp_f16_e64 v5, v1, -1 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0x83,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x01,0x83,0x01,0x00 -# GFX10: v_ldexp_f16_e64 v5, v1, 0xc400 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0xff,0x01,0x00,0x00,0xc4,0x00,0x00] +# GFX10: v_ldexp_f16_e64 v5, v1, -4.0 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0xef,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x01,0xef,0x01,0x00 # GFX10: v_ldexp_f16_e64 v5, v1, 0 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0x01,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x01,0x01,0x01,0x00 -# GFX10: v_ldexp_f16_e64 v5, v1, 0x3800 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0xff,0x01,0x00,0x00,0x38,0x00,0x00] +# GFX10: v_ldexp_f16_e64 v5, v1, 0.5 ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0xe1,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x01,0xe1,0x01,0x00 # GFX10: v_ldexp_f16_e64 v5, v1, exec_hi ; encoding: [0x05,0x00,0x3b,0xd5,0x01,0xff,0x00,0x00] diff --git a/llvm/test/MC/Disassembler/AMDGPU/gfx11_dasm_vop3_from_vop2.txt b/llvm/test/MC/Disassembler/AMDGPU/gfx11_dasm_vop3_from_vop2.txt index 4e430a88a1cb4..3141e8f4b2cbb 100644 --- a/llvm/test/MC/Disassembler/AMDGPU/gfx11_dasm_vop3_from_vop2.txt +++ b/llvm/test/MC/Disassembler/AMDGPU/gfx11_dasm_vop3_from_vop2.txt @@ -543,7 +543,7 @@ # GFX11: v_ldexp_f16_e64 v5, ttmp15, src_scc ; encoding: [0x05,0x00,0x3b,0xd5,0x7b,0xfa,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x7b,0xfa,0x01,0x00 -# GFX11: v_ldexp_f16_e64 v5, m0, 0x3800 ; encoding: [0x05,0x00,0x3b,0xd5,0x7d,0xfe,0x01,0x00,0x00,0x38,0x00,0x00] +# GFX11: v_ldexp_f16_e64 v5, m0, 0.5 ; encoding: [0x05,0x00,0x3b,0xd5,0x7d,0xe0,0x01,0x00] 0x05,0x00,0x3b,0xd5,0x7d,0xe0,0x01,0x00 # GFX11: v_ldexp_f16_e64 v5, exec_lo, -1 ; encoding: [0x05,0x00,0x3b,0xd5,0x7e,0x82,0x01,0x00] diff --git a/llvm/test/MC/Disassembler/AMDGPU/gfx8_vop3.txt b/llvm/test/MC/Disassembler/AMDGPU/gfx8_vop3.txt index a0277c706ee23..2b07d620fdad2 100644 --- a/llvm/test/MC/Disassembler/AMDGPU/gfx8_vop3.txt +++ b/llvm/test/MC/Disassembler/AMDGPU/gfx8_vop3.txt @@ -11178,10 +11178,10 @@ # CHECK: v_ldexp_f16_e64 v5, v1, -1 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00 -# CHECK: v_ldexp_f16_e64 v5, v1, 0x3800 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xff,0x01,0x00] +# CHECK: v_ldexp_f16_e64 v5, v1, 0.5 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00 -# CHECK: v_ldexp_f16_e64 v5, v1, 0xc400 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xff,0x01,0x00] +# CHECK: v_ldexp_f16_e64 v5, v1, -4.0 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00 # CHECK: v_ldexp_f16_e64 v5, -v1, v2 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0x05,0x02,0x20] diff --git a/llvm/test/MC/Disassembler/AMDGPU/gfx9_vop3.txt b/llvm/test/MC/Disassembler/AMDGPU/gfx9_vop3.txt index c2ac84b44e0ca..e3ed9778f6fb4 100644 --- a/llvm/test/MC/Disassembler/AMDGPU/gfx9_vop3.txt +++ b/llvm/test/MC/Disassembler/AMDGPU/gfx9_vop3.txt @@ -8814,10 +8814,10 @@ # CHECK: v_ldexp_f16_e64 v5, v1, -1 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0x83,0x01,0x00 -# CHECK: v_ldexp_f16_e64 v5, v1, 0x3800 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xff,0x01,0x00] +# CHECK: v_ldexp_f16_e64 v5, v1, 0.5 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0xe1,0x01,0x00 -# CHECK: v_ldexp_f16_e64 v5, v1, 0xc400 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xff,0x01,0x00] +# CHECK: v_ldexp_f16_e64 v5, v1, -4.0 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00] 0x05,0x00,0x33,0xd1,0x01,0xef,0x01,0x00 # CHECK: v_ldexp_f16_e64 v5, -v1, v2 ; encoding: [0x05,0x00,0x33,0xd1,0x01,0x05,0x02,0x20] From d0f56c3e5cc0ead069280d59c41fe12567ed0619 Mon Sep 17 00:00:00 2001 From: David Green Date: Mon, 19 Jun 2023 15:47:21 +0100 Subject: [PATCH 034/130] [AArch64] Add and expand the testing of fmin/fmax reduction. NFC For both CodeGen and CostModelling, this adds extran testing for the new lvm.vector.reduce.fmaximum and lvm.vector.reduce.fminimum intrinsics, as well as making sure there is test coverage for all the various cases. --- .../CostModel/AArch64/reduce-minmax.ll | 64 +++++ llvm/test/CodeGen/AArch64/vecreduce-fadd.ll | 2 +- .../AArch64/vecreduce-fmax-legalization.ll | 18 +- .../CodeGen/AArch64/vecreduce-fmaximum.ll | 11 + .../AArch64/vecreduce-fmin-legalization.ll | 18 +- .../CodeGen/AArch64/vecreduce-fminimum.ll | 235 ++++++++++++++++++ 6 files changed, 339 insertions(+), 9 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/vecreduce-fminimum.ll diff --git a/llvm/test/Analysis/CostModel/AArch64/reduce-minmax.ll b/llvm/test/Analysis/CostModel/AArch64/reduce-minmax.ll index cf813bae839c6..c10f87fcef658 100644 --- a/llvm/test/Analysis/CostModel/AArch64/reduce-minmax.ll +++ b/llvm/test/Analysis/CostModel/AArch64/reduce-minmax.ll @@ -166,6 +166,10 @@ define void @reduce_fmin16() { ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 40 for instruction: %V4f16 = call half @llvm.vector.reduce.fmin.v4f16(<4 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 198 for instruction: %V8f16 = call half @llvm.vector.reduce.fmin.v8f16(<8 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 298 for instruction: %V16f16 = call half @llvm.vector.reduce.fmin.v16f16(<16 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f16m = call half @llvm.vector.reduce.fminimum.v2f16(<2 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f16m = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 29 for instruction: %V8f16m = call half @llvm.vector.reduce.fminimum.v8f16(<8 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 58 for instruction: %V16f16m = call half @llvm.vector.reduce.fminimum.v16f16(<16 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; ; CHECK-F16-LABEL: 'reduce_fmin16' @@ -173,12 +177,20 @@ define void @reduce_fmin16() { ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V4f16 = call half @llvm.vector.reduce.fmin.v4f16(<4 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V8f16 = call half @llvm.vector.reduce.fmin.v8f16(<8 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V16f16 = call half @llvm.vector.reduce.fmin.v16f16(<16 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f16m = call half @llvm.vector.reduce.fminimum.v2f16(<2 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f16m = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 29 for instruction: %V8f16m = call half @llvm.vector.reduce.fminimum.v8f16(<8 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 58 for instruction: %V16f16m = call half @llvm.vector.reduce.fminimum.v16f16(<16 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %V2f16 = call half @llvm.vector.reduce.fmin.v2f16(<2 x half> undef) %V4f16 = call half @llvm.vector.reduce.fmin.v4f16(<4 x half> undef) %V8f16 = call half @llvm.vector.reduce.fmin.v8f16(<8 x half> undef) %V16f16 = call half @llvm.vector.reduce.fmin.v16f16(<16 x half> undef) + %V2f16m = call half @llvm.vector.reduce.fminimum.v2f16(<2 x half> undef) + %V4f16m = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> undef) + %V8f16m = call half @llvm.vector.reduce.fminimum.v8f16(<8 x half> undef) + %V16f16m = call half @llvm.vector.reduce.fminimum.v16f16(<16 x half> undef) ret void } @@ -188,6 +200,10 @@ define void @reduce_fmax16() { ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 40 for instruction: %V4f16 = call half @llvm.vector.reduce.fmax.v4f16(<4 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 198 for instruction: %V8f16 = call half @llvm.vector.reduce.fmax.v8f16(<8 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 298 for instruction: %V16f16 = call half @llvm.vector.reduce.fmax.v16f16(<16 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f16m = call half @llvm.vector.reduce.fmaximum.v2f16(<2 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f16m = call half @llvm.vector.reduce.fmaximum.v4f16(<4 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 29 for instruction: %V8f16m = call half @llvm.vector.reduce.fmaximum.v8f16(<8 x half> undef) +; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 58 for instruction: %V16f16m = call half @llvm.vector.reduce.fmaximum.v16f16(<16 x half> undef) ; CHECK-NOF16-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; ; CHECK-F16-LABEL: 'reduce_fmax16' @@ -195,12 +211,20 @@ define void @reduce_fmax16() { ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V4f16 = call half @llvm.vector.reduce.fmax.v4f16(<4 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V8f16 = call half @llvm.vector.reduce.fmax.v8f16(<8 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V16f16 = call half @llvm.vector.reduce.fmax.v16f16(<16 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f16m = call half @llvm.vector.reduce.fmaximum.v2f16(<2 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f16m = call half @llvm.vector.reduce.fmaximum.v4f16(<4 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 29 for instruction: %V8f16m = call half @llvm.vector.reduce.fmaximum.v8f16(<8 x half> undef) +; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 58 for instruction: %V16f16m = call half @llvm.vector.reduce.fmaximum.v16f16(<16 x half> undef) ; CHECK-F16-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %V2f16 = call half @llvm.vector.reduce.fmax.v2f16(<2 x half> undef) %V4f16 = call half @llvm.vector.reduce.fmax.v4f16(<4 x half> undef) %V8f16 = call half @llvm.vector.reduce.fmax.v8f16(<8 x half> undef) %V16f16 = call half @llvm.vector.reduce.fmax.v16f16(<16 x half> undef) + %V2f16m = call half @llvm.vector.reduce.fmaximum.v2f16(<2 x half> undef) + %V4f16m = call half @llvm.vector.reduce.fmaximum.v4f16(<4 x half> undef) + %V8f16m = call half @llvm.vector.reduce.fmaximum.v8f16(<8 x half> undef) + %V16f16m = call half @llvm.vector.reduce.fmaximum.v16f16(<16 x half> undef) ret void } @@ -211,6 +235,11 @@ define void @reduce_fmin() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V8f32 = call float @llvm.vector.reduce.fmin.v8f32(<8 x float> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V2f64 = call double @llvm.vector.reduce.fmin.v2f64(<2 x double> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V4f64 = call double @llvm.vector.reduce.fmin.v4f64(<4 x double> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f32m = call float @llvm.vector.reduce.fminimum.v2f32(<2 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f32m = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 26 for instruction: %V8f32m = call float @llvm.vector.reduce.fminimum.v8f32(<8 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f64m = call double @llvm.vector.reduce.fminimum.v2f64(<2 x double> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %V4f64m = call double @llvm.vector.reduce.fminimum.v4f64(<4 x double> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %V2f32 = call float @llvm.vector.reduce.fmin.v2f32(<2 x float> undef) @@ -218,6 +247,11 @@ define void @reduce_fmin() { %V8f32 = call float @llvm.vector.reduce.fmin.v8f32(<8 x float> undef) %V2f64 = call double @llvm.vector.reduce.fmin.v2f64(<2 x double> undef) %V4f64 = call double @llvm.vector.reduce.fmin.v4f64(<4 x double> undef) + %V2f32m = call float @llvm.vector.reduce.fminimum.v2f32(<2 x float> undef) + %V4f32m = call float @llvm.vector.reduce.fminimum.v4f32(<4 x float> undef) + %V8f32m = call float @llvm.vector.reduce.fminimum.v8f32(<8 x float> undef) + %V2f64m = call double @llvm.vector.reduce.fminimum.v2f64(<2 x double> undef) + %V4f64m = call double @llvm.vector.reduce.fminimum.v4f64(<4 x double> undef) ret void } @@ -228,6 +262,11 @@ define void @reduce_fmax() { ; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V8f32 = call float @llvm.vector.reduce.fmax.v8f32(<8 x float> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %V2f64 = call double @llvm.vector.reduce.fmax.v2f64(<2 x double> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %V4f64 = call double @llvm.vector.reduce.fmax.v4f64(<4 x double> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f32m = call float @llvm.vector.reduce.fmaximum.v2f32(<2 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 13 for instruction: %V4f32m = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 26 for instruction: %V8f32m = call float @llvm.vector.reduce.fmaximum.v8f32(<8 x float> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %V2f64m = call double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> undef) +; CHECK-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %V4f64m = call double @llvm.vector.reduce.fmaximum.v4f64(<4 x double> undef) ; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void ; %V2f32 = call float @llvm.vector.reduce.fmax.v2f32(<2 x float> undef) @@ -235,6 +274,11 @@ define void @reduce_fmax() { %V8f32 = call float @llvm.vector.reduce.fmax.v8f32(<8 x float> undef) %V2f64 = call double @llvm.vector.reduce.fmax.v2f64(<2 x double> undef) %V4f64 = call double @llvm.vector.reduce.fmax.v4f64(<4 x double> undef) + %V2f32m = call float @llvm.vector.reduce.fmaximum.v2f32(<2 x float> undef) + %V4f32m = call float @llvm.vector.reduce.fmaximum.v4f32(<4 x float> undef) + %V8f32m = call float @llvm.vector.reduce.fmaximum.v8f32(<8 x float> undef) + %V2f64m = call double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> undef) + %V4f64m = call double @llvm.vector.reduce.fmaximum.v4f64(<4 x double> undef) ret void } @@ -325,3 +369,23 @@ declare float @llvm.vector.reduce.fmax.v4f32(<4 x float>) declare float @llvm.vector.reduce.fmax.v8f32(<8 x float>) declare double @llvm.vector.reduce.fmax.v2f64(<2 x double>) declare double @llvm.vector.reduce.fmax.v4f64(<4 x double>) + +declare half @llvm.vector.reduce.fminimum.v2f16(<2 x half>) +declare half @llvm.vector.reduce.fminimum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fminimum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fminimum.v16f16(<16 x half>) +declare float @llvm.vector.reduce.fminimum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fminimum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fminimum.v8f32(<8 x float>) +declare double @llvm.vector.reduce.fminimum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fminimum.v4f64(<4 x double>) + +declare half @llvm.vector.reduce.fmaximum.v2f16(<2 x half>) +declare half @llvm.vector.reduce.fmaximum.v4f16(<4 x half>) +declare half @llvm.vector.reduce.fmaximum.v8f16(<8 x half>) +declare half @llvm.vector.reduce.fmaximum.v16f16(<16 x half>) +declare float @llvm.vector.reduce.fmaximum.v2f32(<2 x float>) +declare float @llvm.vector.reduce.fmaximum.v4f32(<4 x float>) +declare float @llvm.vector.reduce.fmaximum.v8f32(<8 x float>) +declare double @llvm.vector.reduce.fmaximum.v2f64(<2 x double>) +declare double @llvm.vector.reduce.fmaximum.v4f64(<4 x double>) diff --git a/llvm/test/CodeGen/AArch64/vecreduce-fadd.ll b/llvm/test/CodeGen/AArch64/vecreduce-fadd.ll index 55b140b28bd49..b43b01027dda2 100644 --- a/llvm/test/CodeGen/AArch64/vecreduce-fadd.ll +++ b/llvm/test/CodeGen/AArch64/vecreduce-fadd.ll @@ -227,7 +227,7 @@ define float @add_S_init_42(<4 x float> %bin.rdx) { ; CHECK-LABEL: add_S_init_42: ; CHECK: // %bb.0: ; CHECK-NEXT: faddp v0.4s, v0.4s, v0.4s -; CHECK-NEXT: mov w8, #1109917696 +; CHECK-NEXT: mov w8, #1109917696 // =0x42280000 ; CHECK-NEXT: fmov s1, w8 ; CHECK-NEXT: faddp s0, v0.2s ; CHECK-NEXT: fadd s0, s0, s1 diff --git a/llvm/test/CodeGen/AArch64/vecreduce-fmax-legalization.ll b/llvm/test/CodeGen/AArch64/vecreduce-fmax-legalization.ll index 51b60332bf5ab..3df8749d8978c 100644 --- a/llvm/test/CodeGen/AArch64/vecreduce-fmax-legalization.ll +++ b/llvm/test/CodeGen/AArch64/vecreduce-fmax-legalization.ll @@ -12,6 +12,7 @@ declare half @llvm.vector.reduce.fmax.v11f16(<11 x half> %a) declare float @llvm.vector.reduce.fmax.v3f32(<3 x float> %a) declare fp128 @llvm.vector.reduce.fmax.v2f128(<2 x fp128> %a) declare float @llvm.vector.reduce.fmax.v16f32(<16 x float> %a) +declare double @llvm.vector.reduce.fmax.v2f64(<2 x double> %a) define half @test_v1f16(<1 x half> %a) nounwind { ; CHECK-LABEL: test_v1f16: @@ -131,7 +132,7 @@ define half @test_v11f16(<11 x half> %a) nounwind { ; CHECK-NOFP-NEXT: fmaxnm s0, s0, s1 ; CHECK-NOFP-NEXT: fcsel s1, s2, s16, gt ; CHECK-NOFP-NEXT: ldr h2, [x8, :lo12:.LCPI6_0] -; CHECK-NOFP-NEXT: mov w8, #-8388608 +; CHECK-NOFP-NEXT: mov w8, #-8388608 // =0xff800000 ; CHECK-NOFP-NEXT: fcvt h0, s0 ; CHECK-NOFP-NEXT: fcvt h1, s1 ; CHECK-NOFP-NEXT: fcvt s2, h2 @@ -238,7 +239,7 @@ define half @test_v11f16_ninf(<11 x half> %a) nounwind { ; CHECK-NOFP-NEXT: fmaxnm s0, s0, s1 ; CHECK-NOFP-NEXT: fcsel s1, s2, s16, gt ; CHECK-NOFP-NEXT: ldr h2, [x8, :lo12:.LCPI7_0] -; CHECK-NOFP-NEXT: mov w8, #57344 +; CHECK-NOFP-NEXT: mov w8, #57344 // =0xe000 ; CHECK-NOFP-NEXT: movk w8, #51071, lsl #16 ; CHECK-NOFP-NEXT: fcvt h0, s0 ; CHECK-NOFP-NEXT: fcvt h1, s1 @@ -323,7 +324,7 @@ define half @test_v11f16_ninf(<11 x half> %a) nounwind { define float @test_v3f32(<3 x float> %a) nounwind { ; CHECK-LABEL: test_v3f32: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #-8388608 +; CHECK-NEXT: mov w8, #-8388608 // =0xff800000 ; CHECK-NEXT: fmov s1, w8 ; CHECK-NEXT: mov v0.s[3], v1.s[0] ; CHECK-NEXT: fmaxnmv s0, v0.4s @@ -335,7 +336,7 @@ define float @test_v3f32(<3 x float> %a) nounwind { define float @test_v3f32_ninf(<3 x float> %a) nounwind { ; CHECK-LABEL: test_v3f32_ninf: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #-8388609 +; CHECK-NEXT: mov w8, #-8388609 // =0xff7fffff ; CHECK-NEXT: fmov s1, w8 ; CHECK-NEXT: mov v0.s[3], v1.s[0] ; CHECK-NEXT: fmaxnmv s0, v0.4s @@ -363,3 +364,12 @@ define float @test_v16f32(<16 x float> %a) nounwind { %b = call nnan float @llvm.vector.reduce.fmax.v16f32(<16 x float> %a) ret float %b } + +define double @test_v2f64(<2 x double> %a) nounwind { +; CHECK-LABEL: test_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: fmaxnmp d0, v0.2d +; CHECK-NEXT: ret + %b = call double @llvm.vector.reduce.fmax.v2f64(<2 x double> %a) + ret double %b +} diff --git a/llvm/test/CodeGen/AArch64/vecreduce-fmaximum.ll b/llvm/test/CodeGen/AArch64/vecreduce-fmaximum.ll index 82454564df68d..1204554294fd1 100644 --- a/llvm/test/CodeGen/AArch64/vecreduce-fmaximum.ll +++ b/llvm/test/CodeGen/AArch64/vecreduce-fmaximum.ll @@ -12,6 +12,7 @@ declare half @llvm.vector.reduce.fmaximum.v11f16(<11 x half> %a) declare float @llvm.vector.reduce.fmaximum.v3f32(<3 x float> %a) declare fp128 @llvm.vector.reduce.fmaximum.v2f128(<2 x fp128> %a) declare float @llvm.vector.reduce.fmaximum.v16f32(<16 x float> %a) +declare double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> %a) define half @test_v1f16(<1 x half> %a) nounwind { ; CHECK-LABEL: test_v1f16: @@ -222,3 +223,13 @@ define float @test_v16f32(<16 x float> %a) nounwind { %b = call float @llvm.vector.reduce.fmaximum.v16f32(<16 x float> %a) ret float %b } + +define double @test_v2f64(<2 x double> %a) nounwind { +; CHECK-LABEL: test_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: mov d1, v0.d[1] +; CHECK-NEXT: fmax d0, d0, d1 +; CHECK-NEXT: ret + %b = call double @llvm.vector.reduce.fmaximum.v2f64(<2 x double> %a) + ret double %b +} diff --git a/llvm/test/CodeGen/AArch64/vecreduce-fmin-legalization.ll b/llvm/test/CodeGen/AArch64/vecreduce-fmin-legalization.ll index fade974b07dc7..5e4205855707b 100644 --- a/llvm/test/CodeGen/AArch64/vecreduce-fmin-legalization.ll +++ b/llvm/test/CodeGen/AArch64/vecreduce-fmin-legalization.ll @@ -12,6 +12,7 @@ declare half @llvm.vector.reduce.fmin.v11f16(<11 x half> %a) declare float @llvm.vector.reduce.fmin.v3f32(<3 x float> %a) declare fp128 @llvm.vector.reduce.fmin.v2f128(<2 x fp128> %a) declare float @llvm.vector.reduce.fmin.v16f32(<16 x float> %a) +declare double @llvm.vector.reduce.fmin.v2f64(<2 x double> %a) define half @test_v1f16(<1 x half> %a) nounwind { ; CHECK-LABEL: test_v1f16: @@ -131,7 +132,7 @@ define half @test_v11f16(<11 x half> %a) nounwind { ; CHECK-NOFP-NEXT: fminnm s0, s0, s1 ; CHECK-NOFP-NEXT: fcsel s1, s2, s16, lt ; CHECK-NOFP-NEXT: ldr h2, [x8, :lo12:.LCPI6_0] -; CHECK-NOFP-NEXT: mov w8, #2139095040 +; CHECK-NOFP-NEXT: mov w8, #2139095040 // =0x7f800000 ; CHECK-NOFP-NEXT: fcvt h0, s0 ; CHECK-NOFP-NEXT: fcvt h1, s1 ; CHECK-NOFP-NEXT: fcvt s2, h2 @@ -238,7 +239,7 @@ define half @test_v11f16_ninf(<11 x half> %a) nounwind { ; CHECK-NOFP-NEXT: fminnm s0, s0, s1 ; CHECK-NOFP-NEXT: fcsel s1, s2, s16, lt ; CHECK-NOFP-NEXT: ldr h2, [x8, :lo12:.LCPI7_0] -; CHECK-NOFP-NEXT: mov w8, #57344 +; CHECK-NOFP-NEXT: mov w8, #57344 // =0xe000 ; CHECK-NOFP-NEXT: movk w8, #18303, lsl #16 ; CHECK-NOFP-NEXT: fcvt h0, s0 ; CHECK-NOFP-NEXT: fcvt h1, s1 @@ -323,7 +324,7 @@ define half @test_v11f16_ninf(<11 x half> %a) nounwind { define float @test_v3f32(<3 x float> %a) nounwind { ; CHECK-LABEL: test_v3f32: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #2139095040 +; CHECK-NEXT: mov w8, #2139095040 // =0x7f800000 ; CHECK-NEXT: fmov s1, w8 ; CHECK-NEXT: mov v0.s[3], v1.s[0] ; CHECK-NEXT: fminnmv s0, v0.4s @@ -335,7 +336,7 @@ define float @test_v3f32(<3 x float> %a) nounwind { define float @test_v3f32_ninf(<3 x float> %a) nounwind { ; CHECK-LABEL: test_v3f32_ninf: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #2139095039 +; CHECK-NEXT: mov w8, #2139095039 // =0x7f7fffff ; CHECK-NEXT: fmov s1, w8 ; CHECK-NEXT: mov v0.s[3], v1.s[0] ; CHECK-NEXT: fminnmv s0, v0.4s @@ -363,3 +364,12 @@ define float @test_v16f32(<16 x float> %a) nounwind { %b = call nnan float @llvm.vector.reduce.fmin.v16f32(<16 x float> %a) ret float %b } + +define double @test_v2f64(<2 x double> %a) nounwind { +; CHECK-LABEL: test_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: fminnmp d0, v0.2d +; CHECK-NEXT: ret + %b = call double @llvm.vector.reduce.fmin.v2f64(<2 x double> %a) + ret double %b +} diff --git a/llvm/test/CodeGen/AArch64/vecreduce-fminimum.ll b/llvm/test/CodeGen/AArch64/vecreduce-fminimum.ll new file mode 100644 index 0000000000000..3cf48c9a8ab33 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/vecreduce-fminimum.ll @@ -0,0 +1,235 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=aarch64-none-linux-gnu -mattr=+neon | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOFP +; RUN: llc < %s -mtriple=aarch64-none-linux-gnu -mattr=+neon,+fullfp16 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FP + +declare half @llvm.vector.reduce.fminimum.v1f16(<1 x half> %a) +declare float @llvm.vector.reduce.fminimum.v1f32(<1 x float> %a) +declare double @llvm.vector.reduce.fminimum.v1f64(<1 x double> %a) +declare fp128 @llvm.vector.reduce.fminimum.v1f128(<1 x fp128> %a) + +declare half @llvm.vector.reduce.fminimum.v4f16(<4 x half> %a) +declare half @llvm.vector.reduce.fminimum.v11f16(<11 x half> %a) +declare float @llvm.vector.reduce.fminimum.v3f32(<3 x float> %a) +declare fp128 @llvm.vector.reduce.fminimum.v2f128(<2 x fp128> %a) +declare float @llvm.vector.reduce.fminimum.v16f32(<16 x float> %a) +declare double @llvm.vector.reduce.fminimum.v2f64(<2 x double> %a) + +define half @test_v1f16(<1 x half> %a) nounwind { +; CHECK-LABEL: test_v1f16: +; CHECK: // %bb.0: +; CHECK-NEXT: ret + %b = call half @llvm.vector.reduce.fminimum.v1f16(<1 x half> %a) + ret half %b +} + +define float @test_v1f32(<1 x float> %a) nounwind { +; CHECK-LABEL: test_v1f32: +; CHECK: // %bb.0: +; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NEXT: // kill: def $s0 killed $s0 killed $q0 +; CHECK-NEXT: ret + %b = call float @llvm.vector.reduce.fminimum.v1f32(<1 x float> %a) + ret float %b +} + +define double @test_v1f64(<1 x double> %a) nounwind { +; CHECK-LABEL: test_v1f64: +; CHECK: // %bb.0: +; CHECK-NEXT: ret + %b = call double @llvm.vector.reduce.fminimum.v1f64(<1 x double> %a) + ret double %b +} + +define fp128 @test_v1f128(<1 x fp128> %a) nounwind { +; CHECK-LABEL: test_v1f128: +; CHECK: // %bb.0: +; CHECK-NEXT: ret + %b = call fp128 @llvm.vector.reduce.fminimum.v1f128(<1 x fp128> %a) + ret fp128 %b +} + +define half @test_v4f16(<4 x half> %a) nounwind { +; CHECK-NOFP-LABEL: test_v4f16: +; CHECK-NOFP: // %bb.0: +; CHECK-NOFP-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-NOFP-NEXT: mov h1, v0.h[1] +; CHECK-NOFP-NEXT: fcvt s2, h0 +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: fmin s1, s2, s1 +; CHECK-NOFP-NEXT: mov h2, v0.h[2] +; CHECK-NOFP-NEXT: mov h0, v0.h[3] +; CHECK-NOFP-NEXT: fcvt h1, s1 +; CHECK-NOFP-NEXT: fcvt s2, h2 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: fmin s1, s1, s2 +; CHECK-NOFP-NEXT: fcvt h1, s1 +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: fmin s0, s1, s0 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: ret +; +; CHECK-FP-LABEL: test_v4f16: +; CHECK-FP: // %bb.0: +; CHECK-FP-NEXT: // kill: def $d0 killed $d0 def $q0 +; CHECK-FP-NEXT: mov h1, v0.h[1] +; CHECK-FP-NEXT: mov h2, v0.h[2] +; CHECK-FP-NEXT: fmin h1, h0, h1 +; CHECK-FP-NEXT: mov h0, v0.h[3] +; CHECK-FP-NEXT: fmin h1, h1, h2 +; CHECK-FP-NEXT: fmin h0, h1, h0 +; CHECK-FP-NEXT: ret + %b = call half @llvm.vector.reduce.fminimum.v4f16(<4 x half> %a) + ret half %b +} + +define half @test_v11f16(<11 x half> %a) nounwind { +; CHECK-NOFP-LABEL: test_v11f16: +; CHECK-NOFP: // %bb.0: +; CHECK-NOFP-NEXT: ldr h16, [sp, #8] +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: ldr h17, [sp] +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fcvt s2, h2 +; CHECK-NOFP-NEXT: fcvt s16, h16 +; CHECK-NOFP-NEXT: fcvt s17, h17 +; CHECK-NOFP-NEXT: fmin s1, s1, s16 +; CHECK-NOFP-NEXT: ldr h16, [sp, #16] +; CHECK-NOFP-NEXT: fmin s0, s0, s17 +; CHECK-NOFP-NEXT: fcvt s16, h16 +; CHECK-NOFP-NEXT: fcvt h1, s1 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fmin s1, s2, s16 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt h1, s1 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fcvt s1, h1 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt s1, h3 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt s1, h4 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt s1, h5 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt s1, h6 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt s1, h7 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: fcvt s0, h0 +; CHECK-NOFP-NEXT: fmin s0, s0, s1 +; CHECK-NOFP-NEXT: fcvt h0, s0 +; CHECK-NOFP-NEXT: ret +; +; CHECK-FP-LABEL: test_v11f16: +; CHECK-FP: // %bb.0: +; CHECK-FP-NEXT: // kill: def $h0 killed $h0 def $q0 +; CHECK-FP-NEXT: // kill: def $h1 killed $h1 def $q1 +; CHECK-FP-NEXT: // kill: def $h2 killed $h2 def $q2 +; CHECK-FP-NEXT: // kill: def $h3 killed $h3 def $q3 +; CHECK-FP-NEXT: // kill: def $h4 killed $h4 def $q4 +; CHECK-FP-NEXT: mov x8, sp +; CHECK-FP-NEXT: // kill: def $h5 killed $h5 def $q5 +; CHECK-FP-NEXT: // kill: def $h6 killed $h6 def $q6 +; CHECK-FP-NEXT: // kill: def $h7 killed $h7 def $q7 +; CHECK-FP-NEXT: mov v0.h[1], v1.h[0] +; CHECK-FP-NEXT: movi v1.8h, #124, lsl #8 +; CHECK-FP-NEXT: mov v0.h[2], v2.h[0] +; CHECK-FP-NEXT: ld1 { v1.h }[0], [x8] +; CHECK-FP-NEXT: add x8, sp, #8 +; CHECK-FP-NEXT: mov v0.h[3], v3.h[0] +; CHECK-FP-NEXT: ld1 { v1.h }[1], [x8] +; CHECK-FP-NEXT: add x8, sp, #16 +; CHECK-FP-NEXT: mov v0.h[4], v4.h[0] +; CHECK-FP-NEXT: ld1 { v1.h }[2], [x8] +; CHECK-FP-NEXT: mov v0.h[5], v5.h[0] +; CHECK-FP-NEXT: mov v0.h[6], v6.h[0] +; CHECK-FP-NEXT: mov v0.h[7], v7.h[0] +; CHECK-FP-NEXT: fmin v0.8h, v0.8h, v1.8h +; CHECK-FP-NEXT: ext v1.16b, v0.16b, v0.16b, #8 +; CHECK-FP-NEXT: fmin v0.4h, v0.4h, v1.4h +; CHECK-FP-NEXT: mov h1, v0.h[1] +; CHECK-FP-NEXT: mov h2, v0.h[2] +; CHECK-FP-NEXT: fmin h1, h0, h1 +; CHECK-FP-NEXT: mov h0, v0.h[3] +; CHECK-FP-NEXT: fmin h1, h1, h2 +; CHECK-FP-NEXT: fmin h0, h1, h0 +; CHECK-FP-NEXT: ret + %b = call half @llvm.vector.reduce.fminimum.v11f16(<11 x half> %a) + ret half %b +} + +; Neutral element is negative infinity which is chosen for padding the widened +; vector. +define float @test_v3f32(<3 x float> %a) nounwind { +; CHECK-LABEL: test_v3f32: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #2139095040 // =0x7f800000 +; CHECK-NEXT: fmov s1, w8 +; CHECK-NEXT: mov v0.s[3], v1.s[0] +; CHECK-NEXT: ext v1.16b, v0.16b, v0.16b, #8 +; CHECK-NEXT: fmin v0.2s, v0.2s, v1.2s +; CHECK-NEXT: mov s1, v0.s[1] +; CHECK-NEXT: fmin s0, s0, s1 +; CHECK-NEXT: ret + %b = call float @llvm.vector.reduce.fminimum.v3f32(<3 x float> %a) + ret float %b +} + +; Neutral element chosen for padding the widened vector is not negative infinity. +define float @test_v3f32_ninf(<3 x float> %a) nounwind { +; CHECK-LABEL: test_v3f32_ninf: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, #2139095039 // =0x7f7fffff +; CHECK-NEXT: fmov s1, w8 +; CHECK-NEXT: mov v0.s[3], v1.s[0] +; CHECK-NEXT: ext v1.16b, v0.16b, v0.16b, #8 +; CHECK-NEXT: fmin v0.2s, v0.2s, v1.2s +; CHECK-NEXT: mov s1, v0.s[1] +; CHECK-NEXT: fmin s0, s0, s1 +; CHECK-NEXT: ret + %b = call ninf float @llvm.vector.reduce.fminimum.v3f32(<3 x float> %a) + ret float %b +} + +; Cannot legalize f128. See PR63267 - The underlying fminimum has no default +; expansion and no libcalls. +;define fp128 @test_v2f128(<2 x fp128> %a) nounwind { +; %b = call fp128 @llvm.vector.reduce.fminimum.v2f128(<2 x fp128> %a) +; ret fp128 %b +;} + +define float @test_v16f32(<16 x float> %a) nounwind { +; CHECK-LABEL: test_v16f32: +; CHECK: // %bb.0: +; CHECK-NEXT: fmin v1.4s, v1.4s, v3.4s +; CHECK-NEXT: fmin v0.4s, v0.4s, v2.4s +; CHECK-NEXT: fmin v0.4s, v0.4s, v1.4s +; CHECK-NEXT: ext v1.16b, v0.16b, v0.16b, #8 +; CHECK-NEXT: fmin v0.2s, v0.2s, v1.2s +; CHECK-NEXT: mov s1, v0.s[1] +; CHECK-NEXT: fmin s0, s0, s1 +; CHECK-NEXT: ret + %b = call float @llvm.vector.reduce.fminimum.v16f32(<16 x float> %a) + ret float %b +} + +define double @test_v2f64(<2 x double> %a) nounwind { +; CHECK-LABEL: test_v2f64: +; CHECK: // %bb.0: +; CHECK-NEXT: mov d1, v0.d[1] +; CHECK-NEXT: fmin d0, d0, d1 +; CHECK-NEXT: ret + %b = call double @llvm.vector.reduce.fminimum.v2f64(<2 x double> %a) + ret double %b +} From 3fa96d699256c52b0e2df856e3fd7bec3e33fb73 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 19 Jun 2023 10:47:20 -0400 Subject: [PATCH 035/130] Reland "[gn build] Port 2700da5fe28d (lld/unittests etc)" The lld CL relanded in 6f2e92c10cebca5. This reverts commit d76b37e6954ad0cf66f1f3c6a9c70328c45859f3. --- llvm/utils/gn/secondary/lld/Common/BUILD.gn | 1 + llvm/utils/gn/secondary/lld/test/BUILD.gn | 81 +++++++++++++------ .../secondary/lld/unittests/AsLibAll/BUILD.gn | 14 ++++ .../secondary/lld/unittests/AsLibELF/BUILD.gn | 13 +++ .../utils/gn/secondary/lld/unittests/BUILD.gn | 8 ++ .../gn/secondary/llvm/utils/llvm-lit/BUILD.gn | 1 + 6 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 llvm/utils/gn/secondary/lld/unittests/AsLibAll/BUILD.gn create mode 100644 llvm/utils/gn/secondary/lld/unittests/AsLibELF/BUILD.gn create mode 100644 llvm/utils/gn/secondary/lld/unittests/BUILD.gn diff --git a/llvm/utils/gn/secondary/lld/Common/BUILD.gn b/llvm/utils/gn/secondary/lld/Common/BUILD.gn index 0d5713b6fd3f9..b5286545f867d 100644 --- a/llvm/utils/gn/secondary/lld/Common/BUILD.gn +++ b/llvm/utils/gn/secondary/lld/Common/BUILD.gn @@ -35,6 +35,7 @@ static_library("Common") { "Args.cpp", "CommonLinkerContext.cpp", "DWARF.cpp", + "DriverDispatcher.cpp", "ErrorHandler.cpp", "Filesystem.cpp", "Memory.cpp", diff --git a/llvm/utils/gn/secondary/lld/test/BUILD.gn b/llvm/utils/gn/secondary/lld/test/BUILD.gn index 01ee607e582eb..06256e1ba161b 100644 --- a/llvm/utils/gn/secondary/lld/test/BUILD.gn +++ b/llvm/utils/gn/secondary/lld/test/BUILD.gn @@ -3,28 +3,42 @@ import("//llvm/triples.gni") import("//llvm/utils/gn/build/libs/xml/enable.gni") import("//llvm/utils/gn/build/libs/zlib/enable.gni") import("//llvm/utils/gn/build/write_cmake_config.gni") +import("//llvm/utils/llvm-lit/lit_path_function.gni") import("lld_lit_site_cfg_files.gni") -write_cmake_config("lit_site_cfg") { +# The bits common to writing lit.site.cfg.py.in and Unit/lit.site.cfg.py.in. +template("write_lit_cfg") { + write_cmake_config(target_name) { + input = invoker.input + output = invoker.output + values = [ + "LIT_SITE_CFG_IN_HEADER=" + + "## Autogenerated from $input, do not edit\n\n" + lit_path_function, + "LLD_BINARY_DIR=" + + rebase_path(get_label_info("//lld", "target_out_dir")), + "CURRENT_LIBS_DIR=", # FIXME: for shared builds only (?) + "CURRENT_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), + "LLD_SOURCE_DIR=" + rebase_path("//lld"), + "LLVM_BINARY_DIR=" + + rebase_path(get_label_info("//llvm", "target_out_dir")), + "LLVM_SOURCE_DIR=" + rebase_path("//llvm"), + "LLVM_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), + ] + values += invoker.extra_values + } +} + +write_lit_cfg("lit_site_cfg") { # Fully-qualified instead of relative for LIT_SITE_CFG_IN_HEADER. input = "//lld/test/lit.site.cfg.py.in" output = lld_lit_site_cfg_file dir = get_path_info(output, "dir") - values = [ - "LIT_SITE_CFG_IN_HEADER=## Autogenerated from $input, do not edit", - "LLD_BINARY_DIR=" + rebase_path(get_label_info("//lld", "target_out_dir")), - "CURRENT_LIBS_DIR=", # FIXME: for shared builds only (?) - "CURRENT_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), + extra_values = [ "ENABLE_BACKTRACES=1", - "LLD_SOURCE_DIR=" + rebase_path("//lld"), - "LLVM_BINARY_DIR=" + - rebase_path(get_label_info("//llvm", "target_out_dir")), "LLVM_HOST_TRIPLE=$llvm_current_triple", "LLVM_LIBS_DIR=", # needed only for shared builds "LLVM_LIT_TOOLS_DIR=", # Intentionally empty, matches cmake build. - "LLVM_SOURCE_DIR=" + rebase_path("//llvm"), - "LLVM_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), "Python3_EXECUTABLE=$python_path", "LLVM_TARGET_TRIPLE=$llvm_target_triple", @@ -35,7 +49,7 @@ write_cmake_config("lit_site_cfg") { ] if (host_os == "win") { - values += [ + extra_values += [ "LLVM_LIT_ERRC_MESSAGES=no such file or directory;is a directory;" + "invalid argument;permission denied", "LLVM_ENABLE_PLUGINS=0", @@ -44,7 +58,7 @@ write_cmake_config("lit_site_cfg") { "SHLIBDIR=" + rebase_path("$root_out_dir/bin", dir), ] } else { - values += [ + extra_values += [ "LLVM_LIT_ERRC_MESSAGES=", "LLVM_ENABLE_PLUGINS=1", "SHLIBDIR=" + rebase_path("$root_out_dir/lib", dir), @@ -52,36 +66,53 @@ write_cmake_config("lit_site_cfg") { } if (host_os == "mac") { - values += [ "SHLIBEXT=.dylib" ] + extra_values += [ "SHLIBEXT=.dylib" ] } else if (host_os == "win") { - values += [ "SHLIBEXT=.dll" ] + extra_values += [ "SHLIBEXT=.dll" ] } else { - values += [ "SHLIBEXT=.so" ] + extra_values += [ "SHLIBEXT=.so" ] } if (llvm_enable_dia_sdk) { - values += [ "LLVM_ENABLE_DIA_SDK=1" ] + extra_values += [ "LLVM_ENABLE_DIA_SDK=1" ] } else { - values += [ "LLVM_ENABLE_DIA_SDK=0" ] # Must be 0. + extra_values += [ "LLVM_ENABLE_DIA_SDK=0" ] # Must be 0. } if (llvm_enable_libxml2) { - values += [ "LLVM_ENABLE_LIBXML2=1" ] + extra_values += [ "LLVM_ENABLE_LIBXML2=1" ] } else { - values += [ "LLVM_ENABLE_LIBXML2=0" ] # Must be 0. + extra_values += [ "LLVM_ENABLE_LIBXML2=0" ] # Must be 0. } if (llvm_enable_zlib) { - values += [ "LLVM_ENABLE_ZLIB=1" ] + extra_values += [ "LLVM_ENABLE_ZLIB=1" ] } else { - values += [ "LLVM_ENABLE_ZLIB=0" ] # Must be 0. + extra_values += [ "LLVM_ENABLE_ZLIB=0" ] # Must be 0. } if (current_cpu == "x64" || current_cpu == "arm64" || current_cpu == "ppc64") { - values += [ "CMAKE_SIZEOF_VOID_P=8" ] + extra_values += [ "CMAKE_SIZEOF_VOID_P=8" ] + } else { + extra_values += [ "CMAKE_SIZEOF_VOID_P=4" ] + } +} + +write_lit_cfg("lit_unit_site_cfg") { + # Fully-qualified instead of relative for LIT_SITE_CFG_IN_HEADER. + input = "//lld/test/Unit/lit.site.cfg.py.in" + output = lld_lit_unit_site_cfg_file + extra_values = [ + "ENABLE_SHARED=0", + "LLVM_BUILD_MODE=.", + ] + dir = get_path_info(output, "dir") + if (host_os == "win") { + # See comment for Windows solink in llvm/utils/gn/build/toolchain/BUILD.gn + extra_values += [ "SHLIBDIR=" + rebase_path("$root_out_dir/bin", dir) ] } else { - values += [ "CMAKE_SIZEOF_VOID_P=4" ] + extra_values += [ "SHLIBDIR=" + rebase_path("$root_out_dir/lib", dir) ] } } @@ -91,7 +122,9 @@ write_cmake_config("lit_site_cfg") { group("test") { deps = [ ":lit_site_cfg", + ":lit_unit_site_cfg", "//lld/tools/lld:symlinks", + "//lld/unittests", "//llvm/tools/dsymutil", "//llvm/tools/llc", "//llvm/tools/llvm-ar:symlinks", diff --git a/llvm/utils/gn/secondary/lld/unittests/AsLibAll/BUILD.gn b/llvm/utils/gn/secondary/lld/unittests/AsLibAll/BUILD.gn new file mode 100644 index 0000000000000..d6af6a1c73792 --- /dev/null +++ b/llvm/utils/gn/secondary/lld/unittests/AsLibAll/BUILD.gn @@ -0,0 +1,14 @@ +import("//third-party/unittest/unittest.gni") + +unittest("LLDAsLibAllTests") { + configs += [ "//llvm/utils/gn/build:lld_code" ] + deps = [ + "//lld/Common", + "//lld/COFF", + "//lld/ELF", + "//lld/MachO", + "//lld/MinGW", + "//lld/wasm", + ] + sources = [ "AllDrivers.cpp" ] +} diff --git a/llvm/utils/gn/secondary/lld/unittests/AsLibELF/BUILD.gn b/llvm/utils/gn/secondary/lld/unittests/AsLibELF/BUILD.gn new file mode 100644 index 0000000000000..e22a0eec1ff02 --- /dev/null +++ b/llvm/utils/gn/secondary/lld/unittests/AsLibELF/BUILD.gn @@ -0,0 +1,13 @@ +import("//third-party/unittest/unittest.gni") + +unittest("LLDAsLibELFTests") { + configs += [ "//llvm/utils/gn/build:lld_code" ] + deps = [ + "//lld/Common", + "//lld/ELF", + ] + sources = [ + "ROCm.cpp", + "SomeDrivers.cpp", + ] +} diff --git a/llvm/utils/gn/secondary/lld/unittests/BUILD.gn b/llvm/utils/gn/secondary/lld/unittests/BUILD.gn new file mode 100644 index 0000000000000..c909670f4b1ba --- /dev/null +++ b/llvm/utils/gn/secondary/lld/unittests/BUILD.gn @@ -0,0 +1,8 @@ +group("unittests") { + deps = [ + "AsLibAll:LLDAsLibAllTests", + "AsLibELF:LLDAsLibELFTests", + ] + testonly = true +} + diff --git a/llvm/utils/gn/secondary/llvm/utils/llvm-lit/BUILD.gn b/llvm/utils/gn/secondary/llvm/utils/llvm-lit/BUILD.gn index f9b71bf33cd04..5d3497e7e0044 100644 --- a/llvm/utils/gn/secondary/llvm/utils/llvm-lit/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/utils/llvm-lit/BUILD.gn @@ -31,6 +31,7 @@ write_cmake_config("llvm-lit") { "//clang/test:lit_site_cfg", "//clang/test:lit_unit_site_cfg", "//lld/test:lit_site_cfg", + "//lld/test:lit_unit_site_cfg", "//lldb/test:lit_api_site_cfg", "//lldb/test:lit_shell_site_cfg", "//lldb/test:lit_site_cfg", From f25003dfc28c0dae77b51782ae9e1b8d9fa69337 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 19 Jun 2023 10:48:35 -0400 Subject: [PATCH 036/130] [gn] port 3956a34e4fc6 --- llvm/utils/gn/secondary/libcxx/src/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn index fbdf26f50ec2a..330c280416f6d 100644 --- a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn @@ -149,6 +149,7 @@ cxx_sources = [ "mutex_destructor.cpp", "new.cpp", "new_handler.cpp", + "new_helpers.cpp", "optional.cpp", "random.cpp", "random_shuffle.cpp", From ce02978bd45086890eef0c407b456bcfcf7d4aac Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 19 Jun 2023 10:49:44 -0400 Subject: [PATCH 037/130] [gn] port c7d3c84449f4 --- llvm/utils/gn/secondary/libcxx/src/BUILD.gn | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn index 330c280416f6d..50ffd388a0d0f 100644 --- a/llvm/utils/gn/secondary/libcxx/src/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/src/BUILD.gn @@ -203,10 +203,16 @@ if (libcxx_enable_debug_mode) { } if (libcxx_enable_filesystem) { cxx_sources += [ + "filesystem/directory_entry.cpp", "filesystem/directory_iterator.cpp", - "filesystem/filesystem_common.h", + "filesystem/file_descriptor.h", + "filesystem/filesystem_clock.cpp", + "filesystem/filesystem_error.cpp", "filesystem/operations.cpp", + "filesystem/path.cpp", + "filesystem/path_parser.h", "filesystem/posix_compat.h", + "filesystem/time_utils.h", ] if (libcxx_use_compiler_rt) { cxx_sources += [ "filesystem/int128_builtins.cpp" ] From 3f1e45005fd19314abd4565be0c75e15091f1245 Mon Sep 17 00:00:00 2001 From: Nicolas Vasilache Date: Mon, 19 Jun 2023 14:51:12 +0000 Subject: [PATCH 038/130] Revert "[mlir][Vector] Let VectorToLLVM operate on non-ModuleOp" This reverts commit aabea3d320c87561fe98b56c9f53cca1c6d18869. That commit had mistakenly squashed spurious changes in. --- mlir/include/mlir/Conversion/Passes.td | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index 1e16d7b1dbdf8..ac53af4709098 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -361,6 +361,10 @@ def GpuToLLVMConversionPass : Pass<"gpu-to-llvm", "ModuleOp"> { }]; let options = [ + Option<"hostBarePtrCallConv", "use-bare-pointers-for-host", "bool", + /*default=*/"false", + "Use bare pointers to pass memref arguments to host functions. " + "All memrefs must have static shape.">, Option<"kernelBarePtrCallConv", "use-bare-pointers-for-kernels", "bool", /*default=*/"false", "Use bare pointers to pass memref arguments to kernels. " @@ -422,6 +426,10 @@ def ConvertGpuOpsToNVVMOps : Pass<"convert-gpu-to-nvvm", "gpu::GPUModuleOp"> { "Bitwidth of the index type, 0 to use size of machine word">, Option<"hasRedux", "has-redux", "bool", /*default=*/"false", "Target gpu supports redux">, + Option<"useBarePtrCallConv", "use-bare-ptr-memref-call-conv", "bool", + /*default=*/"false", + "Replace memref arguments in GPU functions with bare pointers. " + "All memrefs must have static shape.">, Option<"useOpaquePointers", "use-opaque-pointers", "bool", /*default=*/"true", "Generate LLVM IR using opaque pointers " "instead of typed pointers">, @@ -1057,7 +1065,7 @@ def ConvertVectorToSCF : Pass<"convert-vector-to-scf"> { // VectorToLLVM //===----------------------------------------------------------------------===// -def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm"> { +def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm", "ModuleOp"> { let summary = "Lower the operations from the vector dialect into the LLVM " "dialect"; let description = [{ @@ -1092,6 +1100,10 @@ def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm"> { "bool", /*default=*/"false", "Enables the use of ArmSVE dialect while lowering the vector " "dialect.">, + Option<"armSME", "enable-arm-sme", + "bool", /*default=*/"false", + "Enables the use of ArmSME dialect while lowering the vector " + "dialect.">, Option<"x86Vector", "enable-x86vector", "bool", /*default=*/"false", "Enables the use of X86Vector dialect while lowering the vector " From 72e598957c63c507f1d2dd63c365b64c11cf704f Mon Sep 17 00:00:00 2001 From: Nicolas Vasilache Date: Mon, 19 Jun 2023 14:54:14 +0000 Subject: [PATCH 039/130] [mlir][Vector] Let VectorToLLVM operate on non-ModuleOp --- mlir/include/mlir/Conversion/Passes.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td index ac53af4709098..287386411f935 100644 --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -1065,7 +1065,7 @@ def ConvertVectorToSCF : Pass<"convert-vector-to-scf"> { // VectorToLLVM //===----------------------------------------------------------------------===// -def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm", "ModuleOp"> { +def ConvertVectorToLLVMPass : Pass<"convert-vector-to-llvm"> { let summary = "Lower the operations from the vector dialect into the LLVM " "dialect"; let description = [{ From 3f05d044f491b97596fdaab7614f81cfb70ba54d Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 17 Jun 2023 12:00:23 +0200 Subject: [PATCH 040/130] [libc++] Update status after Varna meeting. This updates: - The status tables - Feature test macros - New headers for modules The latter avoids forgetting about modules when implementing the feature in a new header. Reviewed By: #libc, philnik Differential Revision: https://reviews.llvm.org/D153192 --- libcxx/docs/FeatureTestMacroTable.rst | 732 +++++++-------- libcxx/docs/Status/Cxx2cIssues.csv | 19 +- libcxx/docs/Status/Cxx2cPapers.csv | 27 + libcxx/docs/Status/FormatIssues.csv | 3 + libcxx/include/version | 40 +- libcxx/modules/CMakeLists.txt | 3 + libcxx/modules/std.cppm | 3 + libcxx/modules/std/hazard_pointer.cppm | 30 + libcxx/modules/std/rcu.cppm | 29 + libcxx/modules/std/text_encoding.cppm | 26 + .../bitset.version.compile.pass.cpp | 34 + .../fstream.version.compile.pass.cpp | 73 ++ .../functional.version.compile.pass.cpp | 78 +- .../map.version.compile.pass.cpp | 52 +- .../mdspan.version.compile.pass.cpp | 38 +- .../memory.version.compile.pass.cpp | 34 + .../ratio.version.compile.pass.cpp | 71 ++ .../set.version.compile.pass.cpp | 50 +- .../sstream.version.compile.pass.cpp | 73 ++ .../string.version.compile.pass.cpp | 43 + .../type_traits.version.compile.pass.cpp | 34 + .../unordered_map.version.compile.pass.cpp | 52 +- .../unordered_set.version.compile.pass.cpp | 50 +- .../version.version.compile.pass.cpp | 839 ++++++++++++++---- .../generate_feature_test_macro_components.py | 126 ++- 25 files changed, 1982 insertions(+), 577 deletions(-) create mode 100644 libcxx/modules/std/hazard_pointer.cppm create mode 100644 libcxx/modules/std/rcu.cppm create mode 100644 libcxx/modules/std/text_encoding.cppm create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/sstream.version.compile.pass.cpp diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index f24e210926473..45e580f397756 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -21,359 +21,391 @@ Status :name: feature-status-table :widths: auto - ================================================= ================= - Macro Name Value - ================================================= ================= + =================================================== ================= + Macro Name Value + =================================================== ================= **C++ 14** - ------------------------------------------------------------------- - ``__cpp_lib_chrono_udls`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_complex_udls`` ``201309L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_exchange_function`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_generic_associative_lookup`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_integer_sequence`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_integral_constant_callable`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_final`` ``201402L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_null_pointer`` ``201309L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_make_reverse_iterator`` ``201402L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_make_unique`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_null_iterators`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_quoted_string_io`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_result_of_sfinae`` ``201210L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_robust_nonmodifying_seq_ops`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shared_timed_mutex`` ``201402L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_string_udls`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_transformation_trait_aliases`` ``201304L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_transparent_operators`` ``201210L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_tuple_element_t`` ``201402L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_tuples_by_type`` ``201304L`` - ------------------------------------------------- ----------------- + --------------------------------------------------------------------- + ``__cpp_lib_chrono_udls`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_complex_udls`` ``201309L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_exchange_function`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_generic_associative_lookup`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_integer_sequence`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_integral_constant_callable`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_final`` ``201402L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_null_pointer`` ``201309L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_make_reverse_iterator`` ``201402L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_make_unique`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_null_iterators`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_quoted_string_io`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_result_of_sfinae`` ``201210L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_robust_nonmodifying_seq_ops`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shared_timed_mutex`` ``201402L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_string_udls`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_transformation_trait_aliases`` ``201304L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_transparent_operators`` ``201210L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_tuple_element_t`` ``201402L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_tuples_by_type`` ``201304L`` + --------------------------------------------------- ----------------- **C++ 17** - ------------------------------------------------------------------- - ``__cpp_lib_addressof_constexpr`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_allocator_traits_is_always_equal`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_any`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_apply`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_array_constexpr`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_as_const`` ``201510L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_is_always_lock_free`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_bool_constant`` ``201505L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_boyer_moore_searcher`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_byte`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_chrono`` ``201611L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_clamp`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_enable_shared_from_this`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_execution`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_filesystem`` ``201703L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_gcd_lcm`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_hardware_interference_size`` ``201703L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_has_unique_object_representations`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_hypot`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_incomplete_container_elements`` ``201505L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_invoke`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_aggregate`` ``201703L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_invocable`` ``201703L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_swappable`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_launder`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_logical_traits`` ``201510L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_make_from_tuple`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_map_try_emplace`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_math_special_functions`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_memory_resource`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_node_extract`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_nonmember_container_access`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_not_fn`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_optional`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_parallel_algorithm`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_raw_memory_algorithms`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_sample`` ``201603L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_scoped_lock`` ``201703L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shared_mutex`` ``201505L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shared_ptr_arrays`` ``201611L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shared_ptr_weak_type`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_string_view`` ``201606L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_to_chars`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_transparent_operators`` ``201510L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_type_trait_variable_templates`` ``201510L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_uncaught_exceptions`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_unordered_map_try_emplace`` ``201411L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_variant`` ``202102L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_void_t`` ``201411L`` - ------------------------------------------------- ----------------- + --------------------------------------------------------------------- + ``__cpp_lib_addressof_constexpr`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_allocator_traits_is_always_equal`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_any`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_apply`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_array_constexpr`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_as_const`` ``201510L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_is_always_lock_free`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_bool_constant`` ``201505L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_boyer_moore_searcher`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_byte`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_chrono`` ``201611L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_clamp`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_enable_shared_from_this`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_execution`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_filesystem`` ``201703L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_gcd_lcm`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_hardware_interference_size`` ``201703L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_has_unique_object_representations`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_hypot`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_incomplete_container_elements`` ``201505L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_invoke`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_aggregate`` ``201703L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_invocable`` ``201703L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_swappable`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_launder`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_logical_traits`` ``201510L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_make_from_tuple`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_map_try_emplace`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_math_special_functions`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_memory_resource`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_node_extract`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_nonmember_container_access`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_not_fn`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_optional`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_parallel_algorithm`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_raw_memory_algorithms`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_sample`` ``201603L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_scoped_lock`` ``201703L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shared_mutex`` ``201505L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shared_ptr_arrays`` ``201611L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shared_ptr_weak_type`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_string_view`` ``201606L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_to_chars`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_transparent_operators`` ``201510L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_type_trait_variable_templates`` ``201510L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_uncaught_exceptions`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_unordered_map_try_emplace`` ``201411L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_variant`` ``202102L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_void_t`` ``201411L`` + --------------------------------------------------- ----------------- **C++ 20** - ------------------------------------------------------------------- - ``__cpp_lib_array_constexpr`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_assume_aligned`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_flag_test`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_float`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_lock_free_type_aliases`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_ref`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_shared_ptr`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_value_initialization`` ``201911L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_atomic_wait`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_barrier`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_bind_front`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_bit_cast`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_bitops`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_bounded_array_traits`` ``201902L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_char8_t`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_concepts`` ``202002L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_algorithms`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_complex`` ``201711L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_dynamic_alloc`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_functional`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_iterator`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_memory`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_numeric`` ``201911L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_string`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_string_view`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_tuple`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_utility`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_vector`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_coroutine`` ``201902L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_destroying_delete`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_endian`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_erase_if`` ``202002L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_execution`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_format`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_generic_unordered_lookup`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_int_pow2`` ``202002L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_integer_comparison_functions`` ``202002L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_interpolate`` ``201902L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_constant_evaluated`` ``201811L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_layout_compatible`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_is_nothrow_convertible`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_pointer_interconvertible`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_jthread`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_latch`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_list_remove_return_type`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_math_constants`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_move_iterator_concept`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_polymorphic_allocator`` ``201902L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges`` ``202106L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_remove_cvref`` ``201711L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_semaphore`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shared_ptr_arrays`` ``201707L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_shift`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_smart_ptr_for_overwrite`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_source_location`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_span`` ``202002L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_ssize`` ``201902L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_starts_ends_with`` ``201711L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_string_view`` ``201803L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_syncbuf`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_three_way_comparison`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_to_address`` ``201711L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_to_array`` ``201907L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_type_identity`` ``201806L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_unwrap_ref`` ``201811L`` - ------------------------------------------------- ----------------- + --------------------------------------------------------------------- + ``__cpp_lib_array_constexpr`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_assume_aligned`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_flag_test`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_float`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_lock_free_type_aliases`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_ref`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_shared_ptr`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_value_initialization`` ``201911L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_atomic_wait`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_barrier`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_bind_front`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_bit_cast`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_bitops`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_bounded_array_traits`` ``201902L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_char8_t`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_concepts`` ``202002L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_algorithms`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_complex`` ``201711L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_dynamic_alloc`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_functional`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_iterator`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_memory`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_numeric`` ``201911L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_string`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_string_view`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_tuple`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_utility`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_vector`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_coroutine`` ``201902L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_destroying_delete`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_endian`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_erase_if`` ``202002L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_execution`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_format`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_generic_unordered_lookup`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_int_pow2`` ``202002L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_integer_comparison_functions`` ``202002L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_interpolate`` ``201902L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_constant_evaluated`` ``201811L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_layout_compatible`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_is_nothrow_convertible`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_pointer_interconvertible`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_jthread`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_latch`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_list_remove_return_type`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_math_constants`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_move_iterator_concept`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_polymorphic_allocator`` ``201902L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges`` ``202106L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_remove_cvref`` ``201711L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_semaphore`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shared_ptr_arrays`` ``201707L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_shift`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_smart_ptr_for_overwrite`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_source_location`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_span`` ``202002L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_ssize`` ``201902L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_starts_ends_with`` ``201711L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_string_view`` ``201803L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_syncbuf`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_three_way_comparison`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_to_address`` ``201711L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_to_array`` ``201907L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_type_identity`` ``201806L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_unwrap_ref`` ``201811L`` + --------------------------------------------------- ----------------- **C++ 23** - ------------------------------------------------------------------- - ``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_allocate_at_least`` ``202106L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_bind_back`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_byteswap`` ``202110L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_bitset`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_charconv`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_cmath`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_memory`` ``202202L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_constexpr_typeinfo`` ``202106L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_expected`` ``202211L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_format_ranges`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_formatters`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_forward_like`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_invoke_r`` ``202106L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_is_scoped_enum`` ``202011L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_mdspan`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_move_only_function`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_optional`` ``202110L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_out_ptr`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_as_rvalue`` ``202207L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_chunk`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_chunk_by`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_iota`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_join_with`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_slide`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_starts_ends_with`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_to_container`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_ranges_zip`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_reference_from_temporary`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_spanstream`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_stacktrace`` *unimplemented* - ------------------------------------------------- ----------------- - ``__cpp_lib_stdatomic_h`` ``202011L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_string_contains`` ``202011L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_string_resize_and_overwrite`` ``202110L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_to_underlying`` ``202102L`` - ------------------------------------------------- ----------------- - ``__cpp_lib_unreachable`` ``202202L`` - ------------------------------------------------- ----------------- + --------------------------------------------------------------------- + ``__cpp_lib_adaptor_iterator_pair_constructor`` ``202106L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_allocate_at_least`` ``202106L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_associative_heterogeneous_erasure`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_bind_back`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_byteswap`` ``202110L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_bitset`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_charconv`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_cmath`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_memory`` ``202202L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_constexpr_typeinfo`` ``202106L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_expected`` ``202211L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_format_ranges`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_formatters`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_forward_like`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_invoke_r`` ``202106L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_is_scoped_enum`` ``202011L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_mdspan`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_move_only_function`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_optional`` ``202110L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_out_ptr`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_as_rvalue`` ``202207L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_chunk`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_chunk_by`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_iota`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_join_with`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_slide`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_starts_ends_with`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_to_container`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ranges_zip`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_reference_from_temporary`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_spanstream`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_stacktrace`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_stdatomic_h`` ``202011L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_string_contains`` ``202011L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_string_resize_and_overwrite`` ``202110L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_to_string`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_to_underlying`` ``202102L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_unreachable`` ``202202L`` + --------------------------------------------------- ----------------- **C++ 26** - =================================================================== + --------------------------------------------------------------------- + ``__cpp_lib_associative_heterogeneous_insertion`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_bind_back`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_bind_front`` ``202306L`` + --------------------------------------------------- ----------------- + ``__cpp_lib_bitset`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_copyable_function`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_fstream_native_handle`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_function_ref`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_hazard_pointer`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_ratio`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_rcu`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_smart_ptr_owner_equality`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_sstream_from_string_view`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_submdspan`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_text_encoding`` *unimplemented* + --------------------------------------------------- ----------------- + ``__cpp_lib_within_lifetime`` *unimplemented* + =================================================== ================= diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv index b1d423e127f26..00da9135e0aae 100644 --- a/libcxx/docs/Status/Cxx2cIssues.csv +++ b/libcxx/docs/Status/Cxx2cIssues.csv @@ -1,5 +1,22 @@ "Issue #","Issue Name","Meeting","Status","First released version","Labels" +"`2994 `__","Needless UB for ``basic_string`` and ``basic_string_view``","Varna June 2023","","","" +"`3884 `__","``flat_foo`` is missing allocator-extended copy/move constructors","Varna June 2023","","","|flat_containers|" +"`3885 `__","``op`` should be in [zombie.names]","Varna June 2023","","","" +"`3887 `__","Version macro for ``allocate_at_least``","Varna June 2023","","","" +"`3893 `__","LWG 3661 broke ``atomic> a; a = nullptr;``","Varna June 2023","","","" +"`3894 `__","``generator::promise_type::yield_value(ranges::elements_of)`` should not be ``noexcept``","Varna June 2023","","","" +"`3903 `__","span destructor is redundantly noexcept","Varna June 2023","","","" +"`3904 `__","``lazy_split_view::outer-iterator``'s const-converting constructor isn't setting ``trailing_empty_``","Varna June 2023","","","|ranges|" +"`3905 `__","Type of ``std::fexcept_t``","Varna June 2023","","","" +"`3912 `__","``enumerate_view::iterator::operator-`` should be ``noexcept``","Varna June 2023","","","|ranges|" +"`3914 `__","Inconsistent template-head of ``ranges::enumerate_view``","Varna June 2023","","","|ranges|" +"`3915 `__","Redundant paragraph about expression variations","Varna June 2023","","","|ranges|" +"`3925 `__","Concept ``formattable``'s definition is incorrect","Varna June 2023","|In Progress|","","|format|" +"`3927 `__","Unclear preconditions for ``operator[]`` for sequence containers","Varna June 2023","","","" +"`3935 `__","``template constexpr complex& operator=(const complex&)`` has no specification","Varna June 2023","","","" +"`3938 `__","Cannot use ``std::expected`` monadic ops with move-only ``error_type``","Varna June 2023","","","" +"`3940 `__","``std::expected::value()`` also needs ``E`` to be copy constructible","Varna June 2023","","","" "","","","","","" "`3343 `__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0","" -"`3892 `__","Incorrect formatting of nested ranges and tuples","Not Yet Adopted","|Complete|","17.0","" +"`3892 `__","Incorrect formatting of nested ranges and tuples","Not Yet Adopted","|Complete|","17.0","|format|" "","","","","","" diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 8b6942024d865..494e70f22a356 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -1,2 +1,29 @@ "Paper #","Group","Paper Name","Meeting","Status","First released version","Labels" +"`P2497R0 `__","LWG","Testing for success or failure of ```` functions","Varna June 2023","","","" +"`P2592R3 `__","LWG","Hashing support for ``std::chrono`` value classes","Varna June 2023","","","" +"`P2587R3 `__","LWG","``to_string`` or not ``to_string``","Varna June 2023","","","|format|" +"`P2562R1 `__","LWG","``constexpr`` Stable Sorting","Varna June 2023","","","" +"`P2545R4 `__","LWG","Read-Copy Update (RCU)","Varna June 2023","","","" +"`P2530R3 `__","LWG","Hazard Pointers for C++26","Varna June 2023","","","" +"`P2538R1 `__","LWG","ADL-proof ``std::projected``","Varna June 2023","","","|ranges|" +"`P2495R3 `__","LWG","Interfacing ``stringstreams`` with ``string_view``","Varna June 2023","","","" +"`P2510R3 `__","LWG","Formatting pointers","Varna June 2023","|In Progress|","","|format|" +"`P2198R7 `__","LWG","Freestanding Feature-Test Macros and Implementation-Defined Extensions","Varna June 2023","","","" +"`P2338R4 `__","LWG","Freestanding Library: Character primitives and the C library","Varna June 2023","","","" +"`P2013R5 `__","LWG","Freestanding Language: Optional ``::operator new``","Varna June 2023","","","" +"`P2363R5 `__","LWG","Extending associative containers with the remaining heterogeneous overloads","Varna June 2023","","","" +"`P1901R2 `__","LWG","Enabling the Use of ``weak_ptr`` as Keys in Unordered Associative Containers","Varna June 2023","","","" +"`P1885R12 `__","LWG","Naming Text Encodings to Demystify Them","Varna June 2023","","","" +"`P0792R14 `__","LWG","``function_ref``: a type-erased callable reference","Varna June 2023","","","" +"`P2874R2 `__","LWG","Mandating Annex D Require No More","Varna June 2023","","","" +"`P2757R3 `__","LWG","Type-checking format args","Varna June 2023","","","|format|" +"`P2637R3 `__","LWG","Member ``visit``","Varna June 2023","","","|format|" +"`P2641R4 `__","CWG, LWG","Checking if a ``union`` alternative is active","Varna June 2023","","","" +"`P1759R6 `__","LWG","Native handles and file streams","Varna June 2023","","","" +"`P2697R1 `__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","","","" +"`P1383R2 `__","LWG","More ``constexpr`` for ```` and ````","Varna June 2023","","","" +"`P2734R0 `__","LWG","Adding the new SI prefixes","Varna June 2023","","","" +"`P2548R6 `__","LWG","``copyable_function``","Varna June 2023","","","" +"`P2714R1 `__","LWG","Bind front and back to NTTP callables","Varna June 2023","","","" +"`P2630R4 `__","LWG","``submdspan``","Varna June 2023","","","" "","","","","","","" diff --git a/libcxx/docs/Status/FormatIssues.csv b/libcxx/docs/Status/FormatIssues.csv index 20a0be7fc7bb2..0ac1fa6108750 100644 --- a/libcxx/docs/Status/FormatIssues.csv +++ b/libcxx/docs/Status/FormatIssues.csv @@ -14,6 +14,9 @@ Number,Name,Standard,Assignee,Status,First released version "`P2675R1 `__","``format``'s width estimation is too approximate and not forward compatible","C++23","Mark de Wever","|Complete|", Clang 17 "`P2572R1 `__","``std::format`` fill character allowances","C++23","Mark de Wever","|Complete|", Clang 17 "`P2693R1 `__","Formatting ``thread::id`` and ``stacktrace``","C++23","Mark de Wever","|In progress|" +"`P2510R3 `__","Formatting pointers","C++26","Mark de Wever","|In Progress|", +"`P2757R3 `__","Type-checking format args","C++26","","", +"`P2637R3 `__","Member ``visit``","C++26","","", `P1361 `_,"Integration of chrono with text formatting","C++20",Mark de Wever,|In Progress|, `P2372 `__,"Fixing locale handling in chrono formatters","C++20",Mark de Wever,|In Progress|, "`P2419R2 `__","Clarify handling of encodings in localized formatting of chrono types","C++23", diff --git a/libcxx/include/version b/libcxx/include/version index a1525397b988a..5f69eff42b0a1 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -28,6 +28,8 @@ __cpp_lib_array_constexpr 201811L __cpp_lib_associative_heterogeneous_erasure 202110L +__cpp_lib_associative_heterogeneous_insertion 202306L + __cpp_lib_assume_aligned 201811L __cpp_lib_atomic_flag_test 201907L __cpp_lib_atomic_float 201711L @@ -38,10 +40,13 @@ __cpp_lib_atomic_shared_ptr 201711L __cpp_lib_atomic_value_initialization 201911L __cpp_lib_atomic_wait 201907L __cpp_lib_barrier 201907L -__cpp_lib_bind_back 202202L -__cpp_lib_bind_front 201907L +__cpp_lib_bind_back 202306L + 202202L // C++23 +__cpp_lib_bind_front 202306L + 201907L // C++20 __cpp_lib_bit_cast 201806L __cpp_lib_bitops 201907L +__cpp_lib_bitset 202306L __cpp_lib_bool_constant 201505L __cpp_lib_bounded_array_traits 201902L __cpp_lib_boyer_moore_searcher 201603L @@ -72,6 +77,7 @@ __cpp_lib_constexpr_tuple 201811L __cpp_lib_constexpr_typeinfo 202106L __cpp_lib_constexpr_utility 201811L __cpp_lib_constexpr_vector 201907L +__cpp_lib_copyable_function 202306L __cpp_lib_coroutine 201902L __cpp_lib_destroying_delete 201806L __cpp_lib_enable_shared_from_this 201603L @@ -88,11 +94,14 @@ __cpp_lib_format 202106L __cpp_lib_format_ranges 202207L __cpp_lib_formatters 202302L __cpp_lib_forward_like 202207L +__cpp_lib_fstream_native_handle 202306L +__cpp_lib_function_ref 202306L __cpp_lib_gcd_lcm 201606L __cpp_lib_generic_associative_lookup 201304L __cpp_lib_generic_unordered_lookup 201811L __cpp_lib_hardware_interference_size 201703L __cpp_lib_has_unique_object_representations 201606L +__cpp_lib_hazard_pointer 202306L __cpp_lib_hypot 201603L __cpp_lib_incomplete_container_elements 201505L __cpp_lib_int_pow2 202002L @@ -155,7 +164,9 @@ __cpp_lib_ranges_to_container 202202L __cpp_lib_ranges_zip 202110L +__cpp_lib_ratio 202306L __cpp_lib_raw_memory_algorithms 201606L +__cpp_lib_rcu 202306L __cpp_lib_reference_from_temporary 202202L __cpp_lib_remove_cvref 201711L __cpp_lib_result_of_sfinae 201210L @@ -170,10 +181,12 @@ __cpp_lib_shared_ptr_weak_type 201606L __cpp_lib_shared_timed_mutex 201402L __cpp_lib_shift 201806L __cpp_lib_smart_ptr_for_overwrite 202002L +__cpp_lib_smart_ptr_owner_equality 202306L __cpp_lib_source_location 201907L __cpp_lib_span 202002L __cpp_lib_spanstream 202106L __cpp_lib_ssize 201902L +__cpp_lib_sstream_from_string_view 202306L __cpp_lib_stacktrace 202011L __cpp_lib_starts_ends_with 201711L __cpp_lib_stdatomic_h 202011L @@ -182,11 +195,14 @@ __cpp_lib_string_resize_and_overwrite 202110L __cpp_lib_string_udls 201304L __cpp_lib_string_view 201803L 201606L // C++17 +__cpp_lib_submdspan 202306L __cpp_lib_syncbuf 201803L +__cpp_lib_text_encoding 202306L __cpp_lib_three_way_comparison 201907L __cpp_lib_to_address 201711L __cpp_lib_to_array 201907L __cpp_lib_to_chars 201611L +__cpp_lib_to_string 202306L __cpp_lib_to_underlying 202102L __cpp_lib_transformation_trait_aliases 201304L __cpp_lib_transparent_operators 201510L @@ -201,6 +217,7 @@ __cpp_lib_unreachable 202202L __cpp_lib_unwrap_ref 201811L __cpp_lib_variant 202102L __cpp_lib_void_t 201411L +__cpp_lib_within_lifetime 202306L */ @@ -423,12 +440,29 @@ __cpp_lib_void_t 201411L # define __cpp_lib_stdatomic_h 202011L # define __cpp_lib_string_contains 202011L # define __cpp_lib_string_resize_and_overwrite 202110L +// # define __cpp_lib_to_string 202306L # define __cpp_lib_to_underlying 202102L # define __cpp_lib_unreachable 202202L #endif #if _LIBCPP_STD_VER >= 26 - +// # define __cpp_lib_associative_heterogeneous_insertion 202306L +# undef __cpp_lib_bind_back +// # define __cpp_lib_bind_back 202306L +# undef __cpp_lib_bind_front +# define __cpp_lib_bind_front 202306L +// # define __cpp_lib_bitset 202306L +// # define __cpp_lib_copyable_function 202306L +// # define __cpp_lib_fstream_native_handle 202306L +// # define __cpp_lib_function_ref 202306L +// # define __cpp_lib_hazard_pointer 202306L +// # define __cpp_lib_ratio 202306L +// # define __cpp_lib_rcu 202306L +// # define __cpp_lib_smart_ptr_owner_equality 202306L +// # define __cpp_lib_sstream_from_string_view 202306L +// # define __cpp_lib_submdspan 202306L +// # define __cpp_lib_text_encoding 202306L +// # define __cpp_lib_within_lifetime 202306L #endif // clang-format on diff --git a/libcxx/modules/CMakeLists.txt b/libcxx/modules/CMakeLists.txt index 0070780a65dd1..d24ddb0efc7fa 100644 --- a/libcxx/modules/CMakeLists.txt +++ b/libcxx/modules/CMakeLists.txt @@ -56,6 +56,7 @@ set(LIBCXX_SOURCES_MODULE_STD std/functional.cppm std/future.cppm std/generator.cppm + std/hazard_pointer.cppm std/initializer_list.cppm std/iomanip.cppm std/ios.cppm @@ -83,6 +84,7 @@ set(LIBCXX_SOURCES_MODULE_STD std/random.cppm std/ranges.cppm std/ratio.cppm + std/rcu.cppm std/regex.cppm std/scoped_allocator.cppm std/semaphore.cppm @@ -104,6 +106,7 @@ set(LIBCXX_SOURCES_MODULE_STD std/strstream.cppm std/syncstream.cppm std/system_error.cppm + std/text_encoding.cppm std/thread.cppm std/tuple.cppm std/type_traits.cppm diff --git a/libcxx/modules/std.cppm b/libcxx/modules/std.cppm index d01e167169e53..fcd7d55bbed0a 100644 --- a/libcxx/modules/std.cppm +++ b/libcxx/modules/std.cppm @@ -61,6 +61,7 @@ export import :fstream; export import :functional; export import :future; export import :generator; +export import :hazard_pointer; export import :initializer_list; export import :iomanip; export import :ios; @@ -86,6 +87,7 @@ export import :queue; export import :random; export import :ranges; export import :ratio; +export import :rcu; export import :regex; export import :scoped_allocator; export import :semaphore; @@ -106,6 +108,7 @@ export import :string_view; export import :strstream; export import :syncstream; export import :system_error; +export import :text_encoding; export import :thread; export import :tuple; export import :type_traits; diff --git a/libcxx/modules/std/hazard_pointer.cppm b/libcxx/modules/std/hazard_pointer.cppm new file mode 100644 index 0000000000000..84b83f55b31fb --- /dev/null +++ b/libcxx/modules/std/hazard_pointer.cppm @@ -0,0 +1,30 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +module; +#if __has_include() +# error "include this header unconditionally and uncomment the exported symbols" +# include +#endif + +export module std:hazard_pointer; +export namespace std { +#if 0 +# if _LIBCPP_STD_VER >= 23 + // 4.1.3, class template hazard_pointer_obj_base + using std::hazard_pointer_obj_base; + // 4.1.4, class hazard_pointer + using std::hazard_pointer; + // 4.1.5, Construct non-empty hazard_pointer + using std::make_hazard_pointer; + // 4.1.6, Hazard pointer swap + using std::swap; +# endif // _LIBCPP_STD_VER >= 23 +#endif +} // namespace std diff --git a/libcxx/modules/std/rcu.cppm b/libcxx/modules/std/rcu.cppm new file mode 100644 index 0000000000000..fb5e5e1a5066a --- /dev/null +++ b/libcxx/modules/std/rcu.cppm @@ -0,0 +1,29 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +module; +#if __has_include() +# error "include this header unconditionally and uncomment the exported symbols" +# include +#endif + +export module std:rcu; +export namespace std { +#if 0 +# if _LIBCPP_STD_VER >= 23 + // 2.2.3, class template rcu_obj_base using std::rcu_obj_base; + // 2.2.4, class rcu_domain + using std::rcu_domain; + using std::rcu_default_domain(); + using std::rcu_barrier; + using std::rcu_retire; + using std::rcu_synchronize; +# endif // _LIBCPP_STD_VER >= 23 +#endif +} // namespace std diff --git a/libcxx/modules/std/text_encoding.cppm b/libcxx/modules/std/text_encoding.cppm new file mode 100644 index 0000000000000..dcbaa734a6856 --- /dev/null +++ b/libcxx/modules/std/text_encoding.cppm @@ -0,0 +1,26 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +module; +#if __has_include() +# error "include this header unconditionally and uncomment the exported symbols" +# include +#endif + +export module std:text_encoding; +export namespace std { +#if 0 +# if _LIBCPP_STD_VER >= 23 + using std::text_encoding; + + // hash support + using std::hash; +# endif // _LIBCPP_STD_VER >= 23 +#endif +} // namespace std diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/bitset.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/bitset.version.compile.pass.cpp index bd1f5feddac0d..e850479d99e1c 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/bitset.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/bitset.version.compile.pass.cpp @@ -16,6 +16,7 @@ // Test the feature test macros defined by /* Constant Value + __cpp_lib_bitset 202306L [C++26] __cpp_lib_constexpr_bitset 202207L [C++23] */ @@ -24,30 +25,50 @@ #if TEST_STD_VER < 14 +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should not be defined before c++23" # endif #elif TEST_STD_VER == 14 +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should not be defined before c++23" # endif #elif TEST_STD_VER == 17 +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should not be defined before c++23" # endif #elif TEST_STD_VER == 20 +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should not be defined before c++23" # endif #elif TEST_STD_VER == 23 +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifndef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should be defined in c++23" # endif @@ -57,6 +78,19 @@ #elif TEST_STD_VER > 23 +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_bitset +# error "__cpp_lib_bitset should be defined in c++26" +# endif +# if __cpp_lib_bitset != 202306L +# error "__cpp_lib_bitset should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_constexpr_bitset # error "__cpp_lib_constexpr_bitset should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp new file mode 100644 index 0000000000000..981f5420ff7e0 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/fstream.version.compile.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// UNSUPPORTED: no-localization + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_fstream_native_handle 202306L [C++26] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 23 + +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should be defined in c++26" +# endif +# if __cpp_lib_fstream_native_handle != 202306L +# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp index 79cb615c518f3..f14b127e51951 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp @@ -17,9 +17,13 @@ /* Constant Value __cpp_lib_bind_back 202202L [C++23] + 202306L [C++26] __cpp_lib_bind_front 201907L [C++20] + 202306L [C++26] __cpp_lib_boyer_moore_searcher 201603L [C++17] __cpp_lib_constexpr_functional 201907L [C++20] + __cpp_lib_copyable_function 202306L [C++26] + __cpp_lib_function_ref 202306L [C++26] __cpp_lib_invoke 201411L [C++17] __cpp_lib_invoke_r 202106L [C++23] __cpp_lib_move_only_function 202110L [C++23] @@ -52,6 +56,14 @@ # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifdef __cpp_lib_invoke # error "__cpp_lib_invoke should not be defined before c++17" # endif @@ -102,6 +114,14 @@ # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifdef __cpp_lib_invoke # error "__cpp_lib_invoke should not be defined before c++17" # endif @@ -161,6 +181,14 @@ # error "__cpp_lib_constexpr_functional should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_invoke # error "__cpp_lib_invoke should be defined in c++17" # endif @@ -232,6 +260,14 @@ # error "__cpp_lib_constexpr_functional should have the value 201907L in c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_invoke # error "__cpp_lib_invoke should be defined in c++20" # endif @@ -318,6 +354,14 @@ # error "__cpp_lib_constexpr_functional should have the value 201907L in c++23" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_invoke # error "__cpp_lib_invoke should be defined in c++23" # endif @@ -386,8 +430,8 @@ # ifndef __cpp_lib_bind_back # error "__cpp_lib_bind_back should be defined in c++26" # endif -# if __cpp_lib_bind_back != 202202L -# error "__cpp_lib_bind_back should have the value 202202L in c++26" +# if __cpp_lib_bind_back != 202306L +# error "__cpp_lib_bind_back should have the value 202306L in c++26" # endif # else // _LIBCPP_VERSION # ifdef __cpp_lib_bind_back @@ -398,8 +442,8 @@ # ifndef __cpp_lib_bind_front # error "__cpp_lib_bind_front should be defined in c++26" # endif -# if __cpp_lib_bind_front != 201907L -# error "__cpp_lib_bind_front should have the value 201907L in c++26" +# if __cpp_lib_bind_front != 202306L +# error "__cpp_lib_bind_front should have the value 202306L in c++26" # endif # ifndef __cpp_lib_boyer_moore_searcher @@ -416,6 +460,32 @@ # error "__cpp_lib_constexpr_functional should have the value 201907L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should be defined in c++26" +# endif +# if __cpp_lib_copyable_function != 202306L +# error "__cpp_lib_copyable_function should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined because it is unimplemented in libc++!" +# endif +# endif + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should be defined in c++26" +# endif +# if __cpp_lib_function_ref != 202306L +# error "__cpp_lib_function_ref should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_invoke # error "__cpp_lib_invoke should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp index 28d10cd3e7f1f..8599c54e24923 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/map.version.compile.pass.cpp @@ -15,15 +15,16 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] - __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] - __cpp_lib_erase_if 202002L [C++20] - __cpp_lib_generic_associative_lookup 201304L [C++14] - __cpp_lib_map_try_emplace 201411L [C++17] - __cpp_lib_node_extract 201606L [C++17] - __cpp_lib_nonmember_container_access 201411L [C++17] - __cpp_lib_ranges_to_container 202202L [C++23] +/* Constant Value + __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] + __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] + __cpp_lib_associative_heterogeneous_insertion 202306L [C++26] + __cpp_lib_erase_if 202002L [C++20] + __cpp_lib_generic_associative_lookup 201304L [C++14] + __cpp_lib_map_try_emplace 201411L [C++17] + __cpp_lib_node_extract 201606L [C++17] + __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_ranges_to_container 202202L [C++23] */ #include @@ -39,6 +40,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -73,6 +78,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -113,6 +122,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -162,6 +175,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++20" # endif @@ -223,6 +240,10 @@ # endif # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++23" # endif @@ -293,6 +314,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should be defined in c++26" +# endif +# if __cpp_lib_associative_heterogeneous_insertion != 202306L +# error "__cpp_lib_associative_heterogeneous_insertion should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp index c2da617f42cc1..e47d678b254ef 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp @@ -15,8 +15,9 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_mdspan 202207L [C++23] +/* Constant Value + __cpp_lib_mdspan 202207L [C++23] + __cpp_lib_submdspan 202306L [C++26] */ #include @@ -28,24 +29,40 @@ # error "__cpp_lib_mdspan should not be defined before c++23" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + #elif TEST_STD_VER == 14 # ifdef __cpp_lib_mdspan # error "__cpp_lib_mdspan should not be defined before c++23" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + #elif TEST_STD_VER == 17 # ifdef __cpp_lib_mdspan # error "__cpp_lib_mdspan should not be defined before c++23" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + #elif TEST_STD_VER == 20 # ifdef __cpp_lib_mdspan # error "__cpp_lib_mdspan should not be defined before c++23" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + #elif TEST_STD_VER == 23 # if !defined(_LIBCPP_VERSION) @@ -61,6 +78,10 @@ # endif # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + #elif TEST_STD_VER > 23 # if !defined(_LIBCPP_VERSION) @@ -76,5 +97,18 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should be defined in c++26" +# endif +# if __cpp_lib_submdspan != 202306L +# error "__cpp_lib_submdspan should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined because it is unimplemented in libc++!" +# endif +# endif + #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp index 7db7c956d3751..02559d1340531 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/memory.version.compile.pass.cpp @@ -33,6 +33,7 @@ 201707L [C++20] __cpp_lib_shared_ptr_weak_type 201606L [C++17] __cpp_lib_smart_ptr_for_overwrite 202002L [C++20] + __cpp_lib_smart_ptr_owner_equality 202306L [C++26] __cpp_lib_to_address 201711L [C++20] __cpp_lib_transparent_operators 201210L [C++14] 201510L [C++17] @@ -103,6 +104,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_to_address # error "__cpp_lib_to_address should not be defined before c++20" # endif @@ -176,6 +181,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_to_address # error "__cpp_lib_to_address should not be defined before c++20" # endif @@ -270,6 +279,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_to_address # error "__cpp_lib_to_address should not be defined before c++20" # endif @@ -388,6 +401,10 @@ # endif # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifndef __cpp_lib_to_address # error "__cpp_lib_to_address should be defined in c++20" # endif @@ -521,6 +538,10 @@ # endif # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifndef __cpp_lib_to_address # error "__cpp_lib_to_address should be defined in c++23" # endif @@ -654,6 +675,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26" +# endif +# if __cpp_lib_smart_ptr_owner_equality != 202306L +# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_to_address # error "__cpp_lib_to_address should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp new file mode 100644 index 0000000000000..f782c24898b43 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_ratio 202306L [C++26] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 23 + +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_ratio +# error "__cpp_lib_ratio should be defined in c++26" +# endif +# if __cpp_lib_ratio != 202306L +# error "__cpp_lib_ratio should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp index 23f93805cc169..241b66b2bfc31 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/set.version.compile.pass.cpp @@ -15,14 +15,15 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] - __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] - __cpp_lib_erase_if 202002L [C++20] - __cpp_lib_generic_associative_lookup 201304L [C++14] - __cpp_lib_node_extract 201606L [C++17] - __cpp_lib_nonmember_container_access 201411L [C++17] - __cpp_lib_ranges_to_container 202202L [C++23] +/* Constant Value + __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] + __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] + __cpp_lib_associative_heterogeneous_insertion 202306L [C++26] + __cpp_lib_erase_if 202002L [C++20] + __cpp_lib_generic_associative_lookup 201304L [C++14] + __cpp_lib_node_extract 201606L [C++17] + __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_ranges_to_container 202202L [C++23] */ #include @@ -38,6 +39,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -68,6 +73,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -104,6 +113,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -146,6 +159,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++20" # endif @@ -200,6 +217,10 @@ # endif # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++23" # endif @@ -263,6 +284,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should be defined in c++26" +# endif +# if __cpp_lib_associative_heterogeneous_insertion != 202306L +# error "__cpp_lib_associative_heterogeneous_insertion should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/sstream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/sstream.version.compile.pass.cpp new file mode 100644 index 0000000000000..78e17e5f1ddb5 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/sstream.version.compile.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// WARNING: This test was generated by generate_feature_test_macro_components.py +// and should not be edited manually. +// +// clang-format off + +// UNSUPPORTED: no-localization + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_sstream_from_string_view 202306L [C++26] +*/ + +#include +#include "test_macros.h" + +#if TEST_STD_VER < 14 + +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 14 + +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 17 + +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 20 + +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + +#elif TEST_STD_VER == 23 + +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + +#elif TEST_STD_VER > 23 + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should be defined in c++26" +# endif +# if __cpp_lib_sstream_from_string_view != 202306L +# error "__cpp_lib_sstream_from_string_view should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined because it is unimplemented in libc++!" +# endif +# endif + +#endif // TEST_STD_VER > 23 + diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp index e869fedbdaaf2..5902bdbd15521 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/string.version.compile.pass.cpp @@ -28,6 +28,7 @@ __cpp_lib_string_udls 201304L [C++14] __cpp_lib_string_view 201606L [C++17] 201803L [C++20] + __cpp_lib_to_string 202306L [C++23] */ #include @@ -79,6 +80,10 @@ # error "__cpp_lib_string_view should not be defined before c++17" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + #elif TEST_STD_VER == 14 # ifdef __cpp_lib_allocator_traits_is_always_equal @@ -128,6 +133,10 @@ # error "__cpp_lib_string_view should not be defined before c++17" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + #elif TEST_STD_VER == 17 # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -186,6 +195,10 @@ # error "__cpp_lib_string_view should have the value 201606L in c++17" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + #elif TEST_STD_VER == 20 # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -262,6 +275,10 @@ # error "__cpp_lib_string_view should have the value 201803L in c++20" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + #elif TEST_STD_VER == 23 # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -353,6 +370,19 @@ # error "__cpp_lib_string_view should have the value 201803L in c++23" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_to_string +# error "__cpp_lib_to_string should be defined in c++23" +# endif +# if __cpp_lib_to_string != 202306L +# error "__cpp_lib_to_string should have the value 202306L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!" +# endif +# endif + #elif TEST_STD_VER > 23 # ifndef __cpp_lib_allocator_traits_is_always_equal @@ -444,5 +474,18 @@ # error "__cpp_lib_string_view should have the value 201803L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_to_string +# error "__cpp_lib_to_string should be defined in c++26" +# endif +# if __cpp_lib_to_string != 202306L +# error "__cpp_lib_to_string should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!" +# endif +# endif + #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp index a851b1bbb19d4..b1dd76b98720d 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/type_traits.version.compile.pass.cpp @@ -38,6 +38,7 @@ __cpp_lib_type_identity 201806L [C++20] __cpp_lib_type_trait_variable_templates 201510L [C++17] __cpp_lib_void_t 201411L [C++17] + __cpp_lib_within_lifetime 202306L [C++26] */ #include @@ -133,6 +134,10 @@ # error "__cpp_lib_void_t should not be defined before c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 14 # ifdef __cpp_lib_bool_constant @@ -238,6 +243,10 @@ # error "__cpp_lib_void_t should not be defined before c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 17 # ifndef __cpp_lib_bool_constant @@ -367,6 +376,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 20 # ifndef __cpp_lib_bool_constant @@ -529,6 +542,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++20" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 23 # ifndef __cpp_lib_bool_constant @@ -703,6 +720,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++23" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER > 23 # ifndef __cpp_lib_bool_constant @@ -877,5 +898,18 @@ # error "__cpp_lib_void_t should have the value 201411L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should be defined in c++26" +# endif +# if __cpp_lib_within_lifetime != 202306L +# error "__cpp_lib_within_lifetime should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined because it is unimplemented in libc++!" +# endif +# endif + #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp index 0e5b5985df60e..c3dfb78cfadd1 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_map.version.compile.pass.cpp @@ -15,15 +15,16 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] - __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] - __cpp_lib_erase_if 202002L [C++20] - __cpp_lib_generic_unordered_lookup 201811L [C++20] - __cpp_lib_node_extract 201606L [C++17] - __cpp_lib_nonmember_container_access 201411L [C++17] - __cpp_lib_ranges_to_container 202202L [C++23] - __cpp_lib_unordered_map_try_emplace 201411L [C++17] +/* Constant Value + __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] + __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] + __cpp_lib_associative_heterogeneous_insertion 202306L [C++26] + __cpp_lib_erase_if 202002L [C++20] + __cpp_lib_generic_unordered_lookup 201811L [C++20] + __cpp_lib_node_extract 201606L [C++17] + __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_ranges_to_container 202202L [C++23] + __cpp_lib_unordered_map_try_emplace 201411L [C++17] */ #include @@ -39,6 +40,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -73,6 +78,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -110,6 +119,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -156,6 +169,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++20" # endif @@ -217,6 +234,10 @@ # endif # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++23" # endif @@ -287,6 +308,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should be defined in c++26" +# endif +# if __cpp_lib_associative_heterogeneous_insertion != 202306L +# error "__cpp_lib_associative_heterogeneous_insertion should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp index 8a3a8afd5b473..d215aec861564 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/unordered_set.version.compile.pass.cpp @@ -15,14 +15,15 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] - __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] - __cpp_lib_erase_if 202002L [C++20] - __cpp_lib_generic_unordered_lookup 201811L [C++20] - __cpp_lib_node_extract 201606L [C++17] - __cpp_lib_nonmember_container_access 201411L [C++17] - __cpp_lib_ranges_to_container 202202L [C++23] +/* Constant Value + __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] + __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] + __cpp_lib_associative_heterogeneous_insertion 202306L [C++26] + __cpp_lib_erase_if 202002L [C++20] + __cpp_lib_generic_unordered_lookup 201811L [C++20] + __cpp_lib_node_extract 201606L [C++17] + __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_ranges_to_container 202202L [C++23] */ #include @@ -38,6 +39,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -68,6 +73,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -101,6 +110,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_erase_if # error "__cpp_lib_erase_if should not be defined before c++20" # endif @@ -140,6 +153,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++20" # endif @@ -194,6 +211,10 @@ # endif # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++23" # endif @@ -257,6 +278,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should be defined in c++26" +# endif +# if __cpp_lib_associative_heterogeneous_insertion != 202306L +# error "__cpp_lib_associative_heterogeneous_insertion should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_erase_if # error "__cpp_lib_erase_if should be defined in c++26" # endif diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index 8443fb1d97513..dbad0e6b3cf0c 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -15,178 +15,194 @@ // Test the feature test macros defined by -/* Constant Value - __cpp_lib_adaptor_iterator_pair_constructor 202106L [C++23] - __cpp_lib_addressof_constexpr 201603L [C++17] - __cpp_lib_allocate_at_least 202106L [C++23] - __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] - __cpp_lib_any 201606L [C++17] - __cpp_lib_apply 201603L [C++17] - __cpp_lib_array_constexpr 201603L [C++17] - 201811L [C++20] - __cpp_lib_as_const 201510L [C++17] - __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] - __cpp_lib_assume_aligned 201811L [C++20] - __cpp_lib_atomic_flag_test 201907L [C++20] - __cpp_lib_atomic_float 201711L [C++20] - __cpp_lib_atomic_is_always_lock_free 201603L [C++17] - __cpp_lib_atomic_lock_free_type_aliases 201907L [C++20] - __cpp_lib_atomic_ref 201806L [C++20] - __cpp_lib_atomic_shared_ptr 201711L [C++20] - __cpp_lib_atomic_value_initialization 201911L [C++20] - __cpp_lib_atomic_wait 201907L [C++20] - __cpp_lib_barrier 201907L [C++20] - __cpp_lib_bind_back 202202L [C++23] - __cpp_lib_bind_front 201907L [C++20] - __cpp_lib_bit_cast 201806L [C++20] - __cpp_lib_bitops 201907L [C++20] - __cpp_lib_bool_constant 201505L [C++17] - __cpp_lib_bounded_array_traits 201902L [C++20] - __cpp_lib_boyer_moore_searcher 201603L [C++17] - __cpp_lib_byte 201603L [C++17] - __cpp_lib_byteswap 202110L [C++23] - __cpp_lib_char8_t 201907L [C++20] - __cpp_lib_chrono 201611L [C++17] - __cpp_lib_chrono_udls 201304L [C++14] - __cpp_lib_clamp 201603L [C++17] - __cpp_lib_complex_udls 201309L [C++14] - __cpp_lib_concepts 202002L [C++20] - __cpp_lib_constexpr_algorithms 201806L [C++20] - __cpp_lib_constexpr_bitset 202207L [C++23] - __cpp_lib_constexpr_charconv 202207L [C++23] - __cpp_lib_constexpr_cmath 202202L [C++23] - __cpp_lib_constexpr_complex 201711L [C++20] - __cpp_lib_constexpr_dynamic_alloc 201907L [C++20] - __cpp_lib_constexpr_functional 201907L [C++20] - __cpp_lib_constexpr_iterator 201811L [C++20] - __cpp_lib_constexpr_memory 201811L [C++20] - 202202L [C++23] - __cpp_lib_constexpr_numeric 201911L [C++20] - __cpp_lib_constexpr_string 201907L [C++20] - __cpp_lib_constexpr_string_view 201811L [C++20] - __cpp_lib_constexpr_tuple 201811L [C++20] - __cpp_lib_constexpr_typeinfo 202106L [C++23] - __cpp_lib_constexpr_utility 201811L [C++20] - __cpp_lib_constexpr_vector 201907L [C++20] - __cpp_lib_coroutine 201902L [C++20] - __cpp_lib_destroying_delete 201806L [C++20] - __cpp_lib_enable_shared_from_this 201603L [C++17] - __cpp_lib_endian 201907L [C++20] - __cpp_lib_erase_if 202002L [C++20] - __cpp_lib_exchange_function 201304L [C++14] - __cpp_lib_execution 201603L [C++17] - 201902L [C++20] - __cpp_lib_expected 202211L [C++23] - __cpp_lib_filesystem 201703L [C++17] - __cpp_lib_format 202106L [C++20] - __cpp_lib_format_ranges 202207L [C++23] - __cpp_lib_formatters 202302L [C++23] - __cpp_lib_forward_like 202207L [C++23] - __cpp_lib_gcd_lcm 201606L [C++17] - __cpp_lib_generic_associative_lookup 201304L [C++14] - __cpp_lib_generic_unordered_lookup 201811L [C++20] - __cpp_lib_hardware_interference_size 201703L [C++17] - __cpp_lib_has_unique_object_representations 201606L [C++17] - __cpp_lib_hypot 201603L [C++17] - __cpp_lib_incomplete_container_elements 201505L [C++17] - __cpp_lib_int_pow2 202002L [C++20] - __cpp_lib_integer_comparison_functions 202002L [C++20] - __cpp_lib_integer_sequence 201304L [C++14] - __cpp_lib_integral_constant_callable 201304L [C++14] - __cpp_lib_interpolate 201902L [C++20] - __cpp_lib_invoke 201411L [C++17] - __cpp_lib_invoke_r 202106L [C++23] - __cpp_lib_is_aggregate 201703L [C++17] - __cpp_lib_is_constant_evaluated 201811L [C++20] - __cpp_lib_is_final 201402L [C++14] - __cpp_lib_is_invocable 201703L [C++17] - __cpp_lib_is_layout_compatible 201907L [C++20] - __cpp_lib_is_nothrow_convertible 201806L [C++20] - __cpp_lib_is_null_pointer 201309L [C++14] - __cpp_lib_is_pointer_interconvertible 201907L [C++20] - __cpp_lib_is_scoped_enum 202011L [C++23] - __cpp_lib_is_swappable 201603L [C++17] - __cpp_lib_jthread 201911L [C++20] - __cpp_lib_latch 201907L [C++20] - __cpp_lib_launder 201606L [C++17] - __cpp_lib_list_remove_return_type 201806L [C++20] - __cpp_lib_logical_traits 201510L [C++17] - __cpp_lib_make_from_tuple 201606L [C++17] - __cpp_lib_make_reverse_iterator 201402L [C++14] - __cpp_lib_make_unique 201304L [C++14] - __cpp_lib_map_try_emplace 201411L [C++17] - __cpp_lib_math_constants 201907L [C++20] - __cpp_lib_math_special_functions 201603L [C++17] - __cpp_lib_mdspan 202207L [C++23] - __cpp_lib_memory_resource 201603L [C++17] - __cpp_lib_move_iterator_concept 202207L [C++20] - __cpp_lib_move_only_function 202110L [C++23] - __cpp_lib_node_extract 201606L [C++17] - __cpp_lib_nonmember_container_access 201411L [C++17] - __cpp_lib_not_fn 201603L [C++17] - __cpp_lib_null_iterators 201304L [C++14] - __cpp_lib_optional 201606L [C++17] - 202110L [C++23] - __cpp_lib_out_ptr 202106L [C++23] - __cpp_lib_parallel_algorithm 201603L [C++17] - __cpp_lib_polymorphic_allocator 201902L [C++20] - __cpp_lib_quoted_string_io 201304L [C++14] - __cpp_lib_ranges 202106L [C++20] - __cpp_lib_ranges_as_rvalue 202207L [C++23] - __cpp_lib_ranges_chunk 202202L [C++23] - __cpp_lib_ranges_chunk_by 202202L [C++23] - __cpp_lib_ranges_iota 202202L [C++23] - __cpp_lib_ranges_join_with 202202L [C++23] - __cpp_lib_ranges_slide 202202L [C++23] - __cpp_lib_ranges_starts_ends_with 202106L [C++23] - __cpp_lib_ranges_to_container 202202L [C++23] - __cpp_lib_ranges_zip 202110L [C++23] - __cpp_lib_raw_memory_algorithms 201606L [C++17] - __cpp_lib_reference_from_temporary 202202L [C++23] - __cpp_lib_remove_cvref 201711L [C++20] - __cpp_lib_result_of_sfinae 201210L [C++14] - __cpp_lib_robust_nonmodifying_seq_ops 201304L [C++14] - __cpp_lib_sample 201603L [C++17] - __cpp_lib_scoped_lock 201703L [C++17] - __cpp_lib_semaphore 201907L [C++20] - __cpp_lib_shared_mutex 201505L [C++17] - __cpp_lib_shared_ptr_arrays 201611L [C++17] - 201707L [C++20] - __cpp_lib_shared_ptr_weak_type 201606L [C++17] - __cpp_lib_shared_timed_mutex 201402L [C++14] - __cpp_lib_shift 201806L [C++20] - __cpp_lib_smart_ptr_for_overwrite 202002L [C++20] - __cpp_lib_source_location 201907L [C++20] - __cpp_lib_span 202002L [C++20] - __cpp_lib_spanstream 202106L [C++23] - __cpp_lib_ssize 201902L [C++20] - __cpp_lib_stacktrace 202011L [C++23] - __cpp_lib_starts_ends_with 201711L [C++20] - __cpp_lib_stdatomic_h 202011L [C++23] - __cpp_lib_string_contains 202011L [C++23] - __cpp_lib_string_resize_and_overwrite 202110L [C++23] - __cpp_lib_string_udls 201304L [C++14] - __cpp_lib_string_view 201606L [C++17] - 201803L [C++20] - __cpp_lib_syncbuf 201803L [C++20] - __cpp_lib_three_way_comparison 201907L [C++20] - __cpp_lib_to_address 201711L [C++20] - __cpp_lib_to_array 201907L [C++20] - __cpp_lib_to_chars 201611L [C++17] - __cpp_lib_to_underlying 202102L [C++23] - __cpp_lib_transformation_trait_aliases 201304L [C++14] - __cpp_lib_transparent_operators 201210L [C++14] - 201510L [C++17] - __cpp_lib_tuple_element_t 201402L [C++14] - __cpp_lib_tuples_by_type 201304L [C++14] - __cpp_lib_type_identity 201806L [C++20] - __cpp_lib_type_trait_variable_templates 201510L [C++17] - __cpp_lib_uncaught_exceptions 201411L [C++17] - __cpp_lib_unordered_map_try_emplace 201411L [C++17] - __cpp_lib_unreachable 202202L [C++23] - __cpp_lib_unwrap_ref 201811L [C++20] - __cpp_lib_variant 202102L [C++17] - __cpp_lib_void_t 201411L [C++17] +/* Constant Value + __cpp_lib_adaptor_iterator_pair_constructor 202106L [C++23] + __cpp_lib_addressof_constexpr 201603L [C++17] + __cpp_lib_allocate_at_least 202106L [C++23] + __cpp_lib_allocator_traits_is_always_equal 201411L [C++17] + __cpp_lib_any 201606L [C++17] + __cpp_lib_apply 201603L [C++17] + __cpp_lib_array_constexpr 201603L [C++17] + 201811L [C++20] + __cpp_lib_as_const 201510L [C++17] + __cpp_lib_associative_heterogeneous_erasure 202110L [C++23] + __cpp_lib_associative_heterogeneous_insertion 202306L [C++26] + __cpp_lib_assume_aligned 201811L [C++20] + __cpp_lib_atomic_flag_test 201907L [C++20] + __cpp_lib_atomic_float 201711L [C++20] + __cpp_lib_atomic_is_always_lock_free 201603L [C++17] + __cpp_lib_atomic_lock_free_type_aliases 201907L [C++20] + __cpp_lib_atomic_ref 201806L [C++20] + __cpp_lib_atomic_shared_ptr 201711L [C++20] + __cpp_lib_atomic_value_initialization 201911L [C++20] + __cpp_lib_atomic_wait 201907L [C++20] + __cpp_lib_barrier 201907L [C++20] + __cpp_lib_bind_back 202202L [C++23] + 202306L [C++26] + __cpp_lib_bind_front 201907L [C++20] + 202306L [C++26] + __cpp_lib_bit_cast 201806L [C++20] + __cpp_lib_bitops 201907L [C++20] + __cpp_lib_bitset 202306L [C++26] + __cpp_lib_bool_constant 201505L [C++17] + __cpp_lib_bounded_array_traits 201902L [C++20] + __cpp_lib_boyer_moore_searcher 201603L [C++17] + __cpp_lib_byte 201603L [C++17] + __cpp_lib_byteswap 202110L [C++23] + __cpp_lib_char8_t 201907L [C++20] + __cpp_lib_chrono 201611L [C++17] + __cpp_lib_chrono_udls 201304L [C++14] + __cpp_lib_clamp 201603L [C++17] + __cpp_lib_complex_udls 201309L [C++14] + __cpp_lib_concepts 202002L [C++20] + __cpp_lib_constexpr_algorithms 201806L [C++20] + __cpp_lib_constexpr_bitset 202207L [C++23] + __cpp_lib_constexpr_charconv 202207L [C++23] + __cpp_lib_constexpr_cmath 202202L [C++23] + __cpp_lib_constexpr_complex 201711L [C++20] + __cpp_lib_constexpr_dynamic_alloc 201907L [C++20] + __cpp_lib_constexpr_functional 201907L [C++20] + __cpp_lib_constexpr_iterator 201811L [C++20] + __cpp_lib_constexpr_memory 201811L [C++20] + 202202L [C++23] + __cpp_lib_constexpr_numeric 201911L [C++20] + __cpp_lib_constexpr_string 201907L [C++20] + __cpp_lib_constexpr_string_view 201811L [C++20] + __cpp_lib_constexpr_tuple 201811L [C++20] + __cpp_lib_constexpr_typeinfo 202106L [C++23] + __cpp_lib_constexpr_utility 201811L [C++20] + __cpp_lib_constexpr_vector 201907L [C++20] + __cpp_lib_copyable_function 202306L [C++26] + __cpp_lib_coroutine 201902L [C++20] + __cpp_lib_destroying_delete 201806L [C++20] + __cpp_lib_enable_shared_from_this 201603L [C++17] + __cpp_lib_endian 201907L [C++20] + __cpp_lib_erase_if 202002L [C++20] + __cpp_lib_exchange_function 201304L [C++14] + __cpp_lib_execution 201603L [C++17] + 201902L [C++20] + __cpp_lib_expected 202211L [C++23] + __cpp_lib_filesystem 201703L [C++17] + __cpp_lib_format 202106L [C++20] + __cpp_lib_format_ranges 202207L [C++23] + __cpp_lib_formatters 202302L [C++23] + __cpp_lib_forward_like 202207L [C++23] + __cpp_lib_fstream_native_handle 202306L [C++26] + __cpp_lib_function_ref 202306L [C++26] + __cpp_lib_gcd_lcm 201606L [C++17] + __cpp_lib_generic_associative_lookup 201304L [C++14] + __cpp_lib_generic_unordered_lookup 201811L [C++20] + __cpp_lib_hardware_interference_size 201703L [C++17] + __cpp_lib_has_unique_object_representations 201606L [C++17] + __cpp_lib_hazard_pointer 202306L [C++26] + __cpp_lib_hypot 201603L [C++17] + __cpp_lib_incomplete_container_elements 201505L [C++17] + __cpp_lib_int_pow2 202002L [C++20] + __cpp_lib_integer_comparison_functions 202002L [C++20] + __cpp_lib_integer_sequence 201304L [C++14] + __cpp_lib_integral_constant_callable 201304L [C++14] + __cpp_lib_interpolate 201902L [C++20] + __cpp_lib_invoke 201411L [C++17] + __cpp_lib_invoke_r 202106L [C++23] + __cpp_lib_is_aggregate 201703L [C++17] + __cpp_lib_is_constant_evaluated 201811L [C++20] + __cpp_lib_is_final 201402L [C++14] + __cpp_lib_is_invocable 201703L [C++17] + __cpp_lib_is_layout_compatible 201907L [C++20] + __cpp_lib_is_nothrow_convertible 201806L [C++20] + __cpp_lib_is_null_pointer 201309L [C++14] + __cpp_lib_is_pointer_interconvertible 201907L [C++20] + __cpp_lib_is_scoped_enum 202011L [C++23] + __cpp_lib_is_swappable 201603L [C++17] + __cpp_lib_jthread 201911L [C++20] + __cpp_lib_latch 201907L [C++20] + __cpp_lib_launder 201606L [C++17] + __cpp_lib_list_remove_return_type 201806L [C++20] + __cpp_lib_logical_traits 201510L [C++17] + __cpp_lib_make_from_tuple 201606L [C++17] + __cpp_lib_make_reverse_iterator 201402L [C++14] + __cpp_lib_make_unique 201304L [C++14] + __cpp_lib_map_try_emplace 201411L [C++17] + __cpp_lib_math_constants 201907L [C++20] + __cpp_lib_math_special_functions 201603L [C++17] + __cpp_lib_mdspan 202207L [C++23] + __cpp_lib_memory_resource 201603L [C++17] + __cpp_lib_move_iterator_concept 202207L [C++20] + __cpp_lib_move_only_function 202110L [C++23] + __cpp_lib_node_extract 201606L [C++17] + __cpp_lib_nonmember_container_access 201411L [C++17] + __cpp_lib_not_fn 201603L [C++17] + __cpp_lib_null_iterators 201304L [C++14] + __cpp_lib_optional 201606L [C++17] + 202110L [C++23] + __cpp_lib_out_ptr 202106L [C++23] + __cpp_lib_parallel_algorithm 201603L [C++17] + __cpp_lib_polymorphic_allocator 201902L [C++20] + __cpp_lib_quoted_string_io 201304L [C++14] + __cpp_lib_ranges 202106L [C++20] + __cpp_lib_ranges_as_rvalue 202207L [C++23] + __cpp_lib_ranges_chunk 202202L [C++23] + __cpp_lib_ranges_chunk_by 202202L [C++23] + __cpp_lib_ranges_iota 202202L [C++23] + __cpp_lib_ranges_join_with 202202L [C++23] + __cpp_lib_ranges_slide 202202L [C++23] + __cpp_lib_ranges_starts_ends_with 202106L [C++23] + __cpp_lib_ranges_to_container 202202L [C++23] + __cpp_lib_ranges_zip 202110L [C++23] + __cpp_lib_ratio 202306L [C++26] + __cpp_lib_raw_memory_algorithms 201606L [C++17] + __cpp_lib_rcu 202306L [C++26] + __cpp_lib_reference_from_temporary 202202L [C++23] + __cpp_lib_remove_cvref 201711L [C++20] + __cpp_lib_result_of_sfinae 201210L [C++14] + __cpp_lib_robust_nonmodifying_seq_ops 201304L [C++14] + __cpp_lib_sample 201603L [C++17] + __cpp_lib_scoped_lock 201703L [C++17] + __cpp_lib_semaphore 201907L [C++20] + __cpp_lib_shared_mutex 201505L [C++17] + __cpp_lib_shared_ptr_arrays 201611L [C++17] + 201707L [C++20] + __cpp_lib_shared_ptr_weak_type 201606L [C++17] + __cpp_lib_shared_timed_mutex 201402L [C++14] + __cpp_lib_shift 201806L [C++20] + __cpp_lib_smart_ptr_for_overwrite 202002L [C++20] + __cpp_lib_smart_ptr_owner_equality 202306L [C++26] + __cpp_lib_source_location 201907L [C++20] + __cpp_lib_span 202002L [C++20] + __cpp_lib_spanstream 202106L [C++23] + __cpp_lib_ssize 201902L [C++20] + __cpp_lib_sstream_from_string_view 202306L [C++26] + __cpp_lib_stacktrace 202011L [C++23] + __cpp_lib_starts_ends_with 201711L [C++20] + __cpp_lib_stdatomic_h 202011L [C++23] + __cpp_lib_string_contains 202011L [C++23] + __cpp_lib_string_resize_and_overwrite 202110L [C++23] + __cpp_lib_string_udls 201304L [C++14] + __cpp_lib_string_view 201606L [C++17] + 201803L [C++20] + __cpp_lib_submdspan 202306L [C++26] + __cpp_lib_syncbuf 201803L [C++20] + __cpp_lib_text_encoding 202306L [C++26] + __cpp_lib_three_way_comparison 201907L [C++20] + __cpp_lib_to_address 201711L [C++20] + __cpp_lib_to_array 201907L [C++20] + __cpp_lib_to_chars 201611L [C++17] + __cpp_lib_to_string 202306L [C++23] + __cpp_lib_to_underlying 202102L [C++23] + __cpp_lib_transformation_trait_aliases 201304L [C++14] + __cpp_lib_transparent_operators 201210L [C++14] + 201510L [C++17] + __cpp_lib_tuple_element_t 201402L [C++14] + __cpp_lib_tuples_by_type 201304L [C++14] + __cpp_lib_type_identity 201806L [C++20] + __cpp_lib_type_trait_variable_templates 201510L [C++17] + __cpp_lib_uncaught_exceptions 201411L [C++17] + __cpp_lib_unordered_map_try_emplace 201411L [C++17] + __cpp_lib_unreachable 202202L [C++23] + __cpp_lib_unwrap_ref 201811L [C++20] + __cpp_lib_variant 202102L [C++17] + __cpp_lib_void_t 201411L [C++17] + __cpp_lib_within_lifetime 202306L [C++26] */ #include @@ -230,6 +246,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should not be defined before c++20" # endif @@ -286,6 +306,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should not be defined before c++17" # endif @@ -394,6 +418,10 @@ # error "__cpp_lib_constexpr_vector should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + # ifdef __cpp_lib_coroutine # error "__cpp_lib_coroutine should not be defined before c++20" # endif @@ -446,6 +474,14 @@ # error "__cpp_lib_forward_like should not be defined before c++23" # endif +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifdef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should not be defined before c++17" # endif @@ -466,6 +502,10 @@ # error "__cpp_lib_has_unique_object_representations should not be defined before c++17" # endif +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined before c++26" +# endif + # ifdef __cpp_lib_hypot # error "__cpp_lib_hypot should not be defined before c++17" # endif @@ -678,10 +718,18 @@ # error "__cpp_lib_ranges_zip should not be defined before c++23" # endif +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + # ifdef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should not be defined before c++17" # endif +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined before c++26" +# endif + # ifdef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should not be defined before c++23" # endif @@ -734,6 +782,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_source_location # error "__cpp_lib_source_location should not be defined before c++20" # endif @@ -750,6 +802,10 @@ # error "__cpp_lib_ssize should not be defined before c++20" # endif +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + # ifdef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should not be defined before c++23" # endif @@ -778,10 +834,18 @@ # error "__cpp_lib_string_view should not be defined before c++17" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + # ifdef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should not be defined before c++20" # endif +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined before c++26" +# endif + # ifdef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should not be defined before c++20" # endif @@ -798,6 +862,10 @@ # error "__cpp_lib_to_chars should not be defined before c++17" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + # ifdef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should not be defined before c++23" # endif @@ -850,6 +918,10 @@ # error "__cpp_lib_void_t should not be defined before c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 14 # ifdef __cpp_lib_adaptor_iterator_pair_constructor @@ -888,6 +960,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should not be defined before c++20" # endif @@ -944,6 +1020,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifdef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should not be defined before c++17" # endif @@ -1058,6 +1138,10 @@ # error "__cpp_lib_constexpr_vector should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + # ifdef __cpp_lib_coroutine # error "__cpp_lib_coroutine should not be defined before c++20" # endif @@ -1113,6 +1197,14 @@ # error "__cpp_lib_forward_like should not be defined before c++23" # endif +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifdef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should not be defined before c++17" # endif @@ -1136,6 +1228,10 @@ # error "__cpp_lib_has_unique_object_representations should not be defined before c++17" # endif +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined before c++26" +# endif + # ifdef __cpp_lib_hypot # error "__cpp_lib_hypot should not be defined before c++17" # endif @@ -1372,10 +1468,18 @@ # error "__cpp_lib_ranges_zip should not be defined before c++23" # endif +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + # ifdef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should not be defined before c++17" # endif +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined before c++26" +# endif + # ifdef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should not be defined before c++23" # endif @@ -1443,6 +1547,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_source_location # error "__cpp_lib_source_location should not be defined before c++20" # endif @@ -1459,6 +1567,10 @@ # error "__cpp_lib_ssize should not be defined before c++20" # endif +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + # ifdef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should not be defined before c++23" # endif @@ -1490,10 +1602,18 @@ # error "__cpp_lib_string_view should not be defined before c++17" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + # ifdef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should not be defined before c++20" # endif +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined before c++26" +# endif + # ifdef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should not be defined before c++20" # endif @@ -1510,6 +1630,10 @@ # error "__cpp_lib_to_chars should not be defined before c++17" # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + # ifdef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should not be defined before c++23" # endif @@ -1574,6 +1698,10 @@ # error "__cpp_lib_void_t should not be defined before c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 17 # ifdef __cpp_lib_adaptor_iterator_pair_constructor @@ -1630,6 +1758,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifdef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should not be defined before c++20" # endif @@ -1689,6 +1821,10 @@ # error "__cpp_lib_bitops should not be defined before c++20" # endif +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifndef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should be defined in c++17" # endif @@ -1818,6 +1954,10 @@ # error "__cpp_lib_constexpr_vector should not be defined before c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + # ifdef __cpp_lib_coroutine # error "__cpp_lib_coroutine should not be defined before c++20" # endif @@ -1894,6 +2034,14 @@ # error "__cpp_lib_forward_like should not be defined before c++23" # endif +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++17" # endif @@ -1932,6 +2080,10 @@ # error "__cpp_lib_has_unique_object_representations should have the value 201606L in c++17" # endif +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined before c++26" +# endif + # ifndef __cpp_lib_hypot # error "__cpp_lib_hypot should be defined in c++17" # endif @@ -2231,6 +2383,10 @@ # error "__cpp_lib_ranges_zip should not be defined before c++23" # endif +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + # ifndef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should be defined in c++17" # endif @@ -2238,6 +2394,10 @@ # error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++17" # endif +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined before c++26" +# endif + # ifdef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should not be defined before c++23" # endif @@ -2326,6 +2486,10 @@ # error "__cpp_lib_smart_ptr_for_overwrite should not be defined before c++20" # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # ifdef __cpp_lib_source_location # error "__cpp_lib_source_location should not be defined before c++20" # endif @@ -2342,6 +2506,10 @@ # error "__cpp_lib_ssize should not be defined before c++20" # endif +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + # ifdef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should not be defined before c++23" # endif @@ -2376,10 +2544,18 @@ # error "__cpp_lib_string_view should have the value 201606L in c++17" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + # ifdef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should not be defined before c++20" # endif +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined before c++26" +# endif + # ifdef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should not be defined before c++20" # endif @@ -2405,6 +2581,10 @@ # endif # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + # ifdef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should not be defined before c++23" # endif @@ -2484,6 +2664,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++17" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 20 # ifdef __cpp_lib_adaptor_iterator_pair_constructor @@ -2540,6 +2724,10 @@ # error "__cpp_lib_associative_heterogeneous_erasure should not be defined before c++23" # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should be defined in c++20" # endif @@ -2671,6 +2859,10 @@ # endif # endif +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifndef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should be defined in c++20" # endif @@ -2851,6 +3043,10 @@ # error "__cpp_lib_constexpr_vector should have the value 201907L in c++20" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + # ifndef __cpp_lib_coroutine # error "__cpp_lib_coroutine should be defined in c++20" # endif @@ -2954,6 +3150,14 @@ # error "__cpp_lib_forward_like should not be defined before c++23" # endif +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++20" # endif @@ -2995,6 +3199,10 @@ # error "__cpp_lib_has_unique_object_representations should have the value 201606L in c++20" # endif +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined before c++26" +# endif + # ifndef __cpp_lib_hypot # error "__cpp_lib_hypot should be defined in c++20" # endif @@ -3360,6 +3568,10 @@ # error "__cpp_lib_ranges_zip should not be defined before c++23" # endif +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + # ifndef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should be defined in c++20" # endif @@ -3367,6 +3579,10 @@ # error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++20" # endif +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined before c++26" +# endif + # ifdef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should not be defined before c++23" # endif @@ -3479,6 +3695,10 @@ # endif # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # if __has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403) # ifndef __cpp_lib_source_location # error "__cpp_lib_source_location should be defined in c++20" @@ -3510,6 +3730,10 @@ # error "__cpp_lib_ssize should have the value 201902L in c++20" # endif +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + # ifdef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should not be defined before c++23" # endif @@ -3547,6 +3771,10 @@ # error "__cpp_lib_string_view should have the value 201803L in c++20" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should be defined in c++20" @@ -3560,6 +3788,10 @@ # endif # endif +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should be defined in c++20" @@ -3600,6 +3832,10 @@ # endif # endif +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined before c++23" +# endif + # ifdef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should not be defined before c++23" # endif @@ -3685,6 +3921,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++20" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER == 23 # ifndef __cpp_lib_adaptor_iterator_pair_constructor @@ -3756,6 +3996,10 @@ # endif # endif +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined before c++26" +# endif + # ifndef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should be defined in c++23" # endif @@ -3896,6 +4140,10 @@ # endif # endif +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined before c++26" +# endif + # ifndef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should be defined in c++23" # endif @@ -4097,6 +4345,10 @@ # error "__cpp_lib_constexpr_vector should have the value 201907L in c++23" # endif +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined before c++26" +# endif + # ifndef __cpp_lib_coroutine # error "__cpp_lib_coroutine should be defined in c++23" # endif @@ -4218,6 +4470,14 @@ # error "__cpp_lib_forward_like should have the value 202207L in c++23" # endif +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined before c++26" +# endif + +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined before c++26" +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++23" # endif @@ -4259,6 +4519,10 @@ # error "__cpp_lib_has_unique_object_representations should have the value 201606L in c++23" # endif +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined before c++26" +# endif + # ifndef __cpp_lib_hypot # error "__cpp_lib_hypot should be defined in c++23" # endif @@ -4732,6 +4996,10 @@ # endif # endif +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined before c++26" +# endif + # ifndef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should be defined in c++23" # endif @@ -4739,6 +5007,10 @@ # error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++23" # endif +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should be defined in c++23" @@ -4860,6 +5132,10 @@ # endif # endif +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined before c++26" +# endif + # if __has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403) # ifndef __cpp_lib_source_location # error "__cpp_lib_source_location should be defined in c++23" @@ -4900,6 +5176,10 @@ # error "__cpp_lib_ssize should have the value 201902L in c++23" # endif +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should be defined in c++23" @@ -4955,6 +5235,10 @@ # error "__cpp_lib_string_view should have the value 201803L in c++23" # endif +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should be defined in c++23" @@ -4968,6 +5252,10 @@ # endif # endif +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined before c++26" +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should be defined in c++23" @@ -5008,6 +5296,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_to_string +# error "__cpp_lib_to_string should be defined in c++23" +# endif +# if __cpp_lib_to_string != 202306L +# error "__cpp_lib_to_string should have the value 202306L in c++23" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should be defined in c++23" # endif @@ -5099,6 +5400,10 @@ # error "__cpp_lib_void_t should have the value 201411L in c++23" # endif +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined before c++26" +# endif + #elif TEST_STD_VER > 23 # ifndef __cpp_lib_adaptor_iterator_pair_constructor @@ -5170,6 +5475,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should be defined in c++26" +# endif +# if __cpp_lib_associative_heterogeneous_insertion != 202306L +# error "__cpp_lib_associative_heterogeneous_insertion should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_associative_heterogeneous_insertion +# error "__cpp_lib_associative_heterogeneous_insertion should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_assume_aligned # error "__cpp_lib_assume_aligned should be defined in c++26" # endif @@ -5274,8 +5592,8 @@ # ifndef __cpp_lib_bind_back # error "__cpp_lib_bind_back should be defined in c++26" # endif -# if __cpp_lib_bind_back != 202202L -# error "__cpp_lib_bind_back should have the value 202202L in c++26" +# if __cpp_lib_bind_back != 202306L +# error "__cpp_lib_bind_back should have the value 202306L in c++26" # endif # else // _LIBCPP_VERSION # ifdef __cpp_lib_bind_back @@ -5286,8 +5604,8 @@ # ifndef __cpp_lib_bind_front # error "__cpp_lib_bind_front should be defined in c++26" # endif -# if __cpp_lib_bind_front != 201907L -# error "__cpp_lib_bind_front should have the value 201907L in c++26" +# if __cpp_lib_bind_front != 202306L +# error "__cpp_lib_bind_front should have the value 202306L in c++26" # endif # ifndef __cpp_lib_bit_cast @@ -5310,6 +5628,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_bitset +# error "__cpp_lib_bitset should be defined in c++26" +# endif +# if __cpp_lib_bitset != 202306L +# error "__cpp_lib_bitset should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_bitset +# error "__cpp_lib_bitset should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_bool_constant # error "__cpp_lib_bool_constant should be defined in c++26" # endif @@ -5511,6 +5842,19 @@ # error "__cpp_lib_constexpr_vector should have the value 201907L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should be defined in c++26" +# endif +# if __cpp_lib_copyable_function != 202306L +# error "__cpp_lib_copyable_function should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_copyable_function +# error "__cpp_lib_copyable_function should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_coroutine # error "__cpp_lib_coroutine should be defined in c++26" # endif @@ -5632,6 +5976,32 @@ # error "__cpp_lib_forward_like should have the value 202207L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should be defined in c++26" +# endif +# if __cpp_lib_fstream_native_handle != 202306L +# error "__cpp_lib_fstream_native_handle should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_fstream_native_handle +# error "__cpp_lib_fstream_native_handle should not be defined because it is unimplemented in libc++!" +# endif +# endif + +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should be defined in c++26" +# endif +# if __cpp_lib_function_ref != 202306L +# error "__cpp_lib_function_ref should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_function_ref +# error "__cpp_lib_function_ref should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_gcd_lcm # error "__cpp_lib_gcd_lcm should be defined in c++26" # endif @@ -5673,6 +6043,19 @@ # error "__cpp_lib_has_unique_object_representations should have the value 201606L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should be defined in c++26" +# endif +# if __cpp_lib_hazard_pointer != 202306L +# error "__cpp_lib_hazard_pointer should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_hazard_pointer +# error "__cpp_lib_hazard_pointer should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_hypot # error "__cpp_lib_hypot should be defined in c++26" # endif @@ -6146,6 +6529,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_ratio +# error "__cpp_lib_ratio should be defined in c++26" +# endif +# if __cpp_lib_ratio != 202306L +# error "__cpp_lib_ratio should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_ratio +# error "__cpp_lib_ratio should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_raw_memory_algorithms # error "__cpp_lib_raw_memory_algorithms should be defined in c++26" # endif @@ -6153,6 +6549,19 @@ # error "__cpp_lib_raw_memory_algorithms should have the value 201606L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_rcu +# error "__cpp_lib_rcu should be defined in c++26" +# endif +# if __cpp_lib_rcu != 202306L +# error "__cpp_lib_rcu should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_rcu +# error "__cpp_lib_rcu should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_reference_from_temporary # error "__cpp_lib_reference_from_temporary should be defined in c++26" @@ -6274,6 +6683,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should be defined in c++26" +# endif +# if __cpp_lib_smart_ptr_owner_equality != 202306L +# error "__cpp_lib_smart_ptr_owner_equality should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_smart_ptr_owner_equality +# error "__cpp_lib_smart_ptr_owner_equality should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if __has_builtin(__builtin_source_location) && !(defined(TEST_APPLE_CLANG_VER) && TEST_APPLE_CLANG_VER <= 1403) # ifndef __cpp_lib_source_location # error "__cpp_lib_source_location should be defined in c++26" @@ -6314,6 +6736,19 @@ # error "__cpp_lib_ssize should have the value 201902L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should be defined in c++26" +# endif +# if __cpp_lib_sstream_from_string_view != 202306L +# error "__cpp_lib_sstream_from_string_view should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_sstream_from_string_view +# error "__cpp_lib_sstream_from_string_view should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_stacktrace # error "__cpp_lib_stacktrace should be defined in c++26" @@ -6369,6 +6804,19 @@ # error "__cpp_lib_string_view should have the value 201803L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should be defined in c++26" +# endif +# if __cpp_lib_submdspan != 202306L +# error "__cpp_lib_submdspan should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_submdspan +# error "__cpp_lib_submdspan should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_syncbuf # error "__cpp_lib_syncbuf should be defined in c++26" @@ -6382,6 +6830,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should be defined in c++26" +# endif +# if __cpp_lib_text_encoding != 202306L +# error "__cpp_lib_text_encoding should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_text_encoding +# error "__cpp_lib_text_encoding should not be defined because it is unimplemented in libc++!" +# endif +# endif + # if !defined(_LIBCPP_VERSION) # ifndef __cpp_lib_three_way_comparison # error "__cpp_lib_three_way_comparison should be defined in c++26" @@ -6422,6 +6883,19 @@ # endif # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_to_string +# error "__cpp_lib_to_string should be defined in c++26" +# endif +# if __cpp_lib_to_string != 202306L +# error "__cpp_lib_to_string should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_to_string +# error "__cpp_lib_to_string should not be defined because it is unimplemented in libc++!" +# endif +# endif + # ifndef __cpp_lib_to_underlying # error "__cpp_lib_to_underlying should be defined in c++26" # endif @@ -6513,5 +6987,18 @@ # error "__cpp_lib_void_t should have the value 201411L in c++26" # endif +# if !defined(_LIBCPP_VERSION) +# ifndef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should be defined in c++26" +# endif +# if __cpp_lib_within_lifetime != 202306L +# error "__cpp_lib_within_lifetime should have the value 202306L in c++26" +# endif +# else // _LIBCPP_VERSION +# ifdef __cpp_lib_within_lifetime +# error "__cpp_lib_within_lifetime should not be defined because it is unimplemented in libc++!" +# endif +# endif + #endif // TEST_STD_VER > 23 diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 19738d80e6f18..72ae5bdd653a8 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -87,7 +87,11 @@ def add_version_header(tc): }, { "name": "__cpp_lib_allocate_at_least", - "values": {"c++23": 202106}, + "values": { + "c++23": 202106, + # Note LWG3887 Version macro for allocate_at_least + #"c++26": 202302, # P2652R2 Disallow User Specialization of allocator_traits + }, "headers": ["memory"], }, { @@ -133,6 +137,12 @@ def add_version_header(tc): "headers": ["map", "set", "unordered_map", "unordered_set"], "unimplemented": True, }, + { + "name": "__cpp_lib_associative_heterogeneous_insertion", + "values": {"c++26": 202306}, # P2363R5 Extending associative containers with the remaining heterogeneous overloads + "headers": ["map", "set", "unordered_map", "unordered_set"], + "unimplemented": True, + }, { "name": "__cpp_lib_assume_aligned", "values": {"c++20": 201811}, @@ -192,13 +202,19 @@ def add_version_header(tc): }, { "name": "__cpp_lib_bind_back", - "values": {"c++23": 202202}, + "values": { + "c++23": 202202, + "c++26": 202306, # P2714R1 Bind front and back to NTTP callables + }, "headers": ["functional"], "unimplemented": True, }, { "name": "__cpp_lib_bind_front", - "values": {"c++20": 201907}, + "values": { + "c++20": 201907, + "c++26": 202306, # P2714R1 Bind front and back to NTTP callables + }, "headers": ["functional"], }, { @@ -212,6 +228,12 @@ def add_version_header(tc): "headers": ["bit"], "unimplemented": True, }, + { + "name": "__cpp_lib_bitset", + "values": {"c++26": 202306}, # P2697R1 Interfacing bitset with string_view + "headers": ["bitset"], + "unimplemented": True, + }, { "name": "__cpp_lib_bool_constant", "values": {"c++17": 201505}, @@ -255,7 +277,10 @@ def add_version_header(tc): }, { "name": "__cpp_lib_chrono", - "values": {"c++17": 201611}, + "values": { + "c++17": 201611, + #"c++26": 202306, # P2592R3 Hashing support for std::chrono value classes + }, "headers": ["chrono"], }, { @@ -280,7 +305,10 @@ def add_version_header(tc): }, { "name": "__cpp_lib_constexpr_algorithms", - "values": {"c++20": 201806}, + "values": { + "c++20": 201806, + #"c++26": 202306, # P2562R1 constexpr Stable Sorting + }, "headers": ["algorithm", "utility"], }, { @@ -359,6 +387,12 @@ def add_version_header(tc): "values": {"c++20": 201907}, "headers": ["vector"], }, + { + "name": "__cpp_lib_copyable_function", + "values": {"c++26": 202306}, # P2548R6 copyable_function + "headers": ["functional"], + "unimplemented": True, + }, { "name": "__cpp_lib_coroutine", "values": {"c++20": 201902}, @@ -428,6 +462,10 @@ def add_version_header(tc): "c++20": 202106, # "c++23": 202207, Not implemented P2419R2 Clarify handling of encodings in localized formatting of chrono types }, + # Note these three papers are adopted at the June 2023 meeting and have sequential numbering + # 202304 P2510R3 Formatting pointers + # 202305 P2757R3 Type-checking format args + # 202306 P2637R3 Member Visit "headers": ["format"], "unimplemented": True, }, @@ -447,6 +485,18 @@ def add_version_header(tc): "values": {"c++23": 202207}, "headers": ["utility"], }, + { + "name": "__cpp_lib_fstream_native_handle", + "values": {"c++26": 202306}, # P1759R6 Native handles and file streams + "headers": ["fstream"], + "unimplemented": True, + }, + { + "name": "__cpp_lib_function_ref", + "values": {"c++26": 202306}, # P0792R14 function_ref: a type-erased callable reference + "headers": ["functional"], + "unimplemented": True, + }, { "name": "__cpp_lib_gcd_lcm", "values": {"c++17": 201606}, @@ -474,6 +524,12 @@ def add_version_header(tc): "values": {"c++17": 201606}, "headers": ["type_traits"], }, + { + "name": "__cpp_lib_hazard_pointer", + "values": {"c++26": 202306}, # P2530R3 Hazard Pointers for C++26 + "headers": ["hazard_pointer"],# TODO verify this entry since the paper was underspecified. + "unimplemented": True, + }, { "name": "__cpp_lib_hypot", "values": {"c++17": 201603}, @@ -679,7 +735,10 @@ def add_version_header(tc): }, { "name": "__cpp_lib_not_fn", - "values": {"c++17": 201603}, + "values": { + "c++17": 201603, + #"c++26": 202306, # P2714R1 Bind front and back to NTTP callables + }, "headers": ["functional"], }, { @@ -785,11 +844,23 @@ def add_version_header(tc): "headers": ["ranges", "tuple", "utility"], "unimplemented": True, }, + { + "name": "__cpp_lib_ratio", + "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes + "headers": ["ratio"], + "unimplemented": True, + }, { "name": "__cpp_lib_raw_memory_algorithms", "values": {"c++17": 201606}, "headers": ["memory"], }, + { + "name": "__cpp_lib_rcu", + "values": {"c++26": 202306}, # P2545R4 Read-Copy Update (RCU) + "headers": ["rcu"], # TODO verify this entry since the paper was underspecified. + "unimplemented": True, + }, { "name": "__cpp_lib_reference_from_temporary", "values": {"c++23": 202202}, @@ -863,6 +934,12 @@ def add_version_header(tc): "headers": ["memory"], "unimplemented": True, }, + { + "name": "__cpp_lib_smart_ptr_owner_equality", + "values": {"c++26": 202306}, # P1901R2 Enabling the Use of weak_ptr as Keys in Unordered Associative Containers + "headers": ["memory"], + "unimplemented": True, + }, { "name": "__cpp_lib_source_location", "values": {"c++20": 201907}, @@ -886,6 +963,12 @@ def add_version_header(tc): "values": {"c++20": 201902}, "headers": ["iterator"], }, + { + "name": "__cpp_lib_sstream_from_string_view", + "values": {"c++26": 202306}, # P2495R3 Interfacing stringstreams with string_view + "headers": ["sstream"], + "unimplemented": True, + }, { "name": "__cpp_lib_stacktrace", "values": {"c++23": 202011}, @@ -922,12 +1005,24 @@ def add_version_header(tc): "values": {"c++17": 201606, "c++20": 201803}, "headers": ["string", "string_view"], }, + { + "name": "__cpp_lib_submdspan", + "values": {"c++26": 202306}, # P2630R4 submdspan + "headers": ["mdspan"], + "unimplemented": True, + }, { "name": "__cpp_lib_syncbuf", "values": {"c++20": 201803}, "headers": ["syncstream"], "unimplemented": True, }, + { + "name": "__cpp_lib_text_encoding", + "values": {"c++26": 202306}, # P1885R12 Naming Text Encodings to Demystify Them + "headers": ["text_encoding"], + "unimplemented": True, + }, { "name": "__cpp_lib_three_way_comparison", "values": {"c++20": 201907}, @@ -946,10 +1041,19 @@ def add_version_header(tc): }, { "name": "__cpp_lib_to_chars", - "values": {"c++17": 201611}, + "values": { + "c++17": 201611, + #"c++26: 202306, # P2497R0 Testing for success or failure of functions + }, "headers": ["charconv"], "unimplemented": True, }, + { + "name": "__cpp_lib_to_string", + "values": {"c++23": 202306}, # P2587R3 to_string or not to_string + "headers": ["string"], + "unimplemented": True, + }, { "name": "__cpp_lib_to_underlying", "values": {"c++23": 202102}, @@ -1015,6 +1119,12 @@ def add_version_header(tc): "values": {"c++17": 201411}, "headers": ["type_traits"], }, + { + "name": "__cpp_lib_within_lifetime", + "values": {"c++26": 202306}, # P2641R4 Checking if a union alternative is active + "headers": ["type_traits"], + "unimplemented": True, + }, ] ] @@ -1048,6 +1158,7 @@ def add_version_header(tc): lit_markup = { "barrier": ["UNSUPPORTED: no-threads"], "filesystem": ["UNSUPPORTED: no-filesystem"], + "fstream": ["UNSUPPORTED: no-localization"], "iomanip": ["UNSUPPORTED: no-localization"], "ios": ["UNSUPPORTED: no-localization"], "iostream": ["UNSUPPORTED: no-localization"], @@ -1059,6 +1170,7 @@ def add_version_header(tc): "regex": ["UNSUPPORTED: no-localization"], "semaphore": ["UNSUPPORTED: no-threads"], "shared_mutex": ["UNSUPPORTED: no-threads"], + "sstream": ["UNSUPPORTED: no-localization"], "stdatomic.h": ["UNSUPPORTED: no-threads"], "stop_token": ["UNSUPPORTED: no-threads"], "thread": ["UNSUPPORTED: no-threads"], From e8b3ba235597de4587379f233d57826fda71855e Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Mon, 19 Jun 2023 10:58:08 -0400 Subject: [PATCH 041/130] [gn] port 6f2e92c10cebca5 better (lld/unittests) lld/test/Unit/lit.site.cfg.py.in got cleaned up in the reland. --- llvm/utils/gn/secondary/lld/test/BUILD.gn | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/llvm/utils/gn/secondary/lld/test/BUILD.gn b/llvm/utils/gn/secondary/lld/test/BUILD.gn index 06256e1ba161b..d6c15608124e3 100644 --- a/llvm/utils/gn/secondary/lld/test/BUILD.gn +++ b/llvm/utils/gn/secondary/lld/test/BUILD.gn @@ -16,13 +16,7 @@ template("write_lit_cfg") { "## Autogenerated from $input, do not edit\n\n" + lit_path_function, "LLD_BINARY_DIR=" + rebase_path(get_label_info("//lld", "target_out_dir")), - "CURRENT_LIBS_DIR=", # FIXME: for shared builds only (?) - "CURRENT_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), "LLD_SOURCE_DIR=" + rebase_path("//lld"), - "LLVM_BINARY_DIR=" + - rebase_path(get_label_info("//llvm", "target_out_dir")), - "LLVM_SOURCE_DIR=" + rebase_path("//llvm"), - "LLVM_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), ] values += invoker.extra_values } @@ -35,10 +29,16 @@ write_lit_cfg("lit_site_cfg") { dir = get_path_info(output, "dir") extra_values = [ + "CURRENT_LIBS_DIR=", # FIXME: for shared builds only (?) + "CURRENT_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), "ENABLE_BACKTRACES=1", + "LLVM_BINARY_DIR=" + + rebase_path(get_label_info("//llvm", "target_out_dir")), "LLVM_HOST_TRIPLE=$llvm_current_triple", "LLVM_LIBS_DIR=", # needed only for shared builds "LLVM_LIT_TOOLS_DIR=", # Intentionally empty, matches cmake build. + "LLVM_SOURCE_DIR=" + rebase_path("//llvm"), + "LLVM_TOOLS_DIR=" + rebase_path("$root_out_dir/bin"), "Python3_EXECUTABLE=$python_path", "LLVM_TARGET_TRIPLE=$llvm_target_triple", @@ -103,10 +103,7 @@ write_lit_cfg("lit_unit_site_cfg") { # Fully-qualified instead of relative for LIT_SITE_CFG_IN_HEADER. input = "//lld/test/Unit/lit.site.cfg.py.in" output = lld_lit_unit_site_cfg_file - extra_values = [ - "ENABLE_SHARED=0", - "LLVM_BUILD_MODE=.", - ] + extra_values = [ "LLVM_BUILD_MODE=." ] dir = get_path_info(output, "dir") if (host_os == "win") { # See comment for Windows solink in llvm/utils/gn/build/toolchain/BUILD.gn From a4f0764aefd6ea41e83a5974f582a1a7e985667d Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 18 Jun 2023 12:35:44 +0200 Subject: [PATCH 042/130] [libc++] Marks __cpp_lib_bitops as implemented. This FTM was introduced in P0553R4 Bit operations Which has been implemented since libc++ 9. This was noticed while working on D153192. Reviewed By: #libc, philnik Differential Revision: https://reviews.llvm.org/D153225 --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/include/version | 2 +- .../bit.version.compile.pass.cpp | 48 ++++++------------- .../version.version.compile.pass.cpp | 48 ++++++------------- .../generate_feature_test_macro_components.py | 1 - 5 files changed, 32 insertions(+), 69 deletions(-) diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 45e580f397756..4c8e1ffc828bb 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -192,7 +192,7 @@ Status --------------------------------------------------- ----------------- ``__cpp_lib_bit_cast`` ``201806L`` --------------------------------------------------- ----------------- - ``__cpp_lib_bitops`` *unimplemented* + ``__cpp_lib_bitops`` ``201907L`` --------------------------------------------------- ----------------- ``__cpp_lib_bounded_array_traits`` ``201902L`` --------------------------------------------------- ----------------- diff --git a/libcxx/include/version b/libcxx/include/version index 5f69eff42b0a1..10abf695dadac 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -332,7 +332,7 @@ __cpp_lib_within_lifetime 202306L # endif # define __cpp_lib_bind_front 201907L # define __cpp_lib_bit_cast 201806L -// # define __cpp_lib_bitops 201907L +# define __cpp_lib_bitops 201907L # define __cpp_lib_bounded_array_traits 201902L # if !defined(_LIBCPP_HAS_NO_CHAR8_T) # define __cpp_lib_char8_t 201907L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp index b858ff65545d5..0e1d06b928019 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/bit.version.compile.pass.cpp @@ -101,17 +101,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++20" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++20" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++20" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++20" # endif # ifdef __cpp_lib_byteswap @@ -141,17 +135,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++23" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++23" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++23" # endif # ifndef __cpp_lib_byteswap @@ -184,17 +172,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++26" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++26" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++26" # endif # ifndef __cpp_lib_byteswap diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index dbad0e6b3cf0c..fb7081f2ebbf7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -2846,17 +2846,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++20" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++20" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++20" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++20" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++20" # endif # ifdef __cpp_lib_bitset @@ -4127,17 +4121,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++23" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++23" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++23" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++23" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++23" # endif # ifdef __cpp_lib_bitset @@ -5615,17 +5603,11 @@ # error "__cpp_lib_bit_cast should have the value 201806L in c++26" # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_bitops -# error "__cpp_lib_bitops should be defined in c++26" -# endif -# if __cpp_lib_bitops != 201907L -# error "__cpp_lib_bitops should have the value 201907L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_bitops -# error "__cpp_lib_bitops should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_bitops +# error "__cpp_lib_bitops should be defined in c++26" +# endif +# if __cpp_lib_bitops != 201907L +# error "__cpp_lib_bitops should have the value 201907L in c++26" # endif # if !defined(_LIBCPP_VERSION) diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 72ae5bdd653a8..4d454f7e42986 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -226,7 +226,6 @@ def add_version_header(tc): "name": "__cpp_lib_bitops", "values": {"c++20": 201907}, "headers": ["bit"], - "unimplemented": True, }, { "name": "__cpp_lib_bitset", From cdcfc5ec9b33da441218041b6cd4f4ad19620eca Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 16 Aug 2022 08:15:51 +0200 Subject: [PATCH 043/130] [libc++][regex] Removes operator!=. Implements part of: - P1614R2 The Mothership has Landed Reviewed By: #libc, H-G-Hristov, philnik Differential Revision: https://reviews.llvm.org/D153222 --- libcxx/docs/Status/SpaceshipProjects.csv | 8 ++++---- libcxx/include/regex | 12 +++++++++--- libcxx/modules/std/regex.cppm | 3 --- .../re.regiter.comp/tested_elsewhere.pass.cpp | 2 +- .../re.tokiter/re.tokiter.comp/equal.pass.cpp | 2 +- .../re.results/re.results.nonmember/equal.pass.cpp | 2 +- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv index 86ce5d9387a3f..17f9f92d67440 100644 --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -188,13 +188,13 @@ Section,Description,Dependencies,Assignee,Complete "| `[fs.class.directory.entry] `_ | `[fs.dir.entry.obs] `_",| `filesystem::directory_entry `_,None,Adrian Vogelsgesang,|Complete| - `5.15 Clause 30: Regular expressions library `_,,,, -| `[re.syn] `_,|,None,Mark de Wever,|In Progress| +| `[re.syn] `_,|,None,Mark de Wever,|Complete| | `[re.submatch.op] `_,| `sub_match `_,None,Mark de Wever,|Complete| -| `[re.results.nonmember] `_,| remove ops `match_results`,None,Mark de Wever,|In Progress| +| `[re.results.nonmember] `_,| remove ops `match_results`,None,Mark de Wever,|Complete| "| `[re.regiter] `_, -| `[re.regiter.comp] `_",| remove ops `regex_iterator`,None,Mark de Wever,|In Progress| +| `[re.regiter.comp] `_",| remove ops `regex_iterator`,None,Mark de Wever,|Complete| "| `[re.tokiter] `_ -| `[re.tokiter.comp] `_",| remove ops `regex_token_iterator`,None,Mark de Wever,|In Progress| +| `[re.tokiter.comp] `_",| remove ops `regex_token_iterator`,None,Mark de Wever,|Complete| - `5.16 Clause 31: Atomic operations library `_,,,, - `5.17 Clause 32: Thread support library `_,,,, | `[thread.thread.id] `_,| `thread::id `_,None,Adrian Vogelsgesang,|Complete| diff --git a/libcxx/include/regex b/libcxx/include/regex index b4545580163ba..ea2711fddafca 100644 --- a/libcxx/include/regex +++ b/libcxx/include/regex @@ -543,7 +543,7 @@ template operator==(const match_results& m1, const match_results& m2); -template +template // Removed in C++20 bool operator!=(const match_results& m1, const match_results& m2); @@ -710,7 +710,7 @@ public: regex_iterator& operator=(const regex_iterator&); bool operator==(const regex_iterator&) const; - bool operator!=(const regex_iterator&) const; + bool operator!=(const regex_iterator&) const; // Removed in C++20 const value_type& operator*() const; const value_type* operator->() const; @@ -768,7 +768,7 @@ public: regex_token_iterator& operator=(const regex_token_iterator&); bool operator==(const regex_token_iterator&) const; - bool operator!=(const regex_token_iterator&) const; + bool operator!=(const regex_token_iterator&) const; // Removed in C++20 const value_type& operator*() const; const value_type* operator->() const; @@ -5816,6 +5816,7 @@ operator==(const match_results<_BidirectionalIterator, _Allocator>& __x, __x.__suffix_ == __y.__suffix_; } +#if _LIBCPP_STD_VER < 20 template inline _LIBCPP_INLINE_VISIBILITY bool @@ -5824,6 +5825,7 @@ operator!=(const match_results<_BidirectionalIterator, _Allocator>& __x, { return !(__x == __y); } +#endif template inline _LIBCPP_INLINE_VISIBILITY @@ -6427,8 +6429,10 @@ public: #endif bool operator==(const regex_iterator& __x) const; +#if _LIBCPP_STD_VER < 20 _LIBCPP_INLINE_VISIBILITY bool operator!=(const regex_iterator& __x) const {return !(*this == __x);} +#endif _LIBCPP_INLINE_VISIBILITY reference operator*() const {return __match_;} @@ -6606,7 +6610,9 @@ public: bool operator==(const regex_token_iterator& __x) const; _LIBCPP_INLINE_VISIBILITY +#if _LIBCPP_STD_VER < 20 bool operator!=(const regex_token_iterator& __x) const {return !(*this == __x);} +#endif _LIBCPP_INLINE_VISIBILITY const value_type& operator*() const {return *__result_;} diff --git a/libcxx/modules/std/regex.cppm b/libcxx/modules/std/regex.cppm index 222ebf94a78a8..7c23e6309c501 100644 --- a/libcxx/modules/std/regex.cppm +++ b/libcxx/modules/std/regex.cppm @@ -64,9 +64,6 @@ export namespace std { // [re.submatch.op], sub_match non-member operators using std::operator==; using std::operator<=>; -# if 1 // P1614 - using std::operator!=; -# endif using std::operator<<; diff --git a/libcxx/test/std/re/re.iter/re.regiter/re.regiter.comp/tested_elsewhere.pass.cpp b/libcxx/test/std/re/re.iter/re.regiter/re.regiter.comp/tested_elsewhere.pass.cpp index f7f71bc8b7c5a..80f6aa3c75051 100644 --- a/libcxx/test/std/re/re.iter/re.regiter/re.regiter.comp/tested_elsewhere.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.regiter/re.regiter.comp/tested_elsewhere.pass.cpp @@ -11,7 +11,7 @@ // class regex_iterator // bool operator==(const regex_iterator& right) const; -// bool operator!=(const regex_iterator& right) const; +// bool operator!=(const regex_iterator& right) const; // generated by the compiler in C++20 int main(int, char**) { diff --git a/libcxx/test/std/re/re.iter/re.tokiter/re.tokiter.comp/equal.pass.cpp b/libcxx/test/std/re/re.iter/re.tokiter/re.tokiter.comp/equal.pass.cpp index 1c602010319e8..7ccb700c1d182 100644 --- a/libcxx/test/std/re/re.iter/re.tokiter/re.tokiter.comp/equal.pass.cpp +++ b/libcxx/test/std/re/re.iter/re.tokiter/re.tokiter.comp/equal.pass.cpp @@ -11,7 +11,7 @@ // class regex_token_iterator // bool operator==(const regex_token_iterator& right) const; -// bool operator!=(const regex_token_iterator& right) const; +// bool operator!=(const regex_token_iterator& right) const; // generated by the compiler in C++20 #include #include diff --git a/libcxx/test/std/re/re.results/re.results.nonmember/equal.pass.cpp b/libcxx/test/std/re/re.results/re.results.nonmember/equal.pass.cpp index 3723ad4740f47..1f01e95861fbc 100644 --- a/libcxx/test/std/re/re.results/re.results.nonmember/equal.pass.cpp +++ b/libcxx/test/std/re/re.results/re.results.nonmember/equal.pass.cpp @@ -15,7 +15,7 @@ // operator==(const match_results& m1, // const match_results& m2); -// template +// template // generated by the compiler in C++20 // bool // operator!=(const match_results& m1, // const match_results& m2); From f805c799bfceae68251ff19a21f60f7335bfaac5 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 17 Jun 2023 15:50:50 +0200 Subject: [PATCH 044/130] [libc++] "Implements" new SI prefixis. Like yocto, zepto, zetta, and yotta. The new prefixes quecto, ronto, ronna, and quetta can't be implemented in a intmax_t. So their implementation does nothing. Implements - P2734R0 Adding the new SI prefixes Depends on D153192 Reviewed By: #libc, philnik Differential Revision: https://reviews.llvm.org/D153200 --- libcxx/docs/FeatureTestMacroTable.rst | 2 +- libcxx/docs/Status/Cxx2cPapers.csv | 2 +- libcxx/include/ratio | 4 ++++ libcxx/include/version | 2 +- .../ratio.version.compile.pass.cpp | 16 +++++----------- .../version.version.compile.pass.cpp | 16 +++++----------- .../generate_feature_test_macro_components.py | 1 - 7 files changed, 17 insertions(+), 26 deletions(-) diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 4c8e1ffc828bb..9fa449557ec06 100644 --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -394,7 +394,7 @@ Status --------------------------------------------------- ----------------- ``__cpp_lib_hazard_pointer`` *unimplemented* --------------------------------------------------- ----------------- - ``__cpp_lib_ratio`` *unimplemented* + ``__cpp_lib_ratio`` ``202306L`` --------------------------------------------------- ----------------- ``__cpp_lib_rcu`` *unimplemented* --------------------------------------------------- ----------------- diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index 494e70f22a356..cd2e93377b20e 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -22,7 +22,7 @@ "`P1759R6 `__","LWG","Native handles and file streams","Varna June 2023","","","" "`P2697R1 `__","LWG","Interfacing ``bitset`` with ``string_view``","Varna June 2023","","","" "`P1383R2 `__","LWG","More ``constexpr`` for ```` and ````","Varna June 2023","","","" -"`P2734R0 `__","LWG","Adding the new SI prefixes","Varna June 2023","","","" +"`P2734R0 `__","LWG","Adding the new SI prefixes","Varna June 2023","|Complete|","Clang 17","" "`P2548R6 `__","LWG","``copyable_function``","Varna June 2023","","","" "`P2714R1 `__","LWG","Bind front and back to NTTP callables","Varna June 2023","","","" "`P2630R4 `__","LWG","``submdspan``","Varna June 2023","","","" diff --git a/libcxx/include/ratio b/libcxx/include/ratio index 327e08cf1b4f1..c9637ab818cda 100644 --- a/libcxx/include/ratio +++ b/libcxx/include/ratio @@ -40,6 +40,8 @@ template struct ratio_greater; template struct ratio_greater_equal; // convenience SI typedefs +using quecto = ratio <1, 1'000'000'000'000'000'000'000'000'000'000>; // Since C++26; not supported +using ronto = ratio <1, 1'000'000'000'000'000'000'000'000'000>; // Since C++26; not supported typedef ratio<1, 1000000000000000000000000> yocto; // not supported typedef ratio<1, 1000000000000000000000> zepto; // not supported typedef ratio<1, 1000000000000000000> atto; @@ -60,6 +62,8 @@ typedef ratio< 1000000000000000, 1> peta; typedef ratio< 1000000000000000000, 1> exa; typedef ratio< 1000000000000000000000, 1> zetta; // not supported typedef ratio<1000000000000000000000000, 1> yotta; // not supported +using ronna = ratio <1'000'000'000'000'000'000'000'000'000, 1>; // Since C++26; not supported +using quetta = ratio <1'000'000'000'000'000'000'000'000'000'000, 1>; // Since C++26; not supported // 20.11.5, ratio comparison template inline constexpr bool ratio_equal_v diff --git a/libcxx/include/version b/libcxx/include/version index 10abf695dadac..0cdf06d6d370c 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -456,7 +456,7 @@ __cpp_lib_within_lifetime 202306L // # define __cpp_lib_fstream_native_handle 202306L // # define __cpp_lib_function_ref 202306L // # define __cpp_lib_hazard_pointer 202306L -// # define __cpp_lib_ratio 202306L +# define __cpp_lib_ratio 202306L // # define __cpp_lib_rcu 202306L // # define __cpp_lib_smart_ptr_owner_equality 202306L // # define __cpp_lib_sstream_from_string_view 202306L diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp index f782c24898b43..38adba62079d7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ratio.version.compile.pass.cpp @@ -54,17 +54,11 @@ #elif TEST_STD_VER > 23 -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ratio -# error "__cpp_lib_ratio should be defined in c++26" -# endif -# if __cpp_lib_ratio != 202306L -# error "__cpp_lib_ratio should have the value 202306L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ratio -# error "__cpp_lib_ratio should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ratio +# error "__cpp_lib_ratio should be defined in c++26" +# endif +# if __cpp_lib_ratio != 202306L +# error "__cpp_lib_ratio should have the value 202306L in c++26" # endif #endif // TEST_STD_VER > 23 diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp index fb7081f2ebbf7..040dc9c6cd9e7 100644 --- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp @@ -6511,17 +6511,11 @@ # endif # endif -# if !defined(_LIBCPP_VERSION) -# ifndef __cpp_lib_ratio -# error "__cpp_lib_ratio should be defined in c++26" -# endif -# if __cpp_lib_ratio != 202306L -# error "__cpp_lib_ratio should have the value 202306L in c++26" -# endif -# else // _LIBCPP_VERSION -# ifdef __cpp_lib_ratio -# error "__cpp_lib_ratio should not be defined because it is unimplemented in libc++!" -# endif +# ifndef __cpp_lib_ratio +# error "__cpp_lib_ratio should be defined in c++26" +# endif +# if __cpp_lib_ratio != 202306L +# error "__cpp_lib_ratio should have the value 202306L in c++26" # endif # ifndef __cpp_lib_raw_memory_algorithms diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py index 4d454f7e42986..4b835791aee53 100755 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -847,7 +847,6 @@ def add_version_header(tc): "name": "__cpp_lib_ratio", "values": {"c++26": 202306}, # P2734R0 Adding the new SI prefixes "headers": ["ratio"], - "unimplemented": True, }, { "name": "__cpp_lib_raw_memory_algorithms", From b4bb6211a5e7679092086324a3bd398bb8fee1f4 Mon Sep 17 00:00:00 2001 From: Job Noorman Date: Mon, 19 Jun 2023 16:51:43 +0200 Subject: [PATCH 045/130] [BOLT] Implement composed relocations BOLT currently assumes (and asserts) that no two relocations can share the same offset. Although this is true in most cases, ELF has a feature called (not sure if this is an official term) composed relocations [1] where multiple relocations at the same offset are combined to produce a single value. For example, to support label subtraction (a - b) on RISC-V, two relocations are emitted at the same offset: - R_RISCV_ADD32 a + 0 - R_RISCV_SUB32 b + 0 which, when combined, will produce the value of (a - b). To support this in BOLT, first, RelocationSetType in BinarySection is changed to be a multiset in order to allow it to store multiple relocations at the same offset. Next, Relocation::emit() is changed to receive an iterator pair of relocations. In most cases, these will point to a single relocation in which case its behavior is unaltered by this patch. For composed relocations, they should point to all relocations at the same offset and the following happens: - A new method Relocation::createExpr() is called for every relocation. This method is essentially the same as the original emit() except that it returns the MCExpr without emitting it. - The MCExprs of relocations i and i+1 are combined using the opcode returned by the new method Relocation::getComposeOpcodeFor(). - After combining all MCExprs, the last one is emitted. Note that in the current patch, getComposeOpcodeFor() simply calls llvm_unreachable() since none of the current targets use composed relocations. This will change once the RISC-V target lands. Finally, BinarySection::emitAsData() is updated to group relocations by offset and emit them all at once. Note that this means composed relocations are only supported in data sections. Since this is the only place they seem to be used in RISC-V, I believe it's reasonable to only support them there for now to avoid further code complexity. [1]: https://www.sco.com/developers/gabi/latest/ch4.reloc.html Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D146546 --- bolt/include/bolt/Core/BinarySection.h | 5 ++- bolt/include/bolt/Core/Relocation.h | 31 ++++++++++++++- bolt/lib/Core/BinarySection.cpp | 53 +++++++++++++++++-------- bolt/lib/Core/Relocation.cpp | 55 +++++++++++++++----------- 4 files changed, 101 insertions(+), 43 deletions(-) diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h index 6890ced83b13b..078b33bc9c5ab 100644 --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -59,7 +59,7 @@ class BinarySection { // Relocations associated with this section. Relocation offsets are // wrt. to the original section address and size. - using RelocationSetType = std::set>; + using RelocationSetType = std::multiset>; RelocationSetType Relocations; // Dynamic relocations associated with this section. Relocation offsets are @@ -345,7 +345,8 @@ class BinarySection { bool removeRelocationAt(uint64_t Offset) { auto Itr = Relocations.find(Offset); if (Itr != Relocations.end()) { - Relocations.erase(Itr); + auto End = Relocations.upper_bound(Offset); + Relocations.erase(Itr, End); return true; } return false; diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h index 1296c001db57c..5ae288a91986e 100644 --- a/bolt/include/bolt/Core/Relocation.h +++ b/bolt/include/bolt/Core/Relocation.h @@ -14,10 +14,11 @@ #ifndef BOLT_CORE_RELOCATION_H #define BOLT_CORE_RELOCATION_H +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/TargetParser/Triple.h" namespace llvm { -class MCStreamer; class MCSymbol; class raw_ostream; @@ -122,8 +123,36 @@ struct Relocation { /// responsible for setting the position correctly. size_t emit(MCStreamer *Streamer) const; + /// Emit a group of composed relocations. All relocations must have the same + /// offset. If std::distance(Begin, End) == 1, this is equivalent to + /// Begin->emit(Streamer). + template + static size_t emit(RelocIt Begin, RelocIt End, MCStreamer *Streamer) { + if (Begin == End) + return 0; + + const MCExpr *Value = nullptr; + + for (auto RI = Begin; RI != End; ++RI) { + assert(RI->Offset == Begin->Offset && + "emitting composed relocations with different offsets"); + Value = RI->createExpr(Streamer, Value); + } + + assert(Value && "failed to create relocation value"); + auto Size = std::prev(End)->getSize(); + Streamer->emitValue(Value, Size); + return Size; + } + /// Print a relocation to \p OS. void print(raw_ostream &OS) const; + +private: + const MCExpr *createExpr(MCStreamer *Streamer) const; + const MCExpr *createExpr(MCStreamer *Streamer, + const MCExpr *RetainedValue) const; + static MCBinaryExpr::Opcode getComposeOpcodeFor(uint64_t Type); }; /// Relocation ordering by offset. diff --git a/bolt/lib/Core/BinarySection.cpp b/bolt/lib/Core/BinarySection.cpp index e0e7b15d04a57..e3a1e79b98b15 100644 --- a/bolt/lib/Core/BinarySection.cpp +++ b/bolt/lib/Core/BinarySection.cpp @@ -90,23 +90,44 @@ void BinarySection::emitAsData(MCStreamer &Streamer, Streamer.emitBytes(SectionContents); } else { uint64_t SectionOffset = 0; - for (const Relocation &Relocation : relocations()) { - assert(Relocation.Offset < SectionContents.size() && "overflow detected"); + for (auto RI = Relocations.begin(), RE = Relocations.end(); RI != RE;) { + auto RelocationOffset = RI->Offset; + assert(RelocationOffset < SectionContents.size() && "overflow detected"); + + if (SectionOffset < RelocationOffset) { + Streamer.emitBytes(SectionContents.substr( + SectionOffset, RelocationOffset - SectionOffset)); + SectionOffset = RelocationOffset; + } + + // Get iterators to all relocations with the same offset. Usually, there + // is only one such relocation but there can be more for composed + // relocations. + auto ROI = RI; + auto ROE = Relocations.upper_bound(RelocationOffset); + + // Start from the next offset on the next iteration. + RI = ROE; + // Skip undefined symbols. - if (BC.UndefinedSymbols.count(Relocation.Symbol)) + auto HasUndefSym = [this](const auto &Relocation) { + return BC.UndefinedSymbols.count(Relocation.Symbol); + }; + + if (std::any_of(ROI, ROE, HasUndefSym)) continue; - if (SectionOffset < Relocation.Offset) { - Streamer.emitBytes(SectionContents.substr( - SectionOffset, Relocation.Offset - SectionOffset)); - SectionOffset = Relocation.Offset; + + for (const auto &Relocation : make_range(ROI, ROE)) { + LLVM_DEBUG( + dbgs() << "BOLT-DEBUG: emitting relocation for symbol " + << (Relocation.Symbol ? Relocation.Symbol->getName() + : StringRef("")) + << " at offset 0x" << Twine::utohexstr(Relocation.Offset) + << " with size " + << Relocation::getSizeForType(Relocation.Type) << '\n'); } - LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting relocation for symbol " - << (Relocation.Symbol ? Relocation.Symbol->getName() - : StringRef("")) - << " at offset 0x" - << Twine::utohexstr(Relocation.Offset) << " with size " - << Relocation::getSizeForType(Relocation.Type) << '\n'); - size_t RelocationSize = Relocation.emit(&Streamer); + + size_t RelocationSize = Relocation::emit(ROI, ROE, &Streamer); SectionOffset += RelocationSize; } assert(SectionOffset <= SectionContents.size() && "overflow error"); @@ -221,9 +242,7 @@ BinarySection::reorderRelocations(bool Inplace) const { assert(NewRel.Offset < getSize()); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: moving " << Rel << " -> " << NewRel << "\n"); - auto Res = NewRelocations.emplace(std::move(NewRel)); - (void)Res; - assert(Res.second && "Can't overwrite existing relocation"); + NewRelocations.emplace(std::move(NewRel)); } return NewRelocations; } diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index 0901a1465193c..b02ca61964a74 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -817,39 +817,48 @@ uint64_t Relocation::getRelative() { size_t Relocation::emit(MCStreamer *Streamer) const { const size_t Size = getSizeForType(Type); + const auto *Value = createExpr(Streamer); + Streamer->emitValue(Value, Size); + return Size; +} + +const MCExpr *Relocation::createExpr(MCStreamer *Streamer) const { MCContext &Ctx = Streamer->getContext(); + const MCExpr *Value = nullptr; + + if (Symbol && Addend) { + Value = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx), + MCConstantExpr::create(Addend, Ctx), Ctx); + } else if (Symbol) { + Value = MCSymbolRefExpr::create(Symbol, Ctx); + } else { + Value = MCConstantExpr::create(Addend, Ctx); + } + if (isPCRelative(Type)) { MCSymbol *TempLabel = Ctx.createNamedTempSymbol(); Streamer->emitLabel(TempLabel); - const MCExpr *Value = nullptr; - if (Symbol) { - Value = MCSymbolRefExpr::create(Symbol, Ctx); - if (Addend) { - Value = MCBinaryExpr::createAdd( - Value, MCConstantExpr::create(Addend, Ctx), Ctx); - } - } else { - Value = MCConstantExpr::create(Addend, Ctx); - } Value = MCBinaryExpr::createSub( Value, MCSymbolRefExpr::create(TempLabel, Ctx), Ctx); - Streamer->emitValue(Value, Size); - - return Size; } - if (Symbol && Addend) { - auto Value = - MCBinaryExpr::createAdd(MCSymbolRefExpr::create(Symbol, Ctx), - MCConstantExpr::create(Addend, Ctx), Ctx); - Streamer->emitValue(Value, Size); - } else if (Symbol) { - Streamer->emitSymbolValue(Symbol, Size); - } else { - Streamer->emitIntValue(Addend, Size); + return Value; +} + +const MCExpr *Relocation::createExpr(MCStreamer *Streamer, + const MCExpr *RetainedValue) const { + const auto *Value = createExpr(Streamer); + + if (RetainedValue) { + Value = MCBinaryExpr::create(getComposeOpcodeFor(Type), RetainedValue, + Value, Streamer->getContext()); } - return Size; + return Value; +} + +MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint64_t Type) { + llvm_unreachable("not implemented"); } #define ELF_RELOC(name, value) #name, From bb4f4a3efeae2bc0785edc19d2347f21729c816c Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 17:04:49 +0200 Subject: [PATCH 046/130] [CVP] Add additional tests for PR63330 (NFC) --- .../udiv-expansion.ll | 18 ++++++++++++++++++ .../urem-expansion.ll | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll index 7284f280fa764..8b796f79e60d0 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll @@ -298,3 +298,21 @@ define i8 @large.divisor.with.overflow.v2.unbound.x(i8 %x) { %div = udiv i8 %x, 128 ret i8 %div } + +define i8 @known_uge(i8 noundef %x) { +; CHECK-LABEL: @known_uge( +; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 6 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) +; CHECK-NEXT: [[CMP_X_LOWER:%.*]] = icmp uge i8 [[X]], 3 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_LOWER]]) +; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3 +; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8 +; CHECK-NEXT: ret i8 [[DIV]] +; + %cmp.x.upper = icmp ult i8 %x, 6 + call void @llvm.assume(i1 %cmp.x.upper) + %cmp.x.lower = icmp uge i8 %x, 3 + call void @llvm.assume(i1 %cmp.x.lower) + %div = udiv i8 %x, 3 + ret i8 %div +} diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll index 2f1ca2483f67d..da38e5a269e6d 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll @@ -342,3 +342,22 @@ define i1 @icmp_after_expansion(i8 noundef %x) { %cmp = icmp eq i8 %rem, 3 ret i1 %cmp } + +define i8 @known_uge(i8 noundef %x) { +; CHECK-LABEL: @known_uge( +; CHECK-NEXT: [[CMP_X_UPPER:%.*]] = icmp ult i8 [[X:%.*]], 6 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) +; CHECK-NEXT: [[CMP_X_LOWER:%.*]] = icmp uge i8 [[X]], 3 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_LOWER]]) +; CHECK-NEXT: [[REM_UREM:%.*]] = sub nuw i8 [[X]], 3 +; CHECK-NEXT: [[REM_CMP:%.*]] = icmp ult i8 [[X]], 3 +; CHECK-NEXT: [[REM:%.*]] = select i1 [[REM_CMP]], i8 [[X]], i8 [[REM_UREM]] +; CHECK-NEXT: ret i8 [[REM]] +; + %cmp.x.upper = icmp ult i8 %x, 6 + call void @llvm.assume(i1 %cmp.x.upper) + %cmp.x.lower = icmp uge i8 %x, 3 + call void @llvm.assume(i1 %cmp.x.lower) + %rem = urem i8 %x, 3 + ret i8 %rem +} From 7cfc82f331182855e2634c21d242c3b418f84bd1 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 19 Jun 2023 17:14:37 +0200 Subject: [PATCH 047/130] [CVP] Use simpler urem expansion when LHS >= RHS (PR63330) In this case we don't need to emit the comparison and select. This is papering over a weakness in CVP in that newly added instructions don't get revisited. If they were revisited, the icmp would be folded at that point. However, even without that it makes sense to handle this explicitly, because it avoids the need to insert freeze, which may prevent further analysis of the operation by LVI. Proofs: https://alive2.llvm.org/ce/z/quyBxp Fixes https://github.com/llvm/llvm-project/issues/63330. --- llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp | 8 +++++++- .../CorrelatedValuePropagation/udiv-expansion.ll | 4 +--- .../CorrelatedValuePropagation/urem-expansion.ll | 4 +--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 488297110d6fa..49d11b790c7ff 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -763,7 +763,13 @@ static bool expandUDivOrURem(BinaryOperator *Instr, const ConstantRange &XCR, IRBuilder<> B(Instr); Value *ExpandedOp; - if (IsRem) { + if (XCR.icmp(ICmpInst::ICMP_UGE, YCR)) { + // If X is between Y and 2*Y the result is known. + if (IsRem) + ExpandedOp = B.CreateNUWSub(X, Y); + else + ExpandedOp = ConstantInt::get(Instr->getType(), 1); + } else if (IsRem) { // NOTE: this transformation introduces two uses of X, // but it may be undef so we must freeze it first. Value *FrozenX = X; diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll index 8b796f79e60d0..a2a767084fbff 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/udiv-expansion.ll @@ -305,9 +305,7 @@ define i8 @known_uge(i8 noundef %x) { ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) ; CHECK-NEXT: [[CMP_X_LOWER:%.*]] = icmp uge i8 [[X]], 3 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_LOWER]]) -; CHECK-NEXT: [[DIV_CMP:%.*]] = icmp uge i8 [[X]], 3 -; CHECK-NEXT: [[DIV:%.*]] = zext i1 [[DIV_CMP]] to i8 -; CHECK-NEXT: ret i8 [[DIV]] +; CHECK-NEXT: ret i8 1 ; %cmp.x.upper = icmp ult i8 %x, 6 call void @llvm.assume(i1 %cmp.x.upper) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll index da38e5a269e6d..cd0ba2f189dc8 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem-expansion.ll @@ -349,9 +349,7 @@ define i8 @known_uge(i8 noundef %x) { ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_UPPER]]) ; CHECK-NEXT: [[CMP_X_LOWER:%.*]] = icmp uge i8 [[X]], 3 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_X_LOWER]]) -; CHECK-NEXT: [[REM_UREM:%.*]] = sub nuw i8 [[X]], 3 -; CHECK-NEXT: [[REM_CMP:%.*]] = icmp ult i8 [[X]], 3 -; CHECK-NEXT: [[REM:%.*]] = select i1 [[REM_CMP]], i8 [[X]], i8 [[REM_UREM]] +; CHECK-NEXT: [[REM:%.*]] = sub nuw i8 [[X]], 3 ; CHECK-NEXT: ret i8 [[REM]] ; %cmp.x.upper = icmp ult i8 %x, 6 From 923dbb01ea6be1ec919d0b71b34551ae91169bc7 Mon Sep 17 00:00:00 2001 From: Andrea Di Biagio Date: Mon, 19 Jun 2023 14:37:22 +0100 Subject: [PATCH 048/130] [llvm-mca][TimelineView] Skip invalid entries when printing the json output. --- llvm/tools/llvm-mca/Views/TimelineView.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/tools/llvm-mca/Views/TimelineView.cpp b/llvm/tools/llvm-mca/Views/TimelineView.cpp index 5c05edbdea686..2eca48aadfd70 100644 --- a/llvm/tools/llvm-mca/Views/TimelineView.cpp +++ b/llvm/tools/llvm-mca/Views/TimelineView.cpp @@ -315,6 +315,10 @@ json::Value TimelineView::toJSON() const { json::Array TimelineInfo; for (const TimelineViewEntry &TLE : Timeline) { + // Check if the timeline-max-cycles has been reached. + if (!TLE.CycleRetired && TLE.CycleExecuted) + break; + TimelineInfo.push_back( json::Object({{"CycleDispatched", TLE.CycleDispatched}, {"CycleReady", TLE.CycleReady}, From 5aa03b648b827128d439f705cd7d57d59673741d Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Fri, 16 Jun 2023 09:49:04 -0400 Subject: [PATCH 049/130] [libc++][NFC] Apply clang-format on large parts of the code base This commit does a pass of clang-format over files in libc++ that don't require major changes to conform to our style guide, or for which we're not overly concerned about conflicting with in-flight patches or hindering the git blame. This roughly covers: - benchmarks - range algorithms - concepts - type traits I did a manual verification of all the changes, and in particular I applied clang-format on/off annotations in a few places where the result was less readable after than before. This was not necessary in a lot of places, however I did find that clang-format had pretty bad taste when it comes to formatting concepts. Differential Revision: https://reviews.llvm.org/D153140 --- libcxx/benchmarks/CartesianBenchmarks.h | 26 +- libcxx/benchmarks/ContainerBenchmarks.h | 150 +++-- libcxx/benchmarks/GenerateInput.h | 143 ++--- libcxx/benchmarks/Utilities.h | 22 +- libcxx/benchmarks/VariantBenchmarks.h | 11 +- .../algorithms.partition_point.bench.cpp | 13 +- libcxx/benchmarks/algorithms/common.h | 53 +- .../algorithms/lower_bound.bench.cpp | 6 +- .../benchmarks/algorithms/make_heap.bench.cpp | 9 +- .../make_heap_then_sort_heap.bench.cpp | 12 +- .../benchmarks/algorithms/pop_heap.bench.cpp | 15 +- .../benchmarks/algorithms/push_heap.bench.cpp | 14 +- .../algorithms/ranges_make_heap.bench.cpp | 9 +- .../ranges_make_heap_then_sort_heap.bench.cpp | 12 +- .../algorithms/ranges_pop_heap.bench.cpp | 15 +- .../algorithms/ranges_push_heap.bench.cpp | 14 +- .../algorithms/ranges_sort.bench.cpp | 9 +- .../algorithms/ranges_sort_heap.bench.cpp | 10 +- .../algorithms/ranges_stable_sort.bench.cpp | 9 +- libcxx/benchmarks/algorithms/sort.bench.cpp | 11 +- .../benchmarks/algorithms/sort_heap.bench.cpp | 10 +- .../algorithms/stable_sort.bench.cpp | 9 +- libcxx/benchmarks/allocation.bench.cpp | 60 +- libcxx/benchmarks/deque.bench.cpp | 29 +- libcxx/benchmarks/filesystem.bench.cpp | 72 ++- libcxx/benchmarks/format_to.bench.cpp | 12 +- libcxx/benchmarks/format_to_n.bench.cpp | 12 +- libcxx/benchmarks/formatter_float.bench.cpp | 15 +- libcxx/benchmarks/formatter_int.bench.cpp | 7 +- libcxx/benchmarks/function.bench.cpp | 78 ++- libcxx/benchmarks/map.bench.cpp | 216 ++----- libcxx/benchmarks/ordered_set.bench.cpp | 49 +- libcxx/benchmarks/random.bench.cpp | 2 +- libcxx/benchmarks/string.bench.cpp | 224 +++---- libcxx/benchmarks/stringstream.bench.cpp | 24 +- .../unordered_set_operations.bench.cpp | 375 +++++------ libcxx/benchmarks/vector_operations.bench.cpp | 39 +- .../__algorithm/ranges_adjacent_find.h | 24 +- libcxx/include/__algorithm/ranges_all_of.h | 21 +- libcxx/include/__algorithm/ranges_any_of.h | 21 +- .../__algorithm/ranges_binary_search.h | 23 +- libcxx/include/__algorithm/ranges_clamp.h | 14 +- libcxx/include/__algorithm/ranges_copy.h | 11 +- .../__algorithm/ranges_copy_backward.h | 13 +- libcxx/include/__algorithm/ranges_copy_if.h | 23 +- libcxx/include/__algorithm/ranges_copy_n.h | 15 +- libcxx/include/__algorithm/ranges_count.h | 10 +- libcxx/include/__algorithm/ranges_count_if.h | 22 +- libcxx/include/__algorithm/ranges_equal.h | 60 +- .../include/__algorithm/ranges_equal_range.h | 29 +- libcxx/include/__algorithm/ranges_fill.h | 10 +- libcxx/include/__algorithm/ranges_fill_n.h | 6 +- libcxx/include/__algorithm/ranges_find.h | 10 +- libcxx/include/__algorithm/ranges_find_end.h | 34 +- .../__algorithm/ranges_find_first_of.h | 70 +-- libcxx/include/__algorithm/ranges_find_if.h | 21 +- .../include/__algorithm/ranges_find_if_not.h | 17 +- libcxx/include/__algorithm/ranges_for_each.h | 20 +- .../include/__algorithm/ranges_for_each_n.h | 15 +- libcxx/include/__algorithm/ranges_generate.h | 17 +- .../include/__algorithm/ranges_generate_n.h | 10 +- libcxx/include/__algorithm/ranges_includes.h | 30 +- .../__algorithm/ranges_inplace_merge.h | 56 +- libcxx/include/__algorithm/ranges_is_heap.h | 24 +- .../__algorithm/ranges_is_heap_until.h | 25 +- .../__algorithm/ranges_is_partitioned.h | 18 +- .../__algorithm/ranges_is_permutation.h | 69 +- libcxx/include/__algorithm/ranges_is_sorted.h | 17 +- .../__algorithm/ranges_is_sorted_until.h | 21 +- .../ranges_lexicographical_compare.h | 73 +-- .../include/__algorithm/ranges_lower_bound.h | 22 +- libcxx/include/__algorithm/ranges_make_heap.h | 14 +- libcxx/include/__algorithm/ranges_max.h | 33 +- .../include/__algorithm/ranges_max_element.h | 17 +- libcxx/include/__algorithm/ranges_merge.h | 91 ++- libcxx/include/__algorithm/ranges_min.h | 33 +- .../include/__algorithm/ranges_min_element.h | 20 +- libcxx/include/__algorithm/ranges_minmax.h | 32 +- .../__algorithm/ranges_minmax_element.h | 16 +- libcxx/include/__algorithm/ranges_mismatch.h | 42 +- libcxx/include/__algorithm/ranges_move.h | 16 +- .../__algorithm/ranges_move_backward.h | 16 +- libcxx/include/__algorithm/ranges_none_of.h | 22 +- .../include/__algorithm/ranges_nth_element.h | 15 +- .../include/__algorithm/ranges_partial_sort.h | 15 +- .../__algorithm/ranges_partial_sort_copy.h | 73 ++- libcxx/include/__algorithm/ranges_partition.h | 27 +- .../__algorithm/ranges_partition_copy.h | 49 +- .../__algorithm/ranges_partition_point.h | 24 +- libcxx/include/__algorithm/ranges_pop_heap.h | 16 +- .../__algorithm/ranges_prev_permutation.h | 8 +- libcxx/include/__algorithm/ranges_push_heap.h | 14 +- libcxx/include/__algorithm/ranges_remove.h | 15 +- .../include/__algorithm/ranges_remove_copy.h | 48 +- .../__algorithm/ranges_remove_copy_if.h | 46 +- libcxx/include/__algorithm/ranges_remove_if.h | 19 +- libcxx/include/__algorithm/ranges_replace.h | 29 +- .../include/__algorithm/ranges_replace_copy.h | 75 ++- .../__algorithm/ranges_replace_copy_if.h | 56 +- .../include/__algorithm/ranges_replace_if.h | 15 +- libcxx/include/__algorithm/ranges_reverse.h | 10 +- .../include/__algorithm/ranges_reverse_copy.h | 12 +- libcxx/include/__algorithm/ranges_rotate.h | 19 +- .../include/__algorithm/ranges_rotate_copy.h | 10 +- libcxx/include/__algorithm/ranges_sample.h | 27 +- libcxx/include/__algorithm/ranges_search.h | 35 +- libcxx/include/__algorithm/ranges_search_n.h | 34 +- .../__algorithm/ranges_set_difference.h | 45 +- .../__algorithm/ranges_set_intersection.h | 59 +- .../ranges_set_symmetric_difference.h | 53 +- libcxx/include/__algorithm/ranges_set_union.h | 57 +- libcxx/include/__algorithm/ranges_shuffle.h | 16 +- libcxx/include/__algorithm/ranges_sort.h | 14 +- libcxx/include/__algorithm/ranges_sort_heap.h | 14 +- .../__algorithm/ranges_stable_partition.h | 29 +- .../include/__algorithm/ranges_stable_sort.h | 12 +- .../include/__algorithm/ranges_swap_ranges.h | 11 +- libcxx/include/__algorithm/ranges_transform.h | 120 ++-- libcxx/include/__algorithm/ranges_unique.h | 48 +- .../include/__algorithm/ranges_unique_copy.h | 6 +- .../include/__algorithm/ranges_upper_bound.h | 29 +- libcxx/include/__concepts/arithmetic.h | 8 +- libcxx/include/__concepts/assignable.h | 12 +- libcxx/include/__concepts/boolean_testable.h | 4 +- libcxx/include/__concepts/class_or_enum.h | 4 +- .../__concepts/common_reference_with.h | 7 +- libcxx/include/__concepts/common_with.h | 30 +- libcxx/include/__concepts/constructible.h | 29 +- libcxx/include/__concepts/convertible_to.h | 8 +- libcxx/include/__concepts/copyable.h | 14 +- libcxx/include/__concepts/derived_from.h | 6 +- libcxx/include/__concepts/destructible.h | 2 +- libcxx/include/__concepts/different_from.h | 2 +- .../include/__concepts/equality_comparable.h | 36 +- libcxx/include/__concepts/invocable.h | 4 +- libcxx/include/__concepts/movable.h | 8 +- libcxx/include/__concepts/predicate.h | 5 +- libcxx/include/__concepts/regular.h | 2 +- libcxx/include/__concepts/relation.h | 9 +- libcxx/include/__concepts/same_as.h | 4 +- libcxx/include/__concepts/semiregular.h | 2 +- libcxx/include/__concepts/swappable.h | 115 ++-- libcxx/include/__concepts/totally_ordered.h | 45 +- libcxx/include/__type_traits/add_const.h | 6 +- libcxx/include/__type_traits/add_cv.h | 6 +- .../__type_traits/add_lvalue_reference.h | 3 +- libcxx/include/__type_traits/add_pointer.h | 12 +- libcxx/include/__type_traits/add_volatile.h | 6 +- .../include/__type_traits/aligned_storage.h | 90 +-- libcxx/include/__type_traits/aligned_union.h | 29 +- libcxx/include/__type_traits/alignment_of.h | 4 +- .../include/__type_traits/can_extract_key.h | 9 +- .../include/__type_traits/common_reference.h | 125 ++-- libcxx/include/__type_traits/common_type.h | 45 +- libcxx/include/__type_traits/copy_cv.h | 20 +- libcxx/include/__type_traits/copy_cvref.h | 15 +- libcxx/include/__type_traits/decay.h | 27 +- libcxx/include/__type_traits/enable_if.h | 14 +- libcxx/include/__type_traits/extent.h | 35 +- .../has_unique_object_representation.h | 6 +- .../__type_traits/has_virtual_destructor.h | 4 +- .../include/__type_traits/integral_constant.h | 15 +- libcxx/include/__type_traits/invoke.h | 595 ++++++++---------- libcxx/include/__type_traits/is_abstract.h | 4 +- libcxx/include/__type_traits/is_aggregate.h | 4 +- libcxx/include/__type_traits/is_allocator.h | 10 +- .../__type_traits/is_always_bitcastable.h | 83 +-- libcxx/include/__type_traits/is_arithmetic.h | 6 +- libcxx/include/__type_traits/is_array.h | 22 +- libcxx/include/__type_traits/is_assignable.h | 4 +- libcxx/include/__type_traits/is_base_of.h | 3 +- .../include/__type_traits/is_bounded_array.h | 15 +- libcxx/include/__type_traits/is_callable.h | 6 +- libcxx/include/__type_traits/is_class.h | 4 +- libcxx/include/__type_traits/is_compound.h | 16 +- libcxx/include/__type_traits/is_const.h | 16 +- .../__type_traits/is_constant_evaluated.h | 8 +- .../include/__type_traits/is_constructible.h | 8 +- libcxx/include/__type_traits/is_convertible.h | 105 ++-- .../__type_traits/is_copy_assignable.h | 3 +- .../__type_traits/is_copy_constructible.h | 5 +- .../__type_traits/is_core_convertible.h | 5 +- .../__type_traits/is_default_constructible.h | 4 +- .../include/__type_traits/is_destructible.h | 43 +- libcxx/include/__type_traits/is_empty.h | 3 +- libcxx/include/__type_traits/is_enum.h | 4 +- libcxx/include/__type_traits/is_final.h | 8 +- .../include/__type_traits/is_floating_point.h | 6 +- libcxx/include/__type_traits/is_fundamental.h | 19 +- .../is_implicitly_default_constructible.h | 16 +- libcxx/include/__type_traits/is_integral.h | 16 +- .../include/__type_traits/is_literal_type.h | 12 +- .../is_member_function_pointer.h | 34 +- .../__type_traits/is_member_object_pointer.h | 18 +- .../include/__type_traits/is_member_pointer.h | 17 +- .../__type_traits/is_move_assignable.h | 4 +- .../__type_traits/is_move_constructible.h | 3 +- .../__type_traits/is_nothrow_assignable.h | 4 +- .../__type_traits/is_nothrow_constructible.h | 38 +- .../__type_traits/is_nothrow_convertible.h | 15 +- .../is_nothrow_copy_assignable.h | 8 +- .../is_nothrow_copy_constructible.h | 6 +- .../is_nothrow_default_constructible.h | 6 +- .../__type_traits/is_nothrow_destructible.h | 45 +- .../is_nothrow_move_assignable.h | 5 +- .../is_nothrow_move_constructible.h | 12 +- .../include/__type_traits/is_null_pointer.h | 18 +- libcxx/include/__type_traits/is_object.h | 22 +- libcxx/include/__type_traits/is_pod.h | 4 +- libcxx/include/__type_traits/is_pointer.h | 32 +- libcxx/include/__type_traits/is_polymorphic.h | 3 +- .../__type_traits/is_primary_template.h | 9 +- libcxx/include/__type_traits/is_reference.h | 45 +- .../__type_traits/is_reference_wrapper.h | 15 +- libcxx/include/__type_traits/is_same.h | 2 +- libcxx/include/__type_traits/is_scalar.h | 36 +- libcxx/include/__type_traits/is_scoped_enum.h | 6 +- libcxx/include/__type_traits/is_signed.h | 20 +- .../include/__type_traits/is_signed_integer.h | 16 +- .../__type_traits/is_standard_layout.h | 5 +- libcxx/include/__type_traits/is_swappable.h | 100 ++- libcxx/include/__type_traits/is_trivial.h | 5 +- .../__type_traits/is_trivially_assignable.h | 4 +- .../is_trivially_constructible.h | 4 +- .../is_trivially_copy_assignable.h | 8 +- .../is_trivially_copy_constructible.h | 6 +- .../__type_traits/is_trivially_copyable.h | 5 +- .../is_trivially_default_constructible.h | 6 +- .../__type_traits/is_trivially_destructible.h | 10 +- .../__type_traits/is_unbounded_array.h | 15 +- libcxx/include/__type_traits/is_union.h | 4 +- libcxx/include/__type_traits/is_unsigned.h | 20 +- .../__type_traits/is_unsigned_integer.h | 16 +- .../__type_traits/is_valid_expansion.h | 6 +- libcxx/include/__type_traits/is_void.h | 14 +- libcxx/include/__type_traits/is_volatile.h | 16 +- libcxx/include/__type_traits/lazy.h | 2 +- .../__type_traits/make_32_64_or_128_bit.h | 19 +- .../__type_traits/make_const_lvalue_ref.h | 2 +- libcxx/include/__type_traits/make_signed.h | 33 +- libcxx/include/__type_traits/make_unsigned.h | 38 +- libcxx/include/__type_traits/maybe_const.h | 2 +- libcxx/include/__type_traits/nat.h | 11 +- libcxx/include/__type_traits/negation.h | 2 +- .../noexcept_move_assign_container.h | 14 +- libcxx/include/__type_traits/promote.h | 84 ++- libcxx/include/__type_traits/rank.h | 12 +- .../__type_traits/remove_all_extents.h | 21 +- libcxx/include/__type_traits/remove_const.h | 13 +- libcxx/include/__type_traits/remove_cv.h | 9 +- libcxx/include/__type_traits/remove_cvref.h | 5 +- libcxx/include/__type_traits/remove_extent.h | 21 +- libcxx/include/__type_traits/remove_pointer.h | 5 +- .../include/__type_traits/remove_reference.h | 5 +- .../include/__type_traits/remove_volatile.h | 13 +- libcxx/include/__type_traits/result_of.h | 23 +- .../include/__type_traits/strip_signature.h | 8 +- libcxx/include/__type_traits/type_identity.h | 12 +- libcxx/include/__type_traits/type_list.h | 20 +- .../include/__type_traits/underlying_type.h | 11 +- libcxx/include/__type_traits/unwrap_ref.h | 15 +- libcxx/include/__type_traits/void_t.h | 3 +- libcxx/utils/data/ignore_format.txt | 262 -------- 263 files changed, 3365 insertions(+), 4090 deletions(-) diff --git a/libcxx/benchmarks/CartesianBenchmarks.h b/libcxx/benchmarks/CartesianBenchmarks.h index 2eea156819330..eca4e15cd009b 100644 --- a/libcxx/benchmarks/CartesianBenchmarks.h +++ b/libcxx/benchmarks/CartesianBenchmarks.h @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// - #include #include #include @@ -22,7 +21,7 @@ struct EnumValue : std::integral_constant(I)> { static std::string name() { return std::string("_") + D::Names[I]; } }; -template +template constexpr auto makeEnumValueTuple(std::index_sequence) { return std::make_tuple(EnumValue{}...); } @@ -41,8 +40,7 @@ void makeBenchmarkFromValuesImpl(const Args& A, std::index_sequence) { for (auto& V : A) { B Bench{std::get(V)...}; if (!internal::skip(Bench, 0)) { - benchmark::RegisterBenchmark(Bench.name().c_str(), - [=](benchmark::State& S) { Bench.run(S); }); + benchmark::RegisterBenchmark(Bench.name().c_str(), [=](benchmark::State& S) { Bench.run(S); }); } } } @@ -57,10 +55,8 @@ void makeBenchmarkImpl(const Args& A, std::tuple t) { makeBenchmarkFromValues >(A); } -template