diff options
40 files changed, 672 insertions, 394 deletions
diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 16ada9e..da1d1ca 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -1121,3 +1121,6 @@ tablegen: - llvm/include/TableGen/** - llvm/lib/TableGen/** - llvm/utils/TableGen/** + +infrastructure: + - .ci/** diff --git a/.github/workflows/llvm-tests.yml b/.github/workflows/llvm-abi-tests.yml index c4701c7..f73d180 100644 --- a/.github/workflows/llvm-tests.yml +++ b/.github/workflows/llvm-abi-tests.yml @@ -1,4 +1,4 @@ -name: LLVM Tests +name: LLVM ABI Tests permissions: contents: read diff --git a/bolt/utils/dot2html/d3-graphviz-template.html b/bolt/utils/dot2html/d3-graphviz-template.html index c86f779..46fdf2a 100644 --- a/bolt/utils/dot2html/d3-graphviz-template.html +++ b/bolt/utils/dot2html/d3-graphviz-template.html @@ -1,9 +1,9 @@ <!DOCTYPE html> <meta charset="utf-8"> <body> -<script src="https://d3js.org/d3.v5.min.js"></script> -<script src="https://unpkg.com/@hpcc-js/wasm@0.3.11/dist/index.min.js"></script> -<script src="https://unpkg.com/d3-graphviz@3.0.5/build/d3-graphviz.js"></script> +<script src="https://d3js.org/d3.v7.min.js"></script> +<script src="https://unpkg.com/@hpcc-js/wasm@2.20.0/dist/graphviz.umd.js"></script> +<script src="https://unpkg.com/d3-graphviz@5.6.0/build/d3-graphviz.js"></script> <div id="graph" style="text-align: center;"></div> <script> var dotSrc = ` diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 93d81e3..569491a 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -178,9 +178,10 @@ public: } mlir::Value createComplexImag(mlir::Location loc, mlir::Value operand) { - auto operandTy = mlir::cast<cir::ComplexType>(operand.getType()); - return cir::ComplexImagOp::create(*this, loc, operandTy.getElementType(), - operand); + auto resultType = operand.getType(); + if (auto complexResultType = mlir::dyn_cast<cir::ComplexType>(resultType)) + resultType = complexResultType.getElementType(); + return cir::ComplexImagOp::create(*this, loc, resultType, operand); } cir::LoadOp createLoad(mlir::Location loc, mlir::Value ptr, diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 7f2e55d..c81f64d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3308,18 +3308,20 @@ def CIR_ComplexRealOp : CIR_Op<"complex.real", [Pure]> { def CIR_ComplexImagOp : CIR_Op<"complex.imag", [Pure]> { let summary = "Extract the imaginary part of a complex value"; let description = [{ - `cir.complex.imag` operation takes an operand of `!cir.complex` type and - yields the imaginary part of it. + `cir.complex.imag` operation takes an operand of `!cir.complex`, `!cir.int` + or `!cir.float`. If the operand is `!cir.complex`, the imag part of it will + be returned, otherwise a zero value will be returned. Example: ```mlir - %1 = cir.complex.imag %0 : !cir.complex<!cir.float> -> !cir.float + %imag = cir.complex.imag %complex : !cir.complex<!cir.float> -> !cir.float + %imag = cir.complex.imag %scalar : !cir.float -> !cir.float ``` }]; let results = (outs CIR_AnyIntOrFloatType:$result); - let arguments = (ins CIR_ComplexType:$operand); + let arguments = (ins CIR_AnyComplexOrIntOrFloatType:$operand); let assemblyFormat = [{ $operand `:` qualified(type($operand)) `->` qualified(type($result)) diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp index e943b02..0f4d6d2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp @@ -718,10 +718,26 @@ void CIRGenFunction::emitAtomicInit(Expr *init, LValue dest) { return; } - case cir::TEK_Aggregate: - cgm.errorNYI(init->getSourceRange(), "emitAtomicInit: aggregate type"); + case cir::TEK_Aggregate: { + // Fix up the destination if the initializer isn't an expression + // of atomic type. + bool zeroed = false; + if (!init->getType()->isAtomicType()) { + zeroed = atomics.emitMemSetZeroIfNecessary(); + dest = atomics.projectValue(); + } + + // Evaluate the expression directly into the destination. + assert(!cir::MissingFeatures::aggValueSlotGC()); + AggValueSlot slot = AggValueSlot::forLValue( + dest, AggValueSlot::IsNotDestructed, AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap, + zeroed ? AggValueSlot::IsZeroed : AggValueSlot::IsNotZeroed); + + emitAggExpr(init, slot); return; } + } llvm_unreachable("bad evaluation kind"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 2970b36..61072f0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -522,7 +522,8 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, assert(!cir::MissingFeatures::opCallPaddingArgs()); mlir::Type argType = convertType(canQualArgType); - if (!mlir::isa<cir::RecordType>(argType)) { + if (!mlir::isa<cir::RecordType>(argType) && + !mlir::isa<cir::ComplexType>(argType)) { mlir::Value v; if (arg.isAggregate()) cgm.errorNYI(loc, "emitCall: aggregate call argument"); @@ -540,15 +541,16 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, cirCallArgs[argNo] = v; } else { Address src = Address::invalid(); - if (!arg.isAggregate()) - cgm.errorNYI(loc, "emitCall: non-aggregate call argument"); - else + if (!arg.isAggregate()) { + src = createMemTemp(arg.ty, loc, "coerce"); + arg.copyInto(*this, src, loc); + } else { src = arg.hasLValue() ? arg.getKnownLValue().getAddress() : arg.getKnownRValue().getAggregateAddress(); + } // Fast-isel and the optimizer generally like scalar values better than // FCAs, so we flatten them if this is safe to do for this argument. - auto argRecordTy = cast<cir::RecordType>(argType); mlir::Type srcTy = src.getElementType(); // FIXME(cir): get proper location for each argument. mlir::Location argLoc = loc; @@ -564,7 +566,7 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, // uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy); // if (SrcSize < DstSize) { assert(!cir::MissingFeatures::dataLayoutTypeAllocSize()); - if (srcTy != argRecordTy) { + if (srcTy != argType) { cgm.errorNYI(loc, "emitCall: source type does not match argument type"); } else { // FIXME(cir): this currently only runs when the types are exactly the @@ -676,6 +678,18 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo, llvm_unreachable("Invalid evaluation kind"); } +void CallArg::copyInto(CIRGenFunction &cgf, Address addr, + mlir::Location loc) const { + LValue dst = cgf.makeAddrLValue(addr, ty); + if (!hasLV && rv.isScalar()) + cgf.cgm.errorNYI(loc, "copyInto scalar value"); + else if (!hasLV && rv.isComplex()) + cgf.emitStoreOfComplex(loc, rv.getComplexValue(), dst, /*isInit=*/true); + else + cgf.cgm.errorNYI(loc, "copyInto hasLV"); + isUsed = true; +} + void CIRGenFunction::emitCallArg(CallArgList &args, const clang::Expr *e, clang::QualType argType) { assert(argType->isReferenceType() == e->isGLValue() && diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.h b/clang/lib/CIR/CodeGen/CIRGenCall.h index 52d541f..55b3d97 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.h +++ b/clang/lib/CIR/CodeGen/CIRGenCall.h @@ -224,6 +224,8 @@ public: } bool isAggregate() const { return hasLV || rv.isAggregate(); } + + void copyInto(CIRGenFunction &cgf, Address addr, mlir::Location loc) const; }; class CallArgList : public llvm::SmallVector<CallArg, 8> { diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 1e987f3..e51c3fc 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -144,10 +144,7 @@ public: void VisitUnaryCoawait(UnaryOperator *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitUnaryCoawait"); } - void VisitUnaryExtension(UnaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitUnaryExtension"); - } + void VisitUnaryExtension(UnaryOperator *e) { Visit(e->getSubExpr()); } void VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr"); @@ -184,7 +181,8 @@ public: cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinAssign"); } void VisitBinComma(const BinaryOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinComma"); + cgf.emitIgnoredExpr(e->getLHS()); + Visit(e->getRHS()); } void VisitBinCmp(const BinaryOperator *e) { cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitBinCmp"); @@ -212,9 +210,11 @@ public: } void VisitChooseExpr(const ChooseExpr *e) { Visit(e->getChosenSubExpr()); } void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitCXXParenListInitExpr"); + visitCXXParenListOrInitListExpr(e, e->getInitExprs(), + e->getInitializedFieldInUnion(), + e->getArrayFiller()); } + void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *e, llvm::Value *outerBegin = nullptr) { cgf.cgm.errorNYI(e->getSourceRange(), diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 500007f..768d75d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -2159,16 +2159,16 @@ mlir::Value ScalarExprEmitter::VisitRealImag(const UnaryOperator *e, // __imag on a scalar returns zero. Emit the subexpr to ensure side // effects are evaluated, but not the actual value. - if (op->isGLValue()) - cgf.emitLValue(op); - else if (!promotionTy.isNull()) - cgf.emitPromotedScalarExpr(op, promotionTy); - else - cgf.emitScalarExpr(op); - - mlir::Type valueTy = - cgf.convertType(promotionTy.isNull() ? e->getType() : promotionTy); - return builder.getNullValue(valueTy, loc); + mlir::Value operand; + if (op->isGLValue()) { + operand = cgf.emitLValue(op).getPointer(); + operand = cir::LoadOp::create(builder, loc, operand); + } else if (!promotionTy.isNull()) { + operand = cgf.emitPromotedScalarExpr(op, promotionTy); + } else { + operand = cgf.emitScalarExpr(op); + } + return builder.createComplexImag(loc, operand); } /// Return the size or alignment of the type of argument of the sizeof diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index fba094f..cdd4e3c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2402,9 +2402,8 @@ OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) { LogicalResult cir::ComplexRealOp::verify() { mlir::Type operandTy = getOperand().getType(); - if (auto complexOperandTy = mlir::dyn_cast<cir::ComplexType>(operandTy)) { + if (auto complexOperandTy = mlir::dyn_cast<cir::ComplexType>(operandTy)) operandTy = complexOperandTy.getElementType(); - } if (getType() != operandTy) { emitOpError() << ": result type does not match operand type"; @@ -2431,14 +2430,22 @@ OpFoldResult cir::ComplexRealOp::fold(FoldAdaptor adaptor) { //===----------------------------------------------------------------------===// LogicalResult cir::ComplexImagOp::verify() { - if (getType() != getOperand().getType().getElementType()) { + mlir::Type operandTy = getOperand().getType(); + if (auto complexOperandTy = mlir::dyn_cast<cir::ComplexType>(operandTy)) + operandTy = complexOperandTy.getElementType(); + + if (getType() != operandTy) { emitOpError() << ": result type does not match operand type"; return failure(); } + return success(); } OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) { + if (!mlir::isa<cir::ComplexType>(getOperand().getType())) + return nullptr; + if (auto complexCreateOp = getOperand().getDefiningOp<cir::ComplexCreateOp>()) return complexCreateOp.getOperand(1); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index bfb1262..1ff8cc5 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -3061,8 +3061,19 @@ mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite( cir::ComplexImagOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType()); - rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>( - op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{1}); + mlir::Value operand = adaptor.getOperand(); + mlir::Location loc = op.getLoc(); + + if (mlir::isa<cir::ComplexType>(op.getOperand().getType())) { + operand = mlir::LLVM::ExtractValueOp::create( + rewriter, loc, resultLLVMTy, operand, llvm::ArrayRef<std::int64_t>{1}); + } else { + mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(resultLLVMTy); + operand = + mlir::LLVM::ConstantOp::create(rewriter, loc, resultLLVMTy, zeroAttr); + } + + rewriter.replaceOp(op, operand); return mlir::success(); } diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index ae69b24..3524b8b 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -1160,8 +1160,9 @@ void imag_on_scalar_glvalue() { // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] -// CIR: %[[CONST_ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float -// CIR: cir.store{{.*}} %[[CONST_ZERO]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// CIR: %[[TMP_A:.*]] = cir.load %[[A_ADDR]] : !cir.ptr<!cir.float>, !cir.float +// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.float -> !cir.float +// CIR: cir.store{{.*}} %[[A_IMAG]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> // LLVM: %[[A_ADDR:.*]] = alloca float, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 @@ -1205,9 +1206,10 @@ void imag_on_scalar_with_type_promotion() { // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.f16, !cir.ptr<!cir.f16>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.f16, !cir.ptr<!cir.f16>, ["b", init] -// CIR: %[[CONST_ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float -// CIR: %[[CONST_ZERO_F16:.*]] = cir.cast floating %[[CONST_ZERO]] : !cir.float -> !cir.f16 -// CIR: cir.store{{.*}} %[[CONST_ZERO_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr<!cir.f16> +// CIR: %[[TMP_A:.*]] = cir.load %[[A_ADDR]] : !cir.ptr<!cir.f16>, !cir.f16 +// CIR: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.f16 -> !cir.f16 +// CIR: %[[A_IMAG_F16:.*]] = cir.cast floating %[[A_IMAG]] : !cir.f16 -> !cir.f16 +// CIR: cir.store{{.*}} %[[A_IMAG_F16]], %[[B_ADDR]] : !cir.f16, !cir.ptr<!cir.f16> // LLVM: %[[A_ADDR:.*]] = alloca half, i64 1, align 2 // LLVM: %[[B_ADDR:.*]] = alloca half, i64 1, align 2 @@ -1225,8 +1227,8 @@ void imag_on_const_scalar() { // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["a"] // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["b", init] // CIR: %[[CONST_ONE:.*]] = cir.const #cir.fp<1.000000e+00> : !cir.float -// CIR: %[[CONST_ZERO:.*]] = cir.const #cir.fp<0.000000e+00> : !cir.float -// CIR: cir.store{{.*}} %[[CONST_ZERO]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> +// CIR: %[[CONST_IMAG:.*]] = cir.complex.imag %[[CONST_ONE]] : !cir.float -> !cir.float +// CIR: cir.store{{.*}} %[[CONST_IMAG]], %[[B_ADDR]] : !cir.float, !cir.ptr<!cir.float> // LLVM: %[[A_ADDR:.*]] = alloca float, i64 1, align 4 // LLVM: %[[B_ADDR:.*]] = alloca float, i64 1, align 4 @@ -1311,3 +1313,49 @@ void real_on_scalar_from_imag_with_type_promotion() { // OGCG: %[[A_IMAG_F32:.*]] = fpext half %[[A_IMAG]] to float // OGCG: %[[A_IMAG_F16:.*]] = fptrunc float %[[A_IMAG_F32]] to half // OGCG: store half %[[A_IMAG_F16]], ptr %[[B_ADDR]], align 2 + +void complex_type_parameter(float _Complex a) {} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a", init] +// CIR: cir.store %{{.*}}, %[[A_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// TODO(CIR): the difference between the CIR LLVM and OGCG is because the lack of calling convention lowering, +// Test will be updated when that is implemented + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: store { float, float } %{{.*}}, ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: store <2 x float> %a.coerce, ptr %[[A_ADDR]], align 4 + +void complex_type_argument() { + float _Complex a; + complex_type_parameter(a); +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR: %[[ARG_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["coerce"] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: cir.store{{.*}} %[[TMP_A]], %[[ARG_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> +// CIR: %[[TMP_ARG:.*]] = cir.load{{.*}} %[[ARG_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR: cir.call @_Z22complex_type_parameterCf(%[[TMP_ARG]]) : (!cir.complex<!cir.float>) -> () + +// LLVM: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[ARG_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM: store { float, float } %[[TMP_A]], ptr %[[ARG_ADDR]], align 4 +// LLVM: %[[TMP_ARG:.*]] = load { float, float }, ptr %[[ARG_ADDR]], align 4 +// LLVM: call void @_Z22complex_type_parameterCf({ float, float } %[[TMP_ARG]]) + +// OGCG: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[ARG_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[ARG_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ARG_ADDR]], i32 0, i32 0 +// OGCG: %[[ARG_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[ARG_ADDR]], i32 0, i32 1 +// OGCG: store float %[[A_REAL]], ptr %[[ARG_REAL_PTR]], align 4 +// OGCG: store float %[[A_IMAG]], ptr %[[ARG_IMAG_PTR]], align 4 +// OGCG: %[[TMP_ARG:.*]] = load <2 x float>, ptr %[[ARG_ADDR]], align 4 +// OGCG: call void @_Z22complex_type_parameterCf(<2 x float> noundef %[[TMP_ARG]]) diff --git a/clang/test/CIR/CodeGen/paren-init-list.cpp b/clang/test/CIR/CodeGen/paren-init-list.cpp new file mode 100644 index 0000000..0efa363 --- /dev/null +++ b/clang/test/CIR/CodeGen/paren-init-list.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct CompleteS { + int a; + char b; +}; + +void cxx_paren_list_init_expr() { CompleteS a(1, 'a'); } + +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] +// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> +// CIR: %[[ELEM_0_VAL:.*]] = cir.const #cir.int<1> : !s32i +// CIR: cir.store{{.*}} %[[ELEM_0_VAL]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ELEM_1_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i> +// CIR: %[[ELEM_1_VAL:.*]] = cir.const #cir.int<97> : !s8i +// CIR: cir.store{{.*}} %[[ELEM_1_VAL]], %[[ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i> + +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0 +// LLVM: store i32 1, ptr %[[ELEM_0_PTR]], align 4 +// LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1 +// LLVM: store i8 97, ptr %[[ELEM_1_PTR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[A_ADDR]], ptr align 4 @__const._Z24cxx_paren_list_init_exprv.a, i64 8, i1 false) diff --git a/clang/test/CIR/CodeGen/struct.cpp b/clang/test/CIR/CodeGen/struct.cpp index 96db82a..c68f742 100644 --- a/clang/test/CIR/CodeGen/struct.cpp +++ b/clang/test/CIR/CodeGen/struct.cpp @@ -183,3 +183,67 @@ void generic_selection() { // OGCG: %[[C_ADDR:.*]] = alloca i32, align 4 // OGCG: %[[D_ADDR:.*]] = alloca %struct.CompleteS, align 4 // OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[D_ADDR]], ptr align 4 %[[A_ADDR]], i64 8, i1 false) + +void atomic_init() { + _Atomic CompleteS a; + __c11_atomic_init(&a, {}); +} + +// CIR: cir.func{{.*}} @_Z11atomic_initv() +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a"] +// CIR: %[[ELEM_0_PTR:.*]] = cir.get_member %[[A_ADDR]][0] {name = "a"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s32i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s32i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr<!s32i> +// CIR: %[[ELEM_1_PTR:.*]] = cir.get_member %[[A_ADDR]][1] {name = "b"} : !cir.ptr<!rec_CompleteS> -> !cir.ptr<!s8i> +// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s8i +// CIR: cir.store{{.*}} %[[CONST_0]], %[[ELEM_1_PTR]] : !s8i, !cir.ptr<!s8i> + +// LLVM: define{{.*}} void @_Z11atomic_initv() +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 8 +// LLVM: %[[ELEM_0_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0 +// LLVM: store i32 0, ptr %[[ELEM_0_PTR]], align 8 +// LLVM: %[[ELEM_1_PTR:.*]] = getelementptr %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1 +// LLVM: store i8 0, ptr %[[ELEM_1_PTR]], align 4 + +// OGCG: define{{.*}} void @_Z11atomic_initv() +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 8 +// OGCG: %[[ELEM_0_PTR:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG: store i32 0, ptr %[[ELEM_0_PTR]], align 8 +// OGCG: %[[ELEM_1_PTR:.*]] = getelementptr inbounds nuw %struct.CompleteS, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG: store i8 0, ptr %[[ELEM_1_PTR]], align 4 + +void unary_extension() { + CompleteS a = __extension__ CompleteS(); +} + +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] +// CIR: %[[ZERO_INIT:.*]] = cir.const #cir.zero : !rec_CompleteS +// CIR: cir.store{{.*}} %[[ZERO_INIT]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> + +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4 + +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false) + +void bin_comma() { + CompleteS a = (CompleteS(), CompleteS()); +} + +// CIR: cir.func{{.*}} @_Z9bin_commav() +// CIR: %[[A_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["a", init] +// CIR: %[[TMP_ADDR:.*]] = cir.alloca !rec_CompleteS, !cir.ptr<!rec_CompleteS>, ["agg.tmp0"] +// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !rec_CompleteS +// CIR: cir.store{{.*}} %[[ZERO]], %[[TMP_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> +// CIR: %[[ZERO:.*]] = cir.const #cir.zero : !rec_CompleteS +// CIR: cir.store{{.*}} %[[ZERO]], %[[A_ADDR]] : !rec_CompleteS, !cir.ptr<!rec_CompleteS> + +// LLVM: define{{.*}} void @_Z9bin_commav() +// LLVM: %[[A_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: %[[TMP_ADDR:.*]] = alloca %struct.CompleteS, i64 1, align 4 +// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[TMP_ADDR]], align 4 +// LLVM: store %struct.CompleteS zeroinitializer, ptr %[[A_ADDR]], align 4 + +// OGCG: define{{.*}} void @_Z9bin_commav() +// OGCG: %[[A_ADDR:.*]] = alloca %struct.CompleteS, align 4 +// OGCG: call void @llvm.memset.p0.i64(ptr align 4 %[[A_ADDR]], i8 0, i64 8, i1 false) diff --git a/flang/lib/Evaluate/check-expression.cpp b/flang/lib/Evaluate/check-expression.cpp index 8931cbe..647eebaaa0 100644 --- a/flang/lib/Evaluate/check-expression.cpp +++ b/flang/lib/Evaluate/check-expression.cpp @@ -135,16 +135,22 @@ bool IsConstantExprHelper<INVARIANT>::operator()( } else if (proc.IsPure()) { std::size_t j{0}; for (const auto &arg : call.arguments()) { - if (const auto *dataDummy{j < proc.dummyArguments.size() - ? std::get_if<characteristics::DummyDataObject>( - &proc.dummyArguments[j].u) - : nullptr}; - dataDummy && + const auto *dataDummy{j < proc.dummyArguments.size() + ? std::get_if<characteristics::DummyDataObject>( + &proc.dummyArguments[j].u) + : nullptr}; + if (dataDummy && dataDummy->attrs.test( characteristics::DummyDataObject::Attr::OnlyIntrinsicInquiry)) { // The value of the argument doesn't matter } else if (!arg) { - return false; + if (dataDummy && + dataDummy->attrs.test( + characteristics::DummyDataObject::Attr::Optional)) { + // Missing optional arguments are okay. + } else { + return false; + } } else if (const auto *expr{arg->UnwrapExpr()}; !expr || !(*this)(*expr)) { return false; diff --git a/flang/test/Semantics/intrinsics03.f90 b/flang/test/Semantics/intrinsics03.f90 index a5b13b6..1a42698 100644 --- a/flang/test/Semantics/intrinsics03.f90 +++ b/flang/test/Semantics/intrinsics03.f90 @@ -129,6 +129,6 @@ subroutine ichar_tests() !Without -Wportability, the warning isn't emitted and the parameter is constant. integer, parameter :: a2 = ichar('B ') !ERROR: Character in intrinsic function ichar must have length one - !ERROR: Must be a constant value + !ERROR: Value of named constant 'a3' (ichar("")) cannot be computed as a constant value integer, parameter :: a3 = ichar('') end subroutine diff --git a/flang/test/Semantics/intrinsics04.f90 b/flang/test/Semantics/intrinsics04.f90 index abb8fe3..e733067 100644 --- a/flang/test/Semantics/intrinsics04.f90 +++ b/flang/test/Semantics/intrinsics04.f90 @@ -29,6 +29,6 @@ subroutine ichar_tests() !WARNING: Character in intrinsic function ichar should have length one [-Wportability] integer, parameter :: a2 = ichar('B ') !ERROR: Character in intrinsic function ichar must have length one - !ERROR: Must be a constant value + !ERROR: Value of named constant 'a3' (ichar("")) cannot be computed as a constant value integer, parameter :: a3 = ichar('') end subroutine diff --git a/flang/test/Semantics/type-parameter-constant.f90 b/flang/test/Semantics/type-parameter-constant.f90 new file mode 100644 index 0000000..376bffd --- /dev/null +++ b/flang/test/Semantics/type-parameter-constant.f90 @@ -0,0 +1,15 @@ +! RUN: %python %S/test_errors.py %s %flang_fc1 +type A (p, r) + integer, kind :: p, r + !ERROR: KIND parameter expression (int(selected_real_kind(six,twenty_three),kind=8)) of intrinsic type REAL did not resolve to a constant value + real (selected_real_kind(p, r)) :: data +end type + integer :: six = 6, twenty_three = 23 + type(a(6,23)) :: a1 + !ERROR: Value of KIND type parameter 'p' must be constant + !ERROR: Value of KIND type parameter 'r' must be constant + !WARNING: specification expression refers to local object 'six' (initialized and saved) [-Wsaved-local-in-spec-expr] + !WARNING: specification expression refers to local object 'twenty_three' (initialized and saved) [-Wsaved-local-in-spec-expr] + type(a(six, twenty_three)) :: a2 + print *, a1%data%kind +end
\ No newline at end of file diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h index ad6b27f..5dbdfb13 100644 --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -17,9 +17,11 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" #include "llvm/Support/SwapByteOrder.h" -#include "llvm/TargetParser/Triple.h" namespace llvm { + +class Triple; + namespace MachO { // Enums from <mach-o/loader.h> enum : uint32_t { @@ -1708,11 +1710,6 @@ LLVM_ABI Expected<uint32_t> getCPUSubType(const Triple &T, unsigned PtrAuthABIVersion, bool PtrAuthKernelABIVersion); -LLVM_ABI Triple::ArchType getArch(uint32_t CPUType, uint32_t CPUSubType); -LLVM_ABI Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault = nullptr, - const char **ArchFlag = nullptr); - struct x86_thread_state32_t { uint32_t eax; uint32_t ebx; diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 0dfe980..3f4a21d 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -752,14 +752,10 @@ public: static StringRef guessLibraryShortName(StringRef Name, bool &isFramework, StringRef &Suffix); - static Triple::ArchType getArch(uint32_t CPUType, uint32_t CPUSubType) { - return MachO::getArch(CPUType, CPUSubType); - } + static Triple::ArchType getArch(uint32_t CPUType, uint32_t CPUSubType); static Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType, const char **McpuDefault = nullptr, - const char **ArchFlag = nullptr) { - return MachO::getArchTriple(CPUType, CPUSubType, McpuDefault, ArchFlag); - } + const char **ArchFlag = nullptr); static bool isValidArch(StringRef ArchFlag); static ArrayRef<StringRef> getValidArchs(); static Triple getHostArch(); diff --git a/llvm/include/llvm/TableGen/CodeGenHelpers.h b/llvm/include/llvm/TableGen/CodeGenHelpers.h new file mode 100644 index 0000000..7dca6a0 --- /dev/null +++ b/llvm/include/llvm/TableGen/CodeGenHelpers.h @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 defines common utilities for generating C++ code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TABLEGEN_CODEGENHELPERS_H +#define LLVM_TABLEGEN_CODEGENHELPERS_H + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace llvm { +// Simple RAII helper for emitting ifdef-undef-endif scope. +class IfDefEmitter { +public: + IfDefEmitter(raw_ostream &OS, StringRef Name) : Name(Name.str()), OS(OS) { + OS << "#ifdef " << Name << "\n" + << "#undef " << Name << "\n\n"; + } + ~IfDefEmitter() { OS << "\n#endif // " << Name << "\n\n"; } + +private: + std::string Name; + raw_ostream &OS; +}; + +// Simple RAII helper for emitting namespace scope. Name can be a single +// namespace (empty for anonymous namespace) or nested namespace. +class NamespaceEmitter { +public: + NamespaceEmitter(raw_ostream &OS, StringRef Name) : OS(OS) { + emitNamespaceStarts(Name); + } + + ~NamespaceEmitter() { close(); } + + // Explicit function to close the namespace scopes. + void close() { + for (StringRef NS : llvm::reverse(Namespaces)) + OS << "} // namespace " << NS << "\n"; + Namespaces.clear(); + } + +private: + void emitNamespaceStarts(StringRef Name) { + llvm::SplitString(Name, Namespaces, "::"); + for (StringRef NS : Namespaces) + OS << "namespace " << NS << " {\n"; + } + + SmallVector<StringRef, 2> Namespaces; + raw_ostream &OS; +}; + +} // end namespace llvm + +#endif // LLVM_TABLEGEN_CODEGENHELPERS_H diff --git a/llvm/lib/BinaryFormat/MachO.cpp b/llvm/lib/BinaryFormat/MachO.cpp index b2af243..f46b9d5 100644 --- a/llvm/lib/BinaryFormat/MachO.cpp +++ b/llvm/lib/BinaryFormat/MachO.cpp @@ -123,160 +123,3 @@ Expected<uint32_t> MachO::getCPUSubType(const Triple &T, return CPU_SUBTYPE_ARM64E_WITH_PTRAUTH_VERSION(PtrAuthABIVersion, PtrAuthKernelABIVersion); } - -Triple::ArchType MachO::getArch(uint32_t CPUType, uint32_t CPUSubType) { - switch (CPUType) { - case MachO::CPU_TYPE_I386: - return Triple::x86; - case MachO::CPU_TYPE_X86_64: - return Triple::x86_64; - case MachO::CPU_TYPE_ARM: - return Triple::arm; - case MachO::CPU_TYPE_ARM64: - return Triple::aarch64; - case MachO::CPU_TYPE_ARM64_32: - return Triple::aarch64_32; - case MachO::CPU_TYPE_POWERPC: - return Triple::ppc; - case MachO::CPU_TYPE_POWERPC64: - return Triple::ppc64; - default: - return Triple::UnknownArch; - } -} - -Triple MachO::getArchTriple(uint32_t CPUType, uint32_t CPUSubType, - const char **McpuDefault, const char **ArchFlag) { - if (McpuDefault) - *McpuDefault = nullptr; - if (ArchFlag) - *ArchFlag = nullptr; - - switch (CPUType) { - case MachO::CPU_TYPE_I386: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_I386_ALL: - if (ArchFlag) - *ArchFlag = "i386"; - return Triple("i386-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_X86_64: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_X86_64_ALL: - if (ArchFlag) - *ArchFlag = "x86_64"; - return Triple("x86_64-apple-darwin"); - case MachO::CPU_SUBTYPE_X86_64_H: - if (ArchFlag) - *ArchFlag = "x86_64h"; - return Triple("x86_64h-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_ARM: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_ARM_V4T: - if (ArchFlag) - *ArchFlag = "armv4t"; - return Triple("armv4t-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V5TEJ: - if (ArchFlag) - *ArchFlag = "armv5e"; - return Triple("armv5e-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_XSCALE: - if (ArchFlag) - *ArchFlag = "xscale"; - return Triple("xscale-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V6: - if (ArchFlag) - *ArchFlag = "armv6"; - return Triple("armv6-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V6M: - if (McpuDefault) - *McpuDefault = "cortex-m0"; - if (ArchFlag) - *ArchFlag = "armv6m"; - return Triple("armv6m-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V7: - if (ArchFlag) - *ArchFlag = "armv7"; - return Triple("armv7-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V7EM: - if (McpuDefault) - *McpuDefault = "cortex-m4"; - if (ArchFlag) - *ArchFlag = "armv7em"; - return Triple("thumbv7em-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V7K: - if (McpuDefault) - *McpuDefault = "cortex-a7"; - if (ArchFlag) - *ArchFlag = "armv7k"; - return Triple("armv7k-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V7M: - if (McpuDefault) - *McpuDefault = "cortex-m3"; - if (ArchFlag) - *ArchFlag = "armv7m"; - return Triple("thumbv7m-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM_V7S: - if (McpuDefault) - *McpuDefault = "cortex-a7"; - if (ArchFlag) - *ArchFlag = "armv7s"; - return Triple("armv7s-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_ARM64: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_ARM64_ALL: - if (McpuDefault) - *McpuDefault = "cyclone"; - if (ArchFlag) - *ArchFlag = "arm64"; - return Triple("arm64-apple-darwin"); - case MachO::CPU_SUBTYPE_ARM64E: - if (McpuDefault) - *McpuDefault = "apple-a12"; - if (ArchFlag) - *ArchFlag = "arm64e"; - return Triple("arm64e-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_ARM64_32: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_ARM64_32_V8: - if (McpuDefault) - *McpuDefault = "cyclone"; - if (ArchFlag) - *ArchFlag = "arm64_32"; - return Triple("arm64_32-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_POWERPC: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_POWERPC_ALL: - if (ArchFlag) - *ArchFlag = "ppc"; - return Triple("ppc-apple-darwin"); - default: - return Triple(); - } - case MachO::CPU_TYPE_POWERPC64: - switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { - case MachO::CPU_SUBTYPE_POWERPC_ALL: - if (ArchFlag) - *ArchFlag = "ppc64"; - return Triple("ppc64-apple-darwin"); - default: - return Triple(); - } - default: - return Triple(); - } -} diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index abadb04..e09dc94 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -2685,6 +2685,164 @@ StringRef MachOObjectFile::getFileFormatName() const { } } +Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { + switch (CPUType) { + case MachO::CPU_TYPE_I386: + return Triple::x86; + case MachO::CPU_TYPE_X86_64: + return Triple::x86_64; + case MachO::CPU_TYPE_ARM: + return Triple::arm; + case MachO::CPU_TYPE_ARM64: + return Triple::aarch64; + case MachO::CPU_TYPE_ARM64_32: + return Triple::aarch64_32; + case MachO::CPU_TYPE_POWERPC: + return Triple::ppc; + case MachO::CPU_TYPE_POWERPC64: + return Triple::ppc64; + default: + return Triple::UnknownArch; + } +} + +Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault, + const char **ArchFlag) { + if (McpuDefault) + *McpuDefault = nullptr; + if (ArchFlag) + *ArchFlag = nullptr; + + switch (CPUType) { + case MachO::CPU_TYPE_I386: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_I386_ALL: + if (ArchFlag) + *ArchFlag = "i386"; + return Triple("i386-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_X86_64: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_X86_64_ALL: + if (ArchFlag) + *ArchFlag = "x86_64"; + return Triple("x86_64-apple-darwin"); + case MachO::CPU_SUBTYPE_X86_64_H: + if (ArchFlag) + *ArchFlag = "x86_64h"; + return Triple("x86_64h-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_ARM: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM_V4T: + if (ArchFlag) + *ArchFlag = "armv4t"; + return Triple("armv4t-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V5TEJ: + if (ArchFlag) + *ArchFlag = "armv5e"; + return Triple("armv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + if (ArchFlag) + *ArchFlag = "xscale"; + return Triple("xscale-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6: + if (ArchFlag) + *ArchFlag = "armv6"; + return Triple("armv6-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; + if (ArchFlag) + *ArchFlag = "armv6m"; + return Triple("armv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + if (ArchFlag) + *ArchFlag = "armv7"; + return Triple("armv7-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; + if (ArchFlag) + *ArchFlag = "armv7em"; + return Triple("thumbv7em-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7K: + if (McpuDefault) + *McpuDefault = "cortex-a7"; + if (ArchFlag) + *ArchFlag = "armv7k"; + return Triple("armv7k-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; + if (ArchFlag) + *ArchFlag = "armv7m"; + return Triple("thumbv7m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7S: + if (McpuDefault) + *McpuDefault = "cortex-a7"; + if (ArchFlag) + *ArchFlag = "armv7s"; + return Triple("armv7s-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_ARM64: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM64_ALL: + if (McpuDefault) + *McpuDefault = "cyclone"; + if (ArchFlag) + *ArchFlag = "arm64"; + return Triple("arm64-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM64E: + if (McpuDefault) + *McpuDefault = "apple-a12"; + if (ArchFlag) + *ArchFlag = "arm64e"; + return Triple("arm64e-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_ARM64_32: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM64_32_V8: + if (McpuDefault) + *McpuDefault = "cyclone"; + if (ArchFlag) + *ArchFlag = "arm64_32"; + return Triple("arm64_32-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_POWERPC: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_POWERPC_ALL: + if (ArchFlag) + *ArchFlag = "ppc"; + return Triple("ppc-apple-darwin"); + default: + return Triple(); + } + case MachO::CPU_TYPE_POWERPC64: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_POWERPC_ALL: + if (ArchFlag) + *ArchFlag = "ppc64"; + return Triple("ppc64-apple-darwin"); + default: + return Triple(); + } + default: + return Triple(); + } +} + Triple MachOObjectFile::getHostArch() { return Triple(sys::getDefaultTargetTriple()); } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp index 9dd64e0..cb49936 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUAttributor.cpp @@ -1224,12 +1224,9 @@ static bool inlineAsmUsesAGPRs(const InlineAsm *IA) { } // TODO: Migrate to range merge of amdgpu-agpr-alloc. -// FIXME: Why is this using Attribute::NoUnwind? -struct AAAMDGPUNoAGPR - : public IRAttribute<Attribute::NoUnwind, - StateWrapper<BooleanState, AbstractAttribute>, - AAAMDGPUNoAGPR> { - AAAMDGPUNoAGPR(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {} +struct AAAMDGPUNoAGPR : public StateWrapper<BooleanState, AbstractAttribute> { + using Base = StateWrapper<BooleanState, AbstractAttribute>; + AAAMDGPUNoAGPR(const IRPosition &IRP, Attributor &A) : Base(IRP) {} static AAAMDGPUNoAGPR &createForPosition(const IRPosition &IRP, Attributor &A) { diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp index cba282c..a2e8c69 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp @@ -15,13 +15,12 @@ using namespace llvm; -namespace { /// Return true if and only if the given instruction does not modify the memory /// location referenced. Note that an idemptent atomicrmw may still have /// ordering effects on nearby instructions, or be volatile. /// TODO: Common w/ the version in AtomicExpandPass, and change the term used. /// Idemptotent is confusing in this context. -bool isIdempotentRMW(AtomicRMWInst& RMWI) { +static bool isIdempotentRMW(AtomicRMWInst &RMWI) { if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand())) switch(RMWI.getOperation()) { case AtomicRMWInst::FAdd: // -0.0 @@ -59,7 +58,7 @@ bool isIdempotentRMW(AtomicRMWInst& RMWI) { /// Return true if the given instruction always produces a value in memory /// equivalent to its value operand. -bool isSaturating(AtomicRMWInst& RMWI) { +static bool isSaturating(AtomicRMWInst &RMWI) { if (auto CF = dyn_cast<ConstantFP>(RMWI.getValOperand())) switch (RMWI.getOperation()) { case AtomicRMWInst::FMax: @@ -98,7 +97,6 @@ bool isSaturating(AtomicRMWInst& RMWI) { return C->isMaxValue(false); }; } -} // namespace Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) { diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 917004c..048cdf4 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -132,8 +132,6 @@ STATISTIC(NumReassoc , "Number of reassociations"); DEBUG_COUNTER(VisitCounter, "instcombine-visit", "Controls which instructions are visited"); -namespace llvm { - static cl::opt<bool> EnableCodeSinking("instcombine-code-sinking", cl::desc("Enable code sinking"), cl::init(true)); @@ -146,7 +144,9 @@ static cl::opt<unsigned> MaxArraySize("instcombine-maxarray-size", cl::init(1024), cl::desc("Maximum array size considered when doing a combine")); +namespace llvm { extern cl::opt<bool> ProfcheckDisableMetadataFixes; +} // end namespace llvm // FIXME: Remove this flag when it is no longer necessary to convert // llvm.dbg.declare to avoid inaccurate debug info. Setting this to false @@ -158,8 +158,6 @@ extern cl::opt<bool> ProfcheckDisableMetadataFixes; static cl::opt<unsigned> ShouldLowerDbgDeclare("instcombine-lower-dbg-declare", cl::Hidden, cl::init(true)); -} // end namespace llvm - std::optional<Instruction *> InstCombiner::targetInstCombineIntrinsic(IntrinsicInst &II) { // Handle target specific intrinsics diff --git a/llvm/test/CodeGen/ARM/llround-conv.ll b/llvm/test/CodeGen/ARM/llround-conv.ll index 0f57e4a..f734db8 100644 --- a/llvm/test/CodeGen/ARM/llround-conv.ll +++ b/llvm/test/CodeGen/ARM/llround-conv.ll @@ -1,25 +1,71 @@ -; RUN: llc < %s -mtriple=arm-eabi -float-abi=soft | FileCheck %s --check-prefix=SOFTFP -; RUN: llc < %s -mtriple=arm-eabi -float-abi=hard | FileCheck %s --check-prefix=HARDFP +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -mtriple=armv7-none-eabi -float-abi=soft | FileCheck %s --check-prefixes=CHECK,CHECK-SOFT +; RUN: llc < %s -mtriple=armv7-none-eabihf -mattr=+vfp2 -float-abi=hard | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP16 +; RUN: llc < %s -mtriple=armv8-none-eabihf -mattr=+fp-armv8,+fullfp16 -float-abi=hard | FileCheck %s --check-prefixes=CHECK,CHECK-FP16 + +define i64 @testmsxh_builtin(half %x) { +; CHECK-SOFT-LABEL: testmsxh_builtin: +; CHECK-SOFT: @ %bb.0: @ %entry +; CHECK-SOFT-NEXT: .save {r11, lr} +; CHECK-SOFT-NEXT: push {r11, lr} +; CHECK-SOFT-NEXT: bl __aeabi_h2f +; CHECK-SOFT-NEXT: bl llroundf +; CHECK-SOFT-NEXT: pop {r11, pc} +; +; CHECK-NOFP16-LABEL: testmsxh_builtin: +; CHECK-NOFP16: @ %bb.0: @ %entry +; CHECK-NOFP16-NEXT: .save {r11, lr} +; CHECK-NOFP16-NEXT: push {r11, lr} +; CHECK-NOFP16-NEXT: vmov r0, s0 +; CHECK-NOFP16-NEXT: bl __aeabi_h2f +; CHECK-NOFP16-NEXT: vmov s0, r0 +; CHECK-NOFP16-NEXT: bl llroundf +; CHECK-NOFP16-NEXT: pop {r11, pc} +; +; CHECK-FP16-LABEL: testmsxh_builtin: +; CHECK-FP16: @ %bb.0: @ %entry +; CHECK-FP16-NEXT: .save {r11, lr} +; CHECK-FP16-NEXT: push {r11, lr} +; CHECK-FP16-NEXT: vcvtb.f32.f16 s0, s0 +; CHECK-FP16-NEXT: bl llroundf +; CHECK-FP16-NEXT: pop {r11, pc} +entry: + %0 = tail call i64 @llvm.llround.i64.f16(half %x) + ret i64 %0 +} -; SOFTFP-LABEL: testmsxs_builtin: -; SOFTFP: bl llroundf -; HARDFP-LABEL: testmsxs_builtin: -; HARDFP: bl llroundf define i64 @testmsxs_builtin(float %x) { +; CHECK-LABEL: testmsxs_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: .save {r11, lr} +; CHECK-NEXT: push {r11, lr} +; CHECK-NEXT: bl llroundf +; CHECK-NEXT: pop {r11, pc} entry: - %0 = tail call i64 @llvm.llround.f32(float %x) + %0 = tail call i64 @llvm.llround.i64.f32(float %x) ret i64 %0 } -; SOFTFP-LABEL: testmsxd_builtin: -; SOFTFP: bl llround -; HARDFP-LABEL: testmsxd_builtin: -; HARDFP: bl llround define i64 @testmsxd_builtin(double %x) { +; CHECK-LABEL: testmsxd_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: .save {r11, lr} +; CHECK-NEXT: push {r11, lr} +; CHECK-NEXT: bl llround +; CHECK-NEXT: pop {r11, pc} entry: - %0 = tail call i64 @llvm.llround.f64(double %x) + %0 = tail call i64 @llvm.llround.i64.f64(double %x) ret i64 %0 } -declare i64 @llvm.llround.f32(float) nounwind readnone -declare i64 @llvm.llround.f64(double) nounwind readnone +define i64 @testmsxq_builtin(fp128 %x) { +; CHECK-LABEL: testmsxq_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: .save {r11, lr} +; CHECK-NEXT: push {r11, lr} +; CHECK-NEXT: bl llroundl +; CHECK-NEXT: pop {r11, pc} +entry: + %0 = tail call i64 @llvm.llround.i64.f128(fp128 %x) + ret i64 %0 +} diff --git a/llvm/test/CodeGen/ARM/lround-conv.ll b/llvm/test/CodeGen/ARM/lround-conv.ll index 3aaed74..03f7a0d 100644 --- a/llvm/test/CodeGen/ARM/lround-conv.ll +++ b/llvm/test/CodeGen/ARM/lround-conv.ll @@ -1,25 +1,47 @@ -; RUN: llc < %s -mtriple=arm-eabi -float-abi=soft | FileCheck %s --check-prefix=SOFTFP -; RUN: llc < %s -mtriple=arm-eabi -float-abi=hard | FileCheck %s --check-prefix=HARDFP +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -mtriple=armv7-none-eabi -float-abi=soft | FileCheck %s --check-prefixes=CHECK,CHECK-SOFT +; RUN: llc < %s -mtriple=armv7-none-eabihf -mattr=+vfp2 -float-abi=hard | FileCheck %s --check-prefixes=CHECK,CHECK-NOFP16 +; RUN: llc < %s -mtriple=armv8-none-eabihf -mattr=+fp-armv8 -float-abi=hard | FileCheck %s --check-prefixes=CHECK,CHECK-FPv8 +; RUN: llc < %s -mtriple=armv8-none-eabihf -mattr=+fp-armv8,+fullfp16 -float-abi=hard | FileCheck %s --check-prefixes=CHECK,CHECK-FP16 + +;define i32 @testmswh_builtin(half %x) { +;entry: +; %0 = tail call i32 @llvm.lround.i32.f16(half %x) +; ret i32 %0 +;} -; SOFTFP-LABEL: testmsws_builtin: -; SOFTFP: bl lroundf -; HARDFP-LABEL: testmsws_builtin: -; HARDFP: bl lroundf define i32 @testmsws_builtin(float %x) { +; CHECK-LABEL: testmsws_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: b lroundf entry: %0 = tail call i32 @llvm.lround.i32.f32(float %x) ret i32 %0 } -; SOFTFP-LABEL: testmswd_builtin: -; SOFTFP: bl lround -; HARDFP-LABEL: testmswd_builtin: -; HARDFP: bl lround define i32 @testmswd_builtin(double %x) { +; CHECK-LABEL: testmswd_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: b lround entry: %0 = tail call i32 @llvm.lround.i32.f64(double %x) ret i32 %0 } -declare i32 @llvm.lround.i32.f32(float) nounwind readnone -declare i32 @llvm.lround.i32.f64(double) nounwind readnone +define i32 @testmswq_builtin(fp128 %x) { +; CHECK-LABEL: testmswq_builtin: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: .save {r11, lr} +; CHECK-NEXT: push {r11, lr} +; CHECK-NEXT: bl lroundl +; CHECK-NEXT: pop {r11, pc} +entry: + %0 = tail call i32 @llvm.lround.i32.f128(fp128 %x) + ret i32 %0 +} + +;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +; CHECK-FP16: {{.*}} +; CHECK-FPv8: {{.*}} +; CHECK-NOFP16: {{.*}} +; CHECK-SOFT: {{.*}} diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index f0e2369..b4d816e 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/TableGen/CodeGenHelpers.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" @@ -30,26 +31,10 @@ using namespace llvm; namespace { -// Simple RAII helper for defining ifdef-undef-endif scopes. -class IfDefScope { -public: - IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { - OS << "#ifdef " << Name << "\n" - << "#undef " << Name << "\n"; - } - - ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } - -private: - StringRef Name; - raw_ostream &OS; -}; -} // namespace - -namespace { enum class Frontend { LLVM, Flang, Clang }; +} // namespace -StringRef getFESpelling(Frontend FE) { +static StringRef getFESpelling(Frontend FE) { switch (FE) { case Frontend::LLVM: return "llvm"; @@ -60,7 +45,6 @@ StringRef getFESpelling(Frontend FE) { } llvm_unreachable("unknown FE kind"); } -} // namespace // Get the full namespace qualifier for the directive language. static std::string getQualifier(const DirectiveLanguage &DirLang, @@ -297,13 +281,8 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "#include <cstddef>\n"; // for size_t OS << "#include <utility>\n"; // for std::pair OS << "\n"; - OS << "namespace llvm {\n"; - - // Open namespaces defined in the directive language - SmallVector<StringRef, 2> Namespaces; - SplitString(DirLang.getCppNamespace(), Namespaces, "::"); - for (auto Ns : Namespaces) - OS << "namespace " << Ns << " {\n"; + NamespaceEmitter LlvmNS(OS, "llvm"); + NamespaceEmitter DirLangNS(OS, DirLang.getCppNamespace()); if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; @@ -380,9 +359,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; } - // Closing namespaces - for (auto Ns : reverse(Namespaces)) - OS << "} // namespace " << Ns << "\n"; + DirLangNS.close(); // These specializations need to be in ::llvm. for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) { @@ -392,9 +369,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << " static constexpr bool is_iterable = true;\n"; OS << "};\n"; } - - OS << "} // namespace llvm\n"; - + LlvmNS.close(); OS << "#endif // LLVM_" << Lang << "_INC\n"; } @@ -971,11 +946,10 @@ static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, std::string IfDefName{"GEN_"}; IfDefName += getFESpelling(FE).upper(); IfDefName += "_DIRECTIVE_CLAUSE_SETS"; - IfDefScope Scope(IfDefName, OS); + IfDefEmitter Scope(OS, IfDefName); StringRef Namespace = getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE); - OS << "\n"; // The namespace has to be different for clang vs flang, as 2 structs with the // same name but different layout is UB. So just put the 'clang' on in the // clang namespace. @@ -1016,9 +990,8 @@ static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang, std::string IfDefName{"GEN_"}; IfDefName += getFESpelling(FE).upper(); IfDefName += "_DIRECTIVE_CLAUSE_MAP"; - IfDefScope Scope(IfDefName, OS); + IfDefEmitter Scope(OS, IfDefName); - OS << "\n"; OS << "{\n"; // The namespace has to be different for clang vs flang, as 2 structs with the @@ -1062,9 +1035,7 @@ static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang, static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); - - OS << "\n"; + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES"); for (const Clause Clause : DirLang.getClauses()) { if (!Clause.getFlangClass().empty()) { @@ -1089,9 +1060,8 @@ static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang, static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST"); - OS << "\n"; interleaveComma(DirLang.getClauses(), OS, [&](const Record *C) { Clause Clause(C); OS << Clause.getFormattedParserClassName() << "\n"; @@ -1102,9 +1072,8 @@ static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang, static void generateFlangClauseDump(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_DUMP_PARSE_TREE_CLAUSES"); - OS << "\n"; for (const Clause Clause : DirLang.getClauses()) { OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " << Clause.getFormattedParserClassName() << ")\n"; @@ -1116,10 +1085,9 @@ static void generateFlangClauseDump(const DirectiveLanguage &DirLang, static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_UNPARSE"); StringRef Base = DirLang.getFlangClauseBaseClass(); - OS << "\n"; for (const Clause Clause : DirLang.getClauses()) { if (Clause.skipFlangUnparser()) @@ -1172,9 +1140,8 @@ static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang, static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_CHECK_ENTER"); - OS << "\n"; for (const Clause Clause : DirLang.getClauses()) { OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() << "::" << Clause.getFormattedParserClassName() << " &);\n"; @@ -1186,12 +1153,11 @@ static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSE_PARSER_KIND_MAP"); StringRef Prefix = DirLang.getClausePrefix(); std::string Qual = getQualifier(DirLang); - OS << "\n"; for (const Record *R : DirLang.getClauses()) { Clause C(R); OS << "if constexpr (std::is_same_v<A, parser::" @@ -1216,11 +1182,10 @@ static void generateFlangClausesParser(const DirectiveLanguage &DirLang, llvm::sort(Names, [](const auto &A, const auto &B) { return A.second.Name > B.second.Name; }); - IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); + IfDefEmitter Scope(OS, "GEN_FLANG_CLAUSES_PARSER"); StringRef Base = DirLang.getFlangClauseBaseClass(); unsigned LastIndex = Names.size() - 1; - OS << "\n"; OS << "TYPE_PARSER(\n"; for (auto [Index, RecSp] : llvm::enumerate(Names)) { auto [R, S] = RecSp; @@ -1313,10 +1278,9 @@ static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang, static void generateClauseClassMacro(const DirectiveLanguage &DirLang, raw_ostream &OS) { // Generate macros style information for legacy code in clang - IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); + IfDefEmitter Scope(OS, "GEN_CLANG_CLAUSE_CLASS"); StringRef Prefix = DirLang.getClausePrefix(); - OS << "\n"; OS << "#ifndef CLAUSE\n"; OS << "#define CLAUSE(Enum, Str, Implicit)\n"; @@ -1375,12 +1339,11 @@ static void generateClauseClassMacro(const DirectiveLanguage &DirLang, // language. This code can be included in library. void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, raw_ostream &OS) { - IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); + IfDefEmitter Scope(OS, "GEN_DIRECTIVES_IMPL"); StringRef DPrefix = DirLang.getDirectivePrefix(); StringRef CPrefix = DirLang.getClausePrefix(); - OS << "\n"; OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; OS << "#include <utility>\n"; diff --git a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp index 6b723bc..e2b5241 100644 --- a/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp +++ b/llvm/utils/TableGen/Basic/TargetFeaturesEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "TargetFeaturesEmitter.h" +#include "llvm/TableGen/CodeGenHelpers.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/TableGenBackend.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -43,7 +44,7 @@ FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) { PrintFatalError( "Too many subtarget features! Bump MAX_SUBTARGET_FEATURES."); - OS << "namespace " << Target << " {\n"; + NamespaceEmitter NS(OS, Target); OS << "enum {\n"; @@ -58,9 +59,8 @@ FeatureMapTy TargetFeaturesEmitter::enumeration(raw_ostream &OS) { OS << " " << "NumSubtargetFeatures = " << N << "\n"; - // Close enumeration and namespace + // Close enumeration. OS << "};\n"; - OS << "} // end namespace " << Target << "\n"; return FeatureMap; } @@ -149,25 +149,23 @@ void TargetFeaturesEmitter::printCPUKeyValues(raw_ostream &OS, void TargetFeaturesEmitter::run(raw_ostream &OS) { OS << "// Autogenerated by TargetFeatureEmitter.cpp\n\n"; - OS << "\n#ifdef GET_SUBTARGETFEATURES_ENUM\n"; - OS << "#undef GET_SUBTARGETFEATURES_ENUM\n\n"; - - OS << "namespace llvm {\n"; - auto FeatureMap = enumeration(OS); - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_SUBTARGETFEATURES_ENUM\n\n"; + FeatureMapTy FeatureMap; + { + IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_ENUM"); + NamespaceEmitter NS(OS, "llvm"); + FeatureMap = enumeration(OS); + } - OS << "\n#ifdef GET_SUBTARGETFEATURES_KV\n"; - OS << "#undef GET_SUBTARGETFEATURES_KV\n\n"; + { + IfDefEmitter IfDef(OS, "GET_SUBTARGETFEATURES_KV"); + NamespaceEmitter NS(OS, "llvm"); - OS << "namespace llvm {\n"; - printFeatureKeyValues(OS, FeatureMap); - OS << "\n"; + printFeatureKeyValues(OS, FeatureMap); + OS << "\n"; - printCPUKeyValues(OS, FeatureMap); - OS << "\n"; - OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_SUBTARGETFEATURES_KV\n\n"; + printCPUKeyValues(OS, FeatureMap); + OS << "\n"; + } } static TableGen::Emitter::OptClass<TargetFeaturesEmitter> diff --git a/llvm/utils/TableGen/CompressInstEmitter.cpp b/llvm/utils/TableGen/CompressInstEmitter.cpp index ccf8385..d8c5ca7 100644 --- a/llvm/utils/TableGen/CompressInstEmitter.cpp +++ b/llvm/utils/TableGen/CompressInstEmitter.cpp @@ -167,7 +167,7 @@ bool CompressInstEmitter::validateRegister(const Record *Reg, assert(RegClass->isSubClassOf("RegisterClass") && "RegClass record should be a RegisterClass"); const CodeGenRegisterClass &RC = Target.getRegisterClass(RegClass); - const CodeGenRegister *R = Target.getRegisterByName(Reg->getName().lower()); + const CodeGenRegister *R = Target.getRegBank().getReg(Reg); assert(R != nullptr && "Register not defined!!"); return RC.contains(R); } diff --git a/mlir/include/mlir/TableGen/CodeGenHelpers.h b/mlir/include/mlir/TableGen/CodeGenHelpers.h index cf14f65..252da21 100644 --- a/mlir/include/mlir/TableGen/CodeGenHelpers.h +++ b/mlir/include/mlir/TableGen/CodeGenHelpers.h @@ -1,3 +1,4 @@ +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -20,6 +21,8 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/CodeGenHelpers.h" +#include <utility> namespace llvm { class RecordKeeper; @@ -36,46 +39,17 @@ std::string strfmt(const char *fmt, Parameters &&...parameters) { return llvm::formatv(fmt, std::forward<Parameters>(parameters)...).str(); } -// Simple RAII helper for defining ifdef-undef-endif scopes. -class IfDefScope { -public: - IfDefScope(llvm::StringRef name, llvm::raw_ostream &os) - : name(name.str()), os(os) { - os << "#ifdef " << name << "\n" - << "#undef " << name << "\n\n"; - } - ~IfDefScope() { os << "\n#endif // " << name << "\n\n"; } - -private: - std::string name; - llvm::raw_ostream &os; -}; - -// A helper RAII class to emit nested namespaces for this op. -class NamespaceEmitter { +// A helper RAII class to emit nested namespaces for a dialect. +class DialectNamespaceEmitter { public: - NamespaceEmitter(raw_ostream &os, const Dialect &dialect) : os(os) { + DialectNamespaceEmitter(raw_ostream &os, const Dialect &dialect) { if (!dialect) return; - emitNamespaceStarts(os, dialect.getCppNamespace()); - } - NamespaceEmitter(raw_ostream &os, StringRef cppNamespace) : os(os) { - emitNamespaceStarts(os, cppNamespace); - } - - ~NamespaceEmitter() { - for (StringRef ns : llvm::reverse(namespaces)) - os << "} // namespace " << ns << "\n"; + nsEmitter.emplace(os, dialect.getCppNamespace()); } private: - void emitNamespaceStarts(raw_ostream &os, StringRef cppNamespace) { - llvm::SplitString(cppNamespace, namespaces, "::"); - for (StringRef ns : namespaces) - os << "namespace " << ns << " {\n"; - } - raw_ostream &os; - SmallVector<StringRef, 2> namespaces; + std::optional<llvm::NamespaceEmitter> nsEmitter; }; /// This class deduplicates shared operation verification code by emitting diff --git a/mlir/include/mlir/TableGen/Dialect.h b/mlir/include/mlir/TableGen/Dialect.h index ea8f405..37c6427a 100644 --- a/mlir/include/mlir/TableGen/Dialect.h +++ b/mlir/include/mlir/TableGen/Dialect.h @@ -107,6 +107,7 @@ public: // Returns whether the dialect is defined. explicit operator bool() const { return def != nullptr; } + bool isDefined() const { return def != nullptr; } private: const llvm::Record *def; diff --git a/mlir/lib/TableGen/CodeGenHelpers.cpp b/mlir/lib/TableGen/CodeGenHelpers.cpp index 2c119fd..cb90ef8 100644 --- a/mlir/lib/TableGen/CodeGenHelpers.cpp +++ b/mlir/lib/TableGen/CodeGenHelpers.cpp @@ -16,6 +16,7 @@ #include "mlir/TableGen/Pattern.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" +#include "llvm/TableGen/CodeGenHelpers.h" #include "llvm/TableGen/Record.h" using namespace llvm; diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp index b911565..06ef396 100644 --- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp +++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp @@ -10,12 +10,12 @@ #include "CppGenUtilities.h" #include "mlir/TableGen/AttrOrTypeDef.h" #include "mlir/TableGen/Class.h" -#include "mlir/TableGen/CodeGenHelpers.h" #include "mlir/TableGen/Format.h" #include "mlir/TableGen/GenInfo.h" #include "mlir/TableGen/Interfaces.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/CommandLine.h" +#include "llvm/TableGen/CodeGenHelpers.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/TableGenBackend.h" @@ -71,14 +71,14 @@ public: void emitDecl(raw_ostream &os) const { if (storageCls && def.genStorageClass()) { - NamespaceEmitter ns(os, def.getStorageNamespace()); + llvm::NamespaceEmitter ns(os, def.getStorageNamespace()); os << "struct " << def.getStorageClassName() << ";\n"; } defCls.writeDeclTo(os); } void emitDef(raw_ostream &os) const { if (storageCls && def.genStorageClass()) { - NamespaceEmitter ns(os, def.getStorageNamespace()); + llvm::NamespaceEmitter ns(os, def.getStorageNamespace()); storageCls->writeDeclTo(os); // everything is inline } defCls.writeDefTo(os); @@ -850,7 +850,7 @@ class AsmPrinter; bool DefGenerator::emitDecls(StringRef selectedDialect) { emitSourceFileHeader((defType + "Def Declarations").str(), os); - IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os); + llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_CLASSES"); // Output the common "header". os << typeDefDeclHeader; @@ -860,7 +860,7 @@ bool DefGenerator::emitDecls(StringRef selectedDialect) { if (defs.empty()) return false; { - NamespaceEmitter nsEmitter(os, defs.front().getDialect()); + DialectNamespaceEmitter nsEmitter(os, defs.front().getDialect()); // Declare all the def classes first (in case they reference each other). for (const AttrOrTypeDef &def : defs) { @@ -892,7 +892,7 @@ bool DefGenerator::emitDecls(StringRef selectedDialect) { //===----------------------------------------------------------------------===// void DefGenerator::emitTypeDefList(ArrayRef<AttrOrTypeDef> defs) { - IfDefScope scope("GET_" + defType.upper() + "DEF_LIST", os); + llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_LIST"); auto interleaveFn = [&](const AttrOrTypeDef &def) { os << def.getDialect().getCppNamespace() << "::" << def.getCppClassName(); }; @@ -1083,11 +1083,11 @@ bool DefGenerator::emitDefs(StringRef selectedDialect) { return false; emitTypeDefList(defs); - IfDefScope scope("GET_" + defType.upper() + "DEF_CLASSES", os); + llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "DEF_CLASSES"); emitParsePrintDispatch(defs); for (const AttrOrTypeDef &def : defs) { { - NamespaceEmitter ns(os, def.getDialect()); + DialectNamespaceEmitter ns(os, def.getDialect()); DefGen gen(def); gen.emitDef(os); } @@ -1102,7 +1102,7 @@ bool DefGenerator::emitDefs(StringRef selectedDialect) { // Emit the default parser/printer for Attributes if the dialect asked for it. if (isAttrGenerator && firstDialect.useDefaultAttributePrinterParser()) { - NamespaceEmitter nsEmitter(os, firstDialect); + DialectNamespaceEmitter nsEmitter(os, firstDialect); if (firstDialect.isExtensible()) { os << llvm::formatv(dialectDefaultAttrPrinterParserDispatch, firstDialect.getCppClassName(), @@ -1116,7 +1116,7 @@ bool DefGenerator::emitDefs(StringRef selectedDialect) { // Emit the default parser/printer for Types if the dialect asked for it. if (!isAttrGenerator && firstDialect.useDefaultTypePrinterParser()) { - NamespaceEmitter nsEmitter(os, firstDialect); + DialectNamespaceEmitter nsEmitter(os, firstDialect); if (firstDialect.isExtensible()) { os << llvm::formatv(dialectDefaultTypePrinterParserDispatch, firstDialect.getCppClassName(), diff --git a/mlir/tools/mlir-tblgen/DialectGen.cpp b/mlir/tools/mlir-tblgen/DialectGen.cpp index 02941ec..2e8810d 100644 --- a/mlir/tools/mlir-tblgen/DialectGen.cpp +++ b/mlir/tools/mlir-tblgen/DialectGen.cpp @@ -242,7 +242,7 @@ static const char *const discardableAttrHelperDecl = R"( static void emitDialectDecl(Dialect &dialect, raw_ostream &os) { // Emit all nested namespaces. { - NamespaceEmitter nsEmitter(os, dialect); + DialectNamespaceEmitter nsEmitter(os, dialect); // Emit the start of the decl. std::string cppName = dialect.getCppClassName(); @@ -358,7 +358,7 @@ static void emitDialectDef(Dialect &dialect, const RecordKeeper &records, << "::" << cppClassName << ")\n"; // Emit all nested namespaces. - NamespaceEmitter nsEmitter(os, dialect); + DialectNamespaceEmitter nsEmitter(os, dialect); /// Build the list of dependent dialects. std::string dependentDialectRegistrations; diff --git a/mlir/tools/mlir-tblgen/OmpOpGen.cpp b/mlir/tools/mlir-tblgen/OmpOpGen.cpp index 91bc61b..e1be11a 100644 --- a/mlir/tools/mlir-tblgen/OmpOpGen.cpp +++ b/mlir/tools/mlir-tblgen/OmpOpGen.cpp @@ -342,7 +342,7 @@ static bool verifyDecls(const RecordKeeper &records, raw_ostream &) { /// structures according to the `clauses` argument of each definition deriving /// from `OpenMP_Op`. static bool genClauseOps(const RecordKeeper &records, raw_ostream &os) { - mlir::tblgen::NamespaceEmitter ns(os, "mlir::omp"); + llvm::NamespaceEmitter ns(os, "mlir::omp"); for (const Record *clause : records.getAllDerivedDefinitions("OpenMP_Clause")) genClauseOpsStruct(clause, os); diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp index 7e8e559..c3420d4 100644 --- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/CodeGenHelpers.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" @@ -4855,7 +4856,7 @@ static void emitOpClassDecls(const RecordKeeper &records, } // Emit the op class declarations. - IfDefScope scope("GET_OP_CLASSES", os); + IfDefEmitter scope(os, "GET_OP_CLASSES"); if (defs.empty()) return; StaticVerifierFunctionEmitter staticVerifierEmitter(os, records); @@ -4898,7 +4899,7 @@ static bool emitOpDecls(const RecordKeeper &records, raw_ostream &os) { return false; Dialect dialect = Operator(defs.front()).getDialect(); - NamespaceEmitter ns(os, dialect); + DialectNamespaceEmitter ns(os, dialect); const char *const opRegistrationHook = "void register{0}Operations{1}({2}::{0} *dialect);\n"; @@ -4921,7 +4922,7 @@ static void emitOpDefShard(const RecordKeeper &records, std::string shardGuard = "GET_OP_DEFS_"; std::string indexStr = std::to_string(shardIndex); shardGuard += indexStr; - IfDefScope scope(shardGuard, os); + IfDefEmitter scope(os, shardGuard); // Emit the op registration hook in the first shard. const char *const opRegistrationHook = @@ -4962,14 +4963,14 @@ static bool emitOpDefs(const RecordKeeper &records, raw_ostream &os) { // If no shard was requested, emit the regular op list and class definitions. if (shardedDefs.size() == 1) { { - IfDefScope scope("GET_OP_LIST", os); + IfDefEmitter scope(os, "GET_OP_LIST"); interleave( defs, os, [&](const Record *def) { os << Operator(def).getQualCppClassName(); }, ",\n"); } { - IfDefScope scope("GET_OP_CLASSES", os); + IfDefEmitter scope(os, "GET_OP_CLASSES"); emitOpClassDefs(records, defs, os); } return false; diff --git a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp index 41ffdfc..3ead2f0 100644 --- a/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp +++ b/mlir/tools/mlir-tblgen/SPIRVUtilsGen.cpp @@ -50,7 +50,6 @@ using mlir::tblgen::EnumCase; using mlir::tblgen::EnumInfo; using mlir::tblgen::NamedAttribute; using mlir::tblgen::NamedTypeConstraint; -using mlir::tblgen::NamespaceEmitter; using mlir::tblgen::Operator; //===----------------------------------------------------------------------===// @@ -261,7 +260,7 @@ static void emitInterfaceDecl(const Availability &availability, std::string(formatv("{0}Traits", interfaceName)); StringRef cppNamespace = availability.getInterfaceClassNamespace(); - NamespaceEmitter nsEmitter(os, cppNamespace); + llvm::NamespaceEmitter nsEmitter(os, cppNamespace); os << "class " << interfaceName << ";\n\n"; // Emit the traits struct containing the concept and model declarations. |