diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1e4e055e04afd..585e88d2490f2 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -910,6 +910,7 @@ class StructFieldAccess public: const ArraySubscriptExpr *ASE = nullptr; + QualType ArrayElementTy; const Expr *VisitMemberExpr(const MemberExpr *E) { if (AddrOfSeen && E->getType()->isArrayType()) @@ -925,6 +926,7 @@ class StructFieldAccess AddrOfSeen = false; // '&ptr->array[idx]' is okay. ASE = E; + ArrayElementTy = E->getBase()->getType(); return Visit(E->getBase()); } const Expr *VisitCastExpr(const CastExpr *E) { @@ -1101,23 +1103,23 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, // count = ptr->count; // // flexible_array_member_base_size = sizeof (*ptr->array); - // flexible_array_member_size = - // count * flexible_array_member_base_size; + // flexible_array_member_size = count * flexible_array_member_base_size; // // if (flexible_array_member_size < 0) // return 0; // return flexible_array_member_size; // - // 2) '&ptr->array[idx]': + // 2) '&((cast) ptr->array)[idx]': // // count = ptr->count; // index = idx; // + // casted_flexible_array_member_base_size = sizeof (*((cast) ptr->array)); + // // flexible_array_member_base_size = sizeof (*ptr->array); - // flexible_array_member_size = - // count * flexible_array_member_base_size; + // flexible_array_member_size = count * flexible_array_member_base_size; // - // index_size = index * flexible_array_member_base_size; + // index_size = index * casted_flexible_array_member_base_size; // // if (flexible_array_member_size < 0 || index < 0) // return 0; @@ -1129,8 +1131,7 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, // sizeof_struct = sizeof (struct s); // // flexible_array_member_base_size = sizeof (*ptr->array); - // flexible_array_member_size = - // count * flexible_array_member_base_size; + // flexible_array_member_size = count * flexible_array_member_base_size; // // field_offset = offsetof (struct s, field); // offset_diff = sizeof_struct - field_offset; @@ -1139,19 +1140,19 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, // return 0; // return offset_diff + flexible_array_member_size; // - // 4) '&ptr->field_array[idx]': + // 4) '&((cast) ptr->field_array)[idx]': // // count = ptr->count; // index = idx; // sizeof_struct = sizeof (struct s); // // flexible_array_member_base_size = sizeof (*ptr->array); - // flexible_array_member_size = - // count * flexible_array_member_base_size; + // flexible_array_member_size = count * flexible_array_member_base_size; + // + // casted_field_base_size = sizeof (*((cast) ptr->field_array)); // - // field_base_size = sizeof (*ptr->field_array); // field_offset = offsetof (struct s, field) - // field_offset += index * field_base_size; + // field_offset += index * casted_field_base_size; // // offset_diff = sizeof_struct - field_offset; // @@ -1162,14 +1163,11 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, QualType CountTy = CountFD->getType(); bool IsSigned = CountTy->isSignedIntegerType(); - QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType(); - QualType FieldTy = FD->getType(); - // Explicit cast because otherwise the CharWidth will promote an i32's into // u64's leading to overflows.. int64_t CharWidth = static_cast(CGM.getContext().getCharWidth()); - // size_t field_offset = offsetof (struct s, field); + // field_offset = offsetof (struct s, field); Value *FieldOffset = nullptr; if (FlexibleArrayMemberFD != FD) { std::optional Offset = GetFieldOffset(Ctx, RD, FD); @@ -1179,13 +1177,13 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, llvm::ConstantInt::get(ResType, *Offset / CharWidth, IsSigned); } - // size_t count = (size_t) ptr->count; + // count = ptr->count; Value *Count = EmitLoadOfCountedByField(ME, FlexibleArrayMemberFD, CountFD); if (!Count) return nullptr; Count = Builder.CreateIntCast(Count, ResType, IsSigned, "count"); - // size_t index = (size_t) ptr->index; + // index = ptr->index; Value *Index = nullptr; if (Idx) { bool IdxSigned = Idx->getType()->isSignedIntegerType(); @@ -1193,23 +1191,35 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, Index = Builder.CreateIntCast(Index, ResType, IdxSigned, "index"); } - // size_t flexible_array_member_base_size = sizeof (*ptr->array); - const ArrayType *ArrayTy = Ctx.getAsArrayType(FlexibleArrayMemberTy); - CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); + // flexible_array_member_base_size = sizeof (*ptr->array); + QualType FlexibleArrayMemberTy = FlexibleArrayMemberFD->getType(); + const ArrayType *FAMTy = Ctx.getAsArrayType(FlexibleArrayMemberTy); + CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getElementType()); auto *FlexibleArrayMemberBaseSize = llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned); - // size_t flexible_array_member_size = - // count * flexible_array_member_base_size; + // flexible_array_member_size = count * flexible_array_member_base_size; Value *FlexibleArrayMemberSize = Builder.CreateMul(Count, FlexibleArrayMemberBaseSize, "flexible_array_member_size", !IsSigned, IsSigned); + QualType CastedArrayElementTy = Visitor.ArrayElementTy; + llvm::ConstantInt *CastedArrayElementSize = nullptr; + if (!CastedArrayElementTy.isNull() && CastedArrayElementTy->isPointerType()) { + const PointerType *FAMTy = cast(CastedArrayElementTy); + CharUnits BaseSize = Ctx.getTypeSizeInChars(FAMTy->getPointeeType()); + CastedArrayElementSize = + llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned); + } + Value *Res = nullptr; if (FlexibleArrayMemberFD == FD) { - if (Idx) { // Option (2) '&ptr->array[idx]' - // size_t index_size = index * flexible_array_member_base_size; - Value *IndexSize = Builder.CreateMul(FlexibleArrayMemberBaseSize, Index, + if (Idx) { // Option (2) '&((cast) ptr->array)[idx]' + if (!CastedArrayElementSize) + CastedArrayElementSize = FlexibleArrayMemberBaseSize; + + // index_size = index * flexible_array_member_base_size; + Value *IndexSize = Builder.CreateMul(CastedArrayElementSize, Index, "index_size", !IsSigned, IsSigned); // return flexible_array_member_size - index_size; @@ -1220,28 +1230,30 @@ CodeGenFunction::emitCountedByMemberSize(const Expr *E, llvm::Value *EmittedE, Res = FlexibleArrayMemberSize; } } else { - // size_t sizeof_struct = sizeof (struct s); + // sizeof_struct = sizeof (struct s); llvm::StructType *StructTy = getTypes().getCGRecordLayout(RD).getLLVMType(); const llvm::DataLayout &Layout = CGM.getDataLayout(); TypeSize Size = Layout.getTypeSizeInBits(StructTy); Value *SizeofStruct = llvm::ConstantInt::get(ResType, Size.getKnownMinValue() / CharWidth); - if (Idx) { // Option (4) '&ptr->field_array[idx]' - // size_t field_base_size = sizeof (*ptr->field_array); - const ArrayType *ArrayTy = Ctx.getAsArrayType(FieldTy); - CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); - auto *FieldBaseSize = - llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned); + if (Idx) { // Option (4) '&((cast) ptr->field_array)[idx]' + // casted_field_base_size = sizeof (*((cast) ptr->field_array)); + if (!CastedArrayElementSize) { + const ArrayType *ArrayTy = Ctx.getAsArrayType(FD->getType()); + CharUnits BaseSize = Ctx.getTypeSizeInChars(ArrayTy->getElementType()); + CastedArrayElementSize = + llvm::ConstantInt::get(ResType, BaseSize.getQuantity(), IsSigned); + } - // field_offset += index * field_base_size; - Value *Mul = Builder.CreateMul(Index, FieldBaseSize, "field_offset", - !IsSigned, IsSigned); + // field_offset += index * casted_field_base_size; + Value *Mul = Builder.CreateMul(Index, CastedArrayElementSize, + "field_offset", !IsSigned, IsSigned); FieldOffset = Builder.CreateAdd(FieldOffset, Mul); } // Option (3) '&ptr->field', and Option (4) continuation. - // size_t offset_diff = flexible_array_member_offset - field_offset; + // offset_diff = flexible_array_member_offset - field_offset; Value *OffsetDiff = Builder.CreateSub(SizeofStruct, FieldOffset, "offset_diff", !IsSigned, IsSigned); diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index dfdf06587f0e2..101949af208e1 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -194,6 +194,42 @@ size_t test2_bdos(struct annotated *p) { return __bdos(p->array); } +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0 +// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]] +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos_cast( +// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[COUNTED_BY_LOAD]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[TMP0]], i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], i64 0 +// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]] +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos_cast( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test2_bdos_cast( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +size_t test2_bdos_cast(struct annotated *p) { + return __bdos((char *)p->array); +} + // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test3( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITH-ATTR-NEXT: entry: @@ -265,6 +301,30 @@ size_t test3_bdos(struct annotated *p) { return __bdos(p); } +// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast( +// SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test3_bdos_cast( +// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 -1 +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test3_bdos_cast( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test3_bdos_cast( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +size_t test3_bdos_cast(struct annotated *p) { + return __bdos((char *)p); +} + // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITH-ATTR-NEXT: entry: @@ -469,6 +529,96 @@ size_t test4_bdos(struct annotated *p, int index) { return __bdos(&p->array[index]); } +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -12884901886, 12884901885) i64 @test4_bdos_cast1( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[INDEX_SIZE:%.*]] = shl nsw i64 [[IDXPROM]], 1 +// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[INDEX_SIZE]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[RESULT]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -12884901886, 12884901885) i64 @test4_bdos_cast1( +// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[INDEX_SIZE:%.*]] = shl nsw i64 [[IDXPROM]], 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[INDEX_SIZE]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[RESULT]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test4_bdos_cast1( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test4_bdos_cast1( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +size_t test4_bdos_cast1(struct annotated *p, int index) { + return __bdos(&((unsigned short *) ((char *)p->array))[index]); +} + +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -10737418239, 10737418237) i64 @test4_bdos_cast2( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[IDXPROM]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[RESULT]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -10737418239, 10737418237) i64 @test4_bdos_cast2( +// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 8 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 2 +// NO-SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[IDXPROM]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[RESULT]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test4_bdos_cast2( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test4_bdos_cast2( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +size_t test4_bdos_cast2(struct annotated *p, int index) { + return __bdos(&((char *) ((unsigned short *)p->array))[index]); +} + // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test5( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITH-ATTR-NEXT: entry: @@ -2059,6 +2209,54 @@ size_t test32_bdos(struct annotated_with_array *ptr, int index) { return __bdos(&ptr->flags[index]); } +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -21474836134, 21474836817) i64 @test32_bdos_cast( +// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITH-ATTR-NEXT: entry: +// SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 336 +// SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 3 +// SANITIZE-WITH-ATTR-NEXT: [[FIELD_OFFSET:%.*]] = shl nsw i64 [[IDXPROM]], 1 +// SANITIZE-WITH-ATTR-NEXT: [[REASS_SUB:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[FIELD_OFFSET]] +// SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = add nsw i64 [[REASS_SUB]], 344 +// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[REASS_SUB]], -345 +// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -21474836134, 21474836817) i64 @test32_bdos_cast( +// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef readonly captures(none) [[PTR:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] { +// NO-SANITIZE-WITH-ATTR-NEXT: entry: +// NO-SANITIZE-WITH-ATTR-NEXT: [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 336 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNTED_BY_LOAD:%.*]] = load i32, ptr [[COUNTED_BY_GEP]], align 4 +// NO-SANITIZE-WITH-ATTR-NEXT: [[COUNT:%.*]] = sext i32 [[COUNTED_BY_LOAD]] to i64 +// NO-SANITIZE-WITH-ATTR-NEXT: [[FLEXIBLE_ARRAY_MEMBER_SIZE:%.*]] = shl nsw i64 [[COUNT]], 3 +// NO-SANITIZE-WITH-ATTR-NEXT: [[FIELD_OFFSET:%.*]] = shl nsw i64 [[IDXPROM]], 1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[REASS_SUB:%.*]] = sub nsw i64 [[FLEXIBLE_ARRAY_MEMBER_SIZE]], [[FIELD_OFFSET]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[RESULT:%.*]] = add nsw i64 [[REASS_SUB]], 344 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = icmp sgt i64 [[REASS_SUB]], -345 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[INDEX]], -1 +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP2:%.*]] = and i1 [[TMP1]], [[TMP0]] +// NO-SANITIZE-WITH-ATTR-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i64 [[RESULT]], i64 0 +// NO-SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP3]] +// +// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test32_bdos_cast( +// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] { +// SANITIZE-WITHOUT-ATTR-NEXT: entry: +// SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test32_bdos_cast( +// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[PTR:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] { +// NO-SANITIZE-WITHOUT-ATTR-NEXT: entry: +// NO-SANITIZE-WITHOUT-ATTR-NEXT: ret i64 -1 +// +size_t test32_bdos_cast(struct annotated_with_array *ptr, int index) { + return __bdos(&((unsigned short *) ((char *) ptr->flags))[index]); +} + // SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test33( // SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]]) local_unnamed_addr #[[ATTR0]] { // SANITIZE-WITH-ATTR-NEXT: entry: