1 | //===------ SemaPPC.cpp ------ PowerPC target-specific routines -----------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file implements semantic analysis functions specific to PowerPC. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "clang/Sema/SemaPPC.h" |
14 | #include "clang/AST/ASTContext.h" |
15 | #include "clang/AST/Attr.h" |
16 | #include "clang/AST/CharUnits.h" |
17 | #include "clang/AST/Decl.h" |
18 | #include "clang/AST/Type.h" |
19 | #include "clang/Basic/DiagnosticSema.h" |
20 | #include "clang/Basic/SourceLocation.h" |
21 | #include "clang/Basic/TargetBuiltins.h" |
22 | #include "clang/Basic/TargetInfo.h" |
23 | #include "clang/Sema/Sema.h" |
24 | #include "llvm/ADT/APSInt.h" |
25 | |
26 | namespace clang { |
27 | |
28 | SemaPPC::SemaPPC(Sema &S) : SemaBase(S) {} |
29 | |
30 | void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { |
31 | const auto *ICE = dyn_cast<ImplicitCastExpr>(Val: Arg->IgnoreParens()); |
32 | if (!ICE) |
33 | return; |
34 | |
35 | const auto *DR = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); |
36 | if (!DR) |
37 | return; |
38 | |
39 | const auto *PD = dyn_cast<ParmVarDecl>(DR->getDecl()); |
40 | if (!PD || !PD->getType()->isRecordType()) |
41 | return; |
42 | |
43 | QualType ArgType = Arg->getType(); |
44 | for (const FieldDecl *FD : |
45 | ArgType->castAs<RecordType>()->getDecl()->fields()) { |
46 | if (const auto *AA = FD->getAttr<AlignedAttr>()) { |
47 | CharUnits Alignment = getASTContext().toCharUnitsFromBits( |
48 | BitSize: AA->getAlignment(getASTContext())); |
49 | if (Alignment.getQuantity() == 16) { |
50 | Diag(FD->getLocation(), diag::warn_not_xl_compatible) << FD; |
51 | Diag(Loc, diag::note_misaligned_member_used_here) << PD; |
52 | } |
53 | } |
54 | } |
55 | } |
56 | |
57 | static bool isPPC_64Builtin(unsigned BuiltinID) { |
58 | // These builtins only work on PPC 64bit targets. |
59 | switch (BuiltinID) { |
60 | case PPC::BI__builtin_divde: |
61 | case PPC::BI__builtin_divdeu: |
62 | case PPC::BI__builtin_bpermd: |
63 | case PPC::BI__builtin_pdepd: |
64 | case PPC::BI__builtin_pextd: |
65 | case PPC::BI__builtin_ppc_cdtbcd: |
66 | case PPC::BI__builtin_ppc_cbcdtd: |
67 | case PPC::BI__builtin_ppc_addg6s: |
68 | case PPC::BI__builtin_ppc_ldarx: |
69 | case PPC::BI__builtin_ppc_stdcx: |
70 | case PPC::BI__builtin_ppc_tdw: |
71 | case PPC::BI__builtin_ppc_trapd: |
72 | case PPC::BI__builtin_ppc_cmpeqb: |
73 | case PPC::BI__builtin_ppc_setb: |
74 | case PPC::BI__builtin_ppc_mulhd: |
75 | case PPC::BI__builtin_ppc_mulhdu: |
76 | case PPC::BI__builtin_ppc_maddhd: |
77 | case PPC::BI__builtin_ppc_maddhdu: |
78 | case PPC::BI__builtin_ppc_maddld: |
79 | case PPC::BI__builtin_ppc_load8r: |
80 | case PPC::BI__builtin_ppc_store8r: |
81 | case PPC::BI__builtin_ppc_insert_exp: |
82 | case PPC::BI__builtin_ppc_extract_sig: |
83 | case PPC::BI__builtin_ppc_addex: |
84 | case PPC::BI__builtin_darn: |
85 | case PPC::BI__builtin_darn_raw: |
86 | case PPC::BI__builtin_ppc_compare_and_swaplp: |
87 | case PPC::BI__builtin_ppc_fetch_and_addlp: |
88 | case PPC::BI__builtin_ppc_fetch_and_andlp: |
89 | case PPC::BI__builtin_ppc_fetch_and_orlp: |
90 | case PPC::BI__builtin_ppc_fetch_and_swaplp: |
91 | return true; |
92 | } |
93 | return false; |
94 | } |
95 | |
96 | bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, |
97 | unsigned BuiltinID, |
98 | CallExpr *TheCall) { |
99 | ASTContext &Context = getASTContext(); |
100 | bool IsTarget64Bit = TI.getTypeWidth(T: TI.getIntPtrType()) == 64; |
101 | |
102 | if (isPPC_64Builtin(BuiltinID) && !IsTarget64Bit) |
103 | return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) |
104 | << TheCall->getSourceRange(); |
105 | |
106 | switch (BuiltinID) { |
107 | default: |
108 | return false; |
109 | case PPC::BI__builtin_altivec_crypto_vshasigmaw: |
110 | case PPC::BI__builtin_altivec_crypto_vshasigmad: |
111 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1) || |
112 | SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 15); |
113 | case PPC::BI__builtin_altivec_dss: |
114 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 3); |
115 | case PPC::BI__builtin_tbegin: |
116 | case PPC::BI__builtin_tend: |
117 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 1); |
118 | case PPC::BI__builtin_tsr: |
119 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 7); |
120 | case PPC::BI__builtin_tabortwc: |
121 | case PPC::BI__builtin_tabortdc: |
122 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 31); |
123 | case PPC::BI__builtin_tabortwci: |
124 | case PPC::BI__builtin_tabortdci: |
125 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 31) || |
126 | SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 31); |
127 | // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', |
128 | // __builtin_(un)pack_longdouble are available only if long double uses IBM |
129 | // extended double representation. |
130 | case PPC::BI__builtin_unpack_longdouble: |
131 | if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1)) |
132 | return true; |
133 | [[fallthrough]]; |
134 | case PPC::BI__builtin_pack_longdouble: |
135 | if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) |
136 | return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) |
137 | << "ibmlongdouble" ; |
138 | return false; |
139 | case PPC::BI__builtin_altivec_dst: |
140 | case PPC::BI__builtin_altivec_dstt: |
141 | case PPC::BI__builtin_altivec_dstst: |
142 | case PPC::BI__builtin_altivec_dststt: |
143 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 3); |
144 | case PPC::BI__builtin_vsx_xxpermdi: |
145 | case PPC::BI__builtin_vsx_xxsldwi: |
146 | return BuiltinVSX(TheCall); |
147 | case PPC::BI__builtin_unpack_vector_int128: |
148 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1); |
149 | case PPC::BI__builtin_altivec_vgnb: |
150 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 2, High: 7); |
151 | case PPC::BI__builtin_vsx_xxeval: |
152 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: 0, High: 255); |
153 | case PPC::BI__builtin_altivec_vsldbi: |
154 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 7); |
155 | case PPC::BI__builtin_altivec_vsrdbi: |
156 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 7); |
157 | case PPC::BI__builtin_vsx_xxpermx: |
158 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 3, Low: 0, High: 7); |
159 | case PPC::BI__builtin_ppc_tw: |
160 | case PPC::BI__builtin_ppc_tdw: |
161 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 1, High: 31); |
162 | case PPC::BI__builtin_ppc_cmprb: |
163 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 1); |
164 | // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must |
165 | // be a constant that represents a contiguous bit field. |
166 | case PPC::BI__builtin_ppc_rlwnm: |
167 | return SemaRef.ValueIsRunOfOnes(TheCall, ArgNum: 2); |
168 | case PPC::BI__builtin_ppc_rlwimi: |
169 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 31) || |
170 | SemaRef.ValueIsRunOfOnes(TheCall, ArgNum: 3); |
171 | case PPC::BI__builtin_ppc_rldimi: |
172 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 63) || |
173 | SemaRef.ValueIsRunOfOnes(TheCall, ArgNum: 3); |
174 | case PPC::BI__builtin_ppc_addex: { |
175 | if (SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 2, Low: 0, High: 3)) |
176 | return true; |
177 | // Output warning for reserved values 1 to 3. |
178 | int ArgValue = |
179 | TheCall->getArg(Arg: 2)->getIntegerConstantExpr(Ctx: Context)->getSExtValue(); |
180 | if (ArgValue != 0) |
181 | Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour) |
182 | << ArgValue; |
183 | return false; |
184 | } |
185 | case PPC::BI__builtin_ppc_mtfsb0: |
186 | case PPC::BI__builtin_ppc_mtfsb1: |
187 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 31); |
188 | case PPC::BI__builtin_ppc_mtfsf: |
189 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 255); |
190 | case PPC::BI__builtin_ppc_mtfsfi: |
191 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 0, Low: 0, High: 7) || |
192 | SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 15); |
193 | case PPC::BI__builtin_ppc_alignx: |
194 | return SemaRef.BuiltinConstantArgPower2(TheCall, ArgNum: 0); |
195 | case PPC::BI__builtin_ppc_rdlam: |
196 | return SemaRef.ValueIsRunOfOnes(TheCall, ArgNum: 2); |
197 | case PPC::BI__builtin_vsx_ldrmb: |
198 | case PPC::BI__builtin_vsx_strmb: |
199 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 1, High: 16); |
200 | case PPC::BI__builtin_altivec_vcntmbb: |
201 | case PPC::BI__builtin_altivec_vcntmbh: |
202 | case PPC::BI__builtin_altivec_vcntmbw: |
203 | case PPC::BI__builtin_altivec_vcntmbd: |
204 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 1); |
205 | case PPC::BI__builtin_vsx_xxgenpcvbm: |
206 | case PPC::BI__builtin_vsx_xxgenpcvhm: |
207 | case PPC::BI__builtin_vsx_xxgenpcvwm: |
208 | case PPC::BI__builtin_vsx_xxgenpcvdm: |
209 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 3); |
210 | case PPC::BI__builtin_ppc_test_data_class: { |
211 | // Check if the first argument of the __builtin_ppc_test_data_class call is |
212 | // valid. The argument must be 'float' or 'double' or '__float128'. |
213 | QualType ArgType = TheCall->getArg(Arg: 0)->getType(); |
214 | if (ArgType != QualType(Context.FloatTy) && |
215 | ArgType != QualType(Context.DoubleTy) && |
216 | ArgType != QualType(Context.Float128Ty)) |
217 | return Diag(TheCall->getBeginLoc(), |
218 | diag::err_ppc_invalid_test_data_class_type); |
219 | return SemaRef.BuiltinConstantArgRange(TheCall, ArgNum: 1, Low: 0, High: 127); |
220 | } |
221 | case PPC::BI__builtin_ppc_maxfe: |
222 | case PPC::BI__builtin_ppc_minfe: |
223 | case PPC::BI__builtin_ppc_maxfl: |
224 | case PPC::BI__builtin_ppc_minfl: |
225 | case PPC::BI__builtin_ppc_maxfs: |
226 | case PPC::BI__builtin_ppc_minfs: { |
227 | if (Context.getTargetInfo().getTriple().isOSAIX() && |
228 | (BuiltinID == PPC::BI__builtin_ppc_maxfe || |
229 | BuiltinID == PPC::BI__builtin_ppc_minfe)) |
230 | return Diag(TheCall->getBeginLoc(), diag::err_target_unsupported_type) |
231 | << "builtin" << true << 128 << QualType(Context.LongDoubleTy) |
232 | << false << Context.getTargetInfo().getTriple().str(); |
233 | // Argument type should be exact. |
234 | QualType ArgType = QualType(Context.LongDoubleTy); |
235 | if (BuiltinID == PPC::BI__builtin_ppc_maxfl || |
236 | BuiltinID == PPC::BI__builtin_ppc_minfl) |
237 | ArgType = QualType(Context.DoubleTy); |
238 | else if (BuiltinID == PPC::BI__builtin_ppc_maxfs || |
239 | BuiltinID == PPC::BI__builtin_ppc_minfs) |
240 | ArgType = QualType(Context.FloatTy); |
241 | for (unsigned I = 0, E = TheCall->getNumArgs(); I < E; ++I) |
242 | if (TheCall->getArg(I)->getType() != ArgType) |
243 | return Diag(TheCall->getBeginLoc(), |
244 | diag::err_typecheck_convert_incompatible) |
245 | << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; |
246 | return false; |
247 | } |
248 | #define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ |
249 | case PPC::BI__builtin_##Name: \ |
250 | return BuiltinPPCMMACall(TheCall, BuiltinID, Types); |
251 | #include "clang/Basic/BuiltinsPPC.def" |
252 | } |
253 | llvm_unreachable("must return from switch" ); |
254 | } |
255 | |
256 | // Check if the given type is a non-pointer PPC MMA type. This function is used |
257 | // in Sema to prevent invalid uses of restricted PPC MMA types. |
258 | bool SemaPPC::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) { |
259 | ASTContext &Context = getASTContext(); |
260 | if (Type->isPointerType() || Type->isArrayType()) |
261 | return false; |
262 | |
263 | QualType CoreType = Type.getCanonicalType().getUnqualifiedType(); |
264 | #define PPC_VECTOR_TYPE(Name, Id, Size) || CoreType == Context.Id##Ty |
265 | if (false |
266 | #include "clang/Basic/PPCTypes.def" |
267 | ) { |
268 | Diag(TypeLoc, diag::err_ppc_invalid_use_mma_type); |
269 | return true; |
270 | } |
271 | return false; |
272 | } |
273 | |
274 | /// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, |
275 | /// advancing the pointer over the consumed characters. The decoded type is |
276 | /// returned. If the decoded type represents a constant integer with a |
277 | /// constraint on its value then Mask is set to that value. The type descriptors |
278 | /// used in Str are specific to PPC MMA builtins and are documented in the file |
279 | /// defining the PPC builtins. |
280 | static QualType DecodePPCMMATypeFromStr(ASTContext &Context, const char *&Str, |
281 | unsigned &Mask) { |
282 | bool RequireICE = false; |
283 | ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; |
284 | switch (*Str++) { |
285 | case 'V': |
286 | return Context.getVectorType(VectorType: Context.UnsignedCharTy, NumElts: 16, |
287 | VecKind: VectorKind::AltiVecVector); |
288 | case 'i': { |
289 | char *End; |
290 | unsigned size = strtoul(nptr: Str, endptr: &End, base: 10); |
291 | assert(End != Str && "Missing constant parameter constraint" ); |
292 | Str = End; |
293 | Mask = size; |
294 | return Context.IntTy; |
295 | } |
296 | case 'W': { |
297 | char *End; |
298 | unsigned size = strtoul(nptr: Str, endptr: &End, base: 10); |
299 | assert(End != Str && "Missing PowerPC MMA type size" ); |
300 | Str = End; |
301 | QualType Type; |
302 | switch (size) { |
303 | #define PPC_VECTOR_TYPE(typeName, Id, size) \ |
304 | case size: \ |
305 | Type = Context.Id##Ty; \ |
306 | break; |
307 | #include "clang/Basic/PPCTypes.def" |
308 | default: |
309 | llvm_unreachable("Invalid PowerPC MMA vector type" ); |
310 | } |
311 | bool CheckVectorArgs = false; |
312 | while (!CheckVectorArgs) { |
313 | switch (*Str++) { |
314 | case '*': |
315 | Type = Context.getPointerType(T: Type); |
316 | break; |
317 | case 'C': |
318 | Type = Type.withConst(); |
319 | break; |
320 | default: |
321 | CheckVectorArgs = true; |
322 | --Str; |
323 | break; |
324 | } |
325 | } |
326 | return Type; |
327 | } |
328 | default: |
329 | return Context.DecodeTypeStr(Str&: --Str, Context, Error, RequireICE, AllowTypeModifiers: true); |
330 | } |
331 | } |
332 | |
333 | bool SemaPPC::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, |
334 | const char *TypeStr) { |
335 | |
336 | assert((TypeStr[0] != '\0') && |
337 | "Invalid types in PPC MMA builtin declaration" ); |
338 | |
339 | ASTContext &Context = getASTContext(); |
340 | unsigned Mask = 0; |
341 | unsigned ArgNum = 0; |
342 | |
343 | // The first type in TypeStr is the type of the value returned by the |
344 | // builtin. So we first read that type and change the type of TheCall. |
345 | QualType type = DecodePPCMMATypeFromStr(Context, Str&: TypeStr, Mask); |
346 | TheCall->setType(type); |
347 | |
348 | while (*TypeStr != '\0') { |
349 | Mask = 0; |
350 | QualType ExpectedType = DecodePPCMMATypeFromStr(Context, Str&: TypeStr, Mask); |
351 | if (ArgNum >= TheCall->getNumArgs()) { |
352 | ArgNum++; |
353 | break; |
354 | } |
355 | |
356 | Expr *Arg = TheCall->getArg(Arg: ArgNum); |
357 | QualType PassedType = Arg->getType(); |
358 | QualType StrippedRVType = PassedType.getCanonicalType(); |
359 | |
360 | // Strip Restrict/Volatile qualifiers. |
361 | if (StrippedRVType.isRestrictQualified() || |
362 | StrippedRVType.isVolatileQualified()) |
363 | StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType(); |
364 | |
365 | // The only case where the argument type and expected type are allowed to |
366 | // mismatch is if the argument type is a non-void pointer (or array) and |
367 | // expected type is a void pointer. |
368 | if (StrippedRVType != ExpectedType) |
369 | if (!(ExpectedType->isVoidPointerType() && |
370 | (StrippedRVType->isPointerType() || StrippedRVType->isArrayType()))) |
371 | return Diag(Arg->getBeginLoc(), |
372 | diag::err_typecheck_convert_incompatible) |
373 | << PassedType << ExpectedType << 1 << 0 << 0; |
374 | |
375 | // If the value of the Mask is not 0, we have a constraint in the size of |
376 | // the integer argument so here we ensure the argument is a constant that |
377 | // is in the valid range. |
378 | if (Mask != 0 && |
379 | SemaRef.BuiltinConstantArgRange(TheCall, ArgNum, Low: 0, High: Mask, RangeIsError: true)) |
380 | return true; |
381 | |
382 | ArgNum++; |
383 | } |
384 | |
385 | // In case we exited early from the previous loop, there are other types to |
386 | // read from TypeStr. So we need to read them all to ensure we have the right |
387 | // number of arguments in TheCall and if it is not the case, to display a |
388 | // better error message. |
389 | while (*TypeStr != '\0') { |
390 | (void)DecodePPCMMATypeFromStr(Context, Str&: TypeStr, Mask); |
391 | ArgNum++; |
392 | } |
393 | if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: ArgNum)) |
394 | return true; |
395 | |
396 | return false; |
397 | } |
398 | |
399 | bool SemaPPC::BuiltinVSX(CallExpr *TheCall) { |
400 | unsigned ExpectedNumArgs = 3; |
401 | if (SemaRef.checkArgCount(Call: TheCall, DesiredArgCount: ExpectedNumArgs)) |
402 | return true; |
403 | |
404 | // Check the third argument is a compile time constant |
405 | if (!TheCall->getArg(2)->isIntegerConstantExpr(getASTContext())) |
406 | return Diag(TheCall->getBeginLoc(), |
407 | diag::err_vsx_builtin_nonconstant_argument) |
408 | << 3 /* argument index */ << TheCall->getDirectCallee() |
409 | << SourceRange(TheCall->getArg(2)->getBeginLoc(), |
410 | TheCall->getArg(2)->getEndLoc()); |
411 | |
412 | QualType Arg1Ty = TheCall->getArg(Arg: 0)->getType(); |
413 | QualType Arg2Ty = TheCall->getArg(Arg: 1)->getType(); |
414 | |
415 | // Check the type of argument 1 and argument 2 are vectors. |
416 | SourceLocation BuiltinLoc = TheCall->getBeginLoc(); |
417 | if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || |
418 | (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { |
419 | return Diag(BuiltinLoc, diag::err_vec_builtin_non_vector) |
420 | << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false |
421 | << SourceRange(TheCall->getArg(0)->getBeginLoc(), |
422 | TheCall->getArg(1)->getEndLoc()); |
423 | } |
424 | |
425 | // Check the first two arguments are the same type. |
426 | if (!getASTContext().hasSameUnqualifiedType(T1: Arg1Ty, T2: Arg2Ty)) { |
427 | return Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector) |
428 | << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ false |
429 | << SourceRange(TheCall->getArg(0)->getBeginLoc(), |
430 | TheCall->getArg(1)->getEndLoc()); |
431 | } |
432 | |
433 | // When default clang type checking is turned off and the customized type |
434 | // checking is used, the returning type of the function must be explicitly |
435 | // set. Otherwise it is _Bool by default. |
436 | TheCall->setType(Arg1Ty); |
437 | |
438 | return false; |
439 | } |
440 | |
441 | } // namespace clang |
442 | |