https://github.com/AmrDeveloper created https://github.com/llvm/llvm-project/pull/150834
This change adds support for mul op for ComplexType https://github.com/llvm/llvm-project/issues/141365 >From 59063f1e4e73eb0c4dfe6d74393ed496c2c3e7be Mon Sep 17 00:00:00 2001 From: AmrDeveloper <am...@programmer.net> Date: Sun, 27 Jul 2025 15:43:30 +0200 Subject: [PATCH] [CIR] Upstream MulOp for ComplexType --- .../CIR/Dialect/Builder/CIRBaseBuilder.h | 4 + clang/include/clang/CIR/Dialect/IR/CIROps.td | 41 +++ clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 27 ++ .../Dialect/Transforms/LoweringPrepare.cpp | 149 +++++++- clang/test/CIR/CodeGen/complex-mul-div.cpp | 325 ++++++++++++++++++ 5 files changed, 544 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/CodeGen/complex-mul-div.cpp diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 5c04d59475b6a..aea8315c274a5 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -441,6 +441,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return create<cir::CmpOp>(loc, getBoolTy(), kind, lhs, rhs); } + mlir::Value createIsNaN(mlir::Location loc, mlir::Value operand) { + return createCompare(loc, cir::CmpOpKind::ne, operand, operand); + } + mlir::Value createShift(mlir::Location loc, mlir::Value lhs, mlir::Value rhs, bool isShiftLeft) { return create<cir::ShiftOp>(loc, lhs.getType(), lhs, rhs, isShiftLeft); diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e2ddbd12c77bd..eb724dd299d3b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2804,6 +2804,47 @@ def CIR_ComplexSubOp : CIR_Op<"complex.sub", [ }]; } +//===----------------------------------------------------------------------===// +// ComplexMulOp +//===----------------------------------------------------------------------===// + +def CIR_ComplexRangeKind : CIR_I32EnumAttr< + "ComplexRangeKind", "complex multiplication and division implementation", [ + I32EnumAttrCase<"Full", 0, "full">, + I32EnumAttrCase<"Improved", 1, "improved">, + I32EnumAttrCase<"Promoted", 2, "promoted">, + I32EnumAttrCase<"Basic", 3, "basic">, + I32EnumAttrCase<"None", 4, "none"> +]>; + +def CIR_ComplexMulOp : CIR_Op<"complex.mul", [ + Pure, SameOperandsAndResultType +]> { + let summary = "Complex multiplication"; + let description = [{ + The `cir.complex.mul` operation takes two complex numbers and returns + their product. + + Example: + + ```mlir + %2 = cir.complex.mul %0, %1 range(basic) : !cir.complex<!cir.float> + %2 = cir.complex.mul %0, %1 range(full) : !cir.complex<!cir.float> + ``` + }]; + + let arguments = (ins + CIR_ComplexType:$lhs, + CIR_ComplexType:$rhs, + CIR_ComplexRangeKind:$range + ); + + let results = (outs CIR_ComplexType:$result); + + let assemblyFormat = [{ + $lhs `,` $rhs `range` `(` $range `)` `:` qualified(type($result)) attr-dict + }]; +} //===----------------------------------------------------------------------===// // Bit Manipulation Operations diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 02685a3d64121..196df0e9e6405 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -110,6 +110,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { mlir::Value emitBinAdd(const BinOpInfo &op); mlir::Value emitBinSub(const BinOpInfo &op); + mlir::Value emitBinMul(const BinOpInfo &op); QualType getPromotionType(QualType ty, bool isDivOpCode = false) { if (auto *complexTy = ty->getAs<ComplexType>()) { @@ -142,6 +143,7 @@ class ComplexExprEmitter : public StmtVisitor<ComplexExprEmitter, mlir::Value> { HANDLEBINOP(Add) HANDLEBINOP(Sub) + HANDLEBINOP(Mul) #undef HANDLEBINOP }; } // namespace @@ -531,6 +533,7 @@ mlir::Value ComplexExprEmitter::emitPromoted(const Expr *e, return emitBin##OP(emitBinOps(bo, promotionTy)); HANDLE_BINOP(Add) HANDLE_BINOP(Sub) + HANDLE_BINOP(Mul) #undef HANDLE_BINOP default: break; @@ -582,6 +585,30 @@ mlir::Value ComplexExprEmitter::emitBinSub(const BinOpInfo &op) { return builder.create<cir::ComplexSubOp>(op.loc, op.lhs, op.rhs); } +static cir::ComplexRangeKind +getComplexRangeAttr(LangOptions::ComplexRangeKind range) { + switch (range) { + case LangOptions::CX_Full: + return cir::ComplexRangeKind::Full; + case LangOptions::CX_Improved: + return cir::ComplexRangeKind::Improved; + case LangOptions::CX_Promoted: + return cir::ComplexRangeKind::Promoted; + case LangOptions::CX_Basic: + return cir::ComplexRangeKind::Basic; + case LangOptions::CX_None: + return cir::ComplexRangeKind::None; + } +} + +mlir::Value ComplexExprEmitter::emitBinMul(const BinOpInfo &op) { + assert(!cir::MissingFeatures::fastMathFlags()); + assert(!cir::MissingFeatures::cgFPOptionsRAII()); + cir::ComplexRangeKind rangeKind = + getComplexRangeAttr(op.fpFeatures.getComplexRange()); + return builder.create<cir::ComplexMulOp>(op.loc, op.lhs, op.rhs, rangeKind); +} + LValue CIRGenFunction::emitComplexAssignmentLValue(const BinaryOperator *e) { assert(e->getOpcode() == BO_Assign && "Expected assign op"); diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index cef83eae2ef50..a2ce550819183 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -15,7 +15,6 @@ #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/MissingFeatures.h" -#include <iostream> #include <memory> using namespace mlir; @@ -28,20 +27,46 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> { void runOnOp(mlir::Operation *op); void lowerCastOp(cir::CastOp op); + void lowerComplexMulOp(cir::ComplexMulOp op); void lowerUnaryOp(cir::UnaryOp op); void lowerArrayCtor(ArrayCtor op); + cir::FuncOp buildRuntimeFunction( + mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, + cir::FuncType type, + cir::GlobalLinkageKind linkage = cir::GlobalLinkageKind::ExternalLinkage); + /// /// AST related /// ----------- clang::ASTContext *astCtx; + /// Tracks current module. + mlir::ModuleOp theModule; + void setASTContext(clang::ASTContext *c) { astCtx = c; } }; } // namespace +cir::FuncOp LoweringPreparePass::buildRuntimeFunction( + mlir::OpBuilder &builder, llvm::StringRef name, mlir::Location loc, + cir::FuncType type, cir::GlobalLinkageKind linkage) { + cir::FuncOp f = dyn_cast_or_null<FuncOp>(SymbolTable::lookupNearestSymbolFrom( + theModule, StringAttr::get(theModule->getContext(), name))); + if (!f) { + f = builder.create<cir::FuncOp>(loc, name, type); + f.setLinkageAttr( + cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage)); + mlir::SymbolTable::setSymbolVisibility( + f, mlir::SymbolTable::Visibility::Private); + + assert(!cir::MissingFeatures::opFuncExtraAttrs()); + } + return f; +} + static mlir::Value lowerScalarToComplexCast(mlir::MLIRContext &ctx, cir::CastOp op) { cir::CIRBaseBuilderTy builder(ctx); @@ -127,6 +152,120 @@ void LoweringPreparePass::lowerCastOp(cir::CastOp op) { } } +static mlir::Value buildComplexBinOpLibCall( + LoweringPreparePass &pass, CIRBaseBuilderTy &builder, + llvm::StringRef (*libFuncNameGetter)(llvm::APFloat::Semantics), + mlir::Location loc, cir::ComplexType ty, mlir::Value lhsReal, + mlir::Value lhsImag, mlir::Value rhsReal, mlir::Value rhsImag) { + cir::FPTypeInterface elementTy = + mlir::cast<cir::FPTypeInterface>(ty.getElementType()); + + llvm::StringRef libFuncName = libFuncNameGetter( + llvm::APFloat::SemanticsToEnum(elementTy.getFloatSemantics())); + llvm::SmallVector<mlir::Type, 4> libFuncInputTypes(4, elementTy); + + cir::FuncType libFuncTy = cir::FuncType::get(libFuncInputTypes, ty); + + cir::FuncOp libFunc; + { + mlir::OpBuilder::InsertionGuard ipGuard{builder}; + builder.setInsertionPointToStart(pass.theModule.getBody()); + libFunc = pass.buildRuntimeFunction(builder, libFuncName, loc, libFuncTy); + } + + cir::CallOp call = + builder.createCallOp(loc, libFunc, {lhsReal, lhsImag, rhsReal, rhsImag}); + return call.getResult(); +} + +static llvm::StringRef +getComplexMulLibCallName(llvm::APFloat::Semantics semantics) { + switch (semantics) { + case llvm::APFloat::S_IEEEhalf: + return "__mulhc3"; + case llvm::APFloat::S_IEEEsingle: + return "__mulsc3"; + case llvm::APFloat::S_IEEEdouble: + return "__muldc3"; + case llvm::APFloat::S_PPCDoubleDouble: + return "__multc3"; + case llvm::APFloat::S_x87DoubleExtended: + return "__mulxc3"; + case llvm::APFloat::S_IEEEquad: + return "__multc3"; + default: + llvm_unreachable("unsupported floating point type"); + } +} + +static mlir::Value lowerComplexMul(LoweringPreparePass &pass, + CIRBaseBuilderTy &builder, + mlir::Location loc, cir::ComplexMulOp op, + mlir::Value lhsReal, mlir::Value lhsImag, + mlir::Value rhsReal, mlir::Value rhsImag) { + // (a+bi) * (c+di) = (ac-bd) + (ad+bc)i + mlir::Value resultRealLhs = + builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsReal); + mlir::Value resultRealRhs = + builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsImag); + mlir::Value resultImagLhs = + builder.createBinop(loc, lhsReal, cir::BinOpKind::Mul, rhsImag); + mlir::Value resultImagRhs = + builder.createBinop(loc, lhsImag, cir::BinOpKind::Mul, rhsReal); + mlir::Value resultReal = builder.createBinop( + loc, resultRealLhs, cir::BinOpKind::Sub, resultRealRhs); + mlir::Value resultImag = builder.createBinop( + loc, resultImagLhs, cir::BinOpKind::Add, resultImagRhs); + mlir::Value algebraicResult = + builder.createComplexCreate(loc, resultReal, resultImag); + + cir::ComplexType complexTy = op.getType(); + cir::ComplexRangeKind rangeKind = op.getRange(); + if (mlir::isa<cir::IntType>(complexTy.getElementType()) || + rangeKind == cir::ComplexRangeKind::Basic || + rangeKind == cir::ComplexRangeKind::Improved || + rangeKind == cir::ComplexRangeKind::Promoted) + return algebraicResult; + + // Check whether the real part and the imaginary part of the result are both + // NaN. If so, emit a library call to compute the multiplication instead. + // We check a value against NaN by comparing the value against itself. + mlir::Value resultRealIsNaN = builder.createIsNaN(loc, resultReal); + mlir::Value resultImagIsNaN = builder.createIsNaN(loc, resultImag); + mlir::Value resultRealAndImagAreNaN = + builder.createLogicalAnd(loc, resultRealIsNaN, resultImagIsNaN); + + return builder + .create<cir::TernaryOp>( + loc, resultRealAndImagAreNaN, + [&](mlir::OpBuilder &, mlir::Location) { + mlir::Value libCallResult = buildComplexBinOpLibCall( + pass, builder, &getComplexMulLibCallName, loc, complexTy, + lhsReal, lhsImag, rhsReal, rhsImag); + builder.createYield(loc, libCallResult); + }, + [&](mlir::OpBuilder &, mlir::Location) { + builder.createYield(loc, algebraicResult); + }) + .getResult(); +} + +void LoweringPreparePass::lowerComplexMulOp(cir::ComplexMulOp op) { + cir::CIRBaseBuilderTy builder(getContext()); + builder.setInsertionPointAfter(op); + mlir::Location loc = op.getLoc(); + mlir::TypedValue<cir::ComplexType> lhs = op.getLhs(); + mlir::TypedValue<cir::ComplexType> rhs = op.getRhs(); + mlir::Value lhsReal = builder.createComplexReal(loc, lhs); + mlir::Value lhsImag = builder.createComplexImag(loc, lhs); + mlir::Value rhsReal = builder.createComplexReal(loc, rhs); + mlir::Value rhsImag = builder.createComplexImag(loc, rhs); + mlir::Value loweredResult = lowerComplexMul(*this, builder, loc, op, lhsReal, + lhsImag, rhsReal, rhsImag); + op.replaceAllUsesWith(loweredResult); + op.erase(); +} + void LoweringPreparePass::lowerUnaryOp(cir::UnaryOp op) { mlir::Type ty = op.getType(); if (!mlir::isa<cir::ComplexType>(ty)) @@ -247,17 +386,23 @@ void LoweringPreparePass::runOnOp(mlir::Operation *op) { lowerArrayCtor(arrayCtor); else if (auto cast = mlir::dyn_cast<cir::CastOp>(op)) lowerCastOp(cast); + else if (auto complexMul = mlir::dyn_cast<cir::ComplexMulOp>(op)) + lowerComplexMulOp(complexMul); else if (auto unary = mlir::dyn_cast<cir::UnaryOp>(op)) lowerUnaryOp(unary); } void LoweringPreparePass::runOnOperation() { mlir::Operation *op = getOperation(); + if (isa<::mlir::ModuleOp>(op)) { + theModule = cast<::mlir::ModuleOp>(op); + } llvm::SmallVector<mlir::Operation *> opsToTransform; op->walk([&](mlir::Operation *op) { - if (mlir::isa<cir::ArrayCtor, cir::CastOp, cir::UnaryOp>(op)) + if (mlir::isa<cir::ArrayCtor, cir::CastOp, cir::ComplexMulOp, cir::UnaryOp>( + op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/complex-mul-div.cpp b/clang/test/CIR/CodeGen/complex-mul-div.cpp new file mode 100644 index 0000000000000..5fe682ac28b53 --- /dev/null +++ b/clang/test/CIR/CodeGen/complex-mul-div.cpp @@ -0,0 +1,325 @@ +// complex-range basic +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=basic -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-BASIC %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR-AFTER-BASIC +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM-BASIC +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=basic -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG-BASIC + +// complex-range improved +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=improved -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-IMPROVED %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR-AFTER-IMPROVED +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM-IMPROVED +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=improved -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG-IMPROVED + +// complex-range promoted +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=promoted -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-PROMOTED %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR-AFTER-PROMOTED +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM-PROMOTED +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=promoted -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG-PROMOTED + +// complex-range full +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -complex-range=full -Wno-unused-value -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-canonicalize -o %t.cir %s 2>&1 | FileCheck --check-prefix=CIR-BEFORE-FULL %s +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR-AFTER-FULL +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM-FULL +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -complex-range=full -Wno-unused-value -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG-FULL + +void foo() { + float _Complex a; + float _Complex b; + float _Complex c = a * b; +} + +// CIR-BEFORE-BASIC: %{{.*}} = cir.complex.mul {{.*}}, {{.*}} range(basic) : !cir.complex<!cir.float> + +// CIR-AFTER-BASIC: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR-AFTER-BASIC: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"] +// CIR-AFTER-BASIC: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init] +// CIR-AFTER-BASIC: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-BASIC: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-BASIC: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-BASIC: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-BASIC: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-BASIC: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-BASIC: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-BASIC: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-BASIC: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-BASIC: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-BASIC: %[[C_REAL:.*]] = cir.binop(sub, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.float +// CIR-AFTER-BASIC: %[[C_IMAG:.*]] = cir.binop(add, %[[MUL_AR_BI]], %[[MUL_AI_BR]]) : !cir.float +// CIR-AFTER-BASIC: %[[RESULT:.*]] = cir.complex.create %[[C_REAL]], %[[C_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// CIR-AFTER-BASIC: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// LLVM-BASIC: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-BASIC: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-BASIC: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-BASIC: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM-BASIC: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-BASIC: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-BASIC: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM-BASIC: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM-BASIC: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM-BASIC: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// LLVM-BASIC: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// LLVM-BASIC: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// LLVM-BASIC: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// LLVM-BASIC: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// LLVM-BASIC: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// LLVM-BASIC: %[[MUL_A_B:.*]] = insertvalue { float, float } {{.*}}, float %[[C_REAL]], 0 +// LLVM-BASIC: %[[RESULT:.*]] = insertvalue { float, float } %[[MUL_A_B]], float %[[C_IMAG]], 1 +// LLVM-BASIC: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-BASIC: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-BASIC: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-BASIC: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-BASIC: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-BASIC: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-BASIC: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-BASIC: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-BASIC: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG-BASIC: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4 +// OGCG-BASIC: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG-BASIC: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4 +// OGCG-BASIC: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// OGCG-BASIC: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// OGCG-BASIC: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// OGCG-BASIC: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// OGCG-BASIC: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// OGCG-BASIC: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// OGCG-BASIC: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG-BASIC: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG-BASIC: store float %[[C_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG-BASIC: store float %[[C_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +// CIR-BEFORE-IMPROVED: %{{.*}} = cir.complex.mul {{.*}}, {{.*}} range(improved) : !cir.complex<!cir.float> + +// CIR-AFTER-IMPROVED: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR-AFTER-IMPROVED: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"] +// CIR-AFTER-IMPROVED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init] +// CIR-AFTER-IMPROVED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-IMPROVED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-IMPROVED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-IMPROVED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-IMPROVED: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-IMPROVED: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-IMPROVED: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[C_REAL:.*]] = cir.binop(sub, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[C_IMAG:.*]] = cir.binop(add, %[[MUL_AR_BI]], %[[MUL_AI_BR]]) : !cir.float +// CIR-AFTER-IMPROVED: %[[RESULT:.*]] = cir.complex.create %[[C_REAL]], %[[C_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// CIR-AFTER-IMPROVED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// LLVM-IMPROVED: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-IMPROVED: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-IMPROVED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-IMPROVED: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM-IMPROVED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-IMPROVED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-IMPROVED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM-IMPROVED: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM-IMPROVED: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM-IMPROVED: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// LLVM-IMPROVED: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// LLVM-IMPROVED: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// LLVM-IMPROVED: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// LLVM-IMPROVED: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// LLVM-IMPROVED: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// LLVM-IMPROVED: %[[MUL_A_B:.*]] = insertvalue { float, float } {{.*}}, float %[[C_REAL]], 0 +// LLVM-IMPROVED: %[[RESULT:.*]] = insertvalue { float, float } %[[MUL_A_B]], float %[[C_IMAG]], 1 +// LLVM-IMPROVED: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-IMPROVED: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-IMPROVED: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-IMPROVED: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-IMPROVED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-IMPROVED: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-IMPROVED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-IMPROVED: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-IMPROVED: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG-IMPROVED: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4 +// OGCG-IMPROVED: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG-IMPROVED: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4 +// OGCG-IMPROVED: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// OGCG-IMPROVED: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// OGCG-IMPROVED: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// OGCG-IMPROVED: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// OGCG-IMPROVED: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// OGCG-IMPROVED: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// OGCG-IMPROVED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG-IMPROVED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG-IMPROVED: store float %[[C_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG-IMPROVED: store float %[[C_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +// CIR-BEFORE-PROMOTED: %{{.*}} = cir.complex.mul {{.*}}, {{.*}} range(promoted) : !cir.complex<!cir.float> + +// CIR-AFTER-PROMOTED: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR-AFTER-PROMOTED: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"] +// CIR-AFTER-PROMOTED: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init] +// CIR-AFTER-PROMOTED: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-PROMOTED: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-PROMOTED: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-PROMOTED: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-PROMOTED: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-PROMOTED: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-PROMOTED: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[C_REAL:.*]] = cir.binop(sub, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[C_IMAG:.*]] = cir.binop(add, %[[MUL_AR_BI]], %[[MUL_AI_BR]]) : !cir.float +// CIR-AFTER-PROMOTED: %[[RESULT:.*]] = cir.complex.create %[[C_REAL]], %[[C_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// CIR-AFTER-PROMOTED: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// LLVM-PROMOTED: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-PROMOTED: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-PROMOTED: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-PROMOTED: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM-PROMOTED: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-PROMOTED: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-PROMOTED: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM-PROMOTED: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM-PROMOTED: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM-PROMOTED: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// LLVM-PROMOTED: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// LLVM-PROMOTED: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// LLVM-PROMOTED: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// LLVM-PROMOTED: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// LLVM-PROMOTED: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// LLVM-PROMOTED: %[[MUL_A_B:.*]] = insertvalue { float, float } {{.*}}, float %[[C_REAL]], 0 +// LLVM-PROMOTED: %[[RESULT:.*]] = insertvalue { float, float } %[[MUL_A_B]], float %[[C_IMAG]], 1 +// LLVM-PROMOTED: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-PROMOTED: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-PROMOTED: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-PROMOTED: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-PROMOTED: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-PROMOTED: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-PROMOTED: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-PROMOTED: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-PROMOTED: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG-PROMOTED: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4 +// OGCG-PROMOTED: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG-PROMOTED: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4 +// OGCG-PROMOTED: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// OGCG-PROMOTED: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// OGCG-PROMOTED: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// OGCG-PROMOTED: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// OGCG-PROMOTED: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// OGCG-PROMOTED: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// OGCG-PROMOTED: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG-PROMOTED: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG-PROMOTED: store float %[[C_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG-PROMOTED: store float %[[C_IMAG]], ptr %[[C_IMAG_PTR]], align 4 + +// CIR-BEFORE-FULL: %{{.*}} = cir.complex.mul {{.*}}, {{.*}} range(full) : !cir.complex<!cir.float> + +// CIR-AFTER-FULL: %[[A_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["a"] +// CIR-AFTER-FULL: %[[B_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["b"] +// CIR-AFTER-FULL: %[[C_ADDR:.*]] = cir.alloca !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>>, ["c", init] +// CIR-AFTER-FULL: %[[TMP_A:.*]] = cir.load{{.*}} %[[A_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-FULL: %[[TMP_B:.*]] = cir.load{{.*}} %[[B_ADDR]] : !cir.ptr<!cir.complex<!cir.float>>, !cir.complex<!cir.float> +// CIR-AFTER-FULL: %[[A_REAL:.*]] = cir.complex.real %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-FULL: %[[A_IMAG:.*]] = cir.complex.imag %[[TMP_A]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-FULL: %[[B_REAL:.*]] = cir.complex.real %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-FULL: %[[B_IMAG:.*]] = cir.complex.imag %[[TMP_B]] : !cir.complex<!cir.float> -> !cir.float +// CIR-AFTER-FULL: %[[MUL_AR_BR:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-FULL: %[[MUL_AI_BI:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-FULL: %[[MUL_AR_BI:.*]] = cir.binop(mul, %[[A_REAL]], %[[B_IMAG]]) : !cir.float +// CIR-AFTER-FULL: %[[MUL_AI_BR:.*]] = cir.binop(mul, %[[A_IMAG]], %[[B_REAL]]) : !cir.float +// CIR-AFTER-FULL: %[[C_REAL:.*]] = cir.binop(sub, %[[MUL_AR_BR]], %[[MUL_AI_BI]]) : !cir.float +// CIR-AFTER-FULL: %[[C_IMAG:.*]] = cir.binop(add, %[[MUL_AR_BI]], %[[MUL_AI_BR]]) : !cir.float +// CIR-AFTER-FULL: %[[COMPLEX:.*]] = cir.complex.create %[[C_REAL]], %[[C_IMAG]] : !cir.float -> !cir.complex<!cir.float> +// CIR-AFTER-FULL: %[[IS_C_REAL_NAN:.*]] = cir.cmp(ne, %[[C_REAL]], %[[C_REAL]]) : !cir.float, !cir.bool +// CIR-AFTER-FULL: %[[IS_C_IMAG_NAN:.*]] = cir.cmp(ne, %[[C_IMAG]], %[[C_IMAG]]) : !cir.float, !cir.bool +// CIR-AFTER-FULL: %[[CONST_FALSE:.*]] = cir.const #false +// CIR-AFTER-FULL: %[[SELECT_CONDITION:.*]] = cir.select if %[[IS_C_REAL_NAN]] then %[[IS_C_IMAG_NAN]] else %[[CONST_FALSE]] : (!cir.bool, !cir.bool, !cir.bool) -> !cir.bool +// CIR-AFTER-FULL: %[[RESULT:.*]] = cir.ternary(%[[SELECT_CONDITION]], true { +// CIR-AFTER-FULL: %[[LIBC_COMPLEX:.*]] = cir.call @__mulsc3(%[[A_REAL]], %[[A_IMAG]], %[[B_REAL]], %[[B_IMAG]]) : (!cir.float, !cir.float, !cir.float, !cir.float) -> !cir.complex<!cir.float> +// CIR-AFTER-FULL: cir.yield %[[LIBC_COMPLEX]] : !cir.complex<!cir.float> +// CIR-AFTER-FULL: }, false { +// CIR-AFTER-FULL: cir.yield %[[COMPLEX]] : !cir.complex<!cir.float> +// CIR-AFTER-FULL: }) : (!cir.bool) -> !cir.complex<!cir.float> +// CIR-AFTER-FULL: cir.store{{.*}} %[[RESULT]], %[[C_ADDR]] : !cir.complex<!cir.float>, !cir.ptr<!cir.complex<!cir.float>> + +// LLVM-FULL: %[[A_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-FULL: %[[B_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-FULL: %[[C_ADDR:.*]] = alloca { float, float }, i64 1, align 4 +// LLVM-FULL: %[[TMP_A:.*]] = load { float, float }, ptr %[[A_ADDR]], align 4 +// LLVM-FULL: %[[TMP_B:.*]] = load { float, float }, ptr %[[B_ADDR]], align 4 +// LLVM-FULL: %[[A_REAL:.*]] = extractvalue { float, float } %[[TMP_A]], 0 +// LLVM-FULL: %[[A_IMAG:.*]] = extractvalue { float, float } %[[TMP_A]], 1 +// LLVM-FULL: %[[B_REAL:.*]] = extractvalue { float, float } %[[TMP_B]], 0 +// LLVM-FULL: %[[B_IMAG:.*]] = extractvalue { float, float } %[[TMP_B]], 1 +// LLVM-FULL: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// LLVM-FULL: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// LLVM-FULL: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// LLVM-FULL: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// LLVM-FULL: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// LLVM-FULL: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// LLVM-FULL: %[[MUL_A_B:.*]] = insertvalue { float, float } {{.*}}, float %[[C_REAL]], 0 +// LLVM-FULL: %[[COMPLEX:.*]] = insertvalue { float, float } %[[MUL_A_B]], float %[[C_IMAG]], 1 +// LLVM-FULL: %[[IS_C_REAL_NAN:.*]] = fcmp une float %[[C_REAL]], %[[C_REAL]] +// LLVM-FULL: %[[IS_C_IMAG_NAN:.*]] = fcmp une float %[[C_IMAG]], %[[C_IMAG]] +// LLVM-FULL: %[[SELECT_CONDITION:.*]] = and i1 %[[IS_C_REAL_NAN]], %[[IS_C_IMAG_NAN]] +// LLVM-FULL: br i1 %[[SELECT_CONDITION]], label %[[THEN_LABEL:.*]], label %[[ELSE_LABEL:.*]] +// LLVM-FULL: [[THEN_LABEL]]: +// LLVM-FULL: %[[LIBC_COMPLEX:.*]] = call { float, float } @__mulsc3(float %[[A_REAL]], float %[[A_IMAG]], float %[[B_REAL]], float %[[B_IMAG]]) +// LLVM-FULL: br label %[[PHI_BRANCH:.*]] +// LLVM-FULL: [[ELSE_LABEL]]: +// LLVM-FULL: br label %[[PHI_BRANCH:]] +// LLVM-FULL: [[PHI_BRANCH:]]: +// LLVM-FULL: %[[RESULT:.*]] = phi { float, float } [ %[[COMPLEX]], %[[ELSE_LABEL]] ], [ %[[LIBC_COMPLEX]], %[[THEN_LABEL]] ] +// LLVM-FULL: br label %[[END_LABEL:.*]] +// LLVM-FULL: [[END_LABEL]]: +// LLVM-FULL: store { float, float } %[[RESULT]], ptr %[[C_ADDR]], align 4 + +// OGCG-FULL: %[[A_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-FULL: %[[B_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-FULL: %[[C_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-FULL: %[[COMPLEX_CALL_ADDR:.*]] = alloca { float, float }, align 4 +// OGCG-FULL: %[[A_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 0 +// OGCG-FULL: %[[A_REAL:.*]] = load float, ptr %[[A_REAL_PTR]], align 4 +// OGCG-FULL: %[[A_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[A_ADDR]], i32 0, i32 1 +// OGCG-FULL: %[[A_IMAG:.*]] = load float, ptr %[[A_IMAG_PTR]], align 4 +// OGCG-FULL: %[[B_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 0 +// OGCG-FULL: %[[B_REAL:.*]] = load float, ptr %[[B_REAL_PTR]], align 4 +// OGCG-FULL: %[[B_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[B_ADDR]], i32 0, i32 1 +// OGCG-FULL: %[[B_IMAG:.*]] = load float, ptr %[[B_IMAG_PTR]], align 4 +// OGCG-FULL: %[[MUL_AR_BR:.*]] = fmul float %[[A_REAL]], %[[B_REAL]] +// OGCG-FULL: %[[MUL_AI_BI:.*]] = fmul float %[[A_IMAG]], %[[B_IMAG]] +// OGCG-FULL: %[[MUL_AR_BI:.*]] = fmul float %[[A_REAL]], %[[B_IMAG]] +// OGCG-FULL: %[[MUL_AI_BR:.*]] = fmul float %[[A_IMAG]], %[[B_REAL]] +// OGCG-FULL: %[[C_REAL:.*]] = fsub float %[[MUL_AR_BR]], %[[MUL_AI_BI]] +// OGCG-FULL: %[[C_IMAG:.*]] = fadd float %[[MUL_AR_BI]], %[[MUL_AI_BR]] +// OGCG-FULL: %[[IS_C_REAL_NAN:.*]] = fcmp uno float %[[C_REAL]], %[[C_REAL]] +// OGCG-FULL: br i1 %[[IS_C_REAL_NAN]], label %[[COMPLEX_IS_IMAG_NAN:.*]], label %[[END_LABEL:.*]], !prof !2 +// OGCG-FULL: [[COMPLEX_IS_IMAG_NAN]]: +// OGCG-FULL: %[[IS_C_IMAG_NAN:.*]] = fcmp uno float %[[C_IMAG]], %[[C_IMAG]] +// OGCG-FULL: br i1 %[[IS_C_IMAG_NAN]], label %[[COMPLEX_LIB_CALL:.*]], label %[[END_LABEL]], !prof !2 +// OGCG-FULL: [[COMPLEX_LIB_CALL]]: +// OGCG-FULL: %[[CALL_RESULT:.*]] = call noundef <2 x float> @__mulsc3(float noundef %[[A_REAL]], float noundef %[[A_IMAG]], float noundef %[[B_REAL]], float noundef %[[B_IMAG]]) +// OGCG-FULL: store <2 x float> %[[CALL_RESULT]], ptr %[[COMPLEX_CALL_ADDR]], align 4 +// OGCG-FULL: %[[COMPLEX_CALL_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_CALL_ADDR]], i32 0, i32 0 +// OGCG-FULL: %[[COMPLEX_CALL_REAL:.*]] = load float, ptr %[[COMPLEX_CALL_REAL_PTR]], align 4 +// OGCG-FULL: %[[COMPLEX_CALL_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[COMPLEX_CALL_ADDR]], i32 0, i32 1 +// OGCG-FULL: %[[COMPLEX_CALL_IMAG:.*]] = load float, ptr %[[COMPLEX_CALL_IMAG_PTR]], align 4 +// OGCG-FULL: br label %[[END_LABEL]] +// OGCG-FULL: [[END_LABEL]]: +// OGCG-FULL: %[[FINAL_REAL:.*]] = phi float [ %[[C_REAL]], %[[ENTRY:.*]] ], [ %[[C_REAL]], %[[COMPLEX_IS_IMAG_NAN]] ], [ %[[COMPLEX_CALL_REAL]], %[[COMPLEX_LIB_CALL]] ] +// OGCG-FULL: %[[FINAL_IMAG:.*]] = phi float [ %[[C_IMAG]], %[[ENTRY]] ], [ %[[C_IMAG]], %[[COMPLEX_IS_IMAG_NAN]] ], [ %[[COMPLEX_CALL_IMAG]], %[[COMPLEX_LIB_CALL]] ] +// OGCG-FULL: %[[C_REAL_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 0 +// OGCG-FULL: %[[C_IMAG_PTR:.*]] = getelementptr inbounds nuw { float, float }, ptr %[[C_ADDR]], i32 0, i32 1 +// OGCG-FULL: store float %[[FINAL_REAL]], ptr %[[C_REAL_PTR]], align 4 +// OGCG-FULL: store float %[[FINAL_IMAG]], ptr %[[C_IMAG_PTR]], align 4 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits