Skip to content

Commit f781328

Browse files
ghehglanza
authored andcommitted
[CIR][CIRGen][Builtin][Neon] Lower neon_vext_v and neon_vextq_v (llvm#951)
as title. There are two highlights of the PR 1. The PR introduced a new test file to cover neon intrinsics that move data, which is a big category. This would the 5th neon test file. And we're committed to keep total number of neon test files within 6. This file uses another opt option instcombine, which makes test LLVM code more concise, and our -fclangir generated LLVM code would be identical to OG with this. It looks like OG did some instcombine optimization. 2. `getIntFromMLIRValue` helper function could be substituted by [`mlir::cir::IntAttr getConstOpIntAttr` in CIRGenAtomic.cpp](https://github.com/llvm/clangir/blob/24b24557c98d1c031572a567b658cfb6254f8a89/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp#L337). The function `mlir::cir::IntAttr getConstOpIntAttr` is doing more than `getIntFromMLIRValue`, and there is FIXME in the comment, so not sure if we should just use `mlir::cir::IntAttr getConstOpIntAttr`, either is fine with me.
1 parent c61da86 commit f781328

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,6 +2195,14 @@ mlir::Value buildNeonCall(unsigned int builtinID, CIRGenFunction &cgf,
21952195
}
21962196
}
21972197

2198+
/// Get integer from a mlir::Value that is an int constant or a constant op.
2199+
static int64_t getIntValueFromConstOp(mlir::Value val) {
2200+
auto constOp = mlir::cast<mlir::cir::ConstantOp>(val.getDefiningOp());
2201+
return (mlir::cast<mlir::cir::IntAttr>(constOp.getValue()))
2202+
.getValue()
2203+
.getSExtValue();
2204+
}
2205+
21982206
mlir::Value CIRGenFunction::buildCommonNeonBuiltinExpr(
21992207
unsigned builtinID, unsigned llvmIntrinsic, unsigned altLLVMIntrinsic,
22002208
const char *nameHint, unsigned modifier, const CallExpr *e,
@@ -2239,6 +2247,18 @@ mlir::Value CIRGenFunction::buildCommonNeonBuiltinExpr(
22392247
// In CIR, integral cast op supports vector of int type truncating.
22402248
return builder.createIntCast(ops[0], ty);
22412249
}
2250+
case NEON::BI__builtin_neon_vext_v:
2251+
case NEON::BI__builtin_neon_vextq_v: {
2252+
int cv = getIntValueFromConstOp(ops[2]);
2253+
llvm::SmallVector<int64_t, 16> indices;
2254+
for (unsigned i = 0, e = vTy.getSize(); i != e; ++i)
2255+
indices.push_back(i + cv);
2256+
2257+
ops[0] = builder.createBitcast(ops[0], ty);
2258+
ops[1] = builder.createBitcast(ops[1], ty);
2259+
return builder.createVecShuffle(getLoc(e->getExprLoc()), ops[0], ops[1],
2260+
indices);
2261+
}
22422262
}
22432263

22442264
// This second switch is for the intrinsics that might have a more generic
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -target-feature +neon \
2+
// RUN: -fclangir -disable-O0-optnone -fno-clangir-call-conv-lowering \
3+
// RUN: -flax-vector-conversions=none -emit-cir -o %t.cir %s
4+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
5+
// XFAIL: *
6+
7+
// RUN: %clang_cc1 -triple aarch64-none-linux-android24 -target-feature +neon \
8+
// RUN: -fclangir -disable-O0-optnone -fno-clangir-call-conv-lowering \
9+
// RUN: -flax-vector-conversions=none -emit-llvm -o - %s \
10+
// RUN: | opt -S -passes=instcombine,mem2reg,simplifycfg -o %t.ll
11+
// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
12+
13+
// REQUIRES: aarch64-registered-target || arm-registered-target
14+
15+
// This test file contains test cases for the intrinsics that move data between
16+
// registers and vectors, such as mov, get, set, and ext. We dedicate this file
17+
// to them becuase they are many. The file neon.c covers some such intrinsics
18+
// that are not in this file.
19+
20+
#include <arm_neon.h>
21+
22+
int8x8_t test_vext_s8(int8x8_t a, int8x8_t b) {
23+
return vext_s8(a, b, 2);
24+
25+
// CIR-LABEL: vext_s8
26+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s8i x 8>)
27+
// CIR-SAME: [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i,
28+
// CIR-SAME: #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i,
29+
// CIR-SAME: #cir.int<8> : !s32i, #cir.int<9> : !s32i] : !cir.vector<!s8i x 8>
30+
31+
// LLVM: {{.*}}test_vext_s8(<8 x i8>{{.*}}[[A:%.*]], <8 x i8>{{.*}}[[B:%.*]])
32+
// LLVM: [[RES:%.*]] = shufflevector <8 x i8> [[A]], <8 x i8> [[B]],
33+
// LLVM-SAME: <8 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9>
34+
// LLVM: ret <8 x i8> [[RES]]
35+
}
36+
37+
int8x16_t test_vextq_s8(int8x16_t a, int8x16_t b) {
38+
return vextq_s8(a, b, 2);
39+
40+
// CIR-LABEL: vextq_s8
41+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s8i x 16>)
42+
// CIR-SAME: [#cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i,
43+
// CIR-SAME: #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i,
44+
// CIR-SAME: #cir.int<8> : !s32i, #cir.int<9> : !s32i, #cir.int<10> : !s32i,
45+
// CIR-SAME: #cir.int<11> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i,
46+
// CIR-SAME: #cir.int<14> : !s32i, #cir.int<15> : !s32i, #cir.int<16> : !s32i,
47+
// CIR-SAME: #cir.int<17> : !s32i] : !cir.vector<!s8i x 16>
48+
49+
// LLVM: {{.*}}test_vextq_s8(<16 x i8>{{.*}}[[A:%.*]], <16 x i8>{{.*}}[[B:%.*]])
50+
// LLVM: [[RES:%.*]] = shufflevector <16 x i8> [[A]], <16 x i8> [[B]],
51+
// LLVM-SAME: <16 x i32> <i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9
52+
// LLVM-SAME: i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16, i32 17>
53+
// LLVM: ret <16 x i8> [[RES]]
54+
}
55+
56+
int16x4_t test_vext_s16(int16x4_t a, int16x4_t b) {
57+
return vext_s16(a, b, 3);
58+
59+
// CIR-LABEL: vext_s16
60+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s16i x 4>)
61+
// CIR-SAME: [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i,
62+
// CIR-SAME: #cir.int<6> : !s32i] : !cir.vector<!s16i x 4>
63+
64+
// LLVM: {{.*}}test_vext_s16(<4 x i16>{{.*}}[[A:%.*]], <4 x i16>{{.*}}[[B:%.*]])
65+
// LLVM: [[RES:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[B]],
66+
// LLVM-SAME: <4 x i32> <i32 3, i32 4, i32 5, i32 6>
67+
// LLVM: ret <4 x i16> [[RES]]
68+
}
69+
70+
int16x8_t test_vextq_s16(int16x8_t a, int16x8_t b) {
71+
return vextq_s16(a, b, 3);
72+
73+
// CIR-LABEL: vextq_s16
74+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s16i x 8>)
75+
// CIR-SAME: [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i,
76+
// CIR-SAME: #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : !s32i,
77+
// CIR-SAME: #cir.int<9> : !s32i, #cir.int<10> : !s32i] : !cir.vector<!s16i x 8>
78+
79+
// LLVM: {{.*}}test_vextq_s16(<8 x i16>{{.*}}[[A:%.*]], <8 x i16>{{.*}}[[B:%.*]])
80+
// LLVM: [[RES:%.*]] = shufflevector <8 x i16> [[A]], <8 x i16> [[B]],
81+
// LLVM-SAME: <8 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10>
82+
// LLVM: ret <8 x i16> [[RES]]
83+
}
84+
85+
86+
uint16x4_t test_vext_u16(uint16x4_t a, uint16x4_t b) {
87+
return vext_u16(a, b, 3);
88+
89+
// CIR-LABEL: vext_u16
90+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!u16i x 4>)
91+
// CIR-SAME: [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i,
92+
// CIR-SAME: #cir.int<6> : !s32i] : !cir.vector<!u16i x 4>
93+
94+
// LLVM: {{.*}}test_vext_u16(<4 x i16>{{.*}}[[A:%.*]], <4 x i16>{{.*}}[[B:%.*]])
95+
// LLVM: [[RES:%.*]] = shufflevector <4 x i16> [[A]], <4 x i16> [[B]],
96+
// LLVM-SAME: <4 x i32> <i32 3, i32 4, i32 5, i32 6>
97+
// LLVM: ret <4 x i16> [[RES]]
98+
}
99+
100+
uint16x8_t test_vextq_u16(uint16x8_t a, uint16x8_t b) {
101+
return vextq_u16(a, b, 3);
102+
103+
// CIR-LABEL: vextq_u16
104+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!u16i x 8>)
105+
// CIR-SAME: [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i,
106+
// CIR-SAME: #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : !s32i,
107+
// CIR-SAME: #cir.int<9> : !s32i, #cir.int<10> : !s32i] : !cir.vector<!u16i x 8>
108+
109+
// LLVM: {{.*}}test_vextq_u16(<8 x i16>{{.*}}[[A:%.*]], <8 x i16>{{.*}}[[B:%.*]])
110+
// LLVM: [[RES:%.*]] = shufflevector <8 x i16> [[A]], <8 x i16> [[B]],
111+
// LLVM-SAME: <8 x i32> <i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10>
112+
// LLVM: ret <8 x i16> [[RES]]
113+
}
114+
115+
int32x2_t test_vext_s32(int32x2_t a, int32x2_t b) {
116+
return vext_s32(a, b, 1);
117+
118+
// CIR-LABEL: vext_s32
119+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s32i x 2>)
120+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i] : !cir.vector<!s32i x 2>
121+
122+
// LLVM: {{.*}}test_vext_s32(<2 x i32>{{.*}}[[A:%.*]], <2 x i32>{{.*}}[[B:%.*]])
123+
// LLVM: [[RES:%.*]] = shufflevector <2 x i32> [[A]], <2 x i32> [[B]],
124+
// LLVM-SAME: <2 x i32> <i32 1, i32 2>
125+
// LLVM: ret <2 x i32> [[RES]]
126+
}
127+
128+
int32x4_t test_vextq_s32(int32x4_t a, int32x4_t b) {
129+
return vextq_s32(a, b, 1);
130+
131+
// CIR-LABEL: vextq_s32
132+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s32i x 4>)
133+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i,
134+
// CIR-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i] : !cir.vector<!s32i x 4>
135+
136+
// LLVM: {{.*}}test_vextq_s32(<4 x i32>{{.*}}[[A:%.*]], <4 x i32>{{.*}}[[B:%.*]])
137+
// LLVM: [[RES:%.*]] = shufflevector <4 x i32> [[A]], <4 x i32> [[B]],
138+
// LLVM-SAME: <4 x i32> <i32 1, i32 2, i32 3, i32 4>
139+
// LLVM: ret <4 x i32> [[RES]]
140+
}
141+
142+
int64x1_t test_vext_s64(int64x1_t a, int64x1_t b) {
143+
return vext_s64(a, b, 0);
144+
145+
// CIR-LABEL: vext_s64
146+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s64i x 1>)
147+
// CIR-SAME: [#cir.int<0> : !s32i] : !cir.vector<!s64i x 1>
148+
149+
// LLVM: {{.*}}test_vext_s64(<1 x i64>{{.*}}[[A:%.*]], <1 x i64>{{.*}}[[B:%.*]])
150+
// LLVM: ret <1 x i64> [[A]]
151+
}
152+
153+
int64x2_t test_vextq_s64(int64x2_t a, int64x2_t b) {
154+
return vextq_s64(a, b, 1);
155+
156+
// CIR-LABEL: vextq_s64
157+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!s64i x 2>)
158+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i] : !cir.vector<!s64i x 2>
159+
160+
// LLVM: {{.*}}test_vextq_s64(<2 x i64>{{.*}}[[A:%.*]], <2 x i64>{{.*}}[[B:%.*]])
161+
// LLVM: [[RES:%.*]] = shufflevector <2 x i64> [[A]], <2 x i64> [[B]],
162+
// LLVM-SAME: <2 x i32> <i32 1, i32 2>
163+
// LLVM: ret <2 x i64> [[RES]]
164+
}
165+
166+
float32x2_t test_vext_f32(float32x2_t a, float32x2_t b) {
167+
return vext_f32(a, b, 1);
168+
169+
// CIR-LABEL: vext_f32
170+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!cir.float x 2>)
171+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i] : !cir.vector<!cir.float x 2>
172+
173+
// LLVM: {{.*}}test_vext_f32(<2 x float>{{.*}}[[A:%.*]], <2 x float>{{.*}}[[B:%.*]])
174+
// LLVM: [[RES:%.*]] = shufflevector <2 x float> [[A]], <2 x float> [[B]],
175+
// LLVM-SAME: <2 x i32> <i32 1, i32 2>
176+
// LLVM: ret <2 x float> [[RES]]
177+
}
178+
179+
float32x4_t test_vextq_f32(float32x4_t a, float32x4_t b) {
180+
return vextq_f32(a, b, 1);
181+
182+
// CIR-LABEL: vextq_f32
183+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!cir.float x 4>)
184+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i,
185+
// CIR-SAME: #cir.int<4> : !s32i] : !cir.vector<!cir.float x 4>
186+
187+
// LLVM: {{.*}}test_vextq_f32(<4 x float>{{.*}}[[A:%.*]], <4 x float>{{.*}}[[B:%.*]])
188+
// LLVM: [[RES:%.*]] = shufflevector <4 x float> [[A]], <4 x float> [[B]],
189+
// LLVM-SAME: <4 x i32> <i32 1, i32 2, i32 3, i32 4>
190+
// LLVM: ret <4 x float> [[RES]]
191+
}
192+
193+
194+
float64x1_t test_vext_f64(float64x1_t a, float64x1_t b) {
195+
return vext_f64(a, b, 0);
196+
197+
// CIR-LABEL: vext_f64
198+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!cir.double x 1>)
199+
// CIR-SAME: [#cir.int<0> : !s32i] : !cir.vector<!cir.double x 1>
200+
201+
// LLVM: {{.*}}test_vext_f64(<1 x double>{{.*}}[[A:%.*]], <1 x double>{{.*}}[[B:%.*]])
202+
// LLVM: ret <1 x double> [[A]]
203+
}
204+
205+
float64x2_t test_vextq_f64(float64x2_t a, float64x2_t b) {
206+
return vextq_f64(a, b, 1);
207+
208+
// CIR-LABEL: vextq_f64
209+
// CIR: {{%.*}}= cir.vec.shuffle({{%.*}}, {{%.*}} : !cir.vector<!cir.double x 2>)
210+
// CIR-SAME: [#cir.int<1> : !s32i, #cir.int<2> : !s32i] : !cir.vector<!cir.double x 2>
211+
212+
// LLVM: {{.*}}test_vextq_f64(<2 x double>{{.*}}[[A:%.*]], <2 x double>{{.*}}[[B:%.*]])
213+
// LLVM: [[RES:%.*]] = shufflevector <2 x double> [[A]], <2 x double> [[B]],
214+
// LLVM-SAME: <2 x i32> <i32 1, i32 2>
215+
// LLVM: ret <2 x double> [[RES]]
216+
}

0 commit comments

Comments
 (0)