Skip to content

Commit b0e6831

Browse files
maciej-czekajgerekon
authored andcommitted
[Xtensa] Add vector conversion builtins
Intrinsics: __builtin_xtensa_ae_int32x2 and builtin_xtensa_int32 are convenience functions for easy integer-vector and vector-vector conversions that conform to Xtensa coding style. Xtensa C dialect allows for implicit conversion between wider and narrower vector (via shuffle) and between integer and any vector (via broadcast). Standard Clang vectors do not support this, so these functions provide a handicap for better portability.
1 parent 7bd87d0 commit b0e6831

File tree

6 files changed

+146
-3
lines changed

6 files changed

+146
-3
lines changed

clang/include/clang/Basic/BuiltinsXtensaHIFI.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2614,4 +2614,6 @@ BUILTIN(__builtin_xtensa_wur_ae_tablesize, "vi", "n")
26142614
// void __builtin_xtensa_wur_ae_ts_fts_bu_bp(int art)
26152615
BUILTIN(__builtin_xtensa_wur_ae_ts_fts_bu_bp, "vi", "n")
26162616

2617-
#undef BUILTIN
2617+
// Type conversion builtins
2618+
BUILTIN(__builtin_xtensa_ae_int32x2, "V2i.", "nct")
2619+
BUILTIN(__builtin_xtensa_ae_int32, "V1i.", "nct")

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13641,7 +13641,8 @@ class Sema final {
1364113641
bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
1364213642
CallExpr *TheCall);
1364313643
bool CheckXtensaBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
13644-
13644+
bool SemaBuiltinXtensaConversion(unsigned BuiltinID, CallExpr *TheCall);
13645+
1364513646
bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall);
1364613647
bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call);
1364713648
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20596,12 +20596,61 @@ llvm::Value *CodeGenFunction::ConvertXtensaToBc(const Expr *ArgExpr,
2059620596
}
2059720597
return ArgCast;
2059820598
}
20599+
llvm::Value *
20600+
CodeGenFunction::EmitXtensaConversionExpr(unsigned BuiltinID, const CallExpr *E,
20601+
ReturnValueSlot ReturnValue,
20602+
llvm::Triple::ArchType Arch) {
20603+
unsigned MaxElems;
20604+
switch (BuiltinID) {
20605+
case Xtensa::BI__builtin_xtensa_ae_int32x2:
20606+
MaxElems = 2;
20607+
break;
20608+
case Xtensa::BI__builtin_xtensa_ae_int32:
20609+
MaxElems = 1;
20610+
break;
20611+
default:
20612+
llvm_unreachable("Unknown intrinsic ID");
20613+
}
20614+
20615+
Value *ArgVal = EmitScalarExpr(E->getArg(0));
20616+
QualType QT = E->getArg(0)->getType();
20617+
if (auto *VecTy = QT->getAs<VectorType>()) {
20618+
unsigned NumEl = VecTy->getNumElements();
20619+
llvm::Type *ElType = ConvertType(VecTy->getElementType());
20620+
if (ElType != Int32Ty || NumEl > MaxElems) {
20621+
CGM.Error(E->getExprLoc(), "Expected int32x1 or int32x2");
20622+
return ArgVal;
20623+
}
20624+
if (NumEl == MaxElems)
20625+
return ArgVal; // no-op
20626+
int Mask[] = {0,0};
20627+
Value *Result =
20628+
Builder.CreateShuffleVector(ArgVal, ArgVal, ArrayRef(Mask, MaxElems));
20629+
return Result;
20630+
} else if (QT->isIntegerType()) {
20631+
Value *Int32Val = (QT->isSignedIntegerType())
20632+
? Builder.CreateSExtOrTrunc(ArgVal, Int32Ty, "cast")
20633+
: Builder.CreateZExtOrTrunc(ArgVal, Int32Ty, "cast");
20634+
Value *VecOps[] = {Int32Val,Int32Val};
20635+
Value *Result = BuildVector(ArrayRef(VecOps, MaxElems));
20636+
return Result;
20637+
}
20638+
llvm_unreachable("Invalid Argument type");
20639+
}
2059920640

