https://github.com/jhuber6 updated https://github.com/llvm/llvm-project/pull/160185
>From be8d1e84e11274f64f931c6c52278e9d3d2daa82 Mon Sep 17 00:00:00 2001 From: Joseph Huber <[email protected]> Date: Mon, 22 Sep 2025 14:26:40 -0500 Subject: [PATCH 1/4] [Clang][FIX] Fix type qualifiers on vector builtins Summary: These were not stripping qualifiers when using them to infer the types, leading to errors when mixiing const and non-const. --- clang/lib/Sema/SemaChecking.cpp | 61 +++++++++++++++++++++++++------- clang/test/Sema/builtin-masked.c | 26 ++++++++++++++ 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 27e3456bc6681..88725806a9920 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2296,12 +2296,21 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); - QualType RetTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); + QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); + if (PtrTy->getPointeeType().isVolatileQualified()) + return ExprError( + S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) + << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType() + << 5 /* different qualifiers */ << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType()); if (TheCall->getNumArgs() == 3) { Expr *PassThruArg = TheCall->getArg(2); QualType PassThruTy = PassThruArg->getType(); - if (!S.Context.hasSameType(PassThruTy, RetTy)) + if (!S.Context.hasSameType(PassThruTy, RetTy.getUnqualifiedType())) return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << /* third argument */ 3 << RetTy; } @@ -2329,12 +2338,22 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { S.Diag(ValArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << 2 << "vector"); + if (PtrTy->getPointeeType().hasQualifiers()) + return ExprError( + S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) + << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType() + << 5 /* different qualifiers */ << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType()); + QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); - QualType RetTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); + QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); - if (!S.Context.hasSameType(ValTy, RetTy)) + if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), RetTy)) return ExprError(S.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ 2 @@ -2366,6 +2385,15 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { QualType PtrTy = PtrArg->getType(); QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); + if (PtrTy->getPointeeType().isVolatileQualified()) + return ExprError( + S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) + << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType() + << 5 /* different qualifiers */ << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType()); if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) @@ -2373,12 +2401,12 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << IdxTy); - QualType RetTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); + QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); if (TheCall->getNumArgs() == 4) { Expr *PassThruArg = TheCall->getArg(3); QualType PassThruTy = PassThruArg->getType(); - if (!S.Context.hasSameType(PassThruTy, RetTy)) + if (!S.Context.hasSameType(PassThruTy.getUnqualifiedType(), RetTy)) return S.Diag(PassThruArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << /* fourth argument */ 4 << RetTy; @@ -2414,6 +2442,15 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { const VectorType *MaskVecTy = MaskTy->castAs<VectorType>(); const VectorType *ValVecTy = ValTy->castAs<VectorType>(); + if (PtrTy->getPointeeType().hasQualifiers()) + return ExprError( + S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) + << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType() + << 5 /* different qualifiers */ << 0 /* qualifier difference */ + << 3 /* parameter mismatch */ + << 2 << PtrTy->getPointeeType() + << PtrTy->getPointeeType().getUnqualifiedType()); if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) @@ -2427,9 +2464,9 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << ValTy); - QualType ArgTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); - if (!S.Context.hasSameType(ValTy, ArgTy)) + QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); + if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy)) return ExprError(S.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2 diff --git a/clang/test/Sema/builtin-masked.c b/clang/test/Sema/builtin-masked.c index e24648da57fb1..c010bfab2ec60 100644 --- a/clang/test/Sema/builtin-masked.c +++ b/clang/test/Sema/builtin-masked.c @@ -54,3 +54,29 @@ void test_masked_scatter(int *p, v8i idx, v8b mask, v2b mask2, v8i val) { __builtin_masked_scatter(mask, idx, val, idx); // expected-error {{3rd argument must be a scalar pointer}} __builtin_masked_scatter(mask, idx, val, &idx); // expected-error {{3rd argument must be a scalar pointer}} } + +void a(v8b mask, v8i val, const int *ptr) { + __builtin_masked_load(mask, ptr, val); + (void)__builtin_masked_load(mask, (volatile int *)ptr, val); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} +} + +void b(v8b mask, v8i idx, const int *ptr) { + (void)__builtin_masked_gather(mask, idx, ptr); + (void)__builtin_masked_gather(mask, idx, (volatile int *)ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} +} + +void c(v8b mask, const v8i val, int *ptr) { + __builtin_masked_store(mask, val, ptr); +} + +void readonly(v8b mask, v8i val, const int *ptr, const int *s) { + __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} + __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} + __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} +} + +void vol(v8b mask, v8i val, volatile int *ptr, volatile int *s) { + __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} + __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} + __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} +} >From cd0ff843ac23e1c1a6af51f18189d06b7831f957 Mon Sep 17 00:00:00 2001 From: Joseph Huber <[email protected]> Date: Thu, 25 Sep 2025 14:22:58 -0500 Subject: [PATCH 2/4] Update qualifiers --- clang/lib/CodeGen/CGBuiltin.cpp | 7 +- clang/lib/Sema/SemaChecking.cpp | 100 +++++++++++++--------------- clang/test/CodeGen/builtin-masked.c | 49 ++++++++++++++ clang/test/Sema/builtin-masked.c | 37 +++++++--- 4 files changed, 128 insertions(+), 65 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1cff1e0de71b7..9ee810c9d5775 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4289,7 +4289,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Result; if (BuiltinID == Builtin::BI__builtin_masked_load) { Function *F = - CGM.getIntrinsic(Intrinsic::masked_load, {RetTy, UnqualPtrTy}); + CGM.getIntrinsic(Intrinsic::masked_load, {RetTy, Ptr->getType()}); Result = Builder.CreateCall(F, {Ptr, AlignVal, Mask, PassThru}, "masked_load"); } else { @@ -4334,7 +4334,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, QualType ValTy = E->getArg(1)->getType(); llvm::Type *ValLLTy = CGM.getTypes().ConvertType(ValTy); - llvm::Type *PtrTy = Ptr->getType(); CharUnits Align = CGM.getNaturalTypeAlignment( E->getArg(1)->getType()->getAs<VectorType>()->getElementType(), @@ -4343,8 +4342,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::ConstantInt::get(Int32Ty, Align.getQuantity()); if (BuiltinID == Builtin::BI__builtin_masked_store) { - llvm::Function *F = - CGM.getIntrinsic(llvm::Intrinsic::masked_store, {ValLLTy, PtrTy}); + llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::masked_store, + {ValLLTy, Ptr->getType()}); Builder.CreateCall(F, {Val, Ptr, AlignVal, Mask}); } else { llvm::Function *F = diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 88725806a9920..0272ad31231cc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2268,7 +2268,8 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { } static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, - unsigned Pos) { + unsigned Pos, bool AllowConst, + bool AllowAS) { QualType MaskTy = MaskArg->getType(); if (!MaskTy->isExtVectorBoolType()) return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type) @@ -2279,6 +2280,20 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, if (!PtrTy->isPointerType() || PtrTy->getPointeeType()->isVectorType()) return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << Pos << "scalar pointer"; + + QualType PointeeTy = PtrTy->getPointeeType(); + if (PointeeTy.isVolatileQualified() || PointeeTy->isAtomicType() || + (!AllowConst && PointeeTy.isConstQualified()) || + (!AllowAS && PointeeTy.hasAddressSpace())) { + QualType Target = S.Context.getPointerType(PointeeTy.getUnqualifiedType()); + if (const auto *AT = dyn_cast<AtomicType>(PointeeTy)) + Target = S.Context.getPointerType(AT->getValueType()); + return S.Diag(PtrArg->getExprLoc(), + diag::err_typecheck_convert_incompatible) + << PtrTy << Target << /*different qualifiers=*/5 + << /*qualifier difference=*/0 << /*parameter mismatch=*/3 << 2 + << PtrTy << Target; + } return false; } @@ -2288,7 +2303,9 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { Expr *MaskArg = TheCall->getArg(0); Expr *PtrArg = TheCall->getArg(1); - if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2)) + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2, /*AllowConst=*/true, + TheCall->getBuiltinCallee() == + Builtin::BI__builtin_masked_load)) return ExprError(); QualType MaskTy = MaskArg->getType(); @@ -2298,19 +2315,15 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), MaskVecTy->getNumElements()); - if (PtrTy->getPointeeType().isVolatileQualified()) - return ExprError( - S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) - << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType() - << 5 /* different qualifiers */ << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 2 << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType()); + Qualifiers Qs = PointeeTy.getQualifiers(); + Qs.removeConst(); + if (Qs.hasAddressSpace()) + RetTy = S.Context.getQualifiedType(RetTy, Qs); + if (TheCall->getNumArgs() == 3) { Expr *PassThruArg = TheCall->getArg(2); QualType PassThruTy = PassThruArg->getType(); - if (!S.Context.hasSameType(PassThruTy, RetTy.getUnqualifiedType())) + if (!S.Context.hasSameType(PassThruTy, RetTy)) return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << /* third argument */ 3 << RetTy; } @@ -2327,7 +2340,9 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { Expr *ValArg = TheCall->getArg(1); Expr *PtrArg = TheCall->getArg(2); - if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3)) + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false, + TheCall->getBuiltinCallee() == + Builtin::BI__builtin_masked_store)) return ExprError(); QualType MaskTy = MaskArg->getType(); @@ -2338,22 +2353,16 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { S.Diag(ValArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << 2 << "vector"); - if (PtrTy->getPointeeType().hasQualifiers()) - return ExprError( - S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) - << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType() - << 5 /* different qualifiers */ << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 2 << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType()); - QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); - QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), - MaskVecTy->getNumElements()); - - if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), RetTy)) + QualType MemoryTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); + Qualifiers Qs = PointeeTy.getQualifiers(); + if (Qs.hasAddressSpace()) + MemoryTy = S.Context.getQualifiedType(MemoryTy, Qs); + + if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), + MemoryTy.getUnqualifiedType())) return ExprError(S.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ 2 @@ -2371,7 +2380,8 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { Expr *MaskArg = TheCall->getArg(0); Expr *IdxArg = TheCall->getArg(1); Expr *PtrArg = TheCall->getArg(2); - if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3)) + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/true, + /*AllowAS=*/false)) return ExprError(); QualType IdxTy = IdxArg->getType(); @@ -2385,15 +2395,6 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { QualType PtrTy = PtrArg->getType(); QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); - if (PtrTy->getPointeeType().isVolatileQualified()) - return ExprError( - S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) - << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType() - << 5 /* different qualifiers */ << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 2 << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType()); if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) @@ -2401,12 +2402,13 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << IdxTy); - QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), - MaskVecTy->getNumElements()); + PointeeTy.removeLocalConst(); + QualType RetTy = + S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); if (TheCall->getNumArgs() == 4) { Expr *PassThruArg = TheCall->getArg(3); QualType PassThruTy = PassThruArg->getType(); - if (!S.Context.hasSameType(PassThruTy.getUnqualifiedType(), RetTy)) + if (!S.Context.hasSameType(PassThruTy, RetTy)) return S.Diag(PassThruArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) << /* fourth argument */ 4 << RetTy; @@ -2425,7 +2427,8 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { Expr *ValArg = TheCall->getArg(2); Expr *PtrArg = TheCall->getArg(3); - if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3)) + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false, + /*AllowAS=*/false)) return ExprError(); QualType IdxTy = IdxArg->getType(); @@ -2442,15 +2445,6 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { const VectorType *MaskVecTy = MaskTy->castAs<VectorType>(); const VectorType *ValVecTy = ValTy->castAs<VectorType>(); - if (PtrTy->getPointeeType().hasQualifiers()) - return ExprError( - S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) - << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType() - << 5 /* different qualifiers */ << 0 /* qualifier difference */ - << 3 /* parameter mismatch */ - << 2 << PtrTy->getPointeeType() - << PtrTy->getPointeeType().getUnqualifiedType()); if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) @@ -2464,9 +2458,9 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << ValTy); - QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), - MaskVecTy->getNumElements()); - if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy)) + QualType ArgTy = + S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); + if (!S.Context.hasSameType(ValTy, ArgTy)) return ExprError(S.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2 diff --git a/clang/test/CodeGen/builtin-masked.c b/clang/test/CodeGen/builtin-masked.c index 2ac05fac219fe..c8fc7c03b4f1d 100644 --- a/clang/test/CodeGen/builtin-masked.c +++ b/clang/test/CodeGen/builtin-masked.c @@ -187,3 +187,52 @@ v8i test_gather(v8b mask, v8i idx, int *ptr) { void test_scatter(v8b mask, v8i val, v8i idx, int *ptr) { __builtin_masked_scatter(mask, val, idx, ptr); } + +// CHECK-LABEL: define dso_local <8 x i32> @test_load_as( +// CHECK-SAME: i8 noundef [[MASK_COERCE:%.*]], ptr addrspace(42) noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[MASK:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[MASK_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr addrspace(42), align 8 +// CHECK-NEXT: store i8 [[MASK_COERCE]], ptr [[MASK]], align 1 +// CHECK-NEXT: [[LOAD_BITS:%.*]] = load i8, ptr [[MASK]], align 1 +// CHECK-NEXT: [[MASK1:%.*]] = bitcast i8 [[LOAD_BITS]] to <8 x i1> +// CHECK-NEXT: [[TMP0:%.*]] = bitcast <8 x i1> [[MASK1]] to i8 +// CHECK-NEXT: store i8 [[TMP0]], ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: store ptr addrspace(42) [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[LOAD_BITS2:%.*]] = load i8, ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast i8 [[LOAD_BITS2]] to <8 x i1> +// CHECK-NEXT: [[TMP2:%.*]] = load ptr addrspace(42), ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[MASKED_LOAD:%.*]] = call <8 x i32> @llvm.masked.load.v8i32.p42(ptr addrspace(42) [[TMP2]], i32 4, <8 x i1> [[TMP1]], <8 x i32> poison) +// CHECK-NEXT: ret <8 x i32> [[MASKED_LOAD]] +// +v8i __attribute__((address_space(42))) test_load_as(v8b mask, int + __attribute__((address_space(42))) * ptr) { + return __builtin_masked_load(mask, ptr); +} + +// CHECK-LABEL: define dso_local void @test_store_as( +// CHECK-SAME: i8 noundef [[M_COERCE:%.*]], ptr noundef byval(<8 x i32>) align 32 [[TMP0:%.*]], ptr addrspace(42) noundef [[P:%.*]]) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[M:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[M_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[V_ADDR:%.*]] = alloca <8 x i32>, align 32 +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr addrspace(42), align 8 +// CHECK-NEXT: store i8 [[M_COERCE]], ptr [[M]], align 1 +// CHECK-NEXT: [[LOAD_BITS:%.*]] = load i8, ptr [[M]], align 1 +// CHECK-NEXT: [[M1:%.*]] = bitcast i8 [[LOAD_BITS]] to <8 x i1> +// CHECK-NEXT: [[V:%.*]] = load <8 x i32>, ptr [[TMP0]], align 32 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i1> [[M1]] to i8 +// CHECK-NEXT: store i8 [[TMP1]], ptr [[M_ADDR]], align 1 +// CHECK-NEXT: store <8 x i32> [[V]], ptr [[V_ADDR]], align 32 +// CHECK-NEXT: store ptr addrspace(42) [[P]], ptr [[P_ADDR]], align 8 +// CHECK-NEXT: [[LOAD_BITS2:%.*]] = load i8, ptr [[M_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8 [[LOAD_BITS2]] to <8 x i1> +// CHECK-NEXT: [[TMP3:%.*]] = load <8 x i32>, ptr [[V_ADDR]], align 32 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr addrspace(42), ptr [[P_ADDR]], align 8 +// CHECK-NEXT: call void @llvm.masked.store.v8i32.p42(<8 x i32> [[TMP3]], ptr addrspace(42) [[TMP4]], i32 4, <8 x i1> [[TMP2]]) +// CHECK-NEXT: ret void +// +void test_store_as(v8b m, v8i v, int __attribute__((address_space(42))) *p) { + __builtin_masked_store(m, v, p); +} diff --git a/clang/test/Sema/builtin-masked.c b/clang/test/Sema/builtin-masked.c index c010bfab2ec60..f809a77bca5de 100644 --- a/clang/test/Sema/builtin-masked.c +++ b/clang/test/Sema/builtin-masked.c @@ -57,12 +57,12 @@ void test_masked_scatter(int *p, v8i idx, v8b mask, v2b mask2, v8i val) { void a(v8b mask, v8i val, const int *ptr) { __builtin_masked_load(mask, ptr, val); - (void)__builtin_masked_load(mask, (volatile int *)ptr, val); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} + (void)__builtin_masked_load(mask, (volatile int *)ptr, val); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} } void b(v8b mask, v8i idx, const int *ptr) { (void)__builtin_masked_gather(mask, idx, ptr); - (void)__builtin_masked_gather(mask, idx, (volatile int *)ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} + (void)__builtin_masked_gather(mask, idx, (volatile int *)ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} } void c(v8b mask, const v8i val, int *ptr) { @@ -70,13 +70,34 @@ void c(v8b mask, const v8i val, int *ptr) { } void readonly(v8b mask, v8i val, const int *ptr, const int *s) { - __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} - __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} - __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'const int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('const int' vs 'int')}} + __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} + __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} + __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} } void vol(v8b mask, v8i val, volatile int *ptr, volatile int *s) { - __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} - __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} - __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'volatile int' to parameter of incompatible type 'int': type mismatch at 2nd parameter ('volatile int' vs 'int')}} + __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} +} + +v8i [[clang::address_space(999)]] load(v8b mask, int [[clang::address_space(999)]] * ptr) { +} + +void as(v8b mask, int [[clang::address_space(999)]] * ptr, v8i v) { + (void)__builtin_masked_load(mask, ptr); + (void)__builtin_masked_store(mask, v, ptr); + (void)__builtin_masked_expand_load(mask, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} + (void)__builtin_masked_compress_store(mask, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} + (void)__builtin_masked_gather(mask, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} + (void)__builtin_masked_scatter(mask, v, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} +} + +void atom(v8b mask, _Atomic int * ptr, v8i v) { + (void)__builtin_masked_load(mask, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} + (void)__builtin_masked_store(mask, v, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} + (void)__builtin_masked_expand_load(mask, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} + (void)__builtin_masked_compress_store(mask, v, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} + (void)__builtin_masked_gather(mask, v, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} + (void)__builtin_masked_scatter(mask, v, v, ptr); // expected-error {{'_Atomic(int) *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('_Atomic(int) *' vs 'int *')}} } >From d9b5d5ea818ef7663d130022c5e95ad414507205 Mon Sep 17 00:00:00 2001 From: Joseph Huber <[email protected]> Date: Thu, 25 Sep 2025 15:44:57 -0500 Subject: [PATCH 3/4] Update --- clang/lib/Sema/SemaChecking.cpp | 58 +++++++++++++++++++-------- clang/test/CodeGen/builtin-masked.c | 61 ++++++++++++++++++++++++++++- clang/test/Sema/builtin-masked.c | 36 ++++++++--------- 3 files changed, 118 insertions(+), 37 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 0272ad31231cc..03c3378ca06ef 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2297,12 +2297,30 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, return false; } +static bool CheckMaskedBuiltinPtr(Sema &S, CallExpr *TheCall, unsigned ArgNum) { + ExprResult ConvertedPtr = + S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(ArgNum)); + if (ConvertedPtr.isInvalid()) + return true; + TheCall->setArg(ArgNum, ConvertedPtr.get()); + + if (ConvertedPtr.get()->isTypeDependent()) + TheCall->setType(S.Context.DependentTy); + return false; +} + static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { if (S.checkArgCountRange(TheCall, 2, 3)) return ExprError(); + if (CheckMaskedBuiltinPtr(S, TheCall, /*PtrArg=*/1)) + return ExprError(); + Expr *MaskArg = TheCall->getArg(0); Expr *PtrArg = TheCall->getArg(1); + if (PtrArg->isTypeDependent()) + return TheCall; + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2, /*AllowConst=*/true, TheCall->getBuiltinCallee() == Builtin::BI__builtin_masked_load)) @@ -2315,11 +2333,6 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), MaskVecTy->getNumElements()); - Qualifiers Qs = PointeeTy.getQualifiers(); - Qs.removeConst(); - if (Qs.hasAddressSpace()) - RetTy = S.Context.getQualifiedType(RetTy, Qs); - if (TheCall->getNumArgs() == 3) { Expr *PassThruArg = TheCall->getArg(2); QualType PassThruTy = PassThruArg->getType(); @@ -2336,9 +2349,14 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { if (S.checkArgCount(TheCall, 3)) return ExprError(); + if (CheckMaskedBuiltinPtr(S, TheCall, /*PtrArg=*/2)) + return ExprError(); + Expr *MaskArg = TheCall->getArg(0); Expr *ValArg = TheCall->getArg(1); Expr *PtrArg = TheCall->getArg(2); + if (PtrArg->isTypeDependent()) + return TheCall; if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false, TheCall->getBuiltinCallee() == @@ -2357,10 +2375,6 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); QualType MemoryTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), MaskVecTy->getNumElements()); - Qualifiers Qs = PointeeTy.getQualifiers(); - if (Qs.hasAddressSpace()) - MemoryTy = S.Context.getQualifiedType(MemoryTy, Qs); - if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), MemoryTy.getUnqualifiedType())) return ExprError(S.Diag(TheCall->getBeginLoc(), @@ -2377,11 +2391,17 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { if (S.checkArgCountRange(TheCall, 3, 4)) return ExprError(); + if (CheckMaskedBuiltinPtr(S, TheCall, /*PtrArg=*/2)) + return ExprError(); + Expr *MaskArg = TheCall->getArg(0); Expr *IdxArg = TheCall->getArg(1); Expr *PtrArg = TheCall->getArg(2); + if (PtrArg->isTypeDependent()) + return TheCall; + if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/true, - /*AllowAS=*/false)) + /*AllowAS=*/true)) return ExprError(); QualType IdxTy = IdxArg->getType(); @@ -2402,9 +2422,8 @@ static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << IdxTy); - PointeeTy.removeLocalConst(); - QualType RetTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); + QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); if (TheCall->getNumArgs() == 4) { Expr *PassThruArg = TheCall->getArg(3); QualType PassThruTy = PassThruArg->getType(); @@ -2422,13 +2441,18 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { if (S.checkArgCount(TheCall, 4)) return ExprError(); + if (CheckMaskedBuiltinPtr(S, TheCall, /*PtrArg=*/3)) + return ExprError(); + Expr *MaskArg = TheCall->getArg(0); Expr *IdxArg = TheCall->getArg(1); Expr *ValArg = TheCall->getArg(2); Expr *PtrArg = TheCall->getArg(3); + if (PtrArg->isTypeDependent()) + return TheCall; if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false, - /*AllowAS=*/false)) + /*AllowAS=*/true)) return ExprError(); QualType IdxTy = IdxArg->getType(); @@ -2458,9 +2482,9 @@ static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) { TheCall->getBuiltinCallee()) << MaskTy << ValTy); - QualType ArgTy = - S.Context.getExtVectorType(PointeeTy, MaskVecTy->getNumElements()); - if (!S.Context.hasSameType(ValTy, ArgTy)) + QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(), + MaskVecTy->getNumElements()); + if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy)) return ExprError(S.Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector) << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2 diff --git a/clang/test/CodeGen/builtin-masked.c b/clang/test/CodeGen/builtin-masked.c index c8fc7c03b4f1d..e2b5e099a4ba9 100644 --- a/clang/test/CodeGen/builtin-masked.c +++ b/clang/test/CodeGen/builtin-masked.c @@ -206,8 +206,7 @@ void test_scatter(v8b mask, v8i val, v8i idx, int *ptr) { // CHECK-NEXT: [[MASKED_LOAD:%.*]] = call <8 x i32> @llvm.masked.load.v8i32.p42(ptr addrspace(42) [[TMP2]], i32 4, <8 x i1> [[TMP1]], <8 x i32> poison) // CHECK-NEXT: ret <8 x i32> [[MASKED_LOAD]] // -v8i __attribute__((address_space(42))) test_load_as(v8b mask, int - __attribute__((address_space(42))) * ptr) { +v8i test_load_as(v8b mask, int __attribute__((address_space(42))) * ptr) { return __builtin_masked_load(mask, ptr); } @@ -236,3 +235,61 @@ v8i __attribute__((address_space(42))) test_load_as(v8b mask, int void test_store_as(v8b m, v8i v, int __attribute__((address_space(42))) *p) { __builtin_masked_store(m, v, p); } + +// CHECK-LABEL: define dso_local <8 x i32> @test_gather_as( +// CHECK-SAME: i8 noundef [[MASK_COERCE:%.*]], ptr noundef byval(<8 x i32>) align 32 [[TMP0:%.*]], ptr addrspace(42) noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[MASK:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[MASK_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca <8 x i32>, align 32 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr addrspace(42), align 8 +// CHECK-NEXT: store i8 [[MASK_COERCE]], ptr [[MASK]], align 1 +// CHECK-NEXT: [[LOAD_BITS:%.*]] = load i8, ptr [[MASK]], align 1 +// CHECK-NEXT: [[MASK1:%.*]] = bitcast i8 [[LOAD_BITS]] to <8 x i1> +// CHECK-NEXT: [[IDX:%.*]] = load <8 x i32>, ptr [[TMP0]], align 32 +// CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x i1> [[MASK1]] to i8 +// CHECK-NEXT: store i8 [[TMP1]], ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: store <8 x i32> [[IDX]], ptr [[IDX_ADDR]], align 32 +// CHECK-NEXT: store ptr addrspace(42) [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[LOAD_BITS2:%.*]] = load i8, ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = bitcast i8 [[LOAD_BITS2]] to <8 x i1> +// CHECK-NEXT: [[TMP3:%.*]] = load <8 x i32>, ptr [[IDX_ADDR]], align 32 +// CHECK-NEXT: [[TMP4:%.*]] = load ptr addrspace(42), ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP5:%.*]] = getelementptr i32, ptr addrspace(42) [[TMP4]], <8 x i32> [[TMP3]] +// CHECK-NEXT: [[MASKED_GATHER:%.*]] = call <8 x i32> @llvm.masked.gather.v8i32.v8p42(<8 x ptr addrspace(42)> [[TMP5]], i32 4, <8 x i1> [[TMP2]], <8 x i32> poison) +// CHECK-NEXT: ret <8 x i32> [[MASKED_GATHER]] +// +v8i test_gather_as(v8b mask, v8i idx, int __attribute__((address_space(42))) *ptr) { + return __builtin_masked_gather(mask, idx, ptr); +} + +// CHECK-LABEL: define dso_local void @test_scatter_as( +// CHECK-SAME: i8 noundef [[MASK_COERCE:%.*]], ptr noundef byval(<8 x i32>) align 32 [[TMP0:%.*]], ptr noundef byval(<8 x i32>) align 32 [[TMP1:%.*]], ptr addrspace(42) noundef [[PTR:%.*]]) #[[ATTR3]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[MASK:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[MASK_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[VAL_ADDR:%.*]] = alloca <8 x i32>, align 32 +// CHECK-NEXT: [[IDX_ADDR:%.*]] = alloca <8 x i32>, align 32 +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr addrspace(42), align 8 +// CHECK-NEXT: store i8 [[MASK_COERCE]], ptr [[MASK]], align 1 +// CHECK-NEXT: [[LOAD_BITS:%.*]] = load i8, ptr [[MASK]], align 1 +// CHECK-NEXT: [[MASK1:%.*]] = bitcast i8 [[LOAD_BITS]] to <8 x i1> +// CHECK-NEXT: [[VAL:%.*]] = load <8 x i32>, ptr [[TMP0]], align 32 +// CHECK-NEXT: [[IDX:%.*]] = load <8 x i32>, ptr [[TMP1]], align 32 +// CHECK-NEXT: [[TMP2:%.*]] = bitcast <8 x i1> [[MASK1]] to i8 +// CHECK-NEXT: store i8 [[TMP2]], ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: store <8 x i32> [[VAL]], ptr [[VAL_ADDR]], align 32 +// CHECK-NEXT: store <8 x i32> [[IDX]], ptr [[IDX_ADDR]], align 32 +// CHECK-NEXT: store ptr addrspace(42) [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[LOAD_BITS2:%.*]] = load i8, ptr [[MASK_ADDR]], align 1 +// CHECK-NEXT: [[TMP3:%.*]] = bitcast i8 [[LOAD_BITS2]] to <8 x i1> +// CHECK-NEXT: [[TMP4:%.*]] = load <8 x i32>, ptr [[VAL_ADDR]], align 32 +// CHECK-NEXT: [[TMP5:%.*]] = load <8 x i32>, ptr [[IDX_ADDR]], align 32 +// CHECK-NEXT: [[TMP6:%.*]] = load ptr addrspace(42), ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr i32, ptr addrspace(42) [[TMP6]], <8 x i32> [[TMP4]] +// CHECK-NEXT: call void @llvm.masked.scatter.v8i32.v8p42(<8 x i32> [[TMP5]], <8 x ptr addrspace(42)> [[TMP7]], i32 4, <8 x i1> [[TMP3]]) +// CHECK-NEXT: ret void +// +void test_scatter_as(v8b mask, v8i val, v8i idx, int __attribute__((address_space(42))) *ptr) { + __builtin_masked_scatter(mask, val, idx, ptr); +} diff --git a/clang/test/Sema/builtin-masked.c b/clang/test/Sema/builtin-masked.c index f809a77bca5de..cacaefc911c9a 100644 --- a/clang/test/Sema/builtin-masked.c +++ b/clang/test/Sema/builtin-masked.c @@ -55,9 +55,9 @@ void test_masked_scatter(int *p, v8i idx, v8b mask, v2b mask2, v8i val) { __builtin_masked_scatter(mask, idx, val, &idx); // expected-error {{3rd argument must be a scalar pointer}} } -void a(v8b mask, v8i val, const int *ptr) { - __builtin_masked_load(mask, ptr, val); - (void)__builtin_masked_load(mask, (volatile int *)ptr, val); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} +void a(v8b mask, v8i v, const int *ptr) { + __builtin_masked_load(mask, ptr, v); + (void)__builtin_masked_load(mask, (volatile int *)ptr, v); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} } void b(v8b mask, v8i idx, const int *ptr) { @@ -65,23 +65,23 @@ void b(v8b mask, v8i idx, const int *ptr) { (void)__builtin_masked_gather(mask, idx, (volatile int *)ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} } -void c(v8b mask, const v8i val, int *ptr) { - __builtin_masked_store(mask, val, ptr); +void c(v8b mask, const v8i v, int *ptr) { + __builtin_masked_store(mask, v, ptr); } -void readonly(v8b mask, v8i val, const int *ptr, const int *s) { - __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} - __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} - __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} +void readonly(v8b mask, v8i v, const int *ptr, const int *s) { + (void)__builtin_masked_store(mask, v, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} + (void)__builtin_masked_compress_store(mask, v, ptr); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} + (void)__builtin_masked_scatter(mask, v, v, s); // expected-error {{sending 'const int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('const int *' vs 'int *')}} } -void vol(v8b mask, v8i val, volatile int *ptr, volatile int *s) { - __builtin_masked_store(mask, val, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} - __builtin_masked_compress_store(mask, val, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} - __builtin_masked_scatter(mask, val, val, s); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} -} - -v8i [[clang::address_space(999)]] load(v8b mask, int [[clang::address_space(999)]] * ptr) { +void vol(v8b mask, v8i v, volatile int *ptr, volatile int *s) { + (void)__builtin_masked_load(mask, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + (void)__builtin_masked_store(mask, v, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + (void)__builtin_masked_expand_load(mask, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + (void)__builtin_masked_compress_store(mask, v, ptr); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + (void)__builtin_masked_gather(mask, v, ptr);// expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} + (void)__builtin_masked_scatter(mask, v, v, s); // expected-error {{sending 'volatile int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('volatile int *' vs 'int *')}} } void as(v8b mask, int [[clang::address_space(999)]] * ptr, v8i v) { @@ -89,8 +89,8 @@ void as(v8b mask, int [[clang::address_space(999)]] * ptr, v8i v) { (void)__builtin_masked_store(mask, v, ptr); (void)__builtin_masked_expand_load(mask, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} (void)__builtin_masked_compress_store(mask, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} - (void)__builtin_masked_gather(mask, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} - (void)__builtin_masked_scatter(mask, v, v, ptr); // expected-error {{sending '__attribute__((address_space(999))) int *' to parameter of incompatible type 'int *': type mismatch at 2nd parameter ('__attribute__((address_space(999))) int *' vs 'int *')}} + (void)__builtin_masked_gather(mask, v, ptr); + (void)__builtin_masked_scatter(mask, v, v, ptr); } void atom(v8b mask, _Atomic int * ptr, v8i v) { >From 29e4a474d7728141f8d3d5916e1c59fd7ac1e3af Mon Sep 17 00:00:00 2001 From: Joseph Huber <[email protected]> Date: Thu, 25 Sep 2025 15:45:53 -0500 Subject: [PATCH 4/4] Simplify atomic --- clang/lib/Sema/SemaChecking.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 03c3378ca06ef..8c3e47698cd21 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2285,9 +2285,8 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, if (PointeeTy.isVolatileQualified() || PointeeTy->isAtomicType() || (!AllowConst && PointeeTy.isConstQualified()) || (!AllowAS && PointeeTy.hasAddressSpace())) { - QualType Target = S.Context.getPointerType(PointeeTy.getUnqualifiedType()); - if (const auto *AT = dyn_cast<AtomicType>(PointeeTy)) - Target = S.Context.getPointerType(AT->getValueType()); + QualType Target = + S.Context.getPointerType(PointeeTy.getAtomicUnqualifiedType()); return S.Diag(PtrArg->getExprLoc(), diag::err_typecheck_convert_incompatible) << PtrTy << Target << /*different qualifiers=*/5 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
