1*0fca6ea1SDimitry Andric //===------ SemaARM.cpp ---------- ARM target-specific routines -----------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file implements semantic analysis functions specific to ARM. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include "clang/Sema/SemaARM.h" 14*0fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticSema.h" 15*0fca6ea1SDimitry Andric #include "clang/Basic/TargetBuiltins.h" 16*0fca6ea1SDimitry Andric #include "clang/Sema/Initialization.h" 17*0fca6ea1SDimitry Andric #include "clang/Sema/ParsedAttr.h" 18*0fca6ea1SDimitry Andric #include "clang/Sema/Sema.h" 19*0fca6ea1SDimitry Andric 20*0fca6ea1SDimitry Andric namespace clang { 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric SemaARM::SemaARM(Sema &S) : SemaBase(S) {} 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric /// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions 25*0fca6ea1SDimitry Andric bool SemaARM::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, 26*0fca6ea1SDimitry Andric CallExpr *TheCall) { 27*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_irg) { 30*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 2)) 31*0fca6ea1SDimitry Andric return true; 32*0fca6ea1SDimitry Andric Expr *Arg0 = TheCall->getArg(0); 33*0fca6ea1SDimitry Andric Expr *Arg1 = TheCall->getArg(1); 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); 36*0fca6ea1SDimitry Andric if (FirstArg.isInvalid()) 37*0fca6ea1SDimitry Andric return true; 38*0fca6ea1SDimitry Andric QualType FirstArgType = FirstArg.get()->getType(); 39*0fca6ea1SDimitry Andric if (!FirstArgType->isAnyPointerType()) 40*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) 41*0fca6ea1SDimitry Andric << "first" << FirstArgType << Arg0->getSourceRange(); 42*0fca6ea1SDimitry Andric TheCall->setArg(0, FirstArg.get()); 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric ExprResult SecArg = SemaRef.DefaultLvalueConversion(Arg1); 45*0fca6ea1SDimitry Andric if (SecArg.isInvalid()) 46*0fca6ea1SDimitry Andric return true; 47*0fca6ea1SDimitry Andric QualType SecArgType = SecArg.get()->getType(); 48*0fca6ea1SDimitry Andric if (!SecArgType->isIntegerType()) 49*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) 50*0fca6ea1SDimitry Andric << "second" << SecArgType << Arg1->getSourceRange(); 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric // Derive the return type from the pointer argument. 53*0fca6ea1SDimitry Andric TheCall->setType(FirstArgType); 54*0fca6ea1SDimitry Andric return false; 55*0fca6ea1SDimitry Andric } 56*0fca6ea1SDimitry Andric 57*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_addg) { 58*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 2)) 59*0fca6ea1SDimitry Andric return true; 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric Expr *Arg0 = TheCall->getArg(0); 62*0fca6ea1SDimitry Andric ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); 63*0fca6ea1SDimitry Andric if (FirstArg.isInvalid()) 64*0fca6ea1SDimitry Andric return true; 65*0fca6ea1SDimitry Andric QualType FirstArgType = FirstArg.get()->getType(); 66*0fca6ea1SDimitry Andric if (!FirstArgType->isAnyPointerType()) 67*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) 68*0fca6ea1SDimitry Andric << "first" << FirstArgType << Arg0->getSourceRange(); 69*0fca6ea1SDimitry Andric TheCall->setArg(0, FirstArg.get()); 70*0fca6ea1SDimitry Andric 71*0fca6ea1SDimitry Andric // Derive the return type from the pointer argument. 72*0fca6ea1SDimitry Andric TheCall->setType(FirstArgType); 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric // Second arg must be an constant in range [0,15] 75*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); 76*0fca6ea1SDimitry Andric } 77*0fca6ea1SDimitry Andric 78*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_gmi) { 79*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 2)) 80*0fca6ea1SDimitry Andric return true; 81*0fca6ea1SDimitry Andric Expr *Arg0 = TheCall->getArg(0); 82*0fca6ea1SDimitry Andric Expr *Arg1 = TheCall->getArg(1); 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); 85*0fca6ea1SDimitry Andric if (FirstArg.isInvalid()) 86*0fca6ea1SDimitry Andric return true; 87*0fca6ea1SDimitry Andric QualType FirstArgType = FirstArg.get()->getType(); 88*0fca6ea1SDimitry Andric if (!FirstArgType->isAnyPointerType()) 89*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) 90*0fca6ea1SDimitry Andric << "first" << FirstArgType << Arg0->getSourceRange(); 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric QualType SecArgType = Arg1->getType(); 93*0fca6ea1SDimitry Andric if (!SecArgType->isIntegerType()) 94*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_integer) 95*0fca6ea1SDimitry Andric << "second" << SecArgType << Arg1->getSourceRange(); 96*0fca6ea1SDimitry Andric TheCall->setType(Context.IntTy); 97*0fca6ea1SDimitry Andric return false; 98*0fca6ea1SDimitry Andric } 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_ldg || 101*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_stg) { 102*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, 1)) 103*0fca6ea1SDimitry Andric return true; 104*0fca6ea1SDimitry Andric Expr *Arg0 = TheCall->getArg(0); 105*0fca6ea1SDimitry Andric ExprResult FirstArg = SemaRef.DefaultFunctionArrayLvalueConversion(Arg0); 106*0fca6ea1SDimitry Andric if (FirstArg.isInvalid()) 107*0fca6ea1SDimitry Andric return true; 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric QualType FirstArgType = FirstArg.get()->getType(); 110*0fca6ea1SDimitry Andric if (!FirstArgType->isAnyPointerType()) 111*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_must_be_pointer) 112*0fca6ea1SDimitry Andric << "first" << FirstArgType << Arg0->getSourceRange(); 113*0fca6ea1SDimitry Andric TheCall->setArg(0, FirstArg.get()); 114*0fca6ea1SDimitry Andric 115*0fca6ea1SDimitry Andric // Derive the return type from the pointer argument. 116*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_ldg) 117*0fca6ea1SDimitry Andric TheCall->setType(FirstArgType); 118*0fca6ea1SDimitry Andric return false; 119*0fca6ea1SDimitry Andric } 120*0fca6ea1SDimitry Andric 121*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_subp) { 122*0fca6ea1SDimitry Andric Expr *ArgA = TheCall->getArg(0); 123*0fca6ea1SDimitry Andric Expr *ArgB = TheCall->getArg(1); 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric ExprResult ArgExprA = SemaRef.DefaultFunctionArrayLvalueConversion(ArgA); 126*0fca6ea1SDimitry Andric ExprResult ArgExprB = SemaRef.DefaultFunctionArrayLvalueConversion(ArgB); 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric if (ArgExprA.isInvalid() || ArgExprB.isInvalid()) 129*0fca6ea1SDimitry Andric return true; 130*0fca6ea1SDimitry Andric 131*0fca6ea1SDimitry Andric QualType ArgTypeA = ArgExprA.get()->getType(); 132*0fca6ea1SDimitry Andric QualType ArgTypeB = ArgExprB.get()->getType(); 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric auto isNull = [&](Expr *E) -> bool { 135*0fca6ea1SDimitry Andric return E->isNullPointerConstant(Context, 136*0fca6ea1SDimitry Andric Expr::NPC_ValueDependentIsNotNull); 137*0fca6ea1SDimitry Andric }; 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric // argument should be either a pointer or null 140*0fca6ea1SDimitry Andric if (!ArgTypeA->isAnyPointerType() && !isNull(ArgA)) 141*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) 142*0fca6ea1SDimitry Andric << "first" << ArgTypeA << ArgA->getSourceRange(); 143*0fca6ea1SDimitry Andric 144*0fca6ea1SDimitry Andric if (!ArgTypeB->isAnyPointerType() && !isNull(ArgB)) 145*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_arg_null_or_pointer) 146*0fca6ea1SDimitry Andric << "second" << ArgTypeB << ArgB->getSourceRange(); 147*0fca6ea1SDimitry Andric 148*0fca6ea1SDimitry Andric // Ensure Pointee types are compatible 149*0fca6ea1SDimitry Andric if (ArgTypeA->isAnyPointerType() && !isNull(ArgA) && 150*0fca6ea1SDimitry Andric ArgTypeB->isAnyPointerType() && !isNull(ArgB)) { 151*0fca6ea1SDimitry Andric QualType pointeeA = ArgTypeA->getPointeeType(); 152*0fca6ea1SDimitry Andric QualType pointeeB = ArgTypeB->getPointeeType(); 153*0fca6ea1SDimitry Andric if (!Context.typesAreCompatible( 154*0fca6ea1SDimitry Andric Context.getCanonicalType(pointeeA).getUnqualifiedType(), 155*0fca6ea1SDimitry Andric Context.getCanonicalType(pointeeB).getUnqualifiedType())) { 156*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), 157*0fca6ea1SDimitry Andric diag::err_typecheck_sub_ptr_compatible) 158*0fca6ea1SDimitry Andric << ArgTypeA << ArgTypeB << ArgA->getSourceRange() 159*0fca6ea1SDimitry Andric << ArgB->getSourceRange(); 160*0fca6ea1SDimitry Andric } 161*0fca6ea1SDimitry Andric } 162*0fca6ea1SDimitry Andric 163*0fca6ea1SDimitry Andric // at least one argument should be pointer type 164*0fca6ea1SDimitry Andric if (!ArgTypeA->isAnyPointerType() && !ArgTypeB->isAnyPointerType()) 165*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_memtag_any2arg_pointer) 166*0fca6ea1SDimitry Andric << ArgTypeA << ArgTypeB << ArgA->getSourceRange(); 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric if (isNull(ArgA)) // adopt type of the other pointer 169*0fca6ea1SDimitry Andric ArgExprA = 170*0fca6ea1SDimitry Andric SemaRef.ImpCastExprToType(ArgExprA.get(), ArgTypeB, CK_NullToPointer); 171*0fca6ea1SDimitry Andric 172*0fca6ea1SDimitry Andric if (isNull(ArgB)) 173*0fca6ea1SDimitry Andric ArgExprB = 174*0fca6ea1SDimitry Andric SemaRef.ImpCastExprToType(ArgExprB.get(), ArgTypeA, CK_NullToPointer); 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric TheCall->setArg(0, ArgExprA.get()); 177*0fca6ea1SDimitry Andric TheCall->setArg(1, ArgExprB.get()); 178*0fca6ea1SDimitry Andric TheCall->setType(Context.LongLongTy); 179*0fca6ea1SDimitry Andric return false; 180*0fca6ea1SDimitry Andric } 181*0fca6ea1SDimitry Andric assert(false && "Unhandled ARM MTE intrinsic"); 182*0fca6ea1SDimitry Andric return true; 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric /// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr 186*0fca6ea1SDimitry Andric /// TheCall is an ARM/AArch64 special register string literal. 187*0fca6ea1SDimitry Andric bool SemaARM::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, 188*0fca6ea1SDimitry Andric int ArgNum, unsigned ExpectedFieldNum, 189*0fca6ea1SDimitry Andric bool AllowName) { 190*0fca6ea1SDimitry Andric bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || 191*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsr64 || 192*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_rsr || 193*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_rsrp || 194*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsr || 195*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsrp; 196*0fca6ea1SDimitry Andric bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || 197*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr64 || 198*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_rsr128 || 199*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr128 || 200*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_rsr || 201*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_rsrp || 202*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr || 203*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsrp; 204*0fca6ea1SDimitry Andric assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); 205*0fca6ea1SDimitry Andric 206*0fca6ea1SDimitry Andric // We can't check the value of a dependent argument. 207*0fca6ea1SDimitry Andric Expr *Arg = TheCall->getArg(ArgNum); 208*0fca6ea1SDimitry Andric if (Arg->isTypeDependent() || Arg->isValueDependent()) 209*0fca6ea1SDimitry Andric return false; 210*0fca6ea1SDimitry Andric 211*0fca6ea1SDimitry Andric // Check if the argument is a string literal. 212*0fca6ea1SDimitry Andric if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) 213*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) 214*0fca6ea1SDimitry Andric << Arg->getSourceRange(); 215*0fca6ea1SDimitry Andric 216*0fca6ea1SDimitry Andric // Check the type of special register given. 217*0fca6ea1SDimitry Andric StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); 218*0fca6ea1SDimitry Andric SmallVector<StringRef, 6> Fields; 219*0fca6ea1SDimitry Andric Reg.split(Fields, ":"); 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) 222*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) 223*0fca6ea1SDimitry Andric << Arg->getSourceRange(); 224*0fca6ea1SDimitry Andric 225*0fca6ea1SDimitry Andric // If the string is the name of a register then we cannot check that it is 226*0fca6ea1SDimitry Andric // valid here but if the string is of one the forms described in ACLE then we 227*0fca6ea1SDimitry Andric // can check that the supplied fields are integers and within the valid 228*0fca6ea1SDimitry Andric // ranges. 229*0fca6ea1SDimitry Andric if (Fields.size() > 1) { 230*0fca6ea1SDimitry Andric bool FiveFields = Fields.size() == 5; 231*0fca6ea1SDimitry Andric 232*0fca6ea1SDimitry Andric bool ValidString = true; 233*0fca6ea1SDimitry Andric if (IsARMBuiltin) { 234*0fca6ea1SDimitry Andric ValidString &= Fields[0].starts_with_insensitive("cp") || 235*0fca6ea1SDimitry Andric Fields[0].starts_with_insensitive("p"); 236*0fca6ea1SDimitry Andric if (ValidString) 237*0fca6ea1SDimitry Andric Fields[0] = Fields[0].drop_front( 238*0fca6ea1SDimitry Andric Fields[0].starts_with_insensitive("cp") ? 2 : 1); 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric ValidString &= Fields[2].starts_with_insensitive("c"); 241*0fca6ea1SDimitry Andric if (ValidString) 242*0fca6ea1SDimitry Andric Fields[2] = Fields[2].drop_front(1); 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric if (FiveFields) { 245*0fca6ea1SDimitry Andric ValidString &= Fields[3].starts_with_insensitive("c"); 246*0fca6ea1SDimitry Andric if (ValidString) 247*0fca6ea1SDimitry Andric Fields[3] = Fields[3].drop_front(1); 248*0fca6ea1SDimitry Andric } 249*0fca6ea1SDimitry Andric } 250*0fca6ea1SDimitry Andric 251*0fca6ea1SDimitry Andric SmallVector<int, 5> Ranges; 252*0fca6ea1SDimitry Andric if (FiveFields) 253*0fca6ea1SDimitry Andric Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); 254*0fca6ea1SDimitry Andric else 255*0fca6ea1SDimitry Andric Ranges.append({15, 7, 15}); 256*0fca6ea1SDimitry Andric 257*0fca6ea1SDimitry Andric for (unsigned i = 0; i < Fields.size(); ++i) { 258*0fca6ea1SDimitry Andric int IntField; 259*0fca6ea1SDimitry Andric ValidString &= !Fields[i].getAsInteger(10, IntField); 260*0fca6ea1SDimitry Andric ValidString &= (IntField >= 0 && IntField <= Ranges[i]); 261*0fca6ea1SDimitry Andric } 262*0fca6ea1SDimitry Andric 263*0fca6ea1SDimitry Andric if (!ValidString) 264*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) 265*0fca6ea1SDimitry Andric << Arg->getSourceRange(); 266*0fca6ea1SDimitry Andric } else if (IsAArch64Builtin && Fields.size() == 1) { 267*0fca6ea1SDimitry Andric // This code validates writes to PSTATE registers. 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric // Not a write. 270*0fca6ea1SDimitry Andric if (TheCall->getNumArgs() != 2) 271*0fca6ea1SDimitry Andric return false; 272*0fca6ea1SDimitry Andric 273*0fca6ea1SDimitry Andric // The 128-bit system register accesses do not touch PSTATE. 274*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_rsr128 || 275*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr128) 276*0fca6ea1SDimitry Andric return false; 277*0fca6ea1SDimitry Andric 278*0fca6ea1SDimitry Andric // These are the named PSTATE accesses using "MSR (immediate)" instructions, 279*0fca6ea1SDimitry Andric // along with the upper limit on the immediates allowed. 280*0fca6ea1SDimitry Andric auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg) 281*0fca6ea1SDimitry Andric .CaseLower("spsel", 15) 282*0fca6ea1SDimitry Andric .CaseLower("daifclr", 15) 283*0fca6ea1SDimitry Andric .CaseLower("daifset", 15) 284*0fca6ea1SDimitry Andric .CaseLower("pan", 15) 285*0fca6ea1SDimitry Andric .CaseLower("uao", 15) 286*0fca6ea1SDimitry Andric .CaseLower("dit", 15) 287*0fca6ea1SDimitry Andric .CaseLower("ssbs", 15) 288*0fca6ea1SDimitry Andric .CaseLower("tco", 15) 289*0fca6ea1SDimitry Andric .CaseLower("allint", 1) 290*0fca6ea1SDimitry Andric .CaseLower("pm", 1) 291*0fca6ea1SDimitry Andric .Default(std::nullopt); 292*0fca6ea1SDimitry Andric 293*0fca6ea1SDimitry Andric // If this is not a named PSTATE, just continue without validating, as this 294*0fca6ea1SDimitry Andric // will be lowered to an "MSR (register)" instruction directly 295*0fca6ea1SDimitry Andric if (!MaxLimit) 296*0fca6ea1SDimitry Andric return false; 297*0fca6ea1SDimitry Andric 298*0fca6ea1SDimitry Andric // Here we only allow constants in the range for that pstate, as required by 299*0fca6ea1SDimitry Andric // the ACLE. 300*0fca6ea1SDimitry Andric // 301*0fca6ea1SDimitry Andric // While clang also accepts the names of system registers in its ACLE 302*0fca6ea1SDimitry Andric // intrinsics, we prevent this with the PSTATE names used in MSR (immediate) 303*0fca6ea1SDimitry Andric // as the value written via a register is different to the value used as an 304*0fca6ea1SDimitry Andric // immediate to have the same effect. e.g., for the instruction `msr tco, 305*0fca6ea1SDimitry Andric // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but 306*0fca6ea1SDimitry Andric // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO. 307*0fca6ea1SDimitry Andric // 308*0fca6ea1SDimitry Andric // If a programmer wants to codegen the MSR (register) form of `msr tco, 309*0fca6ea1SDimitry Andric // xN`, they can still do so by specifying the register using five 310*0fca6ea1SDimitry Andric // colon-separated numbers in a string. 311*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); 312*0fca6ea1SDimitry Andric } 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric return false; 315*0fca6ea1SDimitry Andric } 316*0fca6ea1SDimitry Andric 317*0fca6ea1SDimitry Andric // Get the valid immediate range for the specified NEON type code. 318*0fca6ea1SDimitry Andric static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { 319*0fca6ea1SDimitry Andric NeonTypeFlags Type(t); 320*0fca6ea1SDimitry Andric int IsQuad = ForceQuad ? true : Type.isQuad(); 321*0fca6ea1SDimitry Andric switch (Type.getEltType()) { 322*0fca6ea1SDimitry Andric case NeonTypeFlags::Int8: 323*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly8: 324*0fca6ea1SDimitry Andric return shift ? 7 : (8 << IsQuad) - 1; 325*0fca6ea1SDimitry Andric case NeonTypeFlags::Int16: 326*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly16: 327*0fca6ea1SDimitry Andric return shift ? 15 : (4 << IsQuad) - 1; 328*0fca6ea1SDimitry Andric case NeonTypeFlags::Int32: 329*0fca6ea1SDimitry Andric return shift ? 31 : (2 << IsQuad) - 1; 330*0fca6ea1SDimitry Andric case NeonTypeFlags::Int64: 331*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly64: 332*0fca6ea1SDimitry Andric return shift ? 63 : (1 << IsQuad) - 1; 333*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly128: 334*0fca6ea1SDimitry Andric return shift ? 127 : (1 << IsQuad) - 1; 335*0fca6ea1SDimitry Andric case NeonTypeFlags::Float16: 336*0fca6ea1SDimitry Andric assert(!shift && "cannot shift float types!"); 337*0fca6ea1SDimitry Andric return (4 << IsQuad) - 1; 338*0fca6ea1SDimitry Andric case NeonTypeFlags::Float32: 339*0fca6ea1SDimitry Andric assert(!shift && "cannot shift float types!"); 340*0fca6ea1SDimitry Andric return (2 << IsQuad) - 1; 341*0fca6ea1SDimitry Andric case NeonTypeFlags::Float64: 342*0fca6ea1SDimitry Andric assert(!shift && "cannot shift float types!"); 343*0fca6ea1SDimitry Andric return (1 << IsQuad) - 1; 344*0fca6ea1SDimitry Andric case NeonTypeFlags::BFloat16: 345*0fca6ea1SDimitry Andric assert(!shift && "cannot shift float types!"); 346*0fca6ea1SDimitry Andric return (4 << IsQuad) - 1; 347*0fca6ea1SDimitry Andric } 348*0fca6ea1SDimitry Andric llvm_unreachable("Invalid NeonTypeFlag!"); 349*0fca6ea1SDimitry Andric } 350*0fca6ea1SDimitry Andric 351*0fca6ea1SDimitry Andric /// getNeonEltType - Return the QualType corresponding to the elements of 352*0fca6ea1SDimitry Andric /// the vector type specified by the NeonTypeFlags. This is used to check 353*0fca6ea1SDimitry Andric /// the pointer arguments for Neon load/store intrinsics. 354*0fca6ea1SDimitry Andric static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, 355*0fca6ea1SDimitry Andric bool IsPolyUnsigned, bool IsInt64Long) { 356*0fca6ea1SDimitry Andric switch (Flags.getEltType()) { 357*0fca6ea1SDimitry Andric case NeonTypeFlags::Int8: 358*0fca6ea1SDimitry Andric return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy; 359*0fca6ea1SDimitry Andric case NeonTypeFlags::Int16: 360*0fca6ea1SDimitry Andric return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy; 361*0fca6ea1SDimitry Andric case NeonTypeFlags::Int32: 362*0fca6ea1SDimitry Andric return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy; 363*0fca6ea1SDimitry Andric case NeonTypeFlags::Int64: 364*0fca6ea1SDimitry Andric if (IsInt64Long) 365*0fca6ea1SDimitry Andric return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy; 366*0fca6ea1SDimitry Andric else 367*0fca6ea1SDimitry Andric return Flags.isUnsigned() ? Context.UnsignedLongLongTy 368*0fca6ea1SDimitry Andric : Context.LongLongTy; 369*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly8: 370*0fca6ea1SDimitry Andric return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy; 371*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly16: 372*0fca6ea1SDimitry Andric return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; 373*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly64: 374*0fca6ea1SDimitry Andric if (IsInt64Long) 375*0fca6ea1SDimitry Andric return Context.UnsignedLongTy; 376*0fca6ea1SDimitry Andric else 377*0fca6ea1SDimitry Andric return Context.UnsignedLongLongTy; 378*0fca6ea1SDimitry Andric case NeonTypeFlags::Poly128: 379*0fca6ea1SDimitry Andric break; 380*0fca6ea1SDimitry Andric case NeonTypeFlags::Float16: 381*0fca6ea1SDimitry Andric return Context.HalfTy; 382*0fca6ea1SDimitry Andric case NeonTypeFlags::Float32: 383*0fca6ea1SDimitry Andric return Context.FloatTy; 384*0fca6ea1SDimitry Andric case NeonTypeFlags::Float64: 385*0fca6ea1SDimitry Andric return Context.DoubleTy; 386*0fca6ea1SDimitry Andric case NeonTypeFlags::BFloat16: 387*0fca6ea1SDimitry Andric return Context.BFloat16Ty; 388*0fca6ea1SDimitry Andric } 389*0fca6ea1SDimitry Andric llvm_unreachable("Invalid NeonTypeFlag!"); 390*0fca6ea1SDimitry Andric } 391*0fca6ea1SDimitry Andric 392*0fca6ea1SDimitry Andric enum ArmSMEState : unsigned { 393*0fca6ea1SDimitry Andric ArmNoState = 0, 394*0fca6ea1SDimitry Andric 395*0fca6ea1SDimitry Andric ArmInZA = 0b01, 396*0fca6ea1SDimitry Andric ArmOutZA = 0b10, 397*0fca6ea1SDimitry Andric ArmInOutZA = 0b11, 398*0fca6ea1SDimitry Andric ArmZAMask = 0b11, 399*0fca6ea1SDimitry Andric 400*0fca6ea1SDimitry Andric ArmInZT0 = 0b01 << 2, 401*0fca6ea1SDimitry Andric ArmOutZT0 = 0b10 << 2, 402*0fca6ea1SDimitry Andric ArmInOutZT0 = 0b11 << 2, 403*0fca6ea1SDimitry Andric ArmZT0Mask = 0b11 << 2 404*0fca6ea1SDimitry Andric }; 405*0fca6ea1SDimitry Andric 406*0fca6ea1SDimitry Andric bool SemaARM::ParseSVEImmChecks( 407*0fca6ea1SDimitry Andric CallExpr *TheCall, SmallVector<std::tuple<int, int, int>, 3> &ImmChecks) { 408*0fca6ea1SDimitry Andric // Perform all the immediate checks for this builtin call. 409*0fca6ea1SDimitry Andric bool HasError = false; 410*0fca6ea1SDimitry Andric for (auto &I : ImmChecks) { 411*0fca6ea1SDimitry Andric int ArgNum, CheckTy, ElementSizeInBits; 412*0fca6ea1SDimitry Andric std::tie(ArgNum, CheckTy, ElementSizeInBits) = I; 413*0fca6ea1SDimitry Andric 414*0fca6ea1SDimitry Andric typedef bool (*OptionSetCheckFnTy)(int64_t Value); 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric // Function that checks whether the operand (ArgNum) is an immediate 417*0fca6ea1SDimitry Andric // that is one of the predefined values. 418*0fca6ea1SDimitry Andric auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm, 419*0fca6ea1SDimitry Andric int ErrDiag) -> bool { 420*0fca6ea1SDimitry Andric // We can't check the value of a dependent argument. 421*0fca6ea1SDimitry Andric Expr *Arg = TheCall->getArg(ArgNum); 422*0fca6ea1SDimitry Andric if (Arg->isTypeDependent() || Arg->isValueDependent()) 423*0fca6ea1SDimitry Andric return false; 424*0fca6ea1SDimitry Andric 425*0fca6ea1SDimitry Andric // Check constant-ness first. 426*0fca6ea1SDimitry Andric llvm::APSInt Imm; 427*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArg(TheCall, ArgNum, Imm)) 428*0fca6ea1SDimitry Andric return true; 429*0fca6ea1SDimitry Andric 430*0fca6ea1SDimitry Andric if (!CheckImm(Imm.getSExtValue())) 431*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange(); 432*0fca6ea1SDimitry Andric return false; 433*0fca6ea1SDimitry Andric }; 434*0fca6ea1SDimitry Andric 435*0fca6ea1SDimitry Andric switch ((SVETypeFlags::ImmCheckType)CheckTy) { 436*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_31: 437*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) 438*0fca6ea1SDimitry Andric HasError = true; 439*0fca6ea1SDimitry Andric break; 440*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_13: 441*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) 442*0fca6ea1SDimitry Andric HasError = true; 443*0fca6ea1SDimitry Andric break; 444*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck1_16: 445*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) 446*0fca6ea1SDimitry Andric HasError = true; 447*0fca6ea1SDimitry Andric break; 448*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_7: 449*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) 450*0fca6ea1SDimitry Andric HasError = true; 451*0fca6ea1SDimitry Andric break; 452*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck1_1: 453*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) 454*0fca6ea1SDimitry Andric HasError = true; 455*0fca6ea1SDimitry Andric break; 456*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck1_3: 457*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) 458*0fca6ea1SDimitry Andric HasError = true; 459*0fca6ea1SDimitry Andric break; 460*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck1_7: 461*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) 462*0fca6ea1SDimitry Andric HasError = true; 463*0fca6ea1SDimitry Andric break; 464*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckExtract: 465*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 466*0fca6ea1SDimitry Andric (2048 / ElementSizeInBits) - 1)) 467*0fca6ea1SDimitry Andric HasError = true; 468*0fca6ea1SDimitry Andric break; 469*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckShiftRight: 470*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 471*0fca6ea1SDimitry Andric ElementSizeInBits)) 472*0fca6ea1SDimitry Andric HasError = true; 473*0fca6ea1SDimitry Andric break; 474*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckShiftRightNarrow: 475*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 1, 476*0fca6ea1SDimitry Andric ElementSizeInBits / 2)) 477*0fca6ea1SDimitry Andric HasError = true; 478*0fca6ea1SDimitry Andric break; 479*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckShiftLeft: 480*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 481*0fca6ea1SDimitry Andric ElementSizeInBits - 1)) 482*0fca6ea1SDimitry Andric HasError = true; 483*0fca6ea1SDimitry Andric break; 484*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckLaneIndex: 485*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 486*0fca6ea1SDimitry Andric (128 / (1 * ElementSizeInBits)) - 1)) 487*0fca6ea1SDimitry Andric HasError = true; 488*0fca6ea1SDimitry Andric break; 489*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckLaneIndexCompRotate: 490*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 491*0fca6ea1SDimitry Andric (128 / (2 * ElementSizeInBits)) - 1)) 492*0fca6ea1SDimitry Andric HasError = true; 493*0fca6ea1SDimitry Andric break; 494*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckLaneIndexDot: 495*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 496*0fca6ea1SDimitry Andric (128 / (4 * ElementSizeInBits)) - 1)) 497*0fca6ea1SDimitry Andric HasError = true; 498*0fca6ea1SDimitry Andric break; 499*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckComplexRot90_270: 500*0fca6ea1SDimitry Andric if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; }, 501*0fca6ea1SDimitry Andric diag::err_rotation_argument_to_cadd)) 502*0fca6ea1SDimitry Andric HasError = true; 503*0fca6ea1SDimitry Andric break; 504*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheckComplexRotAll90: 505*0fca6ea1SDimitry Andric if (CheckImmediateInSet( 506*0fca6ea1SDimitry Andric [](int64_t V) { 507*0fca6ea1SDimitry Andric return V == 0 || V == 90 || V == 180 || V == 270; 508*0fca6ea1SDimitry Andric }, 509*0fca6ea1SDimitry Andric diag::err_rotation_argument_to_cmla)) 510*0fca6ea1SDimitry Andric HasError = true; 511*0fca6ea1SDimitry Andric break; 512*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_1: 513*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) 514*0fca6ea1SDimitry Andric HasError = true; 515*0fca6ea1SDimitry Andric break; 516*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_2: 517*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) 518*0fca6ea1SDimitry Andric HasError = true; 519*0fca6ea1SDimitry Andric break; 520*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_3: 521*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) 522*0fca6ea1SDimitry Andric HasError = true; 523*0fca6ea1SDimitry Andric break; 524*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_0: 525*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) 526*0fca6ea1SDimitry Andric HasError = true; 527*0fca6ea1SDimitry Andric break; 528*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_15: 529*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) 530*0fca6ea1SDimitry Andric HasError = true; 531*0fca6ea1SDimitry Andric break; 532*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck0_255: 533*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) 534*0fca6ea1SDimitry Andric HasError = true; 535*0fca6ea1SDimitry Andric break; 536*0fca6ea1SDimitry Andric case SVETypeFlags::ImmCheck2_4_Mul2: 537*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || 538*0fca6ea1SDimitry Andric SemaRef.BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) 539*0fca6ea1SDimitry Andric HasError = true; 540*0fca6ea1SDimitry Andric break; 541*0fca6ea1SDimitry Andric } 542*0fca6ea1SDimitry Andric } 543*0fca6ea1SDimitry Andric 544*0fca6ea1SDimitry Andric return HasError; 545*0fca6ea1SDimitry Andric } 546*0fca6ea1SDimitry Andric 547*0fca6ea1SDimitry Andric SemaARM::ArmStreamingType getArmStreamingFnType(const FunctionDecl *FD) { 548*0fca6ea1SDimitry Andric if (FD->hasAttr<ArmLocallyStreamingAttr>()) 549*0fca6ea1SDimitry Andric return SemaARM::ArmStreaming; 550*0fca6ea1SDimitry Andric if (const Type *Ty = FD->getType().getTypePtrOrNull()) { 551*0fca6ea1SDimitry Andric if (const auto *FPT = Ty->getAs<FunctionProtoType>()) { 552*0fca6ea1SDimitry Andric if (FPT->getAArch64SMEAttributes() & 553*0fca6ea1SDimitry Andric FunctionType::SME_PStateSMEnabledMask) 554*0fca6ea1SDimitry Andric return SemaARM::ArmStreaming; 555*0fca6ea1SDimitry Andric if (FPT->getAArch64SMEAttributes() & 556*0fca6ea1SDimitry Andric FunctionType::SME_PStateSMCompatibleMask) 557*0fca6ea1SDimitry Andric return SemaARM::ArmStreamingCompatible; 558*0fca6ea1SDimitry Andric } 559*0fca6ea1SDimitry Andric } 560*0fca6ea1SDimitry Andric return SemaARM::ArmNonStreaming; 561*0fca6ea1SDimitry Andric } 562*0fca6ea1SDimitry Andric 563*0fca6ea1SDimitry Andric static bool checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall, 564*0fca6ea1SDimitry Andric const FunctionDecl *FD, 565*0fca6ea1SDimitry Andric SemaARM::ArmStreamingType BuiltinType, 566*0fca6ea1SDimitry Andric unsigned BuiltinID) { 567*0fca6ea1SDimitry Andric SemaARM::ArmStreamingType FnType = getArmStreamingFnType(FD); 568*0fca6ea1SDimitry Andric 569*0fca6ea1SDimitry Andric // Check if the intrinsic is available in the right mode, i.e. 570*0fca6ea1SDimitry Andric // * When compiling for SME only, the caller must be in streaming mode. 571*0fca6ea1SDimitry Andric // * When compiling for SVE only, the caller must be in non-streaming mode. 572*0fca6ea1SDimitry Andric // * When compiling for both SVE and SME, the caller can be in either mode. 573*0fca6ea1SDimitry Andric if (BuiltinType == SemaARM::VerifyRuntimeMode) { 574*0fca6ea1SDimitry Andric auto DisableFeatures = [](llvm::StringMap<bool> &Map, StringRef S) { 575*0fca6ea1SDimitry Andric for (StringRef K : Map.keys()) 576*0fca6ea1SDimitry Andric if (K.starts_with(S)) 577*0fca6ea1SDimitry Andric Map[K] = false; 578*0fca6ea1SDimitry Andric }; 579*0fca6ea1SDimitry Andric 580*0fca6ea1SDimitry Andric llvm::StringMap<bool> CallerFeatureMapWithoutSVE; 581*0fca6ea1SDimitry Andric S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSVE, FD); 582*0fca6ea1SDimitry Andric DisableFeatures(CallerFeatureMapWithoutSVE, "sve"); 583*0fca6ea1SDimitry Andric 584*0fca6ea1SDimitry Andric // Avoid emitting diagnostics for a function that can never compile. 585*0fca6ea1SDimitry Andric if (FnType == SemaARM::ArmStreaming && !CallerFeatureMapWithoutSVE["sme"]) 586*0fca6ea1SDimitry Andric return false; 587*0fca6ea1SDimitry Andric 588*0fca6ea1SDimitry Andric llvm::StringMap<bool> CallerFeatureMapWithoutSME; 589*0fca6ea1SDimitry Andric S.Context.getFunctionFeatureMap(CallerFeatureMapWithoutSME, FD); 590*0fca6ea1SDimitry Andric DisableFeatures(CallerFeatureMapWithoutSME, "sme"); 591*0fca6ea1SDimitry Andric 592*0fca6ea1SDimitry Andric // We know the builtin requires either some combination of SVE flags, or 593*0fca6ea1SDimitry Andric // some combination of SME flags, but we need to figure out which part 594*0fca6ea1SDimitry Andric // of the required features is satisfied by the target features. 595*0fca6ea1SDimitry Andric // 596*0fca6ea1SDimitry Andric // For a builtin with target guard 'sve2p1|sme2', if we compile with 597*0fca6ea1SDimitry Andric // '+sve2p1,+sme', then we know that it satisfies the 'sve2p1' part if we 598*0fca6ea1SDimitry Andric // evaluate the features for '+sve2p1,+sme,+nosme'. 599*0fca6ea1SDimitry Andric // 600*0fca6ea1SDimitry Andric // Similarly, if we compile with '+sve2,+sme2', then we know it satisfies 601*0fca6ea1SDimitry Andric // the 'sme2' part if we evaluate the features for '+sve2,+sme2,+nosve'. 602*0fca6ea1SDimitry Andric StringRef BuiltinTargetGuards( 603*0fca6ea1SDimitry Andric S.Context.BuiltinInfo.getRequiredFeatures(BuiltinID)); 604*0fca6ea1SDimitry Andric bool SatisfiesSVE = Builtin::evaluateRequiredTargetFeatures( 605*0fca6ea1SDimitry Andric BuiltinTargetGuards, CallerFeatureMapWithoutSME); 606*0fca6ea1SDimitry Andric bool SatisfiesSME = Builtin::evaluateRequiredTargetFeatures( 607*0fca6ea1SDimitry Andric BuiltinTargetGuards, CallerFeatureMapWithoutSVE); 608*0fca6ea1SDimitry Andric 609*0fca6ea1SDimitry Andric if ((SatisfiesSVE && SatisfiesSME) || 610*0fca6ea1SDimitry Andric (SatisfiesSVE && FnType == SemaARM::ArmStreamingCompatible)) 611*0fca6ea1SDimitry Andric return false; 612*0fca6ea1SDimitry Andric else if (SatisfiesSVE) 613*0fca6ea1SDimitry Andric BuiltinType = SemaARM::ArmNonStreaming; 614*0fca6ea1SDimitry Andric else if (SatisfiesSME) 615*0fca6ea1SDimitry Andric BuiltinType = SemaARM::ArmStreaming; 616*0fca6ea1SDimitry Andric else 617*0fca6ea1SDimitry Andric // This should be diagnosed by CodeGen 618*0fca6ea1SDimitry Andric return false; 619*0fca6ea1SDimitry Andric } 620*0fca6ea1SDimitry Andric 621*0fca6ea1SDimitry Andric if (FnType != SemaARM::ArmNonStreaming && 622*0fca6ea1SDimitry Andric BuiltinType == SemaARM::ArmNonStreaming) 623*0fca6ea1SDimitry Andric S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin) 624*0fca6ea1SDimitry Andric << TheCall->getSourceRange() << "non-streaming"; 625*0fca6ea1SDimitry Andric else if (FnType != SemaARM::ArmStreaming && 626*0fca6ea1SDimitry Andric BuiltinType == SemaARM::ArmStreaming) 627*0fca6ea1SDimitry Andric S.Diag(TheCall->getBeginLoc(), diag::err_attribute_arm_sm_incompat_builtin) 628*0fca6ea1SDimitry Andric << TheCall->getSourceRange() << "streaming"; 629*0fca6ea1SDimitry Andric else 630*0fca6ea1SDimitry Andric return false; 631*0fca6ea1SDimitry Andric 632*0fca6ea1SDimitry Andric return true; 633*0fca6ea1SDimitry Andric } 634*0fca6ea1SDimitry Andric 635*0fca6ea1SDimitry Andric static bool hasArmZAState(const FunctionDecl *FD) { 636*0fca6ea1SDimitry Andric const auto *T = FD->getType()->getAs<FunctionProtoType>(); 637*0fca6ea1SDimitry Andric return (T && FunctionType::getArmZAState(T->getAArch64SMEAttributes()) != 638*0fca6ea1SDimitry Andric FunctionType::ARM_None) || 639*0fca6ea1SDimitry Andric (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZA()); 640*0fca6ea1SDimitry Andric } 641*0fca6ea1SDimitry Andric 642*0fca6ea1SDimitry Andric static bool hasArmZT0State(const FunctionDecl *FD) { 643*0fca6ea1SDimitry Andric const auto *T = FD->getType()->getAs<FunctionProtoType>(); 644*0fca6ea1SDimitry Andric return (T && FunctionType::getArmZT0State(T->getAArch64SMEAttributes()) != 645*0fca6ea1SDimitry Andric FunctionType::ARM_None) || 646*0fca6ea1SDimitry Andric (FD->hasAttr<ArmNewAttr>() && FD->getAttr<ArmNewAttr>()->isNewZT0()); 647*0fca6ea1SDimitry Andric } 648*0fca6ea1SDimitry Andric 649*0fca6ea1SDimitry Andric static ArmSMEState getSMEState(unsigned BuiltinID) { 650*0fca6ea1SDimitry Andric switch (BuiltinID) { 651*0fca6ea1SDimitry Andric default: 652*0fca6ea1SDimitry Andric return ArmNoState; 653*0fca6ea1SDimitry Andric #define GET_SME_BUILTIN_GET_STATE 654*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_builtins_za_state.inc" 655*0fca6ea1SDimitry Andric #undef GET_SME_BUILTIN_GET_STATE 656*0fca6ea1SDimitry Andric } 657*0fca6ea1SDimitry Andric } 658*0fca6ea1SDimitry Andric 659*0fca6ea1SDimitry Andric bool SemaARM::CheckSMEBuiltinFunctionCall(unsigned BuiltinID, 660*0fca6ea1SDimitry Andric CallExpr *TheCall) { 661*0fca6ea1SDimitry Andric if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { 662*0fca6ea1SDimitry Andric std::optional<ArmStreamingType> BuiltinType; 663*0fca6ea1SDimitry Andric 664*0fca6ea1SDimitry Andric switch (BuiltinID) { 665*0fca6ea1SDimitry Andric #define GET_SME_STREAMING_ATTRS 666*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_streaming_attrs.inc" 667*0fca6ea1SDimitry Andric #undef GET_SME_STREAMING_ATTRS 668*0fca6ea1SDimitry Andric } 669*0fca6ea1SDimitry Andric 670*0fca6ea1SDimitry Andric if (BuiltinType && 671*0fca6ea1SDimitry Andric checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID)) 672*0fca6ea1SDimitry Andric return true; 673*0fca6ea1SDimitry Andric 674*0fca6ea1SDimitry Andric if ((getSMEState(BuiltinID) & ArmZAMask) && !hasArmZAState(FD)) 675*0fca6ea1SDimitry Andric Diag(TheCall->getBeginLoc(), 676*0fca6ea1SDimitry Andric diag::warn_attribute_arm_za_builtin_no_za_state) 677*0fca6ea1SDimitry Andric << TheCall->getSourceRange(); 678*0fca6ea1SDimitry Andric 679*0fca6ea1SDimitry Andric if ((getSMEState(BuiltinID) & ArmZT0Mask) && !hasArmZT0State(FD)) 680*0fca6ea1SDimitry Andric Diag(TheCall->getBeginLoc(), 681*0fca6ea1SDimitry Andric diag::warn_attribute_arm_zt0_builtin_no_zt0_state) 682*0fca6ea1SDimitry Andric << TheCall->getSourceRange(); 683*0fca6ea1SDimitry Andric } 684*0fca6ea1SDimitry Andric 685*0fca6ea1SDimitry Andric // Range check SME intrinsics that take immediate values. 686*0fca6ea1SDimitry Andric SmallVector<std::tuple<int, int, int>, 3> ImmChecks; 687*0fca6ea1SDimitry Andric 688*0fca6ea1SDimitry Andric switch (BuiltinID) { 689*0fca6ea1SDimitry Andric default: 690*0fca6ea1SDimitry Andric return false; 691*0fca6ea1SDimitry Andric #define GET_SME_IMMEDIATE_CHECK 692*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sme_sema_rangechecks.inc" 693*0fca6ea1SDimitry Andric #undef GET_SME_IMMEDIATE_CHECK 694*0fca6ea1SDimitry Andric } 695*0fca6ea1SDimitry Andric 696*0fca6ea1SDimitry Andric return ParseSVEImmChecks(TheCall, ImmChecks); 697*0fca6ea1SDimitry Andric } 698*0fca6ea1SDimitry Andric 699*0fca6ea1SDimitry Andric bool SemaARM::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, 700*0fca6ea1SDimitry Andric CallExpr *TheCall) { 701*0fca6ea1SDimitry Andric if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { 702*0fca6ea1SDimitry Andric std::optional<ArmStreamingType> BuiltinType; 703*0fca6ea1SDimitry Andric 704*0fca6ea1SDimitry Andric switch (BuiltinID) { 705*0fca6ea1SDimitry Andric #define GET_SVE_STREAMING_ATTRS 706*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sve_streaming_attrs.inc" 707*0fca6ea1SDimitry Andric #undef GET_SVE_STREAMING_ATTRS 708*0fca6ea1SDimitry Andric } 709*0fca6ea1SDimitry Andric if (BuiltinType && 710*0fca6ea1SDimitry Andric checkArmStreamingBuiltin(SemaRef, TheCall, FD, *BuiltinType, BuiltinID)) 711*0fca6ea1SDimitry Andric return true; 712*0fca6ea1SDimitry Andric } 713*0fca6ea1SDimitry Andric // Range check SVE intrinsics that take immediate values. 714*0fca6ea1SDimitry Andric SmallVector<std::tuple<int, int, int>, 3> ImmChecks; 715*0fca6ea1SDimitry Andric 716*0fca6ea1SDimitry Andric switch (BuiltinID) { 717*0fca6ea1SDimitry Andric default: 718*0fca6ea1SDimitry Andric return false; 719*0fca6ea1SDimitry Andric #define GET_SVE_IMMEDIATE_CHECK 720*0fca6ea1SDimitry Andric #include "clang/Basic/arm_sve_sema_rangechecks.inc" 721*0fca6ea1SDimitry Andric #undef GET_SVE_IMMEDIATE_CHECK 722*0fca6ea1SDimitry Andric } 723*0fca6ea1SDimitry Andric 724*0fca6ea1SDimitry Andric return ParseSVEImmChecks(TheCall, ImmChecks); 725*0fca6ea1SDimitry Andric } 726*0fca6ea1SDimitry Andric 727*0fca6ea1SDimitry Andric bool SemaARM::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, 728*0fca6ea1SDimitry Andric unsigned BuiltinID, 729*0fca6ea1SDimitry Andric CallExpr *TheCall) { 730*0fca6ea1SDimitry Andric if (const FunctionDecl *FD = SemaRef.getCurFunctionDecl()) { 731*0fca6ea1SDimitry Andric 732*0fca6ea1SDimitry Andric switch (BuiltinID) { 733*0fca6ea1SDimitry Andric default: 734*0fca6ea1SDimitry Andric break; 735*0fca6ea1SDimitry Andric #define GET_NEON_BUILTINS 736*0fca6ea1SDimitry Andric #define TARGET_BUILTIN(id, ...) case NEON::BI##id: 737*0fca6ea1SDimitry Andric #define BUILTIN(id, ...) case NEON::BI##id: 738*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc" 739*0fca6ea1SDimitry Andric if (checkArmStreamingBuiltin(SemaRef, TheCall, FD, ArmNonStreaming, 740*0fca6ea1SDimitry Andric BuiltinID)) 741*0fca6ea1SDimitry Andric return true; 742*0fca6ea1SDimitry Andric break; 743*0fca6ea1SDimitry Andric #undef TARGET_BUILTIN 744*0fca6ea1SDimitry Andric #undef BUILTIN 745*0fca6ea1SDimitry Andric #undef GET_NEON_BUILTINS 746*0fca6ea1SDimitry Andric } 747*0fca6ea1SDimitry Andric } 748*0fca6ea1SDimitry Andric 749*0fca6ea1SDimitry Andric llvm::APSInt Result; 750*0fca6ea1SDimitry Andric uint64_t mask = 0; 751*0fca6ea1SDimitry Andric unsigned TV = 0; 752*0fca6ea1SDimitry Andric int PtrArgNum = -1; 753*0fca6ea1SDimitry Andric bool HasConstPtr = false; 754*0fca6ea1SDimitry Andric switch (BuiltinID) { 755*0fca6ea1SDimitry Andric #define GET_NEON_OVERLOAD_CHECK 756*0fca6ea1SDimitry Andric #include "clang/Basic/arm_fp16.inc" 757*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc" 758*0fca6ea1SDimitry Andric #undef GET_NEON_OVERLOAD_CHECK 759*0fca6ea1SDimitry Andric } 760*0fca6ea1SDimitry Andric 761*0fca6ea1SDimitry Andric // For NEON intrinsics which are overloaded on vector element type, validate 762*0fca6ea1SDimitry Andric // the immediate which specifies which variant to emit. 763*0fca6ea1SDimitry Andric unsigned ImmArg = TheCall->getNumArgs() - 1; 764*0fca6ea1SDimitry Andric if (mask) { 765*0fca6ea1SDimitry Andric if (SemaRef.BuiltinConstantArg(TheCall, ImmArg, Result)) 766*0fca6ea1SDimitry Andric return true; 767*0fca6ea1SDimitry Andric 768*0fca6ea1SDimitry Andric TV = Result.getLimitedValue(64); 769*0fca6ea1SDimitry Andric if ((TV > 63) || (mask & (1ULL << TV)) == 0) 770*0fca6ea1SDimitry Andric return Diag(TheCall->getBeginLoc(), diag::err_invalid_neon_type_code) 771*0fca6ea1SDimitry Andric << TheCall->getArg(ImmArg)->getSourceRange(); 772*0fca6ea1SDimitry Andric } 773*0fca6ea1SDimitry Andric 774*0fca6ea1SDimitry Andric if (PtrArgNum >= 0) { 775*0fca6ea1SDimitry Andric // Check that pointer arguments have the specified type. 776*0fca6ea1SDimitry Andric Expr *Arg = TheCall->getArg(PtrArgNum); 777*0fca6ea1SDimitry Andric if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) 778*0fca6ea1SDimitry Andric Arg = ICE->getSubExpr(); 779*0fca6ea1SDimitry Andric ExprResult RHS = SemaRef.DefaultFunctionArrayLvalueConversion(Arg); 780*0fca6ea1SDimitry Andric QualType RHSTy = RHS.get()->getType(); 781*0fca6ea1SDimitry Andric 782*0fca6ea1SDimitry Andric llvm::Triple::ArchType Arch = TI.getTriple().getArch(); 783*0fca6ea1SDimitry Andric bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || 784*0fca6ea1SDimitry Andric Arch == llvm::Triple::aarch64_32 || 785*0fca6ea1SDimitry Andric Arch == llvm::Triple::aarch64_be; 786*0fca6ea1SDimitry Andric bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong; 787*0fca6ea1SDimitry Andric QualType EltTy = getNeonEltType(NeonTypeFlags(TV), getASTContext(), 788*0fca6ea1SDimitry Andric IsPolyUnsigned, IsInt64Long); 789*0fca6ea1SDimitry Andric if (HasConstPtr) 790*0fca6ea1SDimitry Andric EltTy = EltTy.withConst(); 791*0fca6ea1SDimitry Andric QualType LHSTy = getASTContext().getPointerType(EltTy); 792*0fca6ea1SDimitry Andric Sema::AssignConvertType ConvTy; 793*0fca6ea1SDimitry Andric ConvTy = SemaRef.CheckSingleAssignmentConstraints(LHSTy, RHS); 794*0fca6ea1SDimitry Andric if (RHS.isInvalid()) 795*0fca6ea1SDimitry Andric return true; 796*0fca6ea1SDimitry Andric if (SemaRef.DiagnoseAssignmentResult(ConvTy, Arg->getBeginLoc(), LHSTy, 797*0fca6ea1SDimitry Andric RHSTy, RHS.get(), Sema::AA_Assigning)) 798*0fca6ea1SDimitry Andric return true; 799*0fca6ea1SDimitry Andric } 800*0fca6ea1SDimitry Andric 801*0fca6ea1SDimitry Andric // For NEON intrinsics which take an immediate value as part of the 802*0fca6ea1SDimitry Andric // instruction, range check them here. 803*0fca6ea1SDimitry Andric unsigned i = 0, l = 0, u = 0; 804*0fca6ea1SDimitry Andric switch (BuiltinID) { 805*0fca6ea1SDimitry Andric default: 806*0fca6ea1SDimitry Andric return false; 807*0fca6ea1SDimitry Andric #define GET_NEON_IMMEDIATE_CHECK 808*0fca6ea1SDimitry Andric #include "clang/Basic/arm_fp16.inc" 809*0fca6ea1SDimitry Andric #include "clang/Basic/arm_neon.inc" 810*0fca6ea1SDimitry Andric #undef GET_NEON_IMMEDIATE_CHECK 811*0fca6ea1SDimitry Andric } 812*0fca6ea1SDimitry Andric 813*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l); 814*0fca6ea1SDimitry Andric } 815*0fca6ea1SDimitry Andric 816*0fca6ea1SDimitry Andric bool SemaARM::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, 817*0fca6ea1SDimitry Andric CallExpr *TheCall) { 818*0fca6ea1SDimitry Andric switch (BuiltinID) { 819*0fca6ea1SDimitry Andric default: 820*0fca6ea1SDimitry Andric return false; 821*0fca6ea1SDimitry Andric #include "clang/Basic/arm_mve_builtin_sema.inc" 822*0fca6ea1SDimitry Andric } 823*0fca6ea1SDimitry Andric } 824*0fca6ea1SDimitry Andric 825*0fca6ea1SDimitry Andric bool SemaARM::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, 826*0fca6ea1SDimitry Andric unsigned BuiltinID, 827*0fca6ea1SDimitry Andric CallExpr *TheCall) { 828*0fca6ea1SDimitry Andric bool Err = false; 829*0fca6ea1SDimitry Andric switch (BuiltinID) { 830*0fca6ea1SDimitry Andric default: 831*0fca6ea1SDimitry Andric return false; 832*0fca6ea1SDimitry Andric #include "clang/Basic/arm_cde_builtin_sema.inc" 833*0fca6ea1SDimitry Andric } 834*0fca6ea1SDimitry Andric 835*0fca6ea1SDimitry Andric if (Err) 836*0fca6ea1SDimitry Andric return true; 837*0fca6ea1SDimitry Andric 838*0fca6ea1SDimitry Andric return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true); 839*0fca6ea1SDimitry Andric } 840*0fca6ea1SDimitry Andric 841*0fca6ea1SDimitry Andric bool SemaARM::CheckARMCoprocessorImmediate(const TargetInfo &TI, 842*0fca6ea1SDimitry Andric const Expr *CoprocArg, 843*0fca6ea1SDimitry Andric bool WantCDE) { 844*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 845*0fca6ea1SDimitry Andric if (SemaRef.isConstantEvaluatedContext()) 846*0fca6ea1SDimitry Andric return false; 847*0fca6ea1SDimitry Andric 848*0fca6ea1SDimitry Andric // We can't check the value of a dependent argument. 849*0fca6ea1SDimitry Andric if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent()) 850*0fca6ea1SDimitry Andric return false; 851*0fca6ea1SDimitry Andric 852*0fca6ea1SDimitry Andric llvm::APSInt CoprocNoAP = *CoprocArg->getIntegerConstantExpr(Context); 853*0fca6ea1SDimitry Andric int64_t CoprocNo = CoprocNoAP.getExtValue(); 854*0fca6ea1SDimitry Andric assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative"); 855*0fca6ea1SDimitry Andric 856*0fca6ea1SDimitry Andric uint32_t CDECoprocMask = TI.getARMCDECoprocMask(); 857*0fca6ea1SDimitry Andric bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo)); 858*0fca6ea1SDimitry Andric 859*0fca6ea1SDimitry Andric if (IsCDECoproc != WantCDE) 860*0fca6ea1SDimitry Andric return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc) 861*0fca6ea1SDimitry Andric << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange(); 862*0fca6ea1SDimitry Andric 863*0fca6ea1SDimitry Andric return false; 864*0fca6ea1SDimitry Andric } 865*0fca6ea1SDimitry Andric 866*0fca6ea1SDimitry Andric bool SemaARM::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, 867*0fca6ea1SDimitry Andric CallExpr *TheCall, 868*0fca6ea1SDimitry Andric unsigned MaxWidth) { 869*0fca6ea1SDimitry Andric assert((BuiltinID == ARM::BI__builtin_arm_ldrex || 870*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_ldaex || 871*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_strex || 872*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_stlex || 873*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldrex || 874*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldaex || 875*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_strex || 876*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_stlex) && 877*0fca6ea1SDimitry Andric "unexpected ARM builtin"); 878*0fca6ea1SDimitry Andric bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || 879*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_ldaex || 880*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldrex || 881*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldaex; 882*0fca6ea1SDimitry Andric 883*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 884*0fca6ea1SDimitry Andric DeclRefExpr *DRE = 885*0fca6ea1SDimitry Andric cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts()); 886*0fca6ea1SDimitry Andric 887*0fca6ea1SDimitry Andric // Ensure that we have the proper number of arguments. 888*0fca6ea1SDimitry Andric if (SemaRef.checkArgCount(TheCall, IsLdrex ? 1 : 2)) 889*0fca6ea1SDimitry Andric return true; 890*0fca6ea1SDimitry Andric 891*0fca6ea1SDimitry Andric // Inspect the pointer argument of the atomic builtin. This should always be 892*0fca6ea1SDimitry Andric // a pointer type, whose element is an integral scalar or pointer type. 893*0fca6ea1SDimitry Andric // Because it is a pointer type, we don't have to worry about any implicit 894*0fca6ea1SDimitry Andric // casts here. 895*0fca6ea1SDimitry Andric Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1); 896*0fca6ea1SDimitry Andric ExprResult PointerArgRes = 897*0fca6ea1SDimitry Andric SemaRef.DefaultFunctionArrayLvalueConversion(PointerArg); 898*0fca6ea1SDimitry Andric if (PointerArgRes.isInvalid()) 899*0fca6ea1SDimitry Andric return true; 900*0fca6ea1SDimitry Andric PointerArg = PointerArgRes.get(); 901*0fca6ea1SDimitry Andric 902*0fca6ea1SDimitry Andric const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>(); 903*0fca6ea1SDimitry Andric if (!pointerType) { 904*0fca6ea1SDimitry Andric Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer) 905*0fca6ea1SDimitry Andric << PointerArg->getType() << 0 << PointerArg->getSourceRange(); 906*0fca6ea1SDimitry Andric return true; 907*0fca6ea1SDimitry Andric } 908*0fca6ea1SDimitry Andric 909*0fca6ea1SDimitry Andric // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next 910*0fca6ea1SDimitry Andric // task is to insert the appropriate casts into the AST. First work out just 911*0fca6ea1SDimitry Andric // what the appropriate type is. 912*0fca6ea1SDimitry Andric QualType ValType = pointerType->getPointeeType(); 913*0fca6ea1SDimitry Andric QualType AddrType = ValType.getUnqualifiedType().withVolatile(); 914*0fca6ea1SDimitry Andric if (IsLdrex) 915*0fca6ea1SDimitry Andric AddrType.addConst(); 916*0fca6ea1SDimitry Andric 917*0fca6ea1SDimitry Andric // Issue a warning if the cast is dodgy. 918*0fca6ea1SDimitry Andric CastKind CastNeeded = CK_NoOp; 919*0fca6ea1SDimitry Andric if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { 920*0fca6ea1SDimitry Andric CastNeeded = CK_BitCast; 921*0fca6ea1SDimitry Andric Diag(DRE->getBeginLoc(), diag::ext_typecheck_convert_discards_qualifiers) 922*0fca6ea1SDimitry Andric << PointerArg->getType() << Context.getPointerType(AddrType) 923*0fca6ea1SDimitry Andric << Sema::AA_Passing << PointerArg->getSourceRange(); 924*0fca6ea1SDimitry Andric } 925*0fca6ea1SDimitry Andric 926*0fca6ea1SDimitry Andric // Finally, do the cast and replace the argument with the corrected version. 927*0fca6ea1SDimitry Andric AddrType = Context.getPointerType(AddrType); 928*0fca6ea1SDimitry Andric PointerArgRes = SemaRef.ImpCastExprToType(PointerArg, AddrType, CastNeeded); 929*0fca6ea1SDimitry Andric if (PointerArgRes.isInvalid()) 930*0fca6ea1SDimitry Andric return true; 931*0fca6ea1SDimitry Andric PointerArg = PointerArgRes.get(); 932*0fca6ea1SDimitry Andric 933*0fca6ea1SDimitry Andric TheCall->setArg(IsLdrex ? 0 : 1, PointerArg); 934*0fca6ea1SDimitry Andric 935*0fca6ea1SDimitry Andric // In general, we allow ints, floats and pointers to be loaded and stored. 936*0fca6ea1SDimitry Andric if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && 937*0fca6ea1SDimitry Andric !ValType->isBlockPointerType() && !ValType->isFloatingType()) { 938*0fca6ea1SDimitry Andric Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intfltptr) 939*0fca6ea1SDimitry Andric << PointerArg->getType() << 0 << PointerArg->getSourceRange(); 940*0fca6ea1SDimitry Andric return true; 941*0fca6ea1SDimitry Andric } 942*0fca6ea1SDimitry Andric 943*0fca6ea1SDimitry Andric // But ARM doesn't have instructions to deal with 128-bit versions. 944*0fca6ea1SDimitry Andric if (Context.getTypeSize(ValType) > MaxWidth) { 945*0fca6ea1SDimitry Andric assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); 946*0fca6ea1SDimitry Andric Diag(DRE->getBeginLoc(), diag::err_atomic_exclusive_builtin_pointer_size) 947*0fca6ea1SDimitry Andric << PointerArg->getType() << PointerArg->getSourceRange(); 948*0fca6ea1SDimitry Andric return true; 949*0fca6ea1SDimitry Andric } 950*0fca6ea1SDimitry Andric 951*0fca6ea1SDimitry Andric switch (ValType.getObjCLifetime()) { 952*0fca6ea1SDimitry Andric case Qualifiers::OCL_None: 953*0fca6ea1SDimitry Andric case Qualifiers::OCL_ExplicitNone: 954*0fca6ea1SDimitry Andric // okay 955*0fca6ea1SDimitry Andric break; 956*0fca6ea1SDimitry Andric 957*0fca6ea1SDimitry Andric case Qualifiers::OCL_Weak: 958*0fca6ea1SDimitry Andric case Qualifiers::OCL_Strong: 959*0fca6ea1SDimitry Andric case Qualifiers::OCL_Autoreleasing: 960*0fca6ea1SDimitry Andric Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership) 961*0fca6ea1SDimitry Andric << ValType << PointerArg->getSourceRange(); 962*0fca6ea1SDimitry Andric return true; 963*0fca6ea1SDimitry Andric } 964*0fca6ea1SDimitry Andric 965*0fca6ea1SDimitry Andric if (IsLdrex) { 966*0fca6ea1SDimitry Andric TheCall->setType(ValType); 967*0fca6ea1SDimitry Andric return false; 968*0fca6ea1SDimitry Andric } 969*0fca6ea1SDimitry Andric 970*0fca6ea1SDimitry Andric // Initialize the argument to be stored. 971*0fca6ea1SDimitry Andric ExprResult ValArg = TheCall->getArg(0); 972*0fca6ea1SDimitry Andric InitializedEntity Entity = InitializedEntity::InitializeParameter( 973*0fca6ea1SDimitry Andric Context, ValType, /*consume*/ false); 974*0fca6ea1SDimitry Andric ValArg = SemaRef.PerformCopyInitialization(Entity, SourceLocation(), ValArg); 975*0fca6ea1SDimitry Andric if (ValArg.isInvalid()) 976*0fca6ea1SDimitry Andric return true; 977*0fca6ea1SDimitry Andric TheCall->setArg(0, ValArg.get()); 978*0fca6ea1SDimitry Andric 979*0fca6ea1SDimitry Andric // __builtin_arm_strex always returns an int. It's marked as such in the .def, 980*0fca6ea1SDimitry Andric // but the custom checker bypasses all default analysis. 981*0fca6ea1SDimitry Andric TheCall->setType(Context.IntTy); 982*0fca6ea1SDimitry Andric return false; 983*0fca6ea1SDimitry Andric } 984*0fca6ea1SDimitry Andric 985*0fca6ea1SDimitry Andric bool SemaARM::CheckARMBuiltinFunctionCall(const TargetInfo &TI, 986*0fca6ea1SDimitry Andric unsigned BuiltinID, 987*0fca6ea1SDimitry Andric CallExpr *TheCall) { 988*0fca6ea1SDimitry Andric if (BuiltinID == ARM::BI__builtin_arm_ldrex || 989*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_ldaex || 990*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_strex || 991*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_stlex) { 992*0fca6ea1SDimitry Andric return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); 993*0fca6ea1SDimitry Andric } 994*0fca6ea1SDimitry Andric 995*0fca6ea1SDimitry Andric if (BuiltinID == ARM::BI__builtin_arm_prefetch) { 996*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) || 997*0fca6ea1SDimitry Andric SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 1); 998*0fca6ea1SDimitry Andric } 999*0fca6ea1SDimitry Andric 1000*0fca6ea1SDimitry Andric if (BuiltinID == ARM::BI__builtin_arm_rsr64 || 1001*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsr64) 1002*0fca6ea1SDimitry Andric return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); 1003*0fca6ea1SDimitry Andric 1004*0fca6ea1SDimitry Andric if (BuiltinID == ARM::BI__builtin_arm_rsr || 1005*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_rsrp || 1006*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsr || 1007*0fca6ea1SDimitry Andric BuiltinID == ARM::BI__builtin_arm_wsrp) 1008*0fca6ea1SDimitry Andric return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); 1009*0fca6ea1SDimitry Andric 1010*0fca6ea1SDimitry Andric if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) 1011*0fca6ea1SDimitry Andric return true; 1012*0fca6ea1SDimitry Andric if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) 1013*0fca6ea1SDimitry Andric return true; 1014*0fca6ea1SDimitry Andric if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall)) 1015*0fca6ea1SDimitry Andric return true; 1016*0fca6ea1SDimitry Andric 1017*0fca6ea1SDimitry Andric // For intrinsics which take an immediate value as part of the instruction, 1018*0fca6ea1SDimitry Andric // range check them here. 1019*0fca6ea1SDimitry Andric // FIXME: VFP Intrinsics should error if VFP not present. 1020*0fca6ea1SDimitry Andric switch (BuiltinID) { 1021*0fca6ea1SDimitry Andric default: 1022*0fca6ea1SDimitry Andric return false; 1023*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ssat: 1024*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 32); 1025*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_usat: 1026*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 31); 1027*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ssat16: 1028*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 1, 16); 1029*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_usat16: 1030*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 15); 1031*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_vcvtr_f: 1032*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_vcvtr_d: 1033*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1); 1034*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_dmb: 1035*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_dsb: 1036*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_isb: 1037*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_dbg: 1038*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15); 1039*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_cdp: 1040*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_cdp2: 1041*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mcr: 1042*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mcr2: 1043*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mrc: 1044*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mrc2: 1045*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mcrr: 1046*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mcrr2: 1047*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mrrc: 1048*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_mrrc2: 1049*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ldc: 1050*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ldcl: 1051*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ldc2: 1052*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_ldc2l: 1053*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_stc: 1054*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_stcl: 1055*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_stc2: 1056*0fca6ea1SDimitry Andric case ARM::BI__builtin_arm_stc2l: 1057*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 15) || 1058*0fca6ea1SDimitry Andric CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), 1059*0fca6ea1SDimitry Andric /*WantCDE*/ false); 1060*0fca6ea1SDimitry Andric } 1061*0fca6ea1SDimitry Andric } 1062*0fca6ea1SDimitry Andric 1063*0fca6ea1SDimitry Andric bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, 1064*0fca6ea1SDimitry Andric unsigned BuiltinID, 1065*0fca6ea1SDimitry Andric CallExpr *TheCall) { 1066*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_ldrex || 1067*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldaex || 1068*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_strex || 1069*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_stlex) { 1070*0fca6ea1SDimitry Andric return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); 1071*0fca6ea1SDimitry Andric } 1072*0fca6ea1SDimitry Andric 1073*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { 1074*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 1) || 1075*0fca6ea1SDimitry Andric SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 3) || 1076*0fca6ea1SDimitry Andric SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 1) || 1077*0fca6ea1SDimitry Andric SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 1); 1078*0fca6ea1SDimitry Andric } 1079*0fca6ea1SDimitry Andric 1080*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || 1081*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr64 || 1082*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_rsr128 || 1083*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr128) 1084*0fca6ea1SDimitry Andric return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); 1085*0fca6ea1SDimitry Andric 1086*0fca6ea1SDimitry Andric // Memory Tagging Extensions (MTE) Intrinsics 1087*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_irg || 1088*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_addg || 1089*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_gmi || 1090*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_ldg || 1091*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_stg || 1092*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_subp) { 1093*0fca6ea1SDimitry Andric return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); 1094*0fca6ea1SDimitry Andric } 1095*0fca6ea1SDimitry Andric 1096*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__builtin_arm_rsr || 1097*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_rsrp || 1098*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsr || 1099*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI__builtin_arm_wsrp) 1100*0fca6ea1SDimitry Andric return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); 1101*0fca6ea1SDimitry Andric 1102*0fca6ea1SDimitry Andric // Only check the valid encoding range. Any constant in this range would be 1103*0fca6ea1SDimitry Andric // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw 1104*0fca6ea1SDimitry Andric // an exception for incorrect registers. This matches MSVC behavior. 1105*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI_ReadStatusReg || 1106*0fca6ea1SDimitry Andric BuiltinID == AArch64::BI_WriteStatusReg) 1107*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); 1108*0fca6ea1SDimitry Andric 1109*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__getReg) 1110*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31); 1111*0fca6ea1SDimitry Andric 1112*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__break) 1113*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); 1114*0fca6ea1SDimitry Andric 1115*0fca6ea1SDimitry Andric if (BuiltinID == AArch64::BI__hlt) 1116*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); 1117*0fca6ea1SDimitry Andric 1118*0fca6ea1SDimitry Andric if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) 1119*0fca6ea1SDimitry Andric return true; 1120*0fca6ea1SDimitry Andric 1121*0fca6ea1SDimitry Andric if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall)) 1122*0fca6ea1SDimitry Andric return true; 1123*0fca6ea1SDimitry Andric 1124*0fca6ea1SDimitry Andric if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall)) 1125*0fca6ea1SDimitry Andric return true; 1126*0fca6ea1SDimitry Andric 1127*0fca6ea1SDimitry Andric // For intrinsics which take an immediate value as part of the instruction, 1128*0fca6ea1SDimitry Andric // range check them here. 1129*0fca6ea1SDimitry Andric unsigned i = 0, l = 0, u = 0; 1130*0fca6ea1SDimitry Andric switch (BuiltinID) { 1131*0fca6ea1SDimitry Andric default: return false; 1132*0fca6ea1SDimitry Andric case AArch64::BI__builtin_arm_dmb: 1133*0fca6ea1SDimitry Andric case AArch64::BI__builtin_arm_dsb: 1134*0fca6ea1SDimitry Andric case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; 1135*0fca6ea1SDimitry Andric case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; 1136*0fca6ea1SDimitry Andric } 1137*0fca6ea1SDimitry Andric 1138*0fca6ea1SDimitry Andric return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u + l); 1139*0fca6ea1SDimitry Andric } 1140*0fca6ea1SDimitry Andric 1141*0fca6ea1SDimitry Andric namespace { 1142*0fca6ea1SDimitry Andric struct IntrinToName { 1143*0fca6ea1SDimitry Andric uint32_t Id; 1144*0fca6ea1SDimitry Andric int32_t FullName; 1145*0fca6ea1SDimitry Andric int32_t ShortName; 1146*0fca6ea1SDimitry Andric }; 1147*0fca6ea1SDimitry Andric } // unnamed namespace 1148*0fca6ea1SDimitry Andric 1149*0fca6ea1SDimitry Andric static bool BuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, 1150*0fca6ea1SDimitry Andric ArrayRef<IntrinToName> Map, 1151*0fca6ea1SDimitry Andric const char *IntrinNames) { 1152*0fca6ea1SDimitry Andric AliasName.consume_front("__arm_"); 1153*0fca6ea1SDimitry Andric const IntrinToName *It = 1154*0fca6ea1SDimitry Andric llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { 1155*0fca6ea1SDimitry Andric return L.Id < Id; 1156*0fca6ea1SDimitry Andric }); 1157*0fca6ea1SDimitry Andric if (It == Map.end() || It->Id != BuiltinID) 1158*0fca6ea1SDimitry Andric return false; 1159*0fca6ea1SDimitry Andric StringRef FullName(&IntrinNames[It->FullName]); 1160*0fca6ea1SDimitry Andric if (AliasName == FullName) 1161*0fca6ea1SDimitry Andric return true; 1162*0fca6ea1SDimitry Andric if (It->ShortName == -1) 1163*0fca6ea1SDimitry Andric return false; 1164*0fca6ea1SDimitry Andric StringRef ShortName(&IntrinNames[It->ShortName]); 1165*0fca6ea1SDimitry Andric return AliasName == ShortName; 1166*0fca6ea1SDimitry Andric } 1167*0fca6ea1SDimitry Andric 1168*0fca6ea1SDimitry Andric bool SemaARM::MveAliasValid(unsigned BuiltinID, StringRef AliasName) { 1169*0fca6ea1SDimitry Andric #include "clang/Basic/arm_mve_builtin_aliases.inc" 1170*0fca6ea1SDimitry Andric // The included file defines: 1171*0fca6ea1SDimitry Andric // - ArrayRef<IntrinToName> Map 1172*0fca6ea1SDimitry Andric // - const char IntrinNames[] 1173*0fca6ea1SDimitry Andric return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); 1174*0fca6ea1SDimitry Andric } 1175*0fca6ea1SDimitry Andric 1176*0fca6ea1SDimitry Andric bool SemaARM::CdeAliasValid(unsigned BuiltinID, StringRef AliasName) { 1177*0fca6ea1SDimitry Andric #include "clang/Basic/arm_cde_builtin_aliases.inc" 1178*0fca6ea1SDimitry Andric return BuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); 1179*0fca6ea1SDimitry Andric } 1180*0fca6ea1SDimitry Andric 1181*0fca6ea1SDimitry Andric bool SemaARM::SveAliasValid(unsigned BuiltinID, StringRef AliasName) { 1182*0fca6ea1SDimitry Andric if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) 1183*0fca6ea1SDimitry Andric BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID); 1184*0fca6ea1SDimitry Andric return BuiltinID >= AArch64::FirstSVEBuiltin && 1185*0fca6ea1SDimitry Andric BuiltinID <= AArch64::LastSVEBuiltin; 1186*0fca6ea1SDimitry Andric } 1187*0fca6ea1SDimitry Andric 1188*0fca6ea1SDimitry Andric bool SemaARM::SmeAliasValid(unsigned BuiltinID, StringRef AliasName) { 1189*0fca6ea1SDimitry Andric if (getASTContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) 1190*0fca6ea1SDimitry Andric BuiltinID = getASTContext().BuiltinInfo.getAuxBuiltinID(BuiltinID); 1191*0fca6ea1SDimitry Andric return BuiltinID >= AArch64::FirstSMEBuiltin && 1192*0fca6ea1SDimitry Andric BuiltinID <= AArch64::LastSMEBuiltin; 1193*0fca6ea1SDimitry Andric } 1194*0fca6ea1SDimitry Andric 1195*0fca6ea1SDimitry Andric void SemaARM::handleBuiltinAliasAttr(Decl *D, const ParsedAttr &AL) { 1196*0fca6ea1SDimitry Andric ASTContext &Context = getASTContext(); 1197*0fca6ea1SDimitry Andric if (!AL.isArgIdent(0)) { 1198*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_argument_n_type) 1199*0fca6ea1SDimitry Andric << AL << 1 << AANT_ArgumentIdentifier; 1200*0fca6ea1SDimitry Andric return; 1201*0fca6ea1SDimitry Andric } 1202*0fca6ea1SDimitry Andric 1203*0fca6ea1SDimitry Andric IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; 1204*0fca6ea1SDimitry Andric unsigned BuiltinID = Ident->getBuiltinID(); 1205*0fca6ea1SDimitry Andric StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName(); 1206*0fca6ea1SDimitry Andric 1207*0fca6ea1SDimitry Andric bool IsAArch64 = Context.getTargetInfo().getTriple().isAArch64(); 1208*0fca6ea1SDimitry Andric if ((IsAArch64 && !SveAliasValid(BuiltinID, AliasName) && 1209*0fca6ea1SDimitry Andric !SmeAliasValid(BuiltinID, AliasName)) || 1210*0fca6ea1SDimitry Andric (!IsAArch64 && !MveAliasValid(BuiltinID, AliasName) && 1211*0fca6ea1SDimitry Andric !CdeAliasValid(BuiltinID, AliasName))) { 1212*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); 1213*0fca6ea1SDimitry Andric return; 1214*0fca6ea1SDimitry Andric } 1215*0fca6ea1SDimitry Andric 1216*0fca6ea1SDimitry Andric D->addAttr(::new (Context) ArmBuiltinAliasAttr(Context, AL, Ident)); 1217*0fca6ea1SDimitry Andric } 1218*0fca6ea1SDimitry Andric 1219*0fca6ea1SDimitry Andric static bool checkNewAttrMutualExclusion( 1220*0fca6ea1SDimitry Andric Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT, 1221*0fca6ea1SDimitry Andric FunctionType::ArmStateValue CurrentState, StringRef StateName) { 1222*0fca6ea1SDimitry Andric auto CheckForIncompatibleAttr = 1223*0fca6ea1SDimitry Andric [&](FunctionType::ArmStateValue IncompatibleState, 1224*0fca6ea1SDimitry Andric StringRef IncompatibleStateName) { 1225*0fca6ea1SDimitry Andric if (CurrentState == IncompatibleState) { 1226*0fca6ea1SDimitry Andric S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) 1227*0fca6ea1SDimitry Andric << (std::string("'__arm_new(\"") + StateName.str() + "\")'") 1228*0fca6ea1SDimitry Andric << (std::string("'") + IncompatibleStateName.str() + "(\"" + 1229*0fca6ea1SDimitry Andric StateName.str() + "\")'") 1230*0fca6ea1SDimitry Andric << true; 1231*0fca6ea1SDimitry Andric AL.setInvalid(); 1232*0fca6ea1SDimitry Andric } 1233*0fca6ea1SDimitry Andric }; 1234*0fca6ea1SDimitry Andric 1235*0fca6ea1SDimitry Andric CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in"); 1236*0fca6ea1SDimitry Andric CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out"); 1237*0fca6ea1SDimitry Andric CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout"); 1238*0fca6ea1SDimitry Andric CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves"); 1239*0fca6ea1SDimitry Andric return AL.isInvalid(); 1240*0fca6ea1SDimitry Andric } 1241*0fca6ea1SDimitry Andric 1242*0fca6ea1SDimitry Andric void SemaARM::handleNewAttr(Decl *D, const ParsedAttr &AL) { 1243*0fca6ea1SDimitry Andric if (!AL.getNumArgs()) { 1244*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_missing_arm_state) << AL; 1245*0fca6ea1SDimitry Andric AL.setInvalid(); 1246*0fca6ea1SDimitry Andric return; 1247*0fca6ea1SDimitry Andric } 1248*0fca6ea1SDimitry Andric 1249*0fca6ea1SDimitry Andric std::vector<StringRef> NewState; 1250*0fca6ea1SDimitry Andric if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) { 1251*0fca6ea1SDimitry Andric for (StringRef S : ExistingAttr->newArgs()) 1252*0fca6ea1SDimitry Andric NewState.push_back(S); 1253*0fca6ea1SDimitry Andric } 1254*0fca6ea1SDimitry Andric 1255*0fca6ea1SDimitry Andric bool HasZA = false; 1256*0fca6ea1SDimitry Andric bool HasZT0 = false; 1257*0fca6ea1SDimitry Andric for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { 1258*0fca6ea1SDimitry Andric StringRef StateName; 1259*0fca6ea1SDimitry Andric SourceLocation LiteralLoc; 1260*0fca6ea1SDimitry Andric if (!SemaRef.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc)) 1261*0fca6ea1SDimitry Andric return; 1262*0fca6ea1SDimitry Andric 1263*0fca6ea1SDimitry Andric if (StateName == "za") 1264*0fca6ea1SDimitry Andric HasZA = true; 1265*0fca6ea1SDimitry Andric else if (StateName == "zt0") 1266*0fca6ea1SDimitry Andric HasZT0 = true; 1267*0fca6ea1SDimitry Andric else { 1268*0fca6ea1SDimitry Andric Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName; 1269*0fca6ea1SDimitry Andric AL.setInvalid(); 1270*0fca6ea1SDimitry Andric return; 1271*0fca6ea1SDimitry Andric } 1272*0fca6ea1SDimitry Andric 1273*0fca6ea1SDimitry Andric if (!llvm::is_contained(NewState, StateName)) // Avoid adding duplicates. 1274*0fca6ea1SDimitry Andric NewState.push_back(StateName); 1275*0fca6ea1SDimitry Andric } 1276*0fca6ea1SDimitry Andric 1277*0fca6ea1SDimitry Andric if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) { 1278*0fca6ea1SDimitry Andric FunctionType::ArmStateValue ZAState = 1279*0fca6ea1SDimitry Andric FunctionType::getArmZAState(FPT->getAArch64SMEAttributes()); 1280*0fca6ea1SDimitry Andric if (HasZA && ZAState != FunctionType::ARM_None && 1281*0fca6ea1SDimitry Andric checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZAState, "za")) 1282*0fca6ea1SDimitry Andric return; 1283*0fca6ea1SDimitry Andric FunctionType::ArmStateValue ZT0State = 1284*0fca6ea1SDimitry Andric FunctionType::getArmZT0State(FPT->getAArch64SMEAttributes()); 1285*0fca6ea1SDimitry Andric if (HasZT0 && ZT0State != FunctionType::ARM_None && 1286*0fca6ea1SDimitry Andric checkNewAttrMutualExclusion(SemaRef, AL, FPT, ZT0State, "zt0")) 1287*0fca6ea1SDimitry Andric return; 1288*0fca6ea1SDimitry Andric } 1289*0fca6ea1SDimitry Andric 1290*0fca6ea1SDimitry Andric D->dropAttr<ArmNewAttr>(); 1291*0fca6ea1SDimitry Andric D->addAttr(::new (getASTContext()) ArmNewAttr( 1292*0fca6ea1SDimitry Andric getASTContext(), AL, NewState.data(), NewState.size())); 1293*0fca6ea1SDimitry Andric } 1294*0fca6ea1SDimitry Andric 1295*0fca6ea1SDimitry Andric void SemaARM::handleCmseNSEntryAttr(Decl *D, const ParsedAttr &AL) { 1296*0fca6ea1SDimitry Andric if (getLangOpts().CPlusPlus && !D->getDeclContext()->isExternCContext()) { 1297*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL; 1298*0fca6ea1SDimitry Andric return; 1299*0fca6ea1SDimitry Andric } 1300*0fca6ea1SDimitry Andric 1301*0fca6ea1SDimitry Andric const auto *FD = cast<FunctionDecl>(D); 1302*0fca6ea1SDimitry Andric if (!FD->isExternallyVisible()) { 1303*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static); 1304*0fca6ea1SDimitry Andric return; 1305*0fca6ea1SDimitry Andric } 1306*0fca6ea1SDimitry Andric 1307*0fca6ea1SDimitry Andric D->addAttr(::new (getASTContext()) CmseNSEntryAttr(getASTContext(), AL)); 1308*0fca6ea1SDimitry Andric } 1309*0fca6ea1SDimitry Andric 1310*0fca6ea1SDimitry Andric void SemaARM::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { 1311*0fca6ea1SDimitry Andric // Check the attribute arguments. 1312*0fca6ea1SDimitry Andric if (AL.getNumArgs() > 1) { 1313*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1; 1314*0fca6ea1SDimitry Andric return; 1315*0fca6ea1SDimitry Andric } 1316*0fca6ea1SDimitry Andric 1317*0fca6ea1SDimitry Andric StringRef Str; 1318*0fca6ea1SDimitry Andric SourceLocation ArgLoc; 1319*0fca6ea1SDimitry Andric 1320*0fca6ea1SDimitry Andric if (AL.getNumArgs() == 0) 1321*0fca6ea1SDimitry Andric Str = ""; 1322*0fca6ea1SDimitry Andric else if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) 1323*0fca6ea1SDimitry Andric return; 1324*0fca6ea1SDimitry Andric 1325*0fca6ea1SDimitry Andric ARMInterruptAttr::InterruptType Kind; 1326*0fca6ea1SDimitry Andric if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { 1327*0fca6ea1SDimitry Andric Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) 1328*0fca6ea1SDimitry Andric << AL << Str << ArgLoc; 1329*0fca6ea1SDimitry Andric return; 1330*0fca6ea1SDimitry Andric } 1331*0fca6ea1SDimitry Andric 1332*0fca6ea1SDimitry Andric const TargetInfo &TI = getASTContext().getTargetInfo(); 1333*0fca6ea1SDimitry Andric if (TI.hasFeature("vfp")) 1334*0fca6ea1SDimitry Andric Diag(D->getLocation(), diag::warn_arm_interrupt_vfp_clobber); 1335*0fca6ea1SDimitry Andric 1336*0fca6ea1SDimitry Andric D->addAttr(::new (getASTContext()) 1337*0fca6ea1SDimitry Andric ARMInterruptAttr(getASTContext(), AL, Kind)); 1338*0fca6ea1SDimitry Andric } 1339*0fca6ea1SDimitry Andric 1340*0fca6ea1SDimitry Andric } // namespace clang 1341