llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) <details> <summary>Changes</summary> This change adds support for the not equal operation for ComplexType https://github.com/llvm/llvm-project/issues/141365 --- Full diff: https://github.com/llvm/llvm-project/pull/146129.diff 5 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+25) - (modified) clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp (+2-3) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+38) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h (+10) - (modified) clang/test/CIR/CodeGen/complex.cpp (+72) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4daff74cbae5a..b58ebd2dfe509 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2481,6 +2481,31 @@ def ComplexEqualOp : CIR_Op<"complex.eq", [Pure, SameTypeOperands]> { }]; } +//===----------------------------------------------------------------------===// +// ComplexNotEqualOp +//===----------------------------------------------------------------------===// + +def ComplexNotEqualOp : CIR_Op<"complex.neq", [Pure, SameTypeOperands]> { + + let summary = "Computes whether two complex values are not equal"; + let description = [{ + The `complex.equal` op takes two complex numbers and returns whether + they are not equal. + + ```mlir + %r = cir.complex.neq %a, %b : !cir.complex<!cir.float> + ``` + }]; + + let results = (outs CIR_BoolType:$result); + let arguments = (ins CIR_ComplexType:$lhs, CIR_ComplexType:$rhs); + + let assemblyFormat = [{ + $lhs `,` $rhs + `:` qualified(type($lhs)) attr-dict + }]; +} + //===----------------------------------------------------------------------===// // Assume Operations //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 955bb5ffc4395..0ba653add826f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -905,9 +905,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> { result = builder.create<cir::ComplexEqualOp>(loc, boInfo.lhs, boInfo.rhs); } else { - assert(!cir::MissingFeatures::complexType()); - cgf.cgm.errorNYI(loc, "complex not equal"); - result = builder.getBool(false, loc); + result = + builder.create<cir::ComplexNotEqualOp>(loc, boInfo.lhs, boInfo.rhs); } } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 1034b8780c03c..598283eeaf518 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1903,6 +1903,7 @@ void ConvertCIRToLLVMPass::runOnOperation() { CIRToLLVMComplexCreateOpLowering, CIRToLLVMComplexEqualOpLowering, CIRToLLVMComplexImagOpLowering, + CIRToLLVMComplexNotEqualOpLowering, CIRToLLVMComplexRealOpLowering, CIRToLLVMConstantOpLowering, CIRToLLVMExpectOpLowering, @@ -2282,6 +2283,43 @@ mlir::LogicalResult CIRToLLVMComplexEqualOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMComplexNotEqualOpLowering::matchAndRewrite( + cir::ComplexNotEqualOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Value lhs = adaptor.getLhs(); + mlir::Value rhs = adaptor.getRhs(); + + auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType()); + mlir::Type complexElemTy = + getTypeConverter()->convertType(complexType.getElementType()); + + mlir::Location loc = op.getLoc(); + auto lhsReal = + rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0); + auto lhsImag = + rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1); + auto rhsReal = + rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0); + auto rhsImag = + rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1); + + if (complexElemTy.isInteger()) { + auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>( + loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal); + auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>( + loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag); + rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp); + return mlir::success(); + } + + auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>( + loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal); + auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>( + loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag); + rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, realCmp, imagCmp); + return mlir::success(); +} + std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() { return std::make_unique<ConvertCIRToLLVMPass>(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 25cf218cf8b6c..5cd1d09b88c00 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -473,6 +473,16 @@ class CIRToLLVMComplexEqualOpLowering mlir::ConversionPatternRewriter &) const override; }; +class CIRToLLVMComplexNotEqualOpLowering + : public mlir::OpConversionPattern<cir::ComplexNotEqualOp> { +public: + using mlir::OpConversionPattern<cir::ComplexNotEqualOp>::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::ComplexNotEqualOp op, OpAdaptor, + mlir::ConversionPatternRewriter &) const override; +}; + } // namespace direct } // namespace cir diff --git a/clang/test/CIR/CodeGen/complex.cpp b/clang/test/CIR/CodeGen/complex.cpp index 1e9ce0e29fd46..b8a0b99c10f0b 100644 --- a/clang/test/CIR/CodeGen/complex.cpp +++ b/clang/test/CIR/CodeGen/complex.cpp @@ -442,3 +442,75 @@ bool foo19(double _Complex a, double _Complex b) { // OGCG: %[[CMP_IMAG:.*]] = fcmp oeq double %[[A_IMAG]], %[[B_IMAG]] // OGCG: %[[RESULT:.*]] = and i1 %[[CMP_REAL]], %[[CMP_IMAG]] + +bool foo20(int _Complex a, int _Complex b) { + return a != b; +} + +// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!s32i>>, !cir.complex<!s32i> +// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!s32i> + +// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[A_REAL:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 1 +// LLVM: %[[CMP_REAL:.*]] = icmp ne i32 %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[CMP_IMAG:.*]] = icmp ne i32 %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]] + +// OGCG: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, align 4 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load i32, ptr %[[A_REAL_PTR]], align 4 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_A]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load i32, ptr %[[A_IMAG_PTR]], align 4 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 0 +// OGCG: %[[B_REAL:.*]] = load i32, ptr %[[B_REAL_PTR]], align 4 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[COMPLEX_B]], i32 0, i32 1 +// OGCG: %[[B_IMAG:.*]] = load i32, ptr %[[B_IMAG_PTR]], align 4 +// OGCG: %[[CMP_REAL:.*]] = icmp ne i32 %[[A_REAL]], %[[B_REAL]] +// OGCG: %[[CMP_IMAG:.*]] = icmp ne i32 %[[A_IMAG]], %[[B_IMAG]] +// OGCG: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]] + +bool foo21(double _Complex a, double _Complex b) { + return a != b; +} + +// CIR: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double> +// CIR: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.complex<!cir.double>>, !cir.complex<!cir.double> +// CIR: %[[RESULT:.*]] = cir.complex.neq %[[COMPLEX_A]], %[[COMPLEX_B]] : !cir.complex<!cir.double> + +// LLVM: %[[COMPLEX_A:.*]] = load { double, double }, ptr {{.*}}, align 8 +// LLVM: %[[COMPLEX_B:.*]] = load { double, double }, ptr {{.*}}, align 8 +// LLVM: %[[A_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_A]], 0 +// LLVM: %[[A_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_A]], 1 +// LLVM: %[[B_REAL:.*]] = extractvalue { double, double } %[[COMPLEX_B]], 0 +// LLVM: %[[B_IMAG:.*]] = extractvalue { double, double } %[[COMPLEX_B]], 1 +// LLVM: %[[CMP_REAL:.*]] = fcmp une double %[[A_REAL]], %[[B_REAL]] +// LLVM: %[[CMP_IMAG:.*]] = fcmp une double %[[A_IMAG]], %[[B_IMAG]] +// LLVM: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]] + +// OGCG: %[[COMPLEX_A:.*]] = alloca { double, double }, align 8 +// OGCG: %[[COMPLEX_B:.*]] = alloca { double, double }, align 8 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 0 +// OGCG: store double {{.*}}, ptr %[[A_REAL_PTR]], align 8 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 1 +// OGCG: store double {{.*}}, ptr %[[A_IMAG_PTR]], align 8 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 0 +// OGCG: store double {{.*}}, ptr %[[B_REAL_PTR]], align 8 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 1 +// OGCG: store double {{.*}}, ptr %[[B_IMAG_PTR]], align 8 +// OGCG: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 0 +// OGCG: %[[A_REAL:.*]] = load double, ptr %[[A_REAL_PTR]], align 8 +// OGCG: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_A]], i32 0, i32 1 +// OGCG: %[[A_IMAG:.*]] = load double, ptr %[[A_IMAG_PTR]], align 8 +// OGCG: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 0 +// OGCG: %[[B_REAL:.*]] = load double, ptr %[[B_REAL_PTR]], align 8 +// OGCG: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { double, double }, ptr %[[COMPLEX_B]], i32 0, i32 1 +// OGCG: %[[B_IMAG:.*]] = load double, ptr %[[B_IMAG_PTR]], align 8 +// OGCG: %[[CMP_REAL:.*]] = fcmp une double %[[A_REAL]], %[[B_REAL]] +// OGCG: %[[CMP_IMAG:.*]] = fcmp une double %[[A_IMAG]], %[[B_IMAG]] +// OGCG: %[[RESULT:.*]] = or i1 %[[CMP_REAL]], %[[CMP_IMAG]] `````````` </details> https://github.com/llvm/llvm-project/pull/146129 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits