| //===------ 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->castAs<RecordType>()->getDecl()->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: |
| return true; |
| } |
| return false; |
| } |
| |
| bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, |
| unsigned BuiltinID, |
| CallExpr *TheCall) { |
| ASTContext &Context = getASTContext(); |
| bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; |
| llvm::APSInt Result; |
| |
| if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit) |
| return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) |
| << TheCall->getSourceRange(); |
| |
| switch (BuiltinID) { |
| default: |
| return false; |
| 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" |
| } |
| 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 |