Skip to content

Commit cb496ce

Browse files
LuhaocongPriyanshu3820
authored andcommitted
[CIR] Upstream CIR codegen for lzcnt and tzcnt x86 builtins (llvm#168479)
Support CIR codegen for x86 builtins `__builtin_ia32_lzcnt` and `__builtin_ia32_tzcnt`.
1 parent 3fa2223 commit cb496ce

File tree

3 files changed

+132
-3
lines changed

3 files changed

+132
-3
lines changed

clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,26 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
121121
return emitIntrinsicCallOp(*this, expr, "x86.sse.sfence", voidTy);
122122
case X86::BI_mm_prefetch:
123123
case X86::BI__rdtsc:
124-
case X86::BI__builtin_ia32_rdtscp:
124+
case X86::BI__builtin_ia32_rdtscp: {
125+
cgm.errorNYI(expr->getSourceRange(),
126+
std::string("unimplemented X86 builtin call: ") +
127+
getContext().BuiltinInfo.getName(builtinID));
128+
return {};
129+
}
125130
case X86::BI__builtin_ia32_lzcnt_u16:
126131
case X86::BI__builtin_ia32_lzcnt_u32:
127-
case X86::BI__builtin_ia32_lzcnt_u64:
132+
case X86::BI__builtin_ia32_lzcnt_u64: {
133+
mlir::Value isZeroPoison = builder.getFalse(getLoc(expr->getExprLoc()));
134+
return emitIntrinsicCallOp(*this, expr, "ctlz", ops[0].getType(),
135+
mlir::ValueRange{ops[0], isZeroPoison});
136+
}
128137
case X86::BI__builtin_ia32_tzcnt_u16:
129138
case X86::BI__builtin_ia32_tzcnt_u32:
130-
case X86::BI__builtin_ia32_tzcnt_u64:
139+
case X86::BI__builtin_ia32_tzcnt_u64: {
140+
mlir::Value isZeroPoison = builder.getFalse(getLoc(expr->getExprLoc()));
141+
return emitIntrinsicCallOp(*this, expr, "cttz", ops[0].getType(),
142+
mlir::ValueRange{ops[0], isZeroPoison});
143+
}
131144
case X86::BI__builtin_ia32_undef128:
132145
case X86::BI__builtin_ia32_undef256:
133146
case X86::BI__builtin_ia32_undef512:
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
4+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
5+
6+
// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
7+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
8+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
9+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
10+
11+
// RUN: %clang_cc1 -x c -ffreestanding -triple=x86_64-unknown-linux -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefix=OGCG
12+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple=x86_64-unknown-linux -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefix=OGCG
13+
14+
// This test mimics clang/test/CodeGen/X86/bmi-builtins.c, which eventually
15+
// CIR shall be able to support fully.
16+
17+
#include <immintrin.h>
18+
19+
unsigned short test__tzcnt_u16(unsigned short __X) {
20+
// CIR-LABEL: __tzcnt_u16
21+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "cttz" {{%.*}} : (!u16i, !cir.bool) -> !u16i
22+
// LLVM-LABEL: __tzcnt_u16
23+
// LLVM: i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
24+
// OGCG-LABEL: __tzcnt_u16
25+
// OGCG: i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false)
26+
return __tzcnt_u16(__X);
27+
}
28+
29+
unsigned int test__tzcnt_u32(unsigned int __X) {
30+
// CIR-LABEL: __tzcnt_u32
31+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "cttz" {{%.*}} : (!u32i, !cir.bool) -> !u32i
32+
// LLVM-LABEL: __tzcnt_u32
33+
// LLVM: i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
34+
// OGCG-LABEL: __tzcnt_u32
35+
// OGCG: i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false)
36+
return __tzcnt_u32(__X);
37+
}
38+
39+
#ifdef __x86_64__
40+
unsigned long long test__tzcnt_u64(unsigned long long __X) {
41+
// CIR-LABEL: __tzcnt_u64
42+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "cttz" {{%.*}} : (!u64i, !cir.bool) -> !u64i
43+
// LLVM-LABEL: __tzcnt_u64
44+
// LLVM: i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
45+
// OGCG-LABEL: __tzcnt_u64
46+
// OGCG: i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false)
47+
return __tzcnt_u64(__X);
48+
}
49+
#endif
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
4+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
5+
6+
// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
7+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
8+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
9+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
10+
11+
// RUN: %clang_cc1 -x c -ffreestanding -triple=x86_64-unknown-linux -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefix=OGCG
12+
// RUN: %clang_cc1 -x c++ -ffreestanding -triple=x86_64-unknown-linux -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefix=OGCG
13+
14+
// This test mimics clang/test/CodeGen/X86/lzcnt-builtins.c, which eventually
15+
// CIR shall be able to support fully.
16+
17+
#include <immintrin.h>
18+
19+
unsigned int test__lzcnt16(unsigned short __X) {
20+
// CIR-LABEL: __lzcnt16
21+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "ctlz" {{%.*}} : (!u16i, !cir.bool) -> !u16i
22+
// LLVM-LABEL: __lzcnt16
23+
// LLVM: @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
24+
// OGCG-LABEL: __lzcnt16
25+
// OGCG: @llvm.ctlz.i16(i16 %{{.*}}, i1 false)
26+
return __lzcnt16(__X);
27+
}
28+
29+
unsigned int test__lzcnt32(unsigned int __X) {
30+
// CIR-LABEL: __lzcnt32
31+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "ctlz" {{%.*}} : (!u32i, !cir.bool) -> !u32i
32+
// LLVM-LABEL: __lzcnt32
33+
// LLVM: @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
34+
// OGCG-LABEL: __lzcnt32
35+
// OGCG: @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
36+
return __lzcnt32(__X);
37+
}
38+
39+
unsigned long long test__lzcnt64(unsigned long long __X) {
40+
// CIR-LABEL: __lzcnt64
41+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "ctlz" {{%.*}} : (!u64i, !cir.bool) -> !u64i
42+
// LLVM-LABEL: __lzcnt64
43+
// LLVM: @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
44+
// OGCG-LABEL: __lzcnt64
45+
// OGCG: @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
46+
return __lzcnt64(__X);
47+
}
48+
49+
unsigned int test__lzcnt_u32(unsigned int __X) {
50+
// CIR-LABEL: _lzcnt_u32
51+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "ctlz" {{%.*}} : (!u32i, !cir.bool) -> !u32i
52+
// LLVM-LABEL: _lzcnt_u32
53+
// LLVM: @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
54+
// OGCG-LABEL: _lzcnt_u32
55+
// OGCG: @llvm.ctlz.i32(i32 %{{.*}}, i1 false)
56+
return _lzcnt_u32(__X);
57+
}
58+
59+
unsigned long long test__lzcnt_u64(unsigned long long __X) {
60+
// CIR-LABEL: _lzcnt_u64
61+
// CIR: {{%.*}} = cir.call_llvm_intrinsic "ctlz" {{%.*}} : (!u64i, !cir.bool) -> !u64i
62+
// LLVM-LABEL: _lzcnt_u64
63+
// LLVM: @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
64+
// OGCG-LABEL: _lzcnt_u64
65+
// OGCG: @llvm.ctlz.i64(i64 %{{.*}}, i1 false)
66+
return _lzcnt_u64(__X);
67+
}

0 commit comments

Comments
 (0)