|
26 | 26 | #include "clang/AST/Decl.h" |
27 | 27 | #include "clang/AST/OSLog.h" |
28 | 28 | #include "clang/AST/OperationKinds.h" |
| 29 | +#include "clang/AST/StmtVisitor.h" |
29 | 30 | #include "clang/Basic/TargetBuiltins.h" |
30 | 31 | #include "clang/Basic/TargetInfo.h" |
31 | 32 | #include "clang/Basic/TargetOptions.h" |
@@ -1051,6 +1052,145 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, |
1051 | 1052 | return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned)); |
1052 | 1053 | } |
1053 | 1054 |
|
| 1055 | +namespace { |
| 1056 | + |
| 1057 | +/// \p StructBaseExpr returns the base \p Expr with a structure or union type. |
| 1058 | +struct StructBaseExpr : public ConstStmtVisitor<StructBaseExpr, const Expr *> { |
| 1059 | + StructBaseExpr() = default; |
| 1060 | + |
| 1061 | + //===--------------------------------------------------------------------===// |
| 1062 | + // Visitor Methods |
| 1063 | + //===--------------------------------------------------------------------===// |
| 1064 | + |
| 1065 | + const Expr *VisitStmt(const Stmt *S) { return nullptr; } |
| 1066 | + |
| 1067 | + const Expr *Visit(const Expr *E) { |
| 1068 | + QualType Ty = E->getType(); |
| 1069 | + if (Ty->isStructureType() || Ty->isUnionType()) |
| 1070 | + return E; |
| 1071 | + |
| 1072 | + return ConstStmtVisitor<StructBaseExpr, const Expr *>::Visit(E); |
| 1073 | + } |
| 1074 | + |
| 1075 | + const Expr *VisitDeclRefExpr(const DeclRefExpr *E) { return E; } |
| 1076 | + |
| 1077 | + const Expr *VisitMemberExpr(const MemberExpr *E) { |
| 1078 | + return Visit(E->getBase()); |
| 1079 | + } |
| 1080 | + const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { |
| 1081 | + return Visit(E->getBase()); |
| 1082 | + } |
| 1083 | + const Expr *VisitCastExpr(const CastExpr *E) { |
| 1084 | + return Visit(E->getSubExpr()); |
| 1085 | + } |
| 1086 | + const Expr *VisitParenExpr(const ParenExpr *E) { |
| 1087 | + return Visit(E->getSubExpr()); |
| 1088 | + } |
| 1089 | + const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) { |
| 1090 | + return Visit(E->getSubExpr()); |
| 1091 | + } |
| 1092 | + const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) { |
| 1093 | + return Visit(E->getSubExpr()); |
| 1094 | + } |
| 1095 | +}; |
| 1096 | + |
| 1097 | +} // end anonymous namespace |
| 1098 | + |
| 1099 | +/// The offset of a field from the beginning of the record. |
| 1100 | +llvm::Value * |
| 1101 | +CodeGenFunction::tryEmitObjectSizeCalculation(const Expr *E, unsigned Type, |
| 1102 | + llvm::IntegerType *ResType) { |
| 1103 | + if ((Type & 0x01) != 0) |
| 1104 | + // We handle only the whole object size. |
| 1105 | + return nullptr; |
| 1106 | + |
| 1107 | + E = E->IgnoreParenImpCasts(); |
| 1108 | + |
| 1109 | + const Expr *Base = StructBaseExpr().Visit(E); |
| 1110 | + if (!Base) |
| 1111 | + return nullptr; |
| 1112 | + |
| 1113 | + const RecordDecl *RD = Base->getType()->getAsRecordDecl(); |
| 1114 | + if (!RD) |
| 1115 | + return nullptr; |
| 1116 | + |
| 1117 | + // Get the full size of the struct. |
| 1118 | + ASTContext &Ctx = getContext(); |
| 1119 | + const RecordDecl *OuterRD = RD->getOuterLexicalRecordContext(); |
| 1120 | + const clang::Type *RT = OuterRD->getTypeForDecl(); |
| 1121 | + CharUnits RecordSize = Ctx.getTypeSizeInChars(RT); |
| 1122 | + |
| 1123 | + Value *Res = nullptr; |
| 1124 | + |
| 1125 | + if (const auto *U = dyn_cast<UnaryOperator>(E); |
| 1126 | + U && (U->getOpcode() == UO_AddrOf || U->getOpcode() == UO_Deref)) |
| 1127 | + E = U->getSubExpr()->IgnoreParenImpCasts(); |
| 1128 | + |
| 1129 | + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E)) { |
| 1130 | + const Expr *Idx = ASE->getIdx(); |
| 1131 | + Base = ASE->getBase()->IgnoreParenImpCasts(); |
| 1132 | + |
| 1133 | + if (const auto *ME = dyn_cast<MemberExpr>(Base); |
| 1134 | + ME && ME->getType()->isConstantArrayType()) { |
| 1135 | + // The simple case: |
| 1136 | + // |
| 1137 | + // struct s { |
| 1138 | + // int arr[42]; |
| 1139 | + // char c; |
| 1140 | + // /* others */ |
| 1141 | + // }; |
| 1142 | + // |
| 1143 | + // __builtin_dynamic_object_size(&p->arr[idx], 0); |
| 1144 | + // |
| 1145 | + // We can translate the __builtin_dynamic_object_call into: |
| 1146 | + // |
| 1147 | + // sizeof(struct s) - offsetof(arr) - (idx * sizeof(int)) |
| 1148 | + // |
| 1149 | + bool IsSigned = Idx->getType()->isSignedIntegerType(); |
| 1150 | + Value *IdxInst = EmitAnyExprToTemp(Idx).getScalarVal(); |
| 1151 | + IdxInst = Builder.CreateIntCast(IdxInst, ResType, IsSigned); |
| 1152 | + |
| 1153 | + const ConstantArrayType *CAT = cast<ConstantArrayType>(ME->getType()); |
| 1154 | + CharUnits ElemSize = Ctx.getTypeSizeInChars(CAT->getElementType()); |
| 1155 | + Value *ElemSizeInst = Builder.getInt32(ElemSize.getQuantity()); |
| 1156 | + ElemSizeInst = Builder.CreateIntCast(ElemSizeInst, ResType, IsSigned); |
| 1157 | + |
| 1158 | + // idx * sizeof(<arr element type>) |
| 1159 | + Res = Builder.CreateMul(IdxInst, ElemSizeInst, "", !IsSigned, IsSigned); |
| 1160 | + |
| 1161 | + // sizeof(struct s) |
| 1162 | + Value *RecordSizeInst = Builder.getInt32(RecordSize.getQuantity()); |
| 1163 | + RecordSizeInst = Builder.CreateIntCast(RecordSizeInst, ResType, |
| 1164 | + RT->isSignedIntegerType()); |
| 1165 | + |
| 1166 | + // offsetof(arr) |
| 1167 | + int64_t Offset = 0; |
| 1168 | + getFieldOffsetInBits(OuterRD, cast<FieldDecl>(ME->getMemberDecl()), |
| 1169 | + Offset); |
| 1170 | + |
| 1171 | + CharUnits OffsetVal = Ctx.toCharUnitsFromBits(Offset); |
| 1172 | + Value *OffsetInst = Builder.getInt64(OffsetVal.getQuantity()); |
| 1173 | + OffsetInst = Builder.CreateIntCast(OffsetInst, ResType, IsSigned); |
| 1174 | + |
| 1175 | + // sizeof(struct s) - offsetof(arr) ... |
| 1176 | + RecordSizeInst = Builder.CreateSub(RecordSizeInst, OffsetInst, "", |
| 1177 | + !IsSigned, IsSigned); |
| 1178 | + // ... - (idx * sizeof(<arr element type>)) |
| 1179 | + RecordSizeInst = |
| 1180 | + Builder.CreateSub(RecordSizeInst, Res, "", !IsSigned, IsSigned); |
| 1181 | + |
| 1182 | + // Don't allow the index or result to be negative. |
| 1183 | + Value *Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(Res), |
| 1184 | + Builder.CreateIsNotNeg(RecordSizeInst)); |
| 1185 | + |
| 1186 | + Res = Builder.CreateSelect(Cmp, RecordSizeInst, |
| 1187 | + ConstantInt::get(ResType, 0, IsSigned)); |
| 1188 | + } |
| 1189 | + } |
| 1190 | + |
| 1191 | + return Res; |
| 1192 | +} |
| 1193 | + |
1054 | 1194 | /// Returns a Value corresponding to the size of the given expression. |
1055 | 1195 | /// This Value may be either of the following: |
1056 | 1196 | /// - A llvm::Argument (if E is a param with the pass_object_size attribute on |
@@ -1083,18 +1223,21 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type, |
1083 | 1223 | } |
1084 | 1224 | } |
1085 | 1225 |
|
| 1226 | + // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't |
| 1227 | + // evaluate E for side-effects. In either case, we shouldn't lower to |
| 1228 | + // @llvm.objectsize. |
| 1229 | + if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) |
| 1230 | + return getDefaultBuiltinObjectSizeResult(Type, ResType); |
| 1231 | + |
1086 | 1232 | if (IsDynamic) { |
1087 | 1233 | // Emit special code for a flexible array member with the "counted_by" |
1088 | 1234 | // attribute. |
1089 | 1235 | if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType)) |
1090 | 1236 | return V; |
1091 | | - } |
1092 | 1237 |
|
1093 | | - // LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't |
1094 | | - // evaluate E for side-effects. In either case, we shouldn't lower to |
1095 | | - // @llvm.objectsize. |
1096 | | - if (Type == 3 || (!EmittedE && E->HasSideEffects(getContext()))) |
1097 | | - return getDefaultBuiltinObjectSizeResult(Type, ResType); |
| 1238 | + if (Value *V = tryEmitObjectSizeCalculation(E, Type, ResType)) |
| 1239 | + return V; |
| 1240 | + } |
1098 | 1241 |
|
1099 | 1242 | Value *Ptr = EmittedE ? EmittedE : EmitScalarExpr(E); |
1100 | 1243 | assert(Ptr->getType()->isPointerTy() && |
|
0 commit comments