2060020641
llvm::Value *
2060120642
CodeGenFunction::EmitXtensaBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
2060220643
ReturnValueSlot ReturnValue,
2060320644
llvm::Triple::ArchType Arch) {
2060420645

20646+
switch (BuiltinID) {
20647+
case Xtensa::BI__builtin_xtensa_ae_int32x2:
20648+
case Xtensa::BI__builtin_xtensa_ae_int32:
20649+
return EmitXtensaConversionExpr(BuiltinID, E, ReturnValue, Arch);
20650+
default:
20651+
break;
20652+
};
20653+
2060520654
XtensaIntrinsicInfo Info = GetXtensaIntrinsic(BuiltinID);
2060620655
unsigned Intrinsic = Info.IntrinsicID;
2060720656

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4424,6 +4424,9 @@ class CodeGenFunction : public CodeGenTypeCache {
44244424
llvm::Value *EmitXtensaBuiltinExpr(unsigned BuiltinID, const CallExpr *E,
44254425
ReturnValueSlot ReturnValue,
44264426
llvm::Triple::ArchType Arch);
4427+
llvm::Value *EmitXtensaConversionExpr(unsigned BuiltinID, const CallExpr *E,
4428+
ReturnValueSlot ReturnValue,
4429+
llvm::Triple::ArchType Arch);
44274430
//===--------------------------------------------------------------------===//
44284431
// Expression Emission
44294432
//===--------------------------------------------------------------------===//

clang/lib/Sema/SemaChecking.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5739,10 +5739,51 @@ bool Sema::CheckXtensaBuiltinFunctionCall(unsigned BuiltinID,
57395739
SemaBuiltinConstantArgRange(TheCall, 3, 0, 7) &&
57405740
SemaBuiltinConstantArgRange(TheCall, 4, 0, 7) &&
57415741
SemaBuiltinConstantArgRange(TheCall, 5, 0, 7);
5742+
case Xtensa::BI__builtin_xtensa_ae_int32x2:
5743+
case Xtensa::BI__builtin_xtensa_ae_int32:
5744+
return SemaBuiltinXtensaConversion(BuiltinID, TheCall);
57425745
}
57435746
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
57445747
}
57455748

5749+
bool Sema::SemaBuiltinXtensaConversion(unsigned BuiltinID, CallExpr *TheCall) {
5750+
unsigned MaxElems;
5751+
switch (BuiltinID) {
5752+
case Xtensa::BI__builtin_xtensa_ae_int32x2:
5753+
MaxElems = 2;
5754+
break;
5755+
case Xtensa::BI__builtin_xtensa_ae_int32:
5756+
MaxElems = 1;
5757+
break;
5758+
default:
5759+
llvm_unreachable("Unknown intrinsic ID");
5760+
}
5761+
if (checkArgCount(*this, TheCall, 1))
5762+
return true;
5763+
Expr *Arg = TheCall->getArg(0);
5764+
QualType QT = Arg->getType();
5765+
if (auto *VecTy = QT->getAs<VectorType>()) {
5766+
unsigned NumEl = VecTy->getNumElements();
5767+
QualType ElType = VecTy->getElementType();
5768+
unsigned ElWidth = Context.getIntWidth(ElType);
5769+
QualType VecType = Context.getVectorType(Context.IntTy, MaxElems,
5770+
VectorType::GenericVector);
5771+
if (ElWidth != 32 || NumEl > MaxElems)
5772+
return Diag(TheCall->getBeginLoc(),
5773+
diag::err_typecheck_convert_incompatible)
5774+
<< QT << VecType << 1 << 0 << 0;
5775+
return false;
5776+
} else {
5777+
if (!QT->isIntegerType())
5778+
return Diag(TheCall->getBeginLoc(),
5779+
diag::err_typecheck_convert_incompatible)
5780+
<< QT << Context.IntTy << 1 << 0 << 0;
5781+
5782+
return false;
5783+
}
5784+
return false;
5785+
}
5786+
57465787
void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
57475788
const TargetInfo &TI = Context.getTargetInfo();
57485789
// (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at
@@ -5776,7 +5817,6 @@ bool Sema::CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI,
57765817
case NVPTX::BI__nvvm_cp_async_cg_shared_global_16:
57775818
return checkArgCountAtMost(*this, TheCall, 3);
57785819
}
5779-
57805820
return false;
57815821
}
57825822

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: split-file %s %t
2+
// RUN: %clang -target xtensa -mcpu=cnl -S -emit-llvm -O1 -o - %t/correct.c | FileCheck %t/correct.c
3+
// RUN: not %clang -target xtensa -mcpu=cnl -S -emit-llvm -O1 -o - %t/bad_vec.c 2>&1 | FileCheck %t/bad_vec.c
4+
5+
//--- correct.c
6+
7+
typedef int ae_int32 __attribute__(( vector_size(4)));
8+
typedef int ae_int32x2 __attribute__(( vector_size(8)));
9+
10+
ae_int32x2 test_ae_int32x2_from_int(int a) {
11+
// CHECK-LABEL: @test_ae_int32x2_from_int(i
12+
// CHECK: %[[INS:.*]] = insertelement <2 x i32> poison, i32 %{{.*}}, i64 0
13+
// CHECK: %[[SHUF:.*]] = shufflevector <2 x i32> %[[INS]], <2 x i32> poison, <2 x i32> zeroinitializer
14+
// CHECK: ret <2 x i32> %[[SHUF]]
15+
return __builtin_xtensa_ae_int32x2(a);
16+
}
17+
18+
ae_int32x2 test_ae_int32x2_from_ae_int32(ae_int32 a) {
19+
// CHECK-LABEL: @test_ae_int32x2_from_ae_int32(
20+
// CHECK: %[[SHUF:.*]] = shufflevector <1 x i32> %{{.*}}, <1 x i32> poison, <2 x i32> zeroinitializer
21+
// CHECK: ret <2 x i32> %[[SHUF]]
22+
return __builtin_xtensa_ae_int32x2(a);
23+
}
24+
25+
ae_int32x2 test_ae_int32x2_from_ae_int32x2(ae_int32x2 a) {
26+
// CHECK: {{.*}}<2 x i32> @test_ae_int32x2_from_ae_int32x2(<2 x i32>{{.*}} %[[A:.*]])
27+
// CHECK: ret <2 x i32> %[[A]]
28+
return __builtin_xtensa_ae_int32x2(a);
29+
}
30+
31+
ae_int32x2 test_ae_int32x2_from_short(short a) {
32+
// CHECK-LABEL: @test_ae_int32x2_from_short(
33+
// CHECK: %[[SEXT:.*]] = sext i16 %{{.*}} to i32
34+
// CHECK: %[[INS:.*]] = insertelement <2 x i32> poison, i32 %[[SEXT]], i64 0
35+
// CHECK: %[[SHUF:.*]] = shufflevector <2 x i32> %[[INS]], <2 x i32> poison, <2 x i32> zeroinitializer
36+
// CHECK: ret <2 x i32> %[[SHUF]]
37+
return __builtin_xtensa_ae_int32x2(a);
38+
}
39+
40+
//--- bad_vec.c
41+
42+
typedef short ae_int16x4 __attribute__(( vector_size(8)));
43+
typedef int ae_int32x2 __attribute__(( vector_size(8)));
44+
45+
ae_int32x2 test_ae_int32x2_from_bad_vec(ae_int16x4 a) {
46+
// CHECK: error: passing 'ae_int16x4' {{.*}} to parameter of incompatible type
47+
return __builtin_xtensa_ae_int32x2(a);
48+
}

0 commit comments

Comments
 (0)