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