Skip to content

Commit 4e175dc

Browse files
[LLVM][IR] Add textual shorthand for specifying constant vector splats.
Add LL parsing for `<N x ty> splat(ty <imm>)` that lowers onto ConstantInt::get() for integer types and ConstantFP::get() for floating-point types. The intent is to extend ConstantInt/FP classes to support vector types rather than redirecting to other constant classes as the get() methods do today. This patch gives IR writers the convenience of using the shorthand today, thus allowing existing tests to be ported.
1 parent c64385c commit 4e175dc

File tree

7 files changed

+142
-0
lines changed

7 files changed

+142
-0
lines changed

llvm/docs/LangRef.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4299,6 +4299,11 @@ constants and smaller complex constants.
42994299
"``< i32 42, i32 11, i32 74, i32 100 >``". Vector constants
43004300
must have :ref:`vector type <t_vector>`, and the number and types of
43014301
elements must match those specified by the type.
4302+
4303+
When creating a vector whose elements have the same constant value, the
4304+
preferred syntax is ``splat (<Ty> Val)``. For example: "``splat (i32 11)``".
4305+
These vector constants must have ::ref:`vector type <t_vector>` with an
4306+
element type that matches the ``splat`` operand.
43024307
**Zero initialization**
43034308
The string '``zeroinitializer``' can be used to zero initialize a
43044309
value to zero of *any* type, including scalar and

