Skip to content

Commit d0f75b4

Browse files
committed
[CIR][CIRGen] Support __builtin_isinf_sign
This patch adds support for `__builtin_isinf_sign`. The implementation has several limitations that result in discrepancies between the generated LLVM IR and the expected output. Firstly, it uses `IsFPClass` to determine if a value is infinite, whereas the original CGBuiltin implementation used direct comparisons with infinity constants. Secondly, due to #480, there are numerous unnecessary type conversions occurring, such as converting from i1 to i8 and then back to i1. Additionally, `SignBitOp` cannot set the return type to `CIR_BoolType`, as doing so would lead to failures during the lowering to LLVM IR.
1 parent da601b3 commit d0f75b4

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,10 @@ class CIRBaseBuilderTy : public mlir::OpBuilder {
489489
return createCast(cir::CastKind::int_to_ptr, src, newTy);
490490
}
491491

492+
mlir::Value createIntToBoolCast(mlir::Value v) {
493+
return createCast(cir::CastKind::int_to_bool, v, getBoolTy());
494+
}
495+
492496
mlir::Value createGetMemberOp(mlir::Location &loc, mlir::Value structPtr,
493497
const char *fldName, unsigned idx) {
494498

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,27 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
13851385
case Builtin::BI__builtin_matrix_column_major_store:
13861386
llvm_unreachable("BI__builtin_matrix_column_major_store NYI");
13871387

1388+
case Builtin::BI__builtin_isinf_sign: {
1389+
CIRGenFunction::CIRGenFPOptionsRAII FPOptsRAII(*this, E);
1390+
mlir::Location Loc = getLoc(E->getBeginLoc());
1391+
mlir::Value V = emitScalarExpr(E->getArg(0));
1392+
mlir::Value IsInf = builder.createIsFPClass(Loc, V, FPClassTest::fcInf);
1393+
// FIMXE: CIR now will convert cir::BoolType to i8 type unconditionally.
1394+
// see https://github.com/llvm/clangir/issues/480
1395+
// fix the issue can eliminate lots of redundant cast instruction
1396+
// for IsInf, i1 -> i8 -> i1
1397+
// for IsNeg, i1 -> i8 -> i32 -> i1
1398+
mlir::Value IsNeg = emitSignBit(Loc, *this, V);
1399+
IsNeg = builder.createIntToBoolCast(IsNeg);
1400+
auto IntTy = ConvertType(E->getType());
1401+
auto Zero = builder.getNullValue(IntTy, Loc);
1402+
auto One = builder.getConstant(Loc, cir::IntAttr::get(IntTy, 1));
1403+
auto NegativeOne = builder.getConstant(Loc, cir::IntAttr::get(IntTy, -1));
1404+
auto SignResult = builder.createSelect(Loc, IsNeg, NegativeOne, One);
1405+
auto Result = builder.createSelect(Loc, IsInf, SignResult, Zero);
1406+
return RValue::get(Result);
1407+
}
1408+
13881409
case Builtin::BI__builtin_flt_rounds:
13891410
llvm_unreachable("BI__builtin_flt_rounds NYI");
13901411

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll
4+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
5+
6+
int test_float_isinf_sign(float x) {
7+
// CIR-LABEL: test_float_isinf_sign
8+
// CIR: %[[TMP0:.*]] = cir.load %{{.*}} : !cir.ptr<!cir.float>, !cir.float
9+
// CIR: %[[IS_INF:.*]] = cir.is_fp_class %[[TMP0]], 516 : (!cir.float) -> !cir.bool
10+
// CIR: %[[TMP1:.*]] = cir.signbit %[[TMP0]] : !cir.float -> !s32i
11+
// CIR: %[[IS_NEG:.*]] = cir.cast(int_to_bool, %[[TMP1]] : !s32i), !cir.bool
12+
// CIR: %[[C_0:.*]] = cir.const #cir.int<0> : !s32i
13+
// CIR: %[[C_1:.*]] = cir.const #cir.int<1> : !s32i
14+
// CIR: %[[C_m1:.*]] = cir.const #cir.int<-1> : !s32i
15+
// CIR: %[[TMP4:.*]] = cir.select if %[[IS_NEG]] then %[[C_m1]] else %[[C_1]] : (!cir.bool, !s32i, !s32i) -> !s32i
16+
// CIR: %10 = cir.select if %[[IS_INF]] then %[[TMP4]] else %[[C_0]] : (!cir.bool, !s32i, !s32i) -> !s32i
17+
18+
// LLVM-LABEL: test_float_isinf_sign
19+
// LLVM: %[[TMP0:.*]] = load float, ptr %{{.*}}
20+
// LLVM: %[[IS_INF:.*]] = call i1 @llvm.is.fpclass.f32(float %[[TMP0]], i32 516)
21+
// LLVM: %[[IS_INF_I8:.*]] = zext i1 %[[IS_INF]] to i8
22+
// LLVM: %[[TMP1:.*]] = bitcast float %[[TMP0]] to i32
23+
// LLVM: %[[IS_NEG:.*]] = icmp slt i32 %[[TMP1]], 0
24+
// FIXME: eliminate the redundant instruction
25+
// [[IS_NEG]] changes bool -> i8 -> i32 -> i1
26+
// LLVM: %[[TMP2:.*]] = select i1 %{{.*}}, i32 -1, i32 1
27+
// LLVM: %[[IS_INF_I1:.*]] = trunc i8 %[[IS_INF_I8]] to i1
28+
// LLVM: %{{.*}} = select i1 %[[IS_INF_I1]], i32 %[[TMP2]], i32 0
29+
return __builtin_isinf_sign(x);
30+
}

0 commit comments

Comments
 (0)