diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index c8b9a0a03cbf..f1275a472f3c 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -397,6 +397,11 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { return create(loc, dst, src, len); } + cir::SignBitOp createSignBit(mlir::Location loc, mlir::Value val) { + auto resTy = cir::IntType::get(getContext(), 32, true); + return create(loc, resTy, val); + } + mlir::Value createSub(mlir::Value lhs, mlir::Value rhs, bool hasNUW = false, bool hasNSW = false) { auto op = create(lhs.getLoc(), lhs.getType(), diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index a48a99ba95e0..c4413fb311d5 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -5127,4 +5127,17 @@ def AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", let hasVerifier = 0; } +def SignBitOp : CIR_Op<"signbit", [Pure]> { + let summary = "Checks the sign of a floating-point number"; + let description = [{ + It returns a non-zero value (true) if the number is negative + and zero (false) if the number is positive or zero. + }]; + let arguments = (ins CIR_AnyFloat:$input); + let results = (outs SInt32:$res); + let assemblyFormat = [{ + $input attr-dict `:` type($input) `->` qualified(type($res)) + }]; +} + #endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index afc1e6b4f148..b9f81fcd3e22 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -228,6 +228,7 @@ struct MissingFeatures { static bool xray() { return false; } static bool emitConstrainedFPCall() { return false; } static bool emitEmptyRecordCheck() { return false; } + static bool isPPC_FP128Ty() { return false; } // Inline assembly static bool asmGoto() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 6809c3ad5ce3..2f217f5c31f0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -216,6 +216,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()); + auto ret = CGF.getBuilder().createSignBit(loc, val); + return ret->getResult(0); +} + static Address checkAtomicAlignment(CIRGenFunction &CGF, const CallExpr *E) { ASTContext &ctx = CGF.getContext(); Address ptr = CGF.emitPointerWithAlignment(E->getArg(0)); @@ -1700,8 +1707,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: - case Builtin::BI__builtin_signbitl: - llvm_unreachable("BI__builtin_signbit like NYI"); + case Builtin::BI__builtin_signbitl: { + auto loc = getLoc(E->getBeginLoc()); + return RValue::get(builder.createZExtOrBitCast( + loc, emitSignBit(loc, *this, emitScalarExpr(E->getArg(0))), + ConvertType(E->getType()))); + } case Builtin::BI__warn_memset_zero_len: llvm_unreachable("BI__warn_memset_zero_len NYI"); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 2ae12be6efbd..5272c03ddec6 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -4304,6 +4304,37 @@ class CIRAbsOpLowering : public mlir::OpConversionPattern { return mlir::success(); } }; +class CIRSignBitOpLowering : public mlir::OpConversionPattern { +public: + using OpConversionPattern::OpConversionPattern; + + mlir::LogicalResult + matchAndRewrite(cir::SignBitOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + assert(!::cir::MissingFeatures::isPPC_FP128Ty()); + + mlir::DataLayout layout(op->getParentOfType()); + int width = layout.getTypeSizeInBits(op.getInput().getType()); + if (auto longDoubleType = + mlir::dyn_cast(op.getInput().getType())) { + if (mlir::isa(longDoubleType.getUnderlying())) { + // see https://github.com/llvm/clangir/issues/1057 + llvm_unreachable("NYI"); + } + } + auto intTy = mlir::IntegerType::get(rewriter.getContext(), width); + auto bitcast = rewriter.create(op->getLoc(), intTy, + adaptor.getInput()); + auto zero = rewriter.create(op->getLoc(), intTy, 0); + auto cmpResult = rewriter.create( + op.getLoc(), mlir::LLVM::ICmpPredicate::slt, bitcast.getResult(), zero); + auto converted = rewriter.create( + op.getLoc(), mlir::IntegerType::get(rewriter.getContext(), 32), + cmpResult); + rewriter.replaceOp(op, converted); + return mlir::success(); + } +}; void populateCIRToLLVMConversionPatterns( mlir::RewritePatternSet &patterns, mlir::TypeConverter &converter, @@ -4352,7 +4383,7 @@ void populateCIRToLLVMConversionPatterns( CIRAssumeLowering, CIRAssumeAlignedLowering, CIRAssumeSepStorageLowering, CIRBaseClassAddrOpLowering, CIRDerivedClassAddrOpLowering, CIRVTTAddrPointOpLowering, CIRIsFPClassOpLowering, CIRAbsOpLowering, - CIRMemMoveOpLowering, CIRMemsetOpLowering + CIRMemMoveOpLowering, CIRMemsetOpLowering, CIRSignBitOpLowering #define GET_BUILTIN_LOWERING_LIST #include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc" #undef GET_BUILTIN_LOWERING_LIST diff --git a/clang/test/CIR/CodeGen/builtin-signbit.c b/clang/test/CIR/CodeGen/builtin-signbit.c new file mode 100644 index 000000000000..78b25ae4bf9e --- /dev/null +++ b/clang/test/CIR/CodeGen/builtin-signbit.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -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 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +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 + __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 + __builtin_signbitf(val); +}