Skip to content

Commit 7563e31

Browse files
authored
[CIR] Implement lowering of int-to-bool casts (#132996)
Lowering of int-to-bool casts had been left as NYI because the incubator implemented it by lowering to cir.cmp, which hasn't been upstreamed yet, but there is no reason this cast can't be lowered directly to LLVM's compare operation when we're lowering directly to the LLVM dialect. This change lowers the cast directly to an LLVM compare to zero.
1 parent e6dda9c commit 7563e31

File tree

3 files changed

+84
-7
lines changed

3 files changed

+84
-7
lines changed

clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -383,13 +383,13 @@ mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
383383
break;
384384
}
385385
case cir::CastKind::int_to_bool: {
386-
assert(!cir::MissingFeatures::opCmp());
387-
mlir::Type dstType = castOp.getResult().getType();
388-
mlir::Type llvmDstType = getTypeConverter()->convertType(dstType);
389-
auto zeroBool = rewriter.create<mlir::LLVM::ConstantOp>(
390-
castOp.getLoc(), llvmDstType, mlir::BoolAttr::get(getContext(), false));
391-
rewriter.replaceOp(castOp, zeroBool);
392-
return castOp.emitError() << "NYI int_to_bool cast";
386+
mlir::Value llvmSrcVal = adaptor.getOperands().front();
387+
mlir::Value zeroInt = rewriter.create<mlir::LLVM::ConstantOp>(
388+
castOp.getLoc(), llvmSrcVal.getType(),
389+
mlir::IntegerAttr::get(llvmSrcVal.getType(), 0));
390+
rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
391+
castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroInt);
392+
break;
393393
}
394394
case cir::CastKind::integral: {
395395
mlir::Type srcType = castOp.getSrc().getType();
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
3+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
4+
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
5+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
6+
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
7+
8+
bool f1(unsigned char c) {
9+
return c;
10+
}
11+
12+
// CIR: cir.func @f1
13+
// CIR: cir.cast(int_to_bool, %{{.*}} : !u8i), !cir.bool
14+
15+
// Note: The full zext/store/load/trunc sequence is checked here to show what
16+
// CIR is being lowered to. There's no need to check it for every function since
17+
// the lowering is the same for all of them.
18+
19+
// LLVM: define i1 @f1
20+
// LLVM: %[[CMP:.*]] = icmp ne i8 %4, 0
21+
// LLVM: %[[ZEXT:.*]] = zext i1 %[[CMP]] to i8
22+
// LLVM: store i8 %[[ZEXT]], ptr %{{.*}}
23+
// LLVM: %[[LOAD:.*]] = load i8, ptr %{{.*}}
24+
// LLVM: %[[TRUNC:.*]] = trunc i8 %[[LOAD]] to i1
25+
// LLVM: ret i1 %[[TRUNC]]
26+
27+
// OGCG: define{{.*}} i1 @_Z2f1h
28+
// OGCG: %[[CMP:.*]] = icmp ne i8 %{{.*}}, 0
29+
// OGCG: ret i1 %[[CMP]]
30+
31+
bool f2(short s) {
32+
return s;
33+
}
34+
35+
// CIR: cir.func @f2
36+
// CIR: cir.cast(int_to_bool, %{{.*}} : !s16i), !cir.bool
37+
38+
// LLVM: define i1 @f2
39+
// LLVM: %[[CMP:.*]] = icmp ne i16 %4, 0
40+
// LLVM: %[[ZEXT:.*]] = zext i1 %[[CMP]] to i8
41+
42+
// OGCG: define{{.*}} i1 @_Z2f2s
43+
// OGCG: %[[CMP:.*]] = icmp ne i16 %{{.*}}, 0
44+
// OGCG: ret i1 %[[CMP]]
45+
46+
bool f3(unsigned u) {
47+
return u;
48+
}
49+
50+
// CIR: cir.func @f3
51+
// CIR: cir.cast(int_to_bool, %{{.*}} : !u32i), !cir.bool
52+
53+
// LLVM: define i1 @f3
54+
// LLVM: %[[CMP:.*]] = icmp ne i32 %4, 0
55+
// LLVM: %[[ZEXT:.*]] = zext i1 %[[CMP]] to i8
56+
57+
// OGCG: define{{.*}} i1 @_Z2f3j
58+
// OGCG: %[[CMP:.*]] = icmp ne i32 %{{.*}}, 0
59+
// OGCG: ret i1 %[[CMP]]
60+
61+
bool f4(long l) {
62+
return l;
63+
}
64+
65+
// CIR: cir.func @f4
66+
// CIR: cir.cast(int_to_bool, %{{.*}} : !s64i), !cir.bool
67+
68+
// LLVM: define i1 @f4
69+
// LLVM: %[[CMP:.*]] = icmp ne i64 %4, 0
70+
// LLVM: %[[ZEXT:.*]] = zext i1 %[[CMP]] to i8
71+
72+
// OGCG: define{{.*}} i1 @_Z2f4l
73+
// OGCG: %[[CMP:.*]] = icmp ne i64 %{{.*}}, 0
74+
// OGCG: ret i1 %[[CMP]]

clang/test/CIR/Lowering/cast.cir

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ module {
4747
%21 = cir.load %20 : !cir.ptr<!s16i>, !s16i
4848
%22 = cir.cast(integral, %21 : !s16i), !u64i
4949
// CHECK: %[[TMP:[0-9]+]] = llvm.sext %{{[0-9]+}} : i16 to i64
50+
%33 = cir.cast(int_to_bool, %arg1 : !s32i), !cir.bool
51+
// CHECK: %[[#ZERO:]] = llvm.mlir.constant(0 : i32) : i32
52+
// CHECK: %[[#CMP:]] = llvm.icmp "ne" %arg1, %[[#ZERO]] : i32
5053

5154
// Pointer casts.
5255
cir.store %16, %6 : !s64i, !cir.ptr<!s64i>

0 commit comments

Comments
 (0)