Support the following BCD format conversion builtins for PowerPC. - `__builtin_bcdshift` – Shifts a packed decimal value by a specified number of decimal digits. - `__builtin_bcdshiftround` – Shifts a packed decimal value by a specified number of decimal digits, with rounding applied. - `__builtin_bcdtruncate` –Truncates a packed decimal value to a specified number of digits. - `__builtin_bcdunsignedtruncate` – Truncates a packed decimal value and returns the result as an unsigned packed decimal. - `__builtin_bcdunsignedshift` – Shifts an unsigned packed decimal value by a specified number of digits. > Note: This built-in functions are valid only when all following conditions are met: > -qarch is set to utilize POWER9 technology. > The bcd.h file is included. ## Prototypes ```c vector unsigned char __builtin_bcdshift(vector unsigned char, int, unsigned char); vector unsigned char __builtin_bcdshiftround(vector unsigned char, int, unsigned char); vector unsigned char __builtin_bcdtruncate(vector unsigned char, int, unsigned char); vector unsigned char __builtin_bcdunsignedtruncate(vector unsigned char, int); vector unsigned char __builtin_bcdunsignedshift(vector unsigned char, int); ``` ---------
566 lines
21 KiB
C++
566 lines
21 KiB
C++
//===------ SemaPPC.cpp ------ PowerPC target-specific routines -----------===//
|
||
//
|
||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
// See https://llvm.org/LICENSE.txt for license information.
|
||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
//
|
||
// This file implements semantic analysis functions specific to PowerPC.
|
||
//
|
||
//===----------------------------------------------------------------------===//
|
||
|
||
#include "clang/Sema/SemaPPC.h"
|
||
#include "clang/AST/ASTContext.h"
|
||
#include "clang/AST/Attr.h"
|
||
#include "clang/AST/CharUnits.h"
|
||
#include "clang/AST/Decl.h"
|
||
#include "clang/AST/Type.h"
|
||
#include "clang/Basic/DiagnosticSema.h"
|
||
#include "clang/Basic/SourceLocation.h"
|
||
#include "clang/Basic/TargetBuiltins.h"
|
||
#include "clang/Basic/TargetInfo.h"
|
||
#include "clang/Sema/Sema.h"
|
||
#include "llvm/ADT/APSInt.h"
|
||
|
||
namespace clang {
|
||
|
||
SemaPPC::SemaPPC(Sema &S) : SemaBase(S) {}
|
||
|
||
void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) {
|
||
const auto *ICE = dyn_cast<ImplicitCastExpr>(Arg->IgnoreParens());
|
||
if (!ICE)
|
||
return;
|
||
|
||
const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
|
||
if (!DR)
|
||
return;
|
||
|
||
const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl());
|
||
if (!PD || !PD->getType()->isRecordType())
|
||
return;
|
||
|
||
QualType ArgType = Arg->getType();
|
||
for (const FieldDecl *FD : ArgType->castAsRecordDecl()->fields()) {
|
||
if (const auto *AA = FD->getAttr<AlignedAttr>()) {
|
||
CharUnits Alignment = getASTContext().toCharUnitsFromBits(
|
||
AA->getAlignment(getASTContext()));
|
||
if (Alignment.getQuantity() == 16) {
|
||
Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD;
|
||
Diag(Loc, diag::note_misaligned_member_used_here) << PD;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
static bool isPPC_64Builtin(unsigned BuiltinID) {
|
||
// These builtins only work on PPC 64bit targets.
|
||
switch (BuiltinID) {
|
||
case PPC::BI__builtin_divde:
|
||
case PPC::BI__builtin_divdeu:
|
||
case PPC::BI__builtin_bpermd:
|
||
case PPC::BI__builtin_pdepd:
|
||
case PPC::BI__builtin_pextd:
|
||
case PPC::BI__builtin_ppc_cdtbcd:
|
||
case PPC::BI__builtin_ppc_cbcdtd:
|
||
case PPC::BI__builtin_ppc_addg6s:
|
||
case PPC::BI__builtin_ppc_ldarx:
|
||
case PPC::BI__builtin_ppc_stdcx:
|
||
case PPC::BI__builtin_ppc_tdw:
|
||
case PPC::BI__builtin_ppc_trapd:
|
||
case PPC::BI__builtin_ppc_cmpeqb:
|
||
case PPC::BI__builtin_ppc_setb:
|
||
case PPC::BI__builtin_ppc_mulhd:
|
||
case PPC::BI__builtin_ppc_mulhdu:
|
||
case PPC::BI__builtin_ppc_maddhd:
|
||
case PPC::BI__builtin_ppc_maddhdu:
|
||
case PPC::BI__builtin_ppc_maddld:
|
||
case PPC::BI__builtin_ppc_load8r:
|
||
case PPC::BI__builtin_ppc_store8r:
|
||
case PPC::BI__builtin_ppc_insert_exp:
|
||
case PPC::BI__builtin_ppc_extract_sig:
|
||
case PPC::BI__builtin_ppc_addex:
|
||
case PPC::BI__builtin_darn:
|
||
case PPC::BI__builtin_darn_raw:
|
||
case PPC::BI__builtin_ppc_compare_and_swaplp:
|
||
case PPC::BI__builtin_ppc_fetch_and_addlp:
|
||
case PPC::BI__builtin_ppc_fetch_and_andlp:
|
||
case PPC::BI__builtin_ppc_fetch_and_orlp:
|
||
case PPC::BI__builtin_ppc_fetch_and_swaplp:
|
||
case PPC::BI__builtin_amo_lwat:
|
||
case PPC::BI__builtin_amo_ldat:
|
||
case PPC::BI__builtin_amo_lwat_s:
|
||
case PPC::BI__builtin_amo_ldat_s:
|
||
case PPC::BI__builtin_amo_lwat_cond:
|
||
case PPC::BI__builtin_amo_ldat_cond:
|
||
case PPC::BI__builtin_amo_lwat_cond_s:
|
||
case PPC::BI__builtin_amo_ldat_cond_s:
|
||
case PPC::BI__builtin_amo_stwat:
|
||
case PPC::BI__builtin_amo_stdat:
|
||
case PPC::BI__builtin_amo_stwat_s:
|
||
case PPC::BI__builtin_amo_stdat_s:
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI,
|
||
unsigned BuiltinID,
|
||
CallExpr *TheCall) {
|
||
ASTContext &Context = getASTContext();
|
||
bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64;
|
||
|
||
if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit)
|
||
return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt)
|
||
<< TheCall->getSourceRange();
|
||
|
||
// Common BCD type-validation helpers
|
||
// Emit error diagnostics and return true on success
|
||
// - IsTypeVecUChar: enforces vector unsigned char
|
||
// - IsIntType: enforces any integer type
|
||
// Lambdas centralize type checks for BCD builtin handlers
|
||
|
||
// Lambda 1: verify vector unsigned char type
|
||
auto IsTypeVecUChar = [&](QualType ArgTy, unsigned ArgIndex) -> bool {
|
||
QualType VecType = Context.getVectorType(Context.UnsignedCharTy, 16,
|
||
VectorKind::AltiVecVector);
|
||
if (Context.hasSameType(ArgTy, VecType))
|
||
return true;
|
||
|
||
Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
|
||
diag::err_ppc_invalid_arg_type)
|
||
<< ArgIndex << VecType << ArgTy;
|
||
return false;
|
||
};
|
||
|
||
// Lambda 2: verify integer type
|
||
auto IsIntType = [&](QualType ArgTy, unsigned ArgIndex) -> bool {
|
||
if (ArgTy->isIntegerType())
|
||
return true;
|
||
|
||
Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
|
||
diag::err_ppc_invalid_arg_type)
|
||
<< ArgIndex << "integer" << ArgTy;
|
||
return false;
|
||
};
|
||
|
||
switch (BuiltinID) {
|
||
default:
|
||
return false;
|
||
case PPC::BI__builtin_ppc_bcdsetsign:
|
||
case PPC::BI__builtin_ppc_national2packed:
|
||
case PPC::BI__builtin_ppc_packed2zoned:
|
||
case PPC::BI__builtin_ppc_zoned2packed:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
|
||
case PPC::BI__builtin_ppc_bcdshift:
|
||
case PPC::BI__builtin_ppc_bcdshiftround:
|
||
case PPC::BI__builtin_ppc_bcdtruncate: {
|
||
|
||
// Arg0 must be vector unsigned char
|
||
if (!IsTypeVecUChar(TheCall->getArg(0)->getType(), 0))
|
||
return false;
|
||
|
||
// Arg1 must be integer type
|
||
if (!IsIntType(TheCall->getArg(1)->getType(), 1))
|
||
return false;
|
||
|
||
// Restrict Arg2 constant range (0–1)
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1);
|
||
}
|
||
case PPC::BI__builtin_altivec_crypto_vshasigmaw:
|
||
case PPC::BI__builtin_altivec_crypto_vshasigmad:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) ||
|
||
SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 15);
|
||
case PPC::BI__builtin_altivec_dss:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 3);
|
||
case PPC::BI__builtin_tbegin:
|
||
case PPC::BI__builtin_tend:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1);
|
||
case PPC::BI__builtin_tsr:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 7);
|
||
case PPC::BI__builtin_tabortwc:
|
||
case PPC::BI__builtin_tabortdc:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
|
||
case PPC::BI__builtin_tabortwci:
|
||
case PPC::BI__builtin_tabortdci:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31) ||
|
||
SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31);
|
||
// According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05',
|
||
// __builtin_(un)pack_longdouble are available only if long double uses IBM
|
||
// extended double representation.
|
||
case PPC::BI__builtin_unpack_longdouble:
|
||
if (SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1))
|
||
return true;
|
||
[[fallthrough]];
|
||
case PPC::BI__builtin_pack_longdouble:
|
||
if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble())
|
||
return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi)
|
||
<< "ibmlongdouble";
|
||
return false;
|
||
case PPC::BI__builtin_altivec_dst:
|
||
case PPC::BI__builtin_altivec_dstt:
|
||
case PPC::BI__builtin_altivec_dstst:
|
||
case PPC::BI__builtin_altivec_dststt:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3);
|
||
case PPC::BI__builtin_vsx_xxpermdi:
|
||
case PPC::BI__builtin_vsx_xxsldwi:
|
||
return BuiltinVSX(TheCall);
|
||
case PPC::BI__builtin_unpack_vector_int128:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
|
||
case PPC::BI__builtin_altivec_vgnb:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 2, 7);
|
||
case PPC::BI__builtin_vsx_xxeval:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 255);
|
||
case PPC::BI__builtin_altivec_vsldbi:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7);
|
||
case PPC::BI__builtin_altivec_vsrdbi:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7);
|
||
case PPC::BI__builtin_vsx_xxpermx:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 7);
|
||
case PPC::BI__builtin_ppc_tw:
|
||
case PPC::BI__builtin_ppc_tdw:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 1, 31);
|
||
case PPC::BI__builtin_ppc_cmprb:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 1);
|
||
// For __rlwnm, __rlwimi and __rldimi, the last parameter mask must
|
||
// be a constant that represents a contiguous bit field.
|
||
case PPC::BI__builtin_ppc_rlwnm:
|
||
return SemaRef.ValueIsRunOfOnes(TheCall, 2);
|
||
case PPC::BI__builtin_ppc_rlwimi:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 31) ||
|
||
SemaRef.ValueIsRunOfOnes(TheCall, 3);
|
||
case PPC::BI__builtin_ppc_rldimi:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 63) ||
|
||
SemaRef.ValueIsRunOfOnes(TheCall, 3);
|
||
case PPC::BI__builtin_ppc_addex: {
|
||
if (SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3))
|
||
return true;
|
||
// Output warning for reserved values 1 to 3.
|
||
int ArgValue =
|
||
TheCall->getArg(2)->getIntegerConstantExpr(Context)->getSExtValue();
|
||
if (ArgValue != 0)
|
||
Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour)
|
||
<< ArgValue;
|
||
return false;
|
||
}
|
||
case PPC::BI__builtin_ppc_mtfsb0:
|
||
case PPC::BI__builtin_ppc_mtfsb1:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
|
||
case PPC::BI__builtin_ppc_mtfsf:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 255);
|
||
case PPC::BI__builtin_ppc_mtfsfi:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 7) ||
|
||
SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15);
|
||
case PPC::BI__builtin_ppc_alignx:
|
||
return SemaRef.BuiltinConstantArgPower2(TheCall, 0);
|
||
case PPC::BI__builtin_ppc_rdlam:
|
||
return SemaRef.ValueIsRunOfOnes(TheCall, 2);
|
||
case PPC::BI__builtin_vsx_ldrmb:
|
||
case PPC::BI__builtin_vsx_strmb:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16);
|
||
case PPC::BI__builtin_altivec_vcntmbb:
|
||
case PPC::BI__builtin_altivec_vcntmbh:
|
||
case PPC::BI__builtin_altivec_vcntmbw:
|
||
case PPC::BI__builtin_altivec_vcntmbd:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1);
|
||
case PPC::BI__builtin_vsx_xxgenpcvbm:
|
||
case PPC::BI__builtin_vsx_xxgenpcvhm:
|
||
case PPC::BI__builtin_vsx_xxgenpcvwm:
|
||
case PPC::BI__builtin_vsx_xxgenpcvdm:
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 3);
|
||
case PPC::BI__builtin_ppc_test_data_class: {
|
||
// Check if the first argument of the __builtin_ppc_test_data_class call is
|
||
// valid. The argument must be 'float' or 'double' or '__float128'.
|
||
QualType ArgType = TheCall->getArg(0)->getType();
|
||
if (ArgType != QualType(Context.FloatTy) &&
|
||
ArgType != QualType(Context.DoubleTy) &&
|
||
ArgType != QualType(Context.Float128Ty))
|
||
return Diag(TheCall->getBeginLoc(),
|
||
diag::err_ppc_invalid_test_data_class_type);
|
||
return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 127);
|
||
}
|
||
case PPC::BI__builtin_ppc_maxfe:
|
||
case PPC::BI__builtin_ppc_minfe:
|
||
case PPC::BI__builtin_ppc_maxfl:
|
||
case PPC::BI__builtin_ppc_minfl:
|
||
case PPC::BI__builtin_ppc_maxfs:
|
||
case PPC::BI__builtin_ppc_minfs: {
|
||
if (Context.getTargetInfo().getTriple().isOSAIX() &&
|
||
(BuiltinID == PPC::BI__builtin_ppc_maxfe ||
|
||
BuiltinID == PPC::BI__builtin_ppc_minfe))
|
||
return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type)
|
||
<< "builtin" << true << 128 << QualType(Context.LongDoubleTy)
|
||
<< false << Context.getTargetInfo().getTriple().str();
|
||
// Argument type should be exact.
|
||
QualType ArgType = QualType(Context.LongDoubleTy);
|
||
if (BuiltinID == PPC::BI__builtin_ppc_maxfl ||
|
||
BuiltinID == PPC::BI__builtin_ppc_minfl)
|
||
ArgType = QualType(Context.DoubleTy);
|
||
else if (BuiltinID == PPC::BI__builtin_ppc_maxfs ||
|
||
BuiltinID == PPC::BI__builtin_ppc_minfs)
|
||
ArgType = QualType(Context.FloatTy);
|
||
for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I)
|
||
if (TheCall->getArg(I)->getType() != ArgType)
|
||
return Diag(TheCall->getBeginLoc(),
|
||
diag::err_typecheck_convert_incompatible)
|
||
<< TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0;
|
||
return false;
|
||
}
|
||
#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \
|
||
case PPC::BI__builtin_##Name: \
|
||
return BuiltinPPCMMACall(TheCall, BuiltinID, Types);
|
||
#include "clang/Basic/BuiltinsPPC.def"
|
||
case PPC::BI__builtin_amo_lwat:
|
||
case PPC::BI__builtin_amo_ldat:
|
||
case PPC::BI__builtin_amo_lwat_s:
|
||
case PPC::BI__builtin_amo_ldat_s: {
|
||
llvm::APSInt Result;
|
||
if (SemaRef.BuiltinConstantArg(TheCall, 2, Result))
|
||
return true;
|
||
unsigned Val = Result.getZExtValue();
|
||
|
||
bool IsUnsigned = (BuiltinID == PPC::BI__builtin_amo_lwat ||
|
||
BuiltinID == PPC::BI__builtin_amo_ldat);
|
||
|
||
bool IsValid = IsUnsigned
|
||
? llvm::is_contained({0u, 1u, 2u, 3u, 4u, 6u, 8u}, Val)
|
||
: llvm::is_contained({0u, 5u, 7u, 8u}, Val);
|
||
|
||
if (IsValid)
|
||
return false;
|
||
|
||
Expr *Arg = TheCall->getArg(2);
|
||
return SemaRef.Diag(Arg->getBeginLoc(), diag::err_argument_invalid_range)
|
||
<< toString(Result, 10) << (IsUnsigned ? "0-4, 6" : "0, 5, 7") << "8"
|
||
<< Arg->getSourceRange();
|
||
}
|
||
case PPC::BI__builtin_amo_lwat_cond:
|
||
case PPC::BI__builtin_amo_ldat_cond:
|
||
case PPC::BI__builtin_amo_lwat_cond_s:
|
||
case PPC::BI__builtin_amo_ldat_cond_s: {
|
||
llvm::APSInt Result;
|
||
if (SemaRef.BuiltinConstantArg(TheCall, 1, Result))
|
||
return true;
|
||
unsigned Val = Result.getZExtValue();
|
||
if (llvm::is_contained({24u, 25u, 28u}, Val))
|
||
return false;
|
||
|
||
Expr *Arg = TheCall->getArg(1);
|
||
return SemaRef.Diag(Arg->getBeginLoc(), diag::err_argument_invalid_range)
|
||
<< toString(Result, 10) << "24, 25" << "28" << Arg->getSourceRange();
|
||
}
|
||
case PPC::BI__builtin_amo_stwat:
|
||
case PPC::BI__builtin_amo_stdat:
|
||
case PPC::BI__builtin_amo_stwat_s:
|
||
case PPC::BI__builtin_amo_stdat_s: {
|
||
llvm::APSInt Result;
|
||
if (SemaRef.BuiltinConstantArg(TheCall, 2, Result))
|
||
return true;
|
||
unsigned Val = Result.getZExtValue();
|
||
|
||
bool IsUnsigned = (BuiltinID == PPC::BI__builtin_amo_stwat ||
|
||
BuiltinID == PPC::BI__builtin_amo_stdat);
|
||
|
||
bool IsValid = IsUnsigned
|
||
? llvm::is_contained({0u, 1u, 2u, 3u, 4u, 6u, 24u}, Val)
|
||
: llvm::is_contained({0u, 5u, 7u, 24u}, Val);
|
||
|
||
if (IsValid)
|
||
return false;
|
||
|
||
Expr *Arg = TheCall->getArg(2);
|
||
return SemaRef.Diag(Arg->getBeginLoc(), diag::err_argument_invalid_range)
|
||
<< toString(Result, 10) << (IsUnsigned ? "0-4, 6" : "0, 5, 7")
|
||
<< "24" << Arg->getSourceRange();
|
||
}
|
||
}
|
||
llvm_unreachable("must return from switch");
|
||
}
|
||
|
||
// Check if the given type is a non-pointer PPC MMA type. This function is used
|
||
// in Sema to prevent invalid uses of restricted PPC MMA types.
|
||
bool SemaPPC::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) {
|
||
ASTContext &Context = getASTContext();
|
||
if (Type->isPointerType() || Type->isArrayType())
|
||
return false;
|
||
|
||
QualType CoreType = Type.getCanonicalType().getUnqualifiedType();
|
||
#define PPC_VECTOR_TYPE(Name, Id, Size) || CoreType == Context.Id##Ty
|
||
if (false
|
||
#include "clang/Basic/PPCTypes.def"
|
||
) {
|
||
Diag(TypeLoc, diag::err_ppc_invalid_use_mma_type);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str,
|
||
/// advancing the pointer over the consumed characters. The decoded type is
|
||
/// returned. If the decoded type represents a constant integer with a
|
||
/// constraint on its value then Mask is set to that value. The type descriptors
|
||
/// used in Str are specific to PPC MMA builtins and are documented in the file
|
||
/// defining the PPC builtins.
|
||
static QualType DecodePPCMMATypeFromStr(ASTContext &Context, const char *&Str,
|
||
unsigned &Mask) {
|
||
bool RequireICE = false;
|
||
ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None;
|
||
switch (*Str++) {
|
||
case 'V':
|
||
return Context.getVectorType(Context.UnsignedCharTy, 16,
|
||
VectorKind::AltiVecVector);
|
||
case 'i': {
|
||
char *End;
|
||
unsigned size = strtoul(Str, &End, 10);
|
||
assert(End != Str && "Missing constant parameter constraint");
|
||
Str = End;
|
||
Mask = size;
|
||
return Context.IntTy;
|
||
}
|
||
case 'W': {
|
||
char *End;
|
||
unsigned size = strtoul(Str, &End, 10);
|
||
assert(End != Str && "Missing PowerPC MMA type size");
|
||
Str = End;
|
||
QualType Type;
|
||
switch (size) {
|
||
#define PPC_VECTOR_TYPE(typeName, Id, size) \
|
||
case size: \
|
||
Type = Context.Id##Ty; \
|
||
break;
|
||
#include "clang/Basic/PPCTypes.def"
|
||
default:
|
||
llvm_unreachable("Invalid PowerPC MMA vector type");
|
||
}
|
||
bool CheckVectorArgs = false;
|
||
while (!CheckVectorArgs) {
|
||
switch (*Str++) {
|
||
case '*':
|
||
Type = Context.getPointerType(Type);
|
||
break;
|
||
case 'C':
|
||
Type = Type.withConst();
|
||
break;
|
||
default:
|
||
CheckVectorArgs = true;
|
||
--Str;
|
||
break;
|
||
}
|
||
}
|
||
return Type;
|
||
}
|
||
default:
|
||
return Context.DecodeTypeStr(--Str, Context, Error, RequireICE, true);
|
||
}
|
||
}
|
||
|
||
bool SemaPPC::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID,
|
||
const char *TypeStr) {
|
||
|
||
assert((TypeStr[0] != '\0') &&
|
||
"Invalid types in PPC MMA builtin declaration");
|
||
|
||
ASTContext &Context = getASTContext();
|
||
unsigned Mask = 0;
|
||
unsigned ArgNum = 0;
|
||
|
||
// The first type in TypeStr is the type of the value returned by the
|
||
// builtin. So we first read that type and change the type of TheCall.
|
||
QualType type = DecodePPCMMATypeFromStr(Context, TypeStr, Mask);
|
||
TheCall->setType(type);
|
||
|
||
while (*TypeStr != '\0') {
|
||
Mask = 0;
|
||
QualType ExpectedType = DecodePPCMMATypeFromStr(Context, TypeStr, Mask);
|
||
if (ArgNum >= TheCall->getNumArgs()) {
|
||
ArgNum++;
|
||
break;
|
||
}
|
||
|
||
Expr *Arg = TheCall->getArg(ArgNum);
|
||
QualType PassedType = Arg->getType();
|
||
QualType StrippedRVType = PassedType.getCanonicalType();
|
||
|
||
// Strip Restrict/Volatile qualifiers.
|
||
if (StrippedRVType.isRestrictQualified() ||
|
||
StrippedRVType.isVolatileQualified())
|
||
StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType();
|
||
|
||
// The only case where the argument type and expected type are allowed to
|
||
// mismatch is if the argument type is a non-void pointer (or array) and
|
||
// expected type is a void pointer.
|
||
if (StrippedRVType != ExpectedType)
|
||
if (!(ExpectedType->isVoidPointerType() &&
|
||
(StrippedRVType->isPointerType() || StrippedRVType->isArrayType())))
|
||
return Diag(Arg->getBeginLoc(),
|
||
diag::err_typecheck_convert_incompatible)
|
||
<< PassedType << ExpectedType << 1 << 0 << 0;
|
||
|
||
// If the value of the Mask is not 0, we have a constraint in the size of
|
||
// the integer argument so here we ensure the argument is a constant that
|
||
// is in the valid range.
|
||
if (Mask != 0 &&
|
||
SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true))
|
||
return true;
|
||
|
||
ArgNum++;
|
||
}
|
||
|
||
// In case we exited early from the previous loop, there are other types to
|
||
// read from TypeStr. So we need to read them all to ensure we have the right
|
||
// number of arguments in TheCall and if it is not the case, to display a
|
||
// better error message.
|
||
while (*TypeStr != '\0') {
|
||
(void)DecodePPCMMATypeFromStr(Context, TypeStr, Mask);
|
||
ArgNum++;
|
||
}
|
||
if (SemaRef.checkArgCount(TheCall, ArgNum))
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
bool SemaPPC::BuiltinVSX(CallExpr *TheCall) {
|
||
unsigned ExpectedNumArgs = 3;
|
||
if (SemaRef.checkArgCount(TheCall, ExpectedNumArgs))
|
||
return true;
|
||
|
||
// Check the third argument is a compile time constant
|
||
if (!TheCall->getArg(2)->isIntegerConstantExpr(getASTContext()))
|
||
return Diag(TheCall->getBeginLoc(),
|
||
diag::err_vsx_builtin_nonconstant_argument)
|
||
<< 3 /* argument index */ << TheCall->getDirectCallee()
|
||
<< SourceRange(TheCall->getArg(2)->getBeginLoc(),
|
||
TheCall->getArg(2)->getEndLoc());
|
||
|
||
QualType Arg1Ty = TheCall->getArg(0)->getType();
|
||
QualType Arg2Ty = TheCall->getArg(1)->getType();
|
||
|
||
// Check the type of argument 1 and argument 2 are vectors.
|
||
SourceLocation BuiltinLoc = TheCall->getBeginLoc();
|
||
if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) ||
|
||
(!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) {
|
||
return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
|
||
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
|
||
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
|
||
TheCall->getArg(1)->getEndLoc());
|
||
}
|
||
|
||
// Check the first two arguments are the same type.
|
||
if (!getASTContext().hasSameUnqualifiedType(Arg1Ty, Arg2Ty)) {
|
||
return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
|
||
<< TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false
|
||
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
|
||
TheCall->getArg(1)->getEndLoc());
|
||
}
|
||
|
||
// When default clang type checking is turned off and the customized type
|
||
// checking is used, the returning type of the function must be explicitly
|
||
// set. Otherwise it is _Bool by default.
|
||
TheCall->setType(Arg1Ty);
|
||
|
||
return false;
|
||
}
|
||
|
||
} // namespace clang
|