llvm/include/llvm/AsmParser/LLParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ namespace llvm {
6464
t_Poison, // No value.
6565
t_EmptyArray, // No value: []
6666
t_Constant, // Value in ConstantVal.
67+
t_ConstantSplat, // Value in ConstantVal.
6768
t_InlineAsm, // Value in FTy/StrVal/StrVal2/UIntVal.
6869
t_ConstantStruct, // Value in ConstantStructElts.
6970
t_PackedConstantStruct // Value in ConstantStructElts.

llvm/include/llvm/AsmParser/LLToken.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ enum Kind {
336336
kw_extractelement,
337337
kw_insertelement,
338338
kw_shufflevector,
339+
kw_splat,
339340
kw_extractvalue,
340341
kw_insertvalue,
341342
kw_blockaddress,

llvm/lib/AsmParser/LLLexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,7 @@ lltok::Kind LLLexer::LexIdentifier() {
698698
KEYWORD(uinc_wrap);
699699
KEYWORD(udec_wrap);
700700

701+
KEYWORD(splat);
701702
KEYWORD(vscale);
702703
KEYWORD(x);
703704
KEYWORD(blockaddress);

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3981,6 +3981,21 @@ bool LLParser::parseValID(ValID &ID, PerFunctionState *PFS, Type *ExpectedTy) {
39813981
return false;
39823982
}
39833983

3984+
case lltok::kw_splat: {
3985+
Lex.Lex();
3986+
if (parseToken(lltok::lparen, "expected '(' after vector splat"))
3987+
return true;
3988+
Constant *C;
3989+
if (parseGlobalTypeAndValue(C))
3990+
return true;
3991+
if (parseToken(lltok::rparen, "expected ')' at end of vector splat"))
3992+
return true;
3993+
3994+
ID.ConstantVal = C;
3995+
ID.Kind = ValID::t_ConstantSplat;
3996+
return false;
3997+
}
3998+
39843999
case lltok::kw_getelementptr:
39854000
case lltok::kw_shufflevector:
39864001
case lltok::kw_insertelement:
@@ -5824,6 +5839,17 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
58245839
"' but expected '" + getTypeString(Ty) + "'");
58255840
V = ID.ConstantVal;
58265841
return false;
5842+
case ValID::t_ConstantSplat:
5843+
if (!Ty->isVectorTy())
5844+
return error(ID.Loc, "vector constant must have vector type");
5845+
if (ID.ConstantVal->getType() != Ty->getScalarType())
5846+
return error(ID.Loc, "constant expression type mismatch: got type '" +
5847+
getTypeString(ID.ConstantVal->getType()) +
5848+
"' but expected '" +
5849+
getTypeString(Ty->getScalarType()) + "'");
5850+
V = ConstantVector::getSplat(cast<VectorType>(Ty)->getElementCount(),
5851+
ID.ConstantVal);
5852+
return false;
58275853
case ValID::t_ConstantStruct:
58285854
case ValID::t_PackedConstantStruct:
58295855
if (StructType *ST = dyn_cast<StructType>(Ty)) {
@@ -5861,6 +5887,7 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
58615887
case ValID::t_APFloat:
58625888
case ValID::t_Undef:
58635889
case ValID::t_Constant:
5890+
case ValID::t_ConstantSplat:
58645891
case ValID::t_ConstantStruct:
58655892
case ValID::t_PackedConstantStruct: {
58665893
Value *V;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
; RUN: rm -rf %t && split-file %s %t
2+
3+
; RUN: not llvm-as < %t/not_a_constant.ll -o /dev/null 2>&1 | FileCheck -check-prefix=NOT_A_CONSTANT %s
4+
; RUN: not llvm-as < %t/not_a_sclar.ll -o /dev/null 2>&1 | FileCheck -check-prefix=NOT_A_SCALAR %s
5+
; RUN: not llvm-as < %t/not_a_vector.ll -o /dev/null 2>&1 | FileCheck -check-prefix=NOT_A_VECTOR %s
6+
; RUN: not llvm-as < %t/wrong_explicit_type.ll -o /dev/null 2>&1 | FileCheck -check-prefix=WRONG_EXPLICIT_TYPE %s
7+
; RUN: not llvm-as < %t/wrong_implicit_type.ll -o /dev/null 2>&1 | FileCheck -check-prefix=WRONG_IMPLICIT_TYPE %s
8+
9+
;--- not_a_constant.ll
10+
; NOT_A_CONSTANT: error: expected instruction opcode
11+
define <4 x i32> @not_a_constant(i32 %a) {
12+
%splat = splat (i32 %a)
13+
ret <vscale x 4 x i32> %splat
14+
}
15+
16+
;--- not_a_sclar.ll
17+
; NOT_A_SCALAR: error: constant expression type mismatch: got type '<1 x i32>' but expected 'i32'
18+
define <4 x i32> @not_a_scalar() {
19+
ret <4 x i32> splat (<1 x i32> <i32 7>)
20+
}
21+
22+
;--- not_a_vector.ll
23+
; NOT_A_VECTOR: error: vector constant must have vector type
24+
define <4 x i32> @not_a_vector() {
25+
ret i32 splat (i32 7)
26+
}
27+
28+
;--- wrong_explicit_type.ll
29+
; WRONG_EXPLICIT_TYPE: error: constant expression type mismatch: got type 'i8' but expected 'i32'
30+
define <4 x i32> @wrong_explicit_type() {
31+
ret <4 x i32> splat (i8 7)
32+
}
33+
34+
;--- wrong_implicit_type.ll
35+
; WRONG_IMPLICIT_TYPE: error: constant expression type mismatch: got type 'i8' but expected 'i32'
36+
define void @wrong_implicit_type(<4 x i32> %a) {
37+
%add = add <4 x i32> %a, splat (i8 7)
38+
ret void
39+
}
40+

llvm/test/Assembler/constant-splat.ll

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s
2+
3+
; NOTE: Tests the expansion of the "splat" shorthand method to create vector
4+
; constants. Future work will change how "splat" is expanded, ultimately
5+
; leading to a point where "splat" is emitted as the disassembly.
6+
7+
@my_global = external global i32
8+
9+
; CHECK: @constant.splat.i1 = constant <1 x i1> <i1 true>
10+
@constant.splat.i1 = constant <1 x i1> splat (i1 true)
11+
12+
; CHECK: @constant.splat.i32 = constant <5 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7>
13+
@constant.splat.i32 = constant <5 x i32> splat (i32 7)
14+
15+
; CHECK: @constant.splat.i128 = constant <2 x i128> <i128 85070591730234615870450834276742070272, i128 85070591730234615870450834276742070272>
16+
@constant.splat.i128 = constant <2 x i128> splat (i128 85070591730234615870450834276742070272)
17+
18+
; CHECK: @constant.splat.f16 = constant <4 x half> <half 0xHBC00, half 0xHBC00, half 0xHBC00, half 0xHBC00>
19+
@constant.splat.f16 = constant <4 x half> splat (half 0xHBC00)
20+
21+
; CHECK: @constant.splat.f32 = constant <5 x float> <float -2.000000e+00, float -2.000000e+00, float -2.000000e+00, float -2.000000e+00, float -2.000000e+00>
22+
@constant.splat.f32 = constant <5 x float> splat (float -2.000000e+00)
23+
24+
; CHECK: @constant.splat.f64 = constant <3 x double> <double -3.000000e+00, double -3.000000e+00, double -3.000000e+00>
25+
@constant.splat.f64 = constant <3 x double> splat (double -3.000000e+00)
26+
27+
; CHECK: @constant.splat.128 = constant <2 x fp128> <fp128 0xL00000000000000018000000000000000, fp128 0xL00000000000000018000000000000000>
28+
@constant.splat.128 = constant <2 x fp128> splat (fp128 0xL00000000000000018000000000000000)
29+
30+
; CHECK: @constant.splat.bf16 = constant <4 x bfloat> <bfloat 0xRC0A0, bfloat 0xRC0A0, bfloat 0xRC0A0, bfloat 0xRC0A0>
31+
@constant.splat.bf16 = constant <4 x bfloat> splat (bfloat 0xRC0A0)
32+
33+
; CHECK: @constant.splat.x86_fp80 = constant <3 x x86_fp80> <x86_fp80 0xK4000C8F5C28F5C28F800, x86_fp80 0xK4000C8F5C28F5C28F800, x86_fp80 0xK4000C8F5C28F5C28F800>
34+
@constant.splat.x86_fp80 = constant <3 x x86_fp80> splat (x86_fp80 0xK4000C8F5C28F5C28F800)
35+
36+
; CHECK: @constant.splat.ppc_fp128 = constant <1 x ppc_fp128> <ppc_fp128 0xM80000000000000000000000000000000>
37+
@constant.splat.ppc_fp128 = constant <1 x ppc_fp128> splat (ppc_fp128 0xM80000000000000000000000000000000)
38+
39+
; CHECK: @constant.splat.global.ptr = constant <4 x ptr> <ptr @my_global, ptr @my_global, ptr @my_global, ptr @my_global>
40+
@constant.splat.global.ptr = constant <4 x ptr> splat (ptr @my_global)
41+
42+
define void @add_fixed_lenth_vector_splat_i32(<4 x i32> %a) {
43+
; CHECK: %add = add <4 x i32> %a, <i32 137, i32 137, i32 137, i32 137>
44+
%add = add <4 x i32> %a, splat (i32 137)
45+
ret void
46+
}
47+
48+
define <4 x i32> @ret_fixed_lenth_vector_splat_i32() {
49+
; CHECK: ret <4 x i32> <i32 56, i32 56, i32 56, i32 56>
50+
ret <4 x i32> splat (i32 56)
51+
}
52+
53+
define void @add_fixed_lenth_vector_splat_double(<vscale x 2 x double> %a) {
54+
; CHECK: %add = fadd <vscale x 2 x double> %a, shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x double> poison, double 5.700000e+00, i64 0), <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer)
55+
%add = fadd <vscale x 2 x double> %a, splat (double 5.700000e+00)
56+
ret void
57+
}
58+
59+
define <vscale x 4 x i32> @ret_scalable_vector_splat_i32() {
60+
; CHECK: ret <vscale x 4 x i32> shufflevector (<vscale x 4 x i32> insertelement (<vscale x 4 x i32> poison, i32 78, i64 0), <vscale x 4 x i32> poison, <vscale x 4 x i32> zeroinitializer)
61+
ret <vscale x 4 x i32> splat (i32 78)
62+
}
63+
64+
define <vscale x 4 x ptr> @ret_scalable_vector_ptr() {
65+
; CHECK: ret <vscale x 4 x ptr> shufflevector (<vscale x 4 x ptr> insertelement (<vscale x 4 x ptr> poison, ptr @my_global, i64 0), <vscale x 4 x ptr> poison, <vscale x 4 x i32> zeroinitializer)
66+
ret <vscale x 4 x ptr> splat (ptr @my_global)
67+
}

0 commit comments

Comments
 (0)