llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Ayokunle Amodu (ayokunle321) <details> <summary>Changes</summary> This adds CIR codegen and lowering support for `__builtin_isinf_sign`. --- Full diff: https://github.com/llvm/llvm-project/pull/183977.diff 7 Files Affected: - (modified) clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h (+5) - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+17) - (modified) clang/include/clang/CIR/MissingFeatures.h (+1) - (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+24-1) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+29) - (added) clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c (+41) - (added) clang/test/CIR/CodeGenBuiltins/builtin-signbit.cpp (+40) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index efae3d9d894ed..9b14d3ed10a6b 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -544,6 +544,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return cir::VecInsertOp::create(*this, loc, vec, newElt, idxVal); } + cir::SignBitOp createSignBit(mlir::Location loc, mlir::Value val) { + mlir::Type resTy = cir::BoolType::get(getContext()); + return cir::SignBitOp::create(*this, loc, resTy, val); + } + //===--------------------------------------------------------------------===// // Binary Operators //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a5a5197cd3ea6..bde065fb30c30 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -484,6 +484,23 @@ def CIR_ConstantOp : CIR_Op<"const", [ let isLLVMLoweringRecursive = true; } +//===----------------------------------------------------------------------===// +// SignBitOp +//===----------------------------------------------------------------------===// + +def SignBitOp : CIR_Op<"signbit", [Pure]> { + let summary = "Checks the sign of a floating-point number"; + let description = [{ + It returns whether the sign bit (i.e. the highest bit) of the input operand + is set. + }]; + let arguments = (ins CIR_AnyFloatType:$input); + let results = (outs CIR_BoolType:$res); + let assemblyFormat = [{ + $input attr-dict `:` type($input) `->` qualified(type($res)) + }]; +} + //===----------------------------------------------------------------------===// // C/C++ memory order definitions //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index e6a33f56d518f..8c115853fe98a 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -278,6 +278,7 @@ struct MissingFeatures { static bool emitNullabilityCheck() { return false; } static bool emitTypeCheck() { return false; } static bool emitTypeMetadataCodeForVCall() { return false; } + static bool isPPC_FP128Ty() { return false; } // Fast math. static bool fastMathGuard() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index a27e66e0989fa..1de10ec70e91c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -86,6 +86,13 @@ static mlir::Value emitFromInt(CIRGenFunction &cgf, mlir::Value v, QualType t, return v; } +static mlir::Value emitSignBit(mlir::Location loc, CIRGenFunction &cgf, + mlir::Value val) { + assert(!::cir::MissingFeatures::isPPC_FP128Ty()); + cir::SignBitOp returnValue = cgf.getBuilder().createSignBit(loc, val); + return returnValue->getResult(0); +} + static Address checkAtomicAlignment(CIRGenFunction &cgf, const CallExpr *e) { ASTContext &astContext = cgf.getContext(); Address ptr = cgf.emitPointerWithAlignment(e->getArg(0)); @@ -1541,7 +1548,23 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__builtin_masked_store: case Builtin::BI__builtin_masked_compress_store: case Builtin::BI__builtin_masked_scatter: - case Builtin::BI__builtin_isinf_sign: + return errorBuiltinNYI(*this, e, builtinID); + case Builtin::BI__builtin_isinf_sign: { + CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, e); + mlir::Location loc = getLoc(e->getBeginLoc()); + mlir::Value arg = emitScalarExpr(e->getArg(0)); + mlir::Value absArg = cir::FAbsOp::create(builder, loc, arg.getType(), arg); + mlir::Value isInf = + builder.createIsFPClass(loc, absArg, cir::FPClassTest::Infinity); + mlir::Value isNeg = emitSignBit(loc, *this, arg); + auto intTy = convertType(e->getType()); + auto zero = builder.getNullValue(intTy, loc); + auto one = builder.getConstant(loc, cir::IntAttr::get(intTy, 1)); + auto negativeOne = builder.getConstant(loc, cir::IntAttr::get(intTy, -1)); + auto signResult = builder.createSelect(loc, isNeg, negativeOne, one); + auto result = builder.createSelect(loc, isInf, signResult, zero); + return RValue::get(result); + } case Builtin::BI__builtin_flt_rounds: case Builtin::BI__builtin_set_flt_rounds: case Builtin::BI__builtin_fpclassify: diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 3318638b8a03d..d316162508d29 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -835,6 +835,35 @@ mlir::LogicalResult CIRToLLVMIsFPClassOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMSignBitOpLowering::matchAndRewrite( + cir::SignBitOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + assert(!cir::MissingFeatures::isPPC_FP128Ty()); + + mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>()); + int width = layout.getTypeSizeInBits(op.getInput().getType()); + if (auto longDoubleType = + mlir::dyn_cast<cir::LongDoubleType>(op.getInput().getType())) { + if (mlir::isa<cir::FP80Type>(longDoubleType.getUnderlying())) { + // If the underlying type of LongDouble is FP80Type, + // DataLayout::getTypeSizeInBits returns 128. + // See https://github.com/llvm/clangir/issues/1057. + // Set the width to 80 manually. + width = 80; + } + } + mlir::Type intTy = mlir::IntegerType::get(rewriter.getContext(), width); + auto bitcast = mlir::LLVM::BitcastOp::create(rewriter, op->getLoc(), intTy, + adaptor.getInput()); + + auto zero = mlir::LLVM::ConstantOp::create(rewriter, op->getLoc(), intTy, 0); + auto cmpResult = mlir::LLVM::ICmpOp::create(rewriter, op.getLoc(), + mlir::LLVM::ICmpPredicate::slt, + bitcast.getResult(), zero); + rewriter.replaceOp(op, cmpResult); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite( cir::AssumeOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c b/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c new file mode 100644 index 0000000000000..e2a6d97b14480 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-isinf-sign.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.cir.ll +// RUN: FileCheck --input-file=%t.cir.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +int test_float_isinf_sign(float x) { + // CIR-LABEL: test_float_isinf_sign + // CIR: %[[ARG:.*]] = cir.load align(4) %{{.*}} : !cir.ptr<!cir.float>, !cir.float + // CIR: %[[ABS:.*]] = cir.fabs %[[ARG]] : !cir.float + // CIR: %[[IS_INF:.*]] = cir.is_fp_class %[[ABS]], fcInf : (!cir.float) -> !cir.bool + // CIR: %[[IS_NEG:.*]] = cir.signbit %[[ARG]] : !cir.float -> !cir.bool + // CIR: %[[C_0:.*]] = cir.const #cir.int<0> : !s32i + // CIR: %[[C_1:.*]] = cir.const #cir.int<1> : !s32i + // CIR: %[[C_m1:.*]] = cir.const #cir.int<-1> : !s32i + // CIR: %[[SIGN:.*]] = cir.select if %[[IS_NEG]] then %[[C_m1]] else %[[C_1]] : (!cir.bool, !s32i, !s32i) -> !s32i + // CIR: %[[RET:.*]] = cir.select if %[[IS_INF]] then %[[SIGN]] else %[[C_0]] : (!cir.bool, !s32i, !s32i) -> !s32i + // CIR: cir.store %[[RET]], %{{.*}} : !s32i, !cir.ptr<!s32i> + + // LLVM-LABEL: test_float_isinf_sign + // LLVM: %[[ARG:.*]] = load float, ptr %{{.*}} + // LLVM: %[[ABS:.*]] = call float @llvm.fabs.f32(float %[[ARG]]) + // LLVM: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[ABS]], i32 516) + // LLVM: %[[BITCAST:.*]] = bitcast float %[[ARG]] to i32 + // LLVM: %[[IS_NEG:.*]] = icmp slt i32 %[[BITCAST]], 0 + // LLVM: %[[SIGN:.*]] = select i1 %[[IS_NEG]], i32 -1, i32 1 + // LLVM: %[[RET:.*]] = select i1 %[[IS_INF]], i32 %[[SIGN]], i32 0 + // LLVM: store i32 %[[RET]], ptr %{{.*}}, align 4 + + // OGCG-LABEL: test_float_isinf_sign + // OGCG: %[[ARG:.*]] = load float, ptr %{{.*}} + // OGCG: %[[ABS:.*]] = call float @llvm.fabs.f32(float %[[ARG]]) + // OGCG: %[[IS_INF:.*]] = fcmp oeq float %[[ABS]], 0x7FF0000000000000 + // OGCG: %[[BITCAST:.*]] = bitcast float %[[ARG]] to i32 + // OGCG: %[[IS_NEG:.*]] = icmp slt i32 %[[BITCAST]], 0 + // OGCG: %[[SIGN:.*]] = select i1 %[[IS_NEG]], i32 -1, i32 1 + // OGCG: %[[RET:.*]] = select i1 %[[IS_INF]], i32 %[[SIGN]], i32 0 + // OGCG: ret i32 %[[RET]] + return __builtin_isinf_sign(x); +} diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-signbit.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-signbit.cpp new file mode 100644 index 0000000000000..1b568e9adeff0 --- /dev/null +++ b/clang/test/CIR/CodeGenBuiltins/builtin-signbit.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG + +void test_signbit_float(float val) { + // CIR-LABEL: test_signbit_float + // CIR: %{{.+}} = cir.signbit %{{.+}} : !cir.float -> !s32i + + // LLVM-LABEL: test_signbit_float + // LLVM: [[TMP1:%.*]] = bitcast float %{{.+}} to i32 + // LLVM: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 + // LLVM: %{{.+}} = zext i1 [[TMP2]] to i32 + + // OGCG-LABEL: test_signbit_float + // OGCG: [[TMP1:%.*]] = bitcast float %{{.+}} to i32 + // OGCG: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 + // OGCG: %{{.+}} = zext i1 [[TMP2]] to i32 + __builtin_signbit(val); +} + +void test_signbit_double(double val) { + // CIR-LABEL: test_signbit_double + // CIR: %{{.+}} = cir.signbit %{{.+}} : !cir.float -> !s32i + + // LLVM-LABEL: test_signbit_double + // LLVM: [[CONV:%.*]] = fptrunc double %{{.+}} to float + // LLVM: [[TMP1:%.*]] = bitcast float [[CONV]] to i32 + // LLVM: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 + // LLVM: %{{.+}} = zext i1 [[TMP2]] to i32 + + // OGCG-LABEL: test_signbit_double + // OGCG: [[CONV:%.*]] = fptrunc double %{{.+}} to float + // OGCG: [[TMP1:%.*]] = bitcast float [[CONV]] to i32 + // OGCG: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 + // OGCG: %{{.+}} = zext i1 [[TMP2]] to i32 + __builtin_signbitf(val); +} \ No newline at end of file `````````` </details> https://github.com/llvm/llvm-project/pull/183977 